From nobody Wed Jul 1 21:44:16 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 929D7C433F5 for ; Wed, 15 Dec 2021 18:52:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344004AbhLOSwE (ORCPT ); Wed, 15 Dec 2021 13:52:04 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56222 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239049AbhLOSv7 (ORCPT ); Wed, 15 Dec 2021 13:51:59 -0500 Received: from mail-pl1-x636.google.com (mail-pl1-x636.google.com [IPv6:2607:f8b0:4864:20::636]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 076D3C061574 for ; Wed, 15 Dec 2021 10:51:59 -0800 (PST) Received: by mail-pl1-x636.google.com with SMTP id u11so17282579plf.3 for ; Wed, 15 Dec 2021 10:51:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=njr+cYO7xEG0qBkZ/YmHt6HYhJLzs7sEC9t03EpurCA=; b=dCDQ8kWFXlc0N7qfukRib3fou4QHLj/5kM/EJZPYLQp5AuthvNDDS7unLV6CW3E+79 mz0tc0Sq+EP1pROs/sAiKjXUoFFsZtBendfDsoJUu3HyDPsFIzq+e66z/0UyiatuDiMX Zy68QbXKztccQv8YmtCEyb2qZ0XFGQ05hENcILJ900TqDEDQMYomJdxzTMpIIzB0Psov Tw9jw180jtLUxc3kP1xgezYjhCutZMx1TLAWkg48qGs81eUyVR5u9EknH3t7rynsueKx PQAOKLYDikAo0ybIYYVxZPASfVHlMWJMumZfCpZY9C6MY0CHvZlHi5aNiDG5LIhvjNBL LBqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=njr+cYO7xEG0qBkZ/YmHt6HYhJLzs7sEC9t03EpurCA=; b=wZ6UtoiUcyWZSToBxHSiuC0sXgeSum9NCJ+2XUb/RwRlL5SyArpP7d8Bo+ojsH6GMu MgZqywKRtlUs2tiWJuuo1CWNpVOC6SldWWgqz9uurvQt2UbtvYqykD4ofXnngNO+1hrs vdoumwDOtlyyFBQGWWuA5befHZMVXYVO8Ps08E9Vpgo4xQ3Q+dMOxq5jsR6d/T5E7Ts8 v7wIM3DecZSH+DC4jh6F1F+Nkq67HSA4Quq7y5QumK1flxWnk+2NuxO2t1UEoU9tUe+a cbT11gO8Fe6gGr55UuoRaiEHOBlTltJKaT1YTrp0u/Q6VN4scs4Ybrhvr2WZL/lR/Aj1 sb7w== X-Gm-Message-State: AOAM531EqjtWE0GAB96qoGLF5G0TQRgpQYh8IBC0+JgRbYnEvGFLqm6w 8zyDmZ1PEoNNaiM/XXaMQ20= X-Google-Smtp-Source: ABdhPJxWRHc2kwQCDfdoISuiDHm0Dth+7/x/QOIXQ59icPaUp5Kj1BAx6aoQdJDgh64C3NdJ/yzArA== X-Received: by 2002:a17:90b:4f83:: with SMTP id qe3mr1309127pjb.56.1639594318545; Wed, 15 Dec 2021 10:51:58 -0800 (PST) Received: from balhae.hsd1.ca.comcast.net ([2601:647:4800:5800:b969:356c:bdef:8748]) by smtp.gmail.com with ESMTPSA id f2sm3646428pfe.132.2021.12.15.10.51.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Dec 2021 10:51:57 -0800 (PST) Sender: Namhyung Kim From: Namhyung Kim To: Arnaldo Carvalho de Melo , Jiri Olsa Cc: Ingo Molnar , Peter Zijlstra , LKML , Andi Kleen , Ian Rogers , Changbin Du , Song Liu , Athira Rajeev , Stephane Eranian , Arnaldo Carvalho de Melo Subject: [PATCH 1/5] perf ftrace: Add 'trace' subcommand Date: Wed, 15 Dec 2021 10:51:50 -0800 Message-Id: <20211215185154.360314-2-namhyung@kernel.org> X-Mailer: git-send-email 2.34.1.173.g76aa8bc2d0-goog In-Reply-To: <20211215185154.360314-1-namhyung@kernel.org> References: <20211215185154.360314-1-namhyung@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This is a preparation to add more sub-commands for ftrace. The 'trace' subcommand does the same thing when no subcommand is given. Committer testing: The previous mode, i.e. no subcommand and the new 'perf ftrace trace' are equivalent: # perf ftrace -G check_preempt_curr sleep 0.00001 # tracer: function_graph # # CPU DURATION FUNCTION CALLS # | | | | | | | 25) | check_preempt_curr() { 25) | resched_curr() { 25) | native_smp_send_reschedule() { 25) | default_send_IPI_single_phys() { 25) 0.110 us | __default_send_IPI_dest_field(); 25) 0.490 us | } 25) 0.640 us | } 25) 0.850 us | } 25) 2.060 us | } # perf ftrace trace -G check_preempt_curr sleep 0.00001 # tracer: function_graph # # CPU DURATION FUNCTION CALLS # | | | | | | | 10) | check_preempt_curr() { 10) | resched_curr() { 10) | native_smp_send_reschedule() { 10) | default_send_IPI_single_phys() { 10) 0.080 us | __default_send_IPI_dest_field(); 10) 0.460 us | } 10) 0.610 us | } 10) 0.830 us | } 10) 2.020 us | } # Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Andi Kleen Cc: Changbin Du Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Song Liu Cc: Stephane Eranian Link: https://lore.kernel.org/r/20211129231830.1117781-2-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-ftrace.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index 87cb11a7a3ee..b28e762c5d54 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -879,17 +879,7 @@ int cmd_ftrace(int argc, const char **argv) .tracer =3D DEFAULT_TRACER, .target =3D { .uid =3D UINT_MAX, }, }; - const char * const ftrace_usage[] =3D { - "perf ftrace [] []", - "perf ftrace [] -- []", - NULL - }; - const struct option ftrace_options[] =3D { - OPT_STRING('t', "tracer", &ftrace.tracer, "tracer", - "Tracer to use: function_graph(default) or function"), - OPT_CALLBACK_DEFAULT('F', "funcs", NULL, "[FILTER]", - "Show available functions to filter", - opt_list_avail_functions, "*"), + const struct option common_options[] =3D { OPT_STRING('p', "pid", &ftrace.target.pid, "pid", "Trace on existing process id"), /* TODO: Add short option -t after -t/--tracer can be removed. */ @@ -901,6 +891,14 @@ int cmd_ftrace(int argc, const char **argv) "System-wide collection from all CPUs"), OPT_STRING('C', "cpu", &ftrace.target.cpu_list, "cpu", "List of cpus to monitor"), + OPT_END() + }; + const struct option ftrace_options[] =3D { + OPT_STRING('t', "tracer", &ftrace.tracer, "tracer", + "Tracer to use: function_graph(default) or function"), + OPT_CALLBACK_DEFAULT('F', "funcs", NULL, "[FILTER]", + "Show available functions to filter", + opt_list_avail_functions, "*"), OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func", "Trace given functions using function tracer", parse_filter_func), @@ -923,7 +921,15 @@ int cmd_ftrace(int argc, const char **argv) "Trace children processes"), OPT_UINTEGER('D', "delay", &ftrace.initial_delay, "Number of milliseconds to wait before starting tracing after progr= am start"), - OPT_END() + OPT_PARENT(common_options), + }; + + const char * const ftrace_usage[] =3D { + "perf ftrace [] []", + "perf ftrace [] -- [] []", + "perf ftrace trace [] []", + "perf ftrace trace [] -- [] []", + NULL }; =20 INIT_LIST_HEAD(&ftrace.filters); @@ -935,6 +941,11 @@ int cmd_ftrace(int argc, const char **argv) if (ret < 0) return -1; =20 + if (argc > 1 && !strcmp(argv[1], "trace")) { + argc--; + argv++; + } + argc =3D parse_options(argc, argv, ftrace_options, ftrace_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (!argc && target__none(&ftrace.target)) --=20 2.34.1.173.g76aa8bc2d0-goog From nobody Wed Jul 1 21:44:16 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5638BC433F5 for ; Wed, 15 Dec 2021 18:52:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344022AbhLOSwH (ORCPT ); Wed, 15 Dec 2021 13:52:07 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56230 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344000AbhLOSwA (ORCPT ); Wed, 15 Dec 2021 13:52:00 -0500 Received: from mail-pj1-x1033.google.com (mail-pj1-x1033.google.com [IPv6:2607:f8b0:4864:20::1033]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 938EBC06173E for ; Wed, 15 Dec 2021 10:52:00 -0800 (PST) Received: by mail-pj1-x1033.google.com with SMTP id k6-20020a17090a7f0600b001ad9d73b20bso20129263pjl.3 for ; Wed, 15 Dec 2021 10:52:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=tow+Nc6EtPapuXOnqTsuFmvcP25mJfOCoP64WLyCgxo=; b=KddrVcFagg6SyW+/ypspkDVjoJ85Z+S2BlfwFGTOcdL+VqsMqYHkpoKc7e96oKwv5/ +u1m7YAG4A6tcEhlXqr00SBxXulkiwB+KcUKaAQhECKCkriHLaxrpLCx4uSv64SRPzS6 vZwp2948zC9GmENRCuOGdnVjG3d4rGsoALsqLEPhaVmlGiGeKJ5DTCE/rvP46YERLNAY 8aQT8Bhph89o1rqViHsHnRNbLZ+tmQ0/xPvXm4q/VCNxKIgZtUnxCy42K2lON02rZM4I 7cq2LUMntUYcofGk3T5sPIyYMaIJHjrNlNDl1n5hLhWjlGoSd+EIRB+9BGrb157enBrr aVUA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=tow+Nc6EtPapuXOnqTsuFmvcP25mJfOCoP64WLyCgxo=; b=x/rYLmFCyz9FvGbJa1X2xdwGn/bw3A+vsIsX8IMK5Y5DTmHnJKVxBzAxf1L1xEELa9 PjooGOeR2zSJ29FZpeeX3NM1OFKh1TwFT6nMaK4rhK2Qhcm1tWU//hUdxbHC+jYNXBTj AkpDmrsbwgtUXzO90qpvClmIlMe4UwrVbmiYnX/CyCebm49Agc66v7ldiwhsroJrIpOC KJZHGt1lPItd6f0igcfy4CnXfbYR+wLgZ32/z69mPdzvBUI2KyE8xzq+ZLseSMbK6C6U 5+UywGtEPVGCnvQlBGb/VBDZ7WqM29vyhy92ZhJr0P9oL5ZDwJipvw3hbH1G1cIdWGmX YpAw== X-Gm-Message-State: AOAM530vfIRrfxDbYYhLAuxhYvLDb0I8OGgtEENAcRS4oJC+1npdRpC1 nV+3cUo66tb29tWEFTyvLS4= X-Google-Smtp-Source: ABdhPJzDBqLJBNCNXf3sgdQxc6oRSil/aTSZEc0K8oy1X/Yx9zqWp8/W+s5EQO6zkCHM11b9sB4Orw== X-Received: by 2002:a17:90a:bc92:: with SMTP id x18mr65544pjr.130.1639594320116; Wed, 15 Dec 2021 10:52:00 -0800 (PST) Received: from balhae.hsd1.ca.comcast.net ([2601:647:4800:5800:b969:356c:bdef:8748]) by smtp.gmail.com with ESMTPSA id f2sm3646428pfe.132.2021.12.15.10.51.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Dec 2021 10:51:59 -0800 (PST) Sender: Namhyung Kim From: Namhyung Kim To: Arnaldo Carvalho de Melo , Jiri Olsa Cc: Ingo Molnar , Peter Zijlstra , LKML , Andi Kleen , Ian Rogers , Changbin Du , Song Liu , Athira Rajeev , Stephane Eranian , Arnaldo Carvalho de Melo Subject: [PATCH 2/5] perf ftrace: Move out common code from __cmd_ftrace Date: Wed, 15 Dec 2021 10:51:51 -0800 Message-Id: <20211215185154.360314-3-namhyung@kernel.org> X-Mailer: git-send-email 2.34.1.173.g76aa8bc2d0-goog In-Reply-To: <20211215185154.360314-1-namhyung@kernel.org> References: <20211215185154.360314-1-namhyung@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The signal setup code and evlist__prepare_workload() can be used for other subcommands. Let's move them out of the __cmd_ftrace(). Then it doesn't need to pass argc and argv. On the other hand, select_tracer() is specific to the 'trace' subcommand so it'd better moving it into the __cmd_ftrace(). Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Andi Kleen Cc: Changbin Du Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Song Liu Cc: Stephane Eranian Link: https://lore.kernel.org/r/20211129231830.1117781-3-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-ftrace.c | 63 +++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index b28e762c5d54..0f8310bd0e6c 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -565,7 +565,24 @@ static int set_tracing_options(struct perf_ftrace *ftr= ace) return 0; } =20 -static int __cmd_ftrace(struct perf_ftrace *ftrace, int argc, const char *= *argv) +static void select_tracer(struct perf_ftrace *ftrace) +{ + bool graph =3D !list_empty(&ftrace->graph_funcs) || + !list_empty(&ftrace->nograph_funcs); + bool func =3D !list_empty(&ftrace->filters) || + !list_empty(&ftrace->notrace); + + /* The function_graph has priority over function tracer. */ + if (graph) + ftrace->tracer =3D "function_graph"; + else if (func) + ftrace->tracer =3D "function"; + /* Otherwise, the default tracer is used. */ + + pr_debug("%s tracer is used\n", ftrace->tracer); +} + +static int __cmd_ftrace(struct perf_ftrace *ftrace) { char *trace_file; int trace_fd; @@ -586,10 +603,7 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, in= t argc, const char **argv) return -1; } =20 - signal(SIGINT, sig_handler); - signal(SIGUSR1, sig_handler); - signal(SIGCHLD, sig_handler); - signal(SIGPIPE, sig_handler); + select_tracer(ftrace); =20 if (reset_tracing_files(ftrace) < 0) { pr_err("failed to reset ftrace\n"); @@ -600,11 +614,6 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace, in= t argc, const char **argv) if (write_tracing_file("trace", "0") < 0) goto out; =20 - if (argc && evlist__prepare_workload(ftrace->evlist, &ftrace->target, arg= v, false, - ftrace__workload_exec_failed_signal) < 0) { - goto out; - } - if (set_tracing_options(ftrace) < 0) goto out_reset; =20 @@ -855,23 +864,6 @@ static int parse_graph_tracer_opts(const struct option= *opt, return 0; } =20 -static void select_tracer(struct perf_ftrace *ftrace) -{ - bool graph =3D !list_empty(&ftrace->graph_funcs) || - !list_empty(&ftrace->nograph_funcs); - bool func =3D !list_empty(&ftrace->filters) || - !list_empty(&ftrace->notrace); - - /* The function_graph has priority over function tracer. */ - if (graph) - ftrace->tracer =3D "function_graph"; - else if (func) - ftrace->tracer =3D "function"; - /* Otherwise, the default tracer is used. */ - - pr_debug("%s tracer is used\n", ftrace->tracer); -} - int cmd_ftrace(int argc, const char **argv) { int ret; @@ -937,6 +929,11 @@ int cmd_ftrace(int argc, const char **argv) INIT_LIST_HEAD(&ftrace.graph_funcs); INIT_LIST_HEAD(&ftrace.nograph_funcs); =20 + signal(SIGINT, sig_handler); + signal(SIGUSR1, sig_handler); + signal(SIGCHLD, sig_handler); + signal(SIGPIPE, sig_handler); + ret =3D perf_config(perf_ftrace_config, &ftrace); if (ret < 0) return -1; @@ -951,8 +948,6 @@ int cmd_ftrace(int argc, const char **argv) if (!argc && target__none(&ftrace.target)) ftrace.target.system_wide =3D true; =20 - select_tracer(&ftrace); - ret =3D target__validate(&ftrace.target); if (ret) { char errbuf[512]; @@ -972,7 +967,15 @@ int cmd_ftrace(int argc, const char **argv) if (ret < 0) goto out_delete_evlist; =20 - ret =3D __cmd_ftrace(&ftrace, argc, argv); + if (argc) { + ret =3D evlist__prepare_workload(ftrace.evlist, &ftrace.target, + argv, false, + ftrace__workload_exec_failed_signal); + if (ret < 0) + goto out_delete_evlist; + } + + ret =3D __cmd_ftrace(&ftrace); =20 out_delete_evlist: evlist__delete(ftrace.evlist); --=20 2.34.1.173.g76aa8bc2d0-goog From nobody Wed Jul 1 21:44:16 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1DC17C433EF for ; Wed, 15 Dec 2021 18:52:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344029AbhLOSwJ (ORCPT ); Wed, 15 Dec 2021 13:52:09 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56240 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344003AbhLOSwC (ORCPT ); Wed, 15 Dec 2021 13:52:02 -0500 Received: from mail-pf1-x435.google.com (mail-pf1-x435.google.com [IPv6:2607:f8b0:4864:20::435]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 42789C061574 for ; Wed, 15 Dec 2021 10:52:02 -0800 (PST) Received: by mail-pf1-x435.google.com with SMTP id k26so21473444pfp.10 for ; Wed, 15 Dec 2021 10:52:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=HLLgqQRB4m/HzoidgWHxX7MYOmskwUKQwoOfQEqn/wo=; b=IJHoMMzE3VU8/vJeAxgsprB0rEoSjlcIUbpOwGpiFB/r682iN9JMENEos8bh5voq+f NX+1co943dMh4xO6mfB1/WaYc1OGPIrSryNMXwP93g8dntISjWP2jQxB6uH/TzlX9h8w MWX7QJgwSWxBxEHLlj+2s9Jk7+wwT1ked/SFoLSqMEtJQymncFTyygTAN2U74CF/ni22 j8+r1/3aoxsHuW2n2NA9OA6KYCXGay7k3a9OJMX0JTZW+QUSrgUiFTkO4W4QxPIqdHZU IOFS5UaIobigKbIsBGg3S5fN3A1ZYNN9a33WFA7vAEI4Jmr0TmJ+Q44BsdYRtN81yklt k9wQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=HLLgqQRB4m/HzoidgWHxX7MYOmskwUKQwoOfQEqn/wo=; b=ty4+fh7/uCrvFOo6RktIDAvFq+il9wfx9O/mBiGJnei99AxgtffUmbkJM7XKr5Xkuz xWLsE+qBKoUdp9dOg23AZc1pmRl4QNFEaN5WnG4JgqRHwb+r0rK8Ehi3I16rR6Zl2lS1 sXff3KPnKg1yceY7aItUFlOPUz7K8DUGJkxyNM4As1QQpkU9VkbP0DDE9yvhv2uw+GmA Xgj2qAEMrOKqH68Onbz2b3ns4Jz3H5NSNB/gHCCZowW2lqayVniaG7JD5bMPXNI14LSM fw6NQgIUHbYyQZTY5PumoJBJug0Y4PRSYFNeno7xJlnyk0eIGS9QJDsEnC2jdJu00Bfd oBLw== X-Gm-Message-State: AOAM532bVxxuzIt94Ym7jntCE8ojvXYDK8dG33ytU9V4ZypgHrJ5qwEH MTNG6Hns9G7z7u9pSL5e/fM= X-Google-Smtp-Source: ABdhPJxH3+FFL8ImomRWIPGbRTHZuXSMV/QwDwPzSECEoqVtKNEonb3ZVTlTndtdKKYYaGFUU8yUZA== X-Received: by 2002:a05:6a00:811:b0:4af:d1c9:fa3f with SMTP id m17-20020a056a00081100b004afd1c9fa3fmr10376528pfk.21.1639594321724; Wed, 15 Dec 2021 10:52:01 -0800 (PST) Received: from balhae.hsd1.ca.comcast.net ([2601:647:4800:5800:b969:356c:bdef:8748]) by smtp.gmail.com with ESMTPSA id f2sm3646428pfe.132.2021.12.15.10.52.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Dec 2021 10:52:01 -0800 (PST) Sender: Namhyung Kim From: Namhyung Kim To: Arnaldo Carvalho de Melo , Jiri Olsa Cc: Ingo Molnar , Peter Zijlstra , LKML , Andi Kleen , Ian Rogers , Changbin Du , Song Liu , Athira Rajeev , Stephane Eranian , Arnaldo Carvalho de Melo Subject: [PATCH 3/5] perf ftrace: Add 'latency' subcommand Date: Wed, 15 Dec 2021 10:51:52 -0800 Message-Id: <20211215185154.360314-4-namhyung@kernel.org> X-Mailer: git-send-email 2.34.1.173.g76aa8bc2d0-goog In-Reply-To: <20211215185154.360314-1-namhyung@kernel.org> References: <20211215185154.360314-1-namhyung@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The perf ftrace latency is to get a histogram of function execution time. Users should give a function name using -T option. This is implemented using function_graph tracer with the given function only. And it parses the output to extract the time. $ sudo perf ftrace latency -a -T mutex_lock sleep 1 # DURATION | COUNT | GRAPH | 0 - 1 us | 4596 | ######################## | 1 - 2 us | 1680 | ######### | 2 - 4 us | 1106 | ##### | 4 - 8 us | 546 | ## | 8 - 16 us | 562 | ### | 16 - 32 us | 1 | | 32 - 64 us | 0 | | 64 - 128 us | 0 | | 128 - 256 us | 0 | | 256 - 512 us | 0 | | 512 - 1024 us | 0 | | 1 - 2 ms | 0 | | 2 - 4 ms | 0 | | 4 - 8 ms | 0 | | 8 - 16 ms | 0 | | 16 - 32 ms | 0 | | 32 - 64 ms | 0 | | 64 - 128 ms | 0 | | 128 - 256 ms | 0 | | 256 - 512 ms | 0 | | 512 - 1024 ms | 0 | | 1 - ... s | 0 | | Committer testing: Latency for the __handle_mm_fault kernel function, system wide for 1 second, see how one can go from the usual 'perf ftrace' output, now the same as for the 'perf ftrace trace' subcommand, to the new 'perf ftrace latency' subcommand: # perf ftrace -T __handle_mm_fault -a sleep 1 | wc -l 709 # perf ftrace -T __handle_mm_fault -a sleep 1 | wc -l 510 # perf ftrace -T __handle_mm_fault -a sleep 1 | head -20 # tracer: function # # entries-in-buffer/entries-written: 0/0 #P:32 # # TASK-PID CPU# TIMESTAMP FUNCTION # | | | | | perf-exec-1685104 [007] 90638.894613: __handle_mm_fault <-handle_= mm_fault perf-exec-1685104 [007] 90638.894620: __handle_mm_fault <-handle_= mm_fault perf-exec-1685104 [007] 90638.894622: __handle_mm_fault <-handle_= mm_fault perf-exec-1685104 [007] 90638.894635: __handle_mm_fault <-handle_= mm_fault perf-exec-1685104 [007] 90638.894688: __handle_mm_fault <-handle_= mm_fault perf-exec-1685104 [007] 90638.894702: __handle_mm_fault <-handle_= mm_fault perf-exec-1685104 [007] 90638.894714: __handle_mm_fault <-handle_= mm_fault perf-exec-1685104 [007] 90638.894728: __handle_mm_fault <-handle_= mm_fault perf-exec-1685104 [007] 90638.894740: __handle_mm_fault <-handle_= mm_fault perf-exec-1685104 [007] 90638.894751: __handle_mm_fault <-handle_= mm_fault sleep-1685104 [007] 90638.894962: __handle_mm_fault <-handle_= mm_fault sleep-1685104 [007] 90638.894977: __handle_mm_fault <-handle_= mm_fault sleep-1685104 [007] 90638.894983: __handle_mm_fault <-handle_= mm_fault sleep-1685104 [007] 90638.894995: __handle_mm_fault <-handle_= mm_fault # perf ftrace latency -T __handle_mm_fault -a sleep 1 # DURATION | COUNT | GRAPH = | 0 - 1 us | 125 | ###### = | 1 - 2 us | 249 | ############# = | 2 - 4 us | 455 | ######################## = | 4 - 8 us | 37 | # = | 8 - 16 us | 0 | = | 16 - 32 us | 0 | = | 32 - 64 us | 0 | = | 64 - 128 us | 0 | = | 128 - 256 us | 0 | = | 256 - 512 us | 0 | = | 512 - 1024 us | 0 | = | 1 - 2 ms | 0 | = | 2 - 4 ms | 0 | = | 4 - 8 ms | 0 | = | 8 - 16 ms | 0 | = | 16 - 32 ms | 0 | = | 32 - 64 ms | 0 | = | 64 - 128 ms | 0 | = | 128 - 256 ms | 0 | = | 256 - 512 ms | 0 | = | 512 - 1024 ms | 0 | = | 1 - ... s | 0 | = | # Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Andi Kleen Cc: Changbin Du Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Song Liu Cc: Stephane Eranian Link: https://lore.kernel.org/r/20211129231830.1117781-4-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-ftrace.c | 285 ++++++++++++++++++++++++++++++++++-- 1 file changed, 276 insertions(+), 9 deletions(-) diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index 0f8310bd0e6c..8fd3c9c44c69 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include #include #include =20 @@ -702,6 +704,224 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace) return (done && !workload_exec_errno) ? 0 : -1; } =20 +#define NUM_BUCKET 22 /* 20 + 2 (for outliers in both direction) */ + +static void make_histogram(int buckets[], char *buf, size_t len, char *lin= ebuf) +{ + char *p, *q; + char *unit; + double num; + int i; + + /* ensure NUL termination */ + buf[len] =3D '\0'; + + /* handle data line by line */ + for (p =3D buf; (q =3D strchr(p, '\n')) !=3D NULL; p =3D q + 1) { + *q =3D '\0'; + /* move it to the line buffer */ + strcat(linebuf, p); + + /* + * parse trace output to get function duration like in + * + * # tracer: function_graph + * # + * # CPU DURATION FUNCTION CALLS + * # | | | | | | | + * 1) + 10.291 us | do_filp_open(); + * 1) 4.889 us | do_filp_open(); + * 1) 6.086 us | do_filp_open(); + * + */ + if (linebuf[0] =3D=3D '#') + goto next; + + /* ignore CPU */ + p =3D strchr(linebuf, ')'); + if (p =3D=3D NULL) + p =3D linebuf; + + while (*p && !isdigit(*p) && (*p !=3D '|')) + p++; + + /* no duration */ + if (*p =3D=3D '\0' || *p =3D=3D '|') + goto next; + + num =3D strtod(p, &unit); + if (!unit || strncmp(unit, " us", 3)) + goto next; + + i =3D log2(num); + if (i < 0) + i =3D 0; + if (i >=3D NUM_BUCKET) + i =3D NUM_BUCKET - 1; + + buckets[i]++; + +next: + /* empty the line buffer for the next output */ + linebuf[0] =3D '\0'; + } + + /* preserve any remaining output (before newline) */ + strcat(linebuf, p); +} + +static void display_histogram(int buckets[]) +{ + int i; + int total =3D 0; + int bar_total =3D 46; /* to fit in 80 column */ + char bar[] =3D "###############################################"; + int bar_len; + + for (i =3D 0; i < NUM_BUCKET; i++) + total +=3D buckets[i]; + + if (total =3D=3D 0) { + printf("No data found\n"); + return; + } + + printf("# %14s | %10s | %-*s |\n", + " DURATION ", "COUNT", bar_total, "GRAPH"); + + bar_len =3D buckets[0] * bar_total / total; + printf(" %4d - %-4d %s | %10d | %.*s%*s |\n", + 0, 1, "us", buckets[0], bar_len, bar, bar_total - bar_len, ""); + + for (i =3D 1; i < NUM_BUCKET - 1; i++) { + int start =3D (1 << (i - 1)); + int stop =3D 1 << i; + const char *unit =3D "us"; + + if (start >=3D 1024) { + start >>=3D 10; + stop >>=3D 10; + unit =3D "ms"; + } + bar_len =3D buckets[i] * bar_total / total; + printf(" %4d - %-4d %s | %10d | %.*s%*s |\n", + start, stop, unit, buckets[i], bar_len, bar, + bar_total - bar_len, ""); + } + + bar_len =3D buckets[NUM_BUCKET - 1] * bar_total / total; + printf(" %4d - %-4s %s | %10d | %.*s%*s |\n", + 1, "...", " s", buckets[NUM_BUCKET - 1], bar_len, bar, + bar_total - bar_len, ""); + +} + +static int __cmd_latency(struct perf_ftrace *ftrace) +{ + char *trace_file; + int trace_fd; + char buf[4096]; + char line[256]; + struct pollfd pollfd =3D { + .events =3D POLLIN, + }; + int buckets[NUM_BUCKET] =3D { }; + + if (!(perf_cap__capable(CAP_PERFMON) || + perf_cap__capable(CAP_SYS_ADMIN))) { + pr_err("ftrace only works for %s!\n", +#ifdef HAVE_LIBCAP_SUPPORT + "users with the CAP_PERFMON or CAP_SYS_ADMIN capability" +#else + "root" +#endif + ); + return -1; + } + + if (reset_tracing_files(ftrace) < 0) { + pr_err("failed to reset ftrace\n"); + goto out; + } + + /* reset ftrace buffer */ + if (write_tracing_file("trace", "0") < 0) + goto out; + + if (set_tracing_options(ftrace) < 0) + goto out_reset; + + /* force to use the function_graph tracer to track duration */ + if (write_tracing_file("current_tracer", "function_graph") < 0) { + pr_err("failed to set current_tracer to function_graph\n"); + goto out_reset; + } + + trace_file =3D get_tracing_file("trace_pipe"); + if (!trace_file) { + pr_err("failed to open trace_pipe\n"); + goto out_reset; + } + + trace_fd =3D open(trace_file, O_RDONLY); + + put_tracing_file(trace_file); + + if (trace_fd < 0) { + pr_err("failed to open trace_pipe\n"); + goto out_reset; + } + + fcntl(trace_fd, F_SETFL, O_NONBLOCK); + pollfd.fd =3D trace_fd; + + if (write_tracing_file("tracing_on", "1") < 0) { + pr_err("can't enable tracing\n"); + goto out_close_fd; + } + + evlist__start_workload(ftrace->evlist); + + line[0] =3D '\0'; + while (!done) { + if (poll(&pollfd, 1, -1) < 0) + break; + + if (pollfd.revents & POLLIN) { + int n =3D read(trace_fd, buf, sizeof(buf) - 1); + if (n < 0) + break; + + make_histogram(buckets, buf, n, line); + } + } + + write_tracing_file("tracing_on", "0"); + + if (workload_exec_errno) { + const char *emsg =3D str_error_r(workload_exec_errno, buf, sizeof(buf)); + pr_err("workload failed: %s\n", emsg); + goto out_close_fd; + } + + /* read remaining buffer contents */ + while (true) { + int n =3D read(trace_fd, buf, sizeof(buf) - 1); + if (n <=3D 0) + break; + make_histogram(buckets, buf, n, line); + } + + display_histogram(buckets); + +out_close_fd: + close(trace_fd); +out_reset: + reset_tracing_files(ftrace); +out: + return (done && !workload_exec_errno) ? 0 : -1; +} + static int perf_ftrace_config(const char *var, const char *value, void *cb) { struct perf_ftrace *ftrace =3D cb; @@ -864,6 +1084,12 @@ static int parse_graph_tracer_opts(const struct optio= n *opt, return 0; } =20 +enum perf_ftrace_subcommand { + PERF_FTRACE_NONE, + PERF_FTRACE_TRACE, + PERF_FTRACE_LATENCY, +}; + int cmd_ftrace(int argc, const char **argv) { int ret; @@ -915,14 +1141,21 @@ int cmd_ftrace(int argc, const char **argv) "Number of milliseconds to wait before starting tracing after progr= am start"), OPT_PARENT(common_options), }; + const struct option latency_options[] =3D { + OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func", + "Show latency of given function", parse_filter_func), + OPT_PARENT(common_options), + }; + const struct option *options =3D ftrace_options; =20 const char * const ftrace_usage[] =3D { "perf ftrace [] []", "perf ftrace [] -- [] []", - "perf ftrace trace [] []", - "perf ftrace trace [] -- [] []", + "perf ftrace {trace|latency} [] []", + "perf ftrace {trace|latency} [] -- [] []", NULL }; + enum perf_ftrace_subcommand subcmd =3D PERF_FTRACE_NONE; =20 INIT_LIST_HEAD(&ftrace.filters); INIT_LIST_HEAD(&ftrace.notrace); @@ -938,15 +1171,29 @@ int cmd_ftrace(int argc, const char **argv) if (ret < 0) return -1; =20 - if (argc > 1 && !strcmp(argv[1], "trace")) { - argc--; - argv++; + if (argc > 1) { + if (!strcmp(argv[1], "trace")) { + subcmd =3D PERF_FTRACE_TRACE; + } else if (!strcmp(argv[1], "latency")) { + subcmd =3D PERF_FTRACE_LATENCY; + options =3D latency_options; + } + + if (subcmd !=3D PERF_FTRACE_NONE) { + argc--; + argv++; + } } + /* for backward compatibility */ + if (subcmd =3D=3D PERF_FTRACE_NONE) + subcmd =3D PERF_FTRACE_TRACE; =20 - argc =3D parse_options(argc, argv, ftrace_options, ftrace_usage, + argc =3D parse_options(argc, argv, options, ftrace_usage, PARSE_OPT_STOP_AT_NON_OPTION); - if (!argc && target__none(&ftrace.target)) - ftrace.target.system_wide =3D true; + if (argc < 0) { + ret =3D -EINVAL; + goto out_delete_filters; + } =20 ret =3D target__validate(&ftrace.target); if (ret) { @@ -975,7 +1222,27 @@ int cmd_ftrace(int argc, const char **argv) goto out_delete_evlist; } =20 - ret =3D __cmd_ftrace(&ftrace); + switch (subcmd) { + case PERF_FTRACE_TRACE: + if (!argc && target__none(&ftrace.target)) + ftrace.target.system_wide =3D true; + ret =3D __cmd_ftrace(&ftrace); + break; + case PERF_FTRACE_LATENCY: + if (list_empty(&ftrace.filters)) { + pr_err("Should provide a function to measure\n"); + parse_options_usage(ftrace_usage, options, "T", 1); + ret =3D -EINVAL; + goto out_delete_evlist; + } + ret =3D __cmd_latency(&ftrace); + break; + case PERF_FTRACE_NONE: + default: + pr_err("Invalid subcommand\n"); + ret =3D -EINVAL; + break; + } =20 out_delete_evlist: evlist__delete(ftrace.evlist); --=20 2.34.1.173.g76aa8bc2d0-goog From nobody Wed Jul 1 21:44:16 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 233C7C433EF for ; Wed, 15 Dec 2021 18:52:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344032AbhLOSwL (ORCPT ); Wed, 15 Dec 2021 13:52:11 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56250 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344007AbhLOSwE (ORCPT ); Wed, 15 Dec 2021 13:52:04 -0500 Received: from mail-pf1-x430.google.com (mail-pf1-x430.google.com [IPv6:2607:f8b0:4864:20::430]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2A024C061574 for ; Wed, 15 Dec 2021 10:52:04 -0800 (PST) Received: by mail-pf1-x430.google.com with SMTP id x131so21454533pfc.12 for ; Wed, 15 Dec 2021 10:52:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=tFjKLFuX4uaDelvgrdJKxyIkgdk1dtjYVwEUL39uS94=; b=cszCY2gqs7nCcyOKNKlcPEDyJn0HhKeCHDHbD1hIRRKlYZrH15E7q9+aryJ4YT25aG QLk8KTW9C4GoKTlNkM0JmSYiqUEDOknSQA/WcCCTszN/zI3HrANSV7UI5SVeHbooYUw6 sECk0T3BR1okobepObuD4Ch6499EJcVwyhWVu814eWyoTD+IkfvT5qwEaDtIujRBfDiZ 1NEfoV5JD+5TeMRf5FHpI9rHk7LV6OT7diYHYvcJiuUBY8TLfaSnQIjqegXeMKHawAxl OFBqebYciN8DP6f1bp7Q60gGTRw3tbd2YDPNvPQfDOgj1xSy5rnfOSQ1Pf6K3rFFZuNn WM/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=tFjKLFuX4uaDelvgrdJKxyIkgdk1dtjYVwEUL39uS94=; b=Kz3MCwWaoGq6UIOlz14/O1Gow61M6TsLQp4n0gtyNrQbriEUpJ2t0vKHRhLFW6TrMy cIkt0CwtH7bwGrWD0SnNkE9F656q3RhTL2l5PeJTcebpcIituNvBiFVtFEIXwspIyE3b dPNzMQWzc6nnlFb423MIGii84B+CO60Q2LWEaVNYDrpHQo6osjUToQ/eDhQHIsxp4+uJ gquZhUvT5Pw6Xre0iLf8jKW701JpzpWeRi5G9juIDyv6ntREW7GhBZIM/i8pXNTYPoJJ Gn/I1yMAZLsqIehSAofOR5+dxI/uGYi2vOVv8ol82FsC4YG98dQszaio6YbogVIDGL2H Zy9A== X-Gm-Message-State: AOAM532TRI2VWG21k4GAJ/rchvHbEOW/StDw4GCSBwhUYnJJ7SlnuHYE juFc4pPEA/ew47La58v03DE= X-Google-Smtp-Source: ABdhPJzeARkqxdEVFA8gQLu7eEwgECIytGIBDu2YcGD7WygEUKua/l0arrwAqqQHScatr9uioEU1cw== X-Received: by 2002:a05:6a00:c95:b0:49f:c8de:9ae7 with SMTP id a21-20020a056a000c9500b0049fc8de9ae7mr10262303pfv.30.1639594323550; Wed, 15 Dec 2021 10:52:03 -0800 (PST) Received: from balhae.hsd1.ca.comcast.net ([2601:647:4800:5800:b969:356c:bdef:8748]) by smtp.gmail.com with ESMTPSA id f2sm3646428pfe.132.2021.12.15.10.52.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Dec 2021 10:52:03 -0800 (PST) Sender: Namhyung Kim From: Namhyung Kim To: Arnaldo Carvalho de Melo , Jiri Olsa Cc: Ingo Molnar , Peter Zijlstra , LKML , Andi Kleen , Ian Rogers , Changbin Du , Song Liu , Athira Rajeev , Stephane Eranian , Arnaldo Carvalho de Melo Subject: [PATCH 4/5] perf ftrace: Add -b/--use-bpf option for latency subcommand Date: Wed, 15 Dec 2021 10:51:53 -0800 Message-Id: <20211215185154.360314-5-namhyung@kernel.org> X-Mailer: git-send-email 2.34.1.173.g76aa8bc2d0-goog In-Reply-To: <20211215185154.360314-1-namhyung@kernel.org> References: <20211215185154.360314-1-namhyung@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The -b/--use-bpf option is to use BPF to get latency info of kernel functions. It'd have better performance impact and I observed that latency of same function is smaller than before when using BPF. Committer testing: # strace -e bpf perf ftrace latency -b -T __handle_mm_fault -a sleep 1 bpf(BPF_PROG_LOAD, {prog_type=3DBPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=3D2= , insns=3D0x7fff51914e00, license=3D"GPL", log_level=3D0, log_size=3D0, log= _buf=3DNULL, kern_version=3DKERNEL_VERSION(0, 0, 0), prog_flags=3D0, prog_n= ame=3D"", prog_ifindex=3D0, expected_attach_type=3DBPF_CGROUP_INET_INGRESS,= prog_btf_fd=3D0, func_info_rec_size=3D0, func_info=3DNULL, func_info_cnt= =3D0, line_info_rec_size=3D0, line_info=3DNULL, line_info_cnt=3D0, attach_b= tf_id=3D0, attach_prog_fd=3D0}, 128) =3D 3 bpf(BPF_BTF_LOAD, {btf=3D"\237\353\1\0\30\0\0\0\0\0\0\0\20\0\0\0\20\0\0\0= \5\0\0\0\1\0\0\0\0\0\0\1"..., btf_log_buf=3DNULL, btf_size=3D45, btf_log_si= ze=3D0, btf_log_level=3D0}, 128) =3D 3 bpf(BPF_BTF_LOAD, {btf=3D"\237\353\1\0\30\0\0\0\0\0\0\0000\0\0\0000\0\0\0= \t\0\0\0\1\0\0\0\0\0\0\1"..., btf_log_buf=3DNULL, btf_size=3D81, btf_log_si= ze=3D0, btf_log_level=3D0}, 128) =3D 3 bpf(BPF_BTF_LOAD, {btf=3D"\237\353\1\0\30\0\0\0\0\0\0\08\0\0\08\0\0\0\t\0= \0\0\0\0\0\0\0\0\0\1"..., btf_log_buf=3DNULL, btf_size=3D89, btf_log_size= =3D0, btf_log_level=3D0}, 128) =3D 3 bpf(BPF_BTF_LOAD, {btf=3D"\237\353\1\0\30\0\0\0\0\0\0\0\f\0\0\0\f\0\0\0\7= \0\0\0\1\0\0\0\0\0\0\20"..., btf_log_buf=3DNULL, btf_size=3D43, btf_log_siz= e=3D0, btf_log_level=3D0}, 128) =3D 3 bpf(BPF_BTF_LOAD, {btf=3D"\237\353\1\0\30\0\0\0\0\0\0\0000\0\0\0000\0\0\0= \t\0\0\0\1\0\0\0\0\0\0\1"..., btf_log_buf=3DNULL, btf_size=3D81, btf_log_si= ze=3D0, btf_log_level=3D0}, 128) =3D 3 bpf(BPF_BTF_LOAD, {btf=3D"\237\353\1\0\30\0\0\0\0\0\0\0000\0\0\0000\0\0\0= \5\0\0\0\0\0\0\0\0\0\0\1"..., btf_log_buf=3DNULL, btf_size=3D77, btf_log_si= ze=3D0, btf_log_level=3D0}, 128) =3D -1 EINVAL (Invalid argument) bpf(BPF_BTF_LOAD, {btf=3D"\237\353\1\0\30\0\0\0\0\0\0\0\350\2\0\0\350\2\0= \0\353\2\0\0\0\0\0\0\0\0\0\2"..., btf_log_buf=3DNULL, btf_size=3D1515, btf_= log_size=3D0, btf_log_level=3D0}, 128) =3D 3 bpf(BPF_MAP_CREATE, {map_type=3DBPF_MAP_TYPE_ARRAY, key_size=3D4, value_s= ize=3D32, max_entries=3D1, map_flags=3D0, inner_map_fd=3D0, map_name=3D"", = map_ifindex=3D0, btf_fd=3D0, btf_key_type_id=3D0, btf_value_type_id=3D0, bt= f_vmlinux_value_type_id=3D0}, 128) =3D 4 bpf(BPF_PROG_LOAD, {prog_type=3DBPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=3D5= , insns=3D0x7fff51914c30, license=3D"GPL", log_level=3D0, log_size=3D0, log= _buf=3DNULL, kern_version=3DKERNEL_VERSION(0, 0, 0), prog_flags=3D0, prog_n= ame=3D"", prog_ifindex=3D0, expected_attach_type=3DBPF_CGROUP_INET_INGRESS,= prog_btf_fd=3D0, func_info_rec_size=3D0, func_info=3DNULL, func_info_cnt= =3D0, line_info_rec_size=3D0, line_info=3DNULL, line_info_cnt=3D0, attach_b= tf_id=3D0, attach_prog_fd=3D0}, 128) =3D 5 bpf(BPF_MAP_CREATE, {map_type=3DBPF_MAP_TYPE_ARRAY, key_size=3D4, value_s= ize=3D4, max_entries=3D1, map_flags=3DBPF_F_MMAPABLE, inner_map_fd=3D0, map= _name=3D"", map_ifindex=3D0, btf_fd=3D0, btf_key_type_id=3D0, btf_value_typ= e_id=3D0, btf_vmlinux_value_type_id=3D0}, 128) =3D 4 bpf(BPF_PROG_LOAD, {prog_type=3DBPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=3D2= , insns=3D0x7fff51914a80, license=3D"GPL", log_level=3D0, log_size=3D0, log= _buf=3DNULL, kern_version=3DKERNEL_VERSION(0, 0, 0), prog_flags=3D0, prog_n= ame=3D"test", prog_ifindex=3D0, expected_attach_type=3DBPF_CGROUP_INET_INGR= ESS, prog_btf_fd=3D0, func_info_rec_size=3D0, func_info=3DNULL, func_info_c= nt=3D0, line_info_rec_size=3D0, line_info=3DNULL, line_info_cnt=3D0, attach= _btf_id=3D0, attach_prog_fd=3D0}, 128) =3D 4 bpf(BPF_MAP_CREATE, {map_type=3DBPF_MAP_TYPE_HASH, key_size=3D8, value_si= ze=3D8, max_entries=3D10000, map_flags=3D0, inner_map_fd=3D0, map_name=3D"f= unctime", map_ifindex=3D0, btf_fd=3D3, btf_key_type_id=3D0, btf_value_type_= id=3D0, btf_vmlinux_value_type_id=3D0}, 128) =3D 4 bpf(BPF_MAP_CREATE, {map_type=3DBPF_MAP_TYPE_HASH, key_size=3D4, value_si= ze=3D1, max_entries=3D1, map_flags=3D0, inner_map_fd=3D0, map_name=3D"cpu_f= ilter", map_ifindex=3D0, btf_fd=3D3, btf_key_type_id=3D0, btf_value_type_id= =3D0, btf_vmlinux_value_type_id=3D0}, 128) =3D 5 bpf(BPF_MAP_CREATE, {map_type=3DBPF_MAP_TYPE_HASH, key_size=3D4, value_si= ze=3D1, max_entries=3D1, map_flags=3D0, inner_map_fd=3D0, map_name=3D"task_= filter", map_ifindex=3D0, btf_fd=3D3, btf_key_type_id=3D0, btf_value_type_i= d=3D0, btf_vmlinux_value_type_id=3D0}, 128) =3D 7 bpf(BPF_MAP_CREATE, {map_type=3DBPF_MAP_TYPE_PERCPU_ARRAY, key_size=3D4, = value_size=3D8, max_entries=3D22, map_flags=3D0, inner_map_fd=3D0, map_name= =3D"latency", map_ifindex=3D0, btf_fd=3D3, btf_key_type_id=3D0, btf_value_t= ype_id=3D0, btf_vmlinux_value_type_id=3D0}, 128) =3D 8 bpf(BPF_MAP_CREATE, {map_type=3DBPF_MAP_TYPE_ARRAY, key_size=3D4, value_s= ize=3D4, max_entries=3D1, map_flags=3DBPF_F_MMAPABLE, inner_map_fd=3D0, map= _name=3D"func_lat.bss", map_ifindex=3D0, btf_fd=3D3, btf_key_type_id=3D0, b= tf_value_type_id=3D30, btf_vmlinux_value_type_id=3D0}, 128) =3D 9 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D9, key=3D0x7fff51914c40, value=3D0x7f6= e99be2000, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_PROG_LOAD, {prog_type=3DBPF_PROG_TYPE_KPROBE, insn_cnt=3D18, insn= s=3D0x11e4160, license=3D"", log_level=3D0, log_size=3D0, log_buf=3DNULL, k= ern_version=3DKERNEL_VERSION(5, 14, 16), prog_flags=3D0, prog_name=3D"func_= begin", prog_ifindex=3D0, expected_attach_type=3DBPF_CGROUP_INET_INGRESS, p= rog_btf_fd=3D3, func_info_rec_size=3D8, func_info=3D0x11dfc50, func_info_cn= t=3D1, line_info_rec_size=3D16, line_info=3D0x11e04c0, line_info_cnt=3D9, a= ttach_btf_id=3D0, attach_prog_fd=3D0}, 128) =3D 10 bpf(BPF_PROG_LOAD, {prog_type=3DBPF_PROG_TYPE_KPROBE, insn_cnt=3D99, insn= s=3D0x11ded70, license=3D"", log_level=3D0, log_size=3D0, log_buf=3DNULL, k= ern_version=3DKERNEL_VERSION(5, 14, 16), prog_flags=3D0, prog_name=3D"func_= end", prog_ifindex=3D0, expected_attach_type=3DBPF_CGROUP_INET_INGRESS, pro= g_btf_fd=3D3, func_info_rec_size=3D8, func_info=3D0x11dfc70, func_info_cnt= =3D1, line_info_rec_size=3D16, line_info=3D0x11f6e10, line_info_cnt=3D20, a= ttach_btf_id=3D0, attach_prog_fd=3D0}, 128) =3D 11 bpf(BPF_PROG_LOAD, {prog_type=3DBPF_PROG_TYPE_TRACEPOINT, insn_cnt=3D2, i= nsns=3D0x7fff51914a80, license=3D"GPL", log_level=3D0, log_size=3D0, log_bu= f=3DNULL, kern_version=3DKERNEL_VERSION(0, 0, 0), prog_flags=3D0, prog_name= =3D"", prog_ifindex=3D0, expected_attach_type=3DBPF_CGROUP_INET_INGRESS, pr= og_btf_fd=3D0, func_info_rec_size=3D0, func_info=3DNULL, func_info_cnt=3D0,= line_info_rec_size=3D0, line_info=3DNULL, line_info_cnt=3D0, attach_btf_id= =3D0, attach_prog_fd=3D0}, 128) =3D 13 bpf(BPF_LINK_CREATE, {link_create=3D{prog_fd=3D13, target_fd=3D-1, attach= _type=3D0x29 /* BPF_??? */, flags=3D0}}, 128) =3D -1 EINVAL (Invalid argume= nt) --- SIGCHLD {si_signo=3DSIGCHLD, si_code=3DCLD_EXITED, si_pid=3D1699992, = si_uid=3D0, si_status=3D0, si_utime=3D0, si_stime=3D0} --- bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_LOOKUP_ELEM, {map_fd=3D8, key=3D0x7fff51914f84, value=3D0x11f= 6fa0, flags=3DBPF_ANY}, 128) =3D 0 # DURATION | COUNT | GRAPH = | 0 - 1 us | 52 | ################### = | 1 - 2 us | 36 | ############# = | 2 - 4 us | 24 | ######### = | 4 - 8 us | 7 | ## = | 8 - 16 us | 1 | = | 16 - 32 us | 0 | = | 32 - 64 us | 0 | = | 64 - 128 us | 0 | = | 128 - 256 us | 0 | = | 256 - 512 us | 0 | = | 512 - 1024 us | 0 | = | 1 - 2 ms | 0 | = | 2 - 4 ms | 0 | = | 4 - 8 ms | 0 | = | 8 - 16 ms | 0 | = | 16 - 32 ms | 0 | = | 32 - 64 ms | 0 | = | 64 - 128 ms | 0 | = | 128 - 256 ms | 0 | = | 256 - 512 ms | 0 | = | 512 - 1024 ms | 0 | = | 1 - ... s | 0 | = | +++ exited with 0 +++ # Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Andi Kleen Cc: Changbin Du Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Song Liu Cc: Stephane Eranian Link: https://lore.kernel.org/r/20211129231830.1117781-5-namhyung@kernel.org [ Add missing util/cpumap.h include and removed unused 'fd' variable ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile.perf | 2 +- tools/perf/builtin-ftrace.c | 158 ++++++++++++-------- tools/perf/util/Build | 1 + tools/perf/util/bpf_ftrace.c | 112 ++++++++++++++ tools/perf/util/bpf_skel/func_latency.bpf.c | 93 ++++++++++++ tools/perf/util/ftrace.h | 81 ++++++++++ 6 files changed, 380 insertions(+), 67 deletions(-) create mode 100644 tools/perf/util/bpf_ftrace.c create mode 100644 tools/perf/util/bpf_skel/func_latency.bpf.c create mode 100644 tools/perf/util/ftrace.h diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 164a37523781..ac861e42c8f7 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -1041,7 +1041,7 @@ SKEL_OUT :=3D $(abspath $(OUTPUT)util/bpf_skel) SKEL_TMP_OUT :=3D $(abspath $(SKEL_OUT)/.tmp) SKELETONS :=3D $(SKEL_OUT)/bpf_prog_profiler.skel.h SKELETONS +=3D $(SKEL_OUT)/bperf_leader.skel.h $(SKEL_OUT)/bperf_follower.= skel.h -SKELETONS +=3D $(SKEL_OUT)/bperf_cgroup.skel.h +SKELETONS +=3D $(SKEL_OUT)/bperf_cgroup.skel.h $(SKEL_OUT)/func_latency.sk= el.h =20 $(SKEL_TMP_OUT) $(LIBBPF_OUTPUT): $(Q)$(MKDIR) -p $@ diff --git a/tools/perf/builtin-ftrace.c b/tools/perf/builtin-ftrace.c index 8fd3c9c44c69..2b54e2ddc80a 100644 --- a/tools/perf/builtin-ftrace.c +++ b/tools/perf/builtin-ftrace.c @@ -30,36 +30,12 @@ #include "strfilter.h" #include "util/cap.h" #include "util/config.h" +#include "util/ftrace.h" #include "util/units.h" #include "util/parse-sublevel-options.h" =20 #define DEFAULT_TRACER "function_graph" =20 -struct perf_ftrace { - struct evlist *evlist; - struct target target; - const char *tracer; - struct list_head filters; - struct list_head notrace; - struct list_head graph_funcs; - struct list_head nograph_funcs; - int graph_depth; - unsigned long percpu_buffer_size; - bool inherit; - int func_stack_trace; - int func_irq_info; - int graph_nosleep_time; - int graph_noirqs; - int graph_verbose; - int graph_thresh; - unsigned int initial_delay; -}; - -struct filter_entry { - struct list_head list; - char name[]; -}; - static volatile int workload_exec_errno; static bool done; =20 @@ -704,8 +680,6 @@ static int __cmd_ftrace(struct perf_ftrace *ftrace) return (done && !workload_exec_errno) ? 0 : -1; } =20 -#define NUM_BUCKET 22 /* 20 + 2 (for outliers in both direction) */ - static void make_histogram(int buckets[], char *buf, size_t len, char *lin= ebuf) { char *p, *q; @@ -816,69 +790,116 @@ static void display_histogram(int buckets[]) =20 } =20 -static int __cmd_latency(struct perf_ftrace *ftrace) +static int prepare_func_latency(struct perf_ftrace *ftrace) { char *trace_file; - int trace_fd; - char buf[4096]; - char line[256]; - struct pollfd pollfd =3D { - .events =3D POLLIN, - }; - int buckets[NUM_BUCKET] =3D { }; + int fd; =20 - if (!(perf_cap__capable(CAP_PERFMON) || - perf_cap__capable(CAP_SYS_ADMIN))) { - pr_err("ftrace only works for %s!\n", -#ifdef HAVE_LIBCAP_SUPPORT - "users with the CAP_PERFMON or CAP_SYS_ADMIN capability" -#else - "root" -#endif - ); - return -1; - } + if (ftrace->target.use_bpf) + return perf_ftrace__latency_prepare_bpf(ftrace); =20 if (reset_tracing_files(ftrace) < 0) { pr_err("failed to reset ftrace\n"); - goto out; + return -1; } =20 /* reset ftrace buffer */ if (write_tracing_file("trace", "0") < 0) - goto out; + return -1; =20 if (set_tracing_options(ftrace) < 0) - goto out_reset; + return -1; =20 /* force to use the function_graph tracer to track duration */ if (write_tracing_file("current_tracer", "function_graph") < 0) { pr_err("failed to set current_tracer to function_graph\n"); - goto out_reset; + return -1; } =20 trace_file =3D get_tracing_file("trace_pipe"); if (!trace_file) { pr_err("failed to open trace_pipe\n"); - goto out_reset; + return -1; } =20 - trace_fd =3D open(trace_file, O_RDONLY); + fd =3D open(trace_file, O_RDONLY); + if (fd < 0) + pr_err("failed to open trace_pipe\n"); =20 put_tracing_file(trace_file); + return fd; +} =20 - if (trace_fd < 0) { - pr_err("failed to open trace_pipe\n"); - goto out_reset; +static int start_func_latency(struct perf_ftrace *ftrace) +{ + if (ftrace->target.use_bpf) + return perf_ftrace__latency_start_bpf(ftrace); + + if (write_tracing_file("tracing_on", "1") < 0) { + pr_err("can't enable tracing\n"); + return -1; } =20 + return 0; +} + +static int stop_func_latency(struct perf_ftrace *ftrace) +{ + if (ftrace->target.use_bpf) + return perf_ftrace__latency_stop_bpf(ftrace); + + write_tracing_file("tracing_on", "0"); + return 0; +} + +static int read_func_latency(struct perf_ftrace *ftrace, int buckets[]) +{ + if (ftrace->target.use_bpf) + return perf_ftrace__latency_read_bpf(ftrace, buckets); + + return 0; +} + +static int cleanup_func_latency(struct perf_ftrace *ftrace) +{ + if (ftrace->target.use_bpf) + return perf_ftrace__latency_cleanup_bpf(ftrace); + + reset_tracing_files(ftrace); + return 0; +} + +static int __cmd_latency(struct perf_ftrace *ftrace) +{ + int trace_fd; + char buf[4096]; + char line[256]; + struct pollfd pollfd =3D { + .events =3D POLLIN, + }; + int buckets[NUM_BUCKET] =3D { }; + + if (!(perf_cap__capable(CAP_PERFMON) || + perf_cap__capable(CAP_SYS_ADMIN))) { + pr_err("ftrace only works for %s!\n", +#ifdef HAVE_LIBCAP_SUPPORT + "users with the CAP_PERFMON or CAP_SYS_ADMIN capability" +#else + "root" +#endif + ); + return -1; + } + + trace_fd =3D prepare_func_latency(ftrace); + if (trace_fd < 0) + goto out; + fcntl(trace_fd, F_SETFL, O_NONBLOCK); pollfd.fd =3D trace_fd; =20 - if (write_tracing_file("tracing_on", "1") < 0) { - pr_err("can't enable tracing\n"); - goto out_close_fd; - } + if (start_func_latency(ftrace) < 0) + goto out; =20 evlist__start_workload(ftrace->evlist); =20 @@ -896,29 +917,30 @@ static int __cmd_latency(struct perf_ftrace *ftrace) } } =20 - write_tracing_file("tracing_on", "0"); + stop_func_latency(ftrace); =20 if (workload_exec_errno) { const char *emsg =3D str_error_r(workload_exec_errno, buf, sizeof(buf)); pr_err("workload failed: %s\n", emsg); - goto out_close_fd; + goto out; } =20 /* read remaining buffer contents */ - while (true) { + while (!ftrace->target.use_bpf) { int n =3D read(trace_fd, buf, sizeof(buf) - 1); if (n <=3D 0) break; make_histogram(buckets, buf, n, line); } =20 + read_func_latency(ftrace, buckets); + display_histogram(buckets); =20 -out_close_fd: - close(trace_fd); -out_reset: - reset_tracing_files(ftrace); out: + close(trace_fd); + cleanup_func_latency(ftrace); + return (done && !workload_exec_errno) ? 0 : -1; } =20 @@ -1144,6 +1166,10 @@ int cmd_ftrace(int argc, const char **argv) const struct option latency_options[] =3D { OPT_CALLBACK('T', "trace-funcs", &ftrace.filters, "func", "Show latency of given function", parse_filter_func), +#ifdef HAVE_BPF_SKEL + OPT_BOOLEAN('b', "use-bpf", &ftrace.target.use_bpf, + "Use BPF to measure function latency"), +#endif OPT_PARENT(common_options), }; const struct option *options =3D ftrace_options; diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 2e5bfbb69960..294b12430d73 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -144,6 +144,7 @@ perf-$(CONFIG_LIBBPF) +=3D bpf-loader.o perf-$(CONFIG_LIBBPF) +=3D bpf_map.o perf-$(CONFIG_PERF_BPF_SKEL) +=3D bpf_counter.o perf-$(CONFIG_PERF_BPF_SKEL) +=3D bpf_counter_cgroup.o +perf-$(CONFIG_PERF_BPF_SKEL) +=3D bpf_ftrace.o perf-$(CONFIG_BPF_PROLOGUE) +=3D bpf-prologue.o perf-$(CONFIG_LIBELF) +=3D symbol-elf.o perf-$(CONFIG_LIBELF) +=3D probe-file.o diff --git a/tools/perf/util/bpf_ftrace.c b/tools/perf/util/bpf_ftrace.c new file mode 100644 index 000000000000..ec4e2f5a2fc4 --- /dev/null +++ b/tools/perf/util/bpf_ftrace.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include + +#include + +#include "util/ftrace.h" +#include "util/cpumap.h" +#include "util/debug.h" +#include "util/bpf_counter.h" + +#include "util/bpf_skel/func_latency.skel.h" + +static struct func_latency_bpf *skel; + +int perf_ftrace__latency_prepare_bpf(struct perf_ftrace *ftrace) +{ + int err; + struct filter_entry *func; + + if (!list_is_singular(&ftrace->filters)) { + pr_err("ERROR: %s target function(s).\n", + list_empty(&ftrace->filters) ? "No" : "Too many"); + return -1; + } + + func =3D list_first_entry(&ftrace->filters, struct filter_entry, list); + + skel =3D func_latency_bpf__open(); + if (!skel) { + pr_err("Failed to open func latency skeleton\n"); + return -1; + } + + set_max_rlimit(); + + err =3D func_latency_bpf__load(skel); + if (err) { + pr_err("Failed to load func latency skeleton\n"); + goto out; + } + + skel->links.func_begin =3D bpf_program__attach_kprobe(skel->progs.func_be= gin, + false, func->name); + if (IS_ERR(skel->links.func_begin)) { + pr_err("Failed to attach fentry program\n"); + err =3D PTR_ERR(skel->links.func_begin); + goto out; + } + + skel->links.func_end =3D bpf_program__attach_kprobe(skel->progs.func_end, + true, func->name); + if (IS_ERR(skel->links.func_end)) { + pr_err("Failed to attach fexit program\n"); + err =3D PTR_ERR(skel->links.func_end); + goto out; + } + + /* XXX: we don't actually use this fd - just for poll() */ + return open("/dev/null", O_RDONLY); + +out: + return err; +} + +int perf_ftrace__latency_start_bpf(struct perf_ftrace *ftrace __maybe_unus= ed) +{ + skel->bss->enabled =3D 1; + return 0; +} + +int perf_ftrace__latency_stop_bpf(struct perf_ftrace *ftrace __maybe_unuse= d) +{ + skel->bss->enabled =3D 0; + return 0; +} + +int perf_ftrace__latency_read_bpf(struct perf_ftrace *ftrace __maybe_unuse= d, + int buckets[]) +{ + int i, fd, err; + u32 idx; + u64 *hist; + int ncpus =3D cpu__max_cpu(); + + fd =3D bpf_map__fd(skel->maps.latency); + + hist =3D calloc(ncpus, sizeof(*hist)); + if (hist =3D=3D NULL) + return -ENOMEM; + + for (idx =3D 0; idx < NUM_BUCKET; idx++) { + err =3D bpf_map_lookup_elem(fd, &idx, hist); + if (err) { + buckets[idx] =3D 0; + continue; + } + + for (i =3D 0; i < ncpus; i++) + buckets[idx] +=3D hist[i]; + } + + free(hist); + return 0; +} + +int perf_ftrace__latency_cleanup_bpf(struct perf_ftrace *ftrace __maybe_un= used) +{ + func_latency_bpf__destroy(skel); + return 0; +} diff --git a/tools/perf/util/bpf_skel/func_latency.bpf.c b/tools/perf/util/= bpf_skel/func_latency.bpf.c new file mode 100644 index 000000000000..ccd96b09fc42 --- /dev/null +++ b/tools/perf/util/bpf_skel/func_latency.bpf.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +// Copyright (c) 2021 Google +#include "vmlinux.h" +#include +#include + +// This should be in sync with "util/ftrace.h" +#define NUM_BUCKET 22 + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(__u64)); + __uint(value_size, sizeof(__u64)); + __uint(max_entries, 10000); +} functime SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(__u8)); + __uint(max_entries, 1); +} cpu_filter SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(__u8)); + __uint(max_entries, 1); +} task_filter SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); + __uint(key_size, sizeof(__u32)); + __uint(value_size, sizeof(__u64)); + __uint(max_entries, NUM_BUCKET); +} latency SEC(".maps"); + + +int enabled =3D 0; + +SEC("kprobe/func") +int BPF_PROG(func_begin) +{ + __u64 key, now; + + if (!enabled) + return 0; + + key =3D bpf_get_current_pid_tgid(); + now =3D bpf_ktime_get_ns(); + + // overwrite timestamp for nested functions + bpf_map_update_elem(&functime, &key, &now, BPF_ANY); + return 0; +} + +SEC("kretprobe/func") +int BPF_PROG(func_end) +{ + __u64 tid; + __u64 *start; + + if (!enabled) + return 0; + + tid =3D bpf_get_current_pid_tgid(); + + start =3D bpf_map_lookup_elem(&functime, &tid); + if (start) { + __s64 delta =3D bpf_ktime_get_ns() - *start; + __u32 key; + __u64 *hist; + + bpf_map_delete_elem(&functime, &tid); + + if (delta < 0) + return 0; + + // calculate index using delta in usec + for (key =3D 0; key < (NUM_BUCKET - 1); key++) { + if (delta < ((1000UL) << key)) + break; + } + + hist =3D bpf_map_lookup_elem(&latency, &key); + if (!hist) + return 0; + + *hist +=3D 1; + } + + return 0; +} diff --git a/tools/perf/util/ftrace.h b/tools/perf/util/ftrace.h new file mode 100644 index 000000000000..887f68a185f7 --- /dev/null +++ b/tools/perf/util/ftrace.h @@ -0,0 +1,81 @@ +#ifndef __PERF_FTRACE_H__ +#define __PERF_FTRACE_H__ + +#include + +#include "target.h" + +struct evlist; + +struct perf_ftrace { + struct evlist *evlist; + struct target target; + const char *tracer; + struct list_head filters; + struct list_head notrace; + struct list_head graph_funcs; + struct list_head nograph_funcs; + unsigned long percpu_buffer_size; + bool inherit; + int graph_depth; + int func_stack_trace; + int func_irq_info; + int graph_nosleep_time; + int graph_noirqs; + int graph_verbose; + int graph_thresh; + unsigned int initial_delay; +}; + +struct filter_entry { + struct list_head list; + char name[]; +}; + +#define NUM_BUCKET 22 /* 20 + 2 (for outliers in both direction) */ + +#ifdef HAVE_BPF_SKEL + +int perf_ftrace__latency_prepare_bpf(struct perf_ftrace *ftrace); +int perf_ftrace__latency_start_bpf(struct perf_ftrace *ftrace); +int perf_ftrace__latency_stop_bpf(struct perf_ftrace *ftrace); +int perf_ftrace__latency_read_bpf(struct perf_ftrace *ftrace, + int buckets[]); +int perf_ftrace__latency_cleanup_bpf(struct perf_ftrace *ftrace); + +#else /* !HAVE_BPF_SKEL */ + +static inline int +perf_ftrace__latency_prepare_bpf(struct perf_ftrace *ftrace __maybe_unused) +{ + return -1; +} + +static inline int +perf_ftrace__latency_start_bpf(struct perf_ftrace *ftrace __maybe_unused) +{ + return -1; +} + +static inline int +perf_ftrace__latency_stop_bpf(struct perf_ftrace *ftrace __maybe_unused) +{ + return -1; +} + +static inline int +perf_ftrace__latency_read_bpf(struct perf_ftrace *ftrace __maybe_unused, + int buckets[] __maybe_unused) +{ + return -1; +} + +static inline int +perf_ftrace__latency_cleanup_bpf(struct perf_ftrace *ftrace __maybe_unused) +{ + return -1; +} + +#endif /* HAVE_BPF_SKEL */ + +#endif /* __PERF_FTRACE_H__ */ --=20 2.34.1.173.g76aa8bc2d0-goog From nobody Wed Jul 1 21:44:16 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0E133C433FE for ; Wed, 15 Dec 2021 18:52:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343993AbhLOSwO (ORCPT ); Wed, 15 Dec 2021 13:52:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56258 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344011AbhLOSwG (ORCPT ); Wed, 15 Dec 2021 13:52:06 -0500 Received: from mail-pf1-x429.google.com (mail-pf1-x429.google.com [IPv6:2607:f8b0:4864:20::429]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DBB00C06173E for ; Wed, 15 Dec 2021 10:52:05 -0800 (PST) Received: by mail-pf1-x429.google.com with SMTP id o4so21449543pfp.13 for ; Wed, 15 Dec 2021 10:52:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=A1WPEmR1sEOp0zeMUyXARV/HVQt4jiuKOO4s7xu6v28=; b=A0xaTiKazcnyTUWtYVxHbPnA/vLgBwhGD8gJfRoFs3f0yKrlMuKA6bBSpQXmbxNMn2 oewv8DrHrpsZxuoGnarbV7qnJ0LjXZlCYCURsRPrKAeXuZODTrdjl0TCIeUXOaZtXNZl 0nvHGJiMU5yr5uRMrZINVYplQye+RqTUCZMkbYM4svJCDPvIejOvjXkFr0ojja1RZIko WL1DJ19QCJWbgqU0hzG9bxIY8268J+XoyS6U86BAUDXlPuxQQPBTjvKTuzjQlBVoGBRX tlDdrQCwJ4V1xOKyoSlcmy4B65hBu4fLlznfgcRPTK1k7aaaLpkUtvxsoYzvubIQUAHb Wo4Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=A1WPEmR1sEOp0zeMUyXARV/HVQt4jiuKOO4s7xu6v28=; b=7L7sHKuSfbqQxyvZ/KRBMqN93jWgmdtRsaXe3gVxdOjMfSofyundp+2Qz/qRWj34rE +9tCtJYI8Be1IUSA+B/zFnDLtLK5mL3JOQsdUSXP4T2DFIO6MkjmMf5kLRToV4uJBDVW lyNgr9yNZt7in8Ix2q6QIqIh30aQPHji9niaUye5DQ4NTaaS2vP1Te/WOzC9v8CRQ4VS PKktxT9orXfrAdbU7lFld/JWyY/n/tbxJeRhhL34VaUrRjo1HZoWJhv3oBL/WvDX3bYj XC678m6AOhJOoX3fRA0HeIcT4Ov7R8Lpv8mhsJS5mkdqR1pVAlvOlg9lYPDHlKT5N40/ l6Ag== X-Gm-Message-State: AOAM530fTVmCFaeiDUidBBSDdC7MKTOlrMITH+Ath9AdRa+/4SVs3EeI 9ypZ81vhTUWSVnYwlMRsuCI= X-Google-Smtp-Source: ABdhPJwAyajT03W3oUyFtUYuwpiBgOd9/+yk2D7NROjNhcE1rewXyMb2FLZwmDujnvWS7IUP+UDESQ== X-Received: by 2002:a63:a705:: with SMTP id d5mr8917279pgf.556.1639594325288; Wed, 15 Dec 2021 10:52:05 -0800 (PST) Received: from balhae.hsd1.ca.comcast.net ([2601:647:4800:5800:b969:356c:bdef:8748]) by smtp.gmail.com with ESMTPSA id f2sm3646428pfe.132.2021.12.15.10.52.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 15 Dec 2021 10:52:04 -0800 (PST) Sender: Namhyung Kim From: Namhyung Kim To: Arnaldo Carvalho de Melo , Jiri Olsa Cc: Ingo Molnar , Peter Zijlstra , LKML , Andi Kleen , Ian Rogers , Changbin Du , Song Liu , Athira Rajeev , Stephane Eranian , Arnaldo Carvalho de Melo Subject: [PATCH 5/5] perf ftrace: Implement cpu and task filters in BPF Date: Wed, 15 Dec 2021 10:51:54 -0800 Message-Id: <20211215185154.360314-6-namhyung@kernel.org> X-Mailer: git-send-email 2.34.1.173.g76aa8bc2d0-goog In-Reply-To: <20211215185154.360314-1-namhyung@kernel.org> References: <20211215185154.360314-1-namhyung@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Honor cpu and task options to set up filters (by pid or tid) in the BPF program. For example, the following command will show latency of the mutex_lock for process 2570. # perf ftrace latency -b -T mutex_lock -p 2570 sleep 3 # DURATION | COUNT | GRAPH | 0 - 1 us | 675 | ############################## | 1 - 2 us | 9 | | 2 - 4 us | 0 | | 4 - 8 us | 0 | | 8 - 16 us | 0 | | 16 - 32 us | 0 | | 32 - 64 us | 0 | | 64 - 128 us | 0 | | 128 - 256 us | 0 | | 256 - 512 us | 0 | | 512 - 1024 us | 0 | | 1 - 2 ms | 0 | | 2 - 4 ms | 0 | | 4 - 8 ms | 0 | | 8 - 16 ms | 0 | | 16 - 32 ms | 0 | | 32 - 64 ms | 0 | | 64 - 128 ms | 0 | | 128 - 256 ms | 0 | | 256 - 512 ms | 0 | | 512 - 1024 ms | 0 | | 1 - ... s | 0 | | Committer testing: Looking at faults on a firefox process: # strace -e bpf perf ftrace latency -b -p 1674378 -T __handle_mm_fault bpf(BPF_PROG_LOAD, {prog_type=3DBPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=3D2= , insns=3D0x7ffee1fee740, license=3D"GPL", log_level=3D0, log_size=3D0, log= _buf=3DNULL, kern_version=3DKERNEL_VERSION(0, 0, 0), prog_flags=3D0, prog_n= ame=3D"", prog_ifindex=3D0, expected_attach_type=3DBPF_CGROUP_INET_INGRESS,= prog_btf_fd=3D0, func_info_rec_size=3D0, func_info=3DNULL, func_info_cnt= =3D0, line_info_rec_size=3D0, line_info=3DNULL, line_info_cnt=3D0, attach_b= tf_id=3D0, attach_prog_fd=3D0}, 128) =3D 3 bpf(BPF_BTF_LOAD, {btf=3D"\237\353\1\0\30\0\0\0\0\0\0\0\20\0\0\0\20\0\0\0= \5\0\0\0\1\0\0\0\0\0\0\1"..., btf_log_buf=3DNULL, btf_size=3D45, btf_log_si= ze=3D0, btf_log_level=3D0}, 128) =3D 3 bpf(BPF_BTF_LOAD, {btf=3D"\237\353\1\0\30\0\0\0\0\0\0\0000\0\0\0000\0\0\0= \t\0\0\0\1\0\0\0\0\0\0\1"..., btf_log_buf=3DNULL, btf_size=3D81, btf_log_si= ze=3D0, btf_log_level=3D0}, 128) =3D 3 bpf(BPF_BTF_LOAD, {btf=3D"\237\353\1\0\30\0\0\0\0\0\0\08\0\0\08\0\0\0\t\0= \0\0\0\0\0\0\0\0\0\1"..., btf_log_buf=3DNULL, btf_size=3D89, btf_log_size= =3D0, btf_log_level=3D0}, 128) =3D 3 bpf(BPF_BTF_LOAD, {btf=3D"\237\353\1\0\30\0\0\0\0\0\0\0\f\0\0\0\f\0\0\0\7= \0\0\0\1\0\0\0\0\0\0\20"..., btf_log_buf=3DNULL, btf_size=3D43, btf_log_siz= e=3D0, btf_log_level=3D0}, 128) =3D 3 bpf(BPF_BTF_LOAD, {btf=3D"\237\353\1\0\30\0\0\0\0\0\0\0000\0\0\0000\0\0\0= \t\0\0\0\1\0\0\0\0\0\0\1"..., btf_log_buf=3DNULL, btf_size=3D81, btf_log_si= ze=3D0, btf_log_level=3D0}, 128) =3D 3 bpf(BPF_BTF_LOAD, {btf=3D"\237\353\1\0\30\0\0\0\0\0\0\0000\0\0\0000\0\0\0= \5\0\0\0\0\0\0\0\0\0\0\1"..., btf_log_buf=3DNULL, btf_size=3D77, btf_log_si= ze=3D0, btf_log_level=3D0}, 128) =3D -1 EINVAL (Invalid argument) bpf(BPF_BTF_LOAD, {btf=3D"\237\353\1\0\30\0\0\0\0\0\0\0 \3\0\0 \3\0\0\306= \3\0\0\0\0\0\0\0\0\0\2"..., btf_log_buf=3DNULL, btf_size=3D1790, btf_log_si= ze=3D0, btf_log_level=3D0}, 128) =3D 3 bpf(BPF_MAP_CREATE, {map_type=3DBPF_MAP_TYPE_ARRAY, key_size=3D4, value_s= ize=3D32, max_entries=3D1, map_flags=3D0, inner_map_fd=3D0, map_name=3D"", = map_ifindex=3D0, btf_fd=3D0, btf_key_type_id=3D0, btf_value_type_id=3D0, bt= f_vmlinux_value_type_id=3D0}, 128) =3D 4 bpf(BPF_PROG_LOAD, {prog_type=3DBPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=3D5= , insns=3D0x7ffee1fee570, license=3D"GPL", log_level=3D0, log_size=3D0, log= _buf=3DNULL, kern_version=3DKERNEL_VERSION(0, 0, 0), prog_flags=3D0, prog_n= ame=3D"", prog_ifindex=3D0, expected_attach_type=3DBPF_CGROUP_INET_INGRESS,= prog_btf_fd=3D0, func_info_rec_size=3D0, func_info=3DNULL, func_info_cnt= =3D0, line_info_rec_size=3D0, line_info=3DNULL, line_info_cnt=3D0, attach_b= tf_id=3D0, attach_prog_fd=3D0}, 128) =3D 5 bpf(BPF_MAP_CREATE, {map_type=3DBPF_MAP_TYPE_ARRAY, key_size=3D4, value_s= ize=3D4, max_entries=3D1, map_flags=3DBPF_F_MMAPABLE, inner_map_fd=3D0, map= _name=3D"", map_ifindex=3D0, btf_fd=3D0, btf_key_type_id=3D0, btf_value_typ= e_id=3D0, btf_vmlinux_value_type_id=3D0}, 128) =3D 4 bpf(BPF_PROG_LOAD, {prog_type=3DBPF_PROG_TYPE_SOCKET_FILTER, insn_cnt=3D2= , insns=3D0x7ffee1fee3c0, license=3D"GPL", log_level=3D0, log_size=3D0, log= _buf=3DNULL, kern_version=3DKERNEL_VERSION(0, 0, 0), prog_flags=3D0, prog_n= ame=3D"test", prog_ifindex=3D0, expected_attach_type=3DBPF_CGROUP_INET_INGR= ESS, prog_btf_fd=3D0, func_info_rec_size=3D0, func_info=3DNULL, func_info_c= nt=3D0, line_info_rec_size=3D0, line_info=3DNULL, line_info_cnt=3D0, attach= _btf_id=3D0, attach_prog_fd=3D0}, 128) =3D 4 bpf(BPF_MAP_CREATE, {map_type=3DBPF_MAP_TYPE_HASH, key_size=3D8, value_si= ze=3D8, max_entries=3D10000, map_flags=3D0, inner_map_fd=3D0, map_name=3D"f= unctime", map_ifindex=3D0, btf_fd=3D3, btf_key_type_id=3D0, btf_value_type_= id=3D0, btf_vmlinux_value_type_id=3D0}, 128) =3D 4 bpf(BPF_MAP_CREATE, {map_type=3DBPF_MAP_TYPE_HASH, key_size=3D4, value_si= ze=3D1, max_entries=3D1, map_flags=3D0, inner_map_fd=3D0, map_name=3D"cpu_f= ilter", map_ifindex=3D0, btf_fd=3D3, btf_key_type_id=3D0, btf_value_type_id= =3D0, btf_vmlinux_value_type_id=3D0}, 128) =3D 5 bpf(BPF_MAP_CREATE, {map_type=3DBPF_MAP_TYPE_HASH, key_size=3D4, value_si= ze=3D1, max_entries=3D36, map_flags=3D0, inner_map_fd=3D0, map_name=3D"task= _filter", map_ifindex=3D0, btf_fd=3D3, btf_key_type_id=3D0, btf_value_type_= id=3D0, btf_vmlinux_value_type_id=3D0}, 128) =3D 6 bpf(BPF_MAP_CREATE, {map_type=3DBPF_MAP_TYPE_PERCPU_ARRAY, key_size=3D4, = value_size=3D8, max_entries=3D22, map_flags=3D0, inner_map_fd=3D0, map_name= =3D"latency", map_ifindex=3D0, btf_fd=3D3, btf_key_type_id=3D0, btf_value_t= ype_id=3D0, btf_vmlinux_value_type_id=3D0}, 128) =3D 7 bpf(BPF_MAP_CREATE, {map_type=3DBPF_MAP_TYPE_ARRAY, key_size=3D4, value_s= ize=3D12, max_entries=3D1, map_flags=3DBPF_F_MMAPABLE, inner_map_fd=3D0, ma= p_name=3D"func_lat.bss", map_ifindex=3D0, btf_fd=3D3, btf_key_type_id=3D0, = btf_value_type_id=3D32, btf_vmlinux_value_type_id=3D0}, 128) =3D 8 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D8, key=3D0x7ffee1fee580, value=3D0x7f0= 1d940a000, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_PROG_LOAD, {prog_type=3DBPF_PROG_TYPE_KPROBE, insn_cnt=3D42, insn= s=3D0x1871f30, license=3D"", log_level=3D0, log_size=3D0, log_buf=3DNULL, k= ern_version=3DKERNEL_VERSION(5, 14, 16), prog_flags=3D0, prog_name=3D"func_= begin", prog_ifindex=3D0, expected_attach_type=3DBPF_CGROUP_INET_INGRESS, p= rog_btf_fd=3D3, func_info_rec_size=3D8, func_info=3D0x18746a0, func_info_cn= t=3D1, line_info_rec_size=3D16, line_info=3D0x1874550, line_info_cnt=3D20, = attach_btf_id=3D0, attach_prog_fd=3D0}, 128) =3D 9 bpf(BPF_PROG_LOAD, {prog_type=3DBPF_PROG_TYPE_KPROBE, insn_cnt=3D99, insn= s=3D0x18769b0, license=3D"", log_level=3D0, log_size=3D0, log_buf=3DNULL, k= ern_version=3DKERNEL_VERSION(5, 14, 16), prog_flags=3D0, prog_name=3D"func_= end", prog_ifindex=3D0, expected_attach_type=3DBPF_CGROUP_INET_INGRESS, pro= g_btf_fd=3D3, func_info_rec_size=3D8, func_info=3D0x188a640, func_info_cnt= =3D1, line_info_rec_size=3D16, line_info=3D0x188a660, line_info_cnt=3D20, a= ttach_btf_id=3D0, attach_prog_fd=3D0}, 128) =3D 10 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_MAP_UPDATE_ELEM, {map_fd=3D6, key=3D0x7ffee1fee8e0, value=3D0x7ff= ee1fee8df, flags=3DBPF_ANY}, 128) =3D 0 bpf(BPF_PROG_LOAD, {prog_type=3DBPF_PROG_TYPE_TRACEPOINT, insn_cnt=3D2, i= nsns=3D0x7ffee1fee3c0, license=3D"GPL", log_level=3D0, log_size=3D0, log_bu= f=3DNULL, kern_version=3DKERNEL_VERSION(0, 0, 0), prog_flags=3D0, prog_name= =3D"", prog_ifindex=3D0, expected_attach_type=3DBPF_CGROUP_INET_INGRESS, pr= og_btf_fd=3D0, func_info_rec_size=3D0, func_info=3DNULL, func_info_cnt=3D0,= line_info_rec_size=3D0, line_info=3DNULL, line_info_cnt=3D0, attach_btf_id= =3D0, attach_prog_fd=3D0}, 128) =3D 12 bpf(BPF_LINK_CREATE, {link_create=3D{prog_fd=3D12, target_fd=3D-1, attach= _type=3D0x29 /* BPF_??? */, flags=3D0}}, 128) =3D -1 EINVAL (Invalid argume= nt) ^Cstrace: Process 1702285 detached # DURATION | COUNT | GRAPH = | 0 - 1 us | 109 | ################# = | 1 - 2 us | 127 | ################### = | 2 - 4 us | 36 | ##### = | 4 - 8 us | 20 | ### = | 8 - 16 us | 2 | = | 16 - 32 us | 0 | = | 32 - 64 us | 0 | = | 64 - 128 us | 0 | = | 128 - 256 us | 0 | = | 256 - 512 us | 0 | = | 512 - 1024 us | 0 | = | 1 - 2 ms | 0 | = | 2 - 4 ms | 0 | = | 4 - 8 ms | 0 | = | 8 - 16 ms | 0 | = | 16 - 32 ms | 0 | = | 32 - 64 ms | 0 | = | 64 - 128 ms | 0 | = | 128 - 256 ms | 0 | = | 256 - 512 ms | 0 | = | 512 - 1024 ms | 0 | = | 1 - ... s | 0 | = | # Signed-off-by: Namhyung Kim Tested-by: Arnaldo Carvalho de Melo Cc: Andi Kleen Cc: Changbin Du Cc: Ian Rogers Cc: Ingo Molnar Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Song Liu Cc: Stephane Eranian Link: https://lore.kernel.org/r/20211129231830.1117781-6-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/bpf_ftrace.c | 42 ++++++++++++++++++++- tools/perf/util/bpf_skel/func_latency.bpf.c | 21 +++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/bpf_ftrace.c b/tools/perf/util/bpf_ftrace.c index ec4e2f5a2fc4..f00a2de6778c 100644 --- a/tools/perf/util/bpf_ftrace.c +++ b/tools/perf/util/bpf_ftrace.c @@ -7,7 +7,9 @@ =20 #include "util/ftrace.h" #include "util/cpumap.h" +#include "util/thread_map.h" #include "util/debug.h" +#include "util/evlist.h" #include "util/bpf_counter.h" =20 #include "util/bpf_skel/func_latency.skel.h" @@ -16,7 +18,8 @@ static struct func_latency_bpf *skel; =20 int perf_ftrace__latency_prepare_bpf(struct perf_ftrace *ftrace) { - int err; + int fd, err; + int i, ncpus =3D 1, ntasks =3D 1; struct filter_entry *func; =20 if (!list_is_singular(&ftrace->filters)) { @@ -33,6 +36,17 @@ int perf_ftrace__latency_prepare_bpf(struct perf_ftrace = *ftrace) return -1; } =20 + /* don't need to set cpu filter for system-wide mode */ + if (ftrace->target.cpu_list) { + ncpus =3D perf_cpu_map__nr(ftrace->evlist->core.cpus); + bpf_map__set_max_entries(skel->maps.cpu_filter, ncpus); + } + + if (target__has_task(&ftrace->target) || target__none(&ftrace->target)) { + ntasks =3D perf_thread_map__nr(ftrace->evlist->core.threads); + bpf_map__set_max_entries(skel->maps.task_filter, ntasks); + } + set_max_rlimit(); =20 err =3D func_latency_bpf__load(skel); @@ -41,6 +55,32 @@ int perf_ftrace__latency_prepare_bpf(struct perf_ftrace = *ftrace) goto out; } =20 + if (ftrace->target.cpu_list) { + u32 cpu; + u8 val =3D 1; + + skel->bss->has_cpu =3D 1; + fd =3D bpf_map__fd(skel->maps.cpu_filter); + + for (i =3D 0; i < ncpus; i++) { + cpu =3D cpu_map__cpu(ftrace->evlist->core.cpus, i); + bpf_map_update_elem(fd, &cpu, &val, BPF_ANY); + } + } + + if (target__has_task(&ftrace->target) || target__none(&ftrace->target)) { + u32 pid; + u8 val =3D 1; + + skel->bss->has_task =3D 1; + fd =3D bpf_map__fd(skel->maps.task_filter); + + for (i =3D 0; i < ntasks; i++) { + pid =3D perf_thread_map__pid(ftrace->evlist->core.threads, i); + bpf_map_update_elem(fd, &pid, &val, BPF_ANY); + } + } + skel->links.func_begin =3D bpf_program__attach_kprobe(skel->progs.func_be= gin, false, func->name); if (IS_ERR(skel->links.func_begin)) { diff --git a/tools/perf/util/bpf_skel/func_latency.bpf.c b/tools/perf/util/= bpf_skel/func_latency.bpf.c index ccd96b09fc42..ea94187fe443 100644 --- a/tools/perf/util/bpf_skel/func_latency.bpf.c +++ b/tools/perf/util/bpf_skel/func_latency.bpf.c @@ -37,6 +37,8 @@ struct { =20 =20 int enabled =3D 0; +int has_cpu =3D 0; +int has_task =3D 0; =20 SEC("kprobe/func") int BPF_PROG(func_begin) @@ -47,6 +49,25 @@ int BPF_PROG(func_begin) return 0; =20 key =3D bpf_get_current_pid_tgid(); + + if (has_cpu) { + __u32 cpu =3D bpf_get_smp_processor_id(); + __u8 *ok; + + ok =3D bpf_map_lookup_elem(&cpu_filter, &cpu); + if (!ok) + return 0; + } + + if (has_task) { + __u32 pid =3D key & 0xffffffff; + __u8 *ok; + + ok =3D bpf_map_lookup_elem(&task_filter, &pid); + if (!ok) + return 0; + } + now =3D bpf_ktime_get_ns(); =20 // overwrite timestamp for nested functions --=20 2.34.1.173.g76aa8bc2d0-goog