Skip to content

Commit

Permalink
[memory-infra] Implement PollFastMemoryTotal in ProcessMetricsMemoryD…
Browse files Browse the repository at this point in the history
…umpProvider.

For fast polling the dump provider keeps the /proc/<pid>/statm files
open during the tracing session.

BUG=607533

Review-Url: https://codereview.chromium.org/2568313004
Cr-Commit-Position: refs/heads/master@{#439405}
  • Loading branch information
ssiddhartha authored and Commit bot committed Dec 19, 2016
1 parent 0eebfb8 commit 3583cfe
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 9 deletions.
55 changes: 53 additions & 2 deletions components/tracing/common/process_metrics_memory_dump_provider.cc
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,18 @@ uint32_t ReadLinuxProcSmapsFile(FILE* smaps_file,
}
return num_valid_regions;
}

bool GetResidentSizeFromStatmFile(int fd, uint64_t* resident_pages) {
lseek(fd, 0, SEEK_SET);
char line[kMaxLineSize];
int res = read(fd, line, kMaxLineSize - 1);
if (res <= 0)
return false;
line[res] = '\0';
int num_scanned = sscanf(line, "%*s %" SCNu64, resident_pages);
return num_scanned == 1;
}

#endif // defined(OS_LINUX) || defined(OS_ANDROID)

