// str is a line of integers, starting with a line number. Parse it, // returning the first number in *lnno and the rest in a newly // allocated Counts struct. If lnno is non-NULL, treat the first // number as a line number and assign it to *lnno instead of // incorporating it in the counts array. static Counts* splitUpCountsLine ( SOURCE* s, /*OUT*/UWord* lnno, const char* str ) { Bool ok; Counts* counts; ULong *tmpC = NULL; UInt n_tmpC = 0, tmpCsize = 0; while (1) { if (n_tmpC >= tmpCsize) { tmpCsize += 50; tmpC = realloc(tmpC, tmpCsize * sizeof *tmpC); if (tmpC == NULL) mallocFail(s, "splitUpCountsLine:"); } ok = parse_ULong( &tmpC[n_tmpC], &str ); if (!ok) break; n_tmpC++; } if (*str != 0) parseError(s, "garbage in counts line"); if (lnno ? (n_tmpC < 2) : (n_tmpC < 1)) parseError(s, "too few counts in count line"); if (lnno) { *lnno = (UWord)tmpC[0]; counts = new_Counts( n_tmpC-1, /*COPIED*/&tmpC[1] ); } else { counts = new_Counts( n_tmpC, /*COPIED*/&tmpC[0] ); } free(tmpC); return counts; }
// Read a line. Return the line read, or NULL if at EOF. // The line is allocated dynamically but will be overwritten with // every invocation. Caller must not free it. static const char *readline ( SOURCE* s ) { static char *line = NULL; static size_t linesiz = 0; int ch, i = 0; while (1) { ch = getc(s->fp); if (ch != EOF) { if (i + 1 >= linesiz) { linesiz += 500; line = realloc(line, linesiz * sizeof *line); if (line == NULL) mallocFail(s, "readline:"); } line[i++] = ch; line[i] = 0; if (ch == '\n') { line[i-1] = 0; s->lno++; break; } } else { if (ferror(s->fp)) { perror(argv0); barf(s, "I/O error while reading input file"); } else { // hit EOF break; } } } return i == 0 ? NULL : line; }
/*---------------------------------------------*/ static BitStream* bsOpenWriteStream ( FILE* stream ) { BitStream *bs = malloc ( sizeof(BitStream) ); if (bs == NULL) mallocFail ( sizeof(BitStream) ); bs->handle = stream; bs->buffer = 0; bs->buffLive = 0; bs->mode = 'w'; return bs; }
static void handle_counts ( SOURCE* s, CacheProfFile* cpf, char* fi, char* fn, char* newCountsStr ) { WordFM* countsMap; Bool freeNewCounts; UWord lnno; Counts* newCounts; FileFn* topKey; if (0) printf("%s %s %s\n", fi, fn, newCountsStr ); // parse the numbers newCounts = splitUpCountsLine( s, &lnno, newCountsStr ); // Did we get the right number? if (newCounts->n_counts != cpf->n_events) goto oom; // allocate the key topKey = malloc(sizeof(FileFn)); if (topKey) { topKey->fi_name = strdup(fi); topKey->fn_name = strdup(fn); } if (! (topKey && topKey->fi_name && topKey->fn_name)) mallocFail(s, "handle_counts:"); // search for it if (lookupFM( cpf->outerMap, (Word*)(&countsMap), (Word)topKey )) { // found it. Merge in new counts freeNewCounts = addCountsToMap( s, countsMap, lnno, newCounts ); ddel_FileFn(topKey); } else { // not found in the top map. Create new entry countsMap = newFM( malloc, free, cmp_unboxed_UWord ); if (!countsMap) goto oom; addToFM( cpf->outerMap, (Word)topKey, (Word)countsMap ); freeNewCounts = addCountsToMap( s, countsMap, lnno, newCounts ); } // also add to running summary total addCounts( s, cpf->summary, newCounts ); // if safe to do so, free up the count vector if (freeNewCounts) ddel_Counts(newCounts); return; oom: parseError(s, "# counts doesn't match # events"); }
static void merge_CacheProfInfo ( SOURCE* s, /*MOD*/CacheProfFile* dst, CacheProfFile* src ) { /* For each (filefn, innerMap) in src if filefn not in dst add binding dopy(filefn)->dopy(innerMap) in src else // merge src->innerMap with dst->innerMap for each (lineno, counts) in src->innerMap if lineno not in dst->innerMap add binding lineno->dopy(counts) to dst->innerMap else add counts into dst->innerMap[lineno] */ /* Outer iterator: FileFn* -> WordFM* (inner iterator) Inner iterator: UWord -> Counts* */ FileFn* soKey; WordFM* soVal; WordFM* doVal; UWord siKey; Counts* siVal; Counts* diVal; /* First check mundane things: that the events: lines are identical. */ if (!streq( dst->events_line, src->events_line )) barf(s, "\"events:\" line of most recent file does " "not match those previously processed"); initIterFM( src->outerMap ); // for (filefn, innerMap) in src while (nextIterFM( src->outerMap, (Word*)&soKey, (Word*)&soVal )) { // is filefn in dst? if (! lookupFM( dst->outerMap, (Word*)&doVal, (Word)soKey )) { // no .. add dopy(filefn) -> dopy(innerMap) to src FileFn* c_soKey = dopy_FileFn(soKey); WordFM* c_soVal = dopy_InnerMap(soVal); if ((!c_soKey) || (!c_soVal)) goto oom; addToFM( dst->outerMap, (Word)c_soKey, (Word)c_soVal ); } else { // yes .. merge the two innermaps initIterFM( soVal ); // for (lno, counts) in soVal (source inner map) while (nextIterFM( soVal, (Word*)&siKey, (Word*)&siVal )) { // is lno in the corresponding dst inner map? if (! lookupFM( doVal, (Word*)&diVal, siKey )) { // no .. add lineno->dopy(counts) to dst inner map Counts* c_siVal = dopy_Counts( siVal ); if (!c_siVal) goto oom; addToFM( doVal, siKey, (Word)c_siVal ); } else { // yes .. merge counts into dst inner map val addCounts( s, diVal, siVal ); } } } } // add the summaries too addCounts(s, dst->summary, src->summary ); return; oom: mallocFail(s, "merge_CacheProfInfo"); }
/* Parse a complete file from the stream in 's'. If a parse error happens, do not return; instead exit via parseError(). If an out-of-memory condition happens, do not return; instead exit via mallocError(). */ static CacheProfFile* parse_CacheProfFile ( SOURCE* s ) { #define M_TMP_DESCLINES 10 Int i; Bool b; char* tmp_desclines[M_TMP_DESCLINES]; char* p; int n_tmp_desclines = 0; CacheProfFile* cpf; Counts* summaryRead; char* curr_fn_init = "???"; char* curr_fl_init = "???"; char* curr_fn = curr_fn_init; char* curr_fl = curr_fl_init; cpf = new_CacheProfFile( NULL, NULL, NULL, 0, NULL, NULL, NULL ); if (cpf == NULL) mallocFail(s, "parse_CacheProfFile(1)"); // Parse "desc:" lines while (1) { b = readline(s); if (!b) break; if (!streqn(line, "desc: ", 6)) break; if (n_tmp_desclines >= M_TMP_DESCLINES) barf(s, "M_TMP_DESCLINES too low; increase and recompile"); tmp_desclines[n_tmp_desclines++] = strdup(line); } if (n_tmp_desclines == 0) parseError(s, "parse_CacheProfFile: no DESC lines present"); cpf->desc_lines = malloc( (1+n_tmp_desclines) * sizeof(char*) ); if (cpf->desc_lines == NULL) mallocFail(s, "parse_CacheProfFile(2)"); cpf->desc_lines[n_tmp_desclines] = NULL; for (i = 0; i < n_tmp_desclines; i++) cpf->desc_lines[i] = tmp_desclines[i]; // Parse "cmd:" line if (!streqn(line, "cmd: ", 5)) parseError(s, "parse_CacheProfFile: no CMD line present"); cpf->cmd_line = strdup(line); if (cpf->cmd_line == NULL) mallocFail(s, "parse_CacheProfFile(3)"); // Parse "events:" line and figure out how many events there are b = readline(s); if (!b) parseError(s, "parse_CacheProfFile: eof before EVENTS line"); if (!streqn(line, "events: ", 8)) parseError(s, "parse_CacheProfFile: no EVENTS line present"); // figure out how many events there are by counting the number // of space-alphanum transitions in the events_line cpf->events_line = strdup(line); if (cpf->events_line == NULL) mallocFail(s, "parse_CacheProfFile(3)"); cpf->n_events = 0; assert(cpf->events_line[6] == ':'); for (p = &cpf->events_line[6]; *p; p++) { if (p[0] == ' ' && isalpha(p[1])) cpf->n_events++; } // create the running cross-check summary cpf->summary = new_Counts_Zeroed( cpf->n_events ); if (cpf->summary == NULL) mallocFail(s, "parse_CacheProfFile(4)"); // create the outer map (file+fn name --> inner map) cpf->outerMap = newFM ( malloc, free, cmp_FileFn ); if (cpf->outerMap == NULL) mallocFail(s, "parse_CacheProfFile(5)"); // process count lines while (1) { b = readline(s); if (!b) parseError(s, "parse_CacheProfFile: eof before SUMMARY line"); if (isdigit(line[0])) { handle_counts(s, cpf, curr_fl, curr_fn, line); continue; } else if (streqn(line, "fn=", 3)) { if (curr_fn != curr_fn_init) free(curr_fn); curr_fn = strdup(line+3); continue; } else if (streqn(line, "fl=", 3)) { if (curr_fl != curr_fl_init) free(curr_fl); curr_fl = strdup(line+3); continue; } else if (streqn(line, "summary: ", 9)) { break; } else parseError(s, "parse_CacheProfFile: unexpected line in main data"); } // finally, the "summary:" line if (!streqn(line, "summary: ", 9)) parseError(s, "parse_CacheProfFile: missing SUMMARY line"); cpf->summary_line = strdup(line); if (cpf->summary_line == NULL) mallocFail(s, "parse_CacheProfFile(6)"); // there should be nothing more b = readline(s); if (b) parseError(s, "parse_CacheProfFile: " "extraneous content after SUMMARY line"); // check the summary counts are as expected summaryRead = splitUpCountsLine( s, NULL, &cpf->summary_line[8] ); if (summaryRead == NULL) mallocFail(s, "parse_CacheProfFile(7)"); if (summaryRead->n_counts != cpf->n_events) parseError(s, "parse_CacheProfFile: wrong # counts in SUMMARY line"); for (i = 0; i < summaryRead->n_counts; i++) { if (summaryRead->counts[i] != cpf->summary->counts[i]) { parseError(s, "parse_CacheProfFile: " "computed vs stated SUMMARY counts mismatch"); } } free(summaryRead->counts); sdel_Counts(summaryRead); // since the summary counts are OK, free up the summary_line text // which contains the same info. if (cpf->summary_line) { free(cpf->summary_line); cpf->summary_line = NULL; } if (curr_fn != curr_fn_init) free(curr_fn); if (curr_fl != curr_fl_init) free(curr_fl); // All looks OK return cpf; #undef N_TMP_DESCLINES }