Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F168975398
D58928.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D58928.diff
View Options
diff --git a/usr.sbin/pmc/cmd_pmc_ibs.cc b/usr.sbin/pmc/cmd_pmc_ibs.cc
new file mode 100644
--- /dev/null
+++ b/usr.sbin/pmc/cmd_pmc_ibs.cc
@@ -0,0 +1,431 @@
+/*-
+ * 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 ibs_fetch_stats
+{
+ ibs_fetch_stats() : total(0), ocmiss(0), icmiss(0),
+ l2miss(0), l3miss(0), l1tlbmiss(0), l2tlbmiss(0),
+ pgsz(), lat() { }
+ ~ibs_fetch_stats() { }
+
+ uint64_t total;
+
+ uint64_t ocmiss;
+ uint64_t icmiss;
+ uint64_t l2miss;
+ uint64_t l3miss;
+
+ uint64_t l1tlbmiss;
+ uint64_t l2tlbmiss;
+
+ bargraph pgsz;
+
+ histogram lat;
+};
+
+struct ibs_op_stats
+{
+ ibs_op_stats() : total(0), brret(0), brmisp(0), brtaken(0),
+ rets(0), loads(0), stores(0), locked(0), prefetch(0),
+ dctlbmiss(0), dctlbhit2m(0), dctlbhit1g(0),
+ mototal(0), mostate(0), datasrc(), memwidth(), pgsz(),
+ ldlat(), tagtoret(), comptoret() { }
+ ~ibs_op_stats() { }
+
+ uint64_t total;
+
+ uint64_t brret;
+ uint64_t brmisp;
+ uint64_t brtaken;
+ uint64_t rets;
+
+ uint64_t loads;
+ uint64_t stores;
+ uint64_t locked;
+ uint64_t prefetch;
+
+ uint64_t dctlbmiss;
+ uint64_t dctlbhit2m;
+ uint64_t dctlbhit1g;
+
+ uint64_t mototal;
+ uint64_t mostate;
+
+ bargraph datasrc;
+ bargraph memwidth;
+ bargraph pgsz;
+
+ histogram ldlat;
+ histogram tagtoret;
+ histogram comptoret;
+};
+
+static const std::string pgsizestr[4] = { "4 KiB", "2 MiB", "1 GiB", "16 KiB" };
+static const std::string memwidthstr[8] = {
+ "None", "Byte", "Word", "DWord",
+ "QWord", "OWord", "32 Bytes", "64 Bytes"
+};
+static const std::string datasrcstr[16] = {
+ "None", "Local", "Near CCX", "Near DRAM/MMIO",
+ "Reserved", "Remote", "Long Latency DIMM", "Remote DRAM/MMIO",
+ "Extension Memory", "Reserved9", "ReservedA", "ReservedB",
+ "Coherent Memory", "ReservedD", "ReservedE", "ReservedF"
+};
+
+class ibs_view : public pmcview
+{
+public:
+ ibs_view() : pmcview(), fstats(), opstats()
+ {
+ fstats.pgsz = bargraph();
+ /*
+ * Explicitly define the ordering so that 16 KiB pages come
+ * before 2 MiB pages, which doesn't match the encoding.
+ */
+ fstats.pgsz.addcolumn("4 KiB");
+ fstats.pgsz.addcolumn("16 KiB");
+ fstats.pgsz.addcolumn("2 MiB");
+ fstats.pgsz.addcolumn("1 GiB");
+ fstats.lat = histogram();
+
+ opstats.pgsz = bargraph();
+ opstats.pgsz.addcolumn("4 KiB");
+ opstats.pgsz.addcolumn("16 KiB");
+ opstats.pgsz.addcolumn("2 MiB");
+ opstats.pgsz.addcolumn("1 GiB");
+
+ opstats.memwidth = bargraph();
+ for (auto &s : memwidthstr)
+ if (s.substr(0, 8) != "Reserved")
+ opstats.memwidth.addcolumn(s);
+ opstats.datasrc = bargraph();
+ for (auto &s : datasrcstr)
+ if (s.substr(0, 8) != "Reserved")
+ opstats.datasrc.addcolumn(s);
+
+ opstats.tagtoret = histogram();
+ opstats.comptoret = histogram();
+ opstats.ldlat = histogram();
+ }
+
+ ~ibs_view()
+ {
+ }
+
+ virtual void
+ callchain(__unused struct pmclog_ev_callchain &p, ibsfetchinfo &f,
+ __unused uintfptr_t *cc, __unused int len)
+ {
+ int pgsz;
+
+ fstats.total += 1;
+
+ // Cache stats
+ if (f.ctl & IBS_FETCH_CTL_OPCACHEMISS)
+ fstats.ocmiss++;
+ if (f.ctl & IBS_FETCH_CTL_ICMISS)
+ fstats.icmiss++;
+ if (f.ctl & IBS_FETCH_CTL_L2MISS)
+ fstats.l2miss++;
+ if (f.ctl & IBS_FETCH_CTL_L3MISS)
+ fstats.l3miss++;
+
+ // TLB Stats
+ if (f.ctl & IBS_FETCH_CTL_L1TLBMISS)
+ fstats.l1tlbmiss++;
+ if (f.ctl & IBS_FETCH_CTL_L2TLBMISS)
+ fstats.l2tlbmiss++;
+
+ pgsz = IBS_FETCH_CTL_TO_PGSZ(f.ctl);
+ fstats.pgsz.addsample(pgsizestr[pgsz]);
+
+ fstats.lat.addsample(IBS_FETCH_CTL_TO_LAT(f.ctl));
+ }
+
+ virtual void
+ callchain(__unused struct pmclog_ev_callchain &p, ibsopinfo &o,
+ __unused uintfptr_t *cc, __unused int len)
+ {
+ opstats.total += 1;
+
+ // Branch stats
+ if (o.data & IBS_OP_DATA_BRANCHRETIRED)
+ opstats.brret += 1;
+ if (o.data & IBS_OP_DATA_BRANCHMISPREDICTED)
+ opstats.brmisp += 1;
+ if (o.data & IBS_OP_DATA_BRANCHTAKEN)
+ opstats.brtaken += 1;
+ if (o.data & IBS_OP_DATA_RETURN)
+ opstats.rets += 1;
+
+ opstats.tagtoret.addsample(IBS_OP_DATA_TO_TAGTORET(o.data));
+ opstats.comptoret.addsample(IBS_OP_DATA_TO_COMPTORET(o.data));
+
+ // Load/store stats
+ if (o.data3 & IBS_OP_DATA3_LOAD) {
+ opstats.loads += 1;
+ opstats.ldlat.addsample(IBS_OP_DATA3_TO_DCLAT(o.data3));
+ }
+ if (o.data3 & IBS_OP_DATA3_STORE)
+ opstats.stores += 1;
+ if (o.data3 & IBS_OP_DATA3_LOCKEDOP)
+ opstats.locked += 1;
+ if (o.data3 & IBS_OP_DATA3_PREFETCH)
+ opstats.prefetch += 1;
+
+ // DC TLB
+ if (o.data3 & IBS_OP_DATA3_DCL1TLBMISS)
+ opstats.dctlbmiss += 1;
+ if (o.data3 & IBS_OP_DATA3_DCL1TLBHIT2M)
+ opstats.dctlbhit2m += 1;
+ if (o.data3 & IBS_OP_DATA3_DCL1TLBHIT1G)
+ opstats.dctlbhit1g += 1;
+
+ /*
+ * The data2 register is only valid for loads that miss in the L1 and
+ * L2 caches.
+ * From PPR for AMD Family 1Ah Model 70h A0
+ */
+ if ((o.data3 & IBSOPDATA2_VALIDMASK) == IBSOPDATA2_VALIDMASK) {
+ uint64_t datasrc = IBS_OP_DATA2_DATASRC(o.data2);
+ opstats.datasrc.addsample(datasrcstr[datasrc]);
+ if ((datasrc == IBS_DATASRC_NEARFARCACHE_NEAR) ||
+ (datasrc == IBS_DATASRC_NEARFARCACHE_FAR)) {
+ opstats.mototal++;
+ if ((o.data2 & IBS_OP_DATA2_HITO) == 0)
+ opstats.mostate++;
+ }
+ }
+
+ opstats.memwidth.addsample(memwidthstr[IBS_OP_DATA3_MEMWIDTH(o.data3)]);
+
+ if ((o.data3 & IBS_OP_DATA3_DCPHYADDRVALID) != 0) {
+ opstats.pgsz.addsample(pgsizestr[IBS_OP_DATA3_PGSZ(o.data3)]);
+ }
+ }
+
+ virtual void
+ print()
+ {
+ if (fstats.total) {
+ title("IBS Fetch Report");
+
+ printf("Op Cache Miss: %4.2f%%\n", 100.0 * fstats.ocmiss / fstats.total);
+ printf("L1 Cache Miss: %4.2f%%\n", 100.0 * fstats.icmiss / fstats.total);
+ printf("L2 Cache Miss: %4.2f%%\n", 100.0 * fstats.l2miss / fstats.total);
+ printf("L3 Cache Miss: %4.2f%%\n\n", 100.0 * fstats.l3miss / fstats.total);
+
+ printf("L1 TLB Miss: %4.2f%%\n", 100.0 * fstats.l1tlbmiss / fstats.total);
+ printf("L2 TLB Miss: %4.2f%%\n\n", 100.0 * fstats.l2tlbmiss / fstats.total);
+
+ header("Page Size Distribution");
+ fstats.pgsz.print();
+
+ header("Fetch Latency Distribution");
+ printf("Min: %d Cycles\n", fstats.lat.min());
+ printf("Max: %d Cycles\n", fstats.lat.max());
+ printf("Average: %d Cycles\n\n", fstats.lat.average());
+ fstats.lat.setxlabel("Latency (Cycles)");
+ fstats.lat.setylabel("Frequency Log");
+ fstats.lat.setxaxis(0, 2000);
+ // Set colors to approximately L3 and local DRAM latencies
+ fstats.lat.setxcolors({ 0, 50, 400 });
+ fstats.lat.print();
+ }
+
+ if (opstats.total) {
+ title("IBS Op Report");
+
+ printf("Branches: %4.2f%%\n", 100.0 * opstats.brret / opstats.total);
+ printf("Branch Mispredictions: %4.2f%%\n", 100.0 * opstats.brmisp / opstats.brret);
+ printf("Branch Taken: %4.2f%%\n", 100.0 * opstats.brtaken / opstats.brret);
+ printf("Returns: %4.2f%%\n", 100.0 * opstats.rets / opstats.total);
+ printf("\n");
+
+ printf("Loads: %4.2f%%\n", 100.0 * opstats.loads / opstats.total);
+ printf("Stores: %4.2f%%\n", 100.0 * opstats.stores / opstats.total);
+ printf("Locked Operations: %4.2f%%\n", 100.0 * opstats.locked / opstats.total);
+ printf("Software Prefetches: %4.2f%%\n", 100.0 * opstats.prefetch / opstats.total);
+ printf("\n");
+
+ header("Data Source Distribution");
+ if (opstats.mototal)
+ printf("Hit-M: %4.2f%%\n", 100.0 * opstats.mostate / opstats.mototal);
+ opstats.datasrc.print();
+ printf("\n");
+
+ header("Memory Width Distribution");
+ opstats.memwidth.print();
+ printf("\n");
+
+ header("Page Size Distribution");
+ opstats.pgsz.print();
+ printf("\n");
+
+ header("Load Latency Distribution");
+ printf("Min: %d Cycles\n", opstats.ldlat.min());
+ printf("Max: %d Cycles\n", opstats.ldlat.max());
+ printf("Average: %d Cycles\n\n", opstats.ldlat.average());
+ opstats.ldlat.setxlabel("Latency (Cycles)");
+ opstats.ldlat.setylabel("Frequency Log");
+ opstats.ldlat.setxaxis(0, 2000);
+ // Set colors to approximately L3 and local DRAM latencies
+ opstats.ldlat.setxcolors({ 0, 50, 400 });
+ opstats.ldlat.print();
+ printf("\n");
+
+ header("Tag to Retire Distribution");
+ printf("Min: %d Cycles\n", opstats.tagtoret.min());
+ printf("Max: %d Cycles\n", opstats.tagtoret.max());
+ printf("Average: %d Cycles\n\n", opstats.tagtoret.average());
+ opstats.tagtoret.setxlabel("Latency (Cycles)");
+ opstats.tagtoret.setylabel("Frequency Log");
+ opstats.tagtoret.print();
+ printf("\n");
+
+ header("Completion to Retire Distribution");
+ printf("Min: %d Cycles\n", opstats.comptoret.min());
+ printf("Max: %d Cycles\n", opstats.comptoret.max());
+ printf("Average: %d Cycles\n\n", opstats.comptoret.average());
+ opstats.comptoret.setxlabel("Latency (Cycles)");
+ opstats.comptoret.setylabel("Frequency Log");
+ opstats.comptoret.print();
+ }
+ }
+private:
+ ibs_fetch_stats fstats;
+ ibs_op_stats opstats;
+};
+
+static struct option longopts[] = {
+ PMCFILTER_LOPTS,
+ { NULL, 0, NULL, 0 }
+};
+
+static void
+usage(void)
+{
+ printf("Usage: pmc ibs [options] [pmclog]\n\n");
+ printf("Display a summary of an IBS trace\n\n");
+ PMCFILTER_PRINTOPTS();
+}
+
+int
+cmd_pmc_ibs(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 '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc != 0 && argc != 1) {
+ usage();
+ exit(EX_USAGE);
+ }
+ if (argc == 1)
+ logfile = argv[0];
+
+ if ((logfd = open(logfile, O_RDONLY)) < 0) {
+ errx(EX_OSERR, "ERROR: Cannot open \"%s\" for reading: %s.", argv[0],
+ strerror(errno));
+ }
+
+ setup_screen();
+
+ ibs_view v = ibs_view();
+ v.setfilter(filter);
+ v.process(logfd);
+ v.print();
+
+ close(logfd);
+
+ return (0);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Sep 1, 12:56 AM (9 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
36963771
Default Alt Text
D58928.diff (12 KB)
Attached To
Mode
D58928: pmc: Print IBS summary statistics
Attached
Detach File
Event Timeline
Log In to Comment