mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
hwpmc: hwpmc: record page size to fix analysis in some case
This fixes a bug where a binary linked using max-page-size=0x200000 can result in a bogus relocation offset when running on a system with a smaller page size. This causes samples to fall outside the image mapping or be translated to the wrong address (resulting in symbol resolution, or incorrect symbol resolution). We noticed this at Netflix because we run a patchset enabling 16k pages on amd64 and have been compiling userspace with a 2MB page size. Since we started doing this profiling userspace binaries has been wonky. Reviewed by: ali_mashtizadeh.com Differential Revision: https://reviews.freebsd.org/D59771 Sponsored by: Netflix
This commit is contained in:
1 parent
ac9c07a3e9
commit
2449fa9c4d
9 files changed
+52
-12
No files matched your search
+1
-1
@@ -338,7 +338,7 @@ pmclog_get_event(void *cookie, char **data, ssize_t *len,
|
||||
case PMCLOG_TYPE_MAP_IN:
|
||||
PMCLOG_GET_PATHLEN(pathlen,evlen,pmclog_map_in);
|
||||
PMCLOG_READ32(le,ev->pl_u.pl_mi.pl_pid);
|
||||
PMCLOG_SKIP32(le);
|
||||
PMCLOG_READ32(le,ev->pl_u.pl_mi.pl_u);
|
||||
PMCLOG_READADDR(le,ev->pl_u.pl_mi.pl_start);
|
||||
PMCLOG_READSTRING(le, ev->pl_u.pl_mi.pl_pathname, pathlen);
|
||||
break;
|
||||
|
||||
@@ -69,6 +69,13 @@ struct pmclog_ev_initialize {
|
||||
|
||||
struct pmclog_ev_map_in {
|
||||
pid_t pl_pid;
|
||||
union {
|
||||
uint32_t pl_u;
|
||||
struct {
|
||||
uint8_t pl_pageshift;
|
||||
uint8_t pl_pad[3];
|
||||
};
|
||||
};
|
||||
uintfptr_t pl_start;
|
||||
char pl_pathname[PATH_MAX];
|
||||
};
|
||||
|
||||
@@ -132,6 +132,7 @@ struct pmcstat_args {
|
||||
int pa_mergepmc; /* merge PMC with same name */
|
||||
double pa_duration; /* time duration */
|
||||
uint32_t pa_tid;
|
||||
uint8_t pa_pageshift; /* page shift recorded in log */
|
||||
int pa_argc;
|
||||
char **pa_argv;
|
||||
STAILQ_HEAD(, pmcstat_ev) pa_events;
|
||||
|
||||
@@ -312,7 +312,7 @@ pmcstat_image_get_elf_params(struct pmcstat_image *image,
|
||||
const char *path, *elfbase;
|
||||
char *p, *endp;
|
||||
bool first_exec_segment;
|
||||
uintfptr_t minva, maxva;
|
||||
uintfptr_t minva, maxva, pagesize;
|
||||
Elf *e;
|
||||
Elf_Scn *scn;
|
||||
GElf_Ehdr eh;
|
||||
@@ -330,6 +330,11 @@ pmcstat_image_get_elf_params(struct pmcstat_image *image,
|
||||
image->pi_dynlinkerpath = NULL;
|
||||
image->pi_vaddr = 0;
|
||||
|
||||
if (args->pa_pageshift != 0)
|
||||
pagesize = 1ULL << args->pa_pageshift;
|
||||
else
|
||||
pagesize = getpagesize();
|
||||
|
||||
path = pmcstat_string_unintern(image->pi_execpath);
|
||||
assert(path != NULL);
|
||||
|
||||
@@ -421,7 +426,17 @@ pmcstat_image_get_elf_params(struct pmcstat_image *image,
|
||||
case PT_LOAD:
|
||||
if ((ph.p_flags & PF_X) != 0 &&
|
||||
first_exec_segment) {
|
||||
image->pi_vaddr = ph.p_vaddr & (-ph.p_align);
|
||||
if (image->pi_iskernelmodule) {
|
||||
image->pi_vaddr = ph.p_vaddr &
|
||||
(-ph.p_align);
|
||||
} else {
|
||||
/*
|
||||
* User MAP_IN records depend
|
||||
* on page size.
|
||||
*/
|
||||
image->pi_vaddr = rounddown2(
|
||||
ph.p_vaddr, pagesize);
|
||||
}
|
||||
first_exec_segment = false;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -235,6 +235,7 @@ pmcstat_analyze_log(struct pmcstat_args *args,
|
||||
PMCSTAT_ALLOCATE);
|
||||
|
||||
assert(pp != NULL);
|
||||
args->pa_pageshift = ev.pl_u.pl_mi.pl_pageshift;
|
||||
|
||||
image_path = pmcstat_string_intern(ev.pl_u.pl_mi.
|
||||
pl_pathname);
|
||||
|
||||
@@ -947,6 +947,7 @@ void
|
||||
pmclog_process_map_in(struct pmc_owner *po, pid_t pid, uintfptr_t start,
|
||||
const char *path)
|
||||
{
|
||||
struct pmclog_map_in *mi;
|
||||
int pathlen, recordlen;
|
||||
|
||||
KASSERT(path != NULL, ("[pmclog,%d] map-in, null path", __LINE__));
|
||||
@@ -956,8 +957,11 @@ pmclog_process_map_in(struct pmc_owner *po, pid_t pid, uintfptr_t start,
|
||||
pathlen;
|
||||
|
||||
PMCLOG_RESERVE(po, PMCLOG_TYPE_MAP_IN, recordlen);
|
||||
mi = (struct pmclog_map_in *)ph;
|
||||
PMCLOG_EMIT32(pid);
|
||||
PMCLOG_EMIT32(0);
|
||||
mi->pl_u = 0;
|
||||
mi->pl_pageshift = PAGE_SHIFT;
|
||||
PMCLOG_EMIT32(mi->pl_u);
|
||||
PMCLOG_EMITADDR(start);
|
||||
PMCLOG_EMITSTRING(path,pathlen);
|
||||
PMCLOG_DESPATCH_SYNC(po);
|
||||
|
||||
+7
-1
@@ -159,7 +159,13 @@ struct pmclog_initialize {
|
||||
struct pmclog_map_in {
|
||||
PMCLOG_ENTRY_HEADER
|
||||
uint32_t pl_pid;
|
||||
uint32_t pl_pad;
|
||||
union {
|
||||
uint32_t pl_u;
|
||||
struct {
|
||||
uint8_t pl_pageshift;
|
||||
uint8_t pl_pad[3];
|
||||
};
|
||||
};
|
||||
uintfptr_t pl_start; /* 8 byte aligned */
|
||||
char pl_pathname[PATH_MAX];
|
||||
} __packed;
|
||||
|
||||
+11
-6
@@ -89,8 +89,8 @@ syminfo::to_string(bool show_line)
|
||||
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;
|
||||
|
||||
@@ -436,7 +436,7 @@ pmcview::process(struct pmclog_ev_threadexit &p)
|
||||
* 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;
|
||||
@@ -519,7 +519,12 @@ pmcview::loadimage(const std::string &path)
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -727,8 +732,9 @@ pmcview::process(struct pmclog_ev_map_in &p)
|
||||
{
|
||||
// Kernel map-in events should be mapped to pid 0
|
||||
pid_t pid = (p.pl_pid == -1) ? 0 : p.pl_pid;
|
||||
pageshift = p.pl_pageshift;
|
||||
|
||||
image im = loadimage(p.pl_pathname);
|
||||
image im = loadimage(p.pl_pathname, pid == 0);
|
||||
|
||||
mapimage(pid, im, p.pl_start);
|
||||
}
|
||||
@@ -958,4 +964,3 @@ pmcview::printvm(pid_t pid)
|
||||
i.second.highpc, i.second.image.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,6 +389,7 @@ protected:
|
||||
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;
|
||||
@@ -404,7 +405,7 @@ protected:
|
||||
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);
|
||||
|
||||
Reference in new issue
Block a user