| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- #include <stdio.h>
- #include <stdlib.h>
- 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 <profile file> <map file>\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;
- }
|