Christopher Ferris | ee0ce44 | 2019-10-21 12:35:05 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2019 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <gtest/gtest.h> |
| 18 | |
| 19 | #include <inttypes.h> |
| 20 | #include <malloc.h> |
| 21 | #include <limits.h> |
| 22 | #include <stdint.h> |
| 23 | #include <stdio.h> |
| 24 | #include <string.h> |
| 25 | #include <unistd.h> |
| 26 | |
| 27 | #include <thread> |
| 28 | #include <vector> |
| 29 | |
Christopher Ferris | ee0ce44 | 2019-10-21 12:35:05 -0700 | [diff] [blame] | 30 | #if defined(__BIONIC__) |
| 31 | #include <meminfo/procmeminfo.h> |
| 32 | #include <procinfo/process_map.h> |
Christopher Ferris | fe2a9eb | 2024-10-16 15:21:36 -0700 | [diff] [blame] | 33 | |
| 34 | #include <log/log.h> |
| 35 | #include <log/log_read.h> |
| 36 | #endif |
| 37 | |
| 38 | #if defined(__BIONIC__) |
| 39 | static void PrintLogStats(uint64_t& last_time) { |
| 40 | logger_list* logger = |
| 41 | android_logger_list_open(android_name_to_log_id("main"), ANDROID_LOG_NONBLOCK, 0, getpid()); |
| 42 | if (logger == nullptr) { |
| 43 | printf("Failed to open log for main\n"); |
| 44 | return; |
| 45 | } |
| 46 | |
| 47 | uint64_t last_message_time = last_time; |
| 48 | while (true) { |
| 49 | log_msg entry; |
| 50 | ssize_t retval = android_logger_list_read(logger, &entry); |
| 51 | if (retval == 0) { |
| 52 | break; |
| 53 | } |
| 54 | if (retval < 0) { |
| 55 | if (retval == -EINTR) { |
| 56 | continue; |
| 57 | } |
| 58 | // EAGAIN means there is nothing left to read when ANDROID_LOG_NONBLOCK is set. |
| 59 | if (retval != -EAGAIN) { |
| 60 | printf("Failed to read log entry: %s\n", strerrordesc_np(retval)); |
| 61 | } |
| 62 | break; |
| 63 | } |
| 64 | if (entry.msg() == nullptr) { |
| 65 | continue; |
| 66 | } |
| 67 | // Only print allocator tagged log entries. |
| 68 | std::string_view tag(entry.msg() + 1); |
| 69 | if (tag != "scudo" && tag != "jemalloc") { |
| 70 | continue; |
| 71 | } |
| 72 | if (entry.nsec() > last_time) { |
| 73 | printf(" %s\n", &tag.back() + 2); |
| 74 | // Only update the last time outside this loop just in case two or more |
| 75 | // messages have the same timestamp. |
| 76 | last_message_time = entry.nsec(); |
| 77 | } |
| 78 | } |
| 79 | android_logger_list_close(logger); |
| 80 | last_time = last_message_time; |
| 81 | } |
Christopher Ferris | ee0ce44 | 2019-10-21 12:35:05 -0700 | [diff] [blame] | 82 | #endif |
| 83 | |
| 84 | TEST(malloc_stress, multiple_threads_forever) { |
| 85 | constexpr size_t kMaxThreads = 256; |
| 86 | constexpr size_t kAllocSize = 4096; |
| 87 | #if defined(__BIONIC__) |
| 88 | uint64_t rss_min = UINT64_MAX; |
| 89 | uint64_t rss_max = 0; |
| 90 | uint64_t vss_min = UINT64_MAX; |
| 91 | uint64_t vss_max = 0; |
| 92 | ASSERT_EQ(1, mallopt(M_DECAY_TIME, 1)); |
| 93 | #endif |
| 94 | uint64_t mallinfo_min = UINT64_MAX; |
| 95 | uint64_t mallinfo_max = 0; |
Christopher Ferris | fe2a9eb | 2024-10-16 15:21:36 -0700 | [diff] [blame] | 96 | |
| 97 | uint64_t last_message_time = 0; |
Christopher Ferris | ee0ce44 | 2019-10-21 12:35:05 -0700 | [diff] [blame] | 98 | for (size_t i = 0; ; i++) { |
| 99 | printf("Pass %zu\n", i); |
| 100 | |
| 101 | std::vector<std::thread*> threads; |
| 102 | for (size_t i = 0; i < kMaxThreads; i++) { |
| 103 | threads.push_back(new std::thread([]() { |
| 104 | void* buf = malloc(4096); |
| 105 | if (buf == nullptr) { |
| 106 | printf("Failed to allocate memory\n"); |
| 107 | _exit(1); |
| 108 | } |
| 109 | memset(buf, 0, kAllocSize); |
| 110 | sleep(1); |
| 111 | free(buf); |
| 112 | })); |
| 113 | } |
| 114 | |
| 115 | for (auto thread : threads) { |
| 116 | thread->join(); |
| 117 | delete thread; |
| 118 | } |
| 119 | threads.clear(); |
| 120 | |
| 121 | #if defined(__BIONIC__) |
| 122 | android::meminfo::ProcMemInfo proc_mem(getpid()); |
| 123 | const std::vector<android::meminfo::Vma>& maps = proc_mem.MapsWithoutUsageStats(); |
| 124 | uint64_t rss_bytes = 0; |
| 125 | uint64_t vss_bytes = 0; |
| 126 | for (auto& vma : maps) { |
Christopher Ferris | fe2a9eb | 2024-10-16 15:21:36 -0700 | [diff] [blame] | 127 | if (vma.name == "[anon:libc_malloc]" || vma.name.starts_with("[anon:scudo:") || |
| 128 | vma.name.starts_with("[anon:GWP-ASan")) { |
Christopher Ferris | ee0ce44 | 2019-10-21 12:35:05 -0700 | [diff] [blame] | 129 | android::meminfo::Vma update_vma(vma); |
| 130 | ASSERT_TRUE(proc_mem.FillInVmaStats(update_vma)); |
| 131 | rss_bytes += update_vma.usage.rss; |
| 132 | vss_bytes += update_vma.usage.vss; |
| 133 | } |
| 134 | } |
| 135 | if (rss_bytes < rss_min) { |
| 136 | rss_min = rss_bytes; |
| 137 | } |
| 138 | if (rss_bytes > rss_max) { |
| 139 | rss_max = rss_bytes; |
| 140 | } |
| 141 | if (vss_bytes < vss_min) { |
| 142 | vss_min = vss_bytes; |
| 143 | } |
| 144 | if (vss_bytes > vss_max) { |
| 145 | vss_max = vss_bytes; |
| 146 | } |
| 147 | printf("RSS %" PRIu64 " %0.2fMB\n", rss_bytes, rss_bytes / (1024.0 * 1024.0)); |
| 148 | printf(" Min %" PRIu64 " %0.2fMB\n", rss_min, rss_min / (1024.0 * 1024.0)); |
| 149 | printf(" Max %" PRIu64 " %0.2fMB\n", rss_max, rss_max / (1024.0 * 1024.0)); |
| 150 | printf("VSS %" PRIu64 " %0.2f MB\n", vss_bytes, vss_bytes / (1024.0 * 1024.0)); |
| 151 | printf(" Min %" PRIu64 " %0.2fMB\n", vss_min, vss_min / (1024.0 * 1024.0)); |
| 152 | printf(" Max %" PRIu64 " %0.2fMB\n", vss_max, vss_max / (1024.0 * 1024.0)); |
| 153 | #endif |
| 154 | |
| 155 | size_t mallinfo_bytes = mallinfo().uordblks; |
| 156 | if (mallinfo_bytes < mallinfo_min) { |
| 157 | mallinfo_min = mallinfo_bytes; |
| 158 | } |
| 159 | if (mallinfo_bytes > mallinfo_max) { |
| 160 | mallinfo_max = mallinfo_bytes; |
| 161 | } |
| 162 | printf("Allocated memory %zu %0.2fMB\n", mallinfo_bytes, mallinfo_bytes / (1024.0 * 1024.0)); |
| 163 | printf(" Min %" PRIu64 " %0.2fMB\n", mallinfo_min, mallinfo_min / (1024.0 * 1024.0)); |
| 164 | printf(" Max %" PRIu64 " %0.2fMB\n", mallinfo_max, mallinfo_max / (1024.0 * 1024.0)); |
Christopher Ferris | fe2a9eb | 2024-10-16 15:21:36 -0700 | [diff] [blame] | 165 | |
| 166 | #if defined(__BIONIC__) |
| 167 | if (((i + 1) % 100) == 0) { |
| 168 | // Send native allocator stats to the log |
| 169 | mallopt(M_LOG_STATS, 0); |
| 170 | |
| 171 | printf("Log stats:\n"); |
| 172 | PrintLogStats(last_message_time); |
| 173 | } |
| 174 | #endif |
Christopher Ferris | ee0ce44 | 2019-10-21 12:35:05 -0700 | [diff] [blame] | 175 | } |
| 176 | } |