This is the mail archive of the fortran@gcc.gnu.org mailing list for the GNU Fortran project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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;
  

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]