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>
This commit is contained in:
parent
23ac9cbed8
commit
a930d2c0d0
6 changed files with 177 additions and 0 deletions
|
@ -297,11 +297,13 @@ LIB_H += util/util.h
|
|||
LIB_H += util/help.h
|
||||
LIB_H += util/strbuf.h
|
||||
LIB_H += util/run-command.h
|
||||
LIB_H += util/sigchain.h
|
||||
|
||||
LIB_OBJS += util/abspath.o
|
||||
LIB_OBJS += util/alias.o
|
||||
LIB_OBJS += util/config.o
|
||||
LIB_OBJS += util/ctype.o
|
||||
LIB_OBJS += util/environment.o
|
||||
LIB_OBJS += util/exec_cmd.o
|
||||
LIB_OBJS += util/help.o
|
||||
LIB_OBJS += util/levenshtein.o
|
||||
|
@ -314,6 +316,8 @@ LIB_OBJS += util/quote.o
|
|||
LIB_OBJS += util/strbuf.o
|
||||
LIB_OBJS += util/usage.o
|
||||
LIB_OBJS += util/wrapper.o
|
||||
LIB_OBJS += util/sigchain.o
|
||||
LIB_OBJS += util/pager.o
|
||||
|
||||
BUILTIN_OBJS += builtin-help.o
|
||||
BUILTIN_OBJS += builtin-record.o
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <ctype.h>
|
||||
|
||||
#include "util/list.h"
|
||||
#include "util/cache.h"
|
||||
#include "util/rbtree.h"
|
||||
|
||||
#include "perf.h"
|
||||
|
@ -992,5 +993,7 @@ int cmd_report(int argc, const char **argv, const char *prefix)
|
|||
|
||||
parse_options(argc, argv, options, report_usage, 0);
|
||||
|
||||
setup_pager();
|
||||
|
||||
return __cmd_report();
|
||||
}
|
||||
|
|
8
Documentation/perf_counter/util/environment.c
Normal file
8
Documentation/perf_counter/util/environment.c
Normal file
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* We put all the perf config variables in this same object
|
||||
* file, so that programs can link against the config parser
|
||||
* without having to link against all the rest of perf.
|
||||
*/
|
||||
#include "cache.h"
|
||||
|
||||
const char *pager_program;
|
99
Documentation/perf_counter/util/pager.c
Normal file
99
Documentation/perf_counter/util/pager.c
Normal file
|
@ -0,0 +1,99 @@
|
|||
#include "cache.h"
|
||||
#include "run-command.h"
|
||||
#include "sigchain.h"
|
||||
|
||||
/*
|
||||
* This is split up from the rest of git so that we can do
|
||||
* something different on Windows.
|
||||
*/
|
||||
|
||||
static int spawned_pager;
|
||||
|
||||
#ifndef __MINGW32__
|
||||
static void pager_preexec(void)
|
||||
{
|
||||
/*
|
||||
* Work around bug in "less" by not starting it until we
|
||||
* have real input
|
||||
*/
|
||||
fd_set in;
|
||||
|
||||
FD_ZERO(&in);
|
||||
FD_SET(0, &in);
|
||||
select(1, &in, NULL, &in, NULL);
|
||||
|
||||
setenv("LESS", "FRSX", 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char *pager_argv[] = { "sh", "-c", NULL, NULL };
|
||||
static struct child_process pager_process;
|
||||
|
||||
static void wait_for_pager(void)
|
||||
{
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
/* signal EOF to pager */
|
||||
close(1);
|
||||
close(2);
|
||||
finish_command(&pager_process);
|
||||
}
|
||||
|
||||
static void wait_for_pager_signal(int signo)
|
||||
{
|
||||
wait_for_pager();
|
||||
sigchain_pop(signo);
|
||||
raise(signo);
|
||||
}
|
||||
|
||||
void setup_pager(void)
|
||||
{
|
||||
const char *pager = getenv("PERF_PAGER");
|
||||
|
||||
if (!isatty(1))
|
||||
return;
|
||||
if (!pager) {
|
||||
if (!pager_program)
|
||||
perf_config(perf_default_config, NULL);
|
||||
pager = pager_program;
|
||||
}
|
||||
if (!pager)
|
||||
pager = getenv("PAGER");
|
||||
if (!pager)
|
||||
pager = "less";
|
||||
else if (!*pager || !strcmp(pager, "cat"))
|
||||
return;
|
||||
|
||||
spawned_pager = 1; /* means we are emitting to terminal */
|
||||
|
||||
/* spawn the pager */
|
||||
pager_argv[2] = pager;
|
||||
pager_process.argv = pager_argv;
|
||||
pager_process.in = -1;
|
||||
#ifndef __MINGW32__
|
||||
pager_process.preexec_cb = pager_preexec;
|
||||
#endif
|
||||
if (start_command(&pager_process))
|
||||
return;
|
||||
|
||||
/* original process continues, but writes to the pipe */
|
||||
dup2(pager_process.in, 1);
|
||||
if (isatty(2))
|
||||
dup2(pager_process.in, 2);
|
||||
close(pager_process.in);
|
||||
|
||||
/* this makes sure that the parent terminates after the pager */
|
||||
sigchain_push_common(wait_for_pager_signal);
|
||||
atexit(wait_for_pager);
|
||||
}
|
||||
|
||||
int pager_in_use(void)
|
||||
{
|
||||
const char *env;
|
||||
|
||||
if (spawned_pager)
|
||||
return 1;
|
||||
|
||||
env = getenv("PERF_PAGER_IN_USE");
|
||||
return env ? perf_config_bool("PERF_PAGER_IN_USE", env) : 0;
|
||||
}
|
52
Documentation/perf_counter/util/sigchain.c
Normal file
52
Documentation/perf_counter/util/sigchain.c
Normal file
|
@ -0,0 +1,52 @@
|
|||
#include "sigchain.h"
|
||||
#include "cache.h"
|
||||
|
||||
#define SIGCHAIN_MAX_SIGNALS 32
|
||||
|
||||
struct sigchain_signal {
|
||||
sigchain_fun *old;
|
||||
int n;
|
||||
int alloc;
|
||||
};
|
||||
static struct sigchain_signal signals[SIGCHAIN_MAX_SIGNALS];
|
||||
|
||||
static void check_signum(int sig)
|
||||
{
|
||||
if (sig < 1 || sig >= SIGCHAIN_MAX_SIGNALS)
|
||||
die("BUG: signal out of range: %d", sig);
|
||||
}
|
||||
|
||||
int sigchain_push(int sig, sigchain_fun f)
|
||||
{
|
||||
struct sigchain_signal *s = signals + sig;
|
||||
check_signum(sig);
|
||||
|
||||
ALLOC_GROW(s->old, s->n + 1, s->alloc);
|
||||
s->old[s->n] = signal(sig, f);
|
||||
if (s->old[s->n] == SIG_ERR)
|
||||
return -1;
|
||||
s->n++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sigchain_pop(int sig)
|
||||
{
|
||||
struct sigchain_signal *s = signals + sig;
|
||||
check_signum(sig);
|
||||
if (s->n < 1)
|
||||
return 0;
|
||||
|
||||
if (signal(sig, s->old[s->n - 1]) == SIG_ERR)
|
||||
return -1;
|
||||
s->n--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sigchain_push_common(sigchain_fun f)
|
||||
{
|
||||
sigchain_push(SIGINT, f);
|
||||
sigchain_push(SIGHUP, f);
|
||||
sigchain_push(SIGTERM, f);
|
||||
sigchain_push(SIGQUIT, f);
|
||||
sigchain_push(SIGPIPE, f);
|
||||
}
|
11
Documentation/perf_counter/util/sigchain.h
Normal file
11
Documentation/perf_counter/util/sigchain.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#ifndef SIGCHAIN_H
|
||||
#define SIGCHAIN_H
|
||||
|
||||
typedef void (*sigchain_fun)(int);
|
||||
|
||||
int sigchain_push(int sig, sigchain_fun f);
|
||||
int sigchain_pop(int sig);
|
||||
|
||||
void sigchain_push_common(sigchain_fun f);
|
||||
|
||||
#endif /* SIGCHAIN_H */
|
Loading…
Reference in a new issue