diff options
Diffstat (limited to 'tools/perf/util/annotate.c')
| -rw-r--r-- | tools/perf/util/annotate.c | 305 |
1 files changed, 183 insertions, 122 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f91775b4bc3c..20061cf42288 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 | ||
| 54 | static regex_t file_lineno; | 55 | static regex_t file_lineno; |
| @@ -1108,7 +1109,7 @@ annotation_line__new(struct annotate_args *args, size_t privsize) | |||
| 1108 | if (perf_evsel__is_group_event(evsel)) | 1109 | if (perf_evsel__is_group_event(evsel)) |
| 1109 | nr = evsel->nr_members; | 1110 | nr = evsel->nr_members; |
| 1110 | 1111 | ||
| 1111 | size += sizeof(al->samples[0]) * nr; | 1112 | size += sizeof(al->data[0]) * nr; |
| 1112 | 1113 | ||
| 1113 | al = zalloc(size); | 1114 | al = zalloc(size); |
| 1114 | if (al) { | 1115 | if (al) { |
| @@ -1117,7 +1118,7 @@ annotation_line__new(struct annotate_args *args, size_t privsize) | |||
| 1117 | al->offset = args->offset; | 1118 | al->offset = args->offset; |
| 1118 | al->line = strdup(args->line); | 1119 | al->line = strdup(args->line); |
| 1119 | al->line_nr = args->line_nr; | 1120 | al->line_nr = args->line_nr; |
| 1120 | al->samples_nr = nr; | 1121 | al->data_nr = nr; |
| 1121 | } | 1122 | } |
| 1122 | 1123 | ||
| 1123 | return al; | 1124 | return al; |
| @@ -1297,7 +1298,8 @@ static int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_wi | |||
| 1297 | static int | 1298 | static int |
| 1298 | annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, | 1299 | annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, |
| 1299 | struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, | 1300 | struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, |
| 1300 | int max_lines, struct annotation_line *queue, int addr_fmt_width) | 1301 | int max_lines, struct annotation_line *queue, int addr_fmt_width, |
| 1302 | int percent_type) | ||
| 1301 | { | 1303 | { |
| 1302 | struct disasm_line *dl = container_of(al, struct disasm_line, al); | 1304 | struct disasm_line *dl = container_of(al, struct disasm_line, al); |
| 1303 | static const char *prev_line; | 1305 | static const char *prev_line; |
| @@ -1309,15 +1311,18 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start | |||
| 1309 | const char *color; | 1311 | const char *color; |
| 1310 | struct annotation *notes = symbol__annotation(sym); | 1312 | struct annotation *notes = symbol__annotation(sym); |
| 1311 | 1313 | ||
| 1312 | for (i = 0; i < al->samples_nr; i++) { | 1314 | for (i = 0; i < al->data_nr; i++) { |
| 1313 | struct annotation_data *sample = &al->samples[i]; | 1315 | double percent; |
| 1314 | 1316 | ||
| 1315 | if (sample->percent > max_percent) | 1317 | percent = annotation_data__percent(&al->data[i], |
| 1316 | max_percent = sample->percent; | 1318 | percent_type); |
| 1319 | |||
| 1320 | if (percent > max_percent) | ||
| 1321 | max_percent = percent; | ||
| 1317 | } | 1322 | } |
| 1318 | 1323 | ||
| 1319 | if (al->samples_nr > nr_percent) | 1324 | if (al->data_nr > nr_percent) |
| 1320 | nr_percent = al->samples_nr; | 1325 | nr_percent = al->data_nr; |
| 1321 | 1326 | ||
| 1322 | if (max_percent < min_pcnt) | 1327 | if (max_percent < min_pcnt) |
| 1323 | return -1; | 1328 | return -1; |
| @@ -1330,7 +1335,8 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start | |||
| 1330 | if (queue == al) | 1335 | if (queue == al) |
| 1331 | break; | 1336 | break; |
| 1332 | annotation_line__print(queue, sym, start, evsel, len, | 1337 | annotation_line__print(queue, sym, start, evsel, len, |
| 1333 | 0, 0, 1, NULL, addr_fmt_width); | 1338 | 0, 0, 1, NULL, addr_fmt_width, |
| 1339 | percent_type); | ||
| 1334 | } | 1340 | } |
| 1335 | } | 1341 | } |
| 1336 | 1342 | ||
| @@ -1351,18 +1357,20 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start | |||
| 1351 | } | 1357 | } |
| 1352 | 1358 | ||
| 1353 | for (i = 0; i < nr_percent; i++) { | 1359 | for (i = 0; i < nr_percent; i++) { |
| 1354 | struct annotation_data *sample = &al->samples[i]; | 1360 | struct annotation_data *data = &al->data[i]; |
| 1361 | double percent; | ||
| 1355 | 1362 | ||
| 1356 | color = get_percent_color(sample->percent); | 1363 | percent = annotation_data__percent(data, percent_type); |
| 1364 | color = get_percent_color(percent); | ||
| 1357 | 1365 | ||
| 1358 | if (symbol_conf.show_total_period) | 1366 | if (symbol_conf.show_total_period) |
| 1359 | color_fprintf(stdout, color, " %11" PRIu64, | 1367 | color_fprintf(stdout, color, " %11" PRIu64, |
| 1360 | sample->he.period); | 1368 | data->he.period); |
| 1361 | else if (symbol_conf.show_nr_samples) | 1369 | else if (symbol_conf.show_nr_samples) |
| 1362 | color_fprintf(stdout, color, " %7" PRIu64, | 1370 | color_fprintf(stdout, color, " %7" PRIu64, |
| 1363 | sample->he.nr_samples); | 1371 | data->he.nr_samples); |
| 1364 | else | 1372 | else |
| 1365 | color_fprintf(stdout, color, " %7.2f", sample->percent); | 1373 | color_fprintf(stdout, color, " %7.2f", percent); |
| 1366 | } | 1374 | } |
| 1367 | 1375 | ||
| 1368 | printf(" : "); | 1376 | printf(" : "); |
| @@ -1621,6 +1629,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) | |||
| 1621 | char symfs_filename[PATH_MAX]; | 1629 | char symfs_filename[PATH_MAX]; |
| 1622 | struct kcore_extract kce; | 1630 | struct kcore_extract kce; |
| 1623 | bool delete_extract = false; | 1631 | bool delete_extract = false; |
| 1632 | bool decomp = false; | ||
| 1624 | int stdout_fd[2]; | 1633 | int stdout_fd[2]; |
| 1625 | int lineno = 0; | 1634 | int lineno = 0; |
| 1626 | int nline; | 1635 | int nline; |
| @@ -1654,6 +1663,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) | |||
| 1654 | tmp, sizeof(tmp)) < 0) | 1663 | tmp, sizeof(tmp)) < 0) |
| 1655 | goto out; | 1664 | goto out; |
| 1656 | 1665 | ||
| 1666 | decomp = true; | ||
| 1657 | strcpy(symfs_filename, tmp); | 1667 | strcpy(symfs_filename, tmp); |
| 1658 | } | 1668 | } |
| 1659 | 1669 | ||
| @@ -1740,7 +1750,7 @@ out_free_command: | |||
| 1740 | out_remove_tmp: | 1750 | out_remove_tmp: |
| 1741 | close(stdout_fd[0]); | 1751 | close(stdout_fd[0]); |
| 1742 | 1752 | ||
| 1743 | if (dso__needs_decompress(dso)) | 1753 | if (decomp) |
| 1744 | unlink(symfs_filename); | 1754 | unlink(symfs_filename); |
| 1745 | 1755 | ||
| 1746 | if (delete_extract) | 1756 | if (delete_extract) |
| @@ -1753,34 +1763,45 @@ out_close_stdout: | |||
| 1753 | goto out_free_command; | 1763 | goto out_free_command; |
| 1754 | } | 1764 | } |
| 1755 | 1765 | ||
| 1756 | static void calc_percent(struct sym_hist *hist, | 1766 | static void calc_percent(struct sym_hist *sym_hist, |
| 1757 | struct annotation_data *sample, | 1767 | struct hists *hists, |
| 1768 | struct annotation_data *data, | ||
| 1758 | s64 offset, s64 end) | 1769 | s64 offset, s64 end) |
| 1759 | { | 1770 | { |
| 1760 | unsigned int hits = 0; | 1771 | unsigned int hits = 0; |
| 1761 | u64 period = 0; | 1772 | u64 period = 0; |
| 1762 | 1773 | ||
| 1763 | while (offset < end) { | 1774 | while (offset < end) { |
| 1764 | hits += hist->addr[offset].nr_samples; | 1775 | hits += sym_hist->addr[offset].nr_samples; |
| 1765 | period += hist->addr[offset].period; | 1776 | period += sym_hist->addr[offset].period; |
| 1766 | ++offset; | 1777 | ++offset; |
| 1767 | } | 1778 | } |
| 1768 | 1779 | ||
| 1769 | if (hist->nr_samples) { | 1780 | if (sym_hist->nr_samples) { |
| 1770 | sample->he.period = period; | 1781 | data->he.period = period; |
| 1771 | sample->he.nr_samples = hits; | 1782 | data->he.nr_samples = hits; |
| 1772 | sample->percent = 100.0 * hits / hist->nr_samples; | 1783 | data->percent[PERCENT_HITS_LOCAL] = 100.0 * hits / sym_hist->nr_samples; |
| 1773 | } | 1784 | } |
| 1785 | |||
| 1786 | if (hists->stats.nr_non_filtered_samples) | ||
| 1787 | data->percent[PERCENT_HITS_GLOBAL] = 100.0 * hits / hists->stats.nr_non_filtered_samples; | ||
| 1788 | |||
| 1789 | if (sym_hist->period) | ||
| 1790 | data->percent[PERCENT_PERIOD_LOCAL] = 100.0 * period / sym_hist->period; | ||
| 1791 | |||
| 1792 | if (hists->stats.total_period) | ||
| 1793 | data->percent[PERCENT_PERIOD_GLOBAL] = 100.0 * period / hists->stats.total_period; | ||
| 1774 | } | 1794 | } |
| 1775 | 1795 | ||
| 1776 | static void annotation__calc_percent(struct annotation *notes, | 1796 | static void annotation__calc_percent(struct annotation *notes, |
| 1777 | struct perf_evsel *evsel, s64 len) | 1797 | struct perf_evsel *leader, s64 len) |
| 1778 | { | 1798 | { |
| 1779 | struct annotation_line *al, *next; | 1799 | struct annotation_line *al, *next; |
| 1800 | struct perf_evsel *evsel; | ||
| 1780 | 1801 | ||
| 1781 | list_for_each_entry(al, ¬es->src->source, node) { | 1802 | list_for_each_entry(al, ¬es->src->source, node) { |
| 1782 | s64 end; | 1803 | s64 end; |
| 1783 | int i; | 1804 | int i = 0; |
| 1784 | 1805 | ||
| 1785 | if (al->offset == -1) | 1806 | if (al->offset == -1) |
| 1786 | continue; | 1807 | continue; |
| @@ -1788,14 +1809,17 @@ static void annotation__calc_percent(struct annotation *notes, | |||
| 1788 | next = annotation_line__next(al, ¬es->src->source); | 1809 | next = annotation_line__next(al, ¬es->src->source); |
| 1789 | end = next ? next->offset : len; | 1810 | end = next ? next->offset : len; |
| 1790 | 1811 | ||
| 1791 | for (i = 0; i < al->samples_nr; i++) { | 1812 | for_each_group_evsel(evsel, leader) { |
| 1792 | struct annotation_data *sample; | 1813 | struct hists *hists = evsel__hists(evsel); |
| 1793 | struct sym_hist *hist; | 1814 | struct annotation_data *data; |
| 1815 | struct sym_hist *sym_hist; | ||
| 1816 | |||
| 1817 | BUG_ON(i >= al->data_nr); | ||
| 1794 | 1818 | ||
| 1795 | hist = annotation__histogram(notes, evsel->idx + i); | 1819 | sym_hist = annotation__histogram(notes, evsel->idx); |
| 1796 | sample = &al->samples[i]; | 1820 | data = &al->data[i++]; |
| 1797 | 1821 | ||
| 1798 | calc_percent(hist, sample, al->offset, end); | 1822 | calc_percent(sym_hist, hists, data, al->offset, end); |
| 1799 | } | 1823 | } |
| 1800 | } | 1824 | } |
| 1801 | } | 1825 | } |
| @@ -1846,7 +1870,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, | |||
| 1846 | return symbol__disassemble(sym, &args); | 1870 | return symbol__disassemble(sym, &args); |
| 1847 | } | 1871 | } |
| 1848 | 1872 | ||
| 1849 | static void insert_source_line(struct rb_root *root, struct annotation_line *al) | 1873 | static void insert_source_line(struct rb_root *root, struct annotation_line *al, |
| 1874 | struct annotation_options *opts) | ||
| 1850 | { | 1875 | { |
| 1851 | struct annotation_line *iter; | 1876 | struct annotation_line *iter; |
| 1852 | struct rb_node **p = &root->rb_node; | 1877 | struct rb_node **p = &root->rb_node; |
| @@ -1859,8 +1884,10 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al) | |||
| 1859 | 1884 | ||
| 1860 | ret = strcmp(iter->path, al->path); | 1885 | ret = strcmp(iter->path, al->path); |
| 1861 | if (ret == 0) { | 1886 | if (ret == 0) { |
| 1862 | for (i = 0; i < al->samples_nr; i++) | 1887 | for (i = 0; i < al->data_nr; i++) { |
| 1863 | iter->samples[i].percent_sum += al->samples[i].percent; | 1888 | iter->data[i].percent_sum += annotation_data__percent(&al->data[i], |
| 1889 | opts->percent_type); | ||
| 1890 | } | ||
| 1864 | return; | 1891 | return; |
| 1865 | } | 1892 | } |
| 1866 | 1893 | ||
| @@ -1870,8 +1897,10 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al) | |||
| 1870 | p = &(*p)->rb_right; | 1897 | p = &(*p)->rb_right; |
| 1871 | } | 1898 | } |
| 1872 | 1899 | ||
| 1873 | for (i = 0; i < al->samples_nr; i++) | 1900 | for (i = 0; i < al->data_nr; i++) { |
| 1874 | al->samples[i].percent_sum = al->samples[i].percent; | 1901 | al->data[i].percent_sum = annotation_data__percent(&al->data[i], |
| 1902 | opts->percent_type); | ||
| 1903 | } | ||
| 1875 | 1904 | ||
| 1876 | rb_link_node(&al->rb_node, parent, p); | 1905 | rb_link_node(&al->rb_node, parent, p); |
| 1877 | rb_insert_color(&al->rb_node, root); | 1906 | rb_insert_color(&al->rb_node, root); |
| @@ -1881,10 +1910,10 @@ static int cmp_source_line(struct annotation_line *a, struct annotation_line *b) | |||
| 1881 | { | 1910 | { |
| 1882 | int i; | 1911 | int i; |
| 1883 | 1912 | ||
| 1884 | for (i = 0; i < a->samples_nr; i++) { | 1913 | for (i = 0; i < a->data_nr; i++) { |
| 1885 | if (a->samples[i].percent_sum == b->samples[i].percent_sum) | 1914 | if (a->data[i].percent_sum == b->data[i].percent_sum) |
| 1886 | continue; | 1915 | continue; |
| 1887 | return a->samples[i].percent_sum > b->samples[i].percent_sum; | 1916 | return a->data[i].percent_sum > b->data[i].percent_sum; |
| 1888 | } | 1917 | } |
| 1889 | 1918 | ||
| 1890 | return 0; | 1919 | return 0; |
| @@ -1949,8 +1978,8 @@ static void print_summary(struct rb_root *root, const char *filename) | |||
| 1949 | int i; | 1978 | int i; |
| 1950 | 1979 | ||
| 1951 | al = rb_entry(node, struct annotation_line, rb_node); | 1980 | al = rb_entry(node, struct annotation_line, rb_node); |
| 1952 | for (i = 0; i < al->samples_nr; i++) { | 1981 | for (i = 0; i < al->data_nr; i++) { |
| 1953 | percent = al->samples[i].percent_sum; | 1982 | percent = al->data[i].percent_sum; |
| 1954 | color = get_percent_color(percent); | 1983 | color = get_percent_color(percent); |
| 1955 | color_fprintf(stdout, color, " %7.2f", percent); | 1984 | color_fprintf(stdout, color, " %7.2f", percent); |
| 1956 | 1985 | ||
| @@ -2029,10 +2058,12 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
| 2029 | evsel_name = buf; | 2058 | evsel_name = buf; |
| 2030 | } | 2059 | } |
| 2031 | 2060 | ||
| 2032 | graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n", | 2061 | graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples, " |
| 2062 | "percent: %s)\n", | ||
| 2033 | width, width, symbol_conf.show_total_period ? "Period" : | 2063 | width, width, symbol_conf.show_total_period ? "Period" : |
| 2034 | symbol_conf.show_nr_samples ? "Samples" : "Percent", | 2064 | symbol_conf.show_nr_samples ? "Samples" : "Percent", |
| 2035 | d_filename, evsel_name, h->nr_samples); | 2065 | d_filename, evsel_name, h->nr_samples, |
| 2066 | percent_type_str(opts->percent_type)); | ||
| 2036 | 2067 | ||
| 2037 | printf("%-*.*s----\n", | 2068 | printf("%-*.*s----\n", |
| 2038 | graph_dotted_len, graph_dotted_len, graph_dotted_line); | 2069 | graph_dotted_len, graph_dotted_len, graph_dotted_line); |
| @@ -2052,7 +2083,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
| 2052 | 2083 | ||
| 2053 | err = annotation_line__print(pos, sym, start, evsel, len, | 2084 | err = annotation_line__print(pos, sym, start, evsel, len, |
| 2054 | opts->min_pcnt, printed, opts->max_lines, | 2085 | opts->min_pcnt, printed, opts->max_lines, |
| 2055 | queue, addr_fmt_width); | 2086 | queue, addr_fmt_width, opts->percent_type); |
| 2056 | 2087 | ||
| 2057 | switch (err) { | 2088 | switch (err) { |
| 2058 | case 0: | 2089 | case 0: |
| @@ -2129,10 +2160,11 @@ static void FILE__write_graph(void *fp, int graph) | |||
| 2129 | fputs(s, fp); | 2160 | fputs(s, fp); |
| 2130 | } | 2161 | } |
| 2131 | 2162 | ||
| 2132 | int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) | 2163 | static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, |
| 2164 | struct annotation_options *opts) | ||
| 2133 | { | 2165 | { |
| 2134 | struct annotation *notes = symbol__annotation(sym); | 2166 | struct annotation *notes = symbol__annotation(sym); |
| 2135 | struct annotation_write_ops ops = { | 2167 | struct annotation_write_ops wops = { |
| 2136 | .first_line = true, | 2168 | .first_line = true, |
| 2137 | .obj = fp, | 2169 | .obj = fp, |
| 2138 | .set_color = FILE__set_color, | 2170 | .set_color = FILE__set_color, |
| @@ -2146,15 +2178,16 @@ int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) | |||
| 2146 | list_for_each_entry(al, ¬es->src->source, node) { | 2178 | list_for_each_entry(al, ¬es->src->source, node) { |
| 2147 | if (annotation_line__filter(al, notes)) | 2179 | if (annotation_line__filter(al, notes)) |
| 2148 | continue; | 2180 | continue; |
| 2149 | annotation_line__write(al, notes, &ops); | 2181 | annotation_line__write(al, notes, &wops, opts); |
| 2150 | fputc('\n', fp); | 2182 | fputc('\n', fp); |
| 2151 | ops.first_line = false; | 2183 | wops.first_line = false; |
| 2152 | } | 2184 | } |
| 2153 | 2185 | ||
| 2154 | return 0; | 2186 | return 0; |
| 2155 | } | 2187 | } |
| 2156 | 2188 | ||
| 2157 | int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel) | 2189 | int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel, |
| 2190 | struct annotation_options *opts) | ||
| 2158 | { | 2191 | { |
| 2159 | const char *ev_name = perf_evsel__name(evsel); | 2192 | const char *ev_name = perf_evsel__name(evsel); |
| 2160 | char buf[1024]; | 2193 | char buf[1024]; |
| @@ -2176,7 +2209,7 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel) | |||
| 2176 | 2209 | ||
| 2177 | fprintf(fp, "%s() %s\nEvent: %s\n\n", | 2210 | fprintf(fp, "%s() %s\nEvent: %s\n\n", |
| 2178 | ms->sym->name, ms->map->dso->long_name, ev_name); | 2211 | ms->sym->name, ms->map->dso->long_name, ev_name); |
| 2179 | symbol__annotate_fprintf2(ms->sym, fp); | 2212 | symbol__annotate_fprintf2(ms->sym, fp, opts); |
| 2180 | 2213 | ||
| 2181 | fclose(fp); | 2214 | fclose(fp); |
| 2182 | err = 0; | 2215 | err = 0; |
| @@ -2346,7 +2379,8 @@ void annotation__update_column_widths(struct annotation *notes) | |||
| 2346 | } | 2379 | } |
| 2347 | 2380 | ||
| 2348 | static void annotation__calc_lines(struct annotation *notes, struct map *map, | 2381 | static void annotation__calc_lines(struct annotation *notes, struct map *map, |
| 2349 | struct rb_root *root) | 2382 | struct rb_root *root, |
| 2383 | struct annotation_options *opts) | ||
| 2350 | { | 2384 | { |
| 2351 | struct annotation_line *al; | 2385 | struct annotation_line *al; |
| 2352 | struct rb_root tmp_root = RB_ROOT; | 2386 | struct rb_root tmp_root = RB_ROOT; |
| @@ -2355,13 +2389,14 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, | |||
| 2355 | double percent_max = 0.0; | 2389 | double percent_max = 0.0; |
| 2356 | int i; | 2390 | int i; |
| 2357 | 2391 | ||
| 2358 | for (i = 0; i < al->samples_nr; i++) { | 2392 | for (i = 0; i < al->data_nr; i++) { |
| 2359 | struct annotation_data *sample; | 2393 | double percent; |
| 2360 | 2394 | ||
| 2361 | sample = &al->samples[i]; | 2395 | percent = annotation_data__percent(&al->data[i], |
| 2396 | opts->percent_type); | ||
| 2362 | 2397 | ||
| 2363 | if (sample->percent > percent_max) | 2398 | if (percent > percent_max) |
| 2364 | percent_max = sample->percent; | 2399 | percent_max = percent; |
| 2365 | } | 2400 | } |
| 2366 | 2401 | ||
| 2367 | if (percent_max <= 0.5) | 2402 | if (percent_max <= 0.5) |
| @@ -2369,18 +2404,19 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, | |||
| 2369 | 2404 | ||
| 2370 | al->path = get_srcline(map->dso, notes->start + al->offset, NULL, | 2405 | al->path = get_srcline(map->dso, notes->start + al->offset, NULL, |
| 2371 | false, true, notes->start + al->offset); | 2406 | false, true, notes->start + al->offset); |
| 2372 | insert_source_line(&tmp_root, al); | 2407 | insert_source_line(&tmp_root, al, opts); |
| 2373 | } | 2408 | } |
| 2374 | 2409 | ||
| 2375 | resort_source_line(root, &tmp_root); | 2410 | resort_source_line(root, &tmp_root); |
| 2376 | } | 2411 | } |
| 2377 | 2412 | ||
| 2378 | static void symbol__calc_lines(struct symbol *sym, struct map *map, | 2413 | static void symbol__calc_lines(struct symbol *sym, struct map *map, |
| 2379 | struct rb_root *root) | 2414 | struct rb_root *root, |
| 2415 | struct annotation_options *opts) | ||
| 2380 | { | 2416 | { |
| 2381 | struct annotation *notes = symbol__annotation(sym); | 2417 | struct annotation *notes = symbol__annotation(sym); |
| 2382 | 2418 | ||
| 2383 | annotation__calc_lines(notes, map, root); | 2419 | annotation__calc_lines(notes, map, root, opts); |
| 2384 | } | 2420 | } |
| 2385 | 2421 | ||
| 2386 | int symbol__tty_annotate2(struct symbol *sym, struct map *map, | 2422 | int symbol__tty_annotate2(struct symbol *sym, struct map *map, |
| @@ -2389,7 +2425,7 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, | |||
| 2389 | { | 2425 | { |
| 2390 | struct dso *dso = map->dso; | 2426 | struct dso *dso = map->dso; |
| 2391 | struct rb_root source_line = RB_ROOT; | 2427 | struct rb_root source_line = RB_ROOT; |
| 2392 | struct annotation *notes = symbol__annotation(sym); | 2428 | struct hists *hists = evsel__hists(evsel); |
| 2393 | char buf[1024]; | 2429 | char buf[1024]; |
| 2394 | 2430 | ||
| 2395 | if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0) | 2431 | if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0) |
| @@ -2397,13 +2433,14 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, | |||
| 2397 | 2433 | ||
| 2398 | if (opts->print_lines) { | 2434 | if (opts->print_lines) { |
| 2399 | srcline_full_filename = opts->full_path; | 2435 | srcline_full_filename = opts->full_path; |
| 2400 | symbol__calc_lines(sym, map, &source_line); | 2436 | symbol__calc_lines(sym, map, &source_line, opts); |
| 2401 | print_summary(&source_line, dso->long_name); | 2437 | print_summary(&source_line, dso->long_name); |
| 2402 | } | 2438 | } |
| 2403 | 2439 | ||
| 2404 | annotation__scnprintf_samples_period(notes, buf, sizeof(buf), evsel); | 2440 | hists__scnprintf_title(hists, buf, sizeof(buf)); |
| 2405 | fprintf(stdout, "%s\n%s() %s\n", buf, sym->name, dso->long_name); | 2441 | fprintf(stdout, "%s, [percent: %s]\n%s() %s\n", |
| 2406 | symbol__annotate_fprintf2(sym, stdout); | 2442 | buf, percent_type_str(opts->percent_type), sym->name, dso->long_name); |
| 2443 | symbol__annotate_fprintf2(sym, stdout, opts); | ||
| 2407 | 2444 | ||
| 2408 | annotated_source__purge(symbol__annotation(sym)->src); | 2445 | annotated_source__purge(symbol__annotation(sym)->src); |
| 2409 | 2446 | ||
| @@ -2424,7 +2461,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, | |||
| 2424 | 2461 | ||
| 2425 | if (opts->print_lines) { | 2462 | if (opts->print_lines) { |
| 2426 | srcline_full_filename = opts->full_path; | 2463 | srcline_full_filename = opts->full_path; |
| 2427 | symbol__calc_lines(sym, map, &source_line); | 2464 | symbol__calc_lines(sym, map, &source_line, opts); |
| 2428 | print_summary(&source_line, dso->long_name); | 2465 | print_summary(&source_line, dso->long_name); |
| 2429 | } | 2466 | } |
| 2430 | 2467 | ||
| @@ -2441,14 +2478,21 @@ bool ui__has_annotation(void) | |||
| 2441 | } | 2478 | } |
| 2442 | 2479 | ||
| 2443 | 2480 | ||
| 2444 | double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes) | 2481 | static double annotation_line__max_percent(struct annotation_line *al, |
| 2482 | struct annotation *notes, | ||
| 2483 | unsigned int percent_type) | ||
| 2445 | { | 2484 | { |
| 2446 | double percent_max = 0.0; | 2485 | double percent_max = 0.0; |
| 2447 | int i; | 2486 | int i; |
| 2448 | 2487 | ||
| 2449 | for (i = 0; i < notes->nr_events; i++) { | 2488 | for (i = 0; i < notes->nr_events; i++) { |
| 2450 | if (al->samples[i].percent > percent_max) | 2489 | double percent; |
| 2451 | percent_max = al->samples[i].percent; | 2490 | |
| 2491 | percent = annotation_data__percent(&al->data[i], | ||
| 2492 | percent_type); | ||
| 2493 | |||
| 2494 | if (percent > percent_max) | ||
| 2495 | percent_max = percent; | ||
| 2452 | } | 2496 | } |
| 2453 | 2497 | ||
| 2454 | return percent_max; | 2498 | return percent_max; |
| @@ -2487,7 +2531,7 @@ call_like: | |||
| 2487 | 2531 | ||
| 2488 | static void __annotation_line__write(struct annotation_line *al, struct annotation *notes, | 2532 | static void __annotation_line__write(struct annotation_line *al, struct annotation *notes, |
| 2489 | bool first_line, bool current_entry, bool change_color, int width, | 2533 | bool first_line, bool current_entry, bool change_color, int width, |
| 2490 | void *obj, | 2534 | void *obj, unsigned int percent_type, |
| 2491 | int (*obj__set_color)(void *obj, int color), | 2535 | int (*obj__set_color)(void *obj, int color), |
| 2492 | void (*obj__set_percent_color)(void *obj, double percent, bool current), | 2536 | void (*obj__set_percent_color)(void *obj, double percent, bool current), |
| 2493 | int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), | 2537 | int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), |
| @@ -2495,7 +2539,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati | |||
| 2495 | void (*obj__write_graph)(void *obj, int graph)) | 2539 | void (*obj__write_graph)(void *obj, int graph)) |
| 2496 | 2540 | ||
| 2497 | { | 2541 | { |
| 2498 | double percent_max = annotation_line__max_percent(al, notes); | 2542 | double percent_max = annotation_line__max_percent(al, notes, percent_type); |
| 2499 | int pcnt_width = annotation__pcnt_width(notes), | 2543 | int pcnt_width = annotation__pcnt_width(notes), |
| 2500 | cycles_width = annotation__cycles_width(notes); | 2544 | cycles_width = annotation__cycles_width(notes); |
| 2501 | bool show_title = false; | 2545 | bool show_title = false; |
| @@ -2514,15 +2558,18 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati | |||
| 2514 | int i; | 2558 | int i; |
| 2515 | 2559 | ||
| 2516 | for (i = 0; i < notes->nr_events; i++) { | 2560 | for (i = 0; i < notes->nr_events; i++) { |
| 2517 | obj__set_percent_color(obj, al->samples[i].percent, current_entry); | 2561 | double percent; |
| 2562 | |||
| 2563 | percent = annotation_data__percent(&al->data[i], percent_type); | ||
| 2564 | |||
| 2565 | obj__set_percent_color(obj, percent, current_entry); | ||
| 2518 | if (notes->options->show_total_period) { | 2566 | if (notes->options->show_total_period) { |
| 2519 | obj__printf(obj, "%11" PRIu64 " ", al->samples[i].he.period); | 2567 | obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period); |
| 2520 | } else if (notes->options->show_nr_samples) { | 2568 | } else if (notes->options->show_nr_samples) { |
| 2521 | obj__printf(obj, "%6" PRIu64 " ", | 2569 | obj__printf(obj, "%6" PRIu64 " ", |
| 2522 | al->samples[i].he.nr_samples); | 2570 | al->data[i].he.nr_samples); |
| 2523 | } else { | 2571 | } else { |
| 2524 | obj__printf(obj, "%6.2f ", | 2572 | obj__printf(obj, "%6.2f ", percent); |
| 2525 | al->samples[i].percent); | ||
| 2526 | } | 2573 | } |
| 2527 | } | 2574 | } |
| 2528 | } else { | 2575 | } else { |
| @@ -2640,13 +2687,15 @@ print_addr: | |||
| 2640 | } | 2687 | } |
| 2641 | 2688 | ||
| 2642 | void annotation_line__write(struct annotation_line *al, struct annotation *notes, | 2689 | void annotation_line__write(struct annotation_line *al, struct annotation *notes, |
| 2643 | struct annotation_write_ops *ops) | 2690 | struct annotation_write_ops *wops, |
| 2691 | struct annotation_options *opts) | ||
| 2644 | { | 2692 | { |
| 2645 | __annotation_line__write(al, notes, ops->first_line, ops->current_entry, | 2693 | __annotation_line__write(al, notes, wops->first_line, wops->current_entry, |
| 2646 | ops->change_color, ops->width, ops->obj, | 2694 | wops->change_color, wops->width, wops->obj, |
| 2647 | ops->set_color, ops->set_percent_color, | 2695 | opts->percent_type, |
| 2648 | ops->set_jumps_percent_color, ops->printf, | 2696 | wops->set_color, wops->set_percent_color, |
| 2649 | ops->write_graph); | 2697 | wops->set_jumps_percent_color, wops->printf, |
| 2698 | wops->write_graph); | ||
| 2650 | } | 2699 | } |
| 2651 | 2700 | ||
| 2652 | int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, | 2701 | int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, |
| @@ -2688,46 +2737,6 @@ out_free_offsets: | |||
| 2688 | return -1; | 2737 | return -1; |
| 2689 | } | 2738 | } |
| 2690 | 2739 | ||
| 2691 | int __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) \ | 2740 | #define ANNOTATION__CFG(n) \ |
| 2732 | { .name = #n, .value = &annotation__default_options.n, } | 2741 | { .name = #n, .value = &annotation__default_options.n, } |
| 2733 | 2742 | ||
| @@ -2792,3 +2801,55 @@ void annotation_config__init(void) | |||
| 2792 | annotation__default_options.show_total_period = symbol_conf.show_total_period; | 2801 | annotation__default_options.show_total_period = symbol_conf.show_total_period; |
| 2793 | annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples; | 2802 | annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples; |
| 2794 | } | 2803 | } |
| 2804 | |||
| 2805 | static unsigned int parse_percent_type(char *str1, char *str2) | ||
| 2806 | { | ||
| 2807 | unsigned int type = (unsigned int) -1; | ||
| 2808 | |||
| 2809 | if (!strcmp("period", str1)) { | ||
| 2810 | if (!strcmp("local", str2)) | ||
| 2811 | type = PERCENT_PERIOD_LOCAL; | ||
| 2812 | else if (!strcmp("global", str2)) | ||
| 2813 | type = PERCENT_PERIOD_GLOBAL; | ||
| 2814 | } | ||
| 2815 | |||
| 2816 | if (!strcmp("hits", str1)) { | ||
| 2817 | if (!strcmp("local", str2)) | ||
| 2818 | type = PERCENT_HITS_LOCAL; | ||
| 2819 | else if (!strcmp("global", str2)) | ||
| 2820 | type = PERCENT_HITS_GLOBAL; | ||
| 2821 | } | ||
| 2822 | |||
| 2823 | return type; | ||
| 2824 | } | ||
| 2825 | |||
| 2826 | int annotate_parse_percent_type(const struct option *opt, const char *_str, | ||
| 2827 | int unset __maybe_unused) | ||
| 2828 | { | ||
| 2829 | struct annotation_options *opts = opt->value; | ||
| 2830 | unsigned int type; | ||
| 2831 | char *str1, *str2; | ||
| 2832 | int err = -1; | ||
| 2833 | |||
| 2834 | str1 = strdup(_str); | ||
| 2835 | if (!str1) | ||
| 2836 | return -ENOMEM; | ||
| 2837 | |||
| 2838 | str2 = strchr(str1, '-'); | ||
| 2839 | if (!str2) | ||
| 2840 | goto out; | ||
| 2841 | |||
| 2842 | *str2++ = 0; | ||
| 2843 | |||
| 2844 | type = parse_percent_type(str1, str2); | ||
| 2845 | if (type == (unsigned int) -1) | ||
| 2846 | type = parse_percent_type(str2, str1); | ||
| 2847 | if (type != (unsigned int) -1) { | ||
| 2848 | opts->percent_type = type; | ||
| 2849 | err = 0; | ||
| 2850 | } | ||
| 2851 | |||
| 2852 | out: | ||
| 2853 | free(str1); | ||
| 2854 | return err; | ||
| 2855 | } | ||
