#include #include typedef struct { char *name; int offset; int count; float percent; } Profile_Entry; static const char *profile_filename; static const char *map_filename; static int granularity; static int *profile; static int profile_len; static Profile_Entry *functionTable; static int numFunctions; static int maxFunctions; static void read_args(int argc, const char *argv[]) { if (argc < 3) { fprintf(stderr, "annotate \n"); fclose(stderr); exit(EXIT_FAILURE); } profile_filename = argv[1]; map_filename = argv[2]; } static void read_profile() { FILE *in = fopen(profile_filename, "rb"); if (in == NULL) { fprintf(stderr, "Failed to open profile file '%s'\n", profile_filename); fclose(stderr); exit(EXIT_FAILURE); } fseek(in, 0, SEEK_END); profile_len = (int)ftell(in)-8; fseek(in, 0, SEEK_SET); if ((fgetc(in) != 'P') || (fgetc(in) != 'R') || (fgetc(in) != '0') || (fgetc(in) != 'F')) { fclose(in); fprintf(stderr, "'%s' is not a profile file\n", profile_filename); fclose(stderr); exit(EXIT_FAILURE); } fread(&granularity, 4, 1, in); profile = malloc(profile_len); if (profile == NULL) { fclose(in); fprintf(stderr, "Out of memory reading profile\n"); fclose(stderr); exit(EXIT_FAILURE); } fread(profile, 4, profile_len>>2, in); fclose(in); } static void addFn(const char *text, int offset) { if (numFunctions == maxFunctions) { int newSize = maxFunctions*2; if (newSize == 0) newSize = 128; functionTable = realloc(functionTable, newSize*sizeof(Profile_Entry)); if (functionTable == NULL) { fprintf(stderr, "Out of memory reading mapfile\n"); fflush(stderr); exit(EXIT_FAILURE); } maxFunctions = newSize; } functionTable[numFunctions].name = malloc(strlen(text)+1); strcpy(functionTable[numFunctions].name, text); functionTable[numFunctions].offset = offset; functionTable[numFunctions].count = 0; functionTable[numFunctions].percent = 0.0; //fprintf(stdout, "%s %x\n", functionTable[numFunctions].name, // functionTable[numFunctions].offset); numFunctions++; } static void read_map() { FILE *in = fopen(map_filename, "rb"); char text[2048]; if (in == NULL) { fprintf(stderr, "Failed to open map file '%s'\n", map_filename); fclose(stderr); exit(EXIT_FAILURE); } functionTable = NULL; numFunctions = 0; maxFunctions = 0; addFn("Address 0", 0); while (!feof(in)) { int offset; char c; char *t; /* Skip over any whitespace */ do { c = fgetc(in); } while (((c == 32) || (c == 9)) && (!feof(in))); ungetc(c, in); /* Try to read an offset */ if (fscanf(in, "0x%x", &offset) != 1) { goto over; } /* Skip over any whitespace */ do { c = fgetc(in); } while ((c == 32) && (!feof(in))); ungetc(c, in); /* Names never start with . or (*/ if ((c != '_') && ((c < 'a') || (c > 'z')) && ((c < 'A') || (c > 'Z'))) goto over; /* Read the name */ t = text; do { c = fgetc(in); *t++ = c; } while (c > 32); t[-1] = 0; /* Now there should be nothing left on this line */ if ((c != 10) && (c != 13)) goto over; /* And put the return back */ ungetc(c, in); if (t != text) { addFn(text, offset); } over: /* Skip to the end of the line */ do { c = fgetc(in); } while ((c >= 32) && (!feof(in))); /* Skip over any newlines */ while (((c == 10) || (c == 13)) && (!feof(in))) { c = fgetc(in); } /* And put the first non whitespace/non return char back */ ungetc(c, in); } fclose(in); } static void show_profile() { int i; for (i=0; i < numFunctions; i++) { fprintf(stdout, "%08x (%6.2f%%: %6d) %s\n", functionTable[i].offset, functionTable[i].percent, functionTable[i].count, functionTable[i].name); } } int byAddress(const void *_e1, const void *_e2) { const Profile_Entry *e1 = (const Profile_Entry *)_e1; const Profile_Entry *e2 = (const Profile_Entry *)_e2; return e1->offset - e2->offset; } int byTime(const void *_e1, const void *_e2) { const Profile_Entry *e1 = (const Profile_Entry *)_e1; const Profile_Entry *e2 = (const Profile_Entry *)_e2; return e2->count - e1->count; } static void process_profile() { int next; int fn; int idx; int max; int total; /* Sort into address order */ qsort(functionTable, numFunctions, sizeof(Profile_Entry), byAddress); /* Run through the profile adding it to the appropriate function */ fn = -1; /* Which function are we looking at */ next = -1; /* At what address should we move to the next function */ idx = 0; /* Where are we in the profile */ max = profile_len>>2; total = 0; for (idx = 0; idx < max; idx++) { while ((idx<<(granularity+2)) >= next) { /* Move to the next function */ fn++; //fprintf(stdout, "Will be on fn %s until we pass %x\n", // functionTable[fn].name, functionTable[fn+1].offset); next = 0x7FFFFFFF; if (fn+1 < numFunctions) { next = functionTable[fn+1].offset; } } //fprintf(stdout, "fn=%d count=%d idx=%d next=%x\n", // fn, functionTable[fn].count, idx, next); functionTable[fn].count += profile[idx]; total += profile[idx]; } for (fn = 0; fn < numFunctions; fn++) { functionTable[fn].percent = 100.0*functionTable[fn].count/total; } fprintf(stdout, "Profile by Address\n"); show_profile(); /* Sort into time order */ qsort(functionTable, numFunctions, sizeof(Profile_Entry), byTime); fprintf(stdout, "\n\n"); fprintf(stdout, "Profile by Time\n"); show_profile(); } int main(int argc, const char *argv[]) { read_args(argc, argv); read_profile(); read_map(); process_profile(); return EXIT_SUCCESS; }