persistent_histogram_allocator_unittest.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. // Copyright 2016 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. #include "base/metrics/persistent_histogram_allocator.h"
  5. #include "base/files/file.h"
  6. #include "base/files/file_util.h"
  7. #include "base/files/scoped_temp_dir.h"
  8. #include "base/memory/ptr_util.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/metrics/bucket_ranges.h"
  11. #include "base/metrics/histogram_macros.h"
  12. #include "base/metrics/persistent_memory_allocator.h"
  13. #include "base/metrics/statistics_recorder.h"
  14. #include "testing/gmock/include/gmock/gmock.h"
  15. #include "testing/gtest/include/gtest/gtest.h"
  16. namespace base {
  17. class PersistentHistogramAllocatorTest : public testing::Test {
  18. public:
  19. PersistentHistogramAllocatorTest(const PersistentHistogramAllocatorTest&) =
  20. delete;
  21. PersistentHistogramAllocatorTest& operator=(
  22. const PersistentHistogramAllocatorTest&) = delete;
  23. protected:
  24. const int32_t kAllocatorMemorySize = 64 << 10; // 64 KiB
  25. PersistentHistogramAllocatorTest()
  26. : statistics_recorder_(StatisticsRecorder::CreateTemporaryForTesting()) {
  27. CreatePersistentHistogramAllocator();
  28. }
  29. ~PersistentHistogramAllocatorTest() override {
  30. DestroyPersistentHistogramAllocator();
  31. }
  32. void CreatePersistentHistogramAllocator() {
  33. allocator_memory_.reset(new char[kAllocatorMemorySize]);
  34. GlobalHistogramAllocator::ReleaseForTesting();
  35. memset(allocator_memory_.get(), 0, kAllocatorMemorySize);
  36. GlobalHistogramAllocator::CreateWithPersistentMemory(
  37. allocator_memory_.get(), kAllocatorMemorySize, 0, 0,
  38. "PersistentHistogramAllocatorTest");
  39. allocator_ = GlobalHistogramAllocator::Get()->memory_allocator();
  40. }
  41. void DestroyPersistentHistogramAllocator() {
  42. allocator_ = nullptr;
  43. GlobalHistogramAllocator::ReleaseForTesting();
  44. }
  45. std::unique_ptr<StatisticsRecorder> statistics_recorder_;
  46. std::unique_ptr<char[]> allocator_memory_;
  47. raw_ptr<PersistentMemoryAllocator> allocator_ = nullptr;
  48. };
  49. TEST_F(PersistentHistogramAllocatorTest, CreateAndIterate) {
  50. PersistentMemoryAllocator::MemoryInfo meminfo0;
  51. allocator_->GetMemoryInfo(&meminfo0);
  52. // Try basic construction
  53. HistogramBase* histogram = Histogram::FactoryGet(
  54. "TestHistogram", 1, 1000, 10, HistogramBase::kIsPersistent);
  55. EXPECT_TRUE(histogram);
  56. histogram->CheckName("TestHistogram");
  57. PersistentMemoryAllocator::MemoryInfo meminfo1;
  58. allocator_->GetMemoryInfo(&meminfo1);
  59. EXPECT_GT(meminfo0.free, meminfo1.free);
  60. HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
  61. "TestLinearHistogram", 1, 1000, 10, HistogramBase::kIsPersistent);
  62. EXPECT_TRUE(linear_histogram);
  63. linear_histogram->CheckName("TestLinearHistogram");
  64. PersistentMemoryAllocator::MemoryInfo meminfo2;
  65. allocator_->GetMemoryInfo(&meminfo2);
  66. EXPECT_GT(meminfo1.free, meminfo2.free);
  67. HistogramBase* boolean_histogram = BooleanHistogram::FactoryGet(
  68. "TestBooleanHistogram", HistogramBase::kIsPersistent);
  69. EXPECT_TRUE(boolean_histogram);
  70. boolean_histogram->CheckName("TestBooleanHistogram");
  71. PersistentMemoryAllocator::MemoryInfo meminfo3;
  72. allocator_->GetMemoryInfo(&meminfo3);
  73. EXPECT_GT(meminfo2.free, meminfo3.free);
  74. std::vector<int> custom_ranges;
  75. custom_ranges.push_back(1);
  76. custom_ranges.push_back(5);
  77. HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
  78. "TestCustomHistogram", custom_ranges, HistogramBase::kIsPersistent);
  79. EXPECT_TRUE(custom_histogram);
  80. custom_histogram->CheckName("TestCustomHistogram");
  81. PersistentMemoryAllocator::MemoryInfo meminfo4;
  82. allocator_->GetMemoryInfo(&meminfo4);
  83. EXPECT_GT(meminfo3.free, meminfo4.free);
  84. PersistentMemoryAllocator::Iterator iter(allocator_);
  85. uint32_t type;
  86. EXPECT_NE(0U, iter.GetNext(&type)); // Histogram
  87. EXPECT_NE(0U, iter.GetNext(&type)); // LinearHistogram
  88. EXPECT_NE(0U, iter.GetNext(&type)); // BooleanHistogram
  89. EXPECT_NE(0U, iter.GetNext(&type)); // CustomHistogram
  90. EXPECT_EQ(0U, iter.GetNext(&type));
  91. // Create a second allocator and have it access the memory of the first.
  92. std::unique_ptr<HistogramBase> recovered;
  93. PersistentHistogramAllocator recovery(
  94. std::make_unique<PersistentMemoryAllocator>(
  95. allocator_memory_.get(), kAllocatorMemorySize, 0, 0, "", false));
  96. PersistentHistogramAllocator::Iterator histogram_iter(&recovery);
  97. recovered = histogram_iter.GetNext();
  98. ASSERT_TRUE(recovered);
  99. recovered->CheckName("TestHistogram");
  100. recovered = histogram_iter.GetNext();
  101. ASSERT_TRUE(recovered);
  102. recovered->CheckName("TestLinearHistogram");
  103. recovered = histogram_iter.GetNext();
  104. ASSERT_TRUE(recovered);
  105. recovered->CheckName("TestBooleanHistogram");
  106. recovered = histogram_iter.GetNext();
  107. ASSERT_TRUE(recovered);
  108. recovered->CheckName("TestCustomHistogram");
  109. recovered = histogram_iter.GetNext();
  110. EXPECT_FALSE(recovered);
  111. }
  112. TEST_F(PersistentHistogramAllocatorTest, ConstructPaths) {
  113. const FilePath dir_path(FILE_PATH_LITERAL("foo/"));
  114. const std::string dir_string =
  115. dir_path.NormalizePathSeparators().AsUTF8Unsafe();
  116. FilePath path = GlobalHistogramAllocator::ConstructFilePath(dir_path, "bar");
  117. EXPECT_EQ(dir_string + "bar.pma", path.AsUTF8Unsafe());
  118. std::string name;
  119. Time stamp;
  120. ProcessId pid;
  121. EXPECT_FALSE(
  122. GlobalHistogramAllocator::ParseFilePath(path, &name, nullptr, nullptr));
  123. EXPECT_FALSE(
  124. GlobalHistogramAllocator::ParseFilePath(path, nullptr, &stamp, nullptr));
  125. EXPECT_FALSE(
  126. GlobalHistogramAllocator::ParseFilePath(path, nullptr, nullptr, &pid));
  127. path = GlobalHistogramAllocator::ConstructFilePathForUploadDir(
  128. dir_path, "bar", Time::FromTimeT(12345), 6789);
  129. EXPECT_EQ(dir_string + "bar-3039-1A85.pma", path.AsUTF8Unsafe());
  130. ASSERT_TRUE(
  131. GlobalHistogramAllocator::ParseFilePath(path, &name, &stamp, &pid));
  132. EXPECT_EQ(name, "bar");
  133. EXPECT_EQ(Time::FromTimeT(12345), stamp);
  134. EXPECT_EQ(static_cast<ProcessId>(6789), pid);
  135. }
  136. TEST_F(PersistentHistogramAllocatorTest, CreateWithFile) {
  137. const char temp_name[] = "CreateWithFileTest";
  138. ScopedTempDir temp_dir;
  139. ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
  140. FilePath temp_file = temp_dir.GetPath().AppendASCII(temp_name);
  141. const size_t temp_size = 64 << 10; // 64 KiB
  142. // Test creation of a new file.
  143. GlobalHistogramAllocator::ReleaseForTesting();
  144. GlobalHistogramAllocator::CreateWithFile(temp_file, temp_size, 0, temp_name);
  145. EXPECT_EQ(std::string(temp_name),
  146. GlobalHistogramAllocator::Get()->memory_allocator()->Name());
  147. // Test re-open of a possibly-existing file.
  148. GlobalHistogramAllocator::ReleaseForTesting();
  149. GlobalHistogramAllocator::CreateWithFile(temp_file, temp_size, 0, "");
  150. EXPECT_EQ(std::string(temp_name),
  151. GlobalHistogramAllocator::Get()->memory_allocator()->Name());
  152. // Test re-open of an known-existing file.
  153. GlobalHistogramAllocator::ReleaseForTesting();
  154. GlobalHistogramAllocator::CreateWithFile(temp_file, 0, 0, "");
  155. EXPECT_EQ(std::string(temp_name),
  156. GlobalHistogramAllocator::Get()->memory_allocator()->Name());
  157. // Final release so file and temp-dir can be removed.
  158. GlobalHistogramAllocator::ReleaseForTesting();
  159. }
  160. TEST_F(PersistentHistogramAllocatorTest, CreateSpareFile) {
  161. const char temp_name[] = "CreateSpareFileTest.pma";
  162. ScopedTempDir temp_dir;
  163. ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
  164. FilePath temp_file = temp_dir.GetPath().AppendASCII(temp_name);
  165. const size_t temp_size = 64 << 10; // 64 KiB
  166. ASSERT_TRUE(GlobalHistogramAllocator::CreateSpareFile(temp_file, temp_size));
  167. File file(temp_file, File::FLAG_OPEN | File::FLAG_READ);
  168. ASSERT_TRUE(file.IsValid());
  169. EXPECT_EQ(static_cast<int64_t>(temp_size), file.GetLength());
  170. char buffer[256];
  171. for (size_t pos = 0; pos < temp_size; pos += sizeof(buffer)) {
  172. ASSERT_EQ(static_cast<int>(sizeof(buffer)),
  173. file.ReadAtCurrentPos(buffer, sizeof(buffer)));
  174. for (size_t i = 0; i < sizeof(buffer); ++i)
  175. EXPECT_EQ(0, buffer[i]);
  176. }
  177. }
  178. TEST_F(PersistentHistogramAllocatorTest, StatisticsRecorderMerge) {
  179. const char LinearHistogramName[] = "SRTLinearHistogram";
  180. const char SparseHistogramName[] = "SRTSparseHistogram";
  181. const size_t global_sr_initial_histogram_count =
  182. StatisticsRecorder::GetHistogramCount();
  183. const size_t global_sr_initial_bucket_ranges_count =
  184. StatisticsRecorder::GetBucketRanges().size();
  185. // Create a local StatisticsRecorder in which the newly created histogram
  186. // will be recorded. The global allocator must be replaced after because the
  187. // act of releasing will cause the active SR to forget about all histograms
  188. // in the relased memory.
  189. std::unique_ptr<StatisticsRecorder> local_sr =
  190. StatisticsRecorder::CreateTemporaryForTesting();
  191. EXPECT_EQ(0U, StatisticsRecorder::GetHistogramCount());
  192. std::unique_ptr<GlobalHistogramAllocator> old_allocator =
  193. GlobalHistogramAllocator::ReleaseForTesting();
  194. GlobalHistogramAllocator::CreateWithLocalMemory(kAllocatorMemorySize, 0, "");
  195. ASSERT_TRUE(GlobalHistogramAllocator::Get());
  196. // Create a linear histogram for merge testing.
  197. HistogramBase* histogram1 =
  198. LinearHistogram::FactoryGet(LinearHistogramName, 1, 10, 10, 0);
  199. ASSERT_TRUE(histogram1);
  200. EXPECT_EQ(1U, StatisticsRecorder::GetHistogramCount());
  201. histogram1->Add(3);
  202. histogram1->Add(1);
  203. histogram1->Add(4);
  204. histogram1->AddCount(1, 4);
  205. histogram1->Add(6);
  206. // Create a sparse histogram for merge testing.
  207. HistogramBase* histogram2 =
  208. SparseHistogram::FactoryGet(SparseHistogramName, 0);
  209. ASSERT_TRUE(histogram2);
  210. EXPECT_EQ(2U, StatisticsRecorder::GetHistogramCount());
  211. histogram2->Add(3);
  212. histogram2->Add(1);
  213. histogram2->Add(4);
  214. histogram2->AddCount(1, 4);
  215. histogram2->Add(6);
  216. // Destroy the local SR and ensure that we're back to the initial state and
  217. // restore the global allocator. Histograms created in the local SR will
  218. // become unmanaged.
  219. std::unique_ptr<GlobalHistogramAllocator> new_allocator =
  220. GlobalHistogramAllocator::ReleaseForTesting();
  221. local_sr.reset();
  222. EXPECT_EQ(global_sr_initial_histogram_count,
  223. StatisticsRecorder::GetHistogramCount());
  224. EXPECT_EQ(global_sr_initial_bucket_ranges_count,
  225. StatisticsRecorder::GetBucketRanges().size());
  226. GlobalHistogramAllocator::Set(std::move(old_allocator));
  227. // Create a "recovery" allocator using the same memory as the local one.
  228. PersistentHistogramAllocator recovery1(
  229. std::make_unique<PersistentMemoryAllocator>(
  230. const_cast<void*>(new_allocator->memory_allocator()->data()),
  231. new_allocator->memory_allocator()->size(), 0, 0, "", false));
  232. PersistentHistogramAllocator::Iterator histogram_iter1(&recovery1);
  233. // Get the histograms that were created locally (and forgotten) and merge
  234. // them into the global SR. New objects will be created.
  235. std::unique_ptr<HistogramBase> recovered;
  236. while (true) {
  237. recovered = histogram_iter1.GetNext();
  238. if (!recovered)
  239. break;
  240. recovery1.MergeHistogramDeltaToStatisticsRecorder(recovered.get());
  241. HistogramBase* found =
  242. StatisticsRecorder::FindHistogram(recovered->histogram_name());
  243. EXPECT_NE(recovered.get(), found);
  244. }
  245. EXPECT_EQ(global_sr_initial_histogram_count + 2,
  246. StatisticsRecorder::GetHistogramCount());
  247. // Check the merged histograms for accuracy.
  248. HistogramBase* found = StatisticsRecorder::FindHistogram(LinearHistogramName);
  249. ASSERT_TRUE(found);
  250. std::unique_ptr<HistogramSamples> snapshot = found->SnapshotSamples();
  251. EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount());
  252. EXPECT_EQ(1, snapshot->GetCount(3));
  253. EXPECT_EQ(5, snapshot->GetCount(1));
  254. EXPECT_EQ(1, snapshot->GetCount(4));
  255. EXPECT_EQ(1, snapshot->GetCount(6));
  256. found = StatisticsRecorder::FindHistogram(SparseHistogramName);
  257. ASSERT_TRUE(found);
  258. snapshot = found->SnapshotSamples();
  259. EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount());
  260. EXPECT_EQ(1, snapshot->GetCount(3));
  261. EXPECT_EQ(5, snapshot->GetCount(1));
  262. EXPECT_EQ(1, snapshot->GetCount(4));
  263. EXPECT_EQ(1, snapshot->GetCount(6));
  264. // Verify that the LinearHistogram's BucketRanges was registered with the
  265. // global SR since the recovery allocator does not specify a custom
  266. // RangesManager.
  267. ASSERT_EQ(global_sr_initial_bucket_ranges_count + 1,
  268. StatisticsRecorder::GetBucketRanges().size());
  269. // Perform additional histogram increments.
  270. histogram1->AddCount(1, 3);
  271. histogram1->Add(6);
  272. histogram2->AddCount(1, 3);
  273. histogram2->Add(7);
  274. // Do another merge.
  275. PersistentHistogramAllocator recovery2(
  276. std::make_unique<PersistentMemoryAllocator>(
  277. const_cast<void*>(new_allocator->memory_allocator()->data()),
  278. new_allocator->memory_allocator()->size(), 0, 0, "", false));
  279. PersistentHistogramAllocator::Iterator histogram_iter2(&recovery2);
  280. while (true) {
  281. recovered = histogram_iter2.GetNext();
  282. if (!recovered)
  283. break;
  284. recovery2.MergeHistogramDeltaToStatisticsRecorder(recovered.get());
  285. }
  286. EXPECT_EQ(global_sr_initial_histogram_count + 2,
  287. StatisticsRecorder::GetHistogramCount());
  288. // And verify.
  289. found = StatisticsRecorder::FindHistogram(LinearHistogramName);
  290. snapshot = found->SnapshotSamples();
  291. EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount());
  292. EXPECT_EQ(1, snapshot->GetCount(3));
  293. EXPECT_EQ(8, snapshot->GetCount(1));
  294. EXPECT_EQ(1, snapshot->GetCount(4));
  295. EXPECT_EQ(2, snapshot->GetCount(6));
  296. found = StatisticsRecorder::FindHistogram(SparseHistogramName);
  297. snapshot = found->SnapshotSamples();
  298. EXPECT_EQ(found->SnapshotSamples()->TotalCount(), snapshot->TotalCount());
  299. EXPECT_EQ(1, snapshot->GetCount(3));
  300. EXPECT_EQ(8, snapshot->GetCount(1));
  301. EXPECT_EQ(1, snapshot->GetCount(4));
  302. EXPECT_EQ(1, snapshot->GetCount(6));
  303. EXPECT_EQ(1, snapshot->GetCount(7));
  304. }
  305. TEST_F(PersistentHistogramAllocatorTest, CustomRangesManager) {
  306. const char LinearHistogramName[] = "TestLinearHistogram";
  307. const size_t global_sr_initial_bucket_ranges_count =
  308. StatisticsRecorder::GetBucketRanges().size();
  309. // Create a local StatisticsRecorder in which the newly created histogram
  310. // will be recorded. The global allocator must be replaced after because the
  311. // act of releasing will cause the active SR to forget about all histograms
  312. // in the released memory.
  313. std::unique_ptr<StatisticsRecorder> local_sr =
  314. StatisticsRecorder::CreateTemporaryForTesting();
  315. EXPECT_EQ(0U, StatisticsRecorder::GetHistogramCount());
  316. std::unique_ptr<GlobalHistogramAllocator> old_allocator =
  317. GlobalHistogramAllocator::ReleaseForTesting();
  318. GlobalHistogramAllocator::CreateWithLocalMemory(kAllocatorMemorySize, 0, "");
  319. ASSERT_TRUE(GlobalHistogramAllocator::Get());
  320. // Create a linear histogram and verify it is registered with the local SR.
  321. HistogramBase* histogram = LinearHistogram::FactoryGet(
  322. LinearHistogramName, /*minimum=*/1, /*maximum=*/10, /*bucket_count=*/10,
  323. /*flags=*/0);
  324. ASSERT_TRUE(histogram);
  325. EXPECT_EQ(1U, StatisticsRecorder::GetHistogramCount());
  326. histogram->Add(1);
  327. // Destroy the local SR and ensure that we're back to the initial state and
  328. // restore the global allocator. The histogram created in the local SR will
  329. // become unmanaged.
  330. std::unique_ptr<GlobalHistogramAllocator> new_allocator =
  331. GlobalHistogramAllocator::ReleaseForTesting();
  332. local_sr.reset();
  333. EXPECT_EQ(global_sr_initial_bucket_ranges_count,
  334. StatisticsRecorder::GetBucketRanges().size());
  335. GlobalHistogramAllocator::Set(std::move(old_allocator));
  336. // Create a "recovery" allocator using the same memory as the local one.
  337. PersistentHistogramAllocator recovery(
  338. std::make_unique<PersistentMemoryAllocator>(
  339. const_cast<void*>(new_allocator->memory_allocator()->data()),
  340. new_allocator->memory_allocator()->size(), 0, 0, "", false));
  341. // Set a custom RangesManager for the recovery allocator so that the
  342. // BucketRanges are not registered with the global SR.
  343. RangesManager* ranges_manager = new RangesManager();
  344. recovery.SetRangesManager(ranges_manager);
  345. EXPECT_EQ(0U, ranges_manager->GetBucketRanges().size());
  346. // Get the histogram that was created locally (and forgotten).
  347. PersistentHistogramAllocator::Iterator histogram_iter1(&recovery);
  348. std::unique_ptr<HistogramBase> recovered = histogram_iter1.GetNext();
  349. ASSERT_TRUE(recovered);
  350. // Verify that there are no more histograms.
  351. ASSERT_FALSE(histogram_iter1.GetNext());
  352. // Expect that the histogram's BucketRanges was not registered with the global
  353. // statistics recorder since the recovery allocator specifies a custom
  354. // RangesManager.
  355. EXPECT_EQ(global_sr_initial_bucket_ranges_count,
  356. StatisticsRecorder::GetBucketRanges().size());
  357. EXPECT_EQ(1U, ranges_manager->GetBucketRanges().size());
  358. }
  359. TEST_F(PersistentHistogramAllocatorTest, RangesDeDuplication) {
  360. // This corresponds to the "ranges_ref" field of the PersistentHistogramData
  361. // structure defined (privately) inside persistent_histogram_allocator.cc.
  362. const int kRangesRefIndex = 5;
  363. // Create two histograms with the same ranges.
  364. HistogramBase* histogram1 =
  365. Histogram::FactoryGet("TestHistogram1", 1, 1000, 10, 0);
  366. HistogramBase* histogram2 =
  367. Histogram::FactoryGet("TestHistogram2", 1, 1000, 10, 0);
  368. const uint32_t ranges_ref = static_cast<Histogram*>(histogram1)
  369. ->bucket_ranges()
  370. ->persistent_reference();
  371. ASSERT_NE(0U, ranges_ref);
  372. EXPECT_EQ(ranges_ref, static_cast<Histogram*>(histogram2)
  373. ->bucket_ranges()
  374. ->persistent_reference());
  375. // Make sure that the persistent data record is also correct. Two histograms
  376. // will be fetched; other allocations are not "iterable".
  377. PersistentMemoryAllocator::Iterator iter(allocator_);
  378. uint32_t type;
  379. uint32_t ref1 = iter.GetNext(&type);
  380. uint32_t ref2 = iter.GetNext(&type);
  381. EXPECT_EQ(0U, iter.GetNext(&type));
  382. EXPECT_NE(0U, ref1);
  383. EXPECT_NE(0U, ref2);
  384. EXPECT_NE(ref1, ref2);
  385. uint32_t* data1 =
  386. allocator_->GetAsArray<uint32_t>(ref1, 0, kRangesRefIndex + 1);
  387. uint32_t* data2 =
  388. allocator_->GetAsArray<uint32_t>(ref2, 0, kRangesRefIndex + 1);
  389. EXPECT_EQ(ranges_ref, data1[kRangesRefIndex]);
  390. EXPECT_EQ(ranges_ref, data2[kRangesRefIndex]);
  391. }
  392. } // namespace base