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

Commit 89e3bbd5 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge tag 'perf-core-for-mingo' of...

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux

 into perf/core

Pull perf/tools improvements and fixes from Arnaldo Carvalho de Melo:

  * Honour -m option in 'trace', the tool was offering the option to
    set the mmap size, but wasn't using it when doing the actual mmap
    on the events file descriptors, fix from Jiri Olsa.

  * Correct the message in feature-libnuma checking, swowing the right
    devel package names for various distros, from Dongsheng Yang.

  * Polish 'readn' function and introduce its counterpart, 'writen', from
    Jiri Olsa.

  * Start moving timechart state from global variables to a 'perf_tool' derived
    'timechart' struct.

Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 0ed1e0be f885037e
Loading
Loading
Loading
Loading
+6 −14
Original line number Diff line number Diff line
@@ -76,7 +76,7 @@ struct perf_record {
	long			samples;
};

static int do_write_output(struct perf_record *rec, void *buf, size_t size)
static int perf_record__write(struct perf_record *rec, void *buf, size_t size)
{
	struct perf_data_file *file = &rec->file;

@@ -97,21 +97,13 @@ static int do_write_output(struct perf_record *rec, void *buf, size_t size)
	return 0;
}

static int write_output(struct perf_record *rec, void *buf, size_t size)
{
	return do_write_output(rec, buf, size);
}

static int process_synthesized_event(struct perf_tool *tool,
				     union perf_event *event,
				     struct perf_sample *sample __maybe_unused,
				     struct machine *machine __maybe_unused)
{
	struct perf_record *rec = container_of(tool, struct perf_record, tool);
	if (write_output(rec, event, event->header.size) < 0)
		return -1;

	return 0;
	return perf_record__write(rec, event, event->header.size);
}

