| Index: base/memory/memory_uma_perftest.cc
|
| diff --git a/base/memory/memory_uma_perftest.cc b/base/memory/memory_uma_perftest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..587eb0fc7d69d5940863d4271b4a53abc2436e87
|
| --- /dev/null
|
| +++ b/base/memory/memory_uma_perftest.cc
|
| @@ -0,0 +1,128 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include <algorithm>
|
| +
|
| +#include "base/process/process_handle.h"
|
| +#include "base/test/perf_time_logger.h"
|
| +#include "base/time/time.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace base {
|
| +
|
| +namespace {
|
| +
|
| +constexpr const int kNumRuns = 1000;
|
| +constexpr const int kMaxRegions = 1000; // Runs of a single test seem to
|
| + // generate about 330 regions, so 1000
|
| + // should overkill.
|
| +size_t memory_sizes[kNumRuns] = {};
|
| +struct RunStat {
|
| + int num_regions;
|
| + TimeDelta* virtual_query_run_times;
|
| + TimeDelta run_time;
|
| +} run_stats[kNumRuns];
|
| +TimeDelta virtual_query_run_times_storage[kMaxRegions][kNumRuns];
|
| +
|
| +size_t GetPrivateMemoryFootprintWindows(ProcessHandle process,
|
| + const SYSTEM_INFO& system_info,
|
| + RunStat* run_stat) {
|
| + size_t private_memory_footprint = 0;
|
| + const char* current_address =
|
| + reinterpret_cast<const char*>(system_info.lpMinimumApplicationAddress);
|
| +
|
| + TimeDelta* cur_run = &run_stat->virtual_query_run_times[0];
|
| + while (current_address <= system_info.lpMaximumApplicationAddress) {
|
| + MEMORY_BASIC_INFORMATION region;
|
| +
|
| + TimeTicks start = TimeTicks::Now();
|
| + if (::VirtualQueryEx(process, current_address, ®ion, sizeof(region)) !=
|
| + 0) {
|
| + ++(run_stat->num_regions);
|
| + if (region.Type == MEM_PRIVATE && region.State == MEM_COMMIT) {
|
| + private_memory_footprint += region.RegionSize;
|
| + }
|
| + current_address =
|
| + reinterpret_cast<const char*>(region.BaseAddress) + region.RegionSize;
|
| + } else {
|
| + // This should not happen but if it does, just go to the next page and
|
| + // continue.
|
| + DPLOG(ERROR) << "Error calling VirtualQueryEx for process: " << process
|
| + << " and address: "
|
| + << reinterpret_cast<intptr_t>(current_address);
|
| +
|
| + // TODO(ajwong): What happens if we overflow?
|
| + current_address += system_info.dwPageSize;
|
| + }
|
| + *(cur_run++) = TimeTicks::Now() - start;
|
| + }
|
| + return private_memory_footprint;
|
| +}
|
| +
|
| +TEST(MemoryUma, CalculatePrivateMemory) {
|
| + ProcessHandle current_process = GetCurrentProcessHandle();
|
| + SYSTEM_INFO system_info;
|
| + ::GetSystemInfo(&system_info);
|
| +
|
| + PerfTimeLogger timer("Memory_uma_private_memory");
|
| + for (int i = 0; i < kNumRuns; ++i) {
|
| + TimeTicks start = TimeTicks::Now();
|
| + run_stats[i].virtual_query_run_times = virtual_query_run_times_storage[i];
|
| + memory_sizes[i] = GetPrivateMemoryFootprintWindows(
|
| + current_process, system_info, &run_stats[i]);
|
| + run_stats[i].run_time = TimeTicks::Now() - start;
|
| + }
|
| + timer.Done();
|
| +
|
| + std::sort(memory_sizes, memory_sizes + kNumRuns);
|
| + LOG(ERROR) << "Memory Smallest: " << memory_sizes[0];
|
| + LOG(ERROR) << "Memory 95% percentile: "
|
| + << memory_sizes[static_cast<int>(.95 * kNumRuns)];
|
| + LOG(ERROR) << "Memory Largest: " << memory_sizes[kNumRuns - 1] << std::endl;
|
| +
|
| + std::sort(run_stats, run_stats + kNumRuns,
|
| + [](const RunStat& a, const RunStat& b) {
|
| + return a.num_regions < b.num_regions;
|
| + });
|
| + LOG(ERROR) << "Num Regions Smallest: " << run_stats[0].num_regions;
|
| + LOG(ERROR) << "Num Regions 95% percentile: "
|
| + << run_stats[static_cast<int>(.95 * kNumRuns)].num_regions;
|
| + LOG(ERROR) << "Num Regions Largest: " << run_stats[kNumRuns - 1].num_regions
|
| + << std::endl;
|
| +
|
| + std::sort(run_stats, run_stats + kNumRuns,
|
| + [](const RunStat& a, const RunStat& b) {
|
| + return a.run_time < b.run_time;
|
| + });
|
| + LOG(ERROR) << "Run Time Smallest: "
|
| + << run_stats[0].run_time.InMillisecondsF();
|
| + LOG(ERROR)
|
| + << "Run Time 95% percentile: "
|
| + << run_stats[static_cast<int>(.95 * kNumRuns)].run_time.InMillisecondsF();
|
| + LOG(ERROR) << "Run Time Second Largest: "
|
| + << run_stats[kNumRuns - 2].run_time.InMillisecondsF();
|
| + const RunStat& longest = run_stats[kNumRuns - 1];
|
| + LOG(ERROR) << "Run Time Largest: " << longest.run_time.InMillisecondsF()
|
| + << std::endl;
|
| +
|
| + std::sort(longest.virtual_query_run_times,
|
| + longest.virtual_query_run_times + kMaxRegions);
|
| + LOG(ERROR) << "[longest] VirtualQueryEx Run Time Smallest: "
|
| + << longest.virtual_query_run_times[0].InMillisecondsF();
|
| + LOG(ERROR) << "[longest] VirtualQueryEx Run Time 50% percentile: "
|
| + << longest.virtual_query_run_times[static_cast<int>(.5 * kNumRuns)]
|
| + .InMillisecondsF();
|
| + LOG(ERROR) << "[longest] VirtualQueryEx Run Time 95% percentile: "
|
| + << longest
|
| + .virtual_query_run_times[static_cast<int>(.95 * kNumRuns)]
|
| + .InMillisecondsF();
|
| + LOG(ERROR) << "[longest] VirtualQueryEx Run Time Second Largest: "
|
| + << longest.virtual_query_run_times[kNumRuns - 2].InMillisecondsF();
|
| + LOG(ERROR) << "[longest] VirtualQueryEx Run Time Largest: "
|
| + << longest.virtual_query_run_times[kNumRuns - 1].InMillisecondsF();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +} // namespace base
|
|
|