Hi, gfortran seems to use much more memory at compile time when I "use" larger modules that contain many symbols, even if I "use, only" selected one. In the described situation it needs significantly more memory than "competitors". The attached archive contains the following main program and three (3) large modules to demonstrate this. The variant with the commented lines uncommented goes beyond 500 MB virtual memory in a Linux/x86 machine. program main use mo_psas, only: setup_psas use mo_3dvar, only: obs, bg ! use mo_t_enkf, only: enkf_driver ! Uncomment to go beyond 500 MB virt ual mem. implicit none call setup_psas (obs% o, bg% grid% a, bg) ! call enkf_driver end program main Compiling this program with: % gfortran -S -fmem-report -ftime-report Memory still allocated at the end of the compilation process Size Allocated Used Overhead 8 4096 2816 96 16 16k 13k 256 64 4096 1088 40 128 4096 768 36 256 4096 2304 32 512 64k 61k 512 2048 36k 36k 288 4096 16k 16k 128 8192 8192 8192 32 32768 416k 416k 416 8388608 8192k 8192k 32 56 4096 280 40 104 20k 17k 180 92 106M 105M 958k 80 4096 80 36 88 73M 72M 661k 24 24k 15k 312 72 4096 288 36 28 9208k 9189k 107k 112 44k 37k 396 36 4096 288 44 12 10164k 10146k 178k 40 33M 33M 364k Total 240M 238M 2274k String pool entries 336041 identifiers 336041 (100.00%) slots 524288 bytes 4934k (350k overhead) table size 2048k coll/search 0.6655 ins/search 0.2790 avg. entry 15.04 bytes (+/- 0.99) longest entry 34 ??? tree nodes created (No per-node statistics) Type hash: size 1021, 175 elements, 0.084121 collisions DECL_DEBUG_EXPR hash: size 1021, 0 elements, 0.000000 collisions DECL_VALUE_EXPR hash: size 2097143, 865473 elements, 1.209451 collisions Execution times (seconds) garbage collection : 1.56 (19%) usr 0.00 ( 0%) sys 1.54 (17%) wall 0 kB ( 0%) ggc parser : 6.29 (78%) usr 0.78 (99%) sys 7.08 (79%) wall 25 1744 kB (100%) ggc symout : 0.00 ( 0%) usr 0.00 ( 0%) sys 0.01 ( 0%) wall 0 kB ( 0%) ggc TOTAL : 8.11 0.79 8.91 25 2445 kB Extra diagnostic checks enabled; compiler may run slowly. Configure with --disable-checking to disable checks. The modules are extracted from a larger project and should be sufficient to just compile the example. The project uses MPI (mpich) which is why these symbols occur quite frequently in the module files. Gfortran seems to handle the present case quite inefficiently. Maybe there is a solution that handles used modules more economically... Cheers, -ha
Created attachment 12841 [details] main.f90 + 3 modules included my main
Confirmed. Definitely excessive.
if you try the example, f951 may exit with a segfault. reason is this code takes a lot of stack space. for tcsh, "ulimit stacksize unlimited" was required. (just to save 10 minutes for the next person who takes a look at this !!)
from what i see so far, the problem is in the .mod files, not in the reading of them. there are hundreds of thousands of 'commons' defined, which is silly. any way to get source to the attached mod files ? --bud
> from what i see so far, the problem is in the .mod files, not in the reading of > them. there are hundreds of thousands of 'commons' defined, which is silly. This gave me the idea to the code below. Try compiling: module mod0 implicit none INCLUDE 'mpif.h' private public :: sub0 contains subroutine sub0 () end subroutine sub0 end module mod0 module mod1 use mod0, only : sub0 implicit none private public :: sub1 contains subroutine sub1 () end subroutine sub1 end module mod1 module mod2 use mod0, only : sub0 use mod1, only : sub1 implicit none private public :: sub2 contains subroutine sub2 () end subroutine sub2 end module mod2 with mpif.h cut down to: INTEGER MPI_BOTTOM COMMON /MPIPRIV/ MPI_BOTTOM and look at the module files. If you repeat the above, the module files will explode.
Created attachment 12998 [details] Module file size explosion demo I have rewritten the demo code. See how the size of the module files explodes with gfortran.
perfect. that seems to duplicate the problem.
the below patch looks like it fixes the problem. any chance this could be tryed on the reported problem ? --bud Index: gcc/gcc/fortran/module.c =================================================================== --- gcc/gcc/fortran/module.c (revision 122310) +++ gcc/gcc/fortran/module.c (working copy) @@ -3598,6 +3598,7 @@ write_common (gfc_symtree *st) { gfc_common_head *p; + pointer_info *pinfo; const char * name; int flags; @@ -3607,6 +3608,14 @@ write_common (st->left); write_common (st->right); + /* only need to write a given symtree entry once for + common blocks */ + p = st->n.common; + pinfo = find_pointer(p); + + if (pinfo != NULL && pinfo->u.wsym.state != UNREFERENCED) + return; + mio_lparen (); /* Write the unmangled name. */ @@ -3614,7 +3623,6 @@ mio_pool_string (&name); - p = st->n.common; mio_symbol_ref (&p->head); flags = p->saved ? 1 : 0; if (p->threadprivate) flags |= 2;
(In reply to comment #8) > the below patch looks like it fixes the problem. any chance this could be > tryed on the reported problem ? If somebody with sufficient resources can provide a binary (like FX's snapshots), I will try to recompile the project. -ha
Bud, I tried your patch, but it doesn't seem to make a difference. Is it the right patch?
i think not. i must have confued myself (rather easy to do!). will dig through the source this weekend.
i can confirm the attached patch is wrong.
I've adjusted the title slightly to refer to the use of COMMON blocks (in MPICH, OpenMPI) because the problem of .mod size excursion depends only on the "nesting depth", not on the actual size of the modules. I hope this bug will be fixed someday when somebody has a look either at the module writing routines or at the way the structures containing module information are held internally. I am unable to compile a reasonably large project (just in terms of the number of files, not total source code size!) using MPI. The problem appears even worse with OpenMPI than with MPICH.
I think the problem starts with: module mod0 integer mpi_bottom common /mpipriv/ mpi_bottom end module mod0 module mod1 use mod0 end module mod1 module mod2 use mod0 use mod1 end module mod2 Because in that case, mod2.mod already has two copies of the common: (('mpipriv' 2 0 0 'mpipriv') ('mpipriv' 2 0 0 'mpipriv')) and I don't think that's desirable. I think that the module loading is actually wrong here: the code in gfc_get_common (match.c) takes special care to duplicate this common name by creating a unique name for it. While I believe that mangling is necessary, the mangled name shouldn't be unique but simply prefixed, so that of the same name are merged, while prevented to clash with the namespace of the use'ing procedure. I'm regtesting the following patch: Index: match.c =================================================================== --- match.c (revision 129869) +++ match.c (working copy) @@ -2608,23 +2608,19 @@ gfc_common_head * gfc_get_common (const char *name, int from_module) { gfc_symtree *st; - static int serial = 0; - char mangled_name[GFC_MAX_SYMBOL_LEN + 1]; + char mangled_name[GFC_MAX_SYMBOL_LEN + 12]; if (from_module) - { - /* A use associated common block is only needed to correctly layout - the variables it contains. */ - snprintf (mangled_name, GFC_MAX_SYMBOL_LEN, "_%d_%s", serial++, name); - st = gfc_new_symtree (&gfc_current_ns->common_root, mangled_name); - } - else - { - st = gfc_find_symtree (gfc_current_ns->common_root, name); - - if (st == NULL) - st = gfc_new_symtree (&gfc_current_ns->common_root, name); - } + /* A use associated common block is only needed to correctly layout + the variables it contains. */ + snprintf (mangled_name, GFC_MAX_SYMBOL_LEN, "_frommodule_%s", name); + + st = gfc_find_symtree (gfc_current_ns->common_root, + from_module ? mangled_name : name); + + if (st == NULL) + st = gfc_new_symtree (&gfc_current_ns->common_root, + from_module ? mangled_name : name); if (st->n.common == NULL) {
Subject: Re: gfortran excessive memory usage with COMMON blocks in modules fxcoudert at gcc dot gnu dot org wrote: > Because in that case, mod2.mod already has two copies of the common: > > (('mpipriv' 2 0 0 'mpipriv') ('mpipriv' 2 0 0 'mpipriv')) > > and I don't think that's desirable. I think that the module loading is actually > wrong here: the code in gfc_get_common (match.c) takes special care to > duplicate this common name by creating a unique name for it. While I believe > that mangling is necessary, the mangled name shouldn't be unique but simply > prefixed, so that of the same name are merged, while prevented to clash with > the namespace of the use'ing procedure. I wrote this code originally, and I agree with your analysis. > Index: match.c > =================================================================== > --- match.c (revision 129869) > +++ match.c (working copy) > @@ -2608,23 +2608,19 @@ gfc_common_head * > gfc_get_common (const char *name, int from_module) > { > gfc_symtree *st; > - static int serial = 0; > - char mangled_name[GFC_MAX_SYMBOL_LEN + 1]; > + char mangled_name[GFC_MAX_SYMBOL_LEN + 12]; Should be + 13 (need one char for '\0'). > + /* A use associated common block is only needed to correctly layout > + the variables it contains. */ > + snprintf (mangled_name, GFC_MAX_SYMBOL_LEN, "_frommodule_%s", name); GFC_MAX_SYMBOL_LEN + 12, otherwise you could create ambiguities with really long common names. Previously this wasn't possible due to the serial number.
(In reply to comment #15) > I wrote this code originally, and I agree with your analysis. But regtesting doesn't agree with my analysis... in case of common with bind(c,name="..."), this patch hampers the diagnosis of commons with the same name but different labels. I've tried hard to get it rolling that way, because I agree it's cleaner, but I couldn't. I'll propose a different approach (a hack, to avoid writing twice the same combination of name and binding label) to the list when it finishes regtesting.
Subject: Re: gfortran excessive memory usage with COMMON blocks in modules fxcoudert at gcc dot gnu dot org wrote: > ------- Comment #16 from fxcoudert at gcc dot gnu dot org 2007-11-09 23:59 ------- > (In reply to comment #15) >> I wrote this code originally, and I agree with your analysis. > > But regtesting doesn't agree with my analysis... in case of common with > bind(c,name="..."), this patch hampers the diagnosis of commons with the same > name but different labels. I've tried hard to get it rolling that way, because > I agree it's cleaner, but I couldn't. I'll propose a different approach (a > hack, to avoid writing twice the same combination of name and binding label) to > the list when it finishes regtesting. There was no BIND(C) when I wrote it :-) I'll give it a look tomorrow.
Subject: Bug number PR 30285 A patch for this bug has been added to the patch tracker. The mailing list url for the patch is http://gcc.gnu.org/ml/gcc-patches/2007-11/msg00552.html
Harald, can you test the patch at http://gcc.gnu.org/ml/gcc-patches/2007-11/msg00552.html with your real-world program? Due to .mod changes, the "gfc-excessive.tar.gz" does not work. And for the other tests I have, the compile time does not significantly change (too much noise to see the effect).
Tobias, > Harald, can you test the patch at > http://gcc.gnu.org/ml/gcc-patches/2007-11/msg00552.html > with your real-world program? I would love to test it with a i586/i686-compatible build. (f951 should be sufficient that can be used as a replacement in one of those regular builds provided on FX's web page. Unfortunately I don't have the resourced to build gfortran myself.) > And for the other tests I have, the compile time does not > significantly change (too much noise to see the effect). The essential problem was actually the virtual memory used by f951 when I last tried to compile the app with MPI enabled. I think the first "benchmark" is to have the module files of the reworked example to all have the same size and essentially same contents. From comment #14 I presume that this will indeed be the case. Thanks, -ha
(In reply to comment #20) > I would love to test it with a i586/i686-compatible build. (f951 should > be sufficient that can be used as a replacement in one of those regular > builds provided on FX's web page. Unfortunately I don't have the > resourced to build gfortran myself.) I made a build of the patched compiler that you can download from http://www.coudert.name/tmp/gfortran-i686-linux-20071110.tar.gz > I think the > first "benchmark" is to have the module files of the reworked > example to all have the same size and essentially same contents. > From comment #14 I presume that this will indeed be the case. Yes, it is the case. Please let us know how your real-life testing goes.
FX, > I made a build of the patched compiler that you can download from > http://www.coudert.name/tmp/gfortran-i686-linux-20071110.tar.gz I successfully recompiled the app with OpenMPI enabled, which uses several COMMON blocks. Not only are the module files about a factor 100 smaller for me ;-), the compilation actually completes and the executable works. I am currently investigating the output, but the problem described in this PR is solved for me. Many thanks, -ha
Subject: Bug 30285 Author: fxcoudert Date: Sat Nov 17 13:46:53 2007 New Revision: 130257 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=130257 Log: PR fortran/30285 * module.c (struct written_common, written_commons): New structure. (compare_written_commons, free_written_common, write_common_0): New functions. (write_common): Call recursive function write_common_0. Modified: trunk/gcc/fortran/ChangeLog trunk/gcc/fortran/module.c
Fixed.