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

Commit c5079997 authored by Stanislav Fomichev's avatar Stanislav Fomichev Committed by Arnaldo Carvalho de Melo
Browse files

perf timechart: Add support for topology



Add -t switch to sort CPUs topologically.

Signed-off-by: default avatarStanislav Fomichev <stfomichev@yandex-team.ru>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Ramkumar Ramachandra <artagnon@gmail.com>
Link: http://lkml.kernel.org/r/1385995056-20158-5-git-send-email-stfomichev@yandex-team.ru


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 58b9a18e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -59,6 +59,9 @@ $ perf timechart
-n::
--proc-num::
        Print task info for at least given number of tasks.
-t::
--topology::
        Sort CPUs according to topology.

RECORD OPTIONS
--------------
+16 −1
Original line number Diff line number Diff line
@@ -58,7 +58,8 @@ struct timechart {
				first_time, last_time;
	bool			power_only,
				tasks_only,
				with_backtrace;
				with_backtrace,
				topology;
};

struct per_pidcomm;
@@ -1077,6 +1078,18 @@ static int process_header(struct perf_file_section *section __maybe_unused,
	case HEADER_NRCPUS:
		tchart->numcpus = ph->env.nr_cpus_avail;
		break;

	case HEADER_CPU_TOPOLOGY:
		if (!tchart->topology)
			break;

		if (svg_build_topology_map(ph->env.sibling_cores,
					   ph->env.nr_sibling_cores,
					   ph->env.sibling_threads,
					   ph->env.nr_sibling_threads))
			fprintf(stderr, "problem building topology\n");
		break;

	default:
		break;
	}
@@ -1267,6 +1280,8 @@ int cmd_timechart(int argc, const char **argv,
		    "Look for files with symbols relative to this directory"),
	OPT_INTEGER('n', "proc-num", &tchart.proc_num,
		    "min. number of tasks to print"),
	OPT_BOOLEAN('t', "topology", &tchart.topology,
		    "sort CPUs according to topology"),
	OPT_END()
	};
	const char * const timechart_usage[] = {
+130 −2
Original line number Diff line number Diff line
@@ -17,8 +17,11 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <linux/bitops.h>

#include "perf.h"
#include "svghelper.h"
#include "cpumap.h"

static u64 first_time, last_time;
static u64 turbo_frequency, max_freq;
@@ -39,8 +42,13 @@ static double cpu2slot(int cpu)
	return 2 * cpu + 1;
}

static int *topology_map;

static double cpu2y(int cpu)
{
	if (topology_map)
		return cpu2slot(topology_map[cpu]) * SLOT_MULT;
	else
		return cpu2slot(cpu) * SLOT_MULT;
}

@@ -275,7 +283,7 @@ void svg_cpu_box(int cpu, u64 __max_freq, u64 __turbo_freq)
		time2pixels(last_time)-time2pixels(first_time),
		cpu2y(cpu), SLOT_MULT+SLOT_HEIGHT);

	sprintf(cpu_string, "CPU %i", (int)cpu+1);
	sprintf(cpu_string, "CPU %i", (int)cpu);
	fprintf(svgfile, "<text x=\"%4.8f\" y=\"%4.8f\">%s</text>\n",
		10+time2pixels(first_time), cpu2y(cpu) + SLOT_HEIGHT/2, cpu_string);

@@ -568,3 +576,123 @@ void svg_close(void)
		svgfile = NULL;
	}
}

#define cpumask_bits(maskp) ((maskp)->bits)
typedef struct { DECLARE_BITMAP(bits, MAX_NR_CPUS); } cpumask_t;

struct topology {
	cpumask_t *sib_core;
	int sib_core_nr;
	cpumask_t *sib_thr;
	int sib_thr_nr;
};

static void scan_thread_topology(int *map, struct topology *t, int cpu, int *pos)
{
	int i;
	int thr;

	for (i = 0; i < t->sib_thr_nr; i++) {
		if (!test_bit(cpu, cpumask_bits(&t->sib_thr[i])))
			continue;

		for_each_set_bit(thr,
				 cpumask_bits(&t->sib_thr[i]),
				 MAX_NR_CPUS)
			if (map[thr] == -1)
				map[thr] = (*pos)++;
	}
}

static void scan_core_topology(int *map, struct topology *t)
{
	int pos = 0;
	int i;
	int cpu;

	for (i = 0; i < t->sib_core_nr; i++)
		for_each_set_bit(cpu,
				 cpumask_bits(&t->sib_core[i]),
				 MAX_NR_CPUS)
			scan_thread_topology(map, t, cpu, &pos);
}

static int str_to_bitmap(char *s, cpumask_t *b)
{
	int i;
	int ret = 0;
	struct cpu_map *m;
	int c;

	m = cpu_map__new(s);
	if (!m)
		return -1;

	for (i = 0; i < m->nr; i++) {
		c = m->map[i];
		if (c >= MAX_NR_CPUS) {
			ret = -1;
			break;
		}

		set_bit(c, cpumask_bits(b));
	}

	cpu_map__delete(m);

	return ret;
}

int svg_build_topology_map(char *sib_core, int sib_core_nr,
			   char *sib_thr, int sib_thr_nr)
{
	int i;
	struct topology t;

	t.sib_core_nr = sib_core_nr;
	t.sib_thr_nr = sib_thr_nr;
	t.sib_core = calloc(sib_core_nr, sizeof(cpumask_t));
	t.sib_thr = calloc(sib_thr_nr, sizeof(cpumask_t));

	if (!t.sib_core || !t.sib_thr) {
		fprintf(stderr, "topology: no memory\n");
		goto exit;
	}

	for (i = 0; i < sib_core_nr; i++) {
		if (str_to_bitmap(sib_core, &t.sib_core[i])) {
			fprintf(stderr, "topology: can't parse siblings map\n");
			goto exit;
		}

		sib_core += strlen(sib_core) + 1;
	}

	for (i = 0; i < sib_thr_nr; i++) {
		if (str_to_bitmap(sib_thr, &t.sib_thr[i])) {
			fprintf(stderr, "topology: can't parse siblings map\n");
			goto exit;
		}

		sib_thr += strlen(sib_thr) + 1;
	}

	topology_map = malloc(sizeof(int) * MAX_NR_CPUS);
	if (!topology_map) {
		fprintf(stderr, "topology: no memory\n");
		goto exit;
	}

	for (i = 0; i < MAX_NR_CPUS; i++)
		topology_map[i] = -1;

	scan_core_topology(topology_map, &t);

	return 0;

exit:
	free(t.sib_core);
	free(t.sib_thr);

	return -1;
}
+2 −0
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ extern void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, cha
extern void svg_interrupt(u64 start, int row, const char *backtrace);
extern void svg_text(int Yslot, u64 start, const char *text);
extern void svg_close(void);
extern int svg_build_topology_map(char *sib_core, int sib_core_nr,
				  char *sib_thr, int sib_thr_nr);

extern int svg_page_width;