static int max_stack_depth = CONTENTION_STACK_DEPTH;
static int stack_skip = CONTENTION_STACK_SKIP;
static int print_nr_entries = INT_MAX / 2;
+static LIST_HEAD(callstack_filters);
+
+struct callstack_filter {
+ struct list_head list;
+ char name[];
+};
static struct lock_filter filters;
static enum lock_aggr_mode aggr_mode = LOCK_AGGR_ADDR;
+static bool needs_callstack(void)
+{
+ return verbose > 0 || !list_empty(&callstack_filters);
+}
+
static struct thread_stat *thread_stat_find(u32 tid)
{
struct rb_node *node;
if (!ls)
return -ENOMEM;
- if (aggr_mode == LOCK_AGGR_CALLER && verbose > 0) {
+ if (aggr_mode == LOCK_AGGR_CALLER && needs_callstack()) {
ls->callstack = get_callstack(sample, max_stack_depth);
if (ls->callstack == NULL)
return -ENOMEM;
if (!st->wait_time_total)
continue;
+ if (aggr_mode == LOCK_AGGR_CALLER && !list_empty(&callstack_filters)) {
+ struct map *kmap;
+ struct symbol *sym;
+ u64 ip;
+
+ for (int i = 0; i < max_stack_depth; i++) {
+ struct callstack_filter *filter;
+
+ if (!st->callstack || !st->callstack[i])
+ break;
+
+ ip = st->callstack[i];
+ sym = machine__find_kernel_symbol(con->machine, ip, &kmap);
+ if (sym == NULL)
+ continue;
+
+ list_for_each_entry(filter, &callstack_filters, list) {
+ if (strstr(sym->name, filter->name))
+ goto found;
+ }
+ }
+ continue;
+ }
+
+found:
list_for_each_entry(key, &lock_keys, list) {
key->print(key, st);
pr_info(" ");
.max_stack = max_stack_depth,
.stack_skip = stack_skip,
.filters = &filters,
+ .save_callstack = needs_callstack(),
};
session = perf_session__new(use_bpf ? NULL : &data, &eops);
return ret;
}
+static int parse_call_stack(const struct option *opt __maybe_unused, const char *str,
+ int unset __maybe_unused)
+{
+ char *s, *tmp, *tok;
+ int ret = 0;
+
+ s = strdup(str);
+ if (s == NULL)
+ return -1;
+
+ for (tok = strtok_r(s, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) {
+ struct callstack_filter *entry;
+
+ entry = malloc(sizeof(*entry) + strlen(tok) + 1);
+ if (entry == NULL) {
+ pr_err("Memory allocation failure\n");
+ return -1;
+ }
+
+ strcpy(entry->name, tok);
+ list_add_tail(&entry->list, &callstack_filters);
+ }
+
+ free(s);
+ return ret;
+}
+
int cmd_lock(int argc, const char **argv)
{
const struct option lock_options[] = {
"Filter specific type of locks", parse_lock_type),
OPT_CALLBACK('L', "lock-filter", NULL, "ADDRS/NAMES",
"Filter specific address/symbol of locks", parse_lock_addr),
+ OPT_CALLBACK('S', "callstack-filter", NULL, "NAMES",
+ "Filter specific function in the callstack", parse_call_stack),
OPT_PARENT(lock_options)
};