Actual source code: report-once.c

      1: #include <stdio.h>
      2: #include "petscconf.h"
      3: #if defined(PETSC_HAVE_STRINGS_H)
      4: #include <strings.h>
      5: #endif
      6: #if defined(PETSC_HAVE_STRING_H)
      7: #include <string.h>
      8: #endif
      9: #if defined(PETSC_HAVE_STDLIB_H)
     10: #include <stdlib.h>
     11: #endif

     13: #if defined(__cplusplus)
     15: #endif

     17: #ifdef EVERYTHING_STATIC
     18: #define RO_EXTERN static
     19: #else
     20: #define RO_EXTERN
     21: #endif
     22: #include "knr-compat.h"
     23: #ifndef DISABLE_FORTRAN
     24: #define MAX_PREPRO_ARGS 31 /* This is an option for cfortran.h */
     25: #include "cfortran.h"
     26: #endif /* DISABLE_FORTRAN */
     27: #include "report-once.h"
     28:  #include config.h
     29: static void *xmalloc _P((size_t));
     30: static void *xcalloc _P((size_t, size_t));
     31: static void *xrealloc _P((void*, size_t));
     32: typedef struct exception_info {
     33:      int line;
     34:      int exception_type;
     35:      unsigned long int count;

     37:      struct exception_info *down;
     38: } exception_info;
     39: static const char *exceptions[] = {
     40:  #include names.h
     41: };

     43: static int hash_size = HASH_SIZE;
     44: static int initial_max_files = INITIAL_MAX_FILES;
     45: static int current_max_files = 0;
     46: static int file_growth_increment = FILE_GROWTH_INCREMENT;
     47: static int initial_store_created = 0;
     48: static exception_info ***exception_info_store;
     49: static int *line_numbers_count;

     51: static int allocated = 0;
     52: static int used = 0;

     54: static char **filenames;
     55: static char **routine_names;
     56: static FILE *ERROR_FILE = 0;
     57: static void *
     58: xmalloc ARG1(size_t,size)
     59: {
     60:      void *tmp = malloc (size);
     61:      if (!tmp) {
     62:           fprintf(stderr,"report once mode: out of virtual memory\n");
     63:           fflush(stderr);
     64:           abort();
     65:      }
     66:      return tmp;
     67: }
     68: static void *
     69: xcalloc ARG2(size_t, number, size_t, size_of_one)
     70: {
     71:      void *tmp = calloc ( number, size_of_one );
     72:      if (!tmp)
     73:      {
     74:           fprintf (stderr,"report once mode: virtual memory exhausted\n");
     75:           fflush(stderr);
     76:           abort();
     77:      }

     79:      return tmp;
     80: }
     81: static void *
     82: xrealloc ARG2(void*, ptr, size_t, new_size)
     83: {
     84:      void *tmp = realloc (ptr, new_size);
     85:      if (!tmp)
     86:      {
     87:           fprintf (stderr,"report once mode: virtual memory exhausted\n");
     88:           fflush(stderr);
     89:           abort();
     90:      }

     92:      return tmp;
     93: }

     95: /* This depends on what the Fortran AD tool thinks. */
     96: #define FORTRAN_UNDEFINED_FID  0

     98: #define ALREADY_ASSIGNED(fid) (fid != FORTRAN_UNDEFINED_FID)

    100: RO_EXTERN void
    101: reportonce_ehsfid ARG3(int*,g_ehfid, char *,routine, char *,filename)
    102: {
    103:      int routine_len;
    104:      int filename_len;

    106:      if ( ALREADY_ASSIGNED(*g_ehfid) )
    107:      {
    108:           return;
    109:      }

    111:      routine_len = strlen(routine);
    112:      filename_len = strlen(filename);

    114:      {
    115:           if (!allocated)
    116:           {
    117:                allocated = initial_max_files;

    119:                filenames = (char **) xmalloc (allocated * sizeof (char**));
    120:                routine_names = (char **) xmalloc (allocated * sizeof (char**));
    121:           }
    122:           else if ( used >= allocated ) /* Should never be strictly greater */
    123:           {
    124:                allocated += file_growth_increment;

    126:                filenames = (char **) xrealloc (filenames,
    127:                                                allocated * sizeof(char*));

    129:                routine_names = (char **) realloc (routine_names,
    130:                                                   allocated * sizeof(char*));
    131:           }
    132:      }

    134:      filenames[used] = (char *) xcalloc (filename_len+1, sizeof(char));
    135:      routine_names[used] = (char *) xcalloc (routine_len+1, sizeof(char));

    137:      strcpy (filenames[used], filename);
    138:      strcpy (routine_names[used], routine);

    140:      *g_ehfid = (used + 1); /* Fortran likes stuff numbered from 1 */
    141:      used++;
    142: }

    145: RO_EXTERN void
    146: reportonce_report_one ARG4(int, fid, int, line,
    147:                            int, exception_type, long int, count)
    148: {
    149:      if (!ERROR_FILE) ERROR_FILE = stderr;
    150:      fprintf (ERROR_FILE,
    151:               "At line %d in file \"%s\", while executing routine \"%s\",\n",
    152:               line,
    153:               filenames[fid],
    154:               routine_names[fid]
    155:               );
    156:      fprintf (ERROR_FILE,
    157:               "an exception occurred evaluating %.30s : %ld %s.\n",
    158:               exceptions[exception_type],
    159:               count,
    160:               (count == 1) ? "time" : "times"
    161:               );
    162:      fprintf (ERROR_FILE, "\n");
    163: }
    164: RO_EXTERN void
    165: reportonce_files ARG1(int, new_initial_size)
    166: {
    167:      initial_max_files = new_initial_size;
    168: }
    169: RO_EXTERN void
    170: reportonce_accumulate ARG3(int, file, int, line, int, exception)
    171: {
    172:      /* Adjust to internally number from 0 */
    173:      file = file - 1;

    175:      if ( ! initial_store_created )
    176:      {
    177:           {
    178:                int i;
    179:
    180:                /* We depend on calloc'ed memory to read as integer 0 */
    181:
    182:                exception_info_store =
    183:                     (exception_info ***) xcalloc ( initial_max_files,
    184:                                                    sizeof ( exception_info **) );
    185:
    186:                line_numbers_count =
    187:                     (int*) xcalloc ( initial_max_files, sizeof (int));

    189:                for (i=0; i < initial_max_files; i++ )
    190:                {
    191:                     exception_info_store[i] =
    192:                          (exception_info **) xcalloc (hash_size,
    193:                                                       sizeof (exception_info *));
    194:                }

    196:                initial_store_created = 1;
    197:                current_max_files = initial_max_files;
    198:           }
    199:      }

    201:      {
    202:           while ( file >= current_max_files )
    203:           {
    204:                int i;
    205:
    206:                exception_info_store =
    207:                     (exception_info ***) xrealloc ( exception_info_store,
    208:                                  (current_max_files + file_growth_increment ) *
    209:                                  sizeof ( exception_info ** ) );

    211:                line_numbers_count =
    212:                     (int*) xrealloc (line_numbers_count,
    213:                                       (current_max_files + file_growth_increment)*
    214:                                       sizeof (int) );

    216:                for (i = current_max_files;
    217:                     i < current_max_files + file_growth_increment;
    218:                     i++)
    219:                {
    220:                     exception_info_store[i] =
    221:                          (exception_info **) xcalloc (hash_size,
    222:                                                       sizeof (exception_info *));
    223:                     line_numbers_count[i] = 0;
    224:                }

    226:                current_max_files += file_growth_increment;
    227:           }
    228:      }
    229:      do {
    230:           int hashed_line = line % hash_size;
    231:           exception_info *our_loc;
    232:           exception_info *previous_loc = 0;

    234:           {
    235:                if (!exception_info_store[file][hashed_line])
    236:                {
    237:                     exception_info_store[file][hashed_line] =
    238:                          (exception_info*)xcalloc (1, sizeof(exception_info));
    239:
    240:                     our_loc = exception_info_store[file][hashed_line];
    241:
    242:                     our_loc->line = line;
    243:                     our_loc->exception_type = exception;
    244:                     our_loc->count = 1;
    245:                     our_loc->down = NULL;
    246:
    247:                     line_numbers_count[file] += 1;

    249:                     break;
    250:                }
    251:           }
    252:                /* (This routine does a "break" to leave this section.) */

    254:           /* We know this is not zero now */
    255:           our_loc = exception_info_store[file][hashed_line];

    257:           {
    258:                while ((our_loc != NULL) && (our_loc->line != line))
    259:                {
    260:                     previous_loc = our_loc;
    261:                     our_loc = our_loc->down;
    262:                }
    263:           }

    265:           if (!our_loc)
    266:           {
    267:                {
    268:                     exception_info *old_first_elt = exception_info_store[file][hashed_line];

    270:                     exception_info_store[file][hashed_line] =
    271:                          (exception_info*)xcalloc (1, sizeof(exception_info));
    272:
    273:                     our_loc = exception_info_store[file][hashed_line];
    274:
    275:                     our_loc->line = line;
    276:                     our_loc->exception_type = exception;
    277:                     our_loc->count = 1;
    278:                     our_loc->down = old_first_elt;
    279:
    280:                     line_numbers_count[file] += 1;
    281:                }
    282:           }
    283:           else
    284:           {
    285:                /* Move up to the start of the line if we are not already first */
    286:                if ( previous_loc != 0 )
    287:                {
    288:                     /* Save the first node's next pointer in case
    289:                        we are swapping #2 and #1. */

    291:                     exception_info *first_next =
    292:                          exception_info_store[file][hashed_line];

    294:                     /* We are not first (yet...) */
    295:                     previous_loc->down = our_loc->down;
    296:                     our_loc->down = first_next;

    298:                     /* Now we are first */
    299:                     exception_info_store[file][hashed_line] = our_loc;
    300:                }
    301:                our_loc->count += 1;
    302:           }

    304:      } while (0);

    307: }
    308: RO_EXTERN void
    309: reportonce_summary ARG0(void)
    310: {
    311:      {
    312:           int current_file;
    313:           struct exception_info switch_tmp;
    314:           struct exception_info * elts;
    315:           int i,j;

    317:           for (current_file = 0 ; current_file < current_max_files ; current_file++)
    318:           {
    319:                int found_count = 0;

    321:                /* Just skip this iteration if there's nothing to be done. */
    322:                if (!line_numbers_count[current_file])
    323:                     continue;

    325:               /* Make an array big enough to hold all of the extracted
    326:                  info, then sort it in that array.
    327:               */
    328:               elts = (struct exception_info * )
    329:                    xcalloc (line_numbers_count[current_file] + 1,
    330:                             sizeof(struct exception_info));

    332:               /*
    333:                  For a given file, walk along each main bucket of the array.
    334:               */
    335:               for (i = 0; i < hash_size; i++)
    336:               {
    337:                    /* Anybody home? */
    338:                    if ( (exception_info_store[current_file][i] != 0)
    339:                         && (exception_info_store[current_file][i]->line != 0) )
    340:                    {
    341:                         exception_info current_elt;

    343:                         /* Yes. */
    344:                         current_elt = *exception_info_store[current_file][i];
    345:                         elts[found_count] = current_elt;
    346:                         found_count++;

    348:                         /* Check for more folks chained off the bottom */
    349:                         while (current_elt.down != 0)
    350:                         {
    351:                              current_elt = *(current_elt.down);
    352:                              elts[found_count] = current_elt;
    353:                              found_count++;
    354:                         }
    355:                    }
    356:               }

    358:               if ( found_count != line_numbers_count[current_file])
    359:               {
    360:                    fprintf(stderr, "report once: Failed internal consistency check.\n");
    361:                    abort();
    362:               }

    364:                /* Sort the elements: Bubblesort */
    365:                for (i=0;i<found_count; i++)
    366:                {
    367:                     for (j=i; j<found_count; j++)
    368:                     {
    369:                          if ( elts[i].line > elts[j].line )
    370:                          {
    371:                               switch_tmp = elts[i];
    372:                               elts[i] = elts[j];
    373:                               elts[j] = switch_tmp;
    374:                          }
    375:                     }
    376:                }

    378:                /* Now print them out. */
    379:
    380:                for ( i=0; i<found_count; i++)
    381:                {
    382:                     reportonce_report_one (current_file,
    383:                                            elts[i].line,
    384:                                            elts[i].exception_type,
    385:                                            elts[i].count);
    386:                }

    388:                /* Clean up */
    389:                free (elts);
    390:           }
    391:      }

    393: }
    394: RO_EXTERN void reportonce_reset ARG0(void)
    395: {
    396:      int file_count;
    397:      int line_hash_count;
    398:
    399:      for (file_count = 0; file_count < current_max_files; file_count++)
    400:      {
    401:           line_numbers_count[file_count] = 0;
    402:
    403:           for (line_hash_count = 0;
    404:                line_hash_count < hash_size ;
    405:                line_hash_count++)
    406:           {
    407:                if ( exception_info_store[file_count][line_hash_count] != 0 )
    408:                {
    409:                     free(exception_info_store[file_count][line_hash_count]);
    410:                     exception_info_store[file_count][line_hash_count] = 0;
    411:                }
    412:           }
    413:      }
    414: }
    415: RO_EXTERN void
    416: reportonce_set_output_file ARG1(char *,output_filename)
    417: {
    418:      FILE *check_file;
    419:      check_file = fopen(output_filename,"w");
    420:      if (!check_file)
    421:      {
    422:           fprintf(stderr,"Unable to open reportonce output file: %s\n",
    423:                   output_filename);
    424:           fprintf(stderr,"Proceding to emit errors to standard error.\n");
    425:           fflush(stderr);
    426:      }
    427:      else
    428:      {
    429:           ERROR_FILE = check_file;
    430:      }
    431: }
    432: RO_EXTERN void
    433: reportonce_set_raw_output ARG1(FILE *,outfile)
    434: {
    435:      ERROR_FILE = outfile;
    436: }

    438: RO_EXTERN char *
    439: reportonce_get_filename ARG1(int, file_id)
    440: {
    441:      return filenames[file_id];
    442: }

    444: RO_EXTERN char *
    445: reportonce_get_routine_name ARG1(int, file_id)
    446: {
    447:      return routine_names[file_id];
    448: }

    451: /* Long names are disabled unless ENABLE_LONG_FORTRAN_NAMES is defined */
    452: /* Prototypes put here for clarity; real work is done by CFORTRAN.H */
    453: #if 0
    454: void once_summary (void);
    455: void once_reset (void);
    456: void once_accumulate (int *file, int *line, int *exception);
    457: void once_max_files (int *new_files);
    458: void once_output_file (char *filename);
    459: void ehsfid (int *g_ehfid, char *routine, char *filename);
    460: #endif

    462: #ifndef DISABLE_FORTRAN
    463: #ifdef ENABLE_LONG_FORTRAN_NAMES
    464: /* Long names */
    465: FCALLSCSUB0(reportonce_summary,ONCE_SUMMARY,once_summary)
    466: FCALLSCSUB3(reportonce_accumulate,ONCE_ACCUMULATE,once_accumulate,INT,INT,INT)
    467: FCALLSCSUB1(reportonce_files,ONCE_MAX_FILES,once_max_files,INT)
    468: #endif

    470: /* Short (<=6 characters) names */
    471: FCALLSCSUB0(reportonce_summary,EHORPT,ehorpt)
    472: FCALLSCSUB3(reportonce_accumulate,EHOACC,ehoacc,INT,INT,INT)
    473: FCALLSCSUB1(reportonce_files,EHOMXF,ehomxf,INT)

    475: FCALLSCSUB3(reportonce_ehsfid,EHSFID,ehsfid,PINT,STRING,STRING)
    476: #ifdef ENABLE_LONG_FORTRAN_NAMES
    477: FCALLSCSUB1(reportonce_set_output_file,ONCE_OUTPUT_FILE,once_output_file,STRING)
    478: #endif
    479: FCALLSCSUB1(reportonce_set_output_file,EHOFIL,ehofil,STRING)
    480: #ifdef ENABLE_LONG_FORTRAN_NAMES
    481: /* Long name */
    482: FCALLSCSUB0(reportonce_reset,ONCE_RESET,once_reset)
    483: #endif
    484: /* Short name */
    485: FCALLSCSUB0(reportonce_reset,EHORST,ehorst)

    487: #endif /* DISABLE_FORTRAN */

    489: #if defined(__cplusplus)
    490: }
    491: #endif