diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-05-27 03:50:13 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-05-27 03:59:00 -0400 |
commit | a930d2c0d0a685ab955472b08baad041cc5edb4a (patch) | |
tree | 988e0da70e64ef72437058828974d946328280af | |
parent | 23ac9cbed82b00ca3520bb81dbe9ea3b7a936a1b (diff) |
perf_counter tools: Add built-in pager support
Add Git's pager.c (and sigchain) code. A command only
has to call setup_pager() to get paged interactive
output.
Non-interactive (redirected, command-piped, etc.) uses
are not affected.
Update perf-report to make use of this.
[ Impact: new feature ]
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: John Kacur <jkacur@redhat.com>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | Documentation/perf_counter/Makefile | 4 | ||||
-rw-r--r-- | Documentation/perf_counter/builtin-report.c | 3 | ||||
-rw-r--r-- | Documentation/perf_counter/util/environment.c | 8 | ||||
-rw-r--r-- | Documentation/perf_counter/util/pager.c | 99 | ||||
-rw-r--r-- | Documentation/perf_counter/util/sigchain.c | 52 | ||||
-rw-r--r-- | Documentation/perf_counter/util/sigchain.h | 11 |
6 files changed, 177 insertions, 0 deletions
diff --git a/Documentation/perf_counter/Makefile b/Documentation/perf_counter/Makefile index efb05892db69..51b13f989833 100644 --- a/Documentation/perf_counter/Makefile +++ b/Documentation/perf_counter/Makefile | |||
@@ -297,11 +297,13 @@ LIB_H += util/util.h | |||
297 | LIB_H += util/help.h | 297 | LIB_H += util/help.h |
298 | LIB_H += util/strbuf.h | 298 | LIB_H += util/strbuf.h |
299 | LIB_H += util/run-command.h | 299 | LIB_H += util/run-command.h |
300 | LIB_H += util/sigchain.h | ||
300 | 301 | ||
301 | LIB_OBJS += util/abspath.o | 302 | LIB_OBJS += util/abspath.o |
302 | LIB_OBJS += util/alias.o | 303 | LIB_OBJS += util/alias.o |
303 | LIB_OBJS += util/config.o | 304 | LIB_OBJS += util/config.o |
304 | LIB_OBJS += util/ctype.o | 305 | LIB_OBJS += util/ctype.o |
306 | LIB_OBJS += util/environment.o | ||
305 | LIB_OBJS += util/exec_cmd.o | 307 | LIB_OBJS += util/exec_cmd.o |
306 | LIB_OBJS += util/help.o | 308 | LIB_OBJS += util/help.o |
307 | LIB_OBJS += util/levenshtein.o | 309 | LIB_OBJS += util/levenshtein.o |
@@ -314,6 +316,8 @@ LIB_OBJS += util/quote.o | |||
314 | LIB_OBJS += util/strbuf.o | 316 | LIB_OBJS += util/strbuf.o |
315 | LIB_OBJS += util/usage.o | 317 | LIB_OBJS += util/usage.o |
316 | LIB_OBJS += util/wrapper.o | 318 | LIB_OBJS += util/wrapper.o |
319 | LIB_OBJS += util/sigchain.o | ||
320 | LIB_OBJS += util/pager.o | ||
317 | 321 | ||
318 | BUILTIN_OBJS += builtin-help.o | 322 | BUILTIN_OBJS += builtin-help.o |
319 | BUILTIN_OBJS += builtin-record.o | 323 | BUILTIN_OBJS += builtin-record.o |
diff --git a/Documentation/perf_counter/builtin-report.c b/Documentation/perf_counter/builtin-report.c index e2712cd06310..9aef7c54483e 100644 --- a/Documentation/perf_counter/builtin-report.c +++ b/Documentation/perf_counter/builtin-report.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <ctype.h> | 7 | #include <ctype.h> |
8 | 8 | ||
9 | #include "util/list.h" | 9 | #include "util/list.h" |
10 | #include "util/cache.h" | ||
10 | #include "util/rbtree.h" | 11 | #include "util/rbtree.h" |
11 | 12 | ||
12 | #include "perf.h" | 13 | #include "perf.h" |
@@ -992,5 +993,7 @@ int cmd_report(int argc, const char **argv, const char *prefix) | |||
992 | 993 | ||
993 | parse_options(argc, argv, options, report_usage, 0); | 994 | parse_options(argc, argv, options, report_usage, 0); |
994 | 995 | ||
996 | setup_pager(); | ||
997 | |||
995 | return __cmd_report(); | 998 | return __cmd_report(); |
996 | } | 999 | } |
diff --git a/Documentation/perf_counter/util/environment.c b/Documentation/perf_counter/util/environment.c new file mode 100644 index 000000000000..9b1c8199e729 --- /dev/null +++ b/Documentation/perf_counter/util/environment.c | |||
@@ -0,0 +1,8 @@ | |||
1 | /* | ||
2 | * We put all the perf config variables in this same object | ||
3 | * file, so that programs can link against the config parser | ||
4 | * without having to link against all the rest of perf. | ||
5 | */ | ||
6 | #include "cache.h" | ||
7 | |||
8 | const char *pager_program; | ||
diff --git a/Documentation/perf_counter/util/pager.c b/Documentation/perf_counter/util/pager.c new file mode 100644 index 000000000000..a28bccae5458 --- /dev/null +++ b/Documentation/perf_counter/util/pager.c | |||
@@ -0,0 +1,99 @@ | |||
1 | #include "cache.h" | ||
2 | #include "run-command.h" | ||
3 | #include "sigchain.h" | ||
4 | |||
5 | /* | ||
6 | * This is split up from the rest of git so that we can do | ||
7 | * something different on Windows. | ||
8 | */ | ||
9 | |||
10 | static int spawned_pager; | ||
11 | |||
12 | #ifndef __MINGW32__ | ||
13 | static void pager_preexec(void) | ||
14 | { | ||
15 | /* | ||
16 | * Work around bug in "less" by not starting it until we | ||
17 | * have real input | ||
18 | */ | ||
19 | fd_set in; | ||
20 | |||
21 | FD_ZERO(&in); | ||
22 | FD_SET(0, &in); | ||
23 | select(1, &in, NULL, &in, NULL); | ||
24 | |||
25 | setenv("LESS", "FRSX", 0); | ||
26 | } | ||
27 | #endif | ||
28 | |||
29 | static const char *pager_argv[] = { "sh", "-c", NULL, NULL }; | ||
30 | static struct child_process pager_process; | ||
31 | |||
32 | static void wait_for_pager(void) | ||
33 | { | ||
34 | fflush(stdout); | ||
35 | fflush(stderr); | ||
36 | /* signal EOF to pager */ | ||
37 | close(1); | ||
38 | close(2); | ||
39 | finish_command(&pager_process); | ||
40 | } | ||
41 | |||
42 | static void wait_for_pager_signal(int signo) | ||
43 | { | ||
44 | wait_for_pager(); | ||
45 | sigchain_pop(signo); | ||
46 | raise(signo); | ||
47 | } | ||
48 | |||
49 | void setup_pager(void) | ||
50 | { | ||
51 | const char *pager = getenv("PERF_PAGER"); | ||
52 | |||
53 | if (!isatty(1)) | ||
54 | return; | ||
55 | if (!pager) { | ||
56 | if (!pager_program) | ||
57 | perf_config(perf_default_config, NULL); | ||
58 | pager = pager_program; | ||
59 | } | ||
60 | if (!pager) | ||
61 | pager = getenv("PAGER"); | ||
62 | if (!pager) | ||
63 | pager = "less"; | ||
64 | else if (!*pager || !strcmp(pager, "cat")) | ||
65 | return; | ||
66 | |||
67 | spawned_pager = 1; /* means we are emitting to terminal */ | ||
68 | |||
69 | /* spawn the pager */ | ||
70 | pager_argv[2] = pager; | ||
71 | pager_process.argv = pager_argv; | ||
72 | pager_process.in = -1; | ||
73 | #ifndef __MINGW32__ | ||
74 | pager_process.preexec_cb = pager_preexec; | ||
75 | #endif | ||
76 | if (start_command(&pager_process)) | ||
77 | return; | ||
78 | |||
79 | /* original process continues, but writes to the pipe */ | ||
80 | dup2(pager_process.in, 1); | ||
81 | if (isatty(2)) | ||
82 | dup2(pager_process.in, 2); | ||
83 | close(pager_process.in); | ||
84 | |||
85 | /* this makes sure that the parent terminates after the pager */ | ||
86 | sigchain_push_common(wait_for_pager_signal); | ||
87 | atexit(wait_for_pager); | ||
88 | } | ||
89 | |||
90 | int pager_in_use(void) | ||
91 | { | ||
92 | const char *env; | ||
93 | |||
94 | if (spawned_pager) | ||
95 | return 1; | ||
96 | |||
97 | env = getenv("PERF_PAGER_IN_USE"); | ||
98 | return env ? perf_config_bool("PERF_PAGER_IN_USE", env) : 0; | ||
99 | } | ||
diff --git a/Documentation/perf_counter/util/sigchain.c b/Documentation/perf_counter/util/sigchain.c new file mode 100644 index 000000000000..1118b99e57d3 --- /dev/null +++ b/Documentation/perf_counter/util/sigchain.c | |||
@@ -0,0 +1,52 @@ | |||
1 | #include "sigchain.h" | ||
2 | #include "cache.h" | ||
3 | |||
4 | #define SIGCHAIN_MAX_SIGNALS 32 | ||
5 | |||
6 | struct sigchain_signal { | ||
7 | sigchain_fun *old; | ||
8 | int n; | ||
9 | int alloc; | ||
10 | }; | ||
11 | static struct sigchain_signal signals[SIGCHAIN_MAX_SIGNALS]; | ||
12 | |||
13 | static void check_signum(int sig) | ||
14 | { | ||
15 | if (sig < 1 || sig >= SIGCHAIN_MAX_SIGNALS) | ||
16 | die("BUG: signal out of range: %d", sig); | ||
17 | } | ||
18 | |||
19 | int sigchain_push(int sig, sigchain_fun f) | ||
20 | { | ||
21 | struct sigchain_signal *s = signals + sig; | ||
22 | check_signum(sig); | ||
23 | |||
24 | ALLOC_GROW(s->old, s->n + 1, s->alloc); | ||
25 | s->old[s->n] = signal(sig, f); | ||
26 | if (s->old[s->n] == SIG_ERR) | ||
27 | return -1; | ||
28 | s->n++; | ||
29 | return 0; | ||
30 | } | ||
31 | |||
32 | int sigchain_pop(int sig) | ||
33 | { | ||
34 | struct sigchain_signal *s = signals + sig; | ||
35 | check_signum(sig); | ||
36 | if (s->n < 1) | ||
37 | return 0; | ||
38 | |||
39 | if (signal(sig, s->old[s->n - 1]) == SIG_ERR) | ||
40 | return -1; | ||
41 | s->n--; | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | void sigchain_push_common(sigchain_fun f) | ||
46 | { | ||
47 | sigchain_push(SIGINT, f); | ||
48 | sigchain_push(SIGHUP, f); | ||
49 | sigchain_push(SIGTERM, f); | ||
50 | sigchain_push(SIGQUIT, f); | ||
51 | sigchain_push(SIGPIPE, f); | ||
52 | } | ||
diff --git a/Documentation/perf_counter/util/sigchain.h b/Documentation/perf_counter/util/sigchain.h new file mode 100644 index 000000000000..618083bce0c6 --- /dev/null +++ b/Documentation/perf_counter/util/sigchain.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #ifndef SIGCHAIN_H | ||
2 | #define SIGCHAIN_H | ||
3 | |||
4 | typedef void (*sigchain_fun)(int); | ||
5 | |||
6 | int sigchain_push(int sig, sigchain_fun f); | ||
7 | int sigchain_pop(int sig); | ||
8 | |||
9 | void sigchain_push_common(sigchain_fun f); | ||
10 | |||
11 | #endif /* SIGCHAIN_H */ | ||