Date: Tue, 28 Jul 2026 19:29:26 +0000 From: Warner Losh <imp@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Ali Mashtizadeh <ali@mashtizadeh.com> Subject: git: cc94d1bd7414 - main - pmc: pmc frontend stall analysis based on IBS Message-ID: <6a690316.43c88.4582d0dc@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by imp: URL: https://cgit.FreeBSD.org/src/commit/?id=cc94d1bd7414b309a62a379a8e614e3a3f9cd6d9 commit cc94d1bd7414b309a62a379a8e614e3a3f9cd6d9 Author: Ali Mashtizadeh <ali@mashtizadeh.com> AuthorDate: 2026-07-28 17:46:48 +0000 Commit: Warner Losh <imp@FreeBSD.org> CommitDate: 2026-07-28 19:27:45 +0000 pmc: pmc frontend stall analysis based on IBS The frontend command uses AMD IBS frontend events to analyze the major sources of frontend stalls. It displays a table breakind down the major causes of front end stalls. This is a simple demonstration of the tools as you can use the filtering tools to limit the analysis to a subset of the samples including filtering by fetch latencies. Sponsored by: Netflix Reviewed by: adrian, imp Differential Revision: https://reviews.freebsd.org/D57779 --- usr.sbin/pmc/cmd_pmc_frontend.cc | 242 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) diff --git a/usr.sbin/pmc/cmd_pmc_frontend.cc b/usr.sbin/pmc/cmd_pmc_frontend.cc new file mode 100644 index 000000000000..18ffd607bf21 --- /dev/null +++ b/usr.sbin/pmc/cmd_pmc_frontend.cc @@ -0,0 +1,242 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2026, Netflix, Inc. + * + * This software was developed by Ali Mashtizadeh under the sponsorship from + * Netflix, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <sys/param.h> +#include <sys/cpuset.h> +#include <sys/event.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/time.h> +#include <sys/ttycom.h> +#include <sys/user.h> +#include <sys/wait.h> + +#include <assert.h> +#include <curses.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <kvm.h> +#include <libgen.h> +#include <limits.h> +#include <locale.h> +#include <math.h> +#include <pmc.h> +#include <pmclog.h> +#include <regex.h> +#include <signal.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <sysexits.h> +#include <unistd.h> + +#include <libpmcstat.h> +#include "cmd_pmc.h" + +#include <iostream> +#include <map> +#include <set> +#include <string> +#include <unordered_map> +#include <unordered_set> +#include <vector> + +#include <dev/hwpmc/hwpmc_ibs.h> +#include "display.hh" +#include "view.hh" + +struct frontend { + syminfo func; + int64_t ocmiss; + int64_t l2miss; + int64_t l3miss; + int64_t l1tlbmiss; + int64_t l2tlbmiss; + int64_t latency; + int64_t samples; +}; + +static int sortcol = 2; + +class frontend_view : public pmcview +{ +public: + frontend_view() : pmcview(), samples() { } + ~frontend_view() { } + + virtual void + callchain(struct pmclog_ev_callchain &p, + ibsfetchinfo &f, __unused uintfptr_t *cc, __unused int len) + { + int usermode = PMC_CALLCHAIN_CPUFLAGS_TO_USERMODE(p.pl_cpuflags); + + /* Ignore zeros */ + if (IBS_FETCH_CTL_TO_LAT(f.ctl) == 0) + return; + + auto inst = samples.find(f.linaddr); + if (inst == samples.end()) { + syminfo sym = addrtosymbol(usermode ? p.pl_pid : 0, f.linaddr); + if (sym.name == "") + return; + + samples[f.linaddr] = frontend(); + inst = samples.find(f.linaddr); + inst->second.func = sym; + } + + /* + * Save fetch cache and TLB miss counts + */ + if (f.ctl & IBS_FETCH_CTL_OPCACHEMISS) + inst->second.ocmiss += 1; + if (f.ctl & IBS_FETCH_CTL_L2MISS) + inst->second.l2miss += 1; + if (f.ctl & IBS_FETCH_CTL_L3MISS) + inst->second.l3miss += 1; + + if (f.ctl & IBS_FETCH_CTL_L1TLBMISS) + inst->second.l1tlbmiss += 1; + if (f.ctl & IBS_FETCH_CTL_L2TLBMISS) + inst->second.l2tlbmiss += 1; + + inst->second.latency += IBS_FETCH_CTL_TO_LAT(f.ctl); + inst->second.samples += 1; + } + + virtual void + print() + { + title("IBS Frontend Analysis"); + + // Print header + table t = table(); + t.addcolumn("Image", true); + t.addcolumn("Function", true); + t.addcolumn("Latency"); + t.addcolumn("Samples"); + t.addcolumn("OC Miss"); + t.addcolumn("L2 Miss"); + t.addcolumn("L3 Miss"); + t.addcolumn("L1 TLB Miss"); + t.addcolumn("L2 TLB Miss"); + + for (auto &kv : samples) { + std::vector<field> r; + + r.emplace_back(kv.second.func.binary); + r.emplace_back(kv.second.func.to_string()); + r.emplace_back(kv.second.latency); + r.emplace_back(kv.second.samples); + r.emplace_back(kv.second.ocmiss, kv.second.samples, true); + r.emplace_back(kv.second.l2miss, kv.second.samples, true); + r.emplace_back(kv.second.l3miss, kv.second.samples, true); + r.emplace_back(kv.second.l1tlbmiss, kv.second.samples, true); + r.emplace_back(kv.second.l2tlbmiss, kv.second.samples, true); + + t.addrow(r); + } + + t.sort(sortcol); + t.print(); + } +protected: + std::unordered_map<uint64_t, frontend> samples; +}; + + +static struct option longopts[] = { + PMCFILTER_LOPTS, + { "sort", required_argument, NULL, 's' }, + { NULL, 0, NULL, 0 } +}; + +static void +usage(void) +{ + printf("Usage: pmc frontend [options] [pmclog]\n\n"); + printf("Analyze frontend bottlenecks\n\n"); + printf("Options:\n"); + printf("\t-s,--sort Sort by event\n\n"); + PMCFILTER_PRINTOPTS(); +} + +int +cmd_pmc_frontend(int argc, char **argv) +{ + pmcfilter filter = pmcfilter(); + const char *logfile = "default.log"; + int option, logfd; + + while ((option = getopt_long(argc, argv, PMCFILTER_SOPTS, longopts, NULL)) != -1) { + switch (option) { + PMCFILTER_CASE(filter) + case 's': + sortcol = atoi(optarg); + break; + case '?': + default: + usage(); + exit(EX_USAGE); + } + } + argc -= optind; + argv += optind; + if (argc != 0 && argc != 1) { + usage(); + exit(EX_USAGE); + } + if (argc == 1) + logfile = argv[0]; + + setup_screen(); + + if ((logfd = open(logfile, O_RDONLY)) < 0) { + errx(EX_OSERR, "ERROR: Cannot open \"%s\" for reading: %s.", logfile, + strerror(errno)); + } + + frontend_view v = frontend_view(); + v.setfilter(filter); + v.process(logfd); + v.print(); + + close(logfd); + + return (0); +}home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a690316.43c88.4582d0dc>
