builtin-diff.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356
  1. /*
  2. * builtin-diff.c
  3. *
  4. * Builtin diff command: Analyze two perf.data input files, look up and read
  5. * DSOs and symbol information, sort them and produce a diff.
  6. */
  7. #include "builtin.h"
  8. #include "util/debug.h"
  9. #include "util/event.h"
  10. #include "util/hist.h"
  11. #include "util/evsel.h"
  12. #include "util/evlist.h"
  13. #include "util/session.h"
  14. #include "util/tool.h"
  15. #include "util/sort.h"
  16. #include "util/symbol.h"
  17. #include "util/util.h"
  18. #include "util/data.h"
  19. #include "util/config.h"
  20. #include <stdlib.h>
  21. #include <math.h>
  22. /* Diff command specific HPP columns. */
  23. enum {
  24. PERF_HPP_DIFF__BASELINE,
  25. PERF_HPP_DIFF__PERIOD,
  26. PERF_HPP_DIFF__PERIOD_BASELINE,
  27. PERF_HPP_DIFF__DELTA,
  28. PERF_HPP_DIFF__RATIO,
  29. PERF_HPP_DIFF__WEIGHTED_DIFF,
  30. PERF_HPP_DIFF__FORMULA,
  31. PERF_HPP_DIFF__DELTA_ABS,
  32. PERF_HPP_DIFF__MAX_INDEX
  33. };
  34. struct diff_hpp_fmt {
  35. struct perf_hpp_fmt fmt;
  36. int idx;
  37. char *header;
  38. int header_width;
  39. };
  40. struct data__file {
  41. struct perf_session *session;
  42. struct perf_data_file file;
  43. int idx;
  44. struct hists *hists;
  45. struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
  46. };
  47. static struct data__file *data__files;
  48. static int data__files_cnt;
  49. #define data__for_each_file_start(i, d, s) \
  50. for (i = s, d = &data__files[s]; \
  51. i < data__files_cnt; \
  52. i++, d = &data__files[i])
  53. #define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
  54. #define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
  55. static bool force;
  56. static bool show_period;
  57. static bool show_formula;
  58. static bool show_baseline_only;
  59. static unsigned int sort_compute = 1;
  60. static s64 compute_wdiff_w1;
  61. static s64 compute_wdiff_w2;
  62. enum {
  63. COMPUTE_DELTA,
  64. COMPUTE_RATIO,
  65. COMPUTE_WEIGHTED_DIFF,
  66. COMPUTE_DELTA_ABS,
  67. COMPUTE_MAX,
  68. };
  69. const char *compute_names[COMPUTE_MAX] = {
  70. [COMPUTE_DELTA] = "delta",
  71. [COMPUTE_DELTA_ABS] = "delta-abs",
  72. [COMPUTE_RATIO] = "ratio",
  73. [COMPUTE_WEIGHTED_DIFF] = "wdiff",
  74. };
  75. static int compute = COMPUTE_DELTA_ABS;
  76. static int compute_2_hpp[COMPUTE_MAX] = {
  77. [COMPUTE_DELTA] = PERF_HPP_DIFF__DELTA,
  78. [COMPUTE_DELTA_ABS] = PERF_HPP_DIFF__DELTA_ABS,
  79. [COMPUTE_RATIO] = PERF_HPP_DIFF__RATIO,
  80. [COMPUTE_WEIGHTED_DIFF] = PERF_HPP_DIFF__WEIGHTED_DIFF,
  81. };
  82. #define MAX_COL_WIDTH 70
  83. static struct header_column {
  84. const char *name;
  85. int width;
  86. } columns[PERF_HPP_DIFF__MAX_INDEX] = {
  87. [PERF_HPP_DIFF__BASELINE] = {
  88. .name = "Baseline",
  89. },
  90. [PERF_HPP_DIFF__PERIOD] = {
  91. .name = "Period",
  92. .width = 14,
  93. },
  94. [PERF_HPP_DIFF__PERIOD_BASELINE] = {
  95. .name = "Base period",
  96. .width = 14,
  97. },
  98. [PERF_HPP_DIFF__DELTA] = {
  99. .name = "Delta",
  100. .width = 7,
  101. },
  102. [PERF_HPP_DIFF__DELTA_ABS] = {
  103. .name = "Delta Abs",
  104. .width = 7,
  105. },
  106. [PERF_HPP_DIFF__RATIO] = {
  107. .name = "Ratio",
  108. .width = 14,
  109. },
  110. [PERF_HPP_DIFF__WEIGHTED_DIFF] = {
  111. .name = "Weighted diff",
  112. .width = 14,
  113. },
  114. [PERF_HPP_DIFF__FORMULA] = {
  115. .name = "Formula",
  116. .width = MAX_COL_WIDTH,
  117. }
  118. };
  119. static int setup_compute_opt_wdiff(char *opt)
  120. {
  121. char *w1_str = opt;
  122. char *w2_str;
  123. int ret = -EINVAL;
  124. if (!opt)
  125. goto out;
  126. w2_str = strchr(opt, ',');
  127. if (!w2_str)
  128. goto out;
  129. *w2_str++ = 0x0;
  130. if (!*w2_str)
  131. goto out;
  132. compute_wdiff_w1 = strtol(w1_str, NULL, 10);
  133. compute_wdiff_w2 = strtol(w2_str, NULL, 10);
  134. if (!compute_wdiff_w1 || !compute_wdiff_w2)
  135. goto out;
  136. pr_debug("compute wdiff w1(%" PRId64 ") w2(%" PRId64 ")\n",
  137. compute_wdiff_w1, compute_wdiff_w2);
  138. ret = 0;
  139. out:
  140. if (ret)
  141. pr_err("Failed: wrong weight data, use 'wdiff:w1,w2'\n");
  142. return ret;
  143. }
  144. static int setup_compute_opt(char *opt)
  145. {
  146. if (compute == COMPUTE_WEIGHTED_DIFF)
  147. return setup_compute_opt_wdiff(opt);
  148. if (opt) {
  149. pr_err("Failed: extra option specified '%s'", opt);
  150. return -EINVAL;
  151. }
  152. return 0;
  153. }
  154. static int setup_compute(const struct option *opt, const char *str,
  155. int unset __maybe_unused)
  156. {
  157. int *cp = (int *) opt->value;
  158. char *cstr = (char *) str;
  159. char buf[50];
  160. unsigned i;
  161. char *option;
  162. if (!str) {
  163. *cp = COMPUTE_DELTA;
  164. return 0;
  165. }
  166. option = strchr(str, ':');
  167. if (option) {
  168. unsigned len = option++ - str;
  169. /*
  170. * The str data are not writeable, so we need
  171. * to use another buffer.
  172. */
  173. /* No option value is longer. */
  174. if (len >= sizeof(buf))
  175. return -EINVAL;
  176. strncpy(buf, str, len);
  177. buf[len] = 0x0;
  178. cstr = buf;
  179. }
  180. for (i = 0; i < COMPUTE_MAX; i++)
  181. if (!strcmp(cstr, compute_names[i])) {
  182. *cp = i;
  183. return setup_compute_opt(option);
  184. }
  185. pr_err("Failed: '%s' is not computation method "
  186. "(use 'delta','ratio' or 'wdiff')\n", str);
  187. return -EINVAL;
  188. }
  189. static double period_percent(struct hist_entry *he, u64 period)
  190. {
  191. u64 total = hists__total_period(he->hists);
  192. return (period * 100.0) / total;
  193. }
  194. static double compute_delta(struct hist_entry *he, struct hist_entry *pair)
  195. {
  196. double old_percent = period_percent(he, he->stat.period);
  197. double new_percent = period_percent(pair, pair->stat.period);
  198. pair->diff.period_ratio_delta = new_percent - old_percent;
  199. pair->diff.computed = true;
  200. return pair->diff.period_ratio_delta;
  201. }
  202. static double compute_ratio(struct hist_entry *he, struct hist_entry *pair)
  203. {
  204. double old_period = he->stat.period ?: 1;
  205. double new_period = pair->stat.period;
  206. pair->diff.computed = true;
  207. pair->diff.period_ratio = new_period / old_period;
  208. return pair->diff.period_ratio;
  209. }
  210. static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
  211. {
  212. u64 old_period = he->stat.period;
  213. u64 new_period = pair->stat.period;
  214. pair->diff.computed = true;
  215. pair->diff.wdiff = new_period * compute_wdiff_w2 -
  216. old_period * compute_wdiff_w1;
  217. return pair->diff.wdiff;
  218. }
  219. static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
  220. char *buf, size_t size)
  221. {
  222. u64 he_total = he->hists->stats.total_period;
  223. u64 pair_total = pair->hists->stats.total_period;
  224. if (symbol_conf.filter_relative) {
  225. he_total = he->hists->stats.total_non_filtered_period;
  226. pair_total = pair->hists->stats.total_non_filtered_period;
  227. }
  228. return scnprintf(buf, size,
  229. "(%" PRIu64 " * 100 / %" PRIu64 ") - "
  230. "(%" PRIu64 " * 100 / %" PRIu64 ")",
  231. pair->stat.period, pair_total,
  232. he->stat.period, he_total);
  233. }
  234. static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
  235. char *buf, size_t size)
  236. {
  237. double old_period = he->stat.period;
  238. double new_period = pair->stat.period;
  239. return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
  240. }
  241. static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
  242. char *buf, size_t size)
  243. {
  244. u64 old_period = he->stat.period;
  245. u64 new_period = pair->stat.period;
  246. return scnprintf(buf, size,
  247. "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
  248. new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
  249. }
  250. static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
  251. char *buf, size_t size)
  252. {
  253. switch (compute) {
  254. case COMPUTE_DELTA:
  255. case COMPUTE_DELTA_ABS:
  256. return formula_delta(he, pair, buf, size);
  257. case COMPUTE_RATIO:
  258. return formula_ratio(he, pair, buf, size);
  259. case COMPUTE_WEIGHTED_DIFF:
  260. return formula_wdiff(he, pair, buf, size);
  261. default:
  262. BUG_ON(1);
  263. }
  264. return -1;
  265. }
  266. static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
  267. union perf_event *event,
  268. struct perf_sample *sample,
  269. struct perf_evsel *evsel,
  270. struct machine *machine)
  271. {
  272. struct addr_location al;
  273. struct hists *hists = evsel__hists(evsel);
  274. int ret = -1;
  275. if (machine__resolve(machine, &al, sample) < 0) {
  276. pr_warning("problem processing %d event, skipping it.\n",
  277. event->header.type);
  278. return -1;
  279. }
  280. if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample, true)) {
  281. pr_warning("problem incrementing symbol period, skipping event\n");
  282. goto out_put;
  283. }
  284. /*
  285. * The total_period is updated here before going to the output
  286. * tree since normally only the baseline hists will call
  287. * hists__output_resort() and precompute needs the total
  288. * period in order to sort entries by percentage delta.
  289. */
  290. hists->stats.total_period += sample->period;
  291. if (!al.filtered)
  292. hists->stats.total_non_filtered_period += sample->period;
  293. ret = 0;
  294. out_put:
  295. addr_location__put(&al);
  296. return ret;
  297. }
  298. static struct perf_tool tool = {
  299. .sample = diff__process_sample_event,
  300. .mmap = perf_event__process_mmap,
  301. .mmap2 = perf_event__process_mmap2,
  302. .comm = perf_event__process_comm,
  303. .exit = perf_event__process_exit,
  304. .fork = perf_event__process_fork,
  305. .lost = perf_event__process_lost,
  306. .ordered_events = true,
  307. .ordering_requires_timestamps = true,
  308. };
  309. static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
  310. struct perf_evlist *evlist)
  311. {
  312. struct perf_evsel *e;
  313. evlist__for_each_entry(evlist, e) {
  314. if (perf_evsel__match2(evsel, e))
  315. return e;
  316. }
  317. return NULL;
  318. }
  319. static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
  320. {
  321. struct perf_evsel *evsel;
  322. evlist__for_each_entry(evlist, evsel) {
  323. struct hists *hists = evsel__hists(evsel);
  324. hists__collapse_resort(hists, NULL);
  325. }
  326. }
  327. static struct data__file *fmt_to_data_file(struct perf_hpp_fmt *fmt)
  328. {
  329. struct diff_hpp_fmt *dfmt = container_of(fmt, struct diff_hpp_fmt, fmt);
  330. void *ptr = dfmt - dfmt->idx;
  331. struct data__file *d = container_of(ptr, struct data__file, fmt);
  332. return d;
  333. }
  334. static struct hist_entry*
  335. get_pair_data(struct hist_entry *he, struct data__file *d)
  336. {
  337. if (hist_entry__has_pairs(he)) {
  338. struct hist_entry *pair;
  339. list_for_each_entry(pair, &he->pairs.head, pairs.node)
  340. if (pair->hists == d->hists)
  341. return pair;
  342. }
  343. return NULL;
  344. }
  345. static struct hist_entry*
  346. get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)
  347. {
  348. struct data__file *d = fmt_to_data_file(&dfmt->fmt);
  349. return get_pair_data(he, d);
  350. }
  351. static void hists__baseline_only(struct hists *hists)
  352. {
  353. struct rb_root *root;
  354. struct rb_node *next;
  355. if (hists__has(hists, need_collapse))
  356. root = &hists->entries_collapsed;
  357. else
  358. root = hists->entries_in;
  359. next = rb_first(root);
  360. while (next != NULL) {
  361. struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
  362. next = rb_next(&he->rb_node_in);
  363. if (!hist_entry__next_pair(he)) {
  364. rb_erase(&he->rb_node_in, root);
  365. hist_entry__delete(he);
  366. }
  367. }
  368. }
  369. static void hists__precompute(struct hists *hists)
  370. {
  371. struct rb_root *root;
  372. struct rb_node *next;
  373. if (hists__has(hists, need_collapse))
  374. root = &hists->entries_collapsed;
  375. else
  376. root = hists->entries_in;
  377. next = rb_first(root);
  378. while (next != NULL) {
  379. struct hist_entry *he, *pair;
  380. struct data__file *d;
  381. int i;
  382. he = rb_entry(next, struct hist_entry, rb_node_in);
  383. next = rb_next(&he->rb_node_in);
  384. data__for_each_file_new(i, d) {
  385. pair = get_pair_data(he, d);
  386. if (!pair)
  387. continue;
  388. switch (compute) {
  389. case COMPUTE_DELTA:
  390. case COMPUTE_DELTA_ABS:
  391. compute_delta(he, pair);
  392. break;
  393. case COMPUTE_RATIO:
  394. compute_ratio(he, pair);
  395. break;
  396. case COMPUTE_WEIGHTED_DIFF:
  397. compute_wdiff(he, pair);
  398. break;
  399. default:
  400. BUG_ON(1);
  401. }
  402. }
  403. }
  404. }
  405. static int64_t cmp_doubles(double l, double r)
  406. {
  407. if (l > r)
  408. return -1;
  409. else if (l < r)
  410. return 1;
  411. else
  412. return 0;
  413. }
  414. static int64_t
  415. __hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
  416. int c)
  417. {
  418. switch (c) {
  419. case COMPUTE_DELTA:
  420. {
  421. double l = left->diff.period_ratio_delta;
  422. double r = right->diff.period_ratio_delta;
  423. return cmp_doubles(l, r);
  424. }
  425. case COMPUTE_DELTA_ABS:
  426. {
  427. double l = fabs(left->diff.period_ratio_delta);
  428. double r = fabs(right->diff.period_ratio_delta);
  429. return cmp_doubles(l, r);
  430. }
  431. case COMPUTE_RATIO:
  432. {
  433. double l = left->diff.period_ratio;
  434. double r = right->diff.period_ratio;
  435. return cmp_doubles(l, r);
  436. }
  437. case COMPUTE_WEIGHTED_DIFF:
  438. {
  439. s64 l = left->diff.wdiff;
  440. s64 r = right->diff.wdiff;
  441. return r - l;
  442. }
  443. default:
  444. BUG_ON(1);
  445. }
  446. return 0;
  447. }
  448. static int64_t
  449. hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
  450. int c, int sort_idx)
  451. {
  452. bool pairs_left = hist_entry__has_pairs(left);
  453. bool pairs_right = hist_entry__has_pairs(right);
  454. struct hist_entry *p_right, *p_left;
  455. if (!pairs_left && !pairs_right)
  456. return 0;
  457. if (!pairs_left || !pairs_right)
  458. return pairs_left ? -1 : 1;
  459. p_left = get_pair_data(left, &data__files[sort_idx]);
  460. p_right = get_pair_data(right, &data__files[sort_idx]);
  461. if (!p_left && !p_right)
  462. return 0;
  463. if (!p_left || !p_right)
  464. return p_left ? -1 : 1;
  465. /*
  466. * We have 2 entries of same kind, let's
  467. * make the data comparison.
  468. */
  469. return __hist_entry__cmp_compute(p_left, p_right, c);
  470. }
  471. static int64_t
  472. hist_entry__cmp_compute_idx(struct hist_entry *left, struct hist_entry *right,
  473. int c, int sort_idx)
  474. {
  475. struct hist_entry *p_right, *p_left;
  476. p_left = get_pair_data(left, &data__files[sort_idx]);
  477. p_right = get_pair_data(right, &data__files[sort_idx]);
  478. if (!p_left && !p_right)
  479. return 0;
  480. if (!p_left || !p_right)
  481. return p_left ? -1 : 1;
  482. if (c != COMPUTE_DELTA && c != COMPUTE_DELTA_ABS) {
  483. /*
  484. * The delta can be computed without the baseline, but
  485. * others are not. Put those entries which have no
  486. * values below.
  487. */
  488. if (left->dummy && right->dummy)
  489. return 0;
  490. if (left->dummy || right->dummy)
  491. return left->dummy ? 1 : -1;
  492. }
  493. return __hist_entry__cmp_compute(p_left, p_right, c);
  494. }
  495. static int64_t
  496. hist_entry__cmp_nop(struct perf_hpp_fmt *fmt __maybe_unused,
  497. struct hist_entry *left __maybe_unused,
  498. struct hist_entry *right __maybe_unused)
  499. {
  500. return 0;
  501. }
  502. static int64_t
  503. hist_entry__cmp_baseline(struct perf_hpp_fmt *fmt __maybe_unused,
  504. struct hist_entry *left, struct hist_entry *right)
  505. {
  506. if (left->stat.period == right->stat.period)
  507. return 0;
  508. return left->stat.period > right->stat.period ? 1 : -1;
  509. }
  510. static int64_t
  511. hist_entry__cmp_delta(struct perf_hpp_fmt *fmt,
  512. struct hist_entry *left, struct hist_entry *right)
  513. {
  514. struct data__file *d = fmt_to_data_file(fmt);
  515. return hist_entry__cmp_compute(right, left, COMPUTE_DELTA, d->idx);
  516. }
  517. static int64_t
  518. hist_entry__cmp_delta_abs(struct perf_hpp_fmt *fmt,
  519. struct hist_entry *left, struct hist_entry *right)
  520. {
  521. struct data__file *d = fmt_to_data_file(fmt);
  522. return hist_entry__cmp_compute(right, left, COMPUTE_DELTA_ABS, d->idx);
  523. }
  524. static int64_t
  525. hist_entry__cmp_ratio(struct perf_hpp_fmt *fmt,
  526. struct hist_entry *left, struct hist_entry *right)
  527. {
  528. struct data__file *d = fmt_to_data_file(fmt);
  529. return hist_entry__cmp_compute(right, left, COMPUTE_RATIO, d->idx);
  530. }
  531. static int64_t
  532. hist_entry__cmp_wdiff(struct perf_hpp_fmt *fmt,
  533. struct hist_entry *left, struct hist_entry *right)
  534. {
  535. struct data__file *d = fmt_to_data_file(fmt);
  536. return hist_entry__cmp_compute(right, left, COMPUTE_WEIGHTED_DIFF, d->idx);
  537. }
  538. static int64_t
  539. hist_entry__cmp_delta_idx(struct perf_hpp_fmt *fmt __maybe_unused,
  540. struct hist_entry *left, struct hist_entry *right)
  541. {
  542. return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA,
  543. sort_compute);
  544. }
  545. static int64_t
  546. hist_entry__cmp_delta_abs_idx(struct perf_hpp_fmt *fmt __maybe_unused,
  547. struct hist_entry *left, struct hist_entry *right)
  548. {
  549. return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA_ABS,
  550. sort_compute);
  551. }
  552. static int64_t
  553. hist_entry__cmp_ratio_idx(struct perf_hpp_fmt *fmt __maybe_unused,
  554. struct hist_entry *left, struct hist_entry *right)
  555. {
  556. return hist_entry__cmp_compute_idx(right, left, COMPUTE_RATIO,
  557. sort_compute);
  558. }
  559. static int64_t
  560. hist_entry__cmp_wdiff_idx(struct perf_hpp_fmt *fmt __maybe_unused,
  561. struct hist_entry *left, struct hist_entry *right)
  562. {
  563. return hist_entry__cmp_compute_idx(right, left, COMPUTE_WEIGHTED_DIFF,
  564. sort_compute);
  565. }
  566. static void hists__process(struct hists *hists)
  567. {
  568. if (show_baseline_only)
  569. hists__baseline_only(hists);
  570. hists__precompute(hists);
  571. hists__output_resort(hists, NULL);
  572. hists__fprintf(hists, !quiet, 0, 0, 0, stdout,
  573. symbol_conf.use_callchain);
  574. }
  575. static void data__fprintf(void)
  576. {
  577. struct data__file *d;
  578. int i;
  579. fprintf(stdout, "# Data files:\n");
  580. data__for_each_file(i, d)
  581. fprintf(stdout, "# [%d] %s %s\n",
  582. d->idx, d->file.path,
  583. !d->idx ? "(Baseline)" : "");
  584. fprintf(stdout, "#\n");
  585. }
  586. static void data_process(void)
  587. {
  588. struct perf_evlist *evlist_base = data__files[0].session->evlist;
  589. struct perf_evsel *evsel_base;
  590. bool first = true;
  591. evlist__for_each_entry(evlist_base, evsel_base) {
  592. struct hists *hists_base = evsel__hists(evsel_base);
  593. struct data__file *d;
  594. int i;
  595. data__for_each_file_new(i, d) {
  596. struct perf_evlist *evlist = d->session->evlist;
  597. struct perf_evsel *evsel;
  598. struct hists *hists;
  599. evsel = evsel_match(evsel_base, evlist);
  600. if (!evsel)
  601. continue;
  602. hists = evsel__hists(evsel);
  603. d->hists = hists;
  604. hists__match(hists_base, hists);
  605. if (!show_baseline_only)
  606. hists__link(hists_base, hists);
  607. }
  608. if (!quiet) {
  609. fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
  610. perf_evsel__name(evsel_base));
  611. }
  612. first = false;
  613. if (verbose > 0 || ((data__files_cnt > 2) && !quiet))
  614. data__fprintf();
  615. /* Don't sort callchain for perf diff */
  616. perf_evsel__reset_sample_bit(evsel_base, CALLCHAIN);
  617. hists__process(hists_base);
  618. }
  619. }
  620. static void data__free(struct data__file *d)
  621. {
  622. int col;
  623. for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
  624. struct diff_hpp_fmt *fmt = &d->fmt[col];
  625. zfree(&fmt->header);
  626. }
  627. }
  628. static int __cmd_diff(void)
  629. {
  630. struct data__file *d;
  631. int ret = -EINVAL, i;
  632. data__for_each_file(i, d) {
  633. d->session = perf_session__new(&d->file, false, &tool);
  634. if (!d->session) {
  635. pr_err("Failed to open %s\n", d->file.path);
  636. ret = -1;
  637. goto out_delete;
  638. }
  639. ret = perf_session__process_events(d->session);
  640. if (ret) {
  641. pr_err("Failed to process %s\n", d->file.path);
  642. goto out_delete;
  643. }
  644. perf_evlist__collapse_resort(d->session->evlist);
  645. }
  646. data_process();
  647. out_delete:
  648. data__for_each_file(i, d) {
  649. perf_session__delete(d->session);
  650. data__free(d);
  651. }
  652. free(data__files);
  653. return ret;
  654. }
  655. static const char * const diff_usage[] = {
  656. "perf diff [<options>] [old_file] [new_file]",
  657. NULL,
  658. };
  659. static const struct option options[] = {
  660. OPT_INCR('v', "verbose", &verbose,
  661. "be more verbose (show symbol address, etc)"),
  662. OPT_BOOLEAN('q', "quiet", &quiet, "Do not show any message"),
  663. OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
  664. "Show only items with match in baseline"),
  665. OPT_CALLBACK('c', "compute", &compute,
  666. "delta,delta-abs,ratio,wdiff:w1,w2 (default delta-abs)",
  667. "Entries differential computation selection",
  668. setup_compute),
  669. OPT_BOOLEAN('p', "period", &show_period,
  670. "Show period values."),
  671. OPT_BOOLEAN('F', "formula", &show_formula,
  672. "Show formula."),
  673. OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
  674. "dump raw trace in ASCII"),
  675. OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
  676. OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
  677. "file", "kallsyms pathname"),
  678. OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
  679. "load module symbols - WARNING: use only with -k and LIVE kernel"),
  680. OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
  681. "only consider symbols in these dsos"),
  682. OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
  683. "only consider symbols in these comms"),
  684. OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
  685. "only consider these symbols"),
  686. OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
  687. "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
  688. " Please refer the man page for the complete list."),
  689. OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator",
  690. "separator for columns, no spaces will be added between "
  691. "columns '.' is reserved."),
  692. OPT_CALLBACK(0, "symfs", NULL, "directory",
  693. "Look for files with symbols relative to this directory",
  694. symbol__config_symfs),
  695. OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
  696. OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
  697. "How to display percentage of filtered entries", parse_filter_percentage),
  698. OPT_END()
  699. };
  700. static double baseline_percent(struct hist_entry *he)
  701. {
  702. u64 total = hists__total_period(he->hists);
  703. return 100.0 * he->stat.period / total;
  704. }
  705. static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
  706. struct perf_hpp *hpp, struct hist_entry *he)
  707. {
  708. struct diff_hpp_fmt *dfmt =
  709. container_of(fmt, struct diff_hpp_fmt, fmt);
  710. double percent = baseline_percent(he);
  711. char pfmt[20] = " ";
  712. if (!he->dummy) {
  713. scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1);
  714. return percent_color_snprintf(hpp->buf, hpp->size,
  715. pfmt, percent);
  716. } else
  717. return scnprintf(hpp->buf, hpp->size, "%*s",
  718. dfmt->header_width, pfmt);
  719. }
  720. static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
  721. {
  722. double percent = baseline_percent(he);
  723. const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
  724. int ret = 0;
  725. if (!he->dummy)
  726. ret = scnprintf(buf, size, fmt, percent);
  727. return ret;
  728. }
  729. static int __hpp__color_compare(struct perf_hpp_fmt *fmt,
  730. struct perf_hpp *hpp, struct hist_entry *he,
  731. int comparison_method)
  732. {
  733. struct diff_hpp_fmt *dfmt =
  734. container_of(fmt, struct diff_hpp_fmt, fmt);
  735. struct hist_entry *pair = get_pair_fmt(he, dfmt);
  736. double diff;
  737. s64 wdiff;
  738. char pfmt[20] = " ";
  739. if (!pair)
  740. goto no_print;
  741. switch (comparison_method) {
  742. case COMPUTE_DELTA:
  743. if (pair->diff.computed)
  744. diff = pair->diff.period_ratio_delta;
  745. else
  746. diff = compute_delta(he, pair);
  747. scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1);
  748. return percent_color_snprintf(hpp->buf, hpp->size,
  749. pfmt, diff);
  750. case COMPUTE_RATIO:
  751. if (he->dummy)
  752. goto dummy_print;
  753. if (pair->diff.computed)
  754. diff = pair->diff.period_ratio;
  755. else
  756. diff = compute_ratio(he, pair);
  757. scnprintf(pfmt, 20, "%%%d.6f", dfmt->header_width);
  758. return value_color_snprintf(hpp->buf, hpp->size,
  759. pfmt, diff);
  760. case COMPUTE_WEIGHTED_DIFF:
  761. if (he->dummy)
  762. goto dummy_print;
  763. if (pair->diff.computed)
  764. wdiff = pair->diff.wdiff;
  765. else
  766. wdiff = compute_wdiff(he, pair);
  767. scnprintf(pfmt, 20, "%%14ld", dfmt->header_width);
  768. return color_snprintf(hpp->buf, hpp->size,
  769. get_percent_color(wdiff),
  770. pfmt, wdiff);
  771. default:
  772. BUG_ON(1);
  773. }
  774. dummy_print:
  775. return scnprintf(hpp->buf, hpp->size, "%*s",
  776. dfmt->header_width, "N/A");
  777. no_print:
  778. return scnprintf(hpp->buf, hpp->size, "%*s",
  779. dfmt->header_width, pfmt);
  780. }
  781. static int hpp__color_delta(struct perf_hpp_fmt *fmt,
  782. struct perf_hpp *hpp, struct hist_entry *he)
  783. {
  784. return __hpp__color_compare(fmt, hpp, he, COMPUTE_DELTA);
  785. }
  786. static int hpp__color_ratio(struct perf_hpp_fmt *fmt,
  787. struct perf_hpp *hpp, struct hist_entry *he)
  788. {
  789. return __hpp__color_compare(fmt, hpp, he, COMPUTE_RATIO);
  790. }
  791. static int hpp__color_wdiff(struct perf_hpp_fmt *fmt,
  792. struct perf_hpp *hpp, struct hist_entry *he)
  793. {
  794. return __hpp__color_compare(fmt, hpp, he, COMPUTE_WEIGHTED_DIFF);
  795. }
  796. static void
  797. hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
  798. {
  799. switch (idx) {
  800. case PERF_HPP_DIFF__PERIOD_BASELINE:
  801. scnprintf(buf, size, "%" PRIu64, he->stat.period);
  802. break;
  803. default:
  804. break;
  805. }
  806. }
  807. static void
  808. hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
  809. int idx, char *buf, size_t size)
  810. {
  811. double diff;
  812. double ratio;
  813. s64 wdiff;
  814. switch (idx) {
  815. case PERF_HPP_DIFF__DELTA:
  816. case PERF_HPP_DIFF__DELTA_ABS:
  817. if (pair->diff.computed)
  818. diff = pair->diff.period_ratio_delta;
  819. else
  820. diff = compute_delta(he, pair);
  821. scnprintf(buf, size, "%+4.2F%%", diff);
  822. break;
  823. case PERF_HPP_DIFF__RATIO:
  824. /* No point for ratio number if we are dummy.. */
  825. if (he->dummy) {
  826. scnprintf(buf, size, "N/A");
  827. break;
  828. }
  829. if (pair->diff.computed)
  830. ratio = pair->diff.period_ratio;
  831. else
  832. ratio = compute_ratio(he, pair);
  833. if (ratio > 0.0)
  834. scnprintf(buf, size, "%14.6F", ratio);
  835. break;
  836. case PERF_HPP_DIFF__WEIGHTED_DIFF:
  837. /* No point for wdiff number if we are dummy.. */
  838. if (he->dummy) {
  839. scnprintf(buf, size, "N/A");
  840. break;
  841. }
  842. if (pair->diff.computed)
  843. wdiff = pair->diff.wdiff;
  844. else
  845. wdiff = compute_wdiff(he, pair);
  846. if (wdiff != 0)
  847. scnprintf(buf, size, "%14ld", wdiff);
  848. break;
  849. case PERF_HPP_DIFF__FORMULA:
  850. formula_fprintf(he, pair, buf, size);
  851. break;
  852. case PERF_HPP_DIFF__PERIOD:
  853. scnprintf(buf, size, "%" PRIu64, pair->stat.period);
  854. break;
  855. default:
  856. BUG_ON(1);
  857. };
  858. }
  859. static void
  860. __hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt,
  861. char *buf, size_t size)
  862. {
  863. struct hist_entry *pair = get_pair_fmt(he, dfmt);
  864. int idx = dfmt->idx;
  865. /* baseline is special */
  866. if (idx == PERF_HPP_DIFF__BASELINE)
  867. hpp__entry_baseline(he, buf, size);
  868. else {
  869. if (pair)
  870. hpp__entry_pair(he, pair, idx, buf, size);
  871. else
  872. hpp__entry_unpair(he, idx, buf, size);
  873. }
  874. }
  875. static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
  876. struct hist_entry *he)
  877. {
  878. struct diff_hpp_fmt *dfmt =
  879. container_of(_fmt, struct diff_hpp_fmt, fmt);
  880. char buf[MAX_COL_WIDTH] = " ";
  881. __hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH);
  882. if (symbol_conf.field_sep)
  883. return scnprintf(hpp->buf, hpp->size, "%s", buf);
  884. else
  885. return scnprintf(hpp->buf, hpp->size, "%*s",
  886. dfmt->header_width, buf);
  887. }
  888. static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
  889. struct hists *hists __maybe_unused,
  890. int line __maybe_unused,
  891. int *span __maybe_unused)
  892. {
  893. struct diff_hpp_fmt *dfmt =
  894. container_of(fmt, struct diff_hpp_fmt, fmt);
  895. BUG_ON(!dfmt->header);
  896. return scnprintf(hpp->buf, hpp->size, dfmt->header);
  897. }
  898. static int hpp__width(struct perf_hpp_fmt *fmt,
  899. struct perf_hpp *hpp __maybe_unused,
  900. struct hists *hists __maybe_unused)
  901. {
  902. struct diff_hpp_fmt *dfmt =
  903. container_of(fmt, struct diff_hpp_fmt, fmt);
  904. BUG_ON(dfmt->header_width <= 0);
  905. return dfmt->header_width;
  906. }
  907. static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt)
  908. {
  909. #define MAX_HEADER_NAME 100
  910. char buf_indent[MAX_HEADER_NAME];
  911. char buf[MAX_HEADER_NAME];
  912. const char *header = NULL;
  913. int width = 0;
  914. BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX);
  915. header = columns[dfmt->idx].name;
  916. width = columns[dfmt->idx].width;
  917. /* Only our defined HPP fmts should appear here. */
  918. BUG_ON(!header);
  919. if (data__files_cnt > 2)
  920. scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx);
  921. #define NAME (data__files_cnt > 2 ? buf : header)
  922. dfmt->header_width = width;
  923. width = (int) strlen(NAME);
  924. if (dfmt->header_width < width)
  925. dfmt->header_width = width;
  926. scnprintf(buf_indent, MAX_HEADER_NAME, "%*s",
  927. dfmt->header_width, NAME);
  928. dfmt->header = strdup(buf_indent);
  929. #undef MAX_HEADER_NAME
  930. #undef NAME
  931. }
  932. static void data__hpp_register(struct data__file *d, int idx)
  933. {
  934. struct diff_hpp_fmt *dfmt = &d->fmt[idx];
  935. struct perf_hpp_fmt *fmt = &dfmt->fmt;
  936. dfmt->idx = idx;
  937. fmt->header = hpp__header;
  938. fmt->width = hpp__width;
  939. fmt->entry = hpp__entry_global;
  940. fmt->cmp = hist_entry__cmp_nop;
  941. fmt->collapse = hist_entry__cmp_nop;
  942. /* TODO more colors */
  943. switch (idx) {
  944. case PERF_HPP_DIFF__BASELINE:
  945. fmt->color = hpp__color_baseline;
  946. fmt->sort = hist_entry__cmp_baseline;
  947. break;
  948. case PERF_HPP_DIFF__DELTA:
  949. fmt->color = hpp__color_delta;
  950. fmt->sort = hist_entry__cmp_delta;
  951. break;
  952. case PERF_HPP_DIFF__RATIO:
  953. fmt->color = hpp__color_ratio;
  954. fmt->sort = hist_entry__cmp_ratio;
  955. break;
  956. case PERF_HPP_DIFF__WEIGHTED_DIFF:
  957. fmt->color = hpp__color_wdiff;
  958. fmt->sort = hist_entry__cmp_wdiff;
  959. break;
  960. case PERF_HPP_DIFF__DELTA_ABS:
  961. fmt->color = hpp__color_delta;
  962. fmt->sort = hist_entry__cmp_delta_abs;
  963. break;
  964. default:
  965. fmt->sort = hist_entry__cmp_nop;
  966. break;
  967. }
  968. init_header(d, dfmt);
  969. perf_hpp__column_register(fmt);
  970. perf_hpp__register_sort_field(fmt);
  971. }
  972. static int ui_init(void)
  973. {
  974. struct data__file *d;
  975. struct perf_hpp_fmt *fmt;
  976. int i;
  977. data__for_each_file(i, d) {
  978. /*
  979. * Baseline or compute realted columns:
  980. *
  981. * PERF_HPP_DIFF__BASELINE
  982. * PERF_HPP_DIFF__DELTA
  983. * PERF_HPP_DIFF__RATIO
  984. * PERF_HPP_DIFF__WEIGHTED_DIFF
  985. */
  986. data__hpp_register(d, i ? compute_2_hpp[compute] :
  987. PERF_HPP_DIFF__BASELINE);
  988. /*
  989. * And the rest:
  990. *
  991. * PERF_HPP_DIFF__FORMULA
  992. * PERF_HPP_DIFF__PERIOD
  993. * PERF_HPP_DIFF__PERIOD_BASELINE
  994. */
  995. if (show_formula && i)
  996. data__hpp_register(d, PERF_HPP_DIFF__FORMULA);
  997. if (show_period)
  998. data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD :
  999. PERF_HPP_DIFF__PERIOD_BASELINE);
  1000. }
  1001. if (!sort_compute)
  1002. return 0;
  1003. /*
  1004. * Prepend an fmt to sort on columns at 'sort_compute' first.
  1005. * This fmt is added only to the sort list but not to the
  1006. * output fields list.
  1007. *
  1008. * Note that this column (data) can be compared twice - one
  1009. * for this 'sort_compute' fmt and another for the normal
  1010. * diff_hpp_fmt. But it shouldn't a problem as most entries
  1011. * will be sorted out by first try or baseline and comparing
  1012. * is not a costly operation.
  1013. */
  1014. fmt = zalloc(sizeof(*fmt));
  1015. if (fmt == NULL) {
  1016. pr_err("Memory allocation failed\n");
  1017. return -1;
  1018. }
  1019. fmt->cmp = hist_entry__cmp_nop;
  1020. fmt->collapse = hist_entry__cmp_nop;
  1021. switch (compute) {
  1022. case COMPUTE_DELTA:
  1023. fmt->sort = hist_entry__cmp_delta_idx;
  1024. break;
  1025. case COMPUTE_RATIO:
  1026. fmt->sort = hist_entry__cmp_ratio_idx;
  1027. break;
  1028. case COMPUTE_WEIGHTED_DIFF:
  1029. fmt->sort = hist_entry__cmp_wdiff_idx;
  1030. break;
  1031. case COMPUTE_DELTA_ABS:
  1032. fmt->sort = hist_entry__cmp_delta_abs_idx;
  1033. break;
  1034. default:
  1035. BUG_ON(1);
  1036. }
  1037. perf_hpp__prepend_sort_field(fmt);
  1038. return 0;
  1039. }
  1040. static int data_init(int argc, const char **argv)
  1041. {
  1042. struct data__file *d;
  1043. static const char *defaults[] = {
  1044. "perf.data.old",
  1045. "perf.data",
  1046. };
  1047. bool use_default = true;
  1048. int i;
  1049. data__files_cnt = 2;
  1050. if (argc) {
  1051. if (argc == 1)
  1052. defaults[1] = argv[0];
  1053. else {
  1054. data__files_cnt = argc;
  1055. use_default = false;
  1056. }
  1057. } else if (perf_guest) {
  1058. defaults[0] = "perf.data.host";
  1059. defaults[1] = "perf.data.guest";
  1060. }
  1061. if (sort_compute >= (unsigned int) data__files_cnt) {
  1062. pr_err("Order option out of limit.\n");
  1063. return -EINVAL;
  1064. }
  1065. data__files = zalloc(sizeof(*data__files) * data__files_cnt);
  1066. if (!data__files)
  1067. return -ENOMEM;
  1068. data__for_each_file(i, d) {
  1069. struct perf_data_file *file = &d->file;
  1070. file->path = use_default ? defaults[i] : argv[i];
  1071. file->mode = PERF_DATA_MODE_READ,
  1072. file->force = force,
  1073. d->idx = i;
  1074. }
  1075. return 0;
  1076. }
  1077. static int diff__config(const char *var, const char *value,
  1078. void *cb __maybe_unused)
  1079. {
  1080. if (!strcmp(var, "diff.order")) {
  1081. sort_compute = perf_config_int(var, value);
  1082. return 0;
  1083. }
  1084. if (!strcmp(var, "diff.compute")) {
  1085. if (!strcmp(value, "delta")) {
  1086. compute = COMPUTE_DELTA;
  1087. } else if (!strcmp(value, "delta-abs")) {
  1088. compute = COMPUTE_DELTA_ABS;
  1089. } else if (!strcmp(value, "ratio")) {
  1090. compute = COMPUTE_RATIO;
  1091. } else if (!strcmp(value, "wdiff")) {
  1092. compute = COMPUTE_WEIGHTED_DIFF;
  1093. } else {
  1094. pr_err("Invalid compute method: %s\n", value);
  1095. return -1;
  1096. }
  1097. }
  1098. return 0;
  1099. }
  1100. int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
  1101. {
  1102. int ret = hists__init();
  1103. if (ret < 0)
  1104. return ret;
  1105. perf_config(diff__config, NULL);
  1106. argc = parse_options(argc, argv, options, diff_usage, 0);
  1107. if (quiet)
  1108. perf_quiet_option();
  1109. if (symbol__init(NULL) < 0)
  1110. return -1;
  1111. if (data_init(argc, argv) < 0)
  1112. return -1;
  1113. if (ui_init() < 0)
  1114. return -1;
  1115. sort__mode = SORT_MODE__DIFF;
  1116. if (setup_sorting(NULL) < 0)
  1117. usage_with_options(diff_usage, options);
  1118. setup_pager();
  1119. sort__setup_elide(NULL);
  1120. return __cmd_diff();
  1121. }