Skip to content

Commit

Permalink
Merge tag 'perf-core-for-mingo-4.16-20180117' of git://git.kernel.org…
Browse files Browse the repository at this point in the history
…/pub/scm/linux/kernel/git/acme/linux into perf/core

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

- Fix various per event 'max-stack' and 'call-graph=dwarf' issues,
  mostly in 'perf trace', allowing to use 'perf trace --call-graph' with
  'dwarf' and 'fp' to setup the callgraph details for the syscall events
  and make that apply to other events, whilhe allowing to override that on
  a per-event basis, using '-e sched:*switch/call-graph=dwarf/' for
  instance (Arnaldo Carvalho de Melo)

- Improve the --time percent support in record/report/script (Jin Yao)

- Fix copyfile_offset update of output offset (Jiri Olsa)

- Add python script to profile and resolve physical mem type (Kan Liang)

- Add ARM Statistical Profiling Extensions (SPE) support (Kim Phillips)

- Remove trailing semicolon in the evlist code (Luis de Bethencourt)

- Fix incorrect handling of type _TERM_DRV_CFG (Mathieu Poirier)

- Use asprintf when possible in libtraceevent (Federico Vaga)

- Fix bad force_token escape sequence in libtraceevent (Michael Sartain)

- Add UL suffix to MISSING_EVENTS in libtraceevent (Michael Sartain)

- value of unknown symbolic fields in libtraceevent (Jan Kiszka)

- libtraceevent updates: (Steven Rostedt)
  o Show value of flags that have not been parsed
  o Simplify pointer print logic and fix %pF
  o Handle new pointer processing of bprint strings
  o Show contents (in hex) of data of unrecognized type records
  o Fix get_field_str() for dynamic strings

- Add missing break in FALSE case of pevent_filter_clear_trivial() (Taeung Song)

- Fix failed memory allocation for get_cpuid_str (Thomas Richter)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
Ingo Molnar committed Jan 17, 2018
2 parents 7a7368a + 81fccd6 commit a72594c
Show file tree
Hide file tree
Showing 35 changed files with 1,465 additions and 130 deletions.
62 changes: 51 additions & 11 deletions tools/lib/traceevent/event-parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,7 @@ static enum event_type __read_token(char **tok)
if (strcmp(*tok, "LOCAL_PR_FMT") == 0) {
free(*tok);
*tok = NULL;
return force_token("\"\%s\" ", tok);
return force_token("\"%s\" ", tok);
} else if (strcmp(*tok, "STA_PR_FMT") == 0) {
free(*tok);
*tok = NULL;
Expand Down Expand Up @@ -3970,6 +3970,11 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
val &= ~fval;
}
}
if (val) {
if (print && arg->flags.delim)
trace_seq_puts(s, arg->flags.delim);
trace_seq_printf(s, "0x%llx", val);
}
break;
case PRINT_SYMBOL:
val = eval_num_arg(data, size, event, arg->symbol.field);
Expand All @@ -3980,6 +3985,8 @@ static void print_str_arg(struct trace_seq *s, void *data, int size,
break;
}
}
if (!flag)
trace_seq_printf(s, "0x%llx", val);
break;
case PRINT_HEX:
case PRINT_HEX_STR:
Expand Down Expand Up @@ -4293,6 +4300,26 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc
goto process_again;
case 'p':
ls = 1;
if (isalnum(ptr[1])) {
ptr++;
/* Check for special pointers */
switch (*ptr) {
case 's':
case 'S':
case 'f':
case 'F':
break;
default:
/*
* Older kernels do not process
* dereferenced pointers.
* Only process if the pointer
* value is a printable.
*/
if (isprint(*(char *)bptr))
goto process_string;
}
}
/* fall through */
case 'd':
case 'u':
Expand Down Expand Up @@ -4345,6 +4372,7 @@ static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struc

