builtin-periodic.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. /*
  2. * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 and
  6. * only version 2 as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. */
  13. /*
  14. * A very simple perf program to periodically print the performance
  15. * counter reqested on the command line to standard out at the rate
  16. * specified.
  17. *
  18. * This is valuable for showing the output in a simple plot or
  19. * exporting the counter data for post processing. No attempt
  20. * to process the data is made.
  21. *
  22. * Scaling is not supported, use only as many counters as are
  23. * provided by the hardware.
  24. *
  25. * Math functions are support to combine counter results by using
  26. * the -m flag.
  27. *
  28. * The -r -w flags supports user signalling for input. This assumes
  29. * that a pipe/fifo is needed so the -rw cmd line arg is a string
  30. * that is the name of the named pipe to open for read/write. User
  31. * sends data on the read pipe to the process to collect a sample.
  32. * Commands are also supported on the pipe.
  33. *
  34. */
  35. #include "perf.h"
  36. #include "builtin.h"
  37. #include "util/util.h"
  38. #include "util/parse-options.h"
  39. #include "util/parse-events.h"
  40. #include "util/event.h"
  41. #include "util/evsel.h"
  42. #include "util/evlist.h"
  43. #include "util/debug.h"
  44. #include "util/header.h"
  45. #include "util/cpumap.h"
  46. #include "util/thread.h"
  47. #include <signal.h>
  48. #include <sys/types.h>
  49. #define PERF_PERIODIC_ERROR -1
  50. /* number of pieces of data on each read. */
  51. #define DATA_SIZE 2
  52. #define DEFAULT_FIFO_NAME "xxbadFiFo"
  53. #define MAX_NAMELEN 50
  54. struct perf_evlist *evsel_list;
  55. /*
  56. * command line variables and settings
  57. * Default to current process, no_inherit, process
  58. */
  59. static pid_t target_pid = -1; /* all */
  60. static bool system_wide;
  61. static int cpumask = -1; /* all */
  62. static int ncounts;
  63. static int ms_sleep = 1000; /* 1 second */
  64. static char const *operations = "nnnnnnnnnnnnnnnn"; /* nop */
  65. static bool math_enabled;
  66. static bool calc_delta;
  67. static double old_accum, accum;
  68. static int math_op_index;
  69. static char const *wfifo_name = DEFAULT_FIFO_NAME;
  70. static char const *rfifo_name = DEFAULT_FIFO_NAME;
  71. static bool use_fifo;
  72. static bool is_ratio;
  73. static FILE *fd_in, *fd_out;
  74. static FILE *tReadFifo, *tWriteFifo;
  75. /*
  76. * Raw results from perf, we track the current value and
  77. * the old value.
  78. */
  79. struct perf_raw_results_s {
  80. u64 values;
  81. u64 old_value;
  82. };
  83. /*
  84. * Everything we need to support a perf counter across multiple
  85. * CPUs. We need to support multiple file descriptors (perf_fd)
  86. * because perf requires a fd per counter, so 1 per core enabled.
  87. *
  88. * Raw results values are calculated across all the cores as they
  89. * are read.
  90. */
  91. struct perf_setup_s {
  92. int event_index;
  93. struct perf_event_attr *attr;
  94. int perf_fd[MAX_NR_CPUS];
  95. pid_t pid;
  96. int cpu;
  97. int flags;
  98. int group;
  99. struct perf_raw_results_s data;
  100. struct perf_raw_results_s totals;
  101. struct perf_raw_results_s output;
  102. };
  103. static void do_cleanup(void)
  104. {
  105. if (fd_in) {
  106. if (0 != fclose(fd_in))
  107. error("Error closing fd_in\n");
  108. }
  109. if (fd_out) {
  110. if (0 != fclose(fd_out))
  111. error("Error closing fd_out\n");
  112. }
  113. if (use_fifo) {
  114. if (0 != unlink(rfifo_name))
  115. error("Error unlinking rfifo\n");
  116. if (0 != unlink(wfifo_name))
  117. error("Error unlinking wfifo\n");
  118. }
  119. }
  120. /*
  121. * Unexpected signal for error indication, cleanup
  122. */
  123. static int sig_dummy;
  124. static void sig_do_cleanup(int sig)
  125. {
  126. sig_dummy = sig;
  127. do_cleanup();
  128. exit(0);
  129. }
  130. #define PERIODIC_MAX_STRLEN 100
  131. /*
  132. * Delay for either a timed period or the wait on the read_fifo
  133. */
  134. static void delay(unsigned long milli)
  135. {
  136. char tmp_stg[PERIODIC_MAX_STRLEN];
  137. int done;
  138. int ret;
  139. if (use_fifo) {
  140. do {
  141. done = true;
  142. ret = fscanf(tReadFifo, "%s", tmp_stg);
  143. if (ret == 0)
  144. return;
  145. /*
  146. * Look for a command request, and if we get a command
  147. * Need to process and then wait again w/o sending data.
  148. */
  149. if (strncmp(tmp_stg, "PID", strnlen(tmp_stg,
  150. PERIODIC_MAX_STRLEN)) == 0) {
  151. fprintf(fd_out, " %u\n", getpid());
  152. fflush(fd_out);
  153. done = false;
  154. } else if (strncmp(tmp_stg, "EXIT",
  155. strnlen(tmp_stg, PERIODIC_MAX_STRLEN))
  156. == 0) {
  157. do_cleanup();
  158. exit(0);
  159. }
  160. } while (done != true);
  161. } else
  162. usleep(milli*1000);
  163. }
  164. /*
  165. * Create a perf counter event.
  166. * Some interesting behaviour that is not documented anywhere else:
  167. * the CPU will not work if out of range.
  168. * The CPU will only work for a single CPU, so to collect the counts
  169. * on the system in SMP based systems a counter needs to be created
  170. * for each CPU.
  171. */
  172. static int create_perf_counter(struct perf_setup_s *p)
  173. {
  174. struct cpu_map *cpus;
  175. int cpu;
  176. cpus = cpu_map__new(NULL);
  177. if (p == NULL)
  178. return PERF_PERIODIC_ERROR;
  179. for (cpu = 0; cpu < cpus->nr; cpu++) {
  180. if (((1 << cpu) & cpumask) == 0)
  181. continue;
  182. p->perf_fd[cpu] = sys_perf_event_open(p->attr, target_pid, cpu,
  183. -1, 0);
  184. if (p->perf_fd[cpu] < 0)
  185. return PERF_PERIODIC_ERROR;
  186. }
  187. return 0;
  188. }
  189. /*
  190. * Perf init setup
  191. */
  192. static int perf_setup_init(struct perf_setup_s *p)
  193. {
  194. if (p == NULL)
  195. return PERF_PERIODIC_ERROR;
  196. bzero(p, sizeof(struct perf_setup_s));
  197. p->group = -1;
  198. p->flags = 0;
  199. p->output.values = 0;
  200. p->output.old_value = 0;
  201. p->data.values = 0;
  202. p->data.old_value = 0;
  203. p->totals.old_value = 0;
  204. p->totals.values = 0;
  205. return 0;
  206. }
  207. /*
  208. * Read in ALL the performance counters configured for the CPU,
  209. * one performance monitor per core that was configured during
  210. * "all" mode
  211. */
  212. static int perf_setup_read(struct perf_setup_s *p)
  213. {
  214. u64 data[DATA_SIZE];
  215. int i, status;
  216. p->totals.values = 0;
  217. p->data.values = 0;
  218. for (i = 0; i < MAX_NR_CPUS; i++) {
  219. if (p->perf_fd[i] == 0)
  220. continue;
  221. status = read(p->perf_fd[i], &data, sizeof(data));
  222. p->data.values += data[0];
  223. p->totals.values += data[0];
  224. }
  225. /*
  226. * Normally we show totals, we want to support
  227. * showing deltas from the previous value so external apps do not have
  228. * to do this...
  229. */
  230. if (calc_delta) {
  231. p->output.values = p->data.values - p->data.old_value;
  232. p->data.old_value = p->data.values;
  233. } else
  234. p->output.values = p->totals.values;
  235. return 0;
  236. }
  237. static int perf_setup_show(struct perf_setup_s *p)
  238. {
  239. if (p == NULL)
  240. return PERF_PERIODIC_ERROR;
  241. fprintf(fd_out, " %llu", p->output.values);
  242. return 0;
  243. }
  244. static const char * const periodic_usage[] = {
  245. "perf periodic [<options>]",
  246. NULL
  247. };
  248. static const struct option options[] = {
  249. OPT_CALLBACK('e', "event", &evsel_list, "event",
  250. "event selector. use 'perf list' to list available events",
  251. parse_events_option),
  252. OPT_STRING('m', "math-operations", &operations, "nnnnnn",
  253. "math operation to perform on values collected asmd in order"),
  254. OPT_STRING('r', "readpipe", &rfifo_name, "xxbadFiFo",
  255. "wait for a user input fifo - will be created"),
  256. OPT_STRING('w', "writepipe", &wfifo_name, "xxbadFifo",
  257. "write data out on this pipe - pipe is created"),
  258. OPT_INTEGER('i', "increment", &ncounts,
  259. "number of times periods to count/iterate (default 0-forever)"),
  260. OPT_INTEGER('p', "pid", &target_pid,
  261. "stat events on existing process id"),
  262. OPT_INTEGER('c', "cpumask", &cpumask,
  263. "cpumask to enable counters, default all (-1)"),
  264. OPT_INTEGER('s', "sleep", &ms_sleep,
  265. "how long to sleep in ms between each sample (default 1000)"),
  266. OPT_BOOLEAN('a', "all-cpus", &system_wide,
  267. "system-wide collection from all CPUs overrides cpumask"),
  268. OPT_BOOLEAN('d', "delta", &calc_delta,
  269. "calculate and display the delta values math funcs will use delta"),
  270. OPT_INCR('v', "verbose", &verbose,
  271. "be more verbose (show counter open errors, etc)"),
  272. OPT_END()
  273. };
  274. /*
  275. * After every period we reset any math that was performed.
  276. */
  277. static void reset_math(void)
  278. {
  279. math_op_index = 0;
  280. old_accum = accum;
  281. accum = 0;
  282. }
  283. static void do_math_op(struct perf_setup_s *p)
  284. {
  285. if (!math_enabled)
  286. return;
  287. switch (operations[math_op_index++]) {
  288. case 'm':
  289. accum *= (double)p->output.values; break;
  290. case 'a':
  291. accum += (double)p->output.values; break;
  292. case 's':
  293. accum -= (double)p->output.values; break;
  294. case 'd':
  295. accum /= (double)p->output.values; break;
  296. case 'z':
  297. accum = 0; break;
  298. case 't':
  299. accum = (double)p->output.values; break; /*transfer*/
  300. case 'T':
  301. accum += old_accum; break; /*total*/
  302. case 'i': /* ignore */
  303. default:
  304. break;
  305. }
  306. }
  307. int cmd_periodic(int argc, const char **argv, const char *prefix __used)
  308. {
  309. int status = 0;
  310. int c, i;
  311. struct perf_setup_s *p[MAX_COUNTERS];
  312. struct perf_evsel *counter;
  313. FILE *fp;
  314. int nr_counters = 0;
  315. evsel_list = perf_evlist__new(NULL, NULL);
  316. if (evsel_list == NULL)
  317. return -ENOMEM;
  318. argc = parse_options(argc, argv, options, periodic_usage,
  319. PARSE_OPT_STOP_AT_NON_OPTION);
  320. if (system_wide)
  321. cpumask = -1;
  322. /*
  323. * The r & w option redirects stdout to a newly created pipe and
  324. * waits for input on the read pipe before continuing
  325. */
  326. fd_in = stdin;
  327. fd_out = stdout;
  328. if (strncmp(rfifo_name, DEFAULT_FIFO_NAME,
  329. strnlen(rfifo_name, MAX_NAMELEN))) {
  330. fp = fopen(rfifo_name, "r");
  331. if (fp != NULL) {
  332. fclose(fp);
  333. remove(rfifo_name);
  334. }
  335. if (mkfifo(rfifo_name, 0777) == -1) {
  336. error("Could not open read fifo\n");
  337. do_cleanup();
  338. return PERF_PERIODIC_ERROR;
  339. }
  340. tReadFifo = fopen(rfifo_name, "r+");
  341. if (tReadFifo == 0) {
  342. do_cleanup();
  343. error("Could not open read fifo file\n");
  344. return PERF_PERIODIC_ERROR;
  345. }
  346. use_fifo = true;
  347. }
  348. if (strncmp(wfifo_name, DEFAULT_FIFO_NAME,
  349. strnlen(wfifo_name, MAX_NAMELEN))) {
  350. fp = fopen(wfifo_name, "r");
  351. if (fp != NULL) {
  352. fclose(fp);
  353. remove(wfifo_name);
  354. }
  355. if (mkfifo(wfifo_name, 0777) == -1) {
  356. do_cleanup();
  357. error("Could not open write fifo\n");
  358. return PERF_PERIODIC_ERROR;
  359. }
  360. fd_out = fopen(wfifo_name, "w+");
  361. if (fd_out == 0) {
  362. do_cleanup();
  363. error("Could not open write fifo file\n");
  364. return PERF_PERIODIC_ERROR;
  365. }
  366. tWriteFifo = fd_out;
  367. }
  368. math_enabled = (operations[0] != 'n');
  369. /*
  370. * If we don't ignore SIG_PIPE then when the other side
  371. * of a pipe closes we shutdown too...
  372. */
  373. signal(SIGPIPE, SIG_IGN);
  374. signal(SIGINT, sig_do_cleanup);
  375. signal(SIGQUIT, sig_do_cleanup);
  376. signal(SIGKILL, sig_do_cleanup);
  377. signal(SIGTERM, sig_do_cleanup);
  378. i = 0;
  379. list_for_each_entry(counter, &evsel_list->entries, node) {
  380. p[i] = malloc(sizeof(struct perf_setup_s));
  381. if (p[i] == NULL) {
  382. error("Error allocating perf_setup_s\n");
  383. do_cleanup();
  384. return PERF_PERIODIC_ERROR;
  385. }
  386. bzero(p[i], sizeof(struct perf_setup_s));
  387. perf_setup_init(p[i]);
  388. p[i]->attr = &(counter->attr);
  389. p[i]->event_index = counter->idx;
  390. if (create_perf_counter(p[i]) < 0) {
  391. do_cleanup();
  392. die("Not all events could be opened.\n");
  393. return PERF_PERIODIC_ERROR;
  394. }
  395. i++;
  396. nr_counters++;
  397. }
  398. i = 0;
  399. while (1) {
  400. /*
  401. * Wait first otherwise single sample will print w/o signal
  402. * when using the -u (user signal) flag
  403. */
  404. delay(ms_sleep);
  405. /*
  406. * Do the collection, read and then perform any math operations
  407. */
  408. for (c = 0; c < nr_counters; c++) {
  409. status = perf_setup_read(p[c]);
  410. do_math_op(p[c]);
  411. }
  412. /*
  413. * After all collection and math, we perform one last math
  414. * to allow totaling, if enabled etc, then either printout
  415. * a single float value when the math is enabled or ...
  416. */
  417. if (math_enabled) {
  418. do_math_op(p[c]);
  419. if (is_ratio)
  420. fprintf(fd_out, "%#f\n", accum*100);
  421. else
  422. fprintf(fd_out, "%#f\n", accum);
  423. } else {
  424. /*
  425. * ... print out one integer value for each counter
  426. */
  427. for (c = 0; c < nr_counters; c++)
  428. status = perf_setup_show(p[c]);
  429. fprintf(fd_out, "\n");
  430. }
  431. /*
  432. * Did the user give us an iteration count?
  433. */
  434. if ((ncounts != 0) && (++i >= ncounts))
  435. break;
  436. reset_math();
  437. fflush(fd_out); /* make sure data is flushed out the pipe*/
  438. }
  439. do_cleanup();
  440. return status;
  441. }