annotate.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. typedef struct
  4. {
  5. char *name;
  6. int offset;
  7. int count;
  8. float percent;
  9. }
  10. Profile_Entry;
  11. static const char *profile_filename;
  12. static const char *map_filename;
  13. static int granularity;
  14. static int *profile;
  15. static int profile_len;
  16. static Profile_Entry *functionTable;
  17. static int numFunctions;
  18. static int maxFunctions;
  19. static void read_args(int argc, const char *argv[])
  20. {
  21. if (argc < 3)
  22. {
  23. fprintf(stderr, "annotate <profile file> <map file>\n");
  24. fclose(stderr);
  25. exit(EXIT_FAILURE);
  26. }
  27. profile_filename = argv[1];
  28. map_filename = argv[2];
  29. }
  30. static void read_profile()
  31. {
  32. FILE *in = fopen(profile_filename, "rb");
  33. if (in == NULL)
  34. {
  35. fprintf(stderr, "Failed to open profile file '%s'\n",
  36. profile_filename);
  37. fclose(stderr);
  38. exit(EXIT_FAILURE);
  39. }
  40. fseek(in, 0, SEEK_END);
  41. profile_len = (int)ftell(in)-8;
  42. fseek(in, 0, SEEK_SET);
  43. if ((fgetc(in) != 'P') ||
  44. (fgetc(in) != 'R') ||
  45. (fgetc(in) != '0') ||
  46. (fgetc(in) != 'F'))
  47. {
  48. fclose(in);
  49. fprintf(stderr, "'%s' is not a profile file\n",
  50. profile_filename);
  51. fclose(stderr);
  52. exit(EXIT_FAILURE);
  53. }
  54. fread(&granularity, 4, 1, in);
  55. profile = malloc(profile_len);
  56. if (profile == NULL)
  57. {
  58. fclose(in);
  59. fprintf(stderr, "Out of memory reading profile\n");
  60. fclose(stderr);
  61. exit(EXIT_FAILURE);
  62. }
  63. fread(profile, 4, profile_len>>2, in);
  64. fclose(in);
  65. }
  66. static void addFn(const char *text, int offset)
  67. {
  68. if (numFunctions == maxFunctions)
  69. {
  70. int newSize = maxFunctions*2;
  71. if (newSize == 0)
  72. newSize = 128;
  73. functionTable = realloc(functionTable,
  74. newSize*sizeof(Profile_Entry));
  75. if (functionTable == NULL)
  76. {
  77. fprintf(stderr, "Out of memory reading mapfile\n");
  78. fflush(stderr);
  79. exit(EXIT_FAILURE);
  80. }
  81. maxFunctions = newSize;
  82. }
  83. functionTable[numFunctions].name = malloc(strlen(text)+1);
  84. strcpy(functionTable[numFunctions].name, text);
  85. functionTable[numFunctions].offset = offset;
  86. functionTable[numFunctions].count = 0;
  87. functionTable[numFunctions].percent = 0.0;
  88. //fprintf(stdout, "%s %x\n", functionTable[numFunctions].name,
  89. // functionTable[numFunctions].offset);
  90. numFunctions++;
  91. }
  92. static void read_map()
  93. {
  94. FILE *in = fopen(map_filename, "rb");
  95. char text[2048];
  96. if (in == NULL)
  97. {
  98. fprintf(stderr, "Failed to open map file '%s'\n",
  99. map_filename);
  100. fclose(stderr);
  101. exit(EXIT_FAILURE);
  102. }
  103. functionTable = NULL;
  104. numFunctions = 0;
  105. maxFunctions = 0;
  106. addFn("Address 0", 0);
  107. while (!feof(in))
  108. {
  109. int offset;
  110. char c;
  111. char *t;
  112. /* Skip over any whitespace */
  113. do
  114. {
  115. c = fgetc(in);
  116. }
  117. while (((c == 32) || (c == 9)) && (!feof(in)));
  118. ungetc(c, in);
  119. /* Try to read an offset */
  120. if (fscanf(in, "0x%x", &offset) != 1)
  121. {
  122. goto over;
  123. }
  124. /* Skip over any whitespace */
  125. do
  126. {
  127. c = fgetc(in);
  128. }
  129. while ((c == 32) && (!feof(in)));
  130. ungetc(c, in);
  131. /* Names never start with . or (*/
  132. if ((c != '_') &&
  133. ((c < 'a') || (c > 'z')) &&
  134. ((c < 'A') || (c > 'Z')))
  135. goto over;
  136. /* Read the name */
  137. t = text;
  138. do
  139. {
  140. c = fgetc(in);
  141. *t++ = c;
  142. }
  143. while (c > 32);
  144. t[-1] = 0;
  145. /* Now there should be nothing left on this line */
  146. if ((c != 10) && (c != 13))
  147. goto over;
  148. /* And put the return back */
  149. ungetc(c, in);
  150. if (t != text)
  151. {
  152. addFn(text, offset);
  153. }
  154. over:
  155. /* Skip to the end of the line */
  156. do
  157. {
  158. c = fgetc(in);
  159. }
  160. while ((c >= 32) && (!feof(in)));
  161. /* Skip over any newlines */
  162. while (((c == 10) || (c == 13)) && (!feof(in)))
  163. {
  164. c = fgetc(in);
  165. }
  166. /* And put the first non whitespace/non return char back */
  167. ungetc(c, in);
  168. }
  169. fclose(in);
  170. }
  171. static void show_profile()
  172. {
  173. int i;
  174. for (i=0; i < numFunctions; i++)
  175. {
  176. fprintf(stdout, "%08x (%6.2f%%: %6d) %s\n",
  177. functionTable[i].offset,
  178. functionTable[i].percent,
  179. functionTable[i].count,
  180. functionTable[i].name);
  181. }
  182. }
  183. int byAddress(const void *_e1, const void *_e2)
  184. {
  185. const Profile_Entry *e1 = (const Profile_Entry *)_e1;
  186. const Profile_Entry *e2 = (const Profile_Entry *)_e2;
  187. return e1->offset - e2->offset;
  188. }
  189. int byTime(const void *_e1, const void *_e2)
  190. {
  191. const Profile_Entry *e1 = (const Profile_Entry *)_e1;
  192. const Profile_Entry *e2 = (const Profile_Entry *)_e2;
  193. return e2->count - e1->count;
  194. }
  195. static void process_profile()
  196. {
  197. int next;
  198. int fn;
  199. int idx;
  200. int max;
  201. int total;
  202. /* Sort into address order */
  203. qsort(functionTable,
  204. numFunctions,
  205. sizeof(Profile_Entry),
  206. byAddress);
  207. /* Run through the profile adding it to the appropriate function */
  208. fn = -1; /* Which function are we looking at */
  209. next = -1; /* At what address should we move to the next function */
  210. idx = 0; /* Where are we in the profile */
  211. max = profile_len>>2;
  212. total = 0;
  213. for (idx = 0; idx < max; idx++)
  214. {
  215. while ((idx<<(granularity+2)) >= next)
  216. {
  217. /* Move to the next function */
  218. fn++;
  219. //fprintf(stdout, "Will be on fn %s until we pass %x\n",
  220. // functionTable[fn].name, functionTable[fn+1].offset);
  221. next = 0x7FFFFFFF;
  222. if (fn+1 < numFunctions)
  223. {
  224. next = functionTable[fn+1].offset;
  225. }
  226. }
  227. //fprintf(stdout, "fn=%d count=%d idx=%d next=%x\n",
  228. // fn, functionTable[fn].count, idx, next);
  229. functionTable[fn].count += profile[idx];
  230. total += profile[idx];
  231. }
  232. for (fn = 0; fn < numFunctions; fn++)
  233. {
  234. functionTable[fn].percent = 100.0*functionTable[fn].count/total;
  235. }
  236. fprintf(stdout, "Profile by Address\n");
  237. show_profile();
  238. /* Sort into time order */
  239. qsort(functionTable,
  240. numFunctions,
  241. sizeof(Profile_Entry),
  242. byTime);
  243. fprintf(stdout, "\n\n");
  244. fprintf(stdout, "Profile by Time\n");
  245. show_profile();
  246. }
  247. int main(int argc, const char *argv[])
  248. {
  249. read_args(argc, argv);
  250. read_profile();
  251. read_map();
  252. process_profile();
  253. return EXIT_SUCCESS;
  254. }