page_heap_test.cc 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
  2. // Copyright 2009 Google Inc. All Rights Reserved.
  3. // Author: fikes@google.com (Andrew Fikes)
  4. //
  5. // Use of this source code is governed by a BSD-style license that can
  6. // be found in the LICENSE file.
  7. #include "config_for_unittests.h"
  8. #include "page_heap.h"
  9. #include "system-alloc.h"
  10. #include <stdio.h>
  11. #include "base/logging.h"
  12. #include "common.h"
  13. DECLARE_int64(tcmalloc_heap_limit_mb);
  14. namespace {
  15. // The system will only release memory if the block size is equal or hight than
  16. // system page size.
  17. static bool HaveSystemRelease =
  18. TCMalloc_SystemRelease(
  19. TCMalloc_SystemAlloc(getpagesize(), NULL, 0), getpagesize());
  20. static void CheckStats(const tcmalloc::PageHeap* ph,
  21. uint64_t system_pages,
  22. uint64_t free_pages,
  23. uint64_t unmapped_pages) {
  24. tcmalloc::PageHeap::Stats stats = ph->stats();
  25. if (!HaveSystemRelease) {
  26. free_pages += unmapped_pages;
  27. unmapped_pages = 0;
  28. }
  29. EXPECT_EQ(system_pages, stats.system_bytes >> kPageShift);
  30. EXPECT_EQ(free_pages, stats.free_bytes >> kPageShift);
  31. EXPECT_EQ(unmapped_pages, stats.unmapped_bytes >> kPageShift);
  32. }
  33. static void TestPageHeap_Stats() {
  34. tcmalloc::PageHeap* ph = new tcmalloc::PageHeap();
  35. // Empty page heap
  36. CheckStats(ph, 0, 0, 0);
  37. // Allocate a span 's1'
  38. tcmalloc::Span* s1 = ph->New(256);
  39. CheckStats(ph, 256, 0, 0);
  40. // Split span 's1' into 's1', 's2'. Delete 's2'
  41. tcmalloc::Span* s2 = ph->Split(s1, 128);
  42. ph->Delete(s2);
  43. CheckStats(ph, 256, 128, 0);
  44. // Unmap deleted span 's2'
  45. ph->ReleaseAtLeastNPages(1);
  46. CheckStats(ph, 256, 0, 128);
  47. // Delete span 's1'
  48. ph->Delete(s1);
  49. CheckStats(ph, 256, 128, 128);
  50. delete ph;
  51. }
  52. static void TestPageHeap_Limit() {
  53. tcmalloc::PageHeap* ph = new tcmalloc::PageHeap();
  54. CHECK_EQ(kMaxPages, 1 << (20 - kPageShift));
  55. // We do not know much is taken from the system for other purposes,
  56. // so we detect the proper limit:
  57. {
  58. FLAGS_tcmalloc_heap_limit_mb = 1;
  59. tcmalloc::Span* s = NULL;
  60. while((s = ph->New(kMaxPages)) == NULL) {
  61. FLAGS_tcmalloc_heap_limit_mb++;
  62. }
  63. FLAGS_tcmalloc_heap_limit_mb += 9;
  64. ph->Delete(s);
  65. // We are [10, 11) mb from the limit now.
  66. }
  67. // Test AllocLarge and GrowHeap first:
  68. {
  69. tcmalloc::Span * spans[10];
  70. for (int i=0; i<10; ++i) {
  71. spans[i] = ph->New(kMaxPages);
  72. EXPECT_NE(spans[i], NULL);
  73. }
  74. EXPECT_EQ(ph->New(kMaxPages), NULL);
  75. for (int i=0; i<10; i += 2) {
  76. ph->Delete(spans[i]);
  77. }
  78. tcmalloc::Span *defragmented = ph->New(5 * kMaxPages);
  79. if (HaveSystemRelease) {
  80. // EnsureLimit should release deleted normal spans
  81. EXPECT_NE(defragmented, NULL);
  82. EXPECT_TRUE(ph->CheckExpensive());
  83. ph->Delete(defragmented);
  84. }
  85. else
  86. {
  87. EXPECT_EQ(defragmented, NULL);
  88. EXPECT_TRUE(ph->CheckExpensive());
  89. }
  90. for (int i=1; i<10; i += 2) {
  91. ph->Delete(spans[i]);
  92. }
  93. }
  94. // Once again, testing small lists this time (twice smaller spans):
  95. {
  96. tcmalloc::Span * spans[20];
  97. for (int i=0; i<20; ++i) {
  98. spans[i] = ph->New(kMaxPages >> 1);
  99. EXPECT_NE(spans[i], NULL);
  100. }
  101. // one more half size allocation may be possible:
  102. tcmalloc::Span * lastHalf = ph->New(kMaxPages >> 1);
  103. EXPECT_EQ(ph->New(kMaxPages >> 1), NULL);
  104. for (int i=0; i<20; i += 2) {
  105. ph->Delete(spans[i]);
  106. }
  107. for(Length len = kMaxPages >> 2; len < 5 * kMaxPages; len = len << 1)
  108. {
  109. if(len <= kMaxPages >> 1 || HaveSystemRelease) {
  110. tcmalloc::Span *s = ph->New(len);
  111. EXPECT_NE(s, NULL);
  112. ph->Delete(s);
  113. }
  114. }
  115. EXPECT_TRUE(ph->CheckExpensive());
  116. for (int i=1; i<20; i += 2) {
  117. ph->Delete(spans[i]);
  118. }
  119. if (lastHalf != NULL) {
  120. ph->Delete(lastHalf);
  121. }
  122. }
  123. delete ph;
  124. }
  125. } // namespace
  126. int main(int argc, char **argv) {
  127. TestPageHeap_Stats();
  128. TestPageHeap_Limit();
  129. printf("PASS\n");
  130. // on windows as part of library destructors we call getenv which
  131. // calls malloc which fails due to our exhausted heap limit. It then
  132. // causes fancy stack overflow because log message we're printing
  133. // for failed allocation somehow cause malloc calls too
  134. //
  135. // To keep us out of trouble we just drop malloc limit
  136. FLAGS_tcmalloc_heap_limit_mb = 0;
  137. return 0;
  138. }