static int perf_record__mmap_read(struct perf_record *rec,
@@ -136,7 +128,7 @@ static int perf_record__mmap_read(struct perf_record *rec,
		size = md->mask + 1 - (old & md->mask);
		old += size;

		if (write_output(rec, buf, size) < 0) {
		if (perf_record__write(rec, buf, size) < 0) {
			rc = -1;
			goto out;
		}
@@ -146,7 +138,7 @@ static int perf_record__mmap_read(struct perf_record *rec,
	size = head - old;
	old += size;

	if (write_output(rec, buf, size) < 0) {
	if (perf_record__write(rec, buf, size) < 0) {
		rc = -1;
		goto out;
	}
@@ -335,7 +327,7 @@ static int perf_record__mmap_read_all(struct perf_record *rec)
	}

	if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA))
		rc = write_output(rec, &finished_round_event,
		rc = perf_record__write(rec, &finished_round_event,
					sizeof(finished_round_event));

out:
+191 −173
Original line number Diff line number Diff line
@@ -41,19 +41,25 @@
#define SUPPORT_OLD_POWER_EVENTS 1
#define PWR_EVENT_EXIT -1

static int proc_num = 15;

static unsigned int	numcpus;
static u64		min_freq;	/* Lowest CPU frequency seen */
static u64		max_freq;	/* Highest CPU frequency seen */
static u64		turbo_frequency;

static u64		first_time, last_time;

static bool		power_only;
static bool		tasks_only;
static bool		with_backtrace;

struct per_pid;
struct power_event;
struct wake_event;

struct timechart {
	struct perf_tool	tool;
	struct per_pid		*all_data;
	struct power_event	*power_events;
	struct wake_event	*wake_events;
	int			proc_num;
	unsigned int		numcpus;
	u64			min_freq,	/* Lowest CPU frequency seen */
				max_freq,	/* Highest CPU frequency seen */
				turbo_frequency,
				first_time, last_time;
	bool			power_only,
				tasks_only,
				with_backtrace;
};

struct per_pidcomm;
struct cpu_sample;
@@ -124,8 +130,6 @@ struct cpu_sample {
	const char *backtrace;
};

static struct per_pid *all_data;

#define CSTATE 1
#define PSTATE 2

@@ -146,9 +150,6 @@ struct wake_event {
	const char *backtrace;
};

static struct power_event    *power_events;
static struct wake_event     *wake_events;

struct process_filter {
	char			*name;
	int			pid;
@@ -158,9 +159,9 @@ struct process_filter {
static struct process_filter *process_filter;


static struct per_pid *find_create_pid(int pid)
static struct per_pid *find_create_pid(struct timechart *tchart, int pid)
{
	struct per_pid *cursor = all_data;
	struct per_pid *cursor = tchart->all_data;

	while (cursor) {
		if (cursor->pid == pid)
@@ -170,16 +171,16 @@ static struct per_pid *find_create_pid(int pid)
	cursor = zalloc(sizeof(*cursor));
	assert(cursor != NULL);
	cursor->pid = pid;
	cursor->next = all_data;
	all_data = cursor;
	cursor->next = tchart->all_data;
	tchart->all_data = cursor;
	return cursor;
}

static void pid_set_comm(int pid, char *comm)
static void pid_set_comm(struct timechart *tchart, int pid, char *comm)
{
	struct per_pid *p;
	struct per_pidcomm *c;
	p = find_create_pid(pid);
	p = find_create_pid(tchart, pid);
	c = p->all;
	while (c) {
		if (c->comm && strcmp(c->comm, comm) == 0) {
@@ -201,14 +202,14 @@ static void pid_set_comm(int pid, char *comm)
	p->all = c;
}

static void pid_fork(int pid, int ppid, u64 timestamp)
static void pid_fork(struct timechart *tchart, int pid, int ppid, u64 timestamp)
{
	struct per_pid *p, *pp;
	p = find_create_pid(pid);
	pp = find_create_pid(ppid);
	p = find_create_pid(tchart, pid);
	pp = find_create_pid(tchart, ppid);
	p->ppid = ppid;
	if (pp->current && pp->current->comm && !p->current)
		pid_set_comm(pid, pp->current->comm);
		pid_set_comm(tchart, pid, pp->current->comm);

	p->start_time = timestamp;
	if (p->current) {
@@ -217,24 +218,24 @@ static void pid_fork(int pid, int ppid, u64 timestamp)
	}
}

static void pid_exit(int pid, u64 timestamp)
static void pid_exit(struct timechart *tchart, int pid, u64 timestamp)
{
	struct per_pid *p;
	p = find_create_pid(pid);
	p = find_create_pid(tchart, pid);
	p->end_time = timestamp;
	if (p->current)
		p->current->end_time = timestamp;
}

static void
pid_put_sample(int pid, int type, unsigned int cpu, u64 start, u64 end,
static void pid_put_sample(struct timechart *tchart, int pid, int type,
			   unsigned int cpu, u64 start, u64 end,
			   const char *backtrace)
{
	struct per_pid *p;
	struct per_pidcomm *c;
	struct cpu_sample *sample;

	p = find_create_pid(pid);
	p = find_create_pid(tchart, pid);
	c = p->current;
	if (!c) {
		c = zalloc(sizeof(*c));
@@ -272,30 +273,33 @@ static int cpus_cstate_state[MAX_CPUS];
static u64 cpus_pstate_start_times[MAX_CPUS];
static u64 cpus_pstate_state[MAX_CPUS];

static int process_comm_event(struct perf_tool *tool __maybe_unused,
static int process_comm_event(struct perf_tool *tool,
			      union perf_event *event,
			      struct perf_sample *sample __maybe_unused,
			      struct machine *machine __maybe_unused)
{
	pid_set_comm(event->comm.tid, event->comm.comm);
	struct timechart *tchart = container_of(tool, struct timechart, tool);
	pid_set_comm(tchart, event->comm.tid, event->comm.comm);
	return 0;
}

static int process_fork_event(struct perf_tool *tool __maybe_unused,
static int process_fork_event(struct perf_tool *tool,
			      union perf_event *event,
			      struct perf_sample *sample __maybe_unused,
			      struct machine *machine __maybe_unused)
{
	pid_fork(event->fork.pid, event->fork.ppid, event->fork.time);
	struct timechart *tchart = container_of(tool, struct timechart, tool);
	pid_fork(tchart, event->fork.pid, event->fork.ppid, event->fork.time);
	return 0;
}

static int process_exit_event(struct perf_tool *tool __maybe_unused,
static int process_exit_event(struct perf_tool *tool,
			      union perf_event *event,
			      struct perf_sample *sample __maybe_unused,
			      struct machine *machine __maybe_unused)
{
	pid_exit(event->fork.pid, event->fork.time);
	struct timechart *tchart = container_of(tool, struct timechart, tool);
	pid_exit(tchart, event->fork.pid, event->fork.time);
	return 0;
}

@@ -309,7 +313,7 @@ static void c_state_start(int cpu, u64 timestamp, int state)
	cpus_cstate_state[cpu] = state;
}

static void c_state_end(int cpu, u64 timestamp)
static void c_state_end(struct timechart *tchart, int cpu, u64 timestamp)
{
	struct power_event *pwr = zalloc(sizeof(*pwr));

@@ -321,12 +325,12 @@ static void c_state_end(int cpu, u64 timestamp)
	pwr->end_time = timestamp;
	pwr->cpu = cpu;
	pwr->type = CSTATE;
	pwr->next = power_events;
	pwr->next = tchart->power_events;

	power_events = pwr;
	tchart->power_events = pwr;
}

static void p_state_change(int cpu, u64 timestamp, u64 new_freq)
static void p_state_change(struct timechart *tchart, int cpu, u64 timestamp, u64 new_freq)
{
	struct power_event *pwr;

@@ -342,28 +346,28 @@ static void p_state_change(int cpu, u64 timestamp, u64 new_freq)
	pwr->end_time = timestamp;
	pwr->cpu = cpu;
	pwr->type = PSTATE;
	pwr->next = power_events;
	pwr->next = tchart->power_events;

	if (!pwr->start_time)
		pwr->start_time = first_time;
		pwr->start_time = tchart->first_time;

	power_events = pwr;
	tchart->power_events = pwr;

	cpus_pstate_state[cpu] = new_freq;
	cpus_pstate_start_times[cpu] = timestamp;

	if ((u64)new_freq > max_freq)
		max_freq = new_freq;
	if ((u64)new_freq > tchart->max_freq)
		tchart->max_freq = new_freq;

	if (new_freq < min_freq || min_freq == 0)
		min_freq = new_freq;
	if (new_freq < tchart->min_freq || tchart->min_freq == 0)
		tchart->min_freq = new_freq;

	if (new_freq == max_freq - 1000)
			turbo_frequency = max_freq;
	if (new_freq == tchart->max_freq - 1000)
		tchart->turbo_frequency = tchart->max_freq;
}

static void sched_wakeup(int cpu, u64 timestamp, int waker, int wakee,
			 u8 flags, const char *backtrace)
static void sched_wakeup(struct timechart *tchart, int cpu, u64 timestamp,
			 int waker, int wakee, u8 flags, const char *backtrace)
{
	struct per_pid *p;
	struct wake_event *we = zalloc(sizeof(*we));
@@ -379,38 +383,39 @@ static void sched_wakeup(int cpu, u64 timestamp, int waker, int wakee,
		we->waker = -1;

	we->wakee = wakee;
	we->next = wake_events;
	wake_events = we;
	p = find_create_pid(we->wakee);
	we->next = tchart->wake_events;
	tchart->wake_events = we;
	p = find_create_pid(tchart, we->wakee);

	if (p && p->current && p->current->state == TYPE_NONE) {
		p->current->state_since = timestamp;
		p->current->state = TYPE_WAITING;
	}
	if (p && p->current && p->current->state == TYPE_BLOCKED) {
		pid_put_sample(p->pid, p->current->state, cpu,
		pid_put_sample(tchart, p->pid, p->current->state, cpu,
			       p->current->state_since, timestamp, NULL);
		p->current->state_since = timestamp;
		p->current->state = TYPE_WAITING;
	}
}

static void sched_switch(int cpu, u64 timestamp, int prev_pid, int next_pid,
			 u64 prev_state, const char *backtrace)
static void sched_switch(struct timechart *tchart, int cpu, u64 timestamp,
			 int prev_pid, int next_pid, u64 prev_state,
			 const char *backtrace)
{
	struct per_pid *p = NULL, *prev_p;

	prev_p = find_create_pid(prev_pid);
	prev_p = find_create_pid(tchart, prev_pid);

	p = find_create_pid(next_pid);
	p = find_create_pid(tchart, next_pid);

	if (prev_p->current && prev_p->current->state != TYPE_NONE)
		pid_put_sample(prev_pid, TYPE_RUNNING, cpu,
		pid_put_sample(tchart, prev_pid, TYPE_RUNNING, cpu,
			       prev_p->current->state_since, timestamp,
			       backtrace);
	if (p && p->current) {
		if (p->current->state != TYPE_NONE)
			pid_put_sample(next_pid, p->current->state, cpu,
			pid_put_sample(tchart, next_pid, p->current->state, cpu,
				       p->current->state_since, timestamp,
				       backtrace);

@@ -506,36 +511,40 @@ static const char *cat_backtrace(union perf_event *event,
	return p;
}

typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
typedef int (*tracepoint_handler)(struct timechart *tchart,
				  struct perf_evsel *evsel,
				  struct perf_sample *sample,
				  const char *backtrace);

static int process_sample_event(struct perf_tool *tool __maybe_unused,
static int process_sample_event(struct perf_tool *tool,
				union perf_event *event,
				struct perf_sample *sample,
				struct perf_evsel *evsel,
				struct machine *machine __maybe_unused)
				struct machine *machine)
{
	struct timechart *tchart = container_of(tool, struct timechart, tool);

	if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
		if (!first_time || first_time > sample->time)
			first_time = sample->time;
		if (last_time < sample->time)
			last_time = sample->time;
		if (!tchart->first_time || tchart->first_time > sample->time)
			tchart->first_time = sample->time;
		if (tchart->last_time < sample->time)
			tchart->last_time = sample->time;
	}

	if (sample->cpu > numcpus)
		numcpus = sample->cpu;
	if (sample->cpu > tchart->numcpus)
		tchart->numcpus = sample->cpu;

	if (evsel->handler != NULL) {
		tracepoint_handler f = evsel->handler;
		return f(evsel, sample, cat_backtrace(event, sample, machine));
		return f(tchart, evsel, sample, cat_backtrace(event, sample, machine));
	}

	return 0;
}

static int
process_sample_cpu_idle(struct perf_evsel *evsel,
process_sample_cpu_idle(struct timechart *tchart __maybe_unused,
			struct perf_evsel *evsel,
			struct perf_sample *sample,
			const char *backtrace __maybe_unused)
{
@@ -543,26 +552,28 @@ process_sample_cpu_idle(struct perf_evsel *evsel,
	u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");

	if (state == (u32)PWR_EVENT_EXIT)
		c_state_end(cpu_id, sample->time);
		c_state_end(tchart, cpu_id, sample->time);
	else
		c_state_start(cpu_id, sample->time, state);
	return 0;
}

static int
process_sample_cpu_frequency(struct perf_evsel *evsel,
process_sample_cpu_frequency(struct timechart *tchart,
			     struct perf_evsel *evsel,
			     struct perf_sample *sample,
			     const char *backtrace __maybe_unused)
{
	u32 state = perf_evsel__intval(evsel, sample, "state");
	u32 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");

	p_state_change(cpu_id, sample->time, state);
	p_state_change(tchart, cpu_id, sample->time, state);
	return 0;
}

static int
process_sample_sched_wakeup(struct perf_evsel *evsel,
process_sample_sched_wakeup(struct timechart *tchart,
			    struct perf_evsel *evsel,
			    struct perf_sample *sample,
			    const char *backtrace)
{
@@ -570,12 +581,13 @@ process_sample_sched_wakeup(struct perf_evsel *evsel,
	int waker = perf_evsel__intval(evsel, sample, "common_pid");
	int wakee = perf_evsel__intval(evsel, sample, "pid");

	sched_wakeup(sample->cpu, sample->time, waker, wakee, flags, backtrace);
	sched_wakeup(tchart, sample->cpu, sample->time, waker, wakee, flags, backtrace);
	return 0;
}

static int
process_sample_sched_switch(struct perf_evsel *evsel,
process_sample_sched_switch(struct timechart *tchart,
			    struct perf_evsel *evsel,
			    struct perf_sample *sample,
			    const char *backtrace)
{
@@ -583,14 +595,15 @@ process_sample_sched_switch(struct perf_evsel *evsel,
	int next_pid = perf_evsel__intval(evsel, sample, "next_pid");
	u64 prev_state = perf_evsel__intval(evsel, sample, "prev_state");

	sched_switch(sample->cpu, sample->time, prev_pid, next_pid, prev_state,
		     backtrace);
	sched_switch(tchart, sample->cpu, sample->time, prev_pid, next_pid,
		     prev_state, backtrace);
	return 0;
}

#ifdef SUPPORT_OLD_POWER_EVENTS
static int
process_sample_power_start(struct perf_evsel *evsel,
process_sample_power_start(struct timechart *tchart __maybe_unused,
			   struct perf_evsel *evsel,
			   struct perf_sample *sample,
			   const char *backtrace __maybe_unused)
{
@@ -602,23 +615,25 @@ process_sample_power_start(struct perf_evsel *evsel,
}

static int
process_sample_power_end(struct perf_evsel *evsel __maybe_unused,
process_sample_power_end(struct timechart *tchart,
			 struct perf_evsel *evsel __maybe_unused,
			 struct perf_sample *sample,
			 const char *backtrace __maybe_unused)
{
	c_state_end(sample->cpu, sample->time);
	c_state_end(tchart, sample->cpu, sample->time);
	return 0;
}

static int
process_sample_power_frequency(struct perf_evsel *evsel,
process_sample_power_frequency(struct timechart *tchart,
			       struct perf_evsel *evsel,
			       struct perf_sample *sample,
			       const char *backtrace __maybe_unused)
{
	u64 cpu_id = perf_evsel__intval(evsel, sample, "cpu_id");
	u64 value = perf_evsel__intval(evsel, sample, "value");

	p_state_change(cpu_id, sample->time, value);
	p_state_change(tchart, cpu_id, sample->time, value);
	return 0;
}
#endif /* SUPPORT_OLD_POWER_EVENTS */
@@ -627,12 +642,12 @@ process_sample_power_frequency(struct perf_evsel *evsel,
 * After the last sample we need to wrap up the current C/P state
 * and close out each CPU for these.
 */
static void end_sample_processing(void)
static void end_sample_processing(struct timechart *tchart)
{
	u64 cpu;
	struct power_event *pwr;

	for (cpu = 0; cpu <= numcpus; cpu++) {
	for (cpu = 0; cpu <= tchart->numcpus; cpu++) {
		/* C state */
#if 0
		pwr = zalloc(sizeof(*pwr));
@@ -641,12 +656,12 @@ static void end_sample_processing(void)

		pwr->state = cpus_cstate_state[cpu];
		pwr->start_time = cpus_cstate_start_times[cpu];
		pwr->end_time = last_time;
		pwr->end_time = tchart->last_time;
		pwr->cpu = cpu;
		pwr->type = CSTATE;
		pwr->next = power_events;
		pwr->next = tchart->power_events;

		power_events = pwr;
		tchart->power_events = pwr;
#endif
		/* P state */

@@ -656,32 +671,32 @@ static void end_sample_processing(void)

		pwr->state = cpus_pstate_state[cpu];
		pwr->start_time = cpus_pstate_start_times[cpu];
		pwr->end_time = last_time;
		pwr->end_time = tchart->last_time;
		pwr->cpu = cpu;
		pwr->type = PSTATE;
		pwr->next = power_events;
		pwr->next = tchart->power_events;

		if (!pwr->start_time)
			pwr->start_time = first_time;
			pwr->start_time = tchart->first_time;
		if (!pwr->state)
			pwr->state = min_freq;
		power_events = pwr;
			pwr->state = tchart->min_freq;
		tchart->power_events = pwr;
	}
}

/*
 * Sort the pid datastructure
 */
static void sort_pids(void)
static void sort_pids(struct timechart *tchart)
{
	struct per_pid *new_list, *p, *cursor, *prev;
	/* sort by ppid first, then by pid, lowest to highest */

	new_list = NULL;

	while (all_data) {
		p = all_data;
		all_data = p->next;
	while (tchart->all_data) {
		p = tchart->all_data;
		tchart->all_data = p->next;
		p->next = NULL;

		if (new_list == NULL) {
@@ -714,14 +729,14 @@ static void sort_pids(void)
				prev->next = p;
		}
	}
	all_data = new_list;
	tchart->all_data = new_list;
}


static void draw_c_p_states(void)
static void draw_c_p_states(struct timechart *tchart)
{
	struct power_event *pwr;
	pwr = power_events;
	pwr = tchart->power_events;

	/*
	 * two pass drawing so that the P state bars are on top of the C state blocks
@@ -732,30 +747,30 @@ static void draw_c_p_states(void)
		pwr = pwr->next;
	}

	pwr = power_events;
	pwr = tchart->power_events;
	while (pwr) {
		if (pwr->type == PSTATE) {
			if (!pwr->state)
				pwr->state = min_freq;
				pwr->state = tchart->min_freq;
			svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);
		}
		pwr = pwr->next;
	}
}

static void draw_wakeups(void)
static void draw_wakeups(struct timechart *tchart)
{
	struct wake_event *we;
	struct per_pid *p;
	struct per_pidcomm *c;

	we = wake_events;
	we = tchart->wake_events;
	while (we) {
		int from = 0, to = 0;
		char *task_from = NULL, *task_to = NULL;

		/* locate the column of the waker and wakee */
		p = all_data;
		p = tchart->all_data;
		while (p) {
			if (p->pid == we->waker || p->pid == we->wakee) {
				c = p->all;
@@ -811,12 +826,12 @@ static void draw_wakeups(void)
	}
}

static void draw_cpu_usage(void)
static void draw_cpu_usage(struct timechart *tchart)
{
	struct per_pid *p;
	struct per_pidcomm *c;
	struct cpu_sample *sample;
	p = all_data;
	p = tchart->all_data;
	while (p) {
		c = p->all;
		while (c) {
@@ -833,16 +848,16 @@ static void draw_cpu_usage(void)
	}
}

static void draw_process_bars(void)
static void draw_process_bars(struct timechart *tchart)
{
	struct per_pid *p;
	struct per_pidcomm *c;
	struct cpu_sample *sample;
	int Y = 0;

	Y = 2 * numcpus + 2;
	Y = 2 * tchart->numcpus + 2;

	p = all_data;
	p = tchart->all_data;
	while (p) {
		c = p->all;
		while (c) {
@@ -922,21 +937,21 @@ static int passes_filter(struct per_pid *p, struct per_pidcomm *c)
	return 0;
}

static int determine_display_tasks_filtered(void)
static int determine_display_tasks_filtered(struct timechart *tchart)
{
	struct per_pid *p;
	struct per_pidcomm *c;
	int count = 0;

	p = all_data;
	p = tchart->all_data;
	while (p) {
		p->display = 0;
		if (p->start_time == 1)
			p->start_time = first_time;
			p->start_time = tchart->first_time;

		/* no exit marker, task kept running to the end */
		if (p->end_time == 0)
			p->end_time = last_time;
			p->end_time = tchart->last_time;

		c = p->all;

@@ -944,7 +959,7 @@ static int determine_display_tasks_filtered(void)
			c->display = 0;

			if (c->start_time == 1)
				c->start_time = first_time;
				c->start_time = tchart->first_time;

			if (passes_filter(p, c)) {
				c->display = 1;
@@ -953,7 +968,7 @@ static int determine_display_tasks_filtered(void)
			}

			if (c->end_time == 0)
				c->end_time = last_time;
				c->end_time = tchart->last_time;

			c = c->next;
		}
@@ -962,24 +977,24 @@ static int determine_display_tasks_filtered(void)
	return count;
}

static int determine_display_tasks(u64 threshold)
static int determine_display_tasks(struct timechart *tchart, u64 threshold)
{
	struct per_pid *p;
	struct per_pidcomm *c;
	int count = 0;

	if (process_filter)
		return determine_display_tasks_filtered();
		return determine_display_tasks_filtered(tchart);

	p = all_data;
	p = tchart->all_data;
	while (p) {
		p->display = 0;
		if (p->start_time == 1)
			p->start_time = first_time;
			p->start_time = tchart->first_time;

		/* no exit marker, task kept running to the end */
		if (p->end_time == 0)
			p->end_time = last_time;
			p->end_time = tchart->last_time;
		if (p->total_time >= threshold)
			p->display = 1;

@@ -989,7 +1004,7 @@ static int determine_display_tasks(u64 threshold)
			c->display = 0;

			if (c->start_time == 1)
				c->start_time = first_time;
				c->start_time = tchart->first_time;

			if (c->total_time >= threshold) {
				c->display = 1;
@@ -997,7 +1012,7 @@ static int determine_display_tasks(u64 threshold)
			}

			if (c->end_time == 0)
				c->end_time = last_time;
				c->end_time = tchart->last_time;

			c = c->next;
		}
@@ -1010,52 +1025,45 @@ static int determine_display_tasks(u64 threshold)

#define TIME_THRESH 10000000

static void write_svg_file(const char *filename)
static void write_svg_file(struct timechart *tchart, const char *filename)
{
	u64 i;
	int count;
	int thresh = TIME_THRESH;

	numcpus++;
	tchart->numcpus++;

	if (power_only)
		proc_num = 0;
	if (tchart->power_only)
		tchart->proc_num = 0;

	/* We'd like to show at least proc_num tasks;
	 * be less picky if we have fewer */
	do {
		count = determine_display_tasks(thresh);
		count = determine_display_tasks(tchart, thresh);
		thresh /= 10;
	} while (!process_filter && thresh && count < proc_num);
	} while (!process_filter && thresh && count < tchart->proc_num);

	open_svg(filename, numcpus, count, first_time, last_time);
	open_svg(filename, tchart->numcpus, count, tchart->first_time, tchart->last_time);

	svg_time_grid();
	svg_legenda();

	for (i = 0; i < numcpus; i++)
		svg_cpu_box(i, max_freq, turbo_frequency);
	for (i = 0; i < tchart->numcpus; i++)
		svg_cpu_box(i, tchart->max_freq, tchart->turbo_frequency);

	draw_cpu_usage();
	if (proc_num)
		draw_process_bars();
	if (!tasks_only)
		draw_c_p_states();
	if (proc_num)
		draw_wakeups();
	draw_cpu_usage(tchart);
	if (tchart->proc_num)
		draw_process_bars(tchart);
	if (!tchart->tasks_only)
		draw_c_p_states(tchart);
	if (tchart->proc_num)
		draw_wakeups(tchart);

	svg_close();
}

static int __cmd_timechart(const char *output_name)
static int __cmd_timechart(struct timechart *tchart, const char *output_name)
{
	struct perf_tool perf_timechart = {
		.comm		 = process_comm_event,
		.fork		 = process_fork_event,
		.exit		 = process_exit_event,
		.sample		 = process_sample_event,
		.ordered_samples = true,
	};
	const struct perf_evsel_str_handler power_tracepoints[] = {
		{ "power:cpu_idle",		process_sample_cpu_idle },
		{ "power:cpu_frequency",	process_sample_cpu_frequency },
@@ -1073,7 +1081,7 @@ static int __cmd_timechart(const char *output_name)
	};

	struct perf_session *session = perf_session__new(&file, false,
							 &perf_timechart);
							 &tchart->tool);
	int ret = -EINVAL;

	if (session == NULL)
@@ -1088,24 +1096,24 @@ static int __cmd_timechart(const char *output_name)
		goto out_delete;
	}

	ret = perf_session__process_events(session, &perf_timechart);
	ret = perf_session__process_events(session, &tchart->tool);
	if (ret)
		goto out_delete;

	end_sample_processing();
	end_sample_processing(tchart);

	sort_pids();
	sort_pids(tchart);

	write_svg_file(output_name);
	write_svg_file(tchart, output_name);

	pr_info("Written %2.1f seconds of trace to %s.\n",
		(last_time - first_time) / 1000000000.0, output_name);
		(tchart->last_time - tchart->first_time) / 1000000000.0, output_name);
out_delete:
	perf_session__delete(session);
	return ret;
}

static int __cmd_record(int argc, const char **argv)
static int timechart__record(struct timechart *tchart, int argc, const char **argv)
{
	unsigned int rec_argc, i, j;
	const char **rec_argv;
@@ -1153,15 +1161,15 @@ static int __cmd_record(int argc, const char **argv)
	}
#endif

	if (power_only)
	if (tchart->power_only)
		tasks_args_nr = 0;

	if (tasks_only) {
	if (tchart->tasks_only) {
		power_args_nr = 0;
		old_power_args_nr = 0;
	}

	if (!with_backtrace)
	if (!tchart->with_backtrace)
		backtrace_args_no = 0;

	record_elems = common_args_nr + tasks_args_nr +
@@ -1207,20 +1215,30 @@ parse_process(const struct option *opt __maybe_unused, const char *arg,
int cmd_timechart(int argc, const char **argv,
		  const char *prefix __maybe_unused)
{
	struct timechart tchart = {
		.tool = {
			.comm		 = process_comm_event,
			.fork		 = process_fork_event,
			.exit		 = process_exit_event,
			.sample		 = process_sample_event,
			.ordered_samples = true,
		},
		.proc_num = 15,
	};
	const char *output_name = "output.svg";
	const struct option timechart_options[] = {
	OPT_STRING('i', "input", &input_name, "file", "input file name"),
	OPT_STRING('o', "output", &output_name, "file", "output file name"),
	OPT_INTEGER('w', "width", &svg_page_width, "page width"),
	OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"),
	OPT_BOOLEAN('T', "tasks-only", &tasks_only,
	OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
	OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
		    "output processes data only"),
	OPT_CALLBACK('p', "process", NULL, "process",
		      "process selector. Pass a pid or process name.",
		       parse_process),
	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
		    "Look for files with symbols relative to this directory"),
	OPT_INTEGER('n', "proc-num", &proc_num,
	OPT_INTEGER('n', "proc-num", &tchart.proc_num,
		    "min. number of tasks to print"),
	OPT_END()
	};
@@ -1230,10 +1248,10 @@ int cmd_timechart(int argc, const char **argv,
	};

	const struct option record_options[] = {
	OPT_BOOLEAN('P', "power-only", &power_only, "output power data only"),
	OPT_BOOLEAN('T', "tasks-only", &tasks_only,
	OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
	OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
		    "output processes data only"),
	OPT_BOOLEAN('g', "callchain", &with_backtrace, "record callchain"),
	OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"),
	OPT_END()
	};
	const char * const record_usage[] = {
@@ -1243,7 +1261,7 @@ int cmd_timechart(int argc, const char **argv,
	argc = parse_options(argc, argv, timechart_options, timechart_usage,
			PARSE_OPT_STOP_AT_NON_OPTION);

	if (power_only && tasks_only) {
	if (tchart.power_only && tchart.tasks_only) {
		pr_err("-P and -T options cannot be used at the same time.\n");
		return -1;
	}
@@ -1254,16 +1272,16 @@ int cmd_timechart(int argc, const char **argv,
		argc = parse_options(argc, argv, record_options, record_usage,
				     PARSE_OPT_STOP_AT_NON_OPTION);

		if (power_only && tasks_only) {
		if (tchart.power_only && tchart.tasks_only) {
			pr_err("-P and -T options cannot be used at the same time.\n");
			return -1;
		}

		return __cmd_record(argc, argv);
		return timechart__record(&tchart, argc, argv);
	} else if (argc)
		usage_with_options(timechart_usage, timechart_options);

	setup_pager();

	return __cmd_timechart(output_name);
	return __cmd_timechart(&tchart, output_name);
}
Loading