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

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

Merge branch 'email/acme' into perf/core



Merge perf/core improvements and fixes from Arnaldo Carvalho de Melo:

    User visible changes:

 - Allow grouping multiple sort keys per 'perf report/top --hierarchy'
   level (Namhyung Kim)

 - Document 'perf stat --detailed' option (Borislav Petkov)

Infrastructure changes:

 - jitdump prep work for supporting it with Intel PT (Adrian Hunter)

 - Use 64-bit shifts with (TSC) time conversion (Adrian Hunter)

Fixes:

 - Explicitly declare inc_group_count as a void function (Colin Ian King)

Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 00966852 58ecd33b
Loading
Loading
Loading
Loading
+8 −0
Original line number Original line Diff line number Diff line
@@ -69,6 +69,14 @@ report::
--scale::
--scale::
	scale/normalize counter values
	scale/normalize counter values


-d::
--detailed::
	print more detailed statistics, can be specified up to 3 times

	   -d:          detailed events, L1 and LLC data cache
        -d -d:     more detailed events, dTLB and iTLB events
     -d -d -d:     very detailed events, adding prefetch events

-r::
-r::
--repeat=<n>::
--repeat=<n>::
	repeat command and print average + stddev (max: 100). 0 means forever.
	repeat command and print average + stddev (max: 100). 0 means forever.
+1 −1
Original line number Original line Diff line number Diff line
@@ -59,7 +59,7 @@ static u64 mmap_read_self(void *addr)
		u64 quot, rem;
		u64 quot, rem;


		quot = (cyc >> time_shift);
		quot = (cyc >> time_shift);
		rem = cyc & ((1 << time_shift) - 1);
		rem = cyc & (((u64)1 << time_shift) - 1);
		delta = time_offset + quot * time_mult +
		delta = time_offset + quot * time_mult +
			((rem * time_mult) >> time_shift);
			((rem * time_mult) >> time_shift);