std::unique_ptr<base::ProcessMetrics> CreateProcessMetrics(
Expand Down Expand Up @@ -183,6 +195,9 @@ uint64_t ProcessMetricsMemoryDumpProvider::rss_bytes_for_testing = 0;
// static
FILE* ProcessMetricsMemoryDumpProvider::proc_smaps_for_testing = nullptr;

// static
int ProcessMetricsMemoryDumpProvider::fast_polling_statm_fd_for_testing = -1;

bool ProcessMetricsMemoryDumpProvider::DumpProcessMemoryMaps(
const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) {
Expand Down Expand Up @@ -211,6 +226,7 @@ void ProcessMetricsMemoryDumpProvider::RegisterForProcess(
new ProcessMetricsMemoryDumpProvider(process));
base::trace_event::MemoryDumpProvider::Options options;
options.target_pid = process;
options.is_fast_polling_supported = true;
base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
metrics_provider.get(), "ProcessMemoryMetrics", nullptr, options);
bool did_insert =
Expand All @@ -229,9 +245,8 @@ void ProcessMetricsMemoryDumpProvider::RegisterForProcess(
void ProcessMetricsMemoryDumpProvider::UnregisterForProcess(
base::ProcessId process) {
auto iter = g_dump_providers_map.Get().find(process);
if (iter == g_dump_providers_map.Get().end()) {
if (iter == g_dump_providers_map.Get().end())
return;
}
base::trace_event::MemoryDumpManager::GetInstance()
->UnregisterAndDeleteDumpProviderSoon(std::move(iter->second));
g_dump_providers_map.Get().erase(iter);
Expand Down Expand Up @@ -322,4 +337,40 @@ bool ProcessMetricsMemoryDumpProvider::DumpProcessTotals(
return true;
}

void ProcessMetricsMemoryDumpProvider::PollFastMemoryTotal(
uint64_t* memory_total) {
*memory_total = 0;
#if defined(OS_LINUX) || defined(OS_ANDROID)
int statm_fd = fast_polling_statm_fd_for_testing;
if (statm_fd == -1) {
if (!fast_polling_statm_fd_.is_valid()) {
std::string name = "/proc/" + (process_ == base::kNullProcessId
? "self"
: base::IntToString(process_)) +
"/statm";
fast_polling_statm_fd_.reset(open(name.c_str(), O_RDONLY));
DCHECK(fast_polling_statm_fd_.is_valid());
}
statm_fd = fast_polling_statm_fd_.get();
}
if (statm_fd == -1)
return;

uint64_t rss_pages = 0;
if (!GetResidentSizeFromStatmFile(statm_fd, &rss_pages))
return;

static size_t page_size = base::GetPageSize();
*memory_total = rss_pages * page_size;
#else
*memory_total = process_metrics_->GetWorkingSetSize();
#endif
}

void ProcessMetricsMemoryDumpProvider::SuspendFastMemoryPolling() {
#if defined(OS_LINUX) || defined(OS_ANDROID)
fast_polling_statm_fd_.reset();
#endif
}

} // namespace tracing
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <memory>

#include "base/files/scoped_file.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/process/process_handle.h"
Expand All @@ -33,11 +34,15 @@ class TRACING_EXPORT ProcessMetricsMemoryDumpProvider
// MemoryDumpProvider implementation.
bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
base::trace_event::ProcessMemoryDump* pmd) override;
void PollFastMemoryTotal(uint64_t* memory_total) override;
void SuspendFastMemoryPolling() override;

private:
FRIEND_TEST_ALL_PREFIXES(ProcessMetricsMemoryDumpProviderTest,
ParseProcSmaps);
FRIEND_TEST_ALL_PREFIXES(ProcessMetricsMemoryDumpProviderTest, DumpRSS);
FRIEND_TEST_ALL_PREFIXES(ProcessMetricsMemoryDumpProviderTest,
TestPollFastMemoryTotal);

ProcessMetricsMemoryDumpProvider(base::ProcessId process);

Expand All @@ -50,6 +55,9 @@ class TRACING_EXPORT ProcessMetricsMemoryDumpProvider

#if defined(OS_LINUX) || defined(OS_ANDROID)
static FILE* proc_smaps_for_testing;
static int fast_polling_statm_fd_for_testing;

base::ScopedFD fast_polling_statm_fd_;
#endif

base::ProcessId process_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <memory>

#include "base/files/file_util.h"
#include "base/memory/ptr_util.h"
#include "base/process/process_metrics.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/process_memory_maps.h"
#include "base/trace_event/process_memory_totals.h"
Expand Down Expand Up @@ -107,15 +109,16 @@ const char kTestSmaps2[] =
"Locked: 0 kB\n"
"VmFlags: rd wr mr mw me ac sd\n";

void CreateAndSetSmapsFileForTesting(const char* smaps_string,
base::ScopedFILE& file) {
const char kTestStatm[] = "200 100 20 2 3 4";

void CreateTempFileWithContents(const char* contents, base::ScopedFILE* file) {
base::FilePath temp_path;
FILE* temp_file = CreateAndOpenTemporaryFile(&temp_path);
file.reset(temp_file);
file->reset(temp_file);
ASSERT_TRUE(temp_file);

ASSERT_TRUE(base::WriteFileDescriptor(fileno(temp_file), smaps_string,
strlen(smaps_string)));
ASSERT_TRUE(
base::WriteFileDescriptor(fileno(temp_file), contents, strlen(contents)));
}

} // namespace
Expand Down Expand Up @@ -182,7 +185,7 @@ TEST(ProcessMetricsMemoryDumpProviderTest, ParseProcSmaps) {
base::trace_event::ProcessMemoryDump pmd_1(nullptr /* session_state */,
dump_args);
base::ScopedFILE temp_file1;
CreateAndSetSmapsFileForTesting(kTestSmaps1, temp_file1);
CreateTempFileWithContents(kTestSmaps1, &temp_file1);
ProcessMetricsMemoryDumpProvider::proc_smaps_for_testing = temp_file1.get();
pmmdp->OnMemoryDump(dump_args, &pmd_1);
ASSERT_TRUE(pmd_1.has_process_mmaps());
Expand Down Expand Up @@ -215,7 +218,7 @@ TEST(ProcessMetricsMemoryDumpProviderTest, ParseProcSmaps) {
base::trace_event::ProcessMemoryDump pmd_2(nullptr /* session_state */,
dump_args);
base::ScopedFILE temp_file2;
CreateAndSetSmapsFileForTesting(kTestSmaps2, temp_file2);
CreateTempFileWithContents(kTestSmaps2, &temp_file2);
ProcessMetricsMemoryDumpProvider::proc_smaps_for_testing = temp_file2.get();
pmmdp->OnMemoryDump(dump_args, &pmd_2);
ASSERT_TRUE(pmd_2.has_process_mmaps());
Expand All @@ -234,4 +237,36 @@ TEST(ProcessMetricsMemoryDumpProviderTest, ParseProcSmaps) {
}
#endif // defined(OS_LINUX) || defined(OS_ANDROID)

TEST(ProcessMetricsMemoryDumpProviderTest, TestPollFastMemoryTotal) {
ProcessMetricsMemoryDumpProvider mdp(base::kNullProcessId);

uint64_t total1, total2;
mdp.PollFastMemoryTotal(&total1);
ASSERT_GT(total1, 0u);
size_t kBufSize = 16 * 1024 * 1024;
auto buf = base::MakeUnique<char[]>(kBufSize);
for (size_t i = 0; i < kBufSize; i++)
buf[i] = *((volatile char*)&buf[i]) + 1;
mdp.PollFastMemoryTotal(&total2);
ASSERT_GT(total2, 0u);
EXPECT_GT(total2, total1 + kBufSize / 2);

#if defined(OS_LINUX) || defined(OS_ANDROID)
EXPECT_GE(mdp.fast_polling_statm_fd_.get(), 0);

base::ScopedFILE temp_file;
CreateTempFileWithContents(kTestStatm, &temp_file);
mdp.fast_polling_statm_fd_for_testing = fileno(temp_file.get());
size_t page_size = base::GetPageSize();
uint64_t value;
mdp.PollFastMemoryTotal(&value);
EXPECT_EQ(100 * page_size, value);

mdp.SuspendFastMemoryPolling();
EXPECT_FALSE(mdp.fast_polling_statm_fd_.is_valid());
#else
mdp.SuspendFastMemoryPolling();
#endif
}

} // namespace tracing

0 comments on commit 3583cfe

Please sign in to comment.