#ifndef __VIEW_HH__
#define __VIEW_HH__
#include <libdwarf.h>
#include <libelf.h>
#include <libutil.h>
#include <gelf.h>
#include "headers.hh"
#include "util.hh"
struct pmcinfo
{
pmcinfo() : name(), rate(-1), event(0), count(0) { }
pmcinfo(struct pmclog_ev_pmcallocate &p) {
name = p.pl_evname;
rate = p.pl_rate;
event = p.pl_event;
count = 0;
}
pmcinfo(struct pmclog_ev_pmcallocatedyn &p) {
name = p.pl_evname;
rate = 0;
event = p.pl_event;
count = 0;
}
~pmcinfo() { }
std::string name;
int rate;
uint32_t event;
uint64_t count;
};
struct pmcinfox
{
pmcinfox() : rate(0), event() { }
pmcinfox(uint32_t rate, std::string event) : rate(rate), event(event) { }
~pmcinfox() { }
uint32_t rate;
std::string event;
};
struct cpuidleaf
{
uint32_t eax;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
};
struct vmmap
{
vmmap() : lowpc(0), highpc(0), image("") { }
~vmmap() { }
uint64_t lowpc;
uint64_t highpc;
std::string image;
};
struct threadinfo
{
threadinfo() : name("") { }
threadinfo(const std::string &name) : name(name) { }
~threadinfo() { }
std::string name;
};
struct procinfo
{
procinfo() : name(""), fullpath(""), map(), threads(),
baseaddr(0), dynaddr(0) { }
procinfo(struct pmclog_ev_proccreate &p) {
std::string pname = p.pl_pcomm;
if ((p.pl_flags & P_KPROC) != 0)
name = "[" + pname + "]";
else
name = pname;
map = std::map<uint64_t, vmmap>();
threads = std::map<pid_t, threadinfo>();
baseaddr = 0;
dynaddr = 0;
}
~procinfo() { }
std::string name;
std::string fullpath;
std::map<uint64_t, vmmap> map;
std::map<pid_t, threadinfo> threads;
uint64_t baseaddr;
uint64_t dynaddr;
};
struct syminfo
{
syminfo() : binary(""), name(""), offset(0), length(0), funcoff(0),
line(0), column(0) { }
~syminfo() { }
std::string to_string(bool show_line = true);
std::string binary;
std::string name;
uint64_t offset;
uint64_t length;
uint64_t funcoff;
uint32_t line;
uint32_t column;
};
struct image
{
image() : isdynamic(false), vaddr(0), start(0), end(0),
offset(0), name(""), binary(""), path(""), loader(""),
dwarf(""), symbols(), dbg_fd(-1), dbg_elf(NULL) { }
~image() { }
bool isdynamic;
uint64_t vaddr;
uint64_t start;
uint64_t end;
uint64_t offset;
std::string name;
std::string binary;
std::string path;
std::string loader;
std::string dwarf;
std::map<uint64_t, syminfo> symbols;
int dbg_fd;
Elf *dbg_elf;
Dwarf_Debug dbg_dwarf;
};
struct pmcfilter
{
pmcfilter() : filterpid(false), filtertid(false),
filterprogram(false), filterthread(false),
filterevent(false), filtercpu(false),
kernelonly(false), useronly(false),
pids(), tids(), programs(), threads(),
ibs_ldlat(0), ibs_oplat(0) { CPU_ZERO(&cpus); }
~pmcfilter() { }
bool filterpid;
bool filtertid;
bool filterprogram;
bool filterthread;
bool filterevent;
bool filtercpu;
bool kernelonly;
bool useronly;
std::unordered_set<int> pids;
std::unordered_set<int> tids;
std::unordered_set<std::string> programs;
std::unordered_set<std::string> threads;
std::unordered_set<std::string> events;
cpuset_t cpus;
uint64_t ibs_ldlat;
uint64_t ibs_oplat;
bool ibs_mmio;
void addpids(const char *ids) {
split_and_insert(&pids, ids);
filterpid = true;
}
void addtids(const char *ids) {
split_and_insert(&tids, ids);
filtertid = true;
}
void addthreads(const char *ids) {
split_and_insert(&threads, ids);
filterthread = true;
}
void addprograms(const char *ids) {
split_and_insert(&programs, ids);
filterprogram = true;
}
void addevents(const char *ids) {
split_and_insert(&events, ids);
filterevent = true;
}
void addcpus(const char *ids) {
if (cpuset_parselist(ids, &cpus) == CPUSET_PARSE_OK)
filtercpu = true;
else
fprintf(stderr, "Cannot parse cpulist");
}
};
#define PMCFILTER_PRINTOPTS() \
do { \
printf("Filter Options:\n"); \
printf("\t-t,--lwps Filter by thread id\n"); \
printf("\t-p,--pids Filter by process id\n"); \
printf("\t-T,--threads Filter by thread name\n"); \
printf("\t-P,--processes Filter by process name\n"); \
printf("\t-e,--event Filter by event\n"); \
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("\nIBS Fetch Options:\n"); \
printf("\t--ldlat Filter by load latency\n"); \
printf("\nIBS Op Options:\n"); \
printf("\t--ldlat Filter by load latency\n"); \
printf("\t--oplat Filter by operation latency\n"); \
printf("\t--mmio Show only mmio events\n"); \
} while (0)
#define PMCFILTER_LOPTS \
{ "lwps", required_argument, NULL, 't' }, \
{ "pids", required_argument, NULL, 'p' }, \
{ "threads", required_argument, NULL, 'T' }, \
{ "processes", required_argument, NULL, 'P' }, \
{ "events", 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"
#define PMCFILTER_CASE(_filt) \
case 't': \
_filt.addtids(optarg); \
break; \
case 'p': \
_filt.addpids(optarg); \
break; \
case 'T': \
_filt.addthreads(optarg); \
break; \
case 'P': \
_filt.addprograms(optarg); \
break; \
case 'e': \
_filt.addevents(optarg); \
break; \
case 'c': \
_filt.addcpus(optarg); \
break; \
case 'k': \
_filt.kernelonly = true; \
break; \
case 'u': \
_filt.useronly = true; \
break; \
case 10: \
_filt.ibs_ldlat = atoi(optarg); \
break; \
case 11: \
_filt.ibs_oplat = atoi(optarg); \
break; \
case 12: \
_filt.ibs_mmio = true; \
break;
struct ibsfetchinfo
{
int len;
uint64_t ctl;
uint64_t extctl;
uint64_t linaddr;
uint64_t physaddr;
};
struct ibsopinfo
{
int len;
uint64_t ctl;
uint64_t rip;
uint64_t data;
uint64_t data2;
uint64_t data3;
uint64_t linaddr;
uint64_t physaddr;
uint64_t tgtrip;
uint64_t data4;
};
class pmcview
{
protected:
pmcview();
virtual ~pmcview();
public:
void setfilter(const pmcfilter &pmcfilter);
virtual void proccreate(__unused pid_t pid) { };
virtual void procexec(__unused pid_t pid) { };
virtual void procexit(__unused pid_t pid) { };
virtual void callchain(struct pmclog_ev_callchain &p,
__unused ibsfetchinfo &f, uintfptr_t *cc, int len) {
callchain(p, cc, len);
}
virtual void callchain(struct pmclog_ev_callchain &p,
__unused ibsopinfo &o, uintfptr_t *cc, int len) {
callchain(p, cc, len);
}
virtual void callchain(struct pmclog_ev_callchain &p,
__unused uintfptr_t *cc, __unused int len) {
callchain(p);
}
virtual void callchain(__unused struct pmclog_ev_callchain &p) { }
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 process(int logfd);
virtual void process(struct pmclog_ev &p);
virtual void process(struct pmclog_parse_state *ps);
virtual void process(struct pmclog_ev_initialize &p);
virtual void process(struct pmclog_ev_closelog &p);
virtual void process(struct pmclog_ev_pmcallocate &p);
virtual void process(struct pmclog_ev_pmcallocatedyn &p);
virtual void process(struct pmclog_ev_proccreate &p);
virtual void process(struct pmclog_ev_procexit &p);
virtual void process(struct pmclog_ev_procexec &p);
virtual void process(struct pmclog_ev_procfork &p);
virtual void process(struct pmclog_ev_sysexit &p);
virtual void process(struct pmclog_ev_threadcreate &p);
virtual void process(struct pmclog_ev_threadexit &p);
virtual void process(struct pmclog_ev_map_in &p);
virtual void process(struct pmclog_ev_map_out &p);
virtual void process(struct pmclog_ev_callchain &p);
protected:
uint32_t pmcidtoeventid(uint32_t pmcid);
std::string pidtoname(pid_t pid);
syminfo addrtosymbol(pid_t pid, uint64_t addr);
void printvm(pid_t pid);
uint64_t tscfreq;
std::unordered_map<uint32_t, uint32_t> pmcid;
std::unordered_map<uint32_t, pmcinfo> pmcinfo;
std::unordered_map<pid_t, procinfo> procs;
std::unordered_map<pid_t, pid_t> tidtopid;
std::unordered_map<std::string, image> images;
std::string sysroot;
pmcfilter filter;
int arch;
std::string cpumodel;
std::string osrelease;
std::string buildid;
std::vector<pmcinfox> extpmcinfo;
std::map<uint32_t, cpuidleaf> cpuid;
private:
image loadimage(const std::string &path);
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);
};
#endif