+20 −32
Original line number Original line Diff line number Diff line
@@ -253,12 +253,16 @@ static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
{
{
	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
	u64 n = 0;
	u64 n = 0;
	int ret;


	/*
	/*
	 * if jit marker, then inject jit mmaps and generate ELF images
	 * if jit marker, then inject jit mmaps and generate ELF images
	 */
	 */
	if (!jit_process(inject->session, &inject->output, machine,
	ret = jit_process(inject->session, &inject->output, machine,
			 event->mmap.filename, sample->pid, &n)) {
			  event->mmap.filename, sample->pid, &n);
	if (ret < 0)
		return ret;
	if (ret) {
		inject->bytes_written += n;
		inject->bytes_written += n;
		return 0;
		return 0;
	}
	}
@@ -287,12 +291,16 @@ static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
{
{
	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
	u64 n = 0;
	u64 n = 0;
	int ret;


	/*
	/*
	 * if jit marker, then inject jit mmaps and generate ELF images
	 * if jit marker, then inject jit mmaps and generate ELF images
	 */
	 */
	if (!jit_process(inject->session, &inject->output, machine,
	ret = jit_process(inject->session, &inject->output, machine,
			  event->mmap2.filename, sample->pid, &n)) {
			  event->mmap2.filename, sample->pid, &n);
	if (ret < 0)
		return ret;
	if (ret) {
		inject->bytes_written += n;
		inject->bytes_written += n;
		return 0;
		return 0;
	}
	}
@@ -679,12 +687,16 @@ static int __cmd_inject(struct perf_inject *inject)
	ret = perf_session__process_events(session);
	ret = perf_session__process_events(session);


	if (!file_out->is_pipe) {
	if (!file_out->is_pipe) {
		if (inject->build_ids) {
		if (inject->build_ids)
			perf_header__set_feat(&session->header,
			perf_header__set_feat(&session->header,
					      HEADER_BUILD_ID);
					      HEADER_BUILD_ID);
			if (inject->have_auxtrace)
		/*
		 * Keep all buildids when there is unprocessed AUX data because
		 * it is not known which ones the AUX trace hits.
		 */
		if (perf_header__has_feat(&session->header, HEADER_BUILD_ID) &&
		    inject->have_auxtrace && !inject->itrace_synth_opts.set)
			dsos__hit_all(session);
			dsos__hit_all(session);
		}
		/*
		/*
		 * The AUX areas have been removed and replaced with
		 * The AUX areas have been removed and replaced with
		 * synthesized hardware events, so clear the feature flag and
		 * synthesized hardware events, so clear the feature flag and
@@ -717,23 +729,6 @@ static int __cmd_inject(struct perf_inject *inject)
	return ret;
	return ret;
}
}


#ifdef HAVE_LIBELF_SUPPORT
static int
jit_validate_events(struct perf_session *session)
{
	struct perf_evsel *evsel;

	/*
	 * check that all events use CLOCK_MONOTONIC
	 */
	evlist__for_each(session->evlist, evsel) {
		if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC)
			return -1;
	}
	return 0;
}
#endif

int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
{
{
	struct perf_inject inject = {
	struct perf_inject inject = {
@@ -840,13 +835,6 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
	}
	}
#ifdef HAVE_LIBELF_SUPPORT
#ifdef HAVE_LIBELF_SUPPORT
	if (inject.jit_mode) {
	if (inject.jit_mode) {
		/*
		 * validate event is using the correct clockid
		 */
		if (jit_validate_events(inject.session)) {
			fprintf(stderr, "error, jitted code must be sampled with perf record -k 1\n");
			return -1;
		}
		inject.tool.mmap2	   = perf_event__jit_repipe_mmap2;
		inject.tool.mmap2	   = perf_event__jit_repipe_mmap2;
		inject.tool.mmap	   = perf_event__jit_repipe_mmap;
		inject.tool.mmap	   = perf_event__jit_repipe_mmap;
		inject.tool.ordered_events = true;
		inject.tool.ordered_events = true;
+79 −68
Original line number Original line Diff line number Diff line
@@ -1280,7 +1280,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
					      struct hist_entry *entry,
					      struct hist_entry *entry,
					      unsigned short row,
					      unsigned short row,
					      int level, int nr_sort_keys)
					      int level)
{
{
	int printed = 0;
	int printed = 0;
	int width = browser->b.width;
	int width = browser->b.width;
@@ -1289,12 +1289,13 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
	off_t row_offset = entry->row_offset;
	off_t row_offset = entry->row_offset;
	bool first = true;
	bool first = true;
	struct perf_hpp_fmt *fmt;
	struct perf_hpp_fmt *fmt;
	struct perf_hpp_list_node *fmt_node;
	struct hpp_arg arg = {
	struct hpp_arg arg = {
		.b		= &browser->b,
		.b		= &browser->b,
		.current_entry	= current_entry,
		.current_entry	= current_entry,
	};
	};
	int column = 0;
	int column = 0;
	int hierarchy_indent = (nr_sort_keys - 1) * HIERARCHY_INDENT;
	int hierarchy_indent = (entry->hists->nr_hpp_node - 2) * HIERARCHY_INDENT;


	if (current_entry) {
	if (current_entry) {
		browser->he_selection = entry;
		browser->he_selection = entry;
@@ -1320,7 +1321,10 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
	ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
	ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
	width -= level * HIERARCHY_INDENT;
	width -= level * HIERARCHY_INDENT;


	hists__for_each_format(entry->hists, fmt) {
	/* the first hpp_list_node is for overhead columns */
	fmt_node = list_first_entry(&entry->hists->hpp_formats,
				    struct perf_hpp_list_node, list);
	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
		char s[2048];
		char s[2048];
		struct perf_hpp hpp = {
		struct perf_hpp hpp = {
			.buf		= s,
			.buf		= s,
@@ -1332,10 +1336,6 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
		    column++ < browser->b.horiz_scroll)
		    column++ < browser->b.horiz_scroll)
			continue;
			continue;


		if (perf_hpp__is_sort_entry(fmt) ||
		    perf_hpp__is_dynamic_entry(fmt))
			break;

		if (current_entry && browser->b.navkeypressed) {
		if (current_entry && browser->b.navkeypressed) {
			ui_browser__set_color(&browser->b,
			ui_browser__set_color(&browser->b,
					      HE_COLORSET_SELECTED);
					      HE_COLORSET_SELECTED);
@@ -1388,6 +1388,7 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
					      HE_COLORSET_NORMAL);
					      HE_COLORSET_NORMAL);
		}
		}


		perf_hpp_list__for_each_format(entry->hpp_list, fmt) {
			ui_browser__write_nstring(&browser->b, "", 2);
			ui_browser__write_nstring(&browser->b, "", 2);
			width -= 2;
			width -= 2;


@@ -1396,7 +1397,6 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
			 * since this fmt is always the last column in the
			 * since this fmt is always the last column in the
			 * hierarchy mode.
			 * hierarchy mode.
			 */
			 */
		fmt = entry->fmt;
			if (fmt->color) {
			if (fmt->color) {
				width -= fmt->color(fmt, &hpp, entry);
				width -= fmt->color(fmt, &hpp, entry);
			} else {
			} else {
@@ -1409,6 +1409,7 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
					width++;
					width++;
			}
			}
		}
		}
	}


	/* The scroll bar isn't being used */
	/* The scroll bar isn't being used */
	if (!browser->b.navkeypressed)
	if (!browser->b.navkeypressed)
@@ -1435,8 +1436,7 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
}
}


static int hist_browser__show_no_entry(struct hist_browser *browser,
static int hist_browser__show_no_entry(struct hist_browser *browser,
				       unsigned short row,
				       unsigned short row, int level)
				       int level, int nr_sort_keys)
{
{
	int width = browser->b.width;
	int width = browser->b.width;
	bool current_entry = ui_browser__is_current_entry(&browser->b, row);
	bool current_entry = ui_browser__is_current_entry(&browser->b, row);
@@ -1444,6 +1444,8 @@ static int hist_browser__show_no_entry(struct hist_browser *browser,
	int column = 0;
	int column = 0;
	int ret;
	int ret;
	struct perf_hpp_fmt *fmt;
	struct perf_hpp_fmt *fmt;
	struct perf_hpp_list_node *fmt_node;
	int indent = browser->hists->nr_hpp_node - 2;


	if (current_entry) {
	if (current_entry) {
		browser->he_selection = NULL;
		browser->he_selection = NULL;
@@ -1460,15 +1462,14 @@ static int hist_browser__show_no_entry(struct hist_browser *browser,
	ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
	ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
	width -= level * HIERARCHY_INDENT;
	width -= level * HIERARCHY_INDENT;


	hists__for_each_format(browser->hists, fmt) {
	/* the first hpp_list_node is for overhead columns */
	fmt_node = list_first_entry(&browser->hists->hpp_formats,
				    struct perf_hpp_list_node, list);
	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
		if (perf_hpp__should_skip(fmt, browser->hists) ||
		if (perf_hpp__should_skip(fmt, browser->hists) ||
		    column++ < browser->b.horiz_scroll)
		    column++ < browser->b.horiz_scroll)
			continue;
			continue;


		if (perf_hpp__is_sort_entry(fmt) ||
		    perf_hpp__is_dynamic_entry(fmt))
			break;

		ret = fmt->width(fmt, NULL, hists_to_evsel(browser->hists));
		ret = fmt->width(fmt, NULL, hists_to_evsel(browser->hists));


		if (first) {
		if (first) {
@@ -1484,8 +1485,8 @@ static int hist_browser__show_no_entry(struct hist_browser *browser,
		width -= ret;
		width -= ret;
	}
	}


	ui_browser__write_nstring(&browser->b, "", nr_sort_keys * HIERARCHY_INDENT);
	ui_browser__write_nstring(&browser->b, "", indent * HIERARCHY_INDENT);
	width -= nr_sort_keys * HIERARCHY_INDENT;
	width -= indent * HIERARCHY_INDENT;


	if (column >= browser->b.horiz_scroll) {
	if (column >= browser->b.horiz_scroll) {
		char buf[32];
		char buf[32];
@@ -1550,22 +1551,23 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
		.size   = size,
		.size   = size,
	};
	};
	struct perf_hpp_fmt *fmt;
	struct perf_hpp_fmt *fmt;
	struct perf_hpp_list_node *fmt_node;
	size_t ret = 0;
	size_t ret = 0;
	int column = 0;
	int column = 0;
	int nr_sort_keys = hists->nr_sort_keys;
	int indent = hists->nr_hpp_node - 2;
	bool first = true;
	bool first_node, first_col;


	ret = scnprintf(buf, size, " ");
	ret = scnprintf(buf, size, " ");
	if (advance_hpp_check(&dummy_hpp, ret))
	if (advance_hpp_check(&dummy_hpp, ret))
		return ret;
		return ret;


	hists__for_each_format(hists, fmt) {
	/* the first hpp_list_node is for overhead columns */
	fmt_node = list_first_entry(&hists->hpp_formats,
				    struct perf_hpp_list_node, list);
	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
		if (column++ < browser->b.horiz_scroll)
		if (column++ < browser->b.horiz_scroll)
			continue;
			continue;


		if (perf_hpp__is_sort_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
			break;

		ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
		ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
		if (advance_hpp_check(&dummy_hpp, ret))
		if (advance_hpp_check(&dummy_hpp, ret))
			break;
			break;
@@ -1576,25 +1578,32 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
	}
	}


	ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
	ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "%*s",
			(nr_sort_keys - 1) * HIERARCHY_INDENT, "");
			indent * HIERARCHY_INDENT, "");
	if (advance_hpp_check(&dummy_hpp, ret))
	if (advance_hpp_check(&dummy_hpp, ret))
		return ret;
		return ret;


	hists__for_each_format(hists, fmt) {
	first_node = true;
	list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
		if (!first_node) {
			ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
			if (advance_hpp_check(&dummy_hpp, ret))
				break;
		}
		first_node = false;

		first_col = true;
		perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
			char *start;
			char *start;


		if (!perf_hpp__is_sort_entry(fmt) && !perf_hpp__is_dynamic_entry(fmt))
			continue;
			if (perf_hpp__should_skip(fmt, hists))
			if (perf_hpp__should_skip(fmt, hists))
				continue;
				continue;


		if (first) {
			if (!first_col) {
			first = false;
				ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, "+");
		} else {
			ret = scnprintf(dummy_hpp.buf, dummy_hpp.size, " / ");
				if (advance_hpp_check(&dummy_hpp, ret))
				if (advance_hpp_check(&dummy_hpp, ret))
					break;
					break;
			}
			}
			first_col = false;


			ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
			ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
			dummy_hpp.buf[ret] = '\0';
			dummy_hpp.buf[ret] = '\0';
@@ -1609,6 +1618,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
			if (advance_hpp_check(&dummy_hpp, ret))
			if (advance_hpp_check(&dummy_hpp, ret))
				break;
				break;
		}
		}
	}


	return ret;
	return ret;
}
}
@@ -1644,7 +1654,6 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
	u16 header_offset = 0;
	u16 header_offset = 0;
	struct rb_node *nd;
	struct rb_node *nd;
	struct hist_browser *hb = container_of(browser, struct hist_browser, b);
	struct hist_browser *hb = container_of(browser, struct hist_browser, b);
	int nr_sort = hb->hists->nr_sort_keys;


	if (hb->show_headers) {
	if (hb->show_headers) {
		hist_browser__show_headers(hb);
		hist_browser__show_headers(hb);
@@ -1671,14 +1680,12 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)


		if (symbol_conf.report_hierarchy) {
		if (symbol_conf.report_hierarchy) {
			row += hist_browser__show_hierarchy_entry(hb, h, row,
			row += hist_browser__show_hierarchy_entry(hb, h, row,
								  h->depth,
								  h->depth);
								  nr_sort);
			if (row == browser->rows)
			if (row == browser->rows)
				break;
				break;


			if (h->has_no_entry) {
			if (h->has_no_entry) {
				hist_browser__show_no_entry(hb, row, h->depth,
				hist_browser__show_no_entry(hb, row, h->depth + 1);
							    nr_sort);
				row++;
				row++;
			}
			}
		} else {
		} else {
@@ -1934,7 +1941,7 @@ static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
	struct perf_hpp_fmt *fmt;
	struct perf_hpp_fmt *fmt;
	bool first = true;
	bool first = true;
	int ret;
	int ret;
	int hierarchy_indent = (nr_sort_keys + 1) * HIERARCHY_INDENT;
	int hierarchy_indent = nr_sort_keys * HIERARCHY_INDENT;


	printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");
	printed = fprintf(fp, "%*s", level * HIERARCHY_INDENT, "");


@@ -1962,9 +1969,13 @@ static int hist_browser__fprintf_hierarchy_entry(struct hist_browser *browser,
	ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
	ret = scnprintf(hpp.buf, hpp.size, "%*s", hierarchy_indent, "");
	advance_hpp(&hpp, ret);
	advance_hpp(&hpp, ret);


	fmt = he->fmt;
	perf_hpp_list__for_each_format(he->hpp_list, fmt) {
		ret = scnprintf(hpp.buf, hpp.size, "  ");
		advance_hpp(&hpp, ret);

		ret = fmt->entry(fmt, &hpp, he);
		ret = fmt->entry(fmt, &hpp, he);
		advance_hpp(&hpp, ret);
		advance_hpp(&hpp, ret);
	}


	printed += fprintf(fp, "%s\n", rtrim(s));
	printed += fprintf(fp, "%s\n", rtrim(s));


+46 −27
Original line number Original line Diff line number Diff line
@@ -407,11 +407,14 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists,
	struct rb_node *node;
	struct rb_node *node;
	struct hist_entry *he;
	struct hist_entry *he;
	struct perf_hpp_fmt *fmt;
	struct perf_hpp_fmt *fmt;
	struct perf_hpp_list_node *fmt_node;
	u64 total = hists__total_period(hists);
	u64 total = hists__total_period(hists);
	int size;


	for (node = rb_first(root); node; node = rb_next(node)) {
	for (node = rb_first(root); node; node = rb_next(node)) {
		GtkTreeIter iter;
		GtkTreeIter iter;
		float percent;
		float percent;
		char *bf;


		he = rb_entry(node, struct hist_entry, rb_node);
		he = rb_entry(node, struct hist_entry, rb_node);
		if (he->filtered)
		if (he->filtered)
@@ -424,11 +427,11 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists,
		gtk_tree_store_append(store, &iter, parent);
		gtk_tree_store_append(store, &iter, parent);


		col_idx = 0;
		col_idx = 0;
		hists__for_each_format(hists, fmt) {
			if (perf_hpp__is_sort_entry(fmt) ||
			    perf_hpp__is_dynamic_entry(fmt))
				break;


		/* the first hpp_list_node is for overhead columns */
		fmt_node = list_first_entry(&hists->hpp_formats,
					    struct perf_hpp_list_node, list);
		perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
			if (fmt->color)
			if (fmt->color)
				fmt->color(fmt, hpp, he);
				fmt->color(fmt, hpp, he);
			else
			else
@@ -437,15 +440,26 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists,
			gtk_tree_store_set(store, &iter, col_idx++, hpp->buf, -1);
			gtk_tree_store_set(store, &iter, col_idx++, hpp->buf, -1);
		}
		}


		fmt = he->fmt;
		bf = hpp->buf;
		size = hpp->size;
		perf_hpp_list__for_each_format(he->hpp_list, fmt) {
			int ret;

			if (fmt->color)
			if (fmt->color)
			fmt->color(fmt, hpp, he);
				ret = fmt->color(fmt, hpp, he);
			else
			else
			fmt->entry(fmt, hpp, he);
				ret = fmt->entry(fmt, hpp, he);

			snprintf(hpp->buf + ret, hpp->size - ret, "  ");
			advance_hpp(hpp, ret + 2);
		}


		gtk_tree_store_set(store, &iter, col_idx, rtrim(hpp->buf), -1);
		gtk_tree_store_set(store, &iter, col_idx, ltrim(rtrim(bf)), -1);


		if (!he->leaf) {
		if (!he->leaf) {
			hpp->buf = bf;
			hpp->size = size;

			perf_gtk__add_hierarchy_entries(hists, &he->hroot_out,
			perf_gtk__add_hierarchy_entries(hists, &he->hroot_out,
							store, &iter, hpp,
							store, &iter, hpp,
							min_pcnt);
							min_pcnt);
@@ -478,6 +492,7 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
				     float min_pcnt)
				     float min_pcnt)
{
{
	struct perf_hpp_fmt *fmt;
	struct perf_hpp_fmt *fmt;
	struct perf_hpp_list_node *fmt_node;
	GType col_types[MAX_COLUMNS];
	GType col_types[MAX_COLUMNS];
	GtkCellRenderer *renderer;
	GtkCellRenderer *renderer;
	GtkTreeStore *store;
	GtkTreeStore *store;
@@ -486,7 +501,7 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
	int nr_cols = 0;
	int nr_cols = 0;
	char s[512];
	char s[512];
	char buf[512];
	char buf[512];
	bool first = true;
	bool first_node, first_col;
	struct perf_hpp hpp = {
	struct perf_hpp hpp = {
		.buf		= s,
		.buf		= s,
		.size		= sizeof(s),
		.size		= sizeof(s),
@@ -506,11 +521,11 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,
	renderer = gtk_cell_renderer_text_new();
	renderer = gtk_cell_renderer_text_new();


	col_idx = 0;
	col_idx = 0;
	hists__for_each_format(hists, fmt) {
		if (perf_hpp__is_sort_entry(fmt) ||
		    perf_hpp__is_dynamic_entry(fmt))
			break;


	/* the first hpp_list_node is for overhead columns */
	fmt_node = list_first_entry(&hists->hpp_formats,
				    struct perf_hpp_list_node, list);
	perf_hpp_list__for_each_format(&fmt_node->hpp, fmt) {
		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
							    -1, fmt->name,
							    -1, fmt->name,
							    renderer, "markup",
							    renderer, "markup",
@@ -519,20 +534,24 @@ static void perf_gtk__show_hierarchy(GtkWidget *window, struct hists *hists,


	/* construct merged column header since sort keys share single column */
	/* construct merged column header since sort keys share single column */
	buf[0] = '\0';
	buf[0] = '\0';
	hists__for_each_format(hists ,fmt) {
	first_node = true;
		if (!perf_hpp__is_sort_entry(fmt) &&
	list_for_each_entry_continue(fmt_node, &hists->hpp_formats, list) {
		    !perf_hpp__is_dynamic_entry(fmt))
		if (!first_node)
			continue;
			strcat(buf, " / ");
		first_node = false;

		first_col = true;
		perf_hpp_list__for_each_format(&fmt_node->hpp ,fmt) {
			if (perf_hpp__should_skip(fmt, hists))
			if (perf_hpp__should_skip(fmt, hists))
				continue;
				continue;


		if (first)
			if (!first_col)
			first = false;
				strcat(buf, "+");
		else
			first_col = false;
			strcat(buf, " / ");


			fmt->header(fmt, &hpp, hists_to_evsel(hists));
			fmt->header(fmt, &hpp, hists_to_evsel(hists));
		strcat(buf, rtrim(hpp.buf));
			strcat(buf, ltrim(rtrim(hpp.buf)));
		}
	}
	}


	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
	gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
Loading