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