This is the mail archive of the
fortran@gcc.gnu.org
mailing list for the GNU Fortran project.
How much memory does gfortran use when compiling?
- From: Paul Thomas <paulthomas2 at wanadoo dot fr>
- To: Fortran List <fortran at gcc dot gnu dot org>
- Date: Sun, 08 Jul 2007 16:06:46 +0200
- Subject: How much memory does gfortran use when compiling?
Dear All,
I attach a patch that is a first order attempt at a reorganisation of
the parser, on which to hang whole file interface checking and speeded
up module reading. It was the result of a Paris/Marseille train ride
and this is as far as I got in the time. Not it DOES NOT regtest yet:
=== gfortran Summary ===
# of expected passes 18560
# of unexpected failures 356
# of expected failures 8
# of unresolved testcases 1
# of unsupported tests 86
All the failures, except one are segfaults because something gets messed
up in procedure locuses. I am sure that it is a minor problem. The
remaining regression results from the reversal of the order in
resolution and code generation.
Anyway, the name of the game is to hang all the parsed program units in
a global namespace before resolving them and turning them into code. I
suspect that all programme blocks, except modules could be handled in
this way - I just have not tried yet.
Note that the gfc_free_dt_list ()'s and the single gfc_free_namespace
(gfc_global_ns) replace the gfc_done_2 () for the program units. I did
chec that everything is freed, as before.
Beyond curing the above mentioned regressions, the next stage would be
to introduce the whole file interface checking. Clearly, it is a
trivial matter to search the sym_tree of gfc_global_ns for a procedure
and to do the standard interface checking. Beyond this, symbols for all
the other units, including modules, should be added to gfc_global_ns,
to be used for name checking and gsymbols removed. The final step would
be to add module namespaces, exactly as they would be read from a .mod
file. Then read_modules, subsequent to the first call, would copy these
namespaces, subject to need and renaming. I suspect this later step
will be less straightforward than the first.
Anyway, all this preamble brings me to my question: Has anybody checked
how much memory gfortran uses, on average, in a compilation, per byte of
fortran?
I presume that this quantity will be fairly constant for big codes but I
thought that I would ask if anybody had done this before I do some
digging myself. The reason that I ask is obvious - is the scheme that I
outlined above viable or will it be forever leading to memory problems?
Cheers
Paul
Index: gcc/fortran/parse.c
===================================================================
*** gcc/fortran/parse.c (revision 126317)
--- gcc/fortran/parse.c (working copy)
*************** gfc_parse_file (void)
*** 3173,3178 ****
--- 3173,3180 ----
gfc_state_data top, s;
gfc_statement st;
locus prog_locus;
+ gfc_namespace *next;
+ gfc_symtree *stree;
top.state = COMP_NONE;
top.sym = NULL;
*************** gfc_parse_file (void)
*** 3189,3194 ****
--- 3191,3202 ----
if (setjmp (eof_buf))
return FAILURE; /* Come here on unexpected EOF */
+ /* Prepare the global namespace that will contain the
+ program units. */
+ gfc_global_ns = gfc_get_namespace (NULL, 0);
+ gfc_global_ns->contained = NULL;
+ gfc_global_ns->refs = 1;
+
seen_program = 0;
/* Exit early for empty files. */
*************** loop:
*** 3215,3235 ****
accept_statement (st);
add_global_program ();
parse_progunit (ST_NONE);
! break;
case ST_SUBROUTINE:
add_global_procedure (1);
push_state (&s, COMP_SUBROUTINE, gfc_new_block);
accept_statement (st);
parse_progunit (ST_NONE);
! break;
case ST_FUNCTION:
add_global_procedure (0);
push_state (&s, COMP_FUNCTION, gfc_new_block);
accept_statement (st);
parse_progunit (ST_NONE);
! break;
case ST_BLOCK_DATA:
push_state (&s, COMP_BLOCK_DATA, gfc_new_block);
--- 3223,3243 ----
accept_statement (st);
add_global_program ();
parse_progunit (ST_NONE);
! goto prog_units;
case ST_SUBROUTINE:
add_global_procedure (1);
push_state (&s, COMP_SUBROUTINE, gfc_new_block);
accept_statement (st);
parse_progunit (ST_NONE);
! goto prog_units;
case ST_FUNCTION:
add_global_procedure (0);
push_state (&s, COMP_FUNCTION, gfc_new_block);
accept_statement (st);
parse_progunit (ST_NONE);
! goto prog_units;
case ST_BLOCK_DATA:
push_state (&s, COMP_BLOCK_DATA, gfc_new_block);
*************** loop:
*** 3255,3263 ****
push_state (&s, COMP_PROGRAM, gfc_new_block);
main_program_symbol (gfc_current_ns);
parse_progunit (st);
! break;
}
gfc_current_ns->code = s.head;
gfc_resolve (gfc_current_ns);
--- 3263,3272 ----
push_state (&s, COMP_PROGRAM, gfc_new_block);
main_program_symbol (gfc_current_ns);
parse_progunit (st);
! goto prog_units;
}
+ /* Handle the non-program units. */
gfc_current_ns->code = s.head;
gfc_resolve (gfc_current_ns);
*************** loop:
*** 3283,3289 ****
--- 3292,3333 ----
gfc_done_2 ();
goto loop;
+ prog_units:
+ /* The main program and non-contained procedures are put
+ in the global namespace, so that they can be processed
+ later and all their interfaces resolved. */
+ gfc_current_ns->code = s.head;
+ if (gfc_global_ns->contained)
+ gfc_current_ns->sibling = gfc_global_ns->contained;
+ gfc_global_ns->contained = gfc_current_ns;
+
+ gfc_get_sym_tree (gfc_current_ns->proc_name->name, gfc_global_ns, &stree);
+ stree->n.sym = gfc_current_ns->proc_name;
+ gfc_current_ns->proc_name->refs++;
+
+ pop_state ();
+ goto loop;
+
done:
+ gfc_current_ns = gfc_global_ns->contained;
+ for (; gfc_current_ns; gfc_current_ns = next)
+ {
+ next = gfc_current_ns->sibling;
+ gfc_resolve (gfc_current_ns);
+
+ /* Dump the parse tree if requested. */
+ if (gfc_option.verbose)
+ gfc_show_namespace (gfc_current_ns);
+
+ gfc_get_errors (NULL, &errors);
+ if (errors == 0)
+ gfc_generate_code (gfc_current_ns);
+
+ gfc_free_dt_list ();
+ }
+
+ gfc_free_namespace (gfc_global_ns);
+
return SUCCESS;
duplicate_main:
Index: gcc/fortran/symbol.c
===================================================================
*** gcc/fortran/symbol.c (revision 126317)
--- gcc/fortran/symbol.c (working copy)
*************** static int next_dummy_order = 1;
*** 87,92 ****
--- 87,93 ----
gfc_namespace *gfc_current_ns;
+ gfc_namespace *gfc_global_ns;
gfc_gsymbol *gfc_gsym_root = NULL;
*************** free_sym_tree (gfc_symtree *sym_tree)
*** 2672,2678 ****
/* Free the derived type list. */
! static void
gfc_free_dt_list (void)
{
gfc_dt_list *dt, *n;
--- 2673,2679 ----
/* Free the derived type list. */
! void
gfc_free_dt_list (void)
{
gfc_dt_list *dt, *n;
Index: gcc/fortran/gfortran.h
===================================================================
*** gcc/fortran/gfortran.h (revision 126317)
--- gcc/fortran/gfortran.h (working copy)
*************** typedef struct gfc_namespace
*** 1193,1198 ****
--- 1193,1199 ----
gfc_namespace;
extern gfc_namespace *gfc_current_ns;
+ extern gfc_namespace *gfc_global_ns;
/* Global symbols are symbols of global scope. Currently we only use
this to detect collisions already when parsing.
*************** void gfc_symbol_state (void);
*** 2144,2149 ****
--- 2145,2152 ----
gfc_gsymbol *gfc_get_gsymbol (const char *);
gfc_gsymbol *gfc_find_gsymbol (gfc_gsymbol *, const char *);
+ void gfc_free_dt_list (void);
+
/* intrinsic.c */
extern int gfc_init_expr;