| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <algorithm> |
| 6 |
| 7 #include "base/process/process_handle.h" |
| 8 #include "base/test/perf_time_logger.h" |
| 9 #include "base/time/time.h" |
| 10 #include "testing/gtest/include/gtest/gtest.h" |
| 11 |
| 12 namespace base { |
| 13 |
| 14 namespace { |
| 15 |
| 16 constexpr const int kNumRuns = 1000; |
| 17 constexpr const int kMaxRegions = 1000; // Runs of a single test seem to |
| 18 // generate about 330 regions, so 1000 |
| 19 // should overkill. |
| 20 size_t memory_sizes[kNumRuns] = {}; |
| 21 struct RunStat { |
| 22 int num_regions; |
| 23 TimeDelta* virtual_query_run_times; |
| 24 TimeDelta run_time; |
| 25 } run_stats[kNumRuns]; |
| 26 TimeDelta virtual_query_run_times_storage[kMaxRegions][kNumRuns]; |
| 27 |
| 28 size_t GetPrivateMemoryFootprintWindows(ProcessHandle process, |
| 29 const SYSTEM_INFO& system_info, |
| 30 RunStat* run_stat) { |
| 31 size_t private_memory_footprint = 0; |
| 32 const char* current_address = |
| 33 reinterpret_cast<const char*>(system_info.lpMinimumApplicationAddress); |
| 34 |
| 35 TimeDelta* cur_run = &run_stat->virtual_query_run_times[0]; |
| 36 while (current_address <= system_info.lpMaximumApplicationAddress) { |
| 37 MEMORY_BASIC_INFORMATION region; |
| 38 |
| 39 TimeTicks start = TimeTicks::Now(); |
| 40 if (::VirtualQueryEx(process, current_address, ®ion, sizeof(region)) != |
| 41 0) { |
| 42 ++(run_stat->num_regions); |
| 43 if (region.Type == MEM_PRIVATE && region.State == MEM_COMMIT) { |
| 44 private_memory_footprint += region.RegionSize; |
| 45 } |
| 46 current_address = |
| 47 reinterpret_cast<const char*>(region.BaseAddress) + region.RegionSize; |
| 48 } else { |
| 49 // This should not happen but if it does, just go to the next page and |
| 50 // continue. |
| 51 DPLOG(ERROR) << "Error calling VirtualQueryEx for process: " << process |
| 52 << " and address: " |
| 53 << reinterpret_cast<intptr_t>(current_address); |
| 54 |
| 55 // TODO(ajwong): What happens if we overflow? |
| 56 current_address += system_info.dwPageSize; |
| 57 } |
| 58 *(cur_run++) = TimeTicks::Now() - start; |
| 59 } |
| 60 return private_memory_footprint; |
| 61 } |
| 62 |
| 63 TEST(MemoryUma, CalculatePrivateMemory) { |
| 64 ProcessHandle current_process = GetCurrentProcessHandle(); |
| 65 SYSTEM_INFO system_info; |
| 66 ::GetSystemInfo(&system_info); |
| 67 |
| 68 PerfTimeLogger timer("Memory_uma_private_memory"); |
| 69 for (int i = 0; i < kNumRuns; ++i) { |
| 70 TimeTicks start = TimeTicks::Now(); |
| 71 run_stats[i].virtual_query_run_times = virtual_query_run_times_storage[i]; |
| 72 memory_sizes[i] = GetPrivateMemoryFootprintWindows( |
| 73 current_process, system_info, &run_stats[i]); |
| 74 run_stats[i].run_time = TimeTicks::Now() - start; |
| 75 } |
| 76 timer.Done(); |
| 77 |
| 78 std::sort(memory_sizes, memory_sizes + kNumRuns); |
| 79 LOG(ERROR) << "Memory Smallest: " << memory_sizes[0]; |
| 80 LOG(ERROR) << "Memory 95% percentile: " |
| 81 << memory_sizes[static_cast<int>(.95 * kNumRuns)]; |
| 82 LOG(ERROR) << "Memory Largest: " << memory_sizes[kNumRuns - 1] << std::endl; |
| 83 |
| 84 std::sort(run_stats, run_stats + kNumRuns, |
| 85 [](const RunStat& a, const RunStat& b) { |
| 86 return a.num_regions < b.num_regions; |
| 87 }); |
| 88 LOG(ERROR) << "Num Regions Smallest: " << run_stats[0].num_regions; |
| 89 LOG(ERROR) << "Num Regions 95% percentile: " |
| 90 << run_stats[static_cast<int>(.95 * kNumRuns)].num_regions; |
| 91 LOG(ERROR) << "Num Regions Largest: " << run_stats[kNumRuns - 1].num_regions |
| 92 << std::endl; |
| 93 |
| 94 std::sort(run_stats, run_stats + kNumRuns, |
| 95 [](const RunStat& a, const RunStat& b) { |
| 96 return a.run_time < b.run_time; |
| 97 }); |
| 98 LOG(ERROR) << "Run Time Smallest: " |
| 99 << run_stats[0].run_time.InMillisecondsF(); |
| 100 LOG(ERROR) |
| 101 << "Run Time 95% percentile: " |
| 102 << run_stats[static_cast<int>(.95 * kNumRuns)].run_time.InMillisecondsF(); |
| 103 LOG(ERROR) << "Run Time Second Largest: " |
| 104 << run_stats[kNumRuns - 2].run_time.InMillisecondsF(); |
| 105 const RunStat& longest = run_stats[kNumRuns - 1]; |
| 106 LOG(ERROR) << "Run Time Largest: " << longest.run_time.InMillisecondsF() |
| 107 << std::endl; |
| 108 |
| 109 std::sort(longest.virtual_query_run_times, |
| 110 longest.virtual_query_run_times + kMaxRegions); |
| 111 LOG(ERROR) << "[longest] VirtualQueryEx Run Time Smallest: " |
| 112 << longest.virtual_query_run_times[0].InMillisecondsF(); |
| 113 LOG(ERROR) << "[longest] VirtualQueryEx Run Time 50% percentile: " |
| 114 << longest.virtual_query_run_times[static_cast<int>(.5 * kNumRuns)] |
| 115 .InMillisecondsF(); |
| 116 LOG(ERROR) << "[longest] VirtualQueryEx Run Time 95% percentile: " |
| 117 << longest |
| 118 .virtual_query_run_times[static_cast<int>(.95 * kNumRuns)] |
| 119 .InMillisecondsF(); |
| 120 LOG(ERROR) << "[longest] VirtualQueryEx Run Time Second Largest: " |
| 121 << longest.virtual_query_run_times[kNumRuns - 2].InMillisecondsF(); |
| 122 LOG(ERROR) << "[longest] VirtualQueryEx Run Time Largest: " |
| 123 << longest.virtual_query_run_times[kNumRuns - 1].InMillisecondsF(); |
| 124 } |
| 125 |
| 126 } // namespace |
| 127 |
| 128 } // namespace base |
| OLD | NEW |