stat-display.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166
  1. #include <stdio.h>
  2. #include <inttypes.h>
  3. #include <linux/time64.h>
  4. #include <math.h>
  5. #include "evlist.h"
  6. #include "evsel.h"
  7. #include "stat.h"
  8. #include "top.h"
  9. #include "thread_map.h"
  10. #include "cpumap.h"
  11. #include "string2.h"
  12. #include "sane_ctype.h"
  13. #include "cgroup.h"
  14. #include <math.h>
  15. #include <api/fs/fs.h>
  16. #define CNTR_NOT_SUPPORTED "<not supported>"
  17. #define CNTR_NOT_COUNTED "<not counted>"
  18. static bool is_duration_time(struct perf_evsel *evsel)
  19. {
  20. return !strcmp(evsel->name, "duration_time");
  21. }
  22. static void print_running(struct perf_stat_config *config,
  23. u64 run, u64 ena)
  24. {
  25. if (config->csv_output) {
  26. fprintf(config->output, "%s%" PRIu64 "%s%.2f",
  27. config->csv_sep,
  28. run,
  29. config->csv_sep,
  30. ena ? 100.0 * run / ena : 100.0);
  31. } else if (run != ena) {
  32. fprintf(config->output, " (%.2f%%)", 100.0 * run / ena);
  33. }
  34. }
  35. static void print_noise_pct(struct perf_stat_config *config,
  36. double total, double avg)
  37. {
  38. double pct = rel_stddev_stats(total, avg);
  39. if (config->csv_output)
  40. fprintf(config->output, "%s%.2f%%", config->csv_sep, pct);
  41. else if (pct)
  42. fprintf(config->output, " ( +-%6.2f%% )", pct);
  43. }
  44. static void print_noise(struct perf_stat_config *config,
  45. struct perf_evsel *evsel, double avg)
  46. {
  47. struct perf_stat_evsel *ps;
  48. if (config->run_count == 1)
  49. return;
  50. ps = evsel->stats;
  51. print_noise_pct(config, stddev_stats(&ps->res_stats[0]), avg);
  52. }
  53. static void aggr_printout(struct perf_stat_config *config,
  54. struct perf_evsel *evsel, int id, int nr)
  55. {
  56. switch (config->aggr_mode) {
  57. case AGGR_CORE:
  58. fprintf(config->output, "S%d-C%*d%s%*d%s",
  59. cpu_map__id_to_socket(id),
  60. config->csv_output ? 0 : -8,
  61. cpu_map__id_to_cpu(id),
  62. config->csv_sep,
  63. config->csv_output ? 0 : 4,
  64. nr,
  65. config->csv_sep);
  66. break;
  67. case AGGR_SOCKET:
  68. fprintf(config->output, "S%*d%s%*d%s",
  69. config->csv_output ? 0 : -5,
  70. id,
  71. config->csv_sep,
  72. config->csv_output ? 0 : 4,
  73. nr,
  74. config->csv_sep);
  75. break;
  76. case AGGR_NONE:
  77. fprintf(config->output, "CPU%*d%s",
  78. config->csv_output ? 0 : -4,
  79. perf_evsel__cpus(evsel)->map[id], config->csv_sep);
  80. break;
  81. case AGGR_THREAD:
  82. fprintf(config->output, "%*s-%*d%s",
  83. config->csv_output ? 0 : 16,
  84. thread_map__comm(evsel->threads, id),
  85. config->csv_output ? 0 : -8,
  86. thread_map__pid(evsel->threads, id),
  87. config->csv_sep);
  88. break;
  89. case AGGR_GLOBAL:
  90. case AGGR_UNSET:
  91. default:
  92. break;
  93. }
  94. }
  95. struct outstate {
  96. FILE *fh;
  97. bool newline;
  98. const char *prefix;
  99. int nfields;
  100. int id, nr;
  101. struct perf_evsel *evsel;
  102. };
  103. #define METRIC_LEN 35
  104. static void new_line_std(struct perf_stat_config *config __maybe_unused,
  105. void *ctx)
  106. {
  107. struct outstate *os = ctx;
  108. os->newline = true;
  109. }
  110. static void do_new_line_std(struct perf_stat_config *config,
  111. struct outstate *os)
  112. {
  113. fputc('\n', os->fh);
  114. fputs(os->prefix, os->fh);
  115. aggr_printout(config, os->evsel, os->id, os->nr);
  116. if (config->aggr_mode == AGGR_NONE)
  117. fprintf(os->fh, " ");
  118. fprintf(os->fh, " ");
  119. }
  120. static void print_metric_std(struct perf_stat_config *config,
  121. void *ctx, const char *color, const char *fmt,
  122. const char *unit, double val)
  123. {
  124. struct outstate *os = ctx;
  125. FILE *out = os->fh;
  126. int n;
  127. bool newline = os->newline;
  128. os->newline = false;
  129. if (unit == NULL || fmt == NULL) {
  130. fprintf(out, "%-*s", METRIC_LEN, "");
  131. return;
  132. }
  133. if (newline)
  134. do_new_line_std(config, os);
  135. n = fprintf(out, " # ");
  136. if (color)
  137. n += color_fprintf(out, color, fmt, val);
  138. else
  139. n += fprintf(out, fmt, val);
  140. fprintf(out, " %-*s", METRIC_LEN - n - 1, unit);
  141. }
  142. static void new_line_csv(struct perf_stat_config *config, void *ctx)
  143. {
  144. struct outstate *os = ctx;
  145. int i;
  146. fputc('\n', os->fh);
  147. if (os->prefix)
  148. fprintf(os->fh, "%s%s", os->prefix, config->csv_sep);
  149. aggr_printout(config, os->evsel, os->id, os->nr);
  150. for (i = 0; i < os->nfields; i++)
  151. fputs(config->csv_sep, os->fh);
  152. }
  153. static void print_metric_csv(struct perf_stat_config *config __maybe_unused,
  154. void *ctx,
  155. const char *color __maybe_unused,
  156. const char *fmt, const char *unit, double val)
  157. {
  158. struct outstate *os = ctx;
  159. FILE *out = os->fh;
  160. char buf[64], *vals, *ends;
  161. if (unit == NULL || fmt == NULL) {
  162. fprintf(out, "%s%s", config->csv_sep, config->csv_sep);
  163. return;
  164. }
  165. snprintf(buf, sizeof(buf), fmt, val);
  166. ends = vals = ltrim(buf);
  167. while (isdigit(*ends) || *ends == '.')
  168. ends++;
  169. *ends = 0;
  170. while (isspace(*unit))
  171. unit++;
  172. fprintf(out, "%s%s%s%s", config->csv_sep, vals, config->csv_sep, unit);
  173. }
  174. /* Filter out some columns that don't work well in metrics only mode */
  175. static bool valid_only_metric(const char *unit)
  176. {
  177. if (!unit)
  178. return false;
  179. if (strstr(unit, "/sec") ||
  180. strstr(unit, "hz") ||
  181. strstr(unit, "Hz") ||
  182. strstr(unit, "CPUs utilized"))
  183. return false;
  184. return true;
  185. }
  186. static const char *fixunit(char *buf, struct perf_evsel *evsel,
  187. const char *unit)
  188. {
  189. if (!strncmp(unit, "of all", 6)) {
  190. snprintf(buf, 1024, "%s %s", perf_evsel__name(evsel),
  191. unit);
  192. return buf;
  193. }
  194. return unit;
  195. }
  196. static void print_metric_only(struct perf_stat_config *config,
  197. void *ctx, const char *color, const char *fmt,
  198. const char *unit, double val)
  199. {
  200. struct outstate *os = ctx;
  201. FILE *out = os->fh;
  202. char buf[1024], str[1024];
  203. unsigned mlen = config->metric_only_len;
  204. if (!valid_only_metric(unit))
  205. return;
  206. unit = fixunit(buf, os->evsel, unit);
  207. if (mlen < strlen(unit))
  208. mlen = strlen(unit) + 1;
  209. if (color)
  210. mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1;
  211. color_snprintf(str, sizeof(str), color ?: "", fmt, val);
  212. fprintf(out, "%*s ", mlen, str);
  213. }
  214. static void print_metric_only_csv(struct perf_stat_config *config __maybe_unused,
  215. void *ctx, const char *color __maybe_unused,
  216. const char *fmt,
  217. const char *unit, double val)
  218. {
  219. struct outstate *os = ctx;
  220. FILE *out = os->fh;
  221. char buf[64], *vals, *ends;
  222. char tbuf[1024];
  223. if (!valid_only_metric(unit))
  224. return;
  225. unit = fixunit(tbuf, os->evsel, unit);
  226. snprintf(buf, sizeof buf, fmt, val);
  227. ends = vals = ltrim(buf);
  228. while (isdigit(*ends) || *ends == '.')
  229. ends++;
  230. *ends = 0;
  231. fprintf(out, "%s%s", vals, config->csv_sep);
  232. }
  233. static void new_line_metric(struct perf_stat_config *config __maybe_unused,
  234. void *ctx __maybe_unused)
  235. {
  236. }
  237. static void print_metric_header(struct perf_stat_config *config,
  238. void *ctx, const char *color __maybe_unused,
  239. const char *fmt __maybe_unused,
  240. const char *unit, double val __maybe_unused)
  241. {
  242. struct outstate *os = ctx;
  243. char tbuf[1024];
  244. if (!valid_only_metric(unit))
  245. return;
  246. unit = fixunit(tbuf, os->evsel, unit);
  247. if (config->csv_output)
  248. fprintf(os->fh, "%s%s", unit, config->csv_sep);
  249. else
  250. fprintf(os->fh, "%*s ", config->metric_only_len, unit);
  251. }
  252. static int first_shadow_cpu(struct perf_stat_config *config,
  253. struct perf_evsel *evsel, int id)
  254. {
  255. struct perf_evlist *evlist = evsel->evlist;
  256. int i;
  257. if (!config->aggr_get_id)
  258. return 0;
  259. if (config->aggr_mode == AGGR_NONE)
  260. return id;
  261. if (config->aggr_mode == AGGR_GLOBAL)
  262. return 0;
  263. for (i = 0; i < perf_evsel__nr_cpus(evsel); i++) {
  264. int cpu2 = perf_evsel__cpus(evsel)->map[i];
  265. if (config->aggr_get_id(config, evlist->cpus, cpu2) == id)
  266. return cpu2;
  267. }
  268. return 0;
  269. }
  270. static void abs_printout(struct perf_stat_config *config,
  271. int id, int nr, struct perf_evsel *evsel, double avg)
  272. {
  273. FILE *output = config->output;
  274. double sc = evsel->scale;
  275. const char *fmt;
  276. if (config->csv_output) {
  277. fmt = floor(sc) != sc ? "%.2f%s" : "%.0f%s";
  278. } else {
  279. if (config->big_num)
  280. fmt = floor(sc) != sc ? "%'18.2f%s" : "%'18.0f%s";
  281. else
  282. fmt = floor(sc) != sc ? "%18.2f%s" : "%18.0f%s";
  283. }
  284. aggr_printout(config, evsel, id, nr);
  285. fprintf(output, fmt, avg, config->csv_sep);
  286. if (evsel->unit)
  287. fprintf(output, "%-*s%s",
  288. config->csv_output ? 0 : config->unit_width,
  289. evsel->unit, config->csv_sep);
  290. fprintf(output, "%-*s", config->csv_output ? 0 : 25, perf_evsel__name(evsel));
  291. if (evsel->cgrp)
  292. fprintf(output, "%s%s", config->csv_sep, evsel->cgrp->name);
  293. }
  294. static bool is_mixed_hw_group(struct perf_evsel *counter)
  295. {
  296. struct perf_evlist *evlist = counter->evlist;
  297. u32 pmu_type = counter->attr.type;
  298. struct perf_evsel *pos;
  299. if (counter->nr_members < 2)
  300. return false;
  301. evlist__for_each_entry(evlist, pos) {
  302. /* software events can be part of any hardware group */
  303. if (pos->attr.type == PERF_TYPE_SOFTWARE)
  304. continue;
  305. if (pmu_type == PERF_TYPE_SOFTWARE) {
  306. pmu_type = pos->attr.type;
  307. continue;
  308. }
  309. if (pmu_type != pos->attr.type)
  310. return true;
  311. }
  312. return false;
  313. }
  314. static void printout(struct perf_stat_config *config, int id, int nr,
  315. struct perf_evsel *counter, double uval,
  316. char *prefix, u64 run, u64 ena, double noise,
  317. struct runtime_stat *st)
  318. {
  319. struct perf_stat_output_ctx out;
  320. struct outstate os = {
  321. .fh = config->output,
  322. .prefix = prefix ? prefix : "",
  323. .id = id,
  324. .nr = nr,
  325. .evsel = counter,
  326. };
  327. print_metric_t pm = print_metric_std;
  328. new_line_t nl;
  329. if (config->metric_only) {
  330. nl = new_line_metric;
  331. if (config->csv_output)
  332. pm = print_metric_only_csv;
  333. else
  334. pm = print_metric_only;
  335. } else
  336. nl = new_line_std;
  337. if (config->csv_output && !config->metric_only) {
  338. static int aggr_fields[] = {
  339. [AGGR_GLOBAL] = 0,
  340. [AGGR_THREAD] = 1,
  341. [AGGR_NONE] = 1,
  342. [AGGR_SOCKET] = 2,
  343. [AGGR_CORE] = 2,
  344. };
  345. pm = print_metric_csv;
  346. nl = new_line_csv;
  347. os.nfields = 3;
  348. os.nfields += aggr_fields[config->aggr_mode];
  349. if (counter->cgrp)
  350. os.nfields++;
  351. }
  352. if (run == 0 || ena == 0 || counter->counts->scaled == -1) {
  353. if (config->metric_only) {
  354. pm(config, &os, NULL, "", "", 0);
  355. return;
  356. }
  357. aggr_printout(config, counter, id, nr);
  358. fprintf(config->output, "%*s%s",
  359. config->csv_output ? 0 : 18,
  360. counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
  361. config->csv_sep);
  362. if (counter->supported) {
  363. config->print_free_counters_hint = 1;
  364. if (is_mixed_hw_group(counter))
  365. config->print_mixed_hw_group_error = 1;
  366. }
  367. fprintf(config->output, "%-*s%s",
  368. config->csv_output ? 0 : config->unit_width,
  369. counter->unit, config->csv_sep);
  370. fprintf(config->output, "%*s",
  371. config->csv_output ? 0 : -25,
  372. perf_evsel__name(counter));
  373. if (counter->cgrp)
  374. fprintf(config->output, "%s%s",
  375. config->csv_sep, counter->cgrp->name);
  376. if (!config->csv_output)
  377. pm(config, &os, NULL, NULL, "", 0);
  378. print_noise(config, counter, noise);
  379. print_running(config, run, ena);
  380. if (config->csv_output)
  381. pm(config, &os, NULL, NULL, "", 0);
  382. return;
  383. }
  384. if (!config->metric_only)
  385. abs_printout(config, id, nr, counter, uval);
  386. out.print_metric = pm;
  387. out.new_line = nl;
  388. out.ctx = &os;
  389. out.force_header = false;
  390. if (config->csv_output && !config->metric_only) {
  391. print_noise(config, counter, noise);
  392. print_running(config, run, ena);
  393. }
  394. perf_stat__print_shadow_stats(config, counter, uval,
  395. first_shadow_cpu(config, counter, id),
  396. &out, &config->metric_events, st);
  397. if (!config->csv_output && !config->metric_only) {
  398. print_noise(config, counter, noise);
  399. print_running(config, run, ena);
  400. }
  401. }
  402. static void aggr_update_shadow(struct perf_stat_config *config,
  403. struct perf_evlist *evlist)
  404. {
  405. int cpu, s2, id, s;
  406. u64 val;
  407. struct perf_evsel *counter;
  408. for (s = 0; s < config->aggr_map->nr; s++) {
  409. id = config->aggr_map->map[s];
  410. evlist__for_each_entry(evlist, counter) {
  411. val = 0;
  412. for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
  413. s2 = config->aggr_get_id(config, evlist->cpus, cpu);
  414. if (s2 != id)
  415. continue;
  416. val += perf_counts(counter->counts, cpu, 0)->val;
  417. }
  418. perf_stat__update_shadow_stats(counter, val,
  419. first_shadow_cpu(config, counter, id),
  420. &rt_stat);
  421. }
  422. }
  423. }
  424. static void uniquify_event_name(struct perf_evsel *counter)
  425. {
  426. char *new_name;
  427. char *config;
  428. if (counter->uniquified_name ||
  429. !counter->pmu_name || !strncmp(counter->name, counter->pmu_name,
  430. strlen(counter->pmu_name)))
  431. return;
  432. config = strchr(counter->name, '/');
  433. if (config) {
  434. if (asprintf(&new_name,
  435. "%s%s", counter->pmu_name, config) > 0) {
  436. free(counter->name);
  437. counter->name = new_name;
  438. }
  439. } else {
  440. if (asprintf(&new_name,
  441. "%s [%s]", counter->name, counter->pmu_name) > 0) {
  442. free(counter->name);
  443. counter->name = new_name;
  444. }
  445. }
  446. counter->uniquified_name = true;
  447. }
  448. static void collect_all_aliases(struct perf_stat_config *config, struct perf_evsel *counter,
  449. void (*cb)(struct perf_stat_config *config, struct perf_evsel *counter, void *data,
  450. bool first),
  451. void *data)
  452. {
  453. struct perf_evlist *evlist = counter->evlist;
  454. struct perf_evsel *alias;
  455. alias = list_prepare_entry(counter, &(evlist->entries), node);
  456. list_for_each_entry_continue (alias, &evlist->entries, node) {
  457. if (strcmp(perf_evsel__name(alias), perf_evsel__name(counter)) ||
  458. alias->scale != counter->scale ||
  459. alias->cgrp != counter->cgrp ||
  460. strcmp(alias->unit, counter->unit) ||
  461. perf_evsel__is_clock(alias) != perf_evsel__is_clock(counter))
  462. break;
  463. alias->merged_stat = true;
  464. cb(config, alias, data, false);
  465. }
  466. }
  467. static bool collect_data(struct perf_stat_config *config, struct perf_evsel *counter,
  468. void (*cb)(struct perf_stat_config *config, struct perf_evsel *counter, void *data,
  469. bool first),
  470. void *data)
  471. {
  472. if (counter->merged_stat)
  473. return false;
  474. cb(config, counter, data, true);
  475. if (config->no_merge)
  476. uniquify_event_name(counter);
  477. else if (counter->auto_merge_stats)
  478. collect_all_aliases(config, counter, cb, data);
  479. return true;
  480. }
  481. struct aggr_data {
  482. u64 ena, run, val;
  483. int id;
  484. int nr;
  485. int cpu;
  486. };
  487. static void aggr_cb(struct perf_stat_config *config,
  488. struct perf_evsel *counter, void *data, bool first)
  489. {
  490. struct aggr_data *ad = data;
  491. int cpu, s2;
  492. for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
  493. struct perf_counts_values *counts;
  494. s2 = config->aggr_get_id(config, perf_evsel__cpus(counter), cpu);
  495. if (s2 != ad->id)
  496. continue;
  497. if (first)
  498. ad->nr++;
  499. counts = perf_counts(counter->counts, cpu, 0);
  500. /*
  501. * When any result is bad, make them all to give
  502. * consistent output in interval mode.
  503. */
  504. if (counts->ena == 0 || counts->run == 0 ||
  505. counter->counts->scaled == -1) {
  506. ad->ena = 0;
  507. ad->run = 0;
  508. break;
  509. }
  510. ad->val += counts->val;
  511. ad->ena += counts->ena;
  512. ad->run += counts->run;
  513. }
  514. }
  515. static void print_aggr(struct perf_stat_config *config,
  516. struct perf_evlist *evlist,
  517. char *prefix)
  518. {
  519. bool metric_only = config->metric_only;
  520. FILE *output = config->output;
  521. struct perf_evsel *counter;
  522. int s, id, nr;
  523. double uval;
  524. u64 ena, run, val;
  525. bool first;
  526. if (!(config->aggr_map || config->aggr_get_id))
  527. return;
  528. aggr_update_shadow(config, evlist);
  529. /*
  530. * With metric_only everything is on a single line.
  531. * Without each counter has its own line.
  532. */
  533. for (s = 0; s < config->aggr_map->nr; s++) {
  534. struct aggr_data ad;
  535. if (prefix && metric_only)
  536. fprintf(output, "%s", prefix);
  537. ad.id = id = config->aggr_map->map[s];
  538. first = true;
  539. evlist__for_each_entry(evlist, counter) {
  540. if (is_duration_time(counter))
  541. continue;
  542. ad.val = ad.ena = ad.run = 0;
  543. ad.nr = 0;
  544. if (!collect_data(config, counter, aggr_cb, &ad))
  545. continue;
  546. nr = ad.nr;
  547. ena = ad.ena;
  548. run = ad.run;
  549. val = ad.val;
  550. if (first && metric_only) {
  551. first = false;
  552. aggr_printout(config, counter, id, nr);
  553. }
  554. if (prefix && !metric_only)
  555. fprintf(output, "%s", prefix);
  556. uval = val * counter->scale;
  557. printout(config, id, nr, counter, uval, prefix,
  558. run, ena, 1.0, &rt_stat);
  559. if (!metric_only)
  560. fputc('\n', output);
  561. }
  562. if (metric_only)
  563. fputc('\n', output);
  564. }
  565. }
  566. static int cmp_val(const void *a, const void *b)
  567. {
  568. return ((struct perf_aggr_thread_value *)b)->val -
  569. ((struct perf_aggr_thread_value *)a)->val;
  570. }
  571. static struct perf_aggr_thread_value *sort_aggr_thread(
  572. struct perf_evsel *counter,
  573. int nthreads, int ncpus,
  574. int *ret,
  575. struct target *_target)
  576. {
  577. int cpu, thread, i = 0;
  578. double uval;
  579. struct perf_aggr_thread_value *buf;
  580. buf = calloc(nthreads, sizeof(struct perf_aggr_thread_value));
  581. if (!buf)
  582. return NULL;
  583. for (thread = 0; thread < nthreads; thread++) {
  584. u64 ena = 0, run = 0, val = 0;
  585. for (cpu = 0; cpu < ncpus; cpu++) {
  586. val += perf_counts(counter->counts, cpu, thread)->val;
  587. ena += perf_counts(counter->counts, cpu, thread)->ena;
  588. run += perf_counts(counter->counts, cpu, thread)->run;
  589. }
  590. uval = val * counter->scale;
  591. /*
  592. * Skip value 0 when enabling --per-thread globally,
  593. * otherwise too many 0 output.
  594. */
  595. if (uval == 0.0 && target__has_per_thread(_target))
  596. continue;
  597. buf[i].counter = counter;
  598. buf[i].id = thread;
  599. buf[i].uval = uval;
  600. buf[i].val = val;
  601. buf[i].run = run;
  602. buf[i].ena = ena;
  603. i++;
  604. }
  605. qsort(buf, i, sizeof(struct perf_aggr_thread_value), cmp_val);
  606. if (ret)
  607. *ret = i;
  608. return buf;
  609. }
  610. static void print_aggr_thread(struct perf_stat_config *config,
  611. struct target *_target,
  612. struct perf_evsel *counter, char *prefix)
  613. {
  614. FILE *output = config->output;
  615. int nthreads = thread_map__nr(counter->threads);
  616. int ncpus = cpu_map__nr(counter->cpus);
  617. int thread, sorted_threads, id;
  618. struct perf_aggr_thread_value *buf;
  619. buf = sort_aggr_thread(counter, nthreads, ncpus, &sorted_threads, _target);
  620. if (!buf) {
  621. perror("cannot sort aggr thread");
  622. return;
  623. }
  624. for (thread = 0; thread < sorted_threads; thread++) {
  625. if (prefix)
  626. fprintf(output, "%s", prefix);
  627. id = buf[thread].id;
  628. if (config->stats)
  629. printout(config, id, 0, buf[thread].counter, buf[thread].uval,
  630. prefix, buf[thread].run, buf[thread].ena, 1.0,
  631. &config->stats[id]);
  632. else
  633. printout(config, id, 0, buf[thread].counter, buf[thread].uval,
  634. prefix, buf[thread].run, buf[thread].ena, 1.0,
  635. &rt_stat);
  636. fputc('\n', output);
  637. }
  638. free(buf);
  639. }
  640. struct caggr_data {
  641. double avg, avg_enabled, avg_running;
  642. };
  643. static void counter_aggr_cb(struct perf_stat_config *config __maybe_unused,
  644. struct perf_evsel *counter, void *data,
  645. bool first __maybe_unused)
  646. {
  647. struct caggr_data *cd = data;
  648. struct perf_stat_evsel *ps = counter->stats;
  649. cd->avg += avg_stats(&ps->res_stats[0]);
  650. cd->avg_enabled += avg_stats(&ps->res_stats[1]);
  651. cd->avg_running += avg_stats(&ps->res_stats[2]);
  652. }
  653. /*
  654. * Print out the results of a single counter:
  655. * aggregated counts in system-wide mode
  656. */
  657. static void print_counter_aggr(struct perf_stat_config *config,
  658. struct perf_evsel *counter, char *prefix)
  659. {
  660. bool metric_only = config->metric_only;
  661. FILE *output = config->output;
  662. double uval;
  663. struct caggr_data cd = { .avg = 0.0 };
  664. if (!collect_data(config, counter, counter_aggr_cb, &cd))
  665. return;
  666. if (prefix && !metric_only)
  667. fprintf(output, "%s", prefix);
  668. uval = cd.avg * counter->scale;
  669. printout(config, -1, 0, counter, uval, prefix, cd.avg_running, cd.avg_enabled,
  670. cd.avg, &rt_stat);
  671. if (!metric_only)
  672. fprintf(output, "\n");
  673. }
  674. static void counter_cb(struct perf_stat_config *config __maybe_unused,
  675. struct perf_evsel *counter, void *data,
  676. bool first __maybe_unused)
  677. {
  678. struct aggr_data *ad = data;
  679. ad->val += perf_counts(counter->counts, ad->cpu, 0)->val;
  680. ad->ena += perf_counts(counter->counts, ad->cpu, 0)->ena;
  681. ad->run += perf_counts(counter->counts, ad->cpu, 0)->run;
  682. }
  683. /*
  684. * Print out the results of a single counter:
  685. * does not use aggregated count in system-wide
  686. */
  687. static void print_counter(struct perf_stat_config *config,
  688. struct perf_evsel *counter, char *prefix)
  689. {
  690. FILE *output = config->output;
  691. u64 ena, run, val;
  692. double uval;
  693. int cpu;
  694. for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
  695. struct aggr_data ad = { .cpu = cpu };
  696. if (!collect_data(config, counter, counter_cb, &ad))
  697. return;
  698. val = ad.val;
  699. ena = ad.ena;
  700. run = ad.run;
  701. if (prefix)
  702. fprintf(output, "%s", prefix);
  703. uval = val * counter->scale;
  704. printout(config, cpu, 0, counter, uval, prefix, run, ena, 1.0,
  705. &rt_stat);
  706. fputc('\n', output);
  707. }
  708. }
  709. static void print_no_aggr_metric(struct perf_stat_config *config,
  710. struct perf_evlist *evlist,
  711. char *prefix)
  712. {
  713. int cpu;
  714. int nrcpus = 0;
  715. struct perf_evsel *counter;
  716. u64 ena, run, val;
  717. double uval;
  718. nrcpus = evlist->cpus->nr;
  719. for (cpu = 0; cpu < nrcpus; cpu++) {
  720. bool first = true;
  721. if (prefix)
  722. fputs(prefix, config->output);
  723. evlist__for_each_entry(evlist, counter) {
  724. if (is_duration_time(counter))
  725. continue;
  726. if (first) {
  727. aggr_printout(config, counter, cpu, 0);
  728. first = false;
  729. }
  730. val = perf_counts(counter->counts, cpu, 0)->val;
  731. ena = perf_counts(counter->counts, cpu, 0)->ena;
  732. run = perf_counts(counter->counts, cpu, 0)->run;
  733. uval = val * counter->scale;
  734. printout(config, cpu, 0, counter, uval, prefix, run, ena, 1.0,
  735. &rt_stat);
  736. }
  737. fputc('\n', config->output);
  738. }
  739. }
  740. static int aggr_header_lens[] = {
  741. [AGGR_CORE] = 18,
  742. [AGGR_SOCKET] = 12,
  743. [AGGR_NONE] = 6,
  744. [AGGR_THREAD] = 24,
  745. [AGGR_GLOBAL] = 0,
  746. };
  747. static const char *aggr_header_csv[] = {
  748. [AGGR_CORE] = "core,cpus,",
  749. [AGGR_SOCKET] = "socket,cpus",
  750. [AGGR_NONE] = "cpu,",
  751. [AGGR_THREAD] = "comm-pid,",
  752. [AGGR_GLOBAL] = ""
  753. };
  754. static void print_metric_headers(struct perf_stat_config *config,
  755. struct perf_evlist *evlist,
  756. const char *prefix, bool no_indent)
  757. {
  758. struct perf_stat_output_ctx out;
  759. struct perf_evsel *counter;
  760. struct outstate os = {
  761. .fh = config->output
  762. };
  763. if (prefix)
  764. fprintf(config->output, "%s", prefix);
  765. if (!config->csv_output && !no_indent)
  766. fprintf(config->output, "%*s",
  767. aggr_header_lens[config->aggr_mode], "");
  768. if (config->csv_output) {
  769. if (config->interval)
  770. fputs("time,", config->output);
  771. fputs(aggr_header_csv[config->aggr_mode], config->output);
  772. }
  773. /* Print metrics headers only */
  774. evlist__for_each_entry(evlist, counter) {
  775. if (is_duration_time(counter))
  776. continue;
  777. os.evsel = counter;
  778. out.ctx = &os;
  779. out.print_metric = print_metric_header;
  780. out.new_line = new_line_metric;
  781. out.force_header = true;
  782. os.evsel = counter;
  783. perf_stat__print_shadow_stats(config, counter, 0,
  784. 0,
  785. &out,
  786. &config->metric_events,
  787. &rt_stat);
  788. }
  789. fputc('\n', config->output);
  790. }
  791. static void print_interval(struct perf_stat_config *config,
  792. struct perf_evlist *evlist,
  793. char *prefix, struct timespec *ts)
  794. {
  795. bool metric_only = config->metric_only;
  796. unsigned int unit_width = config->unit_width;
  797. FILE *output = config->output;
  798. static int num_print_interval;
  799. if (config->interval_clear)
  800. puts(CONSOLE_CLEAR);
  801. sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, config->csv_sep);
  802. if ((num_print_interval == 0 && !config->csv_output) || config->interval_clear) {
  803. switch (config->aggr_mode) {
  804. case AGGR_SOCKET:
  805. fprintf(output, "# time socket cpus");
  806. if (!metric_only)
  807. fprintf(output, " counts %*s events\n", unit_width, "unit");
  808. break;
  809. case AGGR_CORE:
  810. fprintf(output, "# time core cpus");
  811. if (!metric_only)
  812. fprintf(output, " counts %*s events\n", unit_width, "unit");
  813. break;
  814. case AGGR_NONE:
  815. fprintf(output, "# time CPU ");
  816. if (!metric_only)
  817. fprintf(output, " counts %*s events\n", unit_width, "unit");
  818. break;
  819. case AGGR_THREAD:
  820. fprintf(output, "# time comm-pid");
  821. if (!metric_only)
  822. fprintf(output, " counts %*s events\n", unit_width, "unit");
  823. break;
  824. case AGGR_GLOBAL:
  825. default:
  826. fprintf(output, "# time");
  827. if (!metric_only)
  828. fprintf(output, " counts %*s events\n", unit_width, "unit");
  829. case AGGR_UNSET:
  830. break;
  831. }
  832. }
  833. if ((num_print_interval == 0 || config->interval_clear) && metric_only)
  834. print_metric_headers(config, evlist, " ", true);
  835. if (++num_print_interval == 25)
  836. num_print_interval = 0;
  837. }
  838. static void print_header(struct perf_stat_config *config,
  839. struct target *_target,
  840. int argc, const char **argv)
  841. {
  842. FILE *output = config->output;
  843. int i;
  844. fflush(stdout);
  845. if (!config->csv_output) {
  846. fprintf(output, "\n");
  847. fprintf(output, " Performance counter stats for ");
  848. if (_target->system_wide)
  849. fprintf(output, "\'system wide");
  850. else if (_target->cpu_list)
  851. fprintf(output, "\'CPU(s) %s", _target->cpu_list);
  852. else if (!target__has_task(_target)) {
  853. fprintf(output, "\'%s", argv ? argv[0] : "pipe");
  854. for (i = 1; argv && (i < argc); i++)
  855. fprintf(output, " %s", argv[i]);
  856. } else if (_target->pid)
  857. fprintf(output, "process id \'%s", _target->pid);
  858. else
  859. fprintf(output, "thread id \'%s", _target->tid);
  860. fprintf(output, "\'");
  861. if (config->run_count > 1)
  862. fprintf(output, " (%d runs)", config->run_count);
  863. fprintf(output, ":\n\n");
  864. }
  865. }
  866. static int get_precision(double num)
  867. {
  868. if (num > 1)
  869. return 0;
  870. return lround(ceil(-log10(num)));
  871. }
  872. static void print_table(struct perf_stat_config *config,
  873. FILE *output, int precision, double avg)
  874. {
  875. char tmp[64];
  876. int idx, indent = 0;
  877. scnprintf(tmp, 64, " %17.*f", precision, avg);
  878. while (tmp[indent] == ' ')
  879. indent++;
  880. fprintf(output, "%*s# Table of individual measurements:\n", indent, "");
  881. for (idx = 0; idx < config->run_count; idx++) {
  882. double run = (double) config->walltime_run[idx] / NSEC_PER_SEC;
  883. int h, n = 1 + abs((int) (100.0 * (run - avg)/run) / 5);
  884. fprintf(output, " %17.*f (%+.*f) ",
  885. precision, run, precision, run - avg);
  886. for (h = 0; h < n; h++)
  887. fprintf(output, "#");
  888. fprintf(output, "\n");
  889. }
  890. fprintf(output, "\n%*s# Final result:\n", indent, "");
  891. }
  892. static double timeval2double(struct timeval *t)
  893. {
  894. return t->tv_sec + (double) t->tv_usec/USEC_PER_SEC;
  895. }
  896. static void print_footer(struct perf_stat_config *config)
  897. {
  898. double avg = avg_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
  899. FILE *output = config->output;
  900. int n;
  901. if (!config->null_run)
  902. fprintf(output, "\n");
  903. if (config->run_count == 1) {
  904. fprintf(output, " %17.9f seconds time elapsed", avg);
  905. if (config->ru_display) {
  906. double ru_utime = timeval2double(&config->ru_data.ru_utime);
  907. double ru_stime = timeval2double(&config->ru_data.ru_stime);
  908. fprintf(output, "\n\n");
  909. fprintf(output, " %17.9f seconds user\n", ru_utime);
  910. fprintf(output, " %17.9f seconds sys\n", ru_stime);
  911. }
  912. } else {
  913. double sd = stddev_stats(config->walltime_nsecs_stats) / NSEC_PER_SEC;
  914. /*
  915. * Display at most 2 more significant
  916. * digits than the stddev inaccuracy.
  917. */
  918. int precision = get_precision(sd) + 2;
  919. if (config->walltime_run_table)
  920. print_table(config, output, precision, avg);
  921. fprintf(output, " %17.*f +- %.*f seconds time elapsed",
  922. precision, avg, precision, sd);
  923. print_noise_pct(config, sd, avg);
  924. }
  925. fprintf(output, "\n\n");
  926. if (config->print_free_counters_hint &&
  927. sysctl__read_int("kernel/nmi_watchdog", &n) >= 0 &&
  928. n > 0)
  929. fprintf(output,
  930. "Some events weren't counted. Try disabling the NMI watchdog:\n"
  931. " echo 0 > /proc/sys/kernel/nmi_watchdog\n"
  932. " perf stat ...\n"
  933. " echo 1 > /proc/sys/kernel/nmi_watchdog\n");
  934. if (config->print_mixed_hw_group_error)
  935. fprintf(output,
  936. "The events in group usually have to be from "
  937. "the same PMU. Try reorganizing the group.\n");
  938. }
  939. void
  940. perf_evlist__print_counters(struct perf_evlist *evlist,
  941. struct perf_stat_config *config,
  942. struct target *_target,
  943. struct timespec *ts,
  944. int argc, const char **argv)
  945. {
  946. bool metric_only = config->metric_only;
  947. int interval = config->interval;
  948. struct perf_evsel *counter;
  949. char buf[64], *prefix = NULL;
  950. if (interval)
  951. print_interval(config, evlist, prefix = buf, ts);
  952. else
  953. print_header(config, _target, argc, argv);
  954. if (metric_only) {
  955. static int num_print_iv;
  956. if (num_print_iv == 0 && !interval)
  957. print_metric_headers(config, evlist, prefix, false);
  958. if (num_print_iv++ == 25)
  959. num_print_iv = 0;
  960. if (config->aggr_mode == AGGR_GLOBAL && prefix)
  961. fprintf(config->output, "%s", prefix);
  962. }
  963. switch (config->aggr_mode) {
  964. case AGGR_CORE:
  965. case AGGR_SOCKET:
  966. print_aggr(config, evlist, prefix);
  967. break;
  968. case AGGR_THREAD:
  969. evlist__for_each_entry(evlist, counter) {
  970. if (is_duration_time(counter))
  971. continue;
  972. print_aggr_thread(config, _target, counter, prefix);
  973. }
  974. break;
  975. case AGGR_GLOBAL:
  976. evlist__for_each_entry(evlist, counter) {
  977. if (is_duration_time(counter))
  978. continue;
  979. print_counter_aggr(config, counter, prefix);
  980. }
  981. if (metric_only)
  982. fputc('\n', config->output);
  983. break;
  984. case AGGR_NONE:
  985. if (metric_only)
  986. print_no_aggr_metric(config, evlist, prefix);
  987. else {
  988. evlist__for_each_entry(evlist, counter) {
  989. if (is_duration_time(counter))
  990. continue;
  991. print_counter(config, counter, prefix);
  992. }
  993. }
  994. break;
  995. case AGGR_UNSET:
  996. default:
  997. break;
  998. }
  999. if (!interval && !config->csv_output)
  1000. print_footer(config);
  1001. fflush(config->output);
  1002. }