1 #ifndef MADNESS_WORLD_WORLDMEM_H__INCLUDED 2 #define MADNESS_WORLD_WORLDMEM_H__INCLUDED 3 4 /* 5 This file is part of MADNESS. 6 7 Copyright (C) 2007,2010 Oak Ridge National Laboratory 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 23 For more information please contact: 24 25 Robert J. Harrison 26 Oak Ridge National Laboratory 27 One Bethel Valley Road 28 P.O. Box 2008, MS-6367 29 30 email: harrisonrj@ornl.gov 31 tel: 865-241-3937 32 fax: 865-572-0680 33 34 35 $Id: world.cc 454 2008-01-26 03:08:15Z rjharrison $ 36 */ 37 38 #include <madness/madness_config.h> 39 #include <string> 40 #ifdef WORLD_GATHER_MEM_STATS 41 #include <new> 42 #endif // WORLD_GATHER_MEM_STATS 43 #include <cstddef> 44 #include <fstream> 45 #include <sstream> 46 47 #if defined(HAVE_IBMBGQ) 48 #include <spi/include/kernel/memory.h> 49 #elif defined(ON_A_MAC) 50 #include <malloc/malloc.h> 51 #elif defined(X86_32) 52 #include <stdlib.h> 53 #elif defined(X86_64) 54 #include <sys/types.h> 55 #include <unistd.h> 56 #include <sys/sysinfo.h> 57 #include <string> 58 #endif 59 60 namespace madness { 61 62 /// Used to output memory statistics and control tracing, etc. 63 64 /// There is currently only one instance of this class in worldmem.cc 65 /// that is used by special versions of global new+delete enabled 66 /// by compiling with WORLD_GATHER_MEM_STATS enabled. 67 /// 68 /// Default for max_mem_limit is unlimited. 69 class WorldMemInfo { 70 #ifdef WORLD_GATHER_MEM_STATS 71 friend void* ::operator new(size_t size) throw (std::bad_alloc); 72 friend void ::operator delete(void *p) throw(); 73 #endif 74 private: 75 /// Invoked when user pointer p is allocated with size bytes 76 void do_new(void *p, std::size_t size); 77 78 /// Invoked when user pointer p is deleted with size bytes 79 void do_del(void *p, std::size_t size); 80 81 public: 82 static const unsigned long overhead = 4*sizeof(long) + 16; 83 /// If you add new stats be sure that the initialization in worldmem.cc is OK 84 unsigned long num_new_calls; ///< Counts calls to new 85 unsigned long num_del_calls; ///< Counts calls to delete 86 unsigned long cur_num_frags; ///< Current number of allocated fragments 87 unsigned long max_num_frags; ///< Lifetime maximum number of allocated fragments 88 unsigned long cur_num_bytes; ///< Current amount of allocated memory in bytes 89 unsigned long max_num_bytes; ///< Lifetime maximum number of allocated bytes 90 unsigned long max_mem_limit; ///< if size+cur_num_bytes>max_mem_limit new will throw MadnessException 91 bool trace; 92 93 /// Prints memory use statistics to std::cout 94 void print() const; 95 96 /// Resets all counters to zero 97 void reset(); 98 99 /// If trace is set true a message is printed for every new and delete set_trace(bool trace)100 void set_trace(bool trace) { 101 this->trace = trace; 102 } 103 104 /// Set the maximum memory limit (trying to allocate more will throw MadnessException) set_max_mem_limit(unsigned long max_mem_limit)105 void set_max_mem_limit(unsigned long max_mem_limit) { 106 this->max_mem_limit = max_mem_limit; 107 } 108 }; 109 110 /// Returns pointer to internal structure 111 WorldMemInfo* world_mem_info(); 112 113 namespace detail { 114 template <typename Char> const Char* Vm_cstr(); 115 } 116 117 /// \brief print memory stats to file \c filename_prefix.<rank> , tagged with \c tag 118 /// \param[in] rank process rank 119 /// \param[in] tag record tag as any string type, e.g. \c const char[] , \c std::string , or \c std::wstring 120 /// \param[in] filename_prefix filename prefix; the default value is "MEMORY" 121 /// \note must set global locale properly with \c std::locale::global() if \c tag has 122 /// nontrivial encoding 123 template <typename String> void print_meminfo( 124 int id, const String& tag, 125 const std::string filename_prefix = std::string("MEMORY")) { 126 using namespace std; 127 #if defined(WORLD_MEM_PROFILE_ENABLE) 128 using Char = typename std::iterator_traits<decltype(std::begin(tag))>::value_type; 129 basic_ofstream<Char> memoryfile; 130 ostringstream filename; 131 132 filename << filename_prefix << "." << id; 133 134 memoryfile.open(filename.str().c_str(), ios::out | ios::app); 135 memoryfile << tag << endl; 136 137 const double fac = 1024.0 * 1024.0; /* Convert from bytes to megabytes */ 138 #if defined(HAVE_IBMBGQ) 139 uint64_t shared, persist, heapavail, stackavail, stack, heap, guard, mmap; 140 141 Kernel_GetMemorySize(KERNEL_MEMSIZE_SHARED, &shared); 142 Kernel_GetMemorySize(KERNEL_MEMSIZE_PERSIST, &persist); 143 Kernel_GetMemorySize(KERNEL_MEMSIZE_HEAPAVAIL, &heapavail); 144 Kernel_GetMemorySize(KERNEL_MEMSIZE_STACKAVAIL, &stackavail); 145 Kernel_GetMemorySize(KERNEL_MEMSIZE_STACK, &stack); 146 Kernel_GetMemorySize(KERNEL_MEMSIZE_HEAP, &heap); 147 Kernel_GetMemorySize(KERNEL_MEMSIZE_GUARD, &guard); 148 Kernel_GetMemorySize(KERNEL_MEMSIZE_MMAP, &mmap); 149 150 memoryfile << "Heap size (MB): " << (heap / fac) 151 << ", available: " << (heapavail / fac) << endl; 152 memoryfile << "Stack size (MB): " << (stack / fac) 153 << ", available: " << (stackavail / fac) << endl; 154 memoryfile << "Memory: shared: " << (shared / fac) 155 << ", persist: " << (persist / fac) 156 << ", guard: " << (guard / fac) << ", mmap: " << (mmap / fac) 157 << endl; 158 #elif defined(ON_A_MAC) 159 /* Mac OS X specific hack - un-tested post Snow Leopard */ 160 struct malloc_statistics_t mi; /* structure in bytes */ 161 162 malloc_zone_statistics(nullptr, &mi); 163 164 memoryfile << "Heap size (MB): " << (mi.size_in_use / fac) << endl; 165 #elif defined(X86_32) // 32-bit Linux 166 struct mallinfo mi; /* structure in bytes */ 167 168 mi = mallinfo(); 169 170 memoryfile << "Non-mmap (MB): " << (mi.arena / fac) << endl; 171 memoryfile << "Mmap (MB): " << (mi.hblkhd / fac) << endl; 172 memoryfile << "Total malloc chunks (MB): " << (mi.uordblks / fac) << endl; 173 #elif defined(X86_64) // 64-bit Linux 174 // try parsing /proc/PID/status first, fallback on sysinfo 175 string status_fname = string("/proc/") + to_string(getpid()) + string("/status"); 176 basic_ifstream<Char> status_stream(status_fname); 177 if (status_stream.good()) { 178 basic_string<Char> line; 179 while(getline(status_stream, line)) { 180 if (line.find(detail::Vm_cstr<Char>()) == 0) 181 memoryfile << line << endl; 182 } 183 status_stream.close(); 184 } 185 else { 186 /* Better than nothing, mallinfo unreliable on 64-bit machine due to 187 use of int in mallinfo data structure. Requires Linux 188 kernel. Inaccurate if other processes besides MADNESS are 189 running. Memory differences appear to be reliable. */ 190 struct sysinfo si; /* structure in bytes */ 191 192 sysinfo(&si); 193 194 memoryfile << "Total RAM (MB): " << (si.totalram / fac) << endl; 195 memoryfile << "Free RAM (MB): " << (si.freeram / fac) << endl; 196 memoryfile << "Buffer (MB): " << (si.bufferram / fac) << endl; 197 memoryfile << "RAM in use (MB): " 198 << ((si.totalram - si.freeram + si.bufferram) / fac) << endl; 199 } 200 #endif // platform specific 201 memoryfile.close(); 202 #else // WORLD_MEM_PROFILE_ENABLE 203 return; 204 #endif // WORLD_MEM_PROFILE_ENABLE 205 } 206 207 208 } // namespace madness 209 210 #endif // MADNESS_WORLD_WORLDMEM_H__INCLUDED 211