aboutsummaryrefslogtreecommitdiffstats
path: root/Documentation
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2009-06-04 09:19:47 -0400
committerIngo Molnar <mingo@elte.hu>2009-06-04 09:28:11 -0400
commit8fc0321f1ad0ffef969056dda91b453bbd7a494d (patch)
tree8931ad2c6582a2f59930301c3c099aa1532bb14c /Documentation
parent71dd8945d8d827ab101cd287f9480ef22fc7c1b6 (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/Makefile2
-rw-r--r--Documentation/perf_counter/builtin-report.c15
-rw-r--r--Documentation/perf_counter/builtin-top.c23
-rw-r--r--Documentation/perf_counter/util/color.c230
-rw-r--r--Documentation/perf_counter/util/color.h36
-rw-r--r--Documentation/perf_counter/util/environment.c1
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
298LIB_H += util/run-command.h 298LIB_H += util/run-command.h
299LIB_H += util/sigchain.h 299LIB_H += util/sigchain.h
300LIB_H += util/symbol.h 300LIB_H += util/symbol.h
301LIB_H += util/color.h
301 302
302LIB_OBJS += util/abspath.o 303LIB_OBJS += util/abspath.o
303LIB_OBJS += util/alias.o 304LIB_OBJS += util/alias.o
@@ -319,6 +320,7 @@ LIB_OBJS += util/usage.o
319LIB_OBJS += util/wrapper.o 320LIB_OBJS += util/wrapper.o
320LIB_OBJS += util/sigchain.o 321LIB_OBJS += util/sigchain.o
321LIB_OBJS += util/symbol.o 322LIB_OBJS += util/symbol.o
323LIB_OBJS += util/color.o
322LIB_OBJS += util/pager.o 324LIB_OBJS += util/pager.o
323 325
324BUILTIN_OBJS += builtin-help.o 326BUILTIN_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
4int perf_use_color_default = 0;
5
6static 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
25static 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
40void color_parse(const char *value, const char *var, char *dst)
41{
42 color_parse_mem(value, strlen(value), var, dst);
43}
44
45void 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;
126bad:
127 die("bad color value '%.*s' for variable '%s'", value_len, value, var);
128}
129
130int 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
157int 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
167static 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
184int 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
194int 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 */
209int 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 */
21extern 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 */
27int perf_color_default_config(const char *var, const char *value, void *cb);
28
29int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty);
30void color_parse(const char *value, const char *var, char *dst);
31void color_parse_mem(const char *value, int len, const char *var, char *dst);
32int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
33int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
34int 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
8const char *pager_program; 8const char *pager_program;
9int pager_use_color = 1;