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)
 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 == 0 )
 62:      {
 63:           fprintf(stderr,"report once mode: out of virtual memory\n");
 64:           fflush(stderr);
 65:           abort();
 66:      }
 67:      return tmp;
 68: }
 69: static void *
 70: xcalloc ARG2(size_t, number, size_t, size_of_one)
 71: {
 72:      void *tmp = calloc ( number, size_of_one );
 73:      if ( tmp == 0 )
 74:      {
 75:           fprintf (stderr,"report once mode: virtual memory exhausted\n");
 76:           fflush(stderr);
 77:           abort();
 78:      }

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

 93:      return tmp;
 94: }

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

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

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

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

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

115:      {
116:           if ( allocated == 0 )
117:           {
118:                allocated = initial_max_files;

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

305:      } while (0);


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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

488: #endif /* DISABLE_FORTRAN */

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