| OLD | NEW |
| 1 // Copyright (c) 2005, Google Inc. | 1 // Copyright (c) 2005, Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 // form of the name instead. | 117 // form of the name instead. |
| 118 #ifndef MAP_ANONYMOUS | 118 #ifndef MAP_ANONYMOUS |
| 119 # define MAP_ANONYMOUS MAP_ANON | 119 # define MAP_ANONYMOUS MAP_ANON |
| 120 #endif | 120 #endif |
| 121 | 121 |
| 122 #define LOGSTREAM stdout | 122 #define LOGSTREAM stdout |
| 123 | 123 |
| 124 using std::vector; | 124 using std::vector; |
| 125 using std::string; | 125 using std::string; |
| 126 | 126 |
| 127 DECLARE_double(tcmalloc_release_rate); |
| 128 DECLARE_int32(max_free_queue_size); // in debugallocation.cc |
| 129 |
| 127 namespace testing { | 130 namespace testing { |
| 128 | 131 |
| 129 static const int FLAGS_numtests = 50000; | 132 static const int FLAGS_numtests = 50000; |
| 130 static const int FLAGS_log_every_n_tests = 50000; // log exactly once | 133 static const int FLAGS_log_every_n_tests = 50000; // log exactly once |
| 131 | 134 |
| 132 // Testing parameters | 135 // Testing parameters |
| 133 static const int FLAGS_lgmaxsize = 16; // lg() of the max size object to alloc | 136 static const int FLAGS_lgmaxsize = 16; // lg() of the max size object to alloc |
| 134 static const int FLAGS_numthreads = 10; // Number of threads | 137 static const int FLAGS_numthreads = 10; // Number of threads |
| 135 static const int FLAGS_threadmb = 4; // Max memory size allocated by thread | 138 static const int FLAGS_threadmb = 4; // Max memory size allocated by thread |
| 136 static const int FLAGS_lg_max_memalign = 18; // lg of max alignment for memalign | 139 static const int FLAGS_lg_max_memalign = 18; // lg of max alignment for memalign |
| (...skipping 603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 740 char** array = new char*[kNum]; | 743 char** array = new char*[kNum]; |
| 741 for (int i = 0; i < kNum; ++i) { | 744 for (int i = 0; i < kNum; ++i) { |
| 742 array[i] = new char[10]; | 745 array[i] = new char[10]; |
| 743 } | 746 } |
| 744 for (int i = 0; i < kNum; ++i) { | 747 for (int i = 0; i < kNum; ++i) { |
| 745 delete[] array[i]; | 748 delete[] array[i]; |
| 746 } | 749 } |
| 747 delete[] array; | 750 delete[] array; |
| 748 } | 751 } |
| 749 | 752 |
| 753 namespace { |
| 754 |
| 755 struct RangeCallbackState { |
| 756 uintptr_t ptr; |
| 757 base::MallocRange::Type expected_type; |
| 758 size_t min_size; |
| 759 bool matched; |
| 760 }; |
| 761 |
| 762 static void RangeCallback(void* arg, const base::MallocRange* r) { |
| 763 RangeCallbackState* state = reinterpret_cast<RangeCallbackState*>(arg); |
| 764 if (state->ptr >= r->address && |
| 765 state->ptr < r->address + r->length) { |
| 766 CHECK_EQ(r->type, state->expected_type); |
| 767 CHECK_GE(r->length, state->min_size); |
| 768 state->matched = true; |
| 769 } |
| 770 } |
| 771 |
| 772 // Check that at least one of the callbacks from Ranges() contains |
| 773 // the specified address with the specified type, and has size |
| 774 // >= min_size. |
| 775 static void CheckRangeCallback(void* ptr, base::MallocRange::Type type, |
| 776 size_t min_size) { |
| 777 RangeCallbackState state; |
| 778 state.ptr = reinterpret_cast<uintptr_t>(ptr); |
| 779 state.expected_type = type; |
| 780 state.min_size = min_size; |
| 781 state.matched = false; |
| 782 MallocExtension::instance()->Ranges(&state, RangeCallback); |
| 783 CHECK(state.matched); |
| 784 } |
| 785 |
| 786 } |
| 787 |
| 788 static void TestRanges() { |
| 789 static const int MB = 1048576; |
| 790 void* a = malloc(MB); |
| 791 void* b = malloc(MB); |
| 792 CheckRangeCallback(a, base::MallocRange::INUSE, MB); |
| 793 CheckRangeCallback(b, base::MallocRange::INUSE, MB); |
| 794 free(a); |
| 795 CheckRangeCallback(a, base::MallocRange::FREE, MB); |
| 796 CheckRangeCallback(b, base::MallocRange::INUSE, MB); |
| 797 MallocExtension::instance()->ReleaseFreeMemory(); |
| 798 CheckRangeCallback(a, base::MallocRange::UNMAPPED, MB); |
| 799 CheckRangeCallback(b, base::MallocRange::INUSE, MB); |
| 800 free(b); |
| 801 CheckRangeCallback(a, base::MallocRange::UNMAPPED, MB); |
| 802 CheckRangeCallback(b, base::MallocRange::FREE, MB); |
| 803 } |
| 804 |
| 805 #ifndef DEBUGALLOCATION |
| 806 static size_t GetUnmappedBytes() { |
| 807 size_t bytes; |
| 808 CHECK(MallocExtension::instance()->GetNumericProperty( |
| 809 "tcmalloc.pageheap_unmapped_bytes", &bytes)); |
| 810 return bytes; |
| 811 } |
| 812 #endif |
| 813 |
| 814 static void TestReleaseToSystem() { |
| 815 // Debug allocation mode adds overhead to each allocation which |
| 816 // messes up all the equality tests here. I just disable the |
| 817 // teset in this mode. TODO(csilvers): get it to work for debugalloc? |
| 818 #ifndef DEBUGALLOCATION |
| 819 const double old_tcmalloc_release_rate = FLAGS_tcmalloc_release_rate; |
| 820 FLAGS_tcmalloc_release_rate = 0; |
| 821 |
| 822 static const int MB = 1048576; |
| 823 void* a = malloc(MB); |
| 824 void* b = malloc(MB); |
| 825 MallocExtension::instance()->ReleaseFreeMemory(); |
| 826 size_t starting_bytes = GetUnmappedBytes(); |
| 827 |
| 828 // Calling ReleaseFreeMemory() a second time shouldn't do anything. |
| 829 MallocExtension::instance()->ReleaseFreeMemory(); |
| 830 EXPECT_EQ(starting_bytes, GetUnmappedBytes()); |
| 831 |
| 832 // ReleaseToSystem shouldn't do anything either. |
| 833 MallocExtension::instance()->ReleaseToSystem(MB); |
| 834 EXPECT_EQ(starting_bytes, GetUnmappedBytes()); |
| 835 |
| 836 free(a); |
| 837 |
| 838 // The span to release should be 1MB. |
| 839 MallocExtension::instance()->ReleaseToSystem(MB/2); |
| 840 EXPECT_EQ(starting_bytes + MB, GetUnmappedBytes()); |
| 841 |
| 842 // Should do nothing since the previous call released too much. |
| 843 MallocExtension::instance()->ReleaseToSystem(MB/4); |
| 844 EXPECT_EQ(starting_bytes + MB, GetUnmappedBytes()); |
| 845 |
| 846 free(b); |
| 847 |
| 848 // Use up the extra MB/4 bytes from 'a' and also release 'b'. |
| 849 MallocExtension::instance()->ReleaseToSystem(MB/2); |
| 850 EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes()); |
| 851 |
| 852 // Should do nothing since the previous call released too much. |
| 853 MallocExtension::instance()->ReleaseToSystem(MB/2); |
| 854 EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes()); |
| 855 |
| 856 // Nothing else to release. |
| 857 MallocExtension::instance()->ReleaseFreeMemory(); |
| 858 EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes()); |
| 859 |
| 860 a = malloc(MB); |
| 861 free(a); |
| 862 EXPECT_EQ(starting_bytes + MB, GetUnmappedBytes()); |
| 863 |
| 864 // Releasing less than a page should still trigger a release. |
| 865 MallocExtension::instance()->ReleaseToSystem(1); |
| 866 EXPECT_EQ(starting_bytes + 2*MB, GetUnmappedBytes()); |
| 867 |
| 868 FLAGS_tcmalloc_release_rate = old_tcmalloc_release_rate; |
| 869 #endif // #ifndef DEBUGALLOCATION |
| 870 } |
| 871 |
| 872 bool g_no_memory = false; |
| 873 std::new_handler g_old_handler = NULL; |
| 874 static void OnNoMemory() { |
| 875 g_no_memory = true; |
| 876 std::set_new_handler(g_old_handler); |
| 877 } |
| 878 |
| 879 static void TestSetNewMode() { |
| 880 int old_mode = tc_set_new_mode(1); |
| 881 |
| 882 // DebugAllocation will try to catch huge allocations. We need to avoid this |
| 883 // by requesting a smaller malloc block, that still can't be satisfied. |
| 884 const size_t kHugeRequest = kTooBig - 1024; |
| 885 |
| 886 g_old_handler = std::set_new_handler(&OnNoMemory); |
| 887 g_no_memory = false; |
| 888 void* ret = malloc(kHugeRequest); |
| 889 EXPECT_EQ(NULL, ret); |
| 890 EXPECT_TRUE(g_no_memory); |
| 891 |
| 892 g_old_handler = std::set_new_handler(&OnNoMemory); |
| 893 g_no_memory = false; |
| 894 ret = calloc(1, kHugeRequest); |
| 895 EXPECT_EQ(NULL, ret); |
| 896 EXPECT_TRUE(g_no_memory); |
| 897 |
| 898 g_old_handler = std::set_new_handler(&OnNoMemory); |
| 899 g_no_memory = false; |
| 900 ret = realloc(NULL, kHugeRequest); |
| 901 EXPECT_EQ(NULL, ret); |
| 902 EXPECT_TRUE(g_no_memory); |
| 903 |
| 904 // Not really important, but must be small enough such that kAlignment + |
| 905 // kHugeRequest does not overflow. |
| 906 const int kAlignment = 1 << 5; |
| 907 |
| 908 g_old_handler = std::set_new_handler(&OnNoMemory); |
| 909 g_no_memory = false; |
| 910 ret = memalign(kAlignment, kHugeRequest); |
| 911 EXPECT_EQ(NULL, ret); |
| 912 EXPECT_TRUE(g_no_memory); |
| 913 |
| 914 g_old_handler = std::set_new_handler(&OnNoMemory); |
| 915 g_no_memory = false; |
| 916 EXPECT_EQ(ENOMEM, |
| 917 posix_memalign(&ret, kAlignment, kHugeRequest)); |
| 918 EXPECT_EQ(NULL, ret); |
| 919 EXPECT_TRUE(g_no_memory); |
| 920 |
| 921 tc_set_new_mode(old_mode); |
| 922 } |
| 923 |
| 750 static int RunAllTests(int argc, char** argv) { | 924 static int RunAllTests(int argc, char** argv) { |
| 751 // Optional argv[1] is the seed | 925 // Optional argv[1] is the seed |
| 752 AllocatorState rnd(argc > 1 ? atoi(argv[1]) : 100); | 926 AllocatorState rnd(argc > 1 ? atoi(argv[1]) : 100); |
| 753 | 927 |
| 754 SetTestResourceLimit(); | 928 SetTestResourceLimit(); |
| 755 | 929 |
| 756 // TODO(odo): This test has been disabled because it is only by luck that it | 930 // TODO(odo): This test has been disabled because it is only by luck that it |
| 757 // does not result in fragmentation. When tcmalloc makes an allocation which | 931 // does not result in fragmentation. When tcmalloc makes an allocation which |
| 758 // spans previously unused leaves of the pagemap it will allocate and fill in | 932 // spans previously unused leaves of the pagemap it will allocate and fill in |
| 759 // the leaves to cover the new allocation. The leaves happen to be 256MiB in | 933 // the leaves to cover the new allocation. The leaves happen to be 256MiB in |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1016 #ifndef DEBUGALLOCATION // debug allocation takes forever for huge allocs | 1190 #ifndef DEBUGALLOCATION // debug allocation takes forever for huge allocs |
| 1017 fprintf(LOGSTREAM, "Testing out of memory\n"); | 1191 fprintf(LOGSTREAM, "Testing out of memory\n"); |
| 1018 for (int s = 0; ; s += (10<<20)) { | 1192 for (int s = 0; ; s += (10<<20)) { |
| 1019 void* large_object = rnd.alloc(s); | 1193 void* large_object = rnd.alloc(s); |
| 1020 if (large_object == NULL) break; | 1194 if (large_object == NULL) break; |
| 1021 free(large_object); | 1195 free(large_object); |
| 1022 } | 1196 } |
| 1023 #endif | 1197 #endif |
| 1024 | 1198 |
| 1025 TestHugeThreadCache(); | 1199 TestHugeThreadCache(); |
| 1200 TestRanges(); |
| 1201 TestReleaseToSystem(); |
| 1202 TestSetNewMode(); |
| 1026 | 1203 |
| 1027 return 0; | 1204 return 0; |
| 1028 } | 1205 } |
| 1029 | 1206 |
| 1030 } | 1207 } |
| 1031 | 1208 |
| 1032 using testing::RunAllTests; | 1209 using testing::RunAllTests; |
| 1033 | 1210 |
| 1034 int main(int argc, char** argv) { | 1211 int main(int argc, char** argv) { |
| 1212 #ifdef DEBUGALLOCATION // debug allocation takes forever for huge allocs |
| 1213 FLAGS_max_free_queue_size = 0; // return freed blocks to tcmalloc immediately |
| 1214 #endif |
| 1215 |
| 1035 RunAllTests(argc, argv); | 1216 RunAllTests(argc, argv); |
| 1036 | 1217 |
| 1037 // Test tc_version() | 1218 // Test tc_version() |
| 1038 fprintf(LOGSTREAM, "Testing tc_version()\n"); | 1219 fprintf(LOGSTREAM, "Testing tc_version()\n"); |
| 1039 int major; | 1220 int major; |
| 1040 int minor; | 1221 int minor; |
| 1041 const char* patch; | 1222 const char* patch; |
| 1042 char mmp[64]; | 1223 char mmp[64]; |
| 1043 const char* human_version = tc_version(&major, &minor, &patch); | 1224 const char* human_version = tc_version(&major, &minor, &patch); |
| 1044 snprintf(mmp, sizeof(mmp), "%d.%d%s", major, minor, patch); | 1225 snprintf(mmp, sizeof(mmp), "%d.%d%s", major, minor, patch); |
| 1045 CHECK(!strcmp(PACKAGE_STRING, human_version)); | 1226 CHECK(!strcmp(PACKAGE_STRING, human_version)); |
| 1046 CHECK(!strcmp(PACKAGE_VERSION, mmp)); | 1227 CHECK(!strcmp(PACKAGE_VERSION, mmp)); |
| 1047 | 1228 |
| 1048 fprintf(LOGSTREAM, "PASS\n"); | 1229 fprintf(LOGSTREAM, "PASS\n"); |
| 1049 } | 1230 } |
| OLD | NEW |