Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753254AbbGFES2 (ORCPT ); Mon, 6 Jul 2015 00:18:28 -0400 Received: from szxga02-in.huawei.com ([119.145.14.65]:53264 "EHLO szxga02-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750728AbbGFESV (ORCPT ); Mon, 6 Jul 2015 00:18:21 -0400 From: Wang Nan To: , , , , , , , , , , , CC: , , , , Subject: [PATCH] perf record: Allow passing perf's own pid to '--filter' Date: Mon, 6 Jul 2015 04:17:31 +0000 Message-ID: <1436156251-147535-1-git-send-email-wangnan0@huawei.com> X-Mailer: git-send-email 1.8.3.4 MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.107.197.200] X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4385 Lines: 178 This patch allows passing perf's own PID to '--filter' by using '@PERFPID'. This should be useful when system-widely capturing tracepoints events. Before this patch, when doing something like: # perf record -a -e syscalls:sys_enter_write One could easily get result like this: # /tmp/perf report --stdio ... # Overhead Command Shared Object Symbol # ........ ....... .................. .................... # 99.99% perf libpthread-2.18.so [.] __write_nocancel 0.01% ls libc-2.18.so [.] write 0.01% sshd libc-2.18.so [.] write ... Where most events are generated by perf itself. A shell trick can be done to filter perf itself out: # cat << EOF > ./tmp > #!/bin/sh > exec perf record -e ... --filter="common_pid != \$\$" -a sleep 10 > EOF # chmod a+x ./tmp # ./tmp However, doing so is user unfriendly. This patch introduces '@PERFPID' placeholder to '--filter' options. Now user is allowed to the above work with: # perf record -e ... --filter="common_pid != @PERFPID' sleep 10 Signed-off-by: Wang Nan --- tools/perf/Documentation/perf-record.txt | 1 + tools/perf/util/parse-events.c | 96 ++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 9b9d9d0..c2902d2 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -62,6 +62,7 @@ OPTIONS --filter=:: Event filter. + String '@PERFPID' is allowed to be used to represent pid of 'perf' itself. -a:: --all-cpus:: diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index aaee24c..2d62957 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1175,6 +1175,101 @@ int parse_events_option(const struct option *opt, const char *str, return ret; } +#ifndef PAGE_SIZE +# define PAGE_SIZE 4096 +#endif +static int +postproc_filter_append_token(const char *key, char *new_filter, + ssize_t *pspace) +{ + if (strcmp(key, "PERFPID") == 0) { + char pid_buf[32]; + pid_t self_pid = getpid(); + + snprintf(pid_buf, 32, "%d", self_pid); + strncat(new_filter, pid_buf, *pspace); + *pspace -= strlen(pid_buf); + if (*pspace < 0) + return -1; + return 0; + } + + return -1; +} + +static void postproc_filter(struct perf_evsel *evsel) +{ + char *at = NULL, *sep = NULL, *old_filter, *new_filter; + ssize_t space; + + if (!evsel->filter) + return; + + old_filter = evsel->filter; + at = strchr(old_filter, '@'); + if (!at) + return; + + /* + * See perf_event_set_filter(). Length of a valid filter is + * limited by PAGE_SIZE. + */ + new_filter = malloc(PAGE_SIZE); + if (!new_filter) { + fprintf(stderr, "No enough memory for post proc filter '%s'\n", + old_filter); + return; + } + *new_filter = '\0'; + space = PAGE_SIZE - 1; + + while (1) { + if (at) + *at = '\0'; + strncat(new_filter, old_filter, space); + space -= strlen(old_filter); + if (space < 0) + goto errout; + if (!at) + break; + *at = '@'; + + sep = strchr(at + 1, ' '); + if (sep) + *sep = '\0'; + + if (postproc_filter_append_token(at + 1, new_filter, &space)) + goto errout; + + if (!sep) + break; + *sep = ' '; + + old_filter = sep; + at = strchr(old_filter, '@'); + } + + free(evsel->filter); + /* + * It is safe to use new_filter directly. However, try to + * release some memory by strdup() a smaller string and free + * new_filter, which takes a full page. + */ + evsel->filter = strdup(new_filter); + if (!evsel->filter) + evsel->filter = new_filter; + else + free(new_filter); + return; +errout: + if (at) + *at = '@'; + if (sep) + *sep = ' '; + fprintf(stderr, "Can't post proc filter '%s'\n", evsel->filter); + free(new_filter); +} + int parse_filter(const struct option *opt, const char *str, int unset __maybe_unused) { @@ -1196,6 +1291,7 @@ int parse_filter(const struct option *opt, const char *str, return -1; } + postproc_filter(last); return 0; } -- 1.8.3.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/