Page MenuHomeFreeBSD

D61447.1794527375.diff
No OneTemporary

Authored By
Unknown
Size
13 KB
Referenced Files
None
Subscribers
None

D61447.1794527375.diff

diff --git a/usr.sbin/pmc/cmd_pmc_frontend.cc b/usr.sbin/pmc/cmd_pmc_frontend.cc
--- a/usr.sbin/pmc/cmd_pmc_frontend.cc
+++ b/usr.sbin/pmc/cmd_pmc_frontend.cc
@@ -140,7 +140,7 @@
}
virtual void
- print()
+ print(bool interactive)
{
title("IBS Frontend Analysis");
@@ -159,7 +159,7 @@
for (auto &kv : samples) {
std::vector<field> r;
- r.emplace_back(kv.second.func.binary);
+ r.emplace_back(basename(kv.second.func.binary));
r.emplace_back(kv.second.func.to_string());
r.emplace_back(kv.second.latency);
r.emplace_back(kv.second.samples);
@@ -173,7 +173,10 @@
}
t.sort(sortcol);
- t.print();
+ if (interactive)
+ t.display("Frontend Analysis");
+ else
+ t.print();
}
protected:
std::unordered_map<uint64_t, frontend> samples;
@@ -182,6 +185,7 @@
static struct option longopts[] = {
PMCFILTER_LOPTS,
+ { "format", required_argument, NULL, 'F' },
{ "sort", required_argument, NULL, 's' },
{ NULL, 0, NULL, 0 }
};
@@ -192,6 +196,7 @@
printf("Usage: pmc frontend [options] [pmclog]\n\n");
printf("Analyze frontend bottlenecks\n\n");
printf("Options:\n");
+ printf("\t-F,--format Output format (console, tui)\n");
printf("\t-s,--sort Sort by event\n\n");
PMCFILTER_PRINTOPTS();
}
@@ -202,10 +207,14 @@
pmcfilter filter = pmcfilter();
const char *logfile = "default.log";
int option, logfd;
+ std::string format;
- while ((option = getopt_long(argc, argv, PMCFILTER_SOPTS, longopts, NULL)) != -1) {
+ while ((option = getopt_long(argc, argv, "F:s:" PMCFILTER_SOPTS, longopts, NULL)) != -1) {
switch (option) {
PMCFILTER_CASE(filter)
+ case 'F':
+ format = optarg;
+ break;
case 's':
sortcol = atoi(optarg);
break;
@@ -224,7 +233,8 @@
if (argc == 1)
logfile = argv[0];
- setup_screen();
+ bool interactive = display_getmode(format, {"console", "tui"}) == "tui";
+ setup_screen(interactive);
if ((logfd = open(logfile, O_RDONLY)) < 0) {
errx(EX_OSERR, "ERROR: Cannot open \"%s\" for reading: %s.", logfile,
@@ -234,7 +244,7 @@
frontend_view v = frontend_view();
v.setfilter(filter);
v.process(logfd);
- v.print();
+ v.print(interactive);
close(logfd);
diff --git a/usr.sbin/pmc/view.hh b/usr.sbin/pmc/view.hh
--- a/usr.sbin/pmc/view.hh
+++ b/usr.sbin/pmc/view.hh
@@ -155,10 +155,11 @@
struct image
{
- image() : isdynamic(false), vaddr(0), start(0), end(0),
+ image() : loaded(false), isdynamic(false), vaddr(0), start(0), end(0),
offset(0), name(""), binary(""), path(""), loader(""),
dwarf(""), symbols(), dbg_fd(-1), dbg_elf(NULL) { }
~image() { }
+ bool loaded;
bool isdynamic;
uint64_t vaddr;
uint64_t start;
@@ -182,7 +183,7 @@
filterevent(false), filtercpu(false),
kernelonly(false), useronly(false),
pids(), tids(), programs(), threads(),
- ibs_ldlat(0), ibs_oplat(0) { CPU_ZERO(&cpus); }
+ ibs_ldlat(0), ibs_oplat(0), ibs_mmio(false) { CPU_ZERO(&cpus); }
~pmcfilter() { }
bool filterpid;
bool filtertid;
@@ -250,6 +251,8 @@
printf("\t-c,--cpus Filter by CPU id\n"); \
printf("\t-k,--kernel Show only kernel events\n"); \
printf("\t-u,--user Show only user events\n"); \
+ printf("\nGeneral Options:\n"); \
+ printf("\t-h,--help Display this help\n"); \
printf("\nIBS Fetch Options:\n"); \
printf("\t--ldlat Filter by load latency\n"); \
printf("\nIBS Op Options:\n"); \
@@ -262,15 +265,19 @@
{ "pids", required_argument, NULL, 'p' }, \
{ "threads", required_argument, NULL, 'T' }, \
{ "processes", required_argument, NULL, 'P' }, \
- { "events", required_argument, NULL, 'e' }, \
+ { "event", required_argument, NULL, 'e' }, \
{ "cpus", required_argument, NULL, 'c' }, \
{ "kernel", no_argument, NULL, 'k' }, \
{ "user", no_argument, NULL, 'u' }, \
{ "ldlat", required_argument, NULL, 10 }, \
{ "oplat", required_argument, NULL, 11 }, \
- { "mmio", no_argument, NULL, 12 }
-#define PMCFILTER_SOPTS "t:p:T:P:e:c:ku"
+ { "mmio", no_argument, NULL, 12 }, \
+ { "help", no_argument, NULL, 'h' }
+#define PMCFILTER_SOPTS "t:p:T:P:e:c:kuh"
#define PMCFILTER_CASE(_filt) \
+ case 'h': \
+ usage(); \
+ exit(EX_OK); \
case 't': \
_filt.addtids(optarg); \
break; \
@@ -354,10 +361,10 @@
}
virtual void callchain(__unused struct pmclog_ev_callchain &p) { }
// Console/File output
- virtual void print() { };
- virtual int process_sysinfo(int logfd, const pmchdr_infohdr &infohdr);
- virtual int process_pmcinfo(int logfd, const pmchdr_infohdr &infohdr);
- virtual int process_cpuidinfo(int logfd, const pmchdr_infohdr &infohdr);
+ virtual void print(__unused bool interactive) { };
+ virtual int process_sysinfo(const pmchdr_infohdr &infohdr);
+ virtual int process_pmcinfo(const pmchdr_infohdr &infohdr);
+ virtual int process_cpuidinfo(const pmchdr_infohdr &infohdr);
// Process log
virtual void process(int logfd);
virtual void process(struct pmclog_ev &p);
@@ -389,6 +396,7 @@
void printvm(pid_t pid);
// Fields available to views
uint64_t tscfreq;
+ uint8_t pageshift;
std::unordered_map<uint32_t, uint32_t> pmcid;
std::unordered_map<uint32_t, struct pmcinfo> pmcinfo;
std::unordered_map<pid_t, struct procinfo> procs;
@@ -396,6 +404,7 @@
std::unordered_map<std::string, image> images;
std::string sysroot;
pmcfilter filter;
+ int logfd;
// Extended info
int arch;
std::string cpumodel;
@@ -404,7 +413,7 @@
std::vector<struct pmcinfox> extpmcinfo;
std::map<uint32_t, struct cpuidleaf> cpuid; // x86 Only
private:
- image loadimage(const std::string &path);
+ image loadimage(const std::string &path, bool iskernel = false);
void mapimage(pid_t pid, const image &im, uint64_t linkaddr);
void loadsymboltable(image *im, Elf *e, Elf_Scn *scn, GElf_Shdr *sh);
void loadsymbols(image *im);
diff --git a/usr.sbin/pmc/view.cc b/usr.sbin/pmc/view.cc
--- a/usr.sbin/pmc/view.cc
+++ b/usr.sbin/pmc/view.cc
@@ -89,8 +89,8 @@
return ss.str();
}
-pmcview::pmcview() : tscfreq(0), pmcid(), pmcinfo(), procs(), tidtopid(),
- images(), sysroot(""), filter()
+pmcview::pmcview() : tscfreq(0), pageshift(0), pmcid(), pmcinfo(), procs(),
+ tidtopid(), images(), sysroot(""), filter()
{
char *root;
@@ -136,7 +136,7 @@
}
int
-pmcview::process_sysinfo(int logfd, const pmchdr_infohdr &infohdr)
+pmcview::process_sysinfo(const pmchdr_infohdr &infohdr)
{
int status;
pmchdr_sysinfo sysinfo;
@@ -156,7 +156,7 @@
}
int
-pmcview::process_pmcinfo(int logfd, const pmchdr_infohdr &infohdr)
+pmcview::process_pmcinfo(const pmchdr_infohdr &infohdr)
{
int status;
union {
@@ -164,6 +164,9 @@
__unused char reserve_max_size[256];
};
+ if (infohdr.length > 256)
+ errx(EX_IOERR, "PMC info headers are too large");
+
status = readlog(logfd, &pmcinfo, infohdr.length);
if (status < 0 || status != infohdr.length)
errx(EX_IOERR, "readlog");
@@ -174,7 +177,7 @@
}
int
-pmcview::process_cpuidinfo(int logfd, const pmchdr_infohdr &infohdr)
+pmcview::process_cpuidinfo(const pmchdr_infohdr &infohdr)
{
int status;
uint32_t *cpuidinfo;
@@ -199,6 +202,9 @@
root = maxleaf & 0xFFFF0000;
count = maxleaf & 0x0000FFFF;
+ if (4 * (int)(count + 1) + offset > len)
+ errx(EX_DATAERR, "PMC CPUID leaf count too large");
+
for (uint32_t i = 0; i <= count; i++) {
cpuid[root + i] = { cpuidinfo[4 * i + offset],
cpuidinfo[4 * i + 1 + offset],
@@ -215,12 +221,14 @@
}
void
-pmcview::process(int logfd)
+pmcview::process(int _logfd)
{
int status;
pmchdr_header hdr;
struct pmclog_parse_state *ps;
+ logfd = _logfd;
+
// Read header
status = readlog(logfd, &hdr, sizeof(hdr));
if (status < 0 || status != sizeof(hdr))
@@ -243,11 +251,11 @@
if (infohdr.type == INFOHDR_TYPE_DONE) {
break;
} else if (infohdr.type == INFOHDR_TYPE_SYSINFO) {
- process_sysinfo(logfd, infohdr);
+ process_sysinfo(infohdr);
} else if (infohdr.type == INFOHDR_TYPE_PMCINFO) {
- process_pmcinfo(logfd, infohdr);
+ process_pmcinfo(infohdr);
} else if (infohdr.type == INFOHDR_TYPE_CPUID) {
- process_cpuidinfo(logfd, infohdr);
+ process_cpuidinfo(infohdr);
}
}
@@ -308,7 +316,7 @@
case PMCLOG_TYPE_CALLCHAIN:
process(p.pl_u.pl_cc);
return;
- case PMCLOG_TYPE_PMCATTACH: [[fallthrough]];
+ case PMCLOG_TYPE_PMCATTACH:
case PMCLOG_TYPE_PMCDETACH:
case PMCLOG_TYPE_USERDATA:
case PMCLOG_TYPE_PROCCSW:
@@ -368,7 +376,7 @@
pmcview::process(struct pmclog_ev_procexit &p)
{
/*
- * XXX: Seems we can recieve samples after the process exits we need
+ * XXX: Seems we can receive samples after the process exits we need
* some way to delay cleanup, then after the delayed cleanup discard
* delayed events.
*/
@@ -436,13 +444,14 @@
* if the dwarf symbols are available.
*/
image
-pmcview::loadimage(const std::string &path)
+pmcview::loadimage(const std::string &path, bool iskernel)
{
std::string fullpath;
image im;
GElf_Ehdr eh;
Elf *e;
const char *elf;
+ size_t filesz;
uint64_t start;
uint64_t end;
size_t shstrndx;
@@ -486,11 +495,11 @@
if (eh.e_type != ET_EXEC && eh.e_type != ET_DYN && eh.e_type != ET_REL) {
warnx("WARNING: ELF file type is unsupported for \"%s\".",
- fullpath.c_str());;
+ fullpath.c_str());
goto done;
}
- elf = elf_rawfile(e, NULL);
+ elf = elf_rawfile(e, &filesz);
if (elf == NULL) {
warnx("WARNING: Cannot read the ELF file for \"%s\": %s.",
fullpath.c_str(), elf_errmsg(-1));
@@ -514,19 +523,39 @@
}
if (ph.p_type == PT_INTERP) {
- im.loader = elf + ph.p_offset;
+ int chklen;
+ const char *loader;
+
+ if (ph.p_offset > filesz) {
+ warnx("WARNING: Program header exceeds elf end for \"%s\".",
+ fullpath.c_str());
+ goto done;
+ }
+
+ chklen = ((filesz - ph.p_offset) < 256) ? (filesz - ph.p_offset) : 256;
+ loader = elf + ph.p_offset;
+ im.loader.assign(elf + ph.p_offset, strnlen(loader, chklen));
}
if (ph.p_type == PT_LOAD) {
if ((ph.p_flags & PF_X) != 0 && !foundexec) {
- im.vaddr = ph.p_vaddr & ~(ph.p_align - 1);
+ uint64_t alignment;
+
+ alignment = iskernel ? ph.p_align :
+ (pageshift != 0 ? 1ULL << pageshift :
+ (uint64_t)getpagesize());
+ im.vaddr = rounddown2(ph.p_vaddr, alignment);
foundexec = true;
}
}
}
}
- elf_getshdrstrndx(e, &shstrndx);
+ if (elf_getshdrstrndx(e, &shstrndx) != 0) {
+ warnx("WARNING: Could not retrieve section index for string table for \"%s\".",
+ fullpath.c_str());
+ goto done;
+ }
start = ~(0x0ULL);
end = 0;
@@ -566,7 +595,7 @@
im.name = basename(fullpath);
/*
- * If the dwarf symbols aren't embedded check:
+ * If the DWARF symbols aren't embedded check:
* 1. SYSROOT + /path + .debug
* 2. SYSROOT + /usr/lib/debug + /path + .debug
*/
@@ -622,22 +651,13 @@
if ((fname = elf_strptr(e, sh->sh_link, sym.st_name)) == NULL)
continue;
- // XXX: Extra checks to make sure we don't get corrupted
- for (int i = 0; fname[i] != 0 && i < 32; i++) {
- if (!isascii(fname[i])) {
- printf("EEEK SYMBOL\n");
- printf("%s\n", fname);
- assert(false);
- }
- }
-
si.offset = sym.st_value;
si.length = sym.st_size;
- si.binary = im->name;
+ si.binary = im->path;
si.name = fname;
im->symbols[si.offset] = si;
- }
+ }
}
void
@@ -727,8 +747,9 @@
{
// Kernel map-in events should be mapped to pid 0
pid_t pid = (p.pl_pid == -1) ? 0 : p.pl_pid;
+ pageshift = 12; //p.pl_pageshift;
- image im = loadimage(p.pl_pathname);
+ image im = loadimage(p.pl_pathname, pid == 0);
mapimage(pid, im, p.pl_start);
}
@@ -756,6 +777,7 @@
uintfptr_t *cc = &p.pl_pc[1];
ibsfetchinfo ibsf;
ibsopinfo ibso;
+ uint16_t cclen;
/*
* Callchain events are always attributed to one of the kernel
@@ -771,6 +793,9 @@
type = hdr[2 * i];
len = hdr[2 * i + 1];
+ if (cc + len - &p.pl_pc[0] > p.pl_npc)
+ errx(EX_DATAERR, "Multipart payload lenght exceeds callchain size");
+
switch (type) {
case PMC_CC_MULTIPART_IBS_FETCH:
ibsf.len = len;
@@ -795,6 +820,18 @@
cc += len;
}
+
+ /*
+ * Compute the length for the remaining entries which contain
+ * the stack.
+ */
+ cclen = p.pl_npc - (cc - &p.pl_pc[0]);
+ } else {
+ /*
+ * Default case for non-multipart payloads
+ */
+ cc = &p.pl_pc[0];
+ cclen = p.pl_npc;
}
/*
@@ -845,7 +882,7 @@
if (ibsf.len) {
if (filter.ibs_ldlat > IBS_FETCH_CTL_TO_LAT(ibsf.ctl))
return;
- callchain(p, ibsf, cc, len);
+ callchain(p, ibsf, cc, cclen);
} else if (ibso.len) {
if (filter.ibs_oplat > IBS_OP_DATA_TO_COMPTORET(ibso.data))
return;
@@ -859,9 +896,9 @@
((ibso.data3 & IBS_OP_DATA3_WCMEMACCESS) == 0))
return;
}
- callchain(p, ibso, cc, len);
+ callchain(p, ibso, cc, cclen);
} else {
- callchain(p, cc, len);
+ callchain(p, cc, cclen);
}
}
@@ -911,10 +948,14 @@
addr -= vm->lowpc - im->start;
// Load symbols if they haven't been loaded
- if (im->symbols.size() == 0) {
+ if (!im->loaded) {
+ im->loaded = true;
loadsymbols(im);
}
+ if (im->symbols.size() == 0)
+ return syminfo();
+
// Look for the first symbol
auto s = im->symbols.upper_bound(addr);
if (s != im->symbols.begin())
@@ -940,10 +981,9 @@
#endif
si = syminfo();
- si.binary = im->name;
- std::stringstream str = std::stringstream();
- str << "0x" << std::hex << addr;
- si.name = str.str();
+ si.binary = im->path;
+ si.offset = addr;
+ si.name = "";
return si;
}

File Metadata

Mime Type
text/plain
Expires
Thu, Nov 12, 11:49 PM (14 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41686649
Default Alt Text
D61447.1794527375.diff (13 KB)

Event Timeline