kerneltop.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810
  1. /*
  2. * kerneltop.c: show top kernel functions - performance counters showcase
  3. Build with:
  4. cc -O6 -Wall `pkg-config --cflags --libs glib-2.0` -o kerneltop kerneltop.c
  5. Sample output:
  6. ------------------------------------------------------------------------------
  7. KernelTop: 2669 irqs/sec [NMI, cache-misses/cache-refs], (all, cpu: 2)
  8. ------------------------------------------------------------------------------
  9. weight RIP kernel function
  10. ______ ________________ _______________
  11. 35.20 - ffffffff804ce74b : skb_copy_and_csum_dev
  12. 33.00 - ffffffff804cb740 : sock_alloc_send_skb
  13. 31.26 - ffffffff804ce808 : skb_push
  14. 22.43 - ffffffff80510004 : tcp_established_options
  15. 19.00 - ffffffff8027d250 : find_get_page
  16. 15.76 - ffffffff804e4fc9 : eth_type_trans
  17. 15.20 - ffffffff804d8baa : dst_release
  18. 14.86 - ffffffff804cf5d8 : skb_release_head_state
  19. 14.00 - ffffffff802217d5 : read_hpet
  20. 12.00 - ffffffff804ffb7f : __ip_local_out
  21. 11.97 - ffffffff804fc0c8 : ip_local_deliver_finish
  22. 8.54 - ffffffff805001a3 : ip_queue_xmit
  23. Started by Ingo Molnar <mingo@redhat.com>
  24. Improvements and fixes by:
  25. Arjan van de Ven <arjan@linux.intel.com>
  26. Yanmin Zhang <yanmin.zhang@intel.com>
  27. Mike Galbraith <efault@gmx.de>
  28. Released under the GPL v2. (and only v2, not any later version)
  29. */
  30. #define _GNU_SOURCE
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33. #include <sys/time.h>
  34. #include <unistd.h>
  35. #include <stdint.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include <getopt.h>
  39. #include <assert.h>
  40. #include <fcntl.h>
  41. #include <stdio.h>
  42. #include <errno.h>
  43. #include <ctype.h>
  44. #include <time.h>
  45. #include <glib.h>
  46. #include <sys/syscall.h>
  47. #include <sys/ioctl.h>
  48. #include <sys/poll.h>
  49. #include <sys/prctl.h>
  50. #include <sys/wait.h>
  51. #include <sys/uio.h>
  52. #include <linux/unistd.h>
  53. #include "perfcounters.h"
  54. const char *event_types [] = {
  55. "CPU cycles",
  56. "instructions",
  57. "cache-refs",
  58. "cache-misses",
  59. "branches",
  60. "branch-misses",
  61. "bus cycles"
  62. };
  63. const unsigned int default_count[] = {
  64. 1000000,
  65. 1000000,
  66. 10000,
  67. 10000,
  68. 1000000,
  69. 10000,
  70. };
  71. static __u64 count_filter = 100;
  72. static int event_count[MAX_COUNTERS];
  73. static int tid = -1;
  74. static int profile_cpu = -1;
  75. static int nr_cpus = 0;
  76. static int nmi = 1;
  77. static int group = 0;
  78. static char *vmlinux;
  79. static char *sym_filter;
  80. static unsigned long filter_start;
  81. static unsigned long filter_end;
  82. static int delay_secs = 2;
  83. static int zero;
  84. static int dump_symtab;
  85. struct source_line {
  86. uint64_t EIP;
  87. unsigned long count;
  88. char *line;
  89. };
  90. static GList *lines;
  91. static void display_help(void)
  92. {
  93. printf(
  94. "Usage: kerneltop [<options>]\n\n"
  95. "KernelTop Options (up to %d event types can be specified at once):\n\n",
  96. MAX_COUNTERS);
  97. printf(
  98. " -e EID --event=EID # event type ID [default: 0]\n"
  99. " 0: CPU cycles\n"
  100. " 1: instructions\n"
  101. " 2: cache accesses\n"
  102. " 3: cache misses\n"
  103. " 4: branch instructions\n"
  104. " 5: branch prediction misses\n"
  105. " 6: bus cycles\n\n"
  106. " rNNN: raw PMU events (eventsel+umask)\n\n"
  107. " -c CNT --count=CNT # event period to sample\n\n"
  108. " -C CPU --cpu=CPU # CPU (-1 for all) [default: -1]\n"
  109. " -p PID --pid=PID # PID of sampled task (-1 for all) [default: -1]\n\n"
  110. " -d delay --delay=<seconds> # sampling/display delay [default: 2]\n"
  111. " -f CNT --filter=CNT # min-event-count filter [default: 100]\n\n"
  112. " -s symbol --symbol=<symbol> # function to be showed annotated one-shot\n"
  113. " -x path --vmlinux=<path> # the vmlinux binary, required for -s use:\n"
  114. " -z --zero # zero counts after display\n"
  115. " -D --dump_symtab # dump symbol table to stderr on startup\n"
  116. "\n");
  117. exit(0);
  118. }
  119. static void process_options(int argc, char *argv[])
  120. {
  121. int error = 0, counter;
  122. for (;;) {
  123. int option_index = 0;
  124. /** Options for getopt */
  125. static struct option long_options[] = {
  126. {"count", required_argument, NULL, 'c'},
  127. {"cpu", required_argument, NULL, 'C'},
  128. {"delay", required_argument, NULL, 'd'},
  129. {"dump_symtab", no_argument, NULL, 'D'},
  130. {"event", required_argument, NULL, 'e'},
  131. {"filter", required_argument, NULL, 'f'},
  132. {"group", required_argument, NULL, 'g'},
  133. {"help", no_argument, NULL, 'h'},
  134. {"nmi", required_argument, NULL, 'n'},
  135. {"pid", required_argument, NULL, 'p'},
  136. {"vmlinux", required_argument, NULL, 'x'},
  137. {"symbol", required_argument, NULL, 's'},
  138. {"zero", no_argument, NULL, 'z'},
  139. {NULL, 0, NULL, 0 }
  140. };
  141. int c = getopt_long(argc, argv, "c:C:d:De:f:g:hn:p:s:x:z",
  142. long_options, &option_index);
  143. if (c == -1)
  144. break;
  145. switch (c) {
  146. case 'c':
  147. event_count[nr_counters] = atoi(optarg); break;
  148. case 'C':
  149. /* CPU and PID are mutually exclusive */
  150. if (tid != -1) {
  151. printf("WARNING: CPU switch overriding PID\n");
  152. sleep(1);
  153. tid = -1;
  154. }
  155. profile_cpu = atoi(optarg); break;
  156. case 'd': delay_secs = atoi(optarg); break;
  157. case 'D': dump_symtab = 1; break;
  158. case 'e': error = parse_events(optarg); break;
  159. case 'f': count_filter = atoi(optarg); break;
  160. case 'g': group = atoi(optarg); break;
  161. case 'h': display_help(); break;
  162. case 'n': nmi = atoi(optarg); break;
  163. case 'p':
  164. /* CPU and PID are mutually exclusive */
  165. if (profile_cpu != -1) {
  166. printf("WARNING: PID switch overriding CPU\n");
  167. sleep(1);
  168. profile_cpu = -1;
  169. }
  170. tid = atoi(optarg); break;
  171. case 's': sym_filter = strdup(optarg); break;
  172. case 'x': vmlinux = strdup(optarg); break;
  173. case 'z': zero = 1; break;
  174. default: error = 1; break;
  175. }
  176. }
  177. if (error)
  178. display_help();
  179. if (!nr_counters) {
  180. nr_counters = 1;
  181. event_id[0] = 0;
  182. }
  183. for (counter = 0; counter < nr_counters; counter++) {
  184. if (event_count[counter])
  185. continue;
  186. if (event_id[counter] < PERF_HW_EVENTS_MAX)
  187. event_count[counter] = default_count[event_id[counter]];
  188. else
  189. event_count[counter] = 100000;
  190. }
  191. }
  192. static uint64_t min_ip;
  193. static uint64_t max_ip = -1ll;
  194. struct sym_entry {
  195. unsigned long long addr;
  196. char *sym;
  197. unsigned long count[MAX_COUNTERS];
  198. int skip;
  199. GList *source;
  200. };
  201. #define MAX_SYMS 100000
  202. static int sym_table_count;
  203. struct sym_entry *sym_filter_entry;
  204. static struct sym_entry sym_table[MAX_SYMS];
  205. static void show_details(struct sym_entry *sym);
  206. /*
  207. * Ordering weight: count-1 * count-1 * ... / count-n
  208. */
  209. static double sym_weight(const struct sym_entry *sym)
  210. {
  211. double weight;
  212. int counter;
  213. weight = sym->count[0];
  214. for (counter = 1; counter < nr_counters-1; counter++)
  215. weight *= sym->count[counter];
  216. weight /= (sym->count[counter] + 1);
  217. return weight;
  218. }
  219. static int compare(const void *__sym1, const void *__sym2)
  220. {
  221. const struct sym_entry *sym1 = __sym1, *sym2 = __sym2;
  222. return sym_weight(sym1) < sym_weight(sym2);
  223. }
  224. static time_t last_refresh;
  225. static long events;
  226. static long userspace_events;
  227. static const char CONSOLE_CLEAR[] = "";
  228. static struct sym_entry tmp[MAX_SYMS];
  229. static void print_sym_table(void)
  230. {
  231. int i, printed;
  232. int counter;
  233. float events_per_sec = events/delay_secs;
  234. float kevents_per_sec = (events-userspace_events)/delay_secs;
  235. memcpy(tmp, sym_table, sizeof(sym_table[0])*sym_table_count);
  236. qsort(tmp, sym_table_count, sizeof(tmp[0]), compare);
  237. write(1, CONSOLE_CLEAR, strlen(CONSOLE_CLEAR));
  238. printf(
  239. "------------------------------------------------------------------------------\n");
  240. printf( " KernelTop:%8.0f irqs/sec kernel:%3.1f%% [%s, ",
  241. events_per_sec,
  242. 100.0 - (100.0*((events_per_sec-kevents_per_sec)/events_per_sec)),
  243. nmi ? "NMI" : "IRQ");
  244. if (nr_counters == 1)
  245. printf("%d ", event_count[0]);
  246. for (counter = 0; counter < nr_counters; counter++) {
  247. if (counter)
  248. printf("/");
  249. if (event_id[counter] < PERF_HW_EVENTS_MAX)
  250. printf( "%s", event_types[event_id[counter]]);
  251. else
  252. printf( "raw:%04lx", event_id[counter]);
  253. }
  254. printf( "], ");
  255. if (tid != -1)
  256. printf(" (tid: %d", tid);
  257. else
  258. printf(" (all");
  259. if (profile_cpu != -1)
  260. printf(", cpu: %d)\n", profile_cpu);
  261. else {
  262. if (tid != -1)
  263. printf(")\n");
  264. else
  265. printf(", %d CPUs)\n", nr_cpus);
  266. }
  267. printf("------------------------------------------------------------------------------\n\n");
  268. if (nr_counters == 1)
  269. printf(" events");
  270. else
  271. printf(" weight events");
  272. printf(" RIP kernel function\n"
  273. " ______ ______ ________________ _______________\n\n"
  274. );
  275. printed = 0;
  276. for (i = 0; i < sym_table_count; i++) {
  277. int count;
  278. if (nr_counters == 1) {
  279. if (printed <= 18 &&
  280. tmp[i].count[0] >= count_filter) {
  281. printf("%19.2f - %016llx : %s\n",
  282. sym_weight(tmp + i), tmp[i].addr, tmp[i].sym);
  283. printed++;
  284. }
  285. } else {
  286. if (printed <= 18 &&
  287. tmp[i].count[0] >= count_filter) {
  288. printf("%8.1f %10ld - %016llx : %s\n",
  289. sym_weight(tmp + i),
  290. tmp[i].count[0],
  291. tmp[i].addr, tmp[i].sym);
  292. printed++;
  293. }
  294. }
  295. /*
  296. * Add decay to the counts:
  297. */
  298. for (count = 0; count < nr_counters; count++)
  299. sym_table[i].count[count] = zero ? 0 : sym_table[i].count[count] * 7 / 8;
  300. }
  301. if (sym_filter_entry)
  302. show_details(sym_filter_entry);
  303. last_refresh = time(NULL);
  304. {
  305. struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
  306. if (poll(&stdin_poll, 1, 0) == 1) {
  307. printf("key pressed - exiting.\n");
  308. exit(0);
  309. }
  310. }
  311. }
  312. static int read_symbol(FILE *in, struct sym_entry *s)
  313. {
  314. static int filter_match = 0;
  315. char *sym, stype;
  316. char str[500];
  317. int rc, pos;
  318. rc = fscanf(in, "%llx %c %499s", &s->addr, &stype, str);
  319. if (rc == EOF)
  320. return -1;
  321. assert(rc == 3);
  322. /* skip until end of line: */
  323. pos = strlen(str);
  324. do {
  325. rc = fgetc(in);
  326. if (rc == '\n' || rc == EOF || pos >= 499)
  327. break;
  328. str[pos] = rc;
  329. pos++;
  330. } while (1);
  331. str[pos] = 0;
  332. sym = str;
  333. /* Filter out known duplicates and non-text symbols. */
  334. if (!strcmp(sym, "_text"))
  335. return 1;
  336. if (!min_ip && !strcmp(sym, "_stext"))
  337. return 1;
  338. if (!strcmp(sym, "_etext") || !strcmp(sym, "_sinittext"))
  339. return 1;
  340. if (stype != 'T' && stype != 't')
  341. return 1;
  342. if (!strncmp("init_module", sym, 11) || !strncmp("cleanup_module", sym, 14))
  343. return 1;
  344. if (strstr(sym, "_text_start") || strstr(sym, "_text_end"))
  345. return 1;
  346. s->sym = malloc(strlen(str));
  347. assert(s->sym);
  348. strcpy((char *)s->sym, str);
  349. s->skip = 0;
  350. /* Tag events to be skipped. */
  351. if (!strcmp("default_idle", s->sym) || !strcmp("cpu_idle", s->sym))
  352. s->skip = 1;
  353. if (!strcmp("enter_idle", s->sym) || !strcmp("exit_idle", s->sym))
  354. s->skip = 1;
  355. if (filter_match == 1) {
  356. filter_end = s->addr;
  357. filter_match = -1;
  358. if (filter_end - filter_start > 10000) {
  359. printf("hm, too large filter symbol <%s> - skipping.\n",
  360. sym_filter);
  361. printf("symbol filter start: %016lx\n", filter_start);
  362. printf(" end: %016lx\n", filter_end);
  363. filter_end = filter_start = 0;
  364. sym_filter = NULL;
  365. sleep(1);
  366. }
  367. }
  368. if (filter_match == 0 && sym_filter && !strcmp(s->sym, sym_filter)) {
  369. filter_match = 1;
  370. filter_start = s->addr;
  371. }
  372. return 0;
  373. }
  374. int compare_addr(const void *__sym1, const void *__sym2)
  375. {
  376. const struct sym_entry *sym1 = __sym1, *sym2 = __sym2;
  377. return sym1->addr > sym2->addr;
  378. }
  379. static void sort_symbol_table(void)
  380. {
  381. int i, dups;
  382. do {
  383. qsort(sym_table, sym_table_count, sizeof(sym_table[0]), compare_addr);
  384. for (i = 0, dups = 0; i < sym_table_count; i++) {
  385. if (sym_table[i].addr == sym_table[i+1].addr) {
  386. sym_table[i+1].addr = -1ll;
  387. dups++;
  388. }
  389. }
  390. sym_table_count -= dups;
  391. } while(dups);
  392. }
  393. static void parse_symbols(void)
  394. {
  395. struct sym_entry *last;
  396. FILE *kallsyms = fopen("/proc/kallsyms", "r");
  397. if (!kallsyms) {
  398. printf("Could not open /proc/kallsyms - no CONFIG_KALLSYMS_ALL=y?\n");
  399. exit(-1);
  400. }
  401. while (!feof(kallsyms)) {
  402. if (read_symbol(kallsyms, &sym_table[sym_table_count]) == 0) {
  403. sym_table_count++;
  404. assert(sym_table_count <= MAX_SYMS);
  405. }
  406. }
  407. sort_symbol_table();
  408. min_ip = sym_table[0].addr;
  409. max_ip = sym_table[sym_table_count-1].addr;
  410. last = sym_table + sym_table_count++;
  411. last->addr = -1ll;
  412. last->sym = "<end>";
  413. if (filter_end) {
  414. int count;
  415. for (count=0; count < sym_table_count; count ++) {
  416. if (!strcmp(sym_table[count].sym, sym_filter)) {
  417. sym_filter_entry = &sym_table[count];
  418. break;
  419. }
  420. }
  421. }
  422. if (dump_symtab) {
  423. int i;
  424. for (i = 0; i < sym_table_count; i++)
  425. fprintf(stderr, "%llx %s\n",
  426. sym_table[i].addr, sym_table[i].sym);
  427. }
  428. }
  429. static void parse_vmlinux(char *filename)
  430. {
  431. FILE *file;
  432. char command[PATH_MAX*2];
  433. if (!filename)
  434. return;
  435. sprintf(command, "objdump --start-address=0x%016lx --stop-address=0x%016lx -dS %s", filter_start, filter_end, filename);
  436. file = popen(command, "r");
  437. if (!file)
  438. return;
  439. while (!feof(file)) {
  440. struct source_line *src;
  441. size_t dummy = 0;
  442. char *c;
  443. src = malloc(sizeof(struct source_line));
  444. assert(src != NULL);
  445. memset(src, 0, sizeof(struct source_line));
  446. if (getline(&src->line, &dummy, file) < 0)
  447. break;
  448. if (!src->line)
  449. break;
  450. c = strchr(src->line, '\n');
  451. if (c)
  452. *c = 0;
  453. lines = g_list_prepend(lines, src);
  454. if (strlen(src->line)>8 && src->line[8] == ':')
  455. src->EIP = strtoull(src->line, NULL, 16);
  456. if (strlen(src->line)>8 && src->line[16] == ':')
  457. src->EIP = strtoull(src->line, NULL, 16);
  458. }
  459. pclose(file);
  460. lines = g_list_reverse(lines);
  461. }
  462. static void record_precise_ip(uint64_t ip)
  463. {
  464. struct source_line *line;
  465. GList *item;
  466. item = g_list_first(lines);
  467. while (item) {
  468. line = item->data;
  469. if (line->EIP == ip)
  470. line->count++;
  471. if (line->EIP > ip)
  472. break;
  473. item = g_list_next(item);
  474. }
  475. }
  476. static void lookup_sym_in_vmlinux(struct sym_entry *sym)
  477. {
  478. struct source_line *line;
  479. GList *item;
  480. char pattern[PATH_MAX];
  481. sprintf(pattern, "<%s>:", sym->sym);
  482. item = g_list_first(lines);
  483. while (item) {
  484. line = item->data;
  485. if (strstr(line->line, pattern)) {
  486. sym->source = item;
  487. break;
  488. }
  489. item = g_list_next(item);
  490. }
  491. }
  492. void show_lines(GList *item_queue, int item_queue_count)
  493. {
  494. int i;
  495. struct source_line *line;
  496. for (i = 0; i < item_queue_count; i++) {
  497. line = item_queue->data;
  498. printf("%8li\t%s\n", line->count, line->line);
  499. item_queue = g_list_next(item_queue);
  500. }
  501. }
  502. #define TRACE_COUNT 3
  503. static void show_details(struct sym_entry *sym)
  504. {
  505. struct source_line *line;
  506. GList *item;
  507. int displayed = 0;
  508. GList *item_queue = NULL;
  509. int item_queue_count = 0;
  510. if (!sym->source)
  511. lookup_sym_in_vmlinux(sym);
  512. if (!sym->source)
  513. return;
  514. printf("Showing details for %s\n", sym->sym);
  515. item = sym->source;
  516. while (item) {
  517. line = item->data;
  518. if (displayed && strstr(line->line, ">:"))
  519. break;
  520. if (!item_queue_count)
  521. item_queue = item;
  522. item_queue_count ++;
  523. if (line->count >= count_filter) {
  524. show_lines(item_queue, item_queue_count);
  525. item_queue_count = 0;
  526. item_queue = NULL;
  527. } else if (item_queue_count > TRACE_COUNT) {
  528. item_queue = g_list_next(item_queue);
  529. item_queue_count --;
  530. }
  531. line->count = 0;
  532. displayed++;
  533. if (displayed > 300)
  534. break;
  535. item = g_list_next(item);
  536. }
  537. }
  538. /*
  539. * Binary search in the histogram table and record the hit:
  540. */
  541. static void record_ip(uint64_t ip, int counter)
  542. {
  543. int left_idx, middle_idx, right_idx, idx;
  544. unsigned long left, middle, right;
  545. record_precise_ip(ip);
  546. left_idx = 0;
  547. right_idx = sym_table_count-1;
  548. assert(ip <= max_ip && ip >= min_ip);
  549. while (left_idx + 1 < right_idx) {
  550. middle_idx = (left_idx + right_idx) / 2;
  551. left = sym_table[ left_idx].addr;
  552. middle = sym_table[middle_idx].addr;
  553. right = sym_table[ right_idx].addr;
  554. if (!(left <= middle && middle <= right)) {
  555. printf("%016lx...\n%016lx...\n%016lx\n", left, middle, right);
  556. printf("%d %d %d\n", left_idx, middle_idx, right_idx);
  557. }
  558. assert(left <= middle && middle <= right);
  559. if (!(left <= ip && ip <= right)) {
  560. printf(" left: %016lx\n", left);
  561. printf(" ip: %016lx\n", ip);
  562. printf("right: %016lx\n", right);
  563. }
  564. assert(left <= ip && ip <= right);
  565. /*
  566. * [ left .... target .... middle .... right ]
  567. * => right := middle
  568. */
  569. if (ip < middle) {
  570. right_idx = middle_idx;
  571. continue;
  572. }
  573. /*
  574. * [ left .... middle ... target ... right ]
  575. * => left := middle
  576. */
  577. left_idx = middle_idx;
  578. }
  579. idx = left_idx;
  580. if (!sym_table[idx].skip)
  581. sym_table[idx].count[counter]++;
  582. else events--;
  583. }
  584. static void process_event(uint64_t ip, int counter)
  585. {
  586. events++;
  587. if (ip < min_ip || ip > max_ip) {
  588. userspace_events++;
  589. return;
  590. }
  591. record_ip(ip, counter);
  592. }
  593. int main(int argc, char *argv[])
  594. {
  595. struct pollfd event_array[MAX_NR_CPUS][MAX_COUNTERS];
  596. struct perf_counter_hw_event hw_event;
  597. int fd[MAX_NR_CPUS][MAX_COUNTERS];
  598. int i, counter, group_fd;
  599. unsigned int cpu;
  600. uint64_t ip;
  601. ssize_t res;
  602. int ret;
  603. process_options(argc, argv);
  604. nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
  605. if (tid != -1 || profile_cpu != -1)
  606. nr_cpus = 1;
  607. assert(nr_cpus <= MAX_NR_CPUS);
  608. for (i = 0; i < nr_cpus; i++) {
  609. group_fd = -1;
  610. for (counter = 0; counter < nr_counters; counter++) {
  611. cpu = profile_cpu;
  612. if (tid == -1 && profile_cpu == -1)
  613. cpu = i;
  614. memset(&hw_event, 0, sizeof(hw_event));
  615. hw_event.type = event_id[counter];
  616. hw_event.raw = event_raw[counter];
  617. hw_event.irq_period = event_count[counter];
  618. hw_event.record_type = PERF_RECORD_IRQ;
  619. hw_event.nmi = nmi;
  620. fd[i][counter] = sys_perf_counter_open(&hw_event, tid, cpu, group_fd, 0);
  621. fcntl(fd[i][counter], F_SETFL, O_NONBLOCK);
  622. if (fd[i][counter] < 0) {
  623. printf("kerneltop error: syscall returned with %d (%s)\n",
  624. fd[i][counter], strerror(-fd[i][counter]));
  625. if (fd[i][counter] == -1)
  626. printf("Are you root?\n");
  627. exit(-1);
  628. }
  629. assert(fd[i][counter] >= 0);
  630. /*
  631. * First counter acts as the group leader:
  632. */
  633. if (group && group_fd == -1)
  634. group_fd = fd[i][counter];
  635. event_array[i][counter].fd = fd[i][counter];
  636. event_array[i][counter].events = POLLIN;
  637. }
  638. }
  639. parse_symbols();
  640. if (vmlinux && sym_filter_entry)
  641. parse_vmlinux(vmlinux);
  642. printf("KernelTop refresh period: %d seconds\n", delay_secs);
  643. last_refresh = time(NULL);
  644. while (1) {
  645. int hits = events;
  646. for (i = 0; i < nr_cpus; i++) {
  647. for (counter = 0; counter < nr_counters; counter++) {
  648. res = read(fd[i][counter], (char *) &ip, sizeof(ip));
  649. if (res > 0) {
  650. assert(res == sizeof(ip));
  651. process_event(ip, counter);
  652. }
  653. }
  654. }
  655. if (time(NULL) >= last_refresh + delay_secs) {
  656. print_sym_table();
  657. events = userspace_events = 0;
  658. }
  659. if (hits == events)
  660. ret = poll(event_array[0], nr_cpus, 1000);
  661. hits = events;
  662. }
  663. return 0;
  664. }