break;
case 's':
process_string:
arg = alloc_arg();
if (!arg) {
do_warning_event(event, "%s(%d): not enough memory!",
Expand Down Expand Up @@ -4949,21 +4977,27 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
else
ls = 2;

if (*(ptr+1) == 'F' || *(ptr+1) == 'f' ||
*(ptr+1) == 'S' || *(ptr+1) == 's') {
if (isalnum(ptr[1]))
ptr++;

if (arg->type == PRINT_BSTRING) {
trace_seq_puts(s, arg->string.string);
break;
}

if (*ptr == 'F' || *ptr == 'f' ||
*ptr == 'S' || *ptr == 's') {
show_func = *ptr;
} else if (*(ptr+1) == 'M' || *(ptr+1) == 'm') {
print_mac_arg(s, *(ptr+1), data, size, event, arg);
ptr++;
} else if (*ptr == 'M' || *ptr == 'm') {
print_mac_arg(s, *ptr, data, size, event, arg);
arg = arg->next;
break;
} else if (*(ptr+1) == 'I' || *(ptr+1) == 'i') {
} else if (*ptr == 'I' || *ptr == 'i') {
int n;

n = print_ip_arg(s, ptr+1, data, size, event, arg);
n = print_ip_arg(s, ptr, data, size, event, arg);
if (n > 0) {
ptr += n;
ptr += n - 1;
arg = arg->next;
break;
}
Expand Down Expand Up @@ -5532,8 +5566,14 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,

event = pevent_find_event_by_record(pevent, record);
if (!event) {
do_warning("ug! no event found for type %d",
trace_parse_common_type(pevent, record->data));
int i;
int type = trace_parse_common_type(pevent, record->data);

do_warning("ug! no event found for type %d", type);
trace_seq_printf(s, "[UNKNOWN TYPE %d]", type);
for (i = 0; i < record->size; i++)
trace_seq_printf(s, " %02x",
((unsigned char *)record->data)[i]);
return;
}

Expand Down
24 changes: 9 additions & 15 deletions tools/lib/traceevent/event-plugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,12 @@ char **traceevent_plugin_list_options(void)
for (op = reg->options; op->name; op++) {
char *alias = op->plugin_alias ? op->plugin_alias : op->file;
char **temp = list;
int ret;

name = malloc(strlen(op->name) + strlen(alias) + 2);
if (!name)
ret = asprintf(&name, "%s:%s", alias, op->name);
if (ret < 0)
goto err;

sprintf(name, "%s:%s", alias, op->name);
list = realloc(list, count + 2);
if (!list) {
list = temp;
Expand Down Expand Up @@ -290,17 +290,14 @@ load_plugin(struct pevent *pevent, const char *path,
const char *alias;
char *plugin;
void *handle;
int ret;

plugin = malloc(strlen(path) + strlen(file) + 2);
if (!plugin) {
ret = asprintf(&plugin, "%s/%s", path, file);
if (ret < 0) {
warning("could not allocate plugin memory\n");
return;
}

strcpy(plugin, path);
strcat(plugin, "/");
strcat(plugin, file);

handle = dlopen(plugin, RTLD_NOW | RTLD_GLOBAL);
if (!handle) {
warning("could not load plugin '%s'\n%s\n",
Expand Down Expand Up @@ -391,6 +388,7 @@ load_plugins(struct pevent *pevent, const char *suffix,
char *home;
char *path;
char *envdir;
int ret;

if (pevent->flags & PEVENT_DISABLE_PLUGINS)
return;
Expand Down Expand Up @@ -421,16 +419,12 @@ load_plugins(struct pevent *pevent, const char *suffix,
if (!home)
return;

path = malloc(strlen(home) + strlen(LOCAL_PLUGIN_DIR) + 2);
if (!path) {
ret = asprintf(&path, "%s/%s", home, LOCAL_PLUGIN_DIR);
if (ret < 0) {
warning("could not allocate plugin memory\n");
return;
}

strcpy(path, home);
strcat(path, "/");
strcat(path, LOCAL_PLUGIN_DIR);

load_plugins_dir(pevent, suffix, path, load_plugin, data);

free(path);
Expand Down
4 changes: 2 additions & 2 deletions tools/lib/traceevent/kbuffer-parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@

#include "kbuffer.h"

#define MISSING_EVENTS (1 << 31)
#define MISSING_STORED (1 << 30)
#define MISSING_EVENTS (1UL << 31)
#define MISSING_STORED (1UL << 30)

#define COMMIT_MASK ((1 << 27) - 1)

Expand Down
22 changes: 14 additions & 8 deletions tools/lib/traceevent/parse-filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,26 +287,23 @@ find_event(struct pevent *pevent, struct event_list **events,
sys_name = NULL;
}

reg = malloc(strlen(event_name) + 3);
if (reg == NULL)
ret = asprintf(&reg, "^%s$", event_name);
if (ret < 0)
return PEVENT_ERRNO__MEM_ALLOC_FAILED;

sprintf(reg, "^%s$", event_name);

ret = regcomp(&ereg, reg, REG_ICASE|REG_NOSUB);
free(reg);

if (ret)
return PEVENT_ERRNO__INVALID_EVENT_NAME;

if (sys_name) {
reg = malloc(strlen(sys_name) + 3);
if (reg == NULL) {
ret = asprintf(&reg, "^%s$", sys_name);
if (ret < 0) {
regfree(&ereg);
return PEVENT_ERRNO__MEM_ALLOC_FAILED;
}

sprintf(reg, "^%s$", sys_name);
ret = regcomp(&sreg, reg, REG_ICASE|REG_NOSUB);
free(reg);
if (ret) {
Expand Down Expand Up @@ -1634,6 +1631,7 @@ int pevent_filter_clear_trivial(struct event_filter *filter,
case FILTER_TRIVIAL_FALSE:
if (filter_type->filter->boolean.value)
continue;
break;
case FILTER_TRIVIAL_TRUE:
if (!filter_type->filter->boolean.value)
continue;
Expand Down Expand Up @@ -1879,17 +1877,25 @@ static const char *get_field_str(struct filter_arg *arg, struct pevent_record *r
struct pevent *pevent;
unsigned long long addr;
const char *val = NULL;
unsigned int size;
char hex[64];

/* If the field is not a string convert it */
if (arg->str.field->flags & FIELD_IS_STRING) {
val = record->data + arg->str.field->offset;
size = arg->str.field->size;

if (arg->str.field->flags & FIELD_IS_DYNAMIC) {
addr = *(unsigned int *)val;
val = record->data + (addr & 0xffff);
size = addr >> 16;
}

/*
* We need to copy the data since we can't be sure the field
* is null terminated.
*/
if (*(val + arg->str.field->size - 1)) {
if (*(val + size - 1)) {
/* copy it */
memcpy(arg->str.buffer, val, arg->str.field->size);
/* the buffer is already NULL terminated */
Expand Down
2 changes: 1 addition & 1 deletion tools/perf/Documentation/perf-report.txt
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ OPTIONS
to end of file.

Also support time percent with multiple time range. Time string is
'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'. The maximum number of slices is 10.
'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'.

For example:
Select the second 10% time slice:
Expand Down
10 changes: 5 additions & 5 deletions tools/perf/Documentation/perf-script.txt
Original file line number Diff line number Diff line change
Expand Up @@ -351,19 +351,19 @@ include::itrace.txt[]
to end of file.

Also support time percent with multipe time range. Time string is
'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'. The maximum number of slices is 10.
'a%/n,b%/m,...' or 'a%-b%,c%-%d,...'.

For example:
Select the second 10% time slice
Select the second 10% time slice:
perf script --time 10%/2

Select from 0% to 10% time slice
Select from 0% to 10% time slice:
perf script --time 0%-10%

Select the first and second 10% time slices
Select the first and second 10% time slices:
perf script --time 10%/1,10%/2

Select from 0% to 10% and 30% to 40% slices
Select from 0% to 10% and 30% to 40% slices:
perf script --time 0%-10%,30%-40%

--max-blocks::
Expand Down
77 changes: 71 additions & 6 deletions tools/perf/arch/arm/util/auxtrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,29 +22,94 @@
#include "../../util/evlist.h"
#include "../../util/pmu.h"
#include "cs-etm.h"
#include "arm-spe.h"

static struct perf_pmu **find_all_arm_spe_pmus(int *nr_spes, int *err)
{
struct perf_pmu **arm_spe_pmus = NULL;
int ret, i, nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
/* arm_spe_xxxxxxxxx\0 */
char arm_spe_pmu_name[sizeof(ARM_SPE_PMU_NAME) + 10];

arm_spe_pmus = zalloc(sizeof(struct perf_pmu *) * nr_cpus);
if (!arm_spe_pmus) {
pr_err("spes alloc failed\n");
*err = -ENOMEM;
return NULL;
}

for (i = 0; i < nr_cpus; i++) {
ret = sprintf(arm_spe_pmu_name, "%s%d", ARM_SPE_PMU_NAME, i);
if (ret < 0) {
pr_err("sprintf failed\n");
*err = -ENOMEM;
return NULL;
}

arm_spe_pmus[*nr_spes] = perf_pmu__find(arm_spe_pmu_name);
if (arm_spe_pmus[*nr_spes]) {
pr_debug2("%s %d: arm_spe_pmu %d type %d name %s\n",
__func__, __LINE__, *nr_spes,
arm_spe_pmus[*nr_spes]->type,
arm_spe_pmus[*nr_spes]->name);
(*nr_spes)++;
}
}

return arm_spe_pmus;
}

struct auxtrace_record
*auxtrace_record__init(struct perf_evlist *evlist, int *err)
{
struct perf_pmu *cs_etm_pmu;
struct perf_evsel *evsel;
bool found_etm = false;
bool found_spe = false;
static struct perf_pmu **arm_spe_pmus = NULL;
static int nr_spes = 0;
int i;

if (!evlist)
return NULL;

cs_etm_pmu = perf_pmu__find(CORESIGHT_ETM_PMU_NAME);

if (evlist) {
evlist__for_each_entry(evlist, evsel) {
if (cs_etm_pmu &&
evsel->attr.type == cs_etm_pmu->type)
found_etm = true;
if (!arm_spe_pmus)
arm_spe_pmus = find_all_arm_spe_pmus(&nr_spes, err);

evlist__for_each_entry(evlist, evsel) {
if (cs_etm_pmu &&
evsel->attr.type == cs_etm_pmu->type)
found_etm = true;

if (!nr_spes)
continue;

for (i = 0; i < nr_spes; i++) {
if (evsel->attr.type == arm_spe_pmus[i]->type) {
found_spe = true;
break;
}
}
}

if (found_etm && found_spe) {
pr_err("Concurrent ARM Coresight ETM and SPE operation not currently supported\n");
*err = -EOPNOTSUPP;
return NULL;
}

if (found_etm)
return cs_etm_record_init(err);

#if defined(__aarch64__)
if (found_spe)
return arm_spe_recording_init(err, arm_spe_pmus[i]);
#endif

/*
* Clear 'err' even if we haven't found a cs_etm event - that way perf
* Clear 'err' even if we haven't found an event - that way perf
* record can still be used even if tracers aren't present. The NULL
* return value will take care of telling the infrastructure HW tracing
* isn't available.
Expand Down
Loading

0 comments on commit a72594c

Please sign in to comment.