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