aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/annotate.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/annotate.c')
-rw-r--r--tools/perf/util/annotate.c337
1 files changed, 212 insertions, 125 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index f91775b4bc3c..28cd6a17491b 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -49,6 +49,7 @@ struct annotation_options annotation__default_options = {
49 .jump_arrows = true, 49 .jump_arrows = true,
50 .annotate_src = true, 50 .annotate_src = true,
51 .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, 51 .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS,
52 .percent_type = PERCENT_PERIOD_LOCAL,
52}; 53};
53 54
54static regex_t file_lineno; 55static regex_t file_lineno;
@@ -245,8 +246,14 @@ find_target:
245 246
246indirect_call: 247indirect_call:
247 tok = strchr(endptr, '*'); 248 tok = strchr(endptr, '*');
248 if (tok != NULL) 249 if (tok != NULL) {
249 ops->target.addr = strtoull(tok + 1, NULL, 16); 250 endptr++;
251
252 /* Indirect call can use a non-rip register and offset: callq *0x8(%rbx).
253 * Do not parse such instruction. */
254 if (strstr(endptr, "(%r") == NULL)
255 ops->target.addr = strtoull(endptr, NULL, 16);
256 }
250 goto find_target; 257 goto find_target;
251} 258}
252 259
@@ -275,7 +282,19 @@ bool ins__is_call(const struct ins *ins)
275 return ins->ops == &call_ops || ins->ops == &s390_call_ops; 282 return ins->ops == &call_ops || ins->ops == &s390_call_ops;
276} 283}
277 284
278static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms) 285/*
286 * Prevents from matching commas in the comment section, e.g.:
287 * ffff200008446e70: b.cs ffff2000084470f4 <generic_exec_single+0x314> // b.hs, b.nlast
288 */
289static inline const char *validate_comma(const char *c, struct ins_operands *ops)
290{
291 if (ops->raw_comment && c > ops->raw_comment)
292 return NULL;
293
294 return c;
295}
296
297static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
279{ 298{
280 struct map *map = ms->map; 299 struct map *map = ms->map;
281 struct symbol *sym = ms->sym; 300 struct symbol *sym = ms->sym;
@@ -284,6 +303,10 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op
284 }; 303 };
285 const char *c = strchr(ops->raw, ','); 304 const char *c = strchr(ops->raw, ',');
286 u64 start, end; 305 u64 start, end;
306
307 ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char);
308 c = validate_comma(c, ops);
309
287 /* 310 /*
288 * Examples of lines to parse for the _cpp_lex_token@@Base 311 * Examples of lines to parse for the _cpp_lex_token@@Base
289 * function: 312 * function:
@@ -303,6 +326,7 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op
303 ops->target.addr = strtoull(c, NULL, 16); 326 ops->target.addr = strtoull(c, NULL, 16);
304 if (!ops->target.addr) { 327 if (!ops->target.addr) {
305 c = strchr(c, ','); 328 c = strchr(c, ',');
329 c = validate_comma(c, ops);
306 if (c++ != NULL) 330 if (c++ != NULL)
307 ops->target.addr = strtoull(c, NULL, 16); 331 ops->target.addr = strtoull(c, NULL, 16);
308 } 332 }
@@ -360,9 +384,12 @@ static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
360 return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.sym->name); 384 return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.sym->name);
361 385
362 c = strchr(ops->raw, ','); 386 c = strchr(ops->raw, ',');
387 c = validate_comma(c, ops);
388
363 if (c != NULL) { 389 if (c != NULL) {
364 const char *c2 = strchr(c + 1, ','); 390 const char *c2 = strchr(c + 1, ',');
365 391
392 c2 = validate_comma(c2, ops);
366 /* check for 3-op insn */ 393 /* check for 3-op insn */
367 if (c2 != NULL) 394 if (c2 != NULL)
368 c = c2; 395 c = c2;
@@ -1108,7 +1135,7 @@ annotation_line__new(struct annotate_args *args, size_t privsize)
1108 if (perf_evsel__is_group_event(evsel)) 1135 if (perf_evsel__is_group_event(evsel))
1109 nr = evsel->nr_members; 1136 nr = evsel->nr_members;
1110 1137
1111 size += sizeof(al->samples[0]) * nr; 1138 size += sizeof(al->data[0]) * nr;
1112 1139
1113 al = zalloc(size); 1140 al = zalloc(size);
1114 if (al) { 1141 if (al) {
@@ -1117,7 +1144,7 @@ annotation_line__new(struct annotate_args *args, size_t privsize)
1117 al->offset = args->offset; 1144 al->offset = args->offset;
1118 al->line = strdup(args->line); 1145 al->line = strdup(args->line);
1119 al->line_nr = args->line_nr; 1146 al->line_nr = args->line_nr;
1120 al->samples_nr = nr; 1147 al->data_nr = nr;
1121 } 1148 }
1122 1149
1123 return al; 1150 return al;
@@ -1297,7 +1324,8 @@ static int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_wi
1297static int 1324static int
1298annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, 1325annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start,
1299 struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, 1326 struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,
1300 int max_lines, struct annotation_line *queue, int addr_fmt_width) 1327 int max_lines, struct annotation_line *queue, int addr_fmt_width,
1328 int percent_type)
1301{ 1329{
1302 struct disasm_line *dl = container_of(al, struct disasm_line, al); 1330 struct disasm_line *dl = container_of(al, struct disasm_line, al);
1303 static const char *prev_line; 1331 static const char *prev_line;
@@ -1309,15 +1337,18 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start
1309 const char *color; 1337 const char *color;
1310 struct annotation *notes = symbol__annotation(sym); 1338 struct annotation *notes = symbol__annotation(sym);
1311 1339
1312 for (i = 0; i < al->samples_nr; i++) { 1340 for (i = 0; i < al->data_nr; i++) {
1313 struct annotation_data *sample = &al->samples[i]; 1341 double percent;
1314 1342
1315 if (sample->percent > max_percent) 1343 percent = annotation_data__percent(&al->data[i],
1316 max_percent = sample->percent; 1344 percent_type);
1345
1346 if (percent > max_percent)
1347 max_percent = percent;
1317 } 1348 }
1318 1349
1319 if (al->samples_nr > nr_percent) 1350 if (al->data_nr > nr_percent)
1320 nr_percent = al->samples_nr; 1351 nr_percent = al->data_nr;
1321 1352
1322 if (max_percent < min_pcnt) 1353 if (max_percent < min_pcnt)
1323 return -1; 1354 return -1;
@@ -1330,7 +1361,8 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start
1330 if (queue == al) 1361 if (queue == al)
1331 break; 1362 break;
1332 annotation_line__print(queue, sym, start, evsel, len, 1363 annotation_line__print(queue, sym, start, evsel, len,
1333 0, 0, 1, NULL, addr_fmt_width); 1364 0, 0, 1, NULL, addr_fmt_width,
1365 percent_type);
1334 } 1366 }
1335 } 1367 }
1336 1368
@@ -1351,18 +1383,20 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start
1351 } 1383 }
1352 1384
1353 for (i = 0; i < nr_percent; i++) { 1385 for (i = 0; i < nr_percent; i++) {
1354 struct annotation_data *sample = &al->samples[i]; 1386 struct annotation_data *data = &al->data[i];
1387 double percent;
1355 1388
1356 color = get_percent_color(sample->percent); 1389 percent = annotation_data__percent(data, percent_type);
1390 color = get_percent_color(percent);
1357 1391
1358 if (symbol_conf.show_total_period) 1392 if (symbol_conf.show_total_period)
1359 color_fprintf(stdout, color, " %11" PRIu64, 1393 color_fprintf(stdout, color, " %11" PRIu64,
1360 sample->he.period); 1394 data->he.period);
1361 else if (symbol_conf.show_nr_samples) 1395 else if (symbol_conf.show_nr_samples)
1362 color_fprintf(stdout, color, " %7" PRIu64, 1396 color_fprintf(stdout, color, " %7" PRIu64,
1363 sample->he.nr_samples); 1397 data->he.nr_samples);
1364 else 1398 else
1365 color_fprintf(stdout, color, " %7.2f", sample->percent); 1399 color_fprintf(stdout, color, " %7.2f", percent);
1366 } 1400 }
1367 1401
1368 printf(" : "); 1402 printf(" : ");
@@ -1621,6 +1655,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
1621 char symfs_filename[PATH_MAX]; 1655 char symfs_filename[PATH_MAX];
1622 struct kcore_extract kce; 1656 struct kcore_extract kce;
1623 bool delete_extract = false; 1657 bool delete_extract = false;
1658 bool decomp = false;
1624 int stdout_fd[2]; 1659 int stdout_fd[2];
1625 int lineno = 0; 1660 int lineno = 0;
1626 int nline; 1661 int nline;
@@ -1654,6 +1689,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
1654 tmp, sizeof(tmp)) < 0) 1689 tmp, sizeof(tmp)) < 0)
1655 goto out; 1690 goto out;
1656 1691
1692 decomp = true;
1657 strcpy(symfs_filename, tmp); 1693 strcpy(symfs_filename, tmp);
1658 } 1694 }
1659 1695
@@ -1740,7 +1776,7 @@ out_free_command:
1740out_remove_tmp: 1776out_remove_tmp:
1741 close(stdout_fd[0]); 1777 close(stdout_fd[0]);
1742 1778
1743 if (dso__needs_decompress(dso)) 1779 if (decomp)
1744 unlink(symfs_filename); 1780 unlink(symfs_filename);
1745 1781
1746 if (delete_extract) 1782 if (delete_extract)
@@ -1753,34 +1789,45 @@ out_close_stdout:
1753 goto out_free_command; 1789 goto out_free_command;
1754} 1790}
1755 1791
1756static void calc_percent(struct sym_hist *hist, 1792static void calc_percent(struct sym_hist *sym_hist,
1757 struct annotation_data *sample, 1793 struct hists *hists,
1794 struct annotation_data *data,
1758 s64 offset, s64 end) 1795 s64 offset, s64 end)
1759{ 1796{
1760 unsigned int hits = 0; 1797 unsigned int hits = 0;
1761 u64 period = 0; 1798 u64 period = 0;
1762 1799
1763 while (offset < end) { 1800 while (offset < end) {
1764 hits += hist->addr[offset].nr_samples; 1801 hits += sym_hist->addr[offset].nr_samples;
1765 period += hist->addr[offset].period; 1802 period += sym_hist->addr[offset].period;
1766 ++offset; 1803 ++offset;
1767 } 1804 }
1768 1805
1769 if (hist->nr_samples) { 1806 if (sym_hist->nr_samples) {
1770 sample->he.period = period; 1807 data->he.period = period;
1771 sample->he.nr_samples = hits; 1808 data->he.nr_samples = hits;
1772 sample->percent = 100.0 * hits / hist->nr_samples; 1809 data->percent[PERCENT_HITS_LOCAL] = 100.0 * hits / sym_hist->nr_samples;
1773 } 1810 }
1811
1812 if (hists->stats.nr_non_filtered_samples)
1813 data->percent[PERCENT_HITS_GLOBAL] = 100.0 * hits / hists->stats.nr_non_filtered_samples;
1814
1815 if (sym_hist->period)
1816 data->percent[PERCENT_PERIOD_LOCAL] = 100.0 * period / sym_hist->period;
1817
1818 if (hists->stats.total_period)
1819 data->percent[PERCENT_PERIOD_GLOBAL] = 100.0 * period / hists->stats.total_period;
1774} 1820}
1775 1821
1776static void annotation__calc_percent(struct annotation *notes, 1822static void annotation__calc_percent(struct annotation *notes,
1777 struct perf_evsel *evsel, s64 len) 1823 struct perf_evsel *leader, s64 len)
1778{ 1824{
1779 struct annotation_line *al, *next; 1825 struct annotation_line *al, *next;
1826 struct perf_evsel *evsel;
1780 1827
1781 list_for_each_entry(al, &notes->src->source, node) { 1828 list_for_each_entry(al, &notes->src->source, node) {
1782 s64 end; 1829 s64 end;
1783 int i; 1830 int i = 0;
1784 1831
1785 if (al->offset == -1) 1832 if (al->offset == -1)
1786 continue; 1833 continue;
@@ -1788,14 +1835,17 @@ static void annotation__calc_percent(struct annotation *notes,
1788 next = annotation_line__next(al, &notes->src->source); 1835 next = annotation_line__next(al, &notes->src->source);
1789 end = next ? next->offset : len; 1836 end = next ? next->offset : len;
1790 1837
1791 for (i = 0; i < al->samples_nr; i++) { 1838 for_each_group_evsel(evsel, leader) {
1792 struct annotation_data *sample; 1839 struct hists *hists = evsel__hists(evsel);
1793 struct sym_hist *hist; 1840 struct annotation_data *data;
1841 struct sym_hist *sym_hist;
1794 1842
1795 hist = annotation__histogram(notes, evsel->idx + i); 1843 BUG_ON(i >= al->data_nr);
1796 sample = &al->samples[i];
1797 1844
1798 calc_percent(hist, sample, al->offset, end); 1845 sym_hist = annotation__histogram(notes, evsel->idx);
1846 data = &al->data[i++];
1847
1848 calc_percent(sym_hist, hists, data, al->offset, end);
1799 } 1849 }
1800 } 1850 }
1801} 1851}
@@ -1846,7 +1896,8 @@ int symbol__annotate(struct symbol *sym, struct map *map,
1846 return symbol__disassemble(sym, &args); 1896 return symbol__disassemble(sym, &args);
1847} 1897}
1848 1898
1849static void insert_source_line(struct rb_root *root, struct annotation_line *al) 1899static void insert_source_line(struct rb_root *root, struct annotation_line *al,
1900 struct annotation_options *opts)
1850{ 1901{
1851 struct annotation_line *iter; 1902 struct annotation_line *iter;
1852 struct rb_node **p = &root->rb_node; 1903 struct rb_node **p = &root->rb_node;
@@ -1859,8 +1910,10 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al)
1859 1910
1860 ret = strcmp(iter->path, al->path); 1911 ret = strcmp(iter->path, al->path);
1861 if (ret == 0) { 1912 if (ret == 0) {
1862 for (i = 0; i < al->samples_nr; i++) 1913 for (i = 0; i < al->data_nr; i++) {
1863 iter->samples[i].percent_sum += al->samples[i].percent; 1914 iter->data[i].percent_sum += annotation_data__percent(&al->data[i],
1915 opts->percent_type);
1916 }
1864 return; 1917 return;
1865 } 1918 }
1866 1919
@@ -1870,8 +1923,10 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al)
1870 p = &(*p)->rb_right; 1923 p = &(*p)->rb_right;
1871 } 1924 }
1872 1925
1873 for (i = 0; i < al->samples_nr; i++) 1926 for (i = 0; i < al->data_nr; i++) {
1874 al->samples[i].percent_sum = al->samples[i].percent; 1927 al->data[i].percent_sum = annotation_data__percent(&al->data[i],
1928 opts->percent_type);
1929 }
1875 1930
1876 rb_link_node(&al->rb_node, parent, p); 1931 rb_link_node(&al->rb_node, parent, p);
1877 rb_insert_color(&al->rb_node, root); 1932 rb_insert_color(&al->rb_node, root);
@@ -1881,10 +1936,10 @@ static int cmp_source_line(struct annotation_line *a, struct annotation_line *b)
1881{ 1936{
1882 int i; 1937 int i;
1883 1938
1884 for (i = 0; i < a->samples_nr; i++) { 1939 for (i = 0; i < a->data_nr; i++) {
1885 if (a->samples[i].percent_sum == b->samples[i].percent_sum) 1940 if (a->data[i].percent_sum == b->data[i].percent_sum)
1886 continue; 1941 continue;
1887 return a->samples[i].percent_sum > b->samples[i].percent_sum; 1942 return a->data[i].percent_sum > b->data[i].percent_sum;
1888 } 1943 }
1889 1944
1890 return 0; 1945 return 0;
@@ -1949,8 +2004,8 @@ static void print_summary(struct rb_root *root, const char *filename)
1949 int i; 2004 int i;
1950 2005
1951 al = rb_entry(node, struct annotation_line, rb_node); 2006 al = rb_entry(node, struct annotation_line, rb_node);
1952 for (i = 0; i < al->samples_nr; i++) { 2007 for (i = 0; i < al->data_nr; i++) {
1953 percent = al->samples[i].percent_sum; 2008 percent = al->data[i].percent_sum;
1954 color = get_percent_color(percent); 2009 color = get_percent_color(percent);
1955 color_fprintf(stdout, color, " %7.2f", percent); 2010 color_fprintf(stdout, color, " %7.2f", percent);
1956 2011
@@ -2029,10 +2084,12 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
2029 evsel_name = buf; 2084 evsel_name = buf;
2030 } 2085 }
2031 2086
2032 graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n", 2087 graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples, "
2088 "percent: %s)\n",
2033 width, width, symbol_conf.show_total_period ? "Period" : 2089 width, width, symbol_conf.show_total_period ? "Period" :
2034 symbol_conf.show_nr_samples ? "Samples" : "Percent", 2090 symbol_conf.show_nr_samples ? "Samples" : "Percent",
2035 d_filename, evsel_name, h->nr_samples); 2091 d_filename, evsel_name, h->nr_samples,
2092 percent_type_str(opts->percent_type));
2036 2093
2037 printf("%-*.*s----\n", 2094 printf("%-*.*s----\n",
2038 graph_dotted_len, graph_dotted_len, graph_dotted_line); 2095 graph_dotted_len, graph_dotted_len, graph_dotted_line);
@@ -2052,7 +2109,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
2052 2109
2053 err = annotation_line__print(pos, sym, start, evsel, len, 2110 err = annotation_line__print(pos, sym, start, evsel, len,
2054 opts->min_pcnt, printed, opts->max_lines, 2111 opts->min_pcnt, printed, opts->max_lines,
2055 queue, addr_fmt_width); 2112 queue, addr_fmt_width, opts->percent_type);
2056 2113
2057 switch (err) { 2114 switch (err) {
2058 case 0: 2115 case 0:
@@ -2129,10 +2186,11 @@ static void FILE__write_graph(void *fp, int graph)
2129 fputs(s, fp); 2186 fputs(s, fp);
2130} 2187}
2131 2188
2132int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) 2189static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp,
2190 struct annotation_options *opts)
2133{ 2191{
2134 struct annotation *notes = symbol__annotation(sym); 2192 struct annotation *notes = symbol__annotation(sym);
2135 struct annotation_write_ops ops = { 2193 struct annotation_write_ops wops = {
2136 .first_line = true, 2194 .first_line = true,
2137 .obj = fp, 2195 .obj = fp,
2138 .set_color = FILE__set_color, 2196 .set_color = FILE__set_color,
@@ -2146,15 +2204,16 @@ int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp)
2146 list_for_each_entry(al, &notes->src->source, node) { 2204 list_for_each_entry(al, &notes->src->source, node) {
2147 if (annotation_line__filter(al, notes)) 2205 if (annotation_line__filter(al, notes))
2148 continue; 2206 continue;
2149 annotation_line__write(al, notes, &ops); 2207 annotation_line__write(al, notes, &wops, opts);
2150 fputc('\n', fp); 2208 fputc('\n', fp);
2151 ops.first_line = false; 2209 wops.first_line = false;
2152 } 2210 }
2153 2211
2154 return 0; 2212 return 0;
2155} 2213}
2156 2214
2157int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel) 2215int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel,
2216 struct annotation_options *opts)
2158{ 2217{
2159 const char *ev_name = perf_evsel__name(evsel); 2218 const char *ev_name = perf_evsel__name(evsel);
2160 char buf[1024]; 2219 char buf[1024];
@@ -2176,7 +2235,7 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel)
2176 2235
2177 fprintf(fp, "%s() %s\nEvent: %s\n\n", 2236 fprintf(fp, "%s() %s\nEvent: %s\n\n",
2178 ms->sym->name, ms->map->dso->long_name, ev_name); 2237 ms->sym->name, ms->map->dso->long_name, ev_name);
2179 symbol__annotate_fprintf2(ms->sym, fp); 2238 symbol__annotate_fprintf2(ms->sym, fp, opts);
2180 2239
2181 fclose(fp); 2240 fclose(fp);
2182 err = 0; 2241 err = 0;
@@ -2346,7 +2405,8 @@ void annotation__update_column_widths(struct annotation *notes)
2346} 2405}
2347 2406
2348static void annotation__calc_lines(struct annotation *notes, struct map *map, 2407static void annotation__calc_lines(struct annotation *notes, struct map *map,
2349 struct rb_root *root) 2408 struct rb_root *root,
2409 struct annotation_options *opts)
2350{ 2410{
2351 struct annotation_line *al; 2411 struct annotation_line *al;
2352 struct rb_root tmp_root = RB_ROOT; 2412 struct rb_root tmp_root = RB_ROOT;
@@ -2355,13 +2415,14 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map,
2355 double percent_max = 0.0; 2415 double percent_max = 0.0;
2356 int i; 2416 int i;
2357 2417
2358 for (i = 0; i < al->samples_nr; i++) { 2418 for (i = 0; i < al->data_nr; i++) {
2359 struct annotation_data *sample; 2419 double percent;
2360 2420
2361 sample = &al->samples[i]; 2421 percent = annotation_data__percent(&al->data[i],
2422 opts->percent_type);
2362 2423
2363 if (sample->percent > percent_max) 2424 if (percent > percent_max)
2364 percent_max = sample->percent; 2425 percent_max = percent;
2365 } 2426 }
2366 2427
2367 if (percent_max <= 0.5) 2428 if (percent_max <= 0.5)
@@ -2369,18 +2430,19 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map,
2369 2430
2370 al->path = get_srcline(map->dso, notes->start + al->offset, NULL, 2431 al->path = get_srcline(map->dso, notes->start + al->offset, NULL,
2371 false, true, notes->start + al->offset); 2432 false, true, notes->start + al->offset);
2372 insert_source_line(&tmp_root, al); 2433 insert_source_line(&tmp_root, al, opts);
2373 } 2434 }
2374 2435
2375 resort_source_line(root, &tmp_root); 2436 resort_source_line(root, &tmp_root);
2376} 2437}
2377 2438
2378static void symbol__calc_lines(struct symbol *sym, struct map *map, 2439static void symbol__calc_lines(struct symbol *sym, struct map *map,
2379 struct rb_root *root) 2440 struct rb_root *root,
2441 struct annotation_options *opts)
2380{ 2442{
2381 struct annotation *notes = symbol__annotation(sym); 2443 struct annotation *notes = symbol__annotation(sym);
2382 2444
2383 annotation__calc_lines(notes, map, root); 2445 annotation__calc_lines(notes, map, root, opts);
2384} 2446}
2385 2447
2386int symbol__tty_annotate2(struct symbol *sym, struct map *map, 2448int symbol__tty_annotate2(struct symbol *sym, struct map *map,
@@ -2389,7 +2451,7 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map,
2389{ 2451{
2390 struct dso *dso = map->dso; 2452 struct dso *dso = map->dso;
2391 struct rb_root source_line = RB_ROOT; 2453 struct rb_root source_line = RB_ROOT;
2392 struct annotation *notes = symbol__annotation(sym); 2454 struct hists *hists = evsel__hists(evsel);
2393 char buf[1024]; 2455 char buf[1024];
2394 2456
2395 if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0) 2457 if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0)
@@ -2397,13 +2459,14 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map,
2397 2459
2398 if (opts->print_lines) { 2460 if (opts->print_lines) {
2399 srcline_full_filename = opts->full_path; 2461 srcline_full_filename = opts->full_path;
2400 symbol__calc_lines(sym, map, &source_line); 2462 symbol__calc_lines(sym, map, &source_line, opts);
2401 print_summary(&source_line, dso->long_name); 2463 print_summary(&source_line, dso->long_name);
2402 } 2464 }
2403 2465
2404 annotation__scnprintf_samples_period(notes, buf, sizeof(buf), evsel); 2466 hists__scnprintf_title(hists, buf, sizeof(buf));
2405 fprintf(stdout, "%s\n%s() %s\n", buf, sym->name, dso->long_name); 2467 fprintf(stdout, "%s, [percent: %s]\n%s() %s\n",
2406 symbol__annotate_fprintf2(sym, stdout); 2468 buf, percent_type_str(opts->percent_type), sym->name, dso->long_name);
2469 symbol__annotate_fprintf2(sym, stdout, opts);
2407 2470
2408 annotated_source__purge(symbol__annotation(sym)->src); 2471 annotated_source__purge(symbol__annotation(sym)->src);
2409 2472
@@ -2424,7 +2487,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
2424 2487
2425 if (opts->print_lines) { 2488 if (opts->print_lines) {
2426 srcline_full_filename = opts->full_path; 2489 srcline_full_filename = opts->full_path;
2427 symbol__calc_lines(sym, map, &source_line); 2490 symbol__calc_lines(sym, map, &source_line, opts);
2428 print_summary(&source_line, dso->long_name); 2491 print_summary(&source_line, dso->long_name);
2429 } 2492 }
2430 2493
@@ -2441,14 +2504,21 @@ bool ui__has_annotation(void)
2441} 2504}
2442 2505
2443 2506
2444double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes) 2507static double annotation_line__max_percent(struct annotation_line *al,
2508 struct annotation *notes,
2509 unsigned int percent_type)
2445{ 2510{
2446 double percent_max = 0.0; 2511 double percent_max = 0.0;
2447 int i; 2512 int i;
2448 2513
2449 for (i = 0; i < notes->nr_events; i++) { 2514 for (i = 0; i < notes->nr_events; i++) {
2450 if (al->samples[i].percent > percent_max) 2515 double percent;
2451 percent_max = al->samples[i].percent; 2516
2517 percent = annotation_data__percent(&al->data[i],
2518 percent_type);
2519
2520 if (percent > percent_max)
2521 percent_max = percent;
2452 } 2522 }
2453 2523
2454 return percent_max; 2524 return percent_max;
@@ -2487,7 +2557,7 @@ call_like:
2487 2557
2488static void __annotation_line__write(struct annotation_line *al, struct annotation *notes, 2558static void __annotation_line__write(struct annotation_line *al, struct annotation *notes,
2489 bool first_line, bool current_entry, bool change_color, int width, 2559 bool first_line, bool current_entry, bool change_color, int width,
2490 void *obj, 2560 void *obj, unsigned int percent_type,
2491 int (*obj__set_color)(void *obj, int color), 2561 int (*obj__set_color)(void *obj, int color),
2492 void (*obj__set_percent_color)(void *obj, double percent, bool current), 2562 void (*obj__set_percent_color)(void *obj, double percent, bool current),
2493 int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), 2563 int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current),
@@ -2495,7 +2565,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
2495 void (*obj__write_graph)(void *obj, int graph)) 2565 void (*obj__write_graph)(void *obj, int graph))
2496 2566
2497{ 2567{
2498 double percent_max = annotation_line__max_percent(al, notes); 2568 double percent_max = annotation_line__max_percent(al, notes, percent_type);
2499 int pcnt_width = annotation__pcnt_width(notes), 2569 int pcnt_width = annotation__pcnt_width(notes),
2500 cycles_width = annotation__cycles_width(notes); 2570 cycles_width = annotation__cycles_width(notes);
2501 bool show_title = false; 2571 bool show_title = false;
@@ -2514,15 +2584,18 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
2514 int i; 2584 int i;
2515 2585
2516 for (i = 0; i < notes->nr_events; i++) { 2586 for (i = 0; i < notes->nr_events; i++) {
2517 obj__set_percent_color(obj, al->samples[i].percent, current_entry); 2587 double percent;
2588
2589 percent = annotation_data__percent(&al->data[i], percent_type);
2590
2591 obj__set_percent_color(obj, percent, current_entry);
2518 if (notes->options->show_total_period) { 2592 if (notes->options->show_total_period) {
2519 obj__printf(obj, "%11" PRIu64 " ", al->samples[i].he.period); 2593 obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period);
2520 } else if (notes->options->show_nr_samples) { 2594 } else if (notes->options->show_nr_samples) {
2521 obj__printf(obj, "%6" PRIu64 " ", 2595 obj__printf(obj, "%6" PRIu64 " ",
2522 al->samples[i].he.nr_samples); 2596 al->data[i].he.nr_samples);
2523 } else { 2597 } else {
2524 obj__printf(obj, "%6.2f ", 2598 obj__printf(obj, "%6.2f ", percent);
2525 al->samples[i].percent);
2526 } 2599 }
2527 } 2600 }
2528 } else { 2601 } else {
@@ -2640,13 +2713,15 @@ print_addr:
2640} 2713}
2641 2714
2642void annotation_line__write(struct annotation_line *al, struct annotation *notes, 2715void annotation_line__write(struct annotation_line *al, struct annotation *notes,
2643 struct annotation_write_ops *ops) 2716 struct annotation_write_ops *wops,
2717 struct annotation_options *opts)
2644{ 2718{
2645 __annotation_line__write(al, notes, ops->first_line, ops->current_entry, 2719 __annotation_line__write(al, notes, wops->first_line, wops->current_entry,
2646 ops->change_color, ops->width, ops->obj, 2720 wops->change_color, wops->width, wops->obj,
2647 ops->set_color, ops->set_percent_color, 2721 opts->percent_type,
2648 ops->set_jumps_percent_color, ops->printf, 2722 wops->set_color, wops->set_percent_color,
2649 ops->write_graph); 2723 wops->set_jumps_percent_color, wops->printf,
2724 wops->write_graph);
2650} 2725}
2651 2726
2652int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, 2727int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel,
@@ -2688,46 +2763,6 @@ out_free_offsets:
2688 return -1; 2763 return -1;
2689} 2764}
2690 2765
2691int __annotation__scnprintf_samples_period(struct annotation *notes,
2692 char *bf, size_t size,
2693 struct perf_evsel *evsel,
2694 bool show_freq)
2695{
2696 const char *ev_name = perf_evsel__name(evsel);
2697 char buf[1024], ref[30] = " show reference callgraph, ";
2698 char sample_freq_str[64] = "";
2699 unsigned long nr_samples = 0;
2700 int nr_members = 1;
2701 bool enable_ref = false;
2702 u64 nr_events = 0;
2703 char unit;
2704 int i;
2705
2706 if (perf_evsel__is_group_event(evsel)) {
2707 perf_evsel__group_desc(evsel, buf, sizeof(buf));
2708 ev_name = buf;
2709 nr_members = evsel->nr_members;
2710 }
2711
2712 for (i = 0; i < nr_members; i++) {
2713 struct sym_hist *ah = annotation__histogram(notes, evsel->idx + i);
2714
2715 nr_samples += ah->nr_samples;
2716 nr_events += ah->period;
2717 }
2718
2719 if (symbol_conf.show_ref_callgraph && strstr(ev_name, "call-graph=no"))
2720 enable_ref = true;
2721
2722 if (show_freq)
2723 scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq);
2724
2725 nr_samples = convert_unit(nr_samples, &unit);
2726 return scnprintf(bf, size, "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64,
2727 nr_samples, unit, evsel->nr_members > 1 ? "s" : "",
2728 ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events);
2729}
2730
2731#define ANNOTATION__CFG(n) \ 2766#define ANNOTATION__CFG(n) \
2732 { .name = #n, .value = &annotation__default_options.n, } 2767 { .name = #n, .value = &annotation__default_options.n, }
2733 2768
@@ -2792,3 +2827,55 @@ void annotation_config__init(void)
2792 annotation__default_options.show_total_period = symbol_conf.show_total_period; 2827 annotation__default_options.show_total_period = symbol_conf.show_total_period;
2793 annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples; 2828 annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples;
2794} 2829}
2830
2831static unsigned int parse_percent_type(char *str1, char *str2)
2832{
2833 unsigned int type = (unsigned int) -1;
2834
2835 if (!strcmp("period", str1)) {
2836 if (!strcmp("local", str2))
2837 type = PERCENT_PERIOD_LOCAL;
2838 else if (!strcmp("global", str2))
2839 type = PERCENT_PERIOD_GLOBAL;
2840 }
2841
2842 if (!strcmp("hits", str1)) {
2843 if (!strcmp("local", str2))
2844 type = PERCENT_HITS_LOCAL;
2845 else if (!strcmp("global", str2))
2846 type = PERCENT_HITS_GLOBAL;
2847 }
2848
2849 return type;
2850}
2851
2852int annotate_parse_percent_type(const struct option *opt, const char *_str,
2853 int unset __maybe_unused)
2854{
2855 struct annotation_options *opts = opt->value;
2856 unsigned int type;
2857 char *str1, *str2;
2858 int err = -1;
2859
2860 str1 = strdup(_str);
2861 if (!str1)
2862 return -ENOMEM;
2863
2864 str2 = strchr(str1, '-');
2865 if (!str2)
2866 goto out;
2867
2868 *str2++ = 0;
2869
2870 type = parse_percent_type(str1, str2);
2871 if (type == (unsigned int) -1)
2872 type = parse_percent_type(str2, str1);
2873 if (type != (unsigned int) -1) {
2874 opts->percent_type = type;
2875 err = 0;
2876 }
2877
2878out:
2879 free(str1);
2880 return err;
2881}