xref: /oneTBB/test/common/memory_usage.h (revision c21e688a)
151c0b2f7Stbbdev /*
2*c21e688aSSergey Zheltov     Copyright (c) 2005-2022 Intel Corporation
351c0b2f7Stbbdev 
451c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev     you may not use this file except in compliance with the License.
651c0b2f7Stbbdev     You may obtain a copy of the License at
751c0b2f7Stbbdev 
851c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev 
1051c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev     See the License for the specific language governing permissions and
1451c0b2f7Stbbdev     limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev 
1751c0b2f7Stbbdev // Declarations for simple estimate of the memory being used by a program.
1851c0b2f7Stbbdev // Not yet implemented for macOS*.
1951c0b2f7Stbbdev // This header is an optional part of the test harness.
2051c0b2f7Stbbdev // It assumes that "harness_assert.h" has already been included.
2151c0b2f7Stbbdev 
224523a761Stbbdev #ifndef __TBB_test_common_memory_usage_H_
234523a761Stbbdev #define __TBB_test_common_memory_usage_H_
244523a761Stbbdev 
2549e08aacStbbdev #include "common/test.h"
2651c0b2f7Stbbdev #include "utils.h"
2751c0b2f7Stbbdev #include "utils_assert.h"
2851c0b2f7Stbbdev 
29734f0bc0SPablo Romero #if __unix__ || __sun
3051c0b2f7Stbbdev #include <sys/resource.h>
3151c0b2f7Stbbdev #include <unistd.h>
3251c0b2f7Stbbdev #include <sys/utsname.h> /* for uname */
3351c0b2f7Stbbdev #include <errno.h>       /* for use in LinuxKernelVersion() */
3451c0b2f7Stbbdev 
3551c0b2f7Stbbdev // Parse file utility for THP info
3651c0b2f7Stbbdev #include "src/tbbmalloc/shared_utils.h"
3751c0b2f7Stbbdev 
3851c0b2f7Stbbdev #elif __APPLE__ && !__ARM_ARCH
3951c0b2f7Stbbdev #include <unistd.h>
4051c0b2f7Stbbdev #include <mach/mach.h>
4151c0b2f7Stbbdev #include <AvailabilityMacros.h>
4251c0b2f7Stbbdev #if MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_6 || __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
4351c0b2f7Stbbdev #include <mach/shared_region.h>
4451c0b2f7Stbbdev #else
4551c0b2f7Stbbdev #include <mach/shared_memory_server.h>
4651c0b2f7Stbbdev #endif
4751c0b2f7Stbbdev #if SHARED_TEXT_REGION_SIZE || SHARED_DATA_REGION_SIZE
4851c0b2f7Stbbdev const size_t shared_size = SHARED_TEXT_REGION_SIZE+SHARED_DATA_REGION_SIZE;
4951c0b2f7Stbbdev #else
5051c0b2f7Stbbdev const size_t shared_size = 0;
5151c0b2f7Stbbdev #endif
5251c0b2f7Stbbdev 
5351c0b2f7Stbbdev #elif _WIN32 && !__TBB_WIN8UI_SUPPORT
5451c0b2f7Stbbdev #include <windows.h>
5551c0b2f7Stbbdev #include <psapi.h>
5651c0b2f7Stbbdev #if _MSC_VER
5751c0b2f7Stbbdev #pragma comment(lib, "psapi")
5851c0b2f7Stbbdev #endif
5951c0b2f7Stbbdev 
6051c0b2f7Stbbdev #endif /* OS selection */
6151c0b2f7Stbbdev 
6251c0b2f7Stbbdev namespace utils {
6351c0b2f7Stbbdev 
6451c0b2f7Stbbdev     enum MemoryStatType {
6551c0b2f7Stbbdev         currentUsage,
6651c0b2f7Stbbdev         peakUsage
6751c0b2f7Stbbdev     };
6851c0b2f7Stbbdev 
69734f0bc0SPablo Romero #if __unix__
LinuxKernelVersion()7051c0b2f7Stbbdev     inline unsigned LinuxKernelVersion()
7151c0b2f7Stbbdev     {
7251c0b2f7Stbbdev         unsigned digit1, digit2, digit3;
7351c0b2f7Stbbdev         struct utsname utsnameBuf;
7451c0b2f7Stbbdev 
7551c0b2f7Stbbdev         if (-1 == uname(&utsnameBuf)) {
7651c0b2f7Stbbdev             CHECK_MESSAGE(false, "Can't call uname: errno = " << errno);
7751c0b2f7Stbbdev         }
7851c0b2f7Stbbdev         if (3 != sscanf(utsnameBuf.release, "%u.%u.%u", &digit1, &digit2, &digit3)) {
7951c0b2f7Stbbdev             CHECK_MESSAGE(false, "Unable to parse OS release: " << utsnameBuf.release);
8051c0b2f7Stbbdev         }
8151c0b2f7Stbbdev         return 1000000 * digit1 + 1000 * digit2 + digit3;
8251c0b2f7Stbbdev     }
8351c0b2f7Stbbdev #endif
8451c0b2f7Stbbdev 
8551c0b2f7Stbbdev     //! Return estimate of number of bytes of memory that this program is currently using.
8651c0b2f7Stbbdev     /* Returns 0 if not implemented on platform. */
87b15aabb3Stbbdev     std::size_t GetMemoryUsage(MemoryStatType stat = currentUsage) {
8851c0b2f7Stbbdev         utils::suppress_unused_warning(stat);
8994b62cc1Svlserov #if __TBB_WIN8UI_SUPPORT || defined(WINAPI_FAMILY)
9051c0b2f7Stbbdev         return 0;
9151c0b2f7Stbbdev #elif _WIN32
9251c0b2f7Stbbdev         PROCESS_MEMORY_COUNTERS mem;
9351c0b2f7Stbbdev         bool status = GetProcessMemoryInfo(GetCurrentProcess(), &mem, sizeof(mem)) != 0;
9457f524caSIlya Isaev         ASSERT(status, nullptr);
9551c0b2f7Stbbdev         return stat == currentUsage ? mem.PagefileUsage : mem.PeakPagefileUsage;
96734f0bc0SPablo Romero #elif __unix__
9751c0b2f7Stbbdev         long unsigned size = 0;
9851c0b2f7Stbbdev         FILE* fst = fopen("/proc/self/status", "r");
9957f524caSIlya Isaev         ASSERT(fst != nullptr, nullptr);
10051c0b2f7Stbbdev         const int BUF_SZ = 200;
10151c0b2f7Stbbdev         char buf_stat[BUF_SZ];
10251c0b2f7Stbbdev         const char* pattern = stat == peakUsage ? "VmPeak: %lu" : "VmSize: %lu";
10357f524caSIlya Isaev         while (nullptr != fgets(buf_stat, BUF_SZ, fst)) {
10451c0b2f7Stbbdev             if (1 == sscanf(buf_stat, pattern, &size)) {
10551c0b2f7Stbbdev                 ASSERT(size, "Invalid value of memory consumption.");
10651c0b2f7Stbbdev                 break;
10751c0b2f7Stbbdev             }
10851c0b2f7Stbbdev         }
10951c0b2f7Stbbdev         // VmPeak is available in kernels staring 2.6.15
11051c0b2f7Stbbdev         if (stat != peakUsage || LinuxKernelVersion() >= 2006015)
11151c0b2f7Stbbdev             ASSERT(size, "Invalid /proc/self/status format, pattern not found.");
11251c0b2f7Stbbdev         fclose(fst);
11351c0b2f7Stbbdev         return size * 1024;
11451c0b2f7Stbbdev #elif __APPLE__ && !__ARM_ARCH
11551c0b2f7Stbbdev         // TODO: find how detect peak virtual memory size under macOS
11651c0b2f7Stbbdev         if (stat == peakUsage)
11751c0b2f7Stbbdev             return 0;
11851c0b2f7Stbbdev         kern_return_t status;
11951c0b2f7Stbbdev         task_basic_info info;
12051c0b2f7Stbbdev         mach_msg_type_number_t msg_type = TASK_BASIC_INFO_COUNT;
12151c0b2f7Stbbdev         status = task_info(mach_task_self(), TASK_BASIC_INFO, reinterpret_cast<task_info_t>(&info), &msg_type);
12257f524caSIlya Isaev         ASSERT(status == KERN_SUCCESS, nullptr);
12351c0b2f7Stbbdev         return info.virtual_size - shared_size;
12451c0b2f7Stbbdev #else
12551c0b2f7Stbbdev         return 0;
12651c0b2f7Stbbdev #endif
12751c0b2f7Stbbdev     }
12851c0b2f7Stbbdev 
12951c0b2f7Stbbdev     //! Use approximately a specified amount of stack space.
13051c0b2f7Stbbdev     /** Recursion is used here instead of alloca because some implementations of alloca do not use the stack. */
13157f524caSIlya Isaev     void UseStackSpace(size_t amount, char* top = nullptr) {
13251c0b2f7Stbbdev         char x[1000];
13351c0b2f7Stbbdev         memset(x, -1, sizeof(x));
13451c0b2f7Stbbdev         if (!top)
13551c0b2f7Stbbdev             top = x;
13651c0b2f7Stbbdev         CHECK_MESSAGE(x <= top, "test assumes that stacks grow downwards");
13751c0b2f7Stbbdev         if (size_t(top - x) < amount)
13851c0b2f7Stbbdev             UseStackSpace(amount, top);
13951c0b2f7Stbbdev     }
14051c0b2f7Stbbdev 
141734f0bc0SPablo Romero #if __unix__
14251c0b2f7Stbbdev 
isTHPEnabledOnMachine()14351c0b2f7Stbbdev     inline bool isTHPEnabledOnMachine() {
144e82d2503SIlya Isaev         long long thpPresent = 'n';
145e82d2503SIlya Isaev         long long hugePageSize = -1;
14651c0b2f7Stbbdev 
147e82d2503SIlya Isaev         parseFileItem thpItem[] = { { "[alwa%cs] madvise never\n", thpPresent } };
148e82d2503SIlya Isaev         parseFileItem hpSizeItem[] = { { "Hugepagesize: %lld kB", hugePageSize } };
149e82d2503SIlya Isaev 
150e82d2503SIlya Isaev         parseFile</*BUFF_SIZE=*/100>("/sys/kernel/mm/transparent_hugepage/enabled", thpItem);
151e82d2503SIlya Isaev         parseFile</*BUFF_SIZE=*/100>("/proc/meminfo", hpSizeItem);
152e82d2503SIlya Isaev 
153e82d2503SIlya Isaev         if (hugePageSize > -1 && thpPresent == 'y') {
15451c0b2f7Stbbdev             return true;
15551c0b2f7Stbbdev         } else {
15651c0b2f7Stbbdev             return false;
15751c0b2f7Stbbdev         }
15851c0b2f7Stbbdev     }
getSystemTHPAllocatedSize()159e82d2503SIlya Isaev     inline long long getSystemTHPAllocatedSize() {
160e82d2503SIlya Isaev         long long anonHugePagesSize = 0;
16151c0b2f7Stbbdev         parseFileItem meminfoItems[] = {
162e82d2503SIlya Isaev             { "AnonHugePages: %lld kB", anonHugePagesSize } };
16351c0b2f7Stbbdev         parseFile</*BUFF_SIZE=*/100>("/proc/meminfo", meminfoItems);
16451c0b2f7Stbbdev         return anonHugePagesSize;
16551c0b2f7Stbbdev     }
getSystemTHPCount()166e82d2503SIlya Isaev     inline long long getSystemTHPCount() {
167e82d2503SIlya Isaev         long long anonHugePages = 0;
16851c0b2f7Stbbdev         parseFileItem vmstatItems[] = {
169e82d2503SIlya Isaev             { "nr_anon_transparent_hugepages %lld", anonHugePages } };
17051c0b2f7Stbbdev         parseFile</*BUFF_SIZE=*/100>("/proc/vmstat", vmstatItems);
17151c0b2f7Stbbdev         return anonHugePages;
17251c0b2f7Stbbdev     }
17351c0b2f7Stbbdev 
174734f0bc0SPablo Romero #endif // __unix__
17551c0b2f7Stbbdev 
17651c0b2f7Stbbdev } // namespace utils
1774523a761Stbbdev #endif // __TBB_test_common_memory_usage_H_
178