301 lines
6.8 KiB
C
Raw Permalink Normal View History

2022-06-25 11:52:00 +08:00
#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;
}