mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
perf/core improvements and fixes:
Developer stuff: . Making some code (cpu node map and report parse callchain callback) global to be usable by upcomming changes (Don Zickus) . Fix pmu object compilation error (Jiri Olsa) Signed-off-by: Jiri Olsa <jolsa@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJTVo4MAAoJEPZqUSBWB3s9XZgQANNn4zOdb8UF6A0SpKorLGC7 3CM8YzPGwBddlyV0GRrOFrRrXQagkkJFYWNPqgcUL2QpMw847e1wmVz/uMXQZIfW 8dpJ3CPKv4CAJXRJEvE3WIayR1ZcsuX4JwL02H+V07G1Mk7XG7SHAWFrhcB3TaBU 4uwvw97+SIU/eWNGiC6I8F9agSeUkCW8vVbe76Z2TfQGmPD/OPaOcmbPr7/UaTo9 oSanx/QgyUfWmOXggjZqIwdYDEVNkWmcaiMEvloWCPMCF759aeCYqkWcs6qMMvkC Cuwhvz4x/6VCwgjzpuU1pETV0RZQOu++P/hyZTuceUa4fjGtBSNRCjifJMnaC2m3 uWt06zhjn4vEOjHSAZrLqLrpSD/SGujhFr4YwU8JWqosHF6bSL2TIV4/rBlYte88 dVMYkWJw9g+LFAiTvYSJi2u6Maru0yOnsALltdkehrSS8jqwAQGPj4g/bxlKaALf qgOTTfkGeTHFhb6zwaCnsFB/px/+GUHCrWPxdTP/xAp4hxgfTo9yIwlrnoN8EmEM CCoNBC+1rimcRn0caMAVMWlw8u/u4JW4UDWj1c5+z102m3LDQztIe32SvIxkU2Q5 rKNEJZvP8RguZt+r1R5rUHzhW9liV/PfIvv4w5sdIw+kskCOi+mLHvuCN2bApogD qz+2fe5iHKqAPZH6EQKK =ywz5 -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf into perf/core Pull perf/core improvements and fixes from Jiri Olsa: Infrastructure changes: * Making some code (cpu node map and report parse callchain callback) global to be usable by upcomming changes (Don Zickus) * Fix pmu object compilation error (Jiri Olsa) Signed-off-by: Jiri Olsa <jolsa@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
a81fef347b
@ -14,6 +14,7 @@
|
||||
#include "util/parse-options.h"
|
||||
#include "util/trace-event.h"
|
||||
#include "util/data.h"
|
||||
#include "util/cpumap.h"
|
||||
|
||||
#include "util/debug.h"
|
||||
|
||||
@ -31,9 +32,6 @@ static int caller_lines = -1;
|
||||
|
||||
static bool raw_ip;
|
||||
|
||||
static int *cpunode_map;
|
||||
static int max_cpu_num;
|
||||
|
||||
struct alloc_stat {
|
||||
u64 call_site;
|
||||
u64 ptr;
|
||||
@ -55,76 +53,6 @@ static struct rb_root root_caller_sorted;
|
||||
static unsigned long total_requested, total_allocated;
|
||||
static unsigned long nr_allocs, nr_cross_allocs;
|
||||
|
||||
#define PATH_SYS_NODE "/sys/devices/system/node"
|
||||
|
||||
static int init_cpunode_map(void)
|
||||
{
|
||||
FILE *fp;
|
||||
int i, err = -1;
|
||||
|
||||
fp = fopen("/sys/devices/system/cpu/kernel_max", "r");
|
||||
if (!fp) {
|
||||
max_cpu_num = 4096;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fscanf(fp, "%d", &max_cpu_num) < 1) {
|
||||
pr_err("Failed to read 'kernel_max' from sysfs");
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
max_cpu_num++;
|
||||
|
||||
cpunode_map = calloc(max_cpu_num, sizeof(int));
|
||||
if (!cpunode_map) {
|
||||
pr_err("%s: calloc failed\n", __func__);
|
||||
goto out_close;
|
||||
}
|
||||
|
||||
for (i = 0; i < max_cpu_num; i++)
|
||||
cpunode_map[i] = -1;
|
||||
|
||||
err = 0;
|
||||
out_close:
|
||||
fclose(fp);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int setup_cpunode_map(void)
|
||||
{
|
||||
struct dirent *dent1, *dent2;
|
||||
DIR *dir1, *dir2;
|
||||
unsigned int cpu, mem;
|
||||
char buf[PATH_MAX];
|
||||
|
||||
if (init_cpunode_map())
|
||||
return -1;
|
||||
|
||||
dir1 = opendir(PATH_SYS_NODE);
|
||||
if (!dir1)
|
||||
return 0;
|
||||
|
||||
while ((dent1 = readdir(dir1)) != NULL) {
|
||||
if (dent1->d_type != DT_DIR ||
|
||||
sscanf(dent1->d_name, "node%u", &mem) < 1)
|
||||
continue;
|
||||
|
||||
snprintf(buf, PATH_MAX, "%s/%s", PATH_SYS_NODE, dent1->d_name);
|
||||
dir2 = opendir(buf);
|
||||
if (!dir2)
|
||||
continue;
|
||||
while ((dent2 = readdir(dir2)) != NULL) {
|
||||
if (dent2->d_type != DT_LNK ||
|
||||
sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
|
||||
continue;
|
||||
cpunode_map[cpu] = mem;
|
||||
}
|
||||
closedir(dir2);
|
||||
}
|
||||
closedir(dir1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int insert_alloc_stat(unsigned long call_site, unsigned long ptr,
|
||||
int bytes_req, int bytes_alloc, int cpu)
|
||||
{
|
||||
@ -235,7 +163,7 @@ static int perf_evsel__process_alloc_node_event(struct perf_evsel *evsel,
|
||||
int ret = perf_evsel__process_alloc_event(evsel, sample);
|
||||
|
||||
if (!ret) {
|
||||
int node1 = cpunode_map[sample->cpu],
|
||||
int node1 = cpu__get_node(sample->cpu),
|
||||
node2 = perf_evsel__intval(evsel, sample, "node");
|
||||
|
||||
if (node1 != node2)
|
||||
@ -772,7 +700,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
if (!strncmp(argv[0], "rec", 3)) {
|
||||
return __cmd_record(argc, argv);
|
||||
} else if (!strcmp(argv[0], "stat")) {
|
||||
if (setup_cpunode_map())
|
||||
if (cpu__setup_cpunode_map())
|
||||
return -1;
|
||||
|
||||
if (list_empty(&caller_sort))
|
||||
|
@ -589,11 +589,9 @@ static int __cmd_report(struct report *rep)
|
||||
}
|
||||
|
||||
static int
|
||||
parse_callchain_opt(const struct option *opt, const char *arg, int unset)
|
||||
report_parse_callchain_opt(const struct option *opt, const char *arg, int unset)
|
||||
{
|
||||
struct report *rep = (struct report *)opt->value;
|
||||
char *tok, *tok2;
|
||||
char *endptr;
|
||||
|
||||
/*
|
||||
* --no-call-graph
|
||||
@ -603,80 +601,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
symbol_conf.use_callchain = true;
|
||||
|
||||
if (!arg)
|
||||
return 0;
|
||||
|
||||
tok = strtok((char *)arg, ",");
|
||||
if (!tok)
|
||||
return -1;
|
||||
|
||||
/* get the output mode */
|
||||
if (!strncmp(tok, "graph", strlen(arg)))
|
||||
callchain_param.mode = CHAIN_GRAPH_ABS;
|
||||
|
||||
else if (!strncmp(tok, "flat", strlen(arg)))
|
||||
callchain_param.mode = CHAIN_FLAT;
|
||||
|
||||
else if (!strncmp(tok, "fractal", strlen(arg)))
|
||||
callchain_param.mode = CHAIN_GRAPH_REL;
|
||||
|
||||
else if (!strncmp(tok, "none", strlen(arg))) {
|
||||
callchain_param.mode = CHAIN_NONE;
|
||||
symbol_conf.use_callchain = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* get the min percentage */
|
||||
tok = strtok(NULL, ",");
|
||||
if (!tok)
|
||||
goto setup;
|
||||
|
||||
callchain_param.min_percent = strtod(tok, &endptr);
|
||||
if (tok == endptr)
|
||||
return -1;
|
||||
|
||||
/* get the print limit */
|
||||
tok2 = strtok(NULL, ",");
|
||||
if (!tok2)
|
||||
goto setup;
|
||||
|
||||
if (tok2[0] != 'c') {
|
||||
callchain_param.print_limit = strtoul(tok2, &endptr, 0);
|
||||
tok2 = strtok(NULL, ",");
|
||||
if (!tok2)
|
||||
goto setup;
|
||||
}
|
||||
|
||||
/* get the call chain order */
|
||||
if (!strncmp(tok2, "caller", strlen("caller")))
|
||||
callchain_param.order = ORDER_CALLER;
|
||||
else if (!strncmp(tok2, "callee", strlen("callee")))
|
||||
callchain_param.order = ORDER_CALLEE;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Get the sort key */
|
||||
tok2 = strtok(NULL, ",");
|
||||
if (!tok2)
|
||||
goto setup;
|
||||
if (!strncmp(tok2, "function", strlen("function")))
|
||||
callchain_param.key = CCKEY_FUNCTION;
|
||||
else if (!strncmp(tok2, "address", strlen("address")))
|
||||
callchain_param.key = CCKEY_ADDRESS;
|
||||
else
|
||||
return -1;
|
||||
setup:
|
||||
if (callchain_register_param(&callchain_param) < 0) {
|
||||
pr_err("Can't register callchain params\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
return parse_callchain_report_opt(arg);
|
||||
}
|
||||
|
||||
int
|
||||
@ -788,7 +713,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
"Only display entries with parent-match"),
|
||||
OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
|
||||
"Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
|
||||
"Default: fractal,0.5,callee,function", &parse_callchain_opt, callchain_default_opt),
|
||||
"Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt),
|
||||
OPT_INTEGER(0, "max-stack", &report.max_stack,
|
||||
"Set the maximum stack depth when parsing the callchain, "
|
||||
"anything beyond the specified depth will be ignored. "
|
||||
|
@ -25,6 +25,84 @@
|
||||
|
||||
__thread struct callchain_cursor callchain_cursor;
|
||||
|
||||
int
|
||||
parse_callchain_report_opt(const char *arg)
|
||||
{
|
||||
char *tok, *tok2;
|
||||
char *endptr;
|
||||
|
||||
symbol_conf.use_callchain = true;
|
||||
|
||||
if (!arg)
|
||||
return 0;
|
||||
|
||||
tok = strtok((char *)arg, ",");
|
||||
if (!tok)
|
||||
return -1;
|
||||
|
||||
/* get the output mode */
|
||||
if (!strncmp(tok, "graph", strlen(arg))) {
|
||||
callchain_param.mode = CHAIN_GRAPH_ABS;
|
||||
|
||||
} else if (!strncmp(tok, "flat", strlen(arg))) {
|
||||
callchain_param.mode = CHAIN_FLAT;
|
||||
} else if (!strncmp(tok, "fractal", strlen(arg))) {
|
||||
callchain_param.mode = CHAIN_GRAPH_REL;
|
||||
} else if (!strncmp(tok, "none", strlen(arg))) {
|
||||
callchain_param.mode = CHAIN_NONE;
|
||||
symbol_conf.use_callchain = false;
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* get the min percentage */
|
||||
tok = strtok(NULL, ",");
|
||||
if (!tok)
|
||||
goto setup;
|
||||
|
||||
callchain_param.min_percent = strtod(tok, &endptr);
|
||||
if (tok == endptr)
|
||||
return -1;
|
||||
|
||||
/* get the print limit */
|
||||
tok2 = strtok(NULL, ",");
|
||||
if (!tok2)
|
||||
goto setup;
|
||||
|
||||
if (tok2[0] != 'c') {
|
||||
callchain_param.print_limit = strtoul(tok2, &endptr, 0);
|
||||
tok2 = strtok(NULL, ",");
|
||||
if (!tok2)
|
||||
goto setup;
|
||||
}
|
||||
|
||||
/* get the call chain order */
|
||||
if (!strncmp(tok2, "caller", strlen("caller")))
|
||||
callchain_param.order = ORDER_CALLER;
|
||||
else if (!strncmp(tok2, "callee", strlen("callee")))
|
||||
callchain_param.order = ORDER_CALLEE;
|
||||
else
|
||||
return -1;
|
||||
|
||||
/* Get the sort key */
|
||||
tok2 = strtok(NULL, ",");
|
||||
if (!tok2)
|
||||
goto setup;
|
||||
if (!strncmp(tok2, "function", strlen("function")))
|
||||
callchain_param.key = CCKEY_FUNCTION;
|
||||
else if (!strncmp(tok2, "address", strlen("address")))
|
||||
callchain_param.key = CCKEY_ADDRESS;
|
||||
else
|
||||
return -1;
|
||||
setup:
|
||||
if (callchain_register_param(&callchain_param) < 0) {
|
||||
pr_err("Can't register callchain params\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
|
||||
enum chain_mode mode)
|
||||
|
@ -157,4 +157,5 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
|
||||
int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample);
|
||||
|
||||
extern const char record_callchain_help[];
|
||||
int parse_callchain_report_opt(const char *arg);
|
||||
#endif /* __PERF_CALLCHAIN_H */
|
||||
|
@ -317,3 +317,163 @@ int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep)
|
||||
{
|
||||
return cpu_map__build_map(cpus, corep, cpu_map__get_core);
|
||||
}
|
||||
|
||||
/* setup simple routines to easily access node numbers given a cpu number */
|
||||
static int get_max_num(char *path, int *max)
|
||||
{
|
||||
size_t num;
|
||||
char *buf;
|
||||
int err = 0;
|
||||
|
||||
if (filename__read_str(path, &buf, &num))
|
||||
return -1;
|
||||
|
||||
buf[num] = '\0';
|
||||
|
||||
/* start on the right, to find highest node num */
|
||||
while (--num) {
|
||||
if ((buf[num] == ',') || (buf[num] == '-')) {
|
||||
num++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sscanf(&buf[num], "%d", max) < 1) {
|
||||
err = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* convert from 0-based to 1-based */
|
||||
(*max)++;
|
||||
|
||||
out:
|
||||
free(buf);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Determine highest possible cpu in the system for sparse allocation */
|
||||
static void set_max_cpu_num(void)
|
||||
{
|
||||
const char *mnt;
|
||||
char path[PATH_MAX];
|
||||
int ret = -1;
|
||||
|
||||
/* set up default */
|
||||
max_cpu_num = 4096;
|
||||
|
||||
mnt = sysfs__mountpoint();
|
||||
if (!mnt)
|
||||
goto out;
|
||||
|
||||
/* get the highest possible cpu number for a sparse allocation */
|
||||
ret = snprintf(path, PATH_MAX, "%s/devices/system/cpu/possible", mnt);
|
||||
if (ret == PATH_MAX) {
|
||||
pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = get_max_num(path, &max_cpu_num);
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
pr_err("Failed to read max cpus, using default of %d\n", max_cpu_num);
|
||||
}
|
||||
|
||||
/* Determine highest possible node in the system for sparse allocation */
|
||||
static void set_max_node_num(void)
|
||||
{
|
||||
const char *mnt;
|
||||
char path[PATH_MAX];
|
||||
int ret = -1;
|
||||
|
||||
/* set up default */
|
||||
max_node_num = 8;
|
||||
|
||||
mnt = sysfs__mountpoint();
|
||||
if (!mnt)
|
||||
goto out;
|
||||
|
||||
/* get the highest possible cpu number for a sparse allocation */
|
||||
ret = snprintf(path, PATH_MAX, "%s/devices/system/node/possible", mnt);
|
||||
if (ret == PATH_MAX) {
|
||||
pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = get_max_num(path, &max_node_num);
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
pr_err("Failed to read max nodes, using default of %d\n", max_node_num);
|
||||
}
|
||||
|
||||
static int init_cpunode_map(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
set_max_cpu_num();
|
||||
set_max_node_num();
|
||||
|
||||
cpunode_map = calloc(max_cpu_num, sizeof(int));
|
||||
if (!cpunode_map) {
|
||||
pr_err("%s: calloc failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < max_cpu_num; i++)
|
||||
cpunode_map[i] = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu__setup_cpunode_map(void)
|
||||
{
|
||||
struct dirent *dent1, *dent2;
|
||||
DIR *dir1, *dir2;
|
||||
unsigned int cpu, mem;
|
||||
char buf[PATH_MAX];
|
||||
char path[PATH_MAX];
|
||||
const char *mnt;
|
||||
int n;
|
||||
|
||||
/* initialize globals */
|
||||
if (init_cpunode_map())
|
||||
return -1;
|
||||
|
||||
mnt = sysfs__mountpoint();
|
||||
if (!mnt)
|
||||
return 0;
|
||||
|
||||
n = snprintf(path, PATH_MAX, "%s/devices/system/node", mnt);
|
||||
if (n == PATH_MAX) {
|
||||
pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dir1 = opendir(path);
|
||||
if (!dir1)
|
||||
return 0;
|
||||
|
||||
/* walk tree and setup map */
|
||||
while ((dent1 = readdir(dir1)) != NULL) {
|
||||
if (dent1->d_type != DT_DIR || sscanf(dent1->d_name, "node%u", &mem) < 1)
|
||||
continue;
|
||||
|
||||
n = snprintf(buf, PATH_MAX, "%s/%s", path, dent1->d_name);
|
||||
if (n == PATH_MAX) {
|
||||
pr_err("sysfs path crossed PATH_MAX(%d) size\n", PATH_MAX);
|
||||
continue;
|
||||
}
|
||||
|
||||
dir2 = opendir(buf);
|
||||
if (!dir2)
|
||||
continue;
|
||||
while ((dent2 = readdir(dir2)) != NULL) {
|
||||
if (dent2->d_type != DT_LNK || sscanf(dent2->d_name, "cpu%u", &cpu) < 1)
|
||||
continue;
|
||||
cpunode_map[cpu] = mem;
|
||||
}
|
||||
closedir(dir2);
|
||||
}
|
||||
closedir(dir1);
|
||||
return 0;
|
||||
}
|
||||
|
@ -4,6 +4,9 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "perf.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
struct cpu_map {
|
||||
int nr;
|
||||
int map[];
|
||||
@ -46,4 +49,36 @@ static inline bool cpu_map__empty(const struct cpu_map *map)
|
||||
return map ? map->map[0] == -1 : true;
|
||||
}
|
||||
|
||||
int max_cpu_num;
|
||||
int max_node_num;
|
||||
int *cpunode_map;
|
||||
|
||||
int cpu__setup_cpunode_map(void);
|
||||
|
||||
static inline int cpu__max_node(void)
|
||||
{
|
||||
if (unlikely(!max_node_num))
|
||||
pr_debug("cpu_map not initialized\n");
|
||||
|
||||
return max_node_num;
|
||||
}
|
||||
|
||||
static inline int cpu__max_cpu(void)
|
||||
{
|
||||
if (unlikely(!max_cpu_num))
|
||||
pr_debug("cpu_map not initialized\n");
|
||||
|
||||
return max_cpu_num;
|
||||
}
|
||||
|
||||
static inline int cpu__get_node(int cpu)
|
||||
{
|
||||
if (unlikely(cpunode_map == NULL)) {
|
||||
pr_debug("cpu_map not initialized\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return cpunode_map[cpu];
|
||||
}
|
||||
|
||||
#endif /* __PERF_CPUMAP_H */
|
||||
|
@ -284,17 +284,17 @@ static int pmu_aliases(const char *name, struct list_head *head)
|
||||
static int pmu_alias_terms(struct perf_pmu_alias *alias,
|
||||
struct list_head *terms)
|
||||
{
|
||||
struct parse_events_term *term, *clone;
|
||||
struct parse_events_term *term, *cloned;
|
||||
LIST_HEAD(list);
|
||||
int ret;
|
||||
|
||||
list_for_each_entry(term, &alias->terms, list) {
|
||||
ret = parse_events_term__clone(&clone, term);
|
||||
ret = parse_events_term__clone(&cloned, term);
|
||||
if (ret) {
|
||||
parse_events__free_terms(&list);
|
||||
return ret;
|
||||
}
|
||||
list_add_tail(&clone->list, &list);
|
||||
list_add_tail(&cloned->list, &list);
|
||||
}
|
||||
list_splice(&list, terms);
|
||||
return 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user