From: Don Zickus <dzickus@redhat.com>
To: acme@kernel.org, namhyung@kernel.org, jolsa@redhat.com
Cc: eranian@google.com, Andi Kleen <andi@firstfloor.org>,
LKML <linux-kernel@vger.kernel.org>,
Don Zickus <dzickus@redhat.com>
Subject: [RFC 5/5] perf: Enable multiple hist_entry_group output
Date: Thu, 10 Apr 2014 16:11:01 -0400 [thread overview]
Message-ID: <1397160661-33395-6-git-send-email-dzickus@redhat.com> (raw)
In-Reply-To: <1397160661-33395-1-git-send-email-dzickus@redhat.com>
Enable multiple hist_entry_group groups in the output based on a sort
method.
Currently only 'perf report' is hooked in with '--group-sort='. The choices
are cpu, pid, and cacheline. Only --stdio works right now. I haven't figured
out how the other outputs work.
Sample output from 'perf mem record -a grep -r foo /* > /dev/null'
(normal) perf mem report --percent-limit=1.0 --stdio
Overhead Samples
Local Weight Memory access Symbol
........ ............ ............ ........................ ........................
4.13% 1 1759 Uncached hit [k] ahci_scr_read
1.16% 1 492 L1 hit [k] _raw_read_lock
(cpu groups) perf mem report --group-sort=cpu --percent-limit=1.0 --stdio
Overhead Samples CPU
Local Weight Memory access Symbol
........ ............ ............ ........................ ........................
28.80% 1239 25
3.07% 377 L1 hit [k] complete_walk
2.76% 339 LFB hit [k] update_cfs_shares
2.66% 326 LFB hit [k] copy_user_enhanced_f
2.11% 259 Local RAM hit [k] copy_user_enhanced_f
1.84% 226 LFB hit [k] copy_user_enhanced_f
1.74% 213 LFB hit [k] copy_user_enhanced_f
1.53% 187 LFB hit [k] copy_user_enhanced_f
1.04% 128 LFB hit [k] copy_user_enhanced_f
1.01% 124 LFB hit [k] copy_user_enhanced_f
27.44% 990 7
15.06% 1759 Uncached hit [k] ahci_scr_read
4.21% 492 L1 hit [k] _raw_read_lock
1.04% 122 LFB hit [k] find_busiest_group
1.02% 1 7 L1 hit [.] __gconv_transform_ut
20.34% 1010 0
4.04% 5 7 L1 hit [k] poll_idle
3.56% 308 Local RAM hit [k] copy_user_enhanced_f
2.59% 224 L3 hit [k] copy_user_enhanced_f
2.12% 184 Local RAM hit [k] copy_user_enhanced_f
1.54% 1 7 L1 hit [.] __gconv_transform_ut
(pid groups) perf mem report --group-sort=pid --percent-limit=1.0 --stdio
Overhead Samples Command: Pid
Local Weight Memory access Symbol
........ ............ ............ ........................ ........................
67.98% 3023 grep:77842
1.70% 492 L1 hit [k] _raw_read_lock
1.30% 377 L1 hit [k] complete_walk
1.17% 339 LFB hit [k] update_cfs_shares
1.13% 326 LFB hit [k] copy_user_enhanced_f
1.09% 4 7 L1 hit [.] __gconv_transform_ut
1.06% 308 Local RAM hit [k] copy_user_enhanced_f
23.39% 660 swapper: 0
17.66% 1759 Uncached hit [k] ahci_scr_read
4.17% 415 L1 hit [k] handle_irq
3.51% 5 7 L1 hit [k] poll_idle
3.34% 333 Remote Cache (1 hop) hit [k] update_cfs_rq_blocke
2.79% 278 LFB hit [k] add_interrupt_random
2.69% 268 L1 hit [k] update_cpu_load_nohz
2.69% 268 Local RAM hit [k] find_busiest_group
2.51% 250 LFB hit [k] ktime_get
2.45% 244 L1 hit [k] rcu_eqs_exit_common.
1.89% 188 LFB hit [k] ktime_get
1.25% 124 LFB hit [k] get_next_timer_inter
5.90% 186 rcu_sched: 8
6.14% 154 L1 hit [k] _raw_spin_lock_irq
4.42% 111 L1 hit [k] _raw_spin_lock_irqsa
3.90% 49 L3 hit [k] find_busiest_group
3.11% 78 LFB hit [k] find_busiest_group
3.11% 78 LFB hit [k] find_busiest_group
2.39% 60 LFB hit [k] idle_cpu
2.27% 57 L3 hit [k] idle_cpu
2.27% 57 L3 hit [k] idle_cpu
2.19% 55 L3 hit [k] target_load
(cacheline groups) perf mem report --group-sort=cacheline --percent-limit=1.0 --stdio
Overhead Samples Cacheline
Local Weight Memory access Symbol
........ ............ ............ ........................ ........................
4.67% 284 [.] 0x0000000000b030c0
1.76% 7 L1 hit [.] 0x0000000000008651
1.41% 7 L1 hit [.] 0x00000000000085cc
1.41% 7 L1 hit [.] 0x00000000000085e4
1.41% 7 L1 hit [.] 0x00000000000085e4
1.41% 7 L1 hit [.] 0x00000000000085f8
1.41% 7 L1 hit [.] 0x0000000000008624
1.06% 7 L1 hit [.] 0x00000000000085d8
1.06% 7 L1 hit [.] 0x00000000000085e4
1.06% 7 L1 hit [.] 0x00000000000085e4
1.06% 7 L1 hit [.] 0x0000000000008610
1.06% 7 L1 hit [.] 0x0000000000008610
1.06% 7 L1 hit [.] 0x0000000000008624
1.06% 7 L1 hit [.] 0x0000000000008624
1.06% 7 L1 hit [.] 0x0000000000008645
1.06% 7 L1 hit [.] 0x0000000000008645
1.06% 7 L1 hit [.] 0x0000000000008645
1.06% 7 L1 hit [.] 0x0000000000008651
1.06% 7 L1 hit [.] 0x0000000000008651
4.26% 250 [.] 0x0000000000b03080
3.91% 71 L3 hit [.] 0x0000000000008651
1.54% 7 L1 hit [.] 0x00000000000085d8
1.16% 7 L1 hit [.] 0x00000000000085cc
1.16% 7 L1 hit [.] 0x00000000000085f8
1.16% 7 L1 hit [.] 0x0000000000008604
1.16% 7 L1 hit [.] 0x0000000000008624
1.16% 7 L1 hit [.] 0x0000000000008645
1.16% 7 L1 hit [.] 0x0000000000008645
1.16% 7 L1 hit [.] 0x0000000000008645
4.13% 1 [k] 0xffffc90000062180
100.00% 1759 Uncached hit [k] ahci_scr_read
3.44% 209 [.] 0x0000000000b03040
6.70% 1 7 L1 hit [.] 0x00000000000085e4
6.22% 1 7 L1 hit [.] 0x0000000000008624
5.74% 1 7 L1 hit [.] 0x00000000000085cc
5.74% 1 7 L1 hit [.] 0x0000000000008610
5.74% 1 7 L1 hit [.] 0x0000000000008645
5.26% 1 7 L1 hit [.] 0x00000000000085d8
5.26% 1 7 L1 hit [.] 0x0000000000008651
4.78% 1 7 L1 hit [.] 0x00000000000085f8
4.78% 1 7 L1 hit [.] 0x0000000000008604
2.87% 7 L1 hit [.] 0x0000000000008630
1.44% 7 L1 hit [.] 0x00000000000085f8
Signed-off-by: Don Zickus <dzickus@redhat.com>
---
tools/perf/builtin-report.c | 2 +
tools/perf/ui/gtk/hists.c | 10 +++
tools/perf/ui/hist.c | 19 +++++
tools/perf/ui/stdio/hist.c | 69 ++++++++++++++++-
tools/perf/util/hist.c | 17 +++++
tools/perf/util/hist.h | 3 +
tools/perf/util/sort.c | 181 +++++++++++++++++++++++++++++++++++++++++++-
tools/perf/util/sort.h | 4 +
8 files changed, 301 insertions(+), 4 deletions(-)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 51a37d6..010271e 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -764,6 +764,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
" dso_to, dso_from, symbol_to, symbol_from, mispredict,"
" weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, "
"snoop, locked, abort, in_tx, transaction"),
+ OPT_STRING(0, "group-sort", &group_sort_order, "key[,key2...]",
+ "group sort by key(s): pid, cacheline"),
OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
"Show sample percentage for different cpu modes"),
OPT_STRING('p', "parent", &parent_pattern, "regex",
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index befbf3b..ab9c96a 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -200,6 +200,16 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx++, NULL);
}
+ list_for_each_entry(se, &hist_group__sort_list, list) {
+ if (se->elide)
+ continue;
+
+ gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+ -1, se->se_header,
+ renderer, "text",
+ col_idx++, NULL);
+ }
+
list_for_each_entry(se, &hist_entry__sort_list, list) {
if (se->elide)
continue;
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 21c4e5c..31c74b3 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -319,6 +319,25 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
return ret;
}
+int hist_entry_group__sort_snprintf(struct hist_entry *he, char *s, size_t size,
+ struct hists *hists)
+{
+ const char *sep = symbol_conf.field_sep;
+ struct sort_entry *se;
+ int ret = 0;
+
+ list_for_each_entry(se, &hist_group__sort_list, list) {
+ if (se->elide)
+ continue;
+
+ ret += scnprintf(s + ret, size - ret, "%s", sep ?: " ");
+ ret += se->se_snprintf(he, s + ret, size - ret,
+ hists__col_len(hists, se->se_width_idx));
+ }
+
+ return ret;
+}
+
/*
* See hists__fprintf to match the column widths
*/
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 6c1a85a..c3d3c1b 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -354,6 +354,10 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
if (size == 0 || size > bfsz)
size = hpp.size = bfsz;
+ if (sort__has_group) {
+ *hpp.buf++ = '\t';
+ hpp.size--;
+ }
ret = hist_entry__period_snprintf(&hpp, he);
hist_entry__sort_snprintf(he, bf + ret, size - ret, hists);
@@ -365,6 +369,28 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
return ret;
}
+static int hist_entry_group__fprintf(struct hist_entry *he, size_t size,
+ struct hists *hists,
+ char *bf, size_t bfsz, FILE *fp)
+{
+ int ret;
+ struct perf_hpp hpp = {
+ .buf = bf,
+ .size = size,
+ .total_period = he->groups->hists->stats.total_period,
+ };
+
+ if (size == 0 || size > bfsz)
+ size = hpp.size = bfsz;
+
+ ret = hist_entry__period_snprintf(&hpp, he);
+ hist_entry_group__sort_snprintf(he, bf + ret, size - ret, hists);
+
+ ret = fprintf(fp, "%s\n", bf);
+
+ return ret;
+}
+
size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
int max_cols, float min_pcnt, FILE *fp)
{
@@ -403,6 +429,32 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
fprintf(fp, "%s", bf);
}
+ list_for_each_entry(se, &hist_group__sort_list, list) {
+ if (se->elide)
+ continue;
+ if (sep) {
+ fprintf(fp, "%c%s", *sep, se->se_header);
+ continue;
+ }
+ width = strlen(se->se_header);
+ if (symbol_conf.col_width_list_str) {
+ if (col_width) {
+ hists__set_col_len(hists, se->se_width_idx,
+ atoi(col_width));
+ col_width = strchr(col_width, ',');
+ if (col_width)
+ ++col_width;
+ }
+ }
+ if (!hists__new_col_len(hists, se->se_width_idx, width))
+ width = hists__col_len(hists, se->se_width_idx);
+ fprintf(fp, " %*s", width, se->se_header);
+ }
+
+ fprintf(fp, "\n");
+ if (max_rows && ++nr_rows >= max_rows)
+ goto out;
+
list_for_each_entry(se, &hist_entry__sort_list, list) {
if (se->elide)
continue;
@@ -481,9 +533,22 @@ print_entries:
}
hist__for_each_group_out(g, hists) {
- hist_group__for_each_entry_out(h, g) {
+ float percent = g->entry.stat.period * 100.0 /
+ hists->stats.total_period;
+
+ if (percent < min_pcnt)
+ continue;
- float percent = h->stat.period * 100.0 /
+ if (sort__has_group) {
+ ret += hist_entry_group__fprintf(&g->entry, max_cols, hists,
+ line, linesz, fp);
+
+ if (max_rows && ++nr_rows >= max_rows)
+ break;
+ }
+
+ hist_group__for_each_entry_out(h, g) {
+ percent = h->stat.period * 100.0 /
g->entry.stat.period;
if (h->filtered)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 32cdc7a..f9735c4 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -786,6 +786,12 @@ out:
return ret;
}
+static int hist_entry_group__sort_on_period(struct hist_entry_group *a,
+ struct hist_entry_group *b)
+{
+ return period_cmp(a->entry.stat.period, b->entry.stat.period);
+}
+
static void __hists__insert_output_entry(struct rb_root *entries,
struct hist_entry *he,
u64 min_callchain_hits)
@@ -818,6 +824,17 @@ static void __hists__insert_output_entry_group(struct rb_root *groups,
{
struct rb_node **p = &groups->rb_node;
struct rb_node *parent = NULL;
+ struct hist_entry_group *iter;
+
+ while (*p != NULL) {
+ parent = *p;
+ iter = rb_entry(parent, struct hist_entry_group, rb_node);
+
+ if (hist_entry_group__sort_on_period(hg, iter) > 0)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
rb_link_node(&hg->rb_node, parent, p);
rb_insert_color(&hg->rb_node, groups);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 1155397..75a041c 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -71,6 +71,7 @@ enum hist_column {
HISTC_MEM_TLB,
HISTC_MEM_LVL,
HISTC_MEM_SNOOP,
+ HISTC_MEM_CACHELINE,
HISTC_TRANSACTION,
HISTC_NR_COLS, /* Last entry */
};
@@ -106,6 +107,8 @@ int64_t hist_group__collapse(struct hist_entry *left, struct hist_entry *right);
int hist_entry__transaction_len(void);
int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size,
struct hists *hists);
+int hist_entry_group__sort_snprintf(struct hist_entry *he, char *bf, size_t size,
+ struct hists *hists);
void hist_entry__free(struct hist_entry *);
void hists__output_resort(struct hists *hists);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index c292c78..bfb4a668 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -8,6 +8,8 @@ const char default_parent_pattern[] = "^sys_|^do_page_fault";
const char *parent_pattern = default_parent_pattern;
const char default_sort_order[] = "comm,dso,symbol";
const char *sort_order = default_sort_order;
+const char default_group_sort_order[] = "";
+const char *group_sort_order = default_group_sort_order;
regex_t ignore_callees_regex;
int have_ignore_callees = 0;
int sort__need_collapse = 0;
@@ -61,7 +63,7 @@ static int64_t cmp_null(const void *l, const void *r)
static int64_t
sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
{
- return right->thread->tid - left->thread->tid;
+ return right->thread->pid_ - left->thread->pid_;
}
static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
@@ -809,6 +811,94 @@ static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
}
+#define L1_CACHE_BYTES 64
+#define CACHELINE_MASK (L1_CACHE_BYTES - 1)
+#define CL(x) (x & ~CACHELINE_MASK)
+
+static int64_t
+sort__cacheline_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ u64 l, r;
+ struct map *l_map = left->mem_info->daddr.map;
+ struct map *r_map = right->mem_info->daddr.map;
+
+ /* store all NULL mem maps at the bottom */
+ /* shouldn't even need this check, should have stubs */
+ if (!left->mem_info->daddr.map || !right->mem_info->daddr.map)
+ return 1;
+
+ /* group event types together */
+ if (left->cpumode > right->cpumode) return -1;
+ if (left->cpumode < right->cpumode) return 1;
+
+ /*
+ * Addresses with no major/minor numbers are assumed to be
+ * anonymous in userspace. Sort those on pid then address.
+ *
+ * The kernel and non-zero major/minor mapped areas are
+ * assumed to be unity mapped. Sort those on address then pid.
+ */
+
+ if ((l_map->maj || l_map->min || l_map->ino || l_map-> ino_generation)) {
+ /* mmapped areas */
+
+ if (l_map->maj > r_map->maj) return -1;
+ if (l_map->maj < r_map->maj) return 1;
+
+ if (l_map->min > r_map->min) return -1;
+ if (l_map->min < r_map->min) return 1;
+
+ if (l_map->ino > r_map->ino) return -1;
+ if (l_map->ino < r_map->ino) return 1;
+
+ if (l_map->ino_generation > r_map->ino_generation) return -1;
+ if (l_map->ino_generation < r_map->ino_generation) return 1;
+
+ } else if (left->cpumode != PERF_RECORD_MISC_KERNEL) {
+ /* userspace anonymous */
+ if (left->thread->pid_ > right->thread->pid_) return -1;
+ if (left->thread->pid_ < right->thread->pid_) return 1;
+ }
+
+ /* al_addr does all the right addr - start + offset calculations */
+ l = left->mem_info->daddr.al_addr;
+ r = right->mem_info->daddr.al_addr;
+
+ if (CL(l) > CL(r)) return -1;
+ if (CL(l) < CL(r)) return 1;
+
+ /* sanity check the maps; only mmaped areas should have different maps */
+ if ((left->mem_info->daddr.map != right->mem_info->daddr.map) &&
+ !right->mem_info->daddr.map->maj && !right->mem_info->daddr.map->min)
+ pr_debug("mem_cacheline_cmp: Similar entries have different maps\n");
+
+ return 0;
+}
+
+static int hist_entry__cacheline_snprintf(struct hist_entry *he, char *bf,
+ size_t size, unsigned int width)
+{
+ uint64_t addr = 0;
+ struct map *map = NULL;
+ struct symbol *sym = NULL;
+ char level = he->level;
+
+ if (he->mem_info) {
+ addr = CL(he->mem_info->daddr.al_addr);
+ map = he->mem_info->daddr.map;
+ sym = he->mem_info->daddr.sym;
+
+ /* print [s] for data mmaps */
+ if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
+ map && (map->type == MAP__VARIABLE) &&
+ (map->maj || map->min || map->ino ||
+ map-> ino_generation))
+ level = 's';
+ }
+
+ return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
+ width);
+}
struct sort_entry sort_global_weight = {
.se_header = "Weight",
.se_cmp = sort__global_weight_cmp,
@@ -858,6 +948,13 @@ struct sort_entry sort_mem_snoop = {
.se_width_idx = HISTC_MEM_SNOOP,
};
+struct sort_entry sort_mem_cacheline = {
+ .se_header = "Cacheline",
+ .se_cmp = sort__cacheline_cmp,
+ .se_snprintf = hist_entry__cacheline_snprintf,
+ .se_width_idx = HISTC_MEM_CACHELINE,
+};
+
static int64_t
sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
{
@@ -1000,6 +1097,11 @@ static struct sort_dimension common_sort_dimensions[] = {
DIM(SORT_TRANSACTION, "transaction", sort_transaction),
};
+static struct sort_dimension common_group_sort_dimensions[] = {
+ DIM(0, "pid", sort_thread),
+ DIM(1, "cpu", sort_cpu),
+};
+
#undef DIM
#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
@@ -1027,6 +1129,12 @@ static struct sort_dimension memory_sort_dimensions[] = {
DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
};
+static struct sort_dimension memory_group_sort_dimensions[] = {
+ DIM(0 + __SORT_MEMORY_MODE, "cacheline", sort_mem_cacheline),
+ DIM(1 + __SORT_MEMORY_MODE, "mem", sort_mem_lvl),
+ DIM(2 + __SORT_MEMORY_MODE, "snoop", sort_mem_snoop),
+};
+
#undef DIM
static void __sort_dimension__add(struct sort_dimension *sd, enum sort_type idx)
@@ -1109,12 +1217,81 @@ int sort_dimension__add(const char *tok)
return -ESRCH;
}
+static void __sort_dimension__add_group(struct sort_dimension *sd, enum sort_type idx)
+{
+ if (sd->taken)
+ return;
+
+ if (sd->entry->se_collapse)
+ sort__need_collapse = 1;
+
+ if (list_empty(&hist_group__sort_list))
+ sort__first_dimension = idx;
+
+ list_add_tail(&sd->entry->list, &hist_group__sort_list);
+ sd->taken = 1;
+}
+
+int sort_dimension__add_group(const char *tok)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(common_group_sort_dimensions); i++) {
+ struct sort_dimension *sd = &common_group_sort_dimensions[i];
+
+ if (strncasecmp(tok, sd->name, strlen(tok)))
+ continue;
+
+ sort__has_group = 1;
+
+ __sort_dimension__add_group(sd, i);
+ return 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
+ struct sort_dimension *sd = &memory_group_sort_dimensions[i];
+
+ if (strncasecmp(tok, sd->name, strlen(tok)))
+ continue;
+
+ if (sort__mode != SORT_MODE__MEMORY)
+ return -EINVAL;
+
+ sort__has_group = 1;
+
+ __sort_dimension__add_group(sd, i + __SORT_MEMORY_MODE);
+ return 0;
+ }
+
+ return -ESRCH;
+}
+
int setup_sorting(void)
{
- char *tmp, *tok, *str = strdup(sort_order);
+ char *tmp, *tok, *str = strdup(group_sort_order);
int ret = 0;
if (str == NULL) {
+ error("Not enough memory to setup group sort keys");
+ return -ENOMEM;
+ }
+
+ for (tok = strtok_r(str, ", ", &tmp);
+ tok; tok = strtok_r(NULL, ", ", &tmp)) {
+ ret = sort_dimension__add_group(tok);
+ if (ret == -EINVAL) {
+ error("Invalid --sort key: `%s'", tok);
+ break;
+ } else if (ret == -ESRCH) {
+ error("Unknown --sort key: `%s'", tok);
+ break;
+ }
+ }
+
+ free(str);
+ str = strdup(sort_order);
+
+ if (str == NULL) {
error("Not enough memory to setup sort keys");
return -ENOMEM;
}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index ff24050..ad5001f 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -26,9 +26,11 @@
extern regex_t parent_regex;
extern const char *sort_order;
+extern const char *group_sort_order;
extern const char default_parent_pattern[];
extern const char *parent_pattern;
extern const char default_sort_order[];
+extern const char default_group_sort_order[];
extern regex_t ignore_callees_regex;
extern int have_ignore_callees;
extern int sort__need_collapse;
@@ -91,6 +93,7 @@ struct hist_entry {
u64 ip;
u64 transaction;
s32 cpu;
+ u8 cpumode;
struct hist_entry_diff diff;
@@ -322,6 +325,7 @@ extern struct list_head hist_group__sort_list;
int setup_sorting(void);
extern int sort_dimension__add(const char *);
+extern int sort_dimension__add_group(const char *);
void sort__setup_elide(FILE *fp);
int report_parse_ignore_callees_opt(const struct option *opt, const char *arg, int unset);
--
1.7.11.7
next prev parent reply other threads:[~2014-04-10 20:11 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-04-10 20:10 [RFC 0/5] perf: Create hist_entry groups Don Zickus
2014-04-10 20:10 ` [RFC 1/5] perf: Wrap __hists__add_entry to prep for group entry change Don Zickus
2014-04-10 20:10 ` [RFC 2/5] perf: Use macros to walk hist entries Don Zickus
2014-04-10 20:10 ` [RFC 3/5] perf: Add in stub hist_entry_group code Don Zickus
2014-04-10 20:11 ` [RFC 4/5] perf: Switch to using hist_entry_group Don Zickus
2014-04-10 20:11 ` Don Zickus [this message]
2014-04-11 17:30 ` [RFC 5/5] perf: Enable multiple hist_entry_group output Jiri Olsa
2014-04-11 18:28 ` Don Zickus
2014-04-11 18:34 ` Don Zickus
2014-04-14 9:19 ` Jiri Olsa
2014-04-14 14:13 ` Don Zickus
2014-04-15 3:01 ` [RFC 0/5] perf: Create hist_entry groups Namhyung Kim
2014-04-15 9:40 ` Jiri Olsa
2014-04-15 11:35 ` Namhyung Kim
2014-04-15 16:08 ` Don Zickus
2014-04-16 8:29 ` Namhyung Kim
2014-04-21 20:07 ` Don Zickus
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1397160661-33395-6-git-send-email-dzickus@redhat.com \
--to=dzickus@redhat.com \
--cc=acme@kernel.org \
--cc=andi@firstfloor.org \
--cc=eranian@google.com \
--cc=jolsa@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=namhyung@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.