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