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