diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-06-04 09:19:47 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-04 09:28:11 -0400 |
commit | 8fc0321f1ad0ffef969056dda91b453bbd7a494d (patch) | |
tree | 8931ad2c6582a2f59930301c3c099aa1532bb14c /Documentation | |
parent | 71dd8945d8d827ab101cd287f9480ef22fc7c1b6 (diff) |
perf_counter tools: Add color terminal output support
Add Git's color printing library to util/color.[ch].
Add it to perf report, with a trivial example to print high-overhead
entries in red, low-overhead entries in green.
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'Documentation')
-rw-r--r-- | Documentation/perf_counter/Makefile | 2 | ||||
-rw-r--r-- | Documentation/perf_counter/builtin-report.c | 15 | ||||
-rw-r--r-- | Documentation/perf_counter/builtin-top.c | 23 | ||||
-rw-r--r-- | Documentation/perf_counter/util/color.c | 230 | ||||
-rw-r--r-- | Documentation/perf_counter/util/color.h | 36 | ||||
-rw-r--r-- | Documentation/perf_counter/util/environment.c | 1 |
6 files changed, 300 insertions, 7 deletions
diff --git a/Documentation/perf_counter/Makefile b/Documentation/perf_counter/Makefile index 414399cbc51a..c9ec4585f4d6 100644 --- a/Documentation/perf_counter/Makefile +++ b/Documentation/perf_counter/Makefile | |||
@@ -298,6 +298,7 @@ LIB_H += util/string.h | |||
298 | LIB_H += util/run-command.h | 298 | LIB_H += util/run-command.h |
299 | LIB_H += util/sigchain.h | 299 | LIB_H += util/sigchain.h |
300 | LIB_H += util/symbol.h | 300 | LIB_H += util/symbol.h |
301 | LIB_H += util/color.h | ||
301 | 302 | ||
302 | LIB_OBJS += util/abspath.o | 303 | LIB_OBJS += util/abspath.o |
303 | LIB_OBJS += util/alias.o | 304 | LIB_OBJS += util/alias.o |
@@ -319,6 +320,7 @@ LIB_OBJS += util/usage.o | |||
319 | LIB_OBJS += util/wrapper.o | 320 | LIB_OBJS += util/wrapper.o |
320 | LIB_OBJS += util/sigchain.o | 321 | LIB_OBJS += util/sigchain.o |
321 | LIB_OBJS += util/symbol.o | 322 | LIB_OBJS += util/symbol.o |
323 | LIB_OBJS += util/color.o | ||
322 | LIB_OBJS += util/pager.o | 324 | LIB_OBJS += util/pager.o |
323 | 325 | ||
324 | BUILTIN_OBJS += builtin-help.o | 326 | BUILTIN_OBJS += builtin-help.o |
diff --git a/Documentation/perf_counter/builtin-report.c b/Documentation/perf_counter/builtin-report.c index e930b4e02335..7beedc6effa4 100644 --- a/Documentation/perf_counter/builtin-report.c +++ b/Documentation/perf_counter/builtin-report.c | |||
@@ -9,6 +9,7 @@ | |||
9 | 9 | ||
10 | #include "util/util.h" | 10 | #include "util/util.h" |
11 | 11 | ||
12 | #include "util/color.h" | ||
12 | #include "util/list.h" | 13 | #include "util/list.h" |
13 | #include "util/cache.h" | 14 | #include "util/cache.h" |
14 | #include "util/rbtree.h" | 15 | #include "util/rbtree.h" |
@@ -548,7 +549,19 @@ hist_entry__fprintf(FILE *fp, struct hist_entry *self, uint64_t total_samples) | |||
548 | size_t ret; | 549 | size_t ret; |
549 | 550 | ||
550 | if (total_samples) { | 551 | if (total_samples) { |
551 | ret = fprintf(fp, " %6.2f%%", | 552 | double percent = self->count * 100.0 / total_samples; |
553 | char *color = PERF_COLOR_NORMAL; | ||
554 | |||
555 | /* | ||
556 | * We color high-overhead entries in red, low-overhead | ||
557 | * entries in green - and keep the middle ground normal: | ||
558 | */ | ||
559 | if (percent >= 5.0) | ||
560 | color = PERF_COLOR_RED; | ||
561 | if (percent < 0.5) | ||
562 | color = PERF_COLOR_GREEN; | ||
563 | |||
564 | ret = color_fprintf(fp, color, " %6.2f%%", | ||
552 | (self->count * 100.0) / total_samples); | 565 | (self->count * 100.0) / total_samples); |
553 | } else | 566 | } else |
554 | ret = fprintf(fp, "%12d ", self->count); | 567 | ret = fprintf(fp, "%12d ", self->count); |
diff --git a/Documentation/perf_counter/builtin-top.c b/Documentation/perf_counter/builtin-top.c index 548a8da4b15b..20e5b1200959 100644 --- a/Documentation/perf_counter/builtin-top.c +++ b/Documentation/perf_counter/builtin-top.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include "perf.h" | 21 | #include "perf.h" |
22 | 22 | ||
23 | #include "util/symbol.h" | 23 | #include "util/symbol.h" |
24 | #include "util/color.h" | ||
24 | #include "util/util.h" | 25 | #include "util/util.h" |
25 | #include "util/rbtree.h" | 26 | #include "util/rbtree.h" |
26 | #include "util/parse-options.h" | 27 | #include "util/parse-options.h" |
@@ -253,7 +254,8 @@ static void print_sym_table(void) | |||
253 | for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { | 254 | for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { |
254 | struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node); | 255 | struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node); |
255 | struct symbol *sym = (struct symbol *)(syme + 1); | 256 | struct symbol *sym = (struct symbol *)(syme + 1); |
256 | float pcnt; | 257 | char *color = PERF_COLOR_NORMAL; |
258 | double pcnt; | ||
257 | 259 | ||
258 | if (++printed > print_entries || syme->snap_count < count_filter) | 260 | if (++printed > print_entries || syme->snap_count < count_filter) |
259 | continue; | 261 | continue; |
@@ -261,13 +263,22 @@ static void print_sym_table(void) | |||
261 | pcnt = 100.0 - (100.0 * ((sum_kevents - syme->snap_count) / | 263 | pcnt = 100.0 - (100.0 * ((sum_kevents - syme->snap_count) / |
262 | sum_kevents)); | 264 | sum_kevents)); |
263 | 265 | ||
266 | /* | ||
267 | * We color high-overhead entries in red, low-overhead | ||
268 | * entries in green - and keep the middle ground normal: | ||
269 | */ | ||
270 | if (pcnt >= 5.0) | ||
271 | color = PERF_COLOR_RED; | ||
272 | if (pcnt < 0.5) | ||
273 | color = PERF_COLOR_GREEN; | ||
274 | |||
264 | if (nr_counters == 1) | 275 | if (nr_counters == 1) |
265 | printf("%19.2f - %4.1f%% - %016llx : %s\n", | 276 | printf("%19.2f - ", syme->weight); |
266 | syme->weight, pcnt, sym->start, sym->name); | ||
267 | else | 277 | else |
268 | printf("%8.1f %10ld - %4.1f%% - %016llx : %s\n", | 278 | printf("%8.1f %10ld - ", syme->weight, syme->snap_count); |
269 | syme->weight, syme->snap_count, | 279 | |
270 | pcnt, sym->start, sym->name); | 280 | color_fprintf(stdout, color, "%4.1f%%", pcnt); |
281 | printf(" - %016llx : %s\n", sym->start, sym->name); | ||
271 | } | 282 | } |
272 | 283 | ||
273 | { | 284 | { |
diff --git a/Documentation/perf_counter/util/color.c b/Documentation/perf_counter/util/color.c new file mode 100644 index 000000000000..a77975d66774 --- /dev/null +++ b/Documentation/perf_counter/util/color.c | |||
@@ -0,0 +1,230 @@ | |||
1 | #include "cache.h" | ||
2 | #include "color.h" | ||
3 | |||
4 | int perf_use_color_default = 0; | ||
5 | |||
6 | static int parse_color(const char *name, int len) | ||
7 | { | ||
8 | static const char * const color_names[] = { | ||
9 | "normal", "black", "red", "green", "yellow", | ||
10 | "blue", "magenta", "cyan", "white" | ||
11 | }; | ||
12 | char *end; | ||
13 | int i; | ||
14 | for (i = 0; i < ARRAY_SIZE(color_names); i++) { | ||
15 | const char *str = color_names[i]; | ||
16 | if (!strncasecmp(name, str, len) && !str[len]) | ||
17 | return i - 1; | ||
18 | } | ||
19 | i = strtol(name, &end, 10); | ||
20 | if (end - name == len && i >= -1 && i <= 255) | ||
21 | return i; | ||
22 | return -2; | ||
23 | } | ||
24 | |||
25 | static int parse_attr(const char *name, int len) | ||
26 | { | ||
27 | static const int attr_values[] = { 1, 2, 4, 5, 7 }; | ||
28 | static const char * const attr_names[] = { | ||
29 | "bold", "dim", "ul", "blink", "reverse" | ||
30 | }; | ||
31 | int i; | ||
32 | for (i = 0; i < ARRAY_SIZE(attr_names); i++) { | ||
33 | const char *str = attr_names[i]; | ||
34 | if (!strncasecmp(name, str, len) && !str[len]) | ||
35 | return attr_values[i]; | ||
36 | } | ||
37 | return -1; | ||
38 | } | ||
39 | |||
40 | void color_parse(const char *value, const char *var, char *dst) | ||
41 | { | ||
42 | color_parse_mem(value, strlen(value), var, dst); | ||
43 | } | ||
44 | |||
45 | void color_parse_mem(const char *value, int value_len, const char *var, | ||
46 | char *dst) | ||
47 | { | ||
48 | const char *ptr = value; | ||
49 | int len = value_len; | ||
50 | int attr = -1; | ||
51 | int fg = -2; | ||
52 | int bg = -2; | ||
53 | |||
54 | if (!strncasecmp(value, "reset", len)) { | ||
55 | strcpy(dst, PERF_COLOR_RESET); | ||
56 | return; | ||
57 | } | ||
58 | |||
59 | /* [fg [bg]] [attr] */ | ||
60 | while (len > 0) { | ||
61 | const char *word = ptr; | ||
62 | int val, wordlen = 0; | ||
63 | |||
64 | while (len > 0 && !isspace(word[wordlen])) { | ||
65 | wordlen++; | ||
66 | len--; | ||
67 | } | ||
68 | |||
69 | ptr = word + wordlen; | ||
70 | while (len > 0 && isspace(*ptr)) { | ||
71 | ptr++; | ||
72 | len--; | ||
73 | } | ||
74 | |||
75 | val = parse_color(word, wordlen); | ||
76 | if (val >= -1) { | ||
77 | if (fg == -2) { | ||
78 | fg = val; | ||
79 | continue; | ||
80 | } | ||
81 | if (bg == -2) { | ||
82 | bg = val; | ||
83 | continue; | ||
84 | } | ||
85 | goto bad; | ||
86 | } | ||
87 | val = parse_attr(word, wordlen); | ||
88 | if (val < 0 || attr != -1) | ||
89 | goto bad; | ||
90 | attr = val; | ||
91 | } | ||
92 | |||
93 | if (attr >= 0 || fg >= 0 || bg >= 0) { | ||
94 | int sep = 0; | ||
95 | |||
96 | *dst++ = '\033'; | ||
97 | *dst++ = '['; | ||
98 | if (attr >= 0) { | ||
99 | *dst++ = '0' + attr; | ||
100 | sep++; | ||
101 | } | ||
102 | if (fg >= 0) { | ||
103 | if (sep++) | ||
104 | *dst++ = ';'; | ||
105 | if (fg < 8) { | ||
106 | *dst++ = '3'; | ||
107 | *dst++ = '0' + fg; | ||
108 | } else { | ||
109 | dst += sprintf(dst, "38;5;%d", fg); | ||
110 | } | ||
111 | } | ||
112 | if (bg >= 0) { | ||
113 | if (sep++) | ||
114 | *dst++ = ';'; | ||
115 | if (bg < 8) { | ||
116 | *dst++ = '4'; | ||
117 | *dst++ = '0' + bg; | ||
118 | } else { | ||
119 | dst += sprintf(dst, "48;5;%d", bg); | ||
120 | } | ||
121 | } | ||
122 | *dst++ = 'm'; | ||
123 | } | ||
124 | *dst = 0; | ||
125 | return; | ||
126 | bad: | ||
127 | die("bad color value '%.*s' for variable '%s'", value_len, value, var); | ||
128 | } | ||
129 | |||
130 | int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty) | ||
131 | { | ||
132 | if (value) { | ||
133 | if (!strcasecmp(value, "never")) | ||
134 | return 0; | ||
135 | if (!strcasecmp(value, "always")) | ||
136 | return 1; | ||
137 | if (!strcasecmp(value, "auto")) | ||
138 | goto auto_color; | ||
139 | } | ||
140 | |||
141 | /* Missing or explicit false to turn off colorization */ | ||
142 | if (!perf_config_bool(var, value)) | ||
143 | return 0; | ||
144 | |||
145 | /* any normal truth value defaults to 'auto' */ | ||
146 | auto_color: | ||
147 | if (stdout_is_tty < 0) | ||
148 | stdout_is_tty = isatty(1); | ||
149 | if (stdout_is_tty || (pager_in_use() && pager_use_color)) { | ||
150 | char *term = getenv("TERM"); | ||
151 | if (term && strcmp(term, "dumb")) | ||
152 | return 1; | ||
153 | } | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | int perf_color_default_config(const char *var, const char *value, void *cb) | ||
158 | { | ||
159 | if (!strcmp(var, "color.ui")) { | ||
160 | perf_use_color_default = perf_config_colorbool(var, value, -1); | ||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | return perf_default_config(var, value, cb); | ||
165 | } | ||
166 | |||
167 | static int color_vfprintf(FILE *fp, const char *color, const char *fmt, | ||
168 | va_list args, const char *trail) | ||
169 | { | ||
170 | int r = 0; | ||
171 | |||
172 | if (*color) | ||
173 | r += fprintf(fp, "%s", color); | ||
174 | r += vfprintf(fp, fmt, args); | ||
175 | if (*color) | ||
176 | r += fprintf(fp, "%s", PERF_COLOR_RESET); | ||
177 | if (trail) | ||
178 | r += fprintf(fp, "%s", trail); | ||
179 | return r; | ||
180 | } | ||
181 | |||
182 | |||
183 | |||
184 | int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) | ||
185 | { | ||
186 | va_list args; | ||
187 | int r; | ||
188 | va_start(args, fmt); | ||
189 | r = color_vfprintf(fp, color, fmt, args, NULL); | ||
190 | va_end(args); | ||
191 | return r; | ||
192 | } | ||
193 | |||
194 | int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...) | ||
195 | { | ||
196 | va_list args; | ||
197 | int r; | ||
198 | va_start(args, fmt); | ||
199 | r = color_vfprintf(fp, color, fmt, args, "\n"); | ||
200 | va_end(args); | ||
201 | return r; | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * This function splits the buffer by newlines and colors the lines individually. | ||
206 | * | ||
207 | * Returns 0 on success. | ||
208 | */ | ||
209 | int color_fwrite_lines(FILE *fp, const char *color, | ||
210 | size_t count, const char *buf) | ||
211 | { | ||
212 | if (!*color) | ||
213 | return fwrite(buf, count, 1, fp) != 1; | ||
214 | while (count) { | ||
215 | char *p = memchr(buf, '\n', count); | ||
216 | if (p != buf && (fputs(color, fp) < 0 || | ||
217 | fwrite(buf, p ? p - buf : count, 1, fp) != 1 || | ||
218 | fputs(PERF_COLOR_RESET, fp) < 0)) | ||
219 | return -1; | ||
220 | if (!p) | ||
221 | return 0; | ||
222 | if (fputc('\n', fp) < 0) | ||
223 | return -1; | ||
224 | count -= p + 1 - buf; | ||
225 | buf = p + 1; | ||
226 | } | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | |||
diff --git a/Documentation/perf_counter/util/color.h b/Documentation/perf_counter/util/color.h new file mode 100644 index 000000000000..5abfd379582b --- /dev/null +++ b/Documentation/perf_counter/util/color.h | |||
@@ -0,0 +1,36 @@ | |||
1 | #ifndef COLOR_H | ||
2 | #define COLOR_H | ||
3 | |||
4 | /* "\033[1;38;5;2xx;48;5;2xxm\0" is 23 bytes */ | ||
5 | #define COLOR_MAXLEN 24 | ||
6 | |||
7 | #define PERF_COLOR_NORMAL "" | ||
8 | #define PERF_COLOR_RESET "\033[m" | ||
9 | #define PERF_COLOR_BOLD "\033[1m" | ||
10 | #define PERF_COLOR_RED "\033[31m" | ||
11 | #define PERF_COLOR_GREEN "\033[32m" | ||
12 | #define PERF_COLOR_YELLOW "\033[33m" | ||
13 | #define PERF_COLOR_BLUE "\033[34m" | ||
14 | #define PERF_COLOR_MAGENTA "\033[35m" | ||
15 | #define PERF_COLOR_CYAN "\033[36m" | ||
16 | #define PERF_COLOR_BG_RED "\033[41m" | ||
17 | |||
18 | /* | ||
19 | * This variable stores the value of color.ui | ||
20 | */ | ||
21 | extern int perf_use_color_default; | ||
22 | |||
23 | |||
24 | /* | ||
25 | * Use this instead of perf_default_config if you need the value of color.ui. | ||
26 | */ | ||
27 | int perf_color_default_config(const char *var, const char *value, void *cb); | ||
28 | |||
29 | int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty); | ||
30 | void color_parse(const char *value, const char *var, char *dst); | ||
31 | void color_parse_mem(const char *value, int len, const char *var, char *dst); | ||
32 | int color_fprintf(FILE *fp, const char *color, const char *fmt, ...); | ||
33 | int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...); | ||
34 | int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf); | ||
35 | |||
36 | #endif /* COLOR_H */ | ||
diff --git a/Documentation/perf_counter/util/environment.c b/Documentation/perf_counter/util/environment.c index 9b1c8199e729..275b0ee345f5 100644 --- a/Documentation/perf_counter/util/environment.c +++ b/Documentation/perf_counter/util/environment.c | |||
@@ -6,3 +6,4 @@ | |||
6 | #include "cache.h" | 6 | #include "cache.h" |
7 | 7 | ||
8 | const char *pager_program; | 8 | const char *pager_program; |
9 | int pager_use_color = 1; | ||