[TSan] Move the /proc/self/maps parsing logic to sanitizer_common

Provide a generic way for the tools to generate memory profiles from contents of /proc/self/maps

llvm-svn: 189789
This commit is contained in:
Alexander Potapenko 2013-09-03 11:09:16 +00:00
parent e2391f66f9
commit 7e1c51988d
3 changed files with 78 additions and 59 deletions

View File

@ -403,6 +403,30 @@ static bool IsDecimal(char c) {
return c >= '0' && c <= '9';
}
static bool IsHex(char c) {
return (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'f');
}
static uptr ReadHex(const char *p) {
uptr v = 0;
for (; IsHex(p[0]); p++) {
if (p[0] >= '0' && p[0] <= '9')
v = v * 16 + p[0] - '0';
else
v = v * 16 + p[0] - 'a' + 10;
}
return v;
}
static uptr ReadDecimal(const char *p) {
uptr v = 0;
for (; IsDecimal(p[0]); p++)
v = v * 10 + p[0] - '0';
return v;
}
bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
char filename[], uptr filename_size,
uptr *protection) {
@ -473,6 +497,30 @@ bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
protection);
}
void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
char *smaps = 0;
uptr smaps_cap = 0;
uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
&smaps, &smaps_cap, 64<<20);
uptr total = 0;
uptr start = 0;
bool file = false;
const char *pos = smaps;
while (pos < smaps + smaps_len) {
if (IsHex(pos[0])) {
start = ReadHex(pos);
for (; *pos != '/' && *pos > '\n'; pos++) {}
file = *pos == '/';
} else if (internal_strncmp(pos, "Rss:", 4) == 0) {
for (; *pos < '0' || *pos > '9'; pos++) {}
uptr rss = ReadDecimal(pos) * 1024;
cb(start, rss, file, stats, stats_size);
}
while (*pos++ != '\n') {}
}
UnmapOrDie(smaps, smaps_cap);
}
enum MutexState {
MtxUnlocked = 0,
MtxLocked = 1,

View File

@ -32,7 +32,7 @@ class MemoryMappingLayout {
}
};
#else // _WIN32
#else // SANITIZER_WINDOWS
#if SANITIZER_LINUX
struct ProcSelfMapsBuff {
char *data;
@ -118,7 +118,15 @@ class MemoryMappingLayout {
# endif
};
#endif // _WIN32
typedef void (*fill_profile_f)(uptr start, uptr rss, bool file,
/*out*/uptr *stats, uptr stats_size);
// Parse the contents of /proc/self/smaps and generate a memory profile.
// |cb| is a tool-specific callback that fills the |stats| array containing
// |stats_size| elements.
void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size);
#endif // SANITIZER_WINDOWS
} // namespace __sanitizer

View File

@ -72,70 +72,33 @@ ScopedInRtl::~ScopedInRtl() {
}
#endif
static bool ishex(char c) {
return (c >= '0' && c <= '9')
|| (c >= 'a' && c <= 'f');
}
static uptr readhex(const char *p) {
uptr v = 0;
for (; ishex(p[0]); p++) {
if (p[0] >= '0' && p[0] <= '9')
v = v * 16 + p[0] - '0';
else
v = v * 16 + p[0] - 'a' + 10;
}
return v;
}
static uptr readdec(const char *p) {
uptr v = 0;
for (; p[0] >= '0' && p[0] <= '9' ; p++)
v = v * 10 + p[0] - '0';
return v;
void FillProfileCallback(uptr start, uptr rss, bool file,
uptr *mem, uptr stats_size) {
CHECK_EQ(7, stats_size);
mem[6] += rss; // total
start >>= 40;
if (start < 0x10) // shadow
mem[0] += rss;
else if (start >= 0x20 && start < 0x30) // compat modules
mem[file ? 1 : 2] += rss;
else if (start >= 0x7e) // modules
mem[file ? 1 : 2] += rss;
else if (start >= 0x60 && start < 0x62) // traces
mem[3] += rss;
else if (start >= 0x7d && start < 0x7e) // heap
mem[4] += rss;
else // other
mem[5] += rss;
}
void WriteMemoryProfile(char *buf, uptr buf_size) {
char *smaps = 0;
uptr smaps_cap = 0;
uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
&smaps, &smaps_cap, 64<<20);
uptr mem[6] = {};
uptr total = 0;
uptr start = 0;
bool file = false;
const char *pos = smaps;
while (pos < smaps + smaps_len) {
if (ishex(pos[0])) {
start = readhex(pos);
for (; *pos != '/' && *pos > '\n'; pos++) {}
file = *pos == '/';
} else if (internal_strncmp(pos, "Rss:", 4) == 0) {
for (; *pos < '0' || *pos > '9'; pos++) {}
uptr rss = readdec(pos) * 1024;
total += rss;
start >>= 40;
if (start < 0x10) // shadow
mem[0] += rss;
else if (start >= 0x20 && start < 0x30) // compat modules
mem[file ? 1 : 2] += rss;
else if (start >= 0x7e) // modules
mem[file ? 1 : 2] += rss;
else if (start >= 0x60 && start < 0x62) // traces
mem[3] += rss;
else if (start >= 0x7d && start < 0x7e) // heap
mem[4] += rss;
else // other
mem[5] += rss;
}
while (*pos++ != '\n') {}
}
UnmapOrDie(smaps, smaps_cap);
uptr mem[7] = {};
__sanitizer::GetMemoryProfile(FillProfileCallback, mem, 7);
char *buf_pos = buf;
char *buf_end = buf + buf_size;
buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos,
"RSS %zd MB: shadow:%zd file:%zd mmap:%zd trace:%zd heap:%zd other:%zd\n",
total >> 20, mem[0] >> 20, mem[1] >> 20, mem[2] >> 20,
mem[6] >> 20, mem[0] >> 20, mem[1] >> 20, mem[2] >> 20,
mem[3] >> 20, mem[4] >> 20, mem[5] >> 20);
struct mallinfo mi = __libc_mallinfo();
buf_pos += internal_snprintf(buf_pos, buf_end - buf_pos,