Actual source code: report-once.c

petsc-3.3-p7 2013-05-11
  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)
 14: extern "C" {
 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