Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(920)

Unified Diff: base/memory/i_heart_windows_memory.cc

Issue 2865653003: One perf test for windows VirtualQueryEx calls.
Patch Set: add many test cases Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/BUILD.gn ('k') | base/memory/memory_uma_perftest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/memory/i_heart_windows_memory.cc
diff --git a/base/memory/i_heart_windows_memory.cc b/base/memory/i_heart_windows_memory.cc
new file mode 100644
index 0000000000000000000000000000000000000000..70bc8623f35d9c2fb6dd04f3f7e9c700f2129afb
--- /dev/null
+++ b/base/memory/i_heart_windows_memory.cc
@@ -0,0 +1,526 @@
+#include <cstdio>
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/process/launch.h"
+#include "base/process/process.h"
+#include "base/process/process_metrics.h"
+#include "base/threading/platform_thread.h"
+
+namespace {
+using ProcessList = std::vector<base::Process*>;
+
+void SleepForever() {
+ for (;;) {
+ base::PlatformThread::Sleep(base::TimeDelta::FromMinutes(1));
+ }
+}
+
+void LoadDll() {}
+
+void CreateSharedMemoryButDontShare() {}
+
+void ShareMeSomeMemory(int num_regions, ProcessList process_list) {
+ for (base::Process* process : process_list) {
+ CHECK(process);
+ }
+}
+
+void ShareMeSomeCOWsAndTouchThem(int num_regions, ProcessList process_list) {
+ for (base::Process* process : process_list) {
+ CHECK(process);
+ }
+}
+
+void ForceSwap() {
+ char* leak = new char[12345];
+ leak = nullptr;
+}
+
+struct SavedStats {
+ size_t private_bytes;
+ size_t shared_bytes;
+ uint64_t pss_bytes;
+ base::WorkingSetKBytes working_set;
+ base::CommittedKBytes committed;
+};
+
+void SaveStats(SavedStats* saved_stats, base::Process* process) {
+ std::unique_ptr<base::ProcessMetrics> metrics =
+ base::ProcessMetrics::CreateProcessMetrics(process->Handle());
+
+ CHECK(metrics->GetMemoryBytes(&(saved_stats->private_bytes), &(saved_stats->shared_bytes)));
+ CHECK(metrics->GetProportionalSetSizeBytes(&(saved_stats->pss_bytes)));
+ CHECK(metrics->GetWorkingSetKBytes(&saved_stats->working_set));
+ metrics->GetCommittedKBytes(&saved_stats->committed);
+}
+
+void DumpDiff(SavedStats* first, SavedStats* second) {
+ LOG(ERROR) << " - private kbytes: " << ((int64_t)second->private_bytes - (int64_t)first->private_bytes) / 1024;
+ LOG(ERROR) << " - shared kbytes: " << ((int64_t)second->shared_bytes - (int64_t)first->shared_bytes) / 1024;
+ LOG(ERROR) << " - pss kbytes: " << ((int64_t)second->pss_bytes - (int64_t)first->pss_bytes) / 1024;
+ LOG(ERROR) << " - workingset private kb: " << ((int64_t)second->working_set.priv - (int64_t)first->working_set.priv);
+ LOG(ERROR) << " - workingset mapped kb: " << ((int64_t)second->working_set.shareable - (int64_t)first->working_set.shareable);
+ LOG(ERROR) << " - workingset image kb: " << ((int64_t)second->working_set.shared - (int64_t)first->working_set.shared);
+ LOG(ERROR) << " - committed private kb: " << ((int64_t)second->committed.priv - (int64_t)first->committed.priv);
+ LOG(ERROR) << " - committed mapped kb: " << ((int64_t)second->committed.mapped - (int64_t)first->committed.mapped);
+ LOG(ERROR) << " - committed image kb: " << ((int64_t)second->committed.image - (int64_t)first->committed.image);
+ LOG(ERROR) << std::endl << std::endl;
+}
+
+} // namespace
+
+void malloc1() {
+ LOG(ERROR) << "malloc 16MB, and touch every page";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+
+ char*a = (char*)malloc(16 * 1024 * 1024);
+ for (int i = 0; i < 16 * 1024 * 1024; ++i) {
+ a[i] = 'a';
+ }
+ SaveStats(&second, &process);
+
+ DumpDiff(&first, &second);
+}
+
+void malloc2() {
+ LOG(ERROR) << "malloc 16MB, but only touch every 16th page";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+
+ char*a = (char*)malloc(16 * 1024 * 1024);
+ for(int i = 0; i < 16 * 1024 * 1024 / (16 * 4096); ++i) {
+ a[i * 16 * 4096] = 'a';
+ }
+ SaveStats(&second, &process);
+
+ DumpDiff(&first, &second);
+}
+
+void malloc3() {
+ LOG(ERROR) << "malloc 16MB, touch every page, then free";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+
+ char*a = (char*)malloc(16 * 1024 * 1024);
+ for (int i = 0; i < 16 * 1024 * 1024; ++i) {
+ a[i] = 'a';
+ }
+ free(a);
+ SaveStats(&second, &process);
+
+ DumpDiff(&first, &second);
+}
+
+void malloc4() {
+ LOG(ERROR) << "malloc 16MB in 1024 chunks, touch every page, then free every chunk that isn't a multiple of 16";
+ LOG(ERROR) << "I expect resident memory to hit ~4MB, but instead it stays at 16MB! What's going on?";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ std::vector<char*> chunks;
+ chunks.resize(16 * 1024);
+
+ SaveStats(&first, &process);
+ for (int i = 0; i < 16 * 1024; ++i) {
+ chunks[i] = (char*)malloc(1024);
+ chunks[i][0] = 'a';
+ }
+
+ for (int i = 0; i < 16 * 1024; ++i) {
+ if (i % 16 != 0)
+ free(chunks[i]);
+ }
+ SaveStats(&second, &process);
+
+ DumpDiff(&first, &second);
+}
+
+void anonymous_file_mapping1() {
+ LOG(ERROR) << "create 16MB anonymous file mapping, and touch every page";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+ HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
+ 16 * 1024 * 1024, NULL);
+ char*a = (char*) MapViewOfFile(h, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 16 * 1024 *1024);
+ for (int i = 0; i < 16 * 1024 * 1024; ++i)
+ a[i] = 'a';
+ SaveStats(&second, &process);
+ DumpDiff(&first, &second);
+}
+
+void anonymous_file_mapping2() {
+ LOG(ERROR) << "create 16MB anonymous file mapping";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+ CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
+ 16 * 1024 * 1024, NULL);
+ SaveStats(&second, &process);
+ DumpDiff(&first, &second);
+}
+void anonymous_file_mapping3() {
+ LOG(ERROR) << "create and map 16MB anonymous file mapping";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+ HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
+ 16 * 1024 * 1024, NULL);
+ MapViewOfFile(h, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 16 * 1024 *1024);
+ SaveStats(&second, &process);
+ DumpDiff(&first, &second);
+}
+
+void virtual_alloc1() {
+ LOG(ERROR) << "virtual_alloc 16MB";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+
+ VirtualAlloc(NULL, 16 * 1024 * 1024, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ SaveStats(&second, &process);
+
+ DumpDiff(&first, &second);
+}
+
+void virtual_alloc2() {
+ LOG(ERROR) << "virtual_alloc 16MB, then write to 8MB of pages";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+
+ char* a = (char*)VirtualAlloc(NULL, 16 * 1024 * 1024, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ for (int i = 0; i < 8 * 1024 * 1024; ++i) {
+ a[i] = 'a';
+ }
+ SaveStats(&second, &process);
+
+ DumpDiff(&first, &second);
+}
+
+void virtual_alloc3() {
+ LOG(ERROR) << "virtual_alloc 16MB, then write to 8MB of pages, then decommits 4MB of the written pages";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+
+ char* a = (char*)VirtualAlloc(NULL, 16 * 1024 * 1024, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ for (int i = 0; i < 8 * 1024 * 1024; ++i) {
+ a[i] = 'a';
+ }
+ VirtualFree(a, 4 * 1024 * 1024, MEM_DECOMMIT);
+ SaveStats(&second, &process);
+
+ DumpDiff(&first, &second);
+}
+
+void virtual_alloc4() {
+ LOG(ERROR) << "virtual_alloc 16MB, then write to 8MB of pages, then reset 4MB of the written pages";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+
+ char* a = (char*)VirtualAlloc(NULL, 16 * 1024 * 1024, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ for (int i = 0; i < 8 * 1024 * 1024; ++i) {
+ a[i] = 'a';
+ }
+ VirtualAlloc(a, 4 * 1024 * 1024, MEM_RESET, PAGE_NOACCESS);
+ SaveStats(&second, &process);
+
+ DumpDiff(&first, &second);
+}
+
+void virtual_alloc5() {
+ LOG(ERROR) << "virtual_alloc 16MB, then write to 8MB of pages, then discard 4MB of the written pages";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+
+ char* a = (char*)VirtualAlloc(NULL, 16 * 1024 * 1024, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ for (int i = 0; i < 8 * 1024 * 1024; ++i) {
+ a[i] = 'a';
+ }
+ using DiscardVirtualMemoryFunction =
+ DWORD(WINAPI*)(PVOID virtualAddress, SIZE_T size);
+ DiscardVirtualMemoryFunction discard_virtual_memory =
+ reinterpret_cast<DiscardVirtualMemoryFunction>(GetProcAddress(
+ GetModuleHandle(L"Kernel32.dll"), "DiscardVirtualMemory"));
+ discard_virtual_memory(a, 4 * 1024 * 1024);
+ SaveStats(&second, &process);
+
+ DumpDiff(&first, &second);
+}
+void heap_alloc1() {
+ LOG(ERROR) << "HeapAlloc 16MB";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+
+ HeapAlloc(GetProcessHeap(), 0, 16 * 1024 * 1024);
+ SaveStats(&second, &process);
+
+ DumpDiff(&first, &second);
+}
+void heap_alloc2() {
+ LOG(ERROR) << "HeapAlloc 16MB, and touch 8MB";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+
+ char* a = (char*)HeapAlloc(GetProcessHeap(), 0, 16 * 1024 * 1024);
+ for (int i = 0; i < 8 * 1024 * 1024; ++i) {
+ a[i] = 'a';
+ }
+ SaveStats(&second, &process);
+
+ DumpDiff(&first, &second);
+}
+void heap_alloc3() {
+ LOG(ERROR) << "HeapAlloc 16MB, and touch 8MB, then decommit 4MB";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+
+ char* a = (char*)HeapAlloc(GetProcessHeap(), 0, 16 * 1024 * 1024);
+ for (int i = 0; i < 8 * 1024 * 1024; ++i) {
+ a[i] = 'a';
+ }
+ VirtualFree(a, 4 * 1024 * 1024, MEM_DECOMMIT);
+ SaveStats(&second, &process);
+
+ DumpDiff(&first, &second);
+}
+
+void leak_1gb() {
+ LOG(ERROR) << "leak 1gb";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+ char* a = (char*)malloc(1024 * 1024 * 1024);
+ for (int i = 0; i < 1024 * 1024 * 1024 / 4096; ++i)
+ a[i * 4096] = 'a';
+ SaveStats(&second, &process);
+ DumpDiff(&first, &second);
+}
+
+void swap1() {
+ LOG(ERROR) << "This will crash your machine. Are you sure you want to continue (y)?";
+ char dummy;
+ scanf("%c", &dummy);
+ if (dummy != 'y')
+ return;
+
+ LOG(ERROR) << "malloc 256MB, touch every page, then spawn children that consume 64GB of memory";
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+
+ char*a = (char*)malloc(256 * 1024 * 1024);
+ for (int i = 0; i < 256 * 1024 * 1024 / 4096; ++i) {
+ a[i * 4096] = 'a';
+ }
+ for (int i = 0; i < 64; ++i) {
+ base::LaunchOptions options;
+ base::CommandLine child_command(*base::CommandLine::ForCurrentProcess());
+ child_command.AppendSwitch("leak_1gb");
+ base::LaunchProcess(child_command, options);
+ }
+
+ // Wait 100 seconds for memory to blow up.
+ base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(100));
+ SaveStats(&second, &process);
+ DumpDiff(&first, &second);
+}
+
+void swap2() {
+ LOG(ERROR) << "Spawns 256 process, each of which commits 1GB with VirtualAlloc but only makes 4MB of pages resident.";
+ for (int i = 0; i < 256; ++i) {
+ base::LaunchOptions options;
+ base::CommandLine child_command(*base::CommandLine::ForCurrentProcess());
+ child_command.AppendSwitch("swap2_child");
+ base::LaunchProcess(child_command, options);
+ }
+
+ // Wait 3 seconds for memory to blow up.
+ base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(3));
+
+ LOG(ERROR) << "try to allocate 1GB using malloc";
+ char*b = (char*)malloc(1024 * 1024 * 1024);
+ CHECK(b);
+ for (int i = 0; i < 1024 * 1024 * 1024 / 4096; ++i) {
+ b[i * 4096] = 'a';
+ }
+ LOG(ERROR) << "allocated 1GB using malloc";
+
+ LOG(ERROR) << "try to allocate 1GB using virtual alloc";
+ for (int i = 0; i < 1024; i++) {
+ char* a = (char*)VirtualAlloc(NULL, 1024 * 1024, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ CHECK(a);
+ a[0] = 'a';
+ }
+ LOG(ERROR) << "allocated 1GB using virtual alloc";
+}
+
+void swap2_child() {
+ base::Process process(base::Process::Current());
+ SavedStats first, second;
+ SaveStats(&first, &process);
+ for (int i = 0; i < 1024; i++) {
+ char* a = (char*)VirtualAlloc(NULL, 1024 * 1024, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+
+ // Occasional errors.
+ if (!a)
+ continue;
+
+ a[0] = 'a';
+ }
+ SaveStats(&second, &process);
+ DumpDiff(&first, &second);
+}
+
+int main(int argc, char* argv[]) {
+ base::CommandLine::Init(argc, argv);
+ const base::CommandLine& current_command =
+ *base::CommandLine::ForCurrentProcess();
+
+ if (current_command.HasSwitch("sleepy")) {
+ new char[base::Process::Current().Pid()];
+ SleepForever();
+ }
+
+ if (current_command.HasSwitch("malloc1")) {
+ malloc1();
+ SleepForever();
+ }
+
+ if (current_command.HasSwitch("malloc2")) {
+ malloc2();
+ SleepForever();
+ }
+
+ if (current_command.HasSwitch("malloc3")) {
+ malloc3();
+ SleepForever();
+ }
+
+ if (current_command.HasSwitch("malloc4")) {
+ malloc4();
+ SleepForever();
+ }
+
+ if (current_command.HasSwitch("anonymous_file_mapping1")) {
+ anonymous_file_mapping1();
+ SleepForever();
+ }
+
+ if (current_command.HasSwitch("anonymous_file_mapping2")) {
+ anonymous_file_mapping2();
+ SleepForever();
+ }
+ if (current_command.HasSwitch("anonymous_file_mapping3")) {
+ anonymous_file_mapping3();
+ SleepForever();
+ }
+ if (current_command.HasSwitch("virtual_alloc1")) {
+ virtual_alloc1();
+ SleepForever();
+ }
+ if (current_command.HasSwitch("virtual_alloc2")) {
+ virtual_alloc2();
+ SleepForever();
+ }
+ if (current_command.HasSwitch("virtual_alloc3")) {
+ virtual_alloc3();
+ SleepForever();
+ }
+ if (current_command.HasSwitch("virtual_alloc4")) {
+ virtual_alloc4();
+ SleepForever();
+ }
+ if (current_command.HasSwitch("virtual_alloc5")) {
+ virtual_alloc4();
+ SleepForever();
+ }
+ if (current_command.HasSwitch("heap_alloc1")) {
+ heap_alloc1();
+ SleepForever();
+ }
+ if (current_command.HasSwitch("heap_alloc2")) {
+ heap_alloc2();
+ SleepForever();
+ }
+ if (current_command.HasSwitch("heap_alloc3")) {
+ heap_alloc3();
+ SleepForever();
+ }
+ if (current_command.HasSwitch("leak_1gb")) {
+ leak_1gb();
+ SleepForever();
+ }
+ if (current_command.HasSwitch("swap1")) {
+ swap1();
+ SleepForever();
+ }
+ if (current_command.HasSwitch("swap2_child")) {
+ swap2_child();
+ SleepForever();
+ }
+ if (current_command.HasSwitch("swap2")) {
+ swap2();
+ SleepForever();
+ }
+ // Launch 2 child processes to mess with.
+ // base::LaunchOptions options;
+ base::Process a(base::Process::Current());
+ // base::CommandLine child_command(current_command);
+ // child_command.AppendSwitch("sleepy");
+ // base::Process b(base::LaunchProcess(child_command, options));
+ // base::Process c(base::LaunchProcess(child_command, options));
+
+ // // Test sharing a DLL.
+ // LoadDll();
+
+ // // Test shared memory that's not shared.
+ // CreateSharedMemoryButDontShare();
+
+ // // Test sharing with just one other process.
+ // ShareMeSomeMemory(2, {&b});
+ // ShareMeSomeMemory(4, {&c});
+
+ // // Test sharing with bunches of processes.
+ // ShareMeSomeMemory(7, {&b, &c});
+
+ // // Test sharing Copy on write pgae.
+ // ShareMeSomeCOWsAndTouchThem(12, {&b, &c});
+
+ // // Force us to swap out memory.
+ // ForceSwap();
+ // DumpStats({&a});
+
+ // for (int i = 0; i < 1000; ++i) {
+ // char*a = (char*)malloc(4096 * 16);
+ // *a = 'a';
+ // // for (int j = 0; j < 16; ++j)
+ // // a[j * 4096] = 'a';
+ // // base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
+ // }
+
+ // // Print out stats.
+ // DumpStats({&a});
+ //DumpStats({&a, &b, &c});
+
+ // Wait until input so it can be inspected.
+ char dummy;
+ scanf("%c", &dummy);
+
+ // Clean up 2 child processes.
+ // b.Terminate(0, true);
+ // c.Terminate(0, true);
+
+ return 0;
+}
« no previous file with comments | « base/BUILD.gn ('k') | base/memory/memory_uma_perftest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698