Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a930d2c0 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

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: default avatarIngo Molnar <mingo@elte.hu>
parent 23ac9cbe
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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
+3 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
/*
 * 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 −0
Original line number Diff line number Diff line
#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 −0
Original line number Diff line number Diff line
#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);
}
Loading