Line data Source code
1 : //* This file is part of the MOOSE framework 2 : //* https://mooseframework.inl.gov 3 : //* 4 : //* All rights reserved, see COPYRIGHT for full restrictions 5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT 6 : //* 7 : //* Licensed under LGPL 2.1, please see LICENSE for details 8 : //* https://www.gnu.org/licenses/lgpl-2.1.html 9 : 10 : #include "MemoryUtils.h" 11 : #include "MooseError.h" 12 : 13 : #include <unistd.h> 14 : #include <mpi.h> 15 : #include <fstream> 16 : #include <array> 17 : 18 : #if defined(__APPLE__) 19 : #include <mach/task.h> 20 : #include <mach/clock.h> 21 : #include <mach/mach.h> 22 : #include <mach/vm_page_size.h> 23 : #include <sys/types.h> 24 : #include <sys/sysctl.h> 25 : #include <sys/vmmeter.h> 26 : #elif defined(__WIN32__) 27 : #include <windows.h> 28 : #include <psapi.h> 29 : #include <processthreadsapi.h> 30 : #include <sysinfoapi.h> 31 : #else 32 : #include <sys/sysinfo.h> 33 : #endif 34 : 35 : namespace MemoryUtils 36 : { 37 : 38 : std::string 39 0 : getMPIProcessorName() 40 : { 41 : #ifdef LIBMESH_HAVE_MPI 42 : int mpi_namelen; 43 : char mpi_name[MPI_MAX_PROCESSOR_NAME]; 44 0 : MPI_Get_processor_name(mpi_name, &mpi_namelen); 45 0 : return mpi_name; 46 : #else 47 : return "serial"; 48 : #endif 49 : } 50 : 51 : MooseEnum 52 29626 : getMemUnitsEnum() 53 : { 54 : return MooseEnum("bytes kibibytes mebibytes gibibytes kilobytes megabytes gigabytes", 55 29626 : "mebibytes"); 56 : } 57 : 58 : std::size_t 59 548 : getTotalRAM() 60 : { 61 : #if defined(__APPLE__) 62 : uint64_t hwmem_size; 63 : size_t length = sizeof(hwmem_size); 64 : if (0 <= sysctlbyname("hw.memsize", &hwmem_size, &length, NULL, 0)) 65 : return hwmem_size; 66 : #elif defined(__WIN32__) 67 : ULONGLONG mem_kb; 68 : if (GetPhysicallyInstalledSystemMemory(&mem_kb)) 69 : return mem_kb * 1024; 70 : #else 71 : struct sysinfo si_data; 72 548 : if (!sysinfo(&si_data)) 73 548 : return si_data.totalram * si_data.mem_unit; 74 : #endif 75 0 : return 0; 76 : } 77 : 78 : bool 79 186659728 : getMemoryStats(Stats & stats) 80 : { 81 186659728 : bool retval = false; 82 : 83 : enum StatItem 84 : { 85 : index_page_faults = 8, 86 : index_virtual_size = 19, 87 : index_resident_size = 20, 88 : num = 21 // total number of entries read 89 : }; 90 : 91 : // inspect /proc 92 186659728 : std::ifstream stat_stream("/proc/self/stat", std::ios_base::in); 93 : std::array<std::size_t, 21> val; 94 186659728 : val.fill(0); 95 : 96 186659728 : if (stat_stream) 97 : { 98 : // if the proc filesystem file is found (Linux) read its contents 99 186659728 : std::string pid, comm, state; 100 186659728 : stat_stream >> pid >> comm >> state; 101 : 102 186659728 : unsigned int i = 0; 103 : 104 4106514016 : while (!stat_stream.eof() && i < val.size()) 105 : { 106 3919854288 : stat_stream >> val[i]; 107 3919854288 : i++; 108 : } 109 : 110 : // Handle the case where we didn't get enough values by just zeroing everything 111 : // since we probably got junk 112 186659728 : if (i != val.size()) 113 0 : val.fill(0); 114 : else 115 186659728 : retval = true; 116 : 117 : // resident size is reported as number of pages in /proc 118 : #ifndef __WIN32__ 119 186659728 : val[index_resident_size] *= sysconf(_SC_PAGE_SIZE); 120 : #endif 121 186659728 : } 122 : else 123 : { 124 : #ifdef __WIN32__ 125 : auto pid = GetCurrentProcessId(); 126 : auto hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); 127 : 128 : PROCESS_MEMORY_COUNTERS pmc; 129 : if (NULL == hProcess || !GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) 130 : val.fill(0); 131 : else 132 : { 133 : retval = true; 134 : val[index_page_faults] = pmc.PageFaultCount; 135 : val[index_virtual_size] = pmc.WorkingSetSize + pmc.PagefileUsage; 136 : val[index_resident_size] = pmc.WorkingSetSize; 137 : } 138 : #else 139 : // set all data entries to zero (if all else should fail) 140 0 : val.fill(0); 141 : #endif 142 : 143 : // obtain mach task info on mac OS 144 : #if defined(__APPLE__) 145 : struct task_basic_info t_info; 146 : mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; 147 : if (KERN_SUCCESS == task_info(mach_task_self(), 148 : TASK_BASIC_INFO, 149 : reinterpret_cast<task_info_t>(&t_info), 150 : &t_info_count)) 151 : { 152 : retval = true; 153 : val[index_virtual_size] = t_info.virtual_size; // in bytes 154 : val[index_resident_size] = t_info.resident_size; // in bytes 155 : } 156 : else 157 : mooseDoOnce(::mooseWarning("task_info call failed, memory usage numbers will be incorrect")); 158 : #endif 159 : } 160 : 161 : // physical mem 162 186659728 : stats._physical_memory = val[index_resident_size]; 163 : 164 : // virtual mem 165 186659728 : stats._virtual_memory = val[index_virtual_size]; 166 : 167 : // page faults 168 186659728 : stats._page_faults = val[index_page_faults]; 169 : 170 186659728 : return retval; 171 186659728 : } 172 : 173 : std::size_t 174 186660043 : convertBytes(std::size_t bytes, MemUnits unit) 175 : { 176 186660043 : if (unit == MemUnits::Bytes) 177 840 : return bytes; 178 : 179 186659203 : unsigned int nunit = static_cast<unsigned int>(unit); 180 : 181 : // kibi, mebi, gibi 182 186659203 : if (nunit <= 3) 183 705 : return bytes >> (nunit * 10); 184 : 185 : // kilo, mega, giga 186 186658498 : if (nunit <= 6) 187 : { 188 559975380 : while (nunit-- > 3) 189 373316882 : bytes /= 1000; 190 186658498 : return bytes; 191 : } 192 : 193 0 : mooseError("Unknown memory unit"); 194 : } 195 : 196 : } // namespace MemoryUtils