MADNESS 0.10.1
memory_measurement.h
Go to the documentation of this file.
1//
2// Created by Florian Bischoff on 2/16/25.
3//
4
5#ifndef MEMORY_MEASUREMENT_H
6#define MEMORY_MEASUREMENT_H
7
8
10#include<madness/mra/mra.h>
11
12#if defined(__APPLE__)
13# include <malloc/malloc.h>
14#elif defined(__linux__) && defined(__GLIBC__)
15# include <malloc.h>
16#endif
17
18
19
20namespace madness {
21 /// measure the memory usage of all FunctionImpl objects of all worlds
22
23 /// Assuming FunctionImpl are the largest objects in a calculation
24 /// data is kept as key-value pairs in a map: key=world_id,rank,hostname,NDIM, value=#functions,memory_GB
26 public:
27 /// forward declaration
28 struct MemKey;
29 struct MemInfo;
30
31 /// measure the memory usage of all objects of all worlds
32 static std::map<MemKey,MemInfo> measure_and_print(World& world) {
34 world.gop.fence();
36 world.gop.fence();
37 mm.print_memory_map(world); // will reduce memory_map to rank0 of universe
38 world.gop.fence();
39 // mm.clear_map();
40 return mm.world_memory_map; // on rank0 only!
41 }
42
43 static void release_free_memory() {
44#if defined(__linux__) && defined(__GLIBC__)
45 malloc_trim(0);
46#elif defined(__APPLE__)
47 malloc_zone_pressure_relief(nullptr, 0);
48#endif
49 }
50
51
52
53 private:
54 /// get the hostname of this machine, rank-local
55 static std::string get_hostname() {
56 char buffer[256];
57 gethostname(buffer, 256);
58 return std::string(buffer);
59 }
60
61 public:
62 struct MemKey {
63 unsigned long world_id=1;
64 unsigned long rank=0;
65 std::string hostname="localhost";
66 std::size_t DIM=0;
67 MemKey() = default;
68 explicit MemKey(World& world) : world_id(world.id()), rank(world.rank()) {
70 }
71
72 template<typename T, std::size_t NDIM>
73 explicit MemKey(const FunctionImpl<T,NDIM>& fimpl) : MemKey(fimpl.world) {
74 DIM=NDIM;
75 }
76 MemKey(const MemKey& other) = default;
77
78 template<typename Archive>
79 void serialize(Archive& ar) const {
80 ar & world_id & rank & hostname & DIM;
81 }
82 };
83 friend bool operator<(const MemKey& lhs, const MemKey& other) {
84 if (lhs.hostname!=other.hostname) return lhs.hostname<other.hostname;
85 if (lhs.world_id!=other.world_id) return lhs.world_id<other.world_id;
86 if (lhs.rank!=other.rank) return lhs.rank<other.rank;
87 return lhs.DIM<other.DIM;
88 }
89
90 struct MemInfo {
91 MemInfo() =default;
92 MemInfo(const MemInfo& other) =default;
94 double memory_GB=0.0;
95 template <typename Archive>
96 void serialize(Archive& ar) const {
98 }
99 };
100
101 typedef std::map<MemKey,MemInfo> MemInfoMapT;
102
103
104 private:
105 template<typename T, std::size_t NDIM>
107 World& world=*World::world_from_id(obj_id.get_world_id());
108 auto ptr_opt = world.ptr_from_id< WorldObject< FunctionImpl<T,NDIM> > >(obj_id);
109 if (!ptr_opt)
110 MADNESS_EXCEPTION("FunctionImpl: remote operation attempting to use a locally uninitialized object",0);
111 return (dynamic_cast< const FunctionImpl<T,NDIM>*>(*ptr_opt));
112 }
113
114 /// keeps track of the memory usage of all objects of one or many worlds **on this rank**
116 bool debug=false;
117
118 template<typename T, std::size_t NDIM>
120 const double toGB=double(sizeof(T))/(1024*1024*1024); // convert to GB
121 auto sz=f.nCoeff_local();
122 if (debug) print("funcimpl<T,",NDIM,"> id",f.id(), "rank",f.world.rank(),"size in GB",sz*toGB);
123
124 // accumulate the sizes into the world_memory_map
125 world_memory_map[MemKey(f)].num_functions++;
126 world_memory_map[MemKey(f)].memory_GB+=sz*toGB;
127 }
128
129 public:
130
131 /// add all FunctionImpl<T,NDIM> objects of the given world to the memory map
132 /// the memory map is a rank-local object
133 void search_world(World& world) {
134
135 auto all_objects=world.get_object_ids();
136 if (debug and (world.rank()==0)) print("objects in this world ",all_objects);
137
138 for (const auto& obj : all_objects) {
139 if (auto funcimpl=cast_to_funcimpl_ptr<double,1>(obj)) add_memory_to_map(*funcimpl);
140 if (auto funcimpl=cast_to_funcimpl_ptr<double,2>(obj)) add_memory_to_map(*funcimpl);
141 if (auto funcimpl=cast_to_funcimpl_ptr<double,3>(obj)) add_memory_to_map(*funcimpl);
142 if (auto funcimpl=cast_to_funcimpl_ptr<double,4>(obj)) add_memory_to_map(*funcimpl);
143 if (auto funcimpl=cast_to_funcimpl_ptr<double,5>(obj)) add_memory_to_map(*funcimpl);
144 if (auto funcimpl=cast_to_funcimpl_ptr<double,6>(obj)) add_memory_to_map(*funcimpl);
145 }
146 }
147
148 /// add all FunctionImpl<T,NDIM> objects **of all worlds** to the memory map
149 /// the memory map is a rank-local object
151 auto all_worlds=World::get_world_ids(); // all worlds but the default world
152 all_worlds.push_back(World::get_default().id()); // add the default world
153 if (debug) print("searching worlds",all_worlds);
154 for (auto world_id : all_worlds) {
155 if (debug) print("searching world",world_id);
156 World* thisworld=World::world_from_id(world_id);
157 if (World::exists(thisworld)) search_world(*thisworld);
158 }
159 }
160
161 /// reset the memory map
162 void clear_map() {
163 world_memory_map.clear();
164 }
165
166 /// gather all information of the map on rank 0 of the universe
167 void reduce_map(World& universe) {
168 // turn map into vector
169 std::vector<std::pair<MemKey,MemInfo>> memory_vec(world_memory_map.begin(),world_memory_map.end());
170 // gather all data on rank 0
171 memory_vec=universe.gop.concat0(memory_vec);
172 // turn back into map
173 clear_map();
174 for (const auto& [memkey,memval] : memory_vec) {
175 world_memory_map[memkey]=memval;
176 }
177 }
178
179
180 /// given the hostname, return number of ranks and total rss on that node
181 static std::map<std::string,std::pair<int,double>> host_to_nrank_and_rss_map(World& universe) {
182 auto accumulate_left =[](std::pair<int,double>& a, const std::pair<int,double>& b) {
183 a.first++;
184 a.second+=b.second;
185 };
186 auto rank_to_host=rank_to_host_and_rss_map(universe);
187 std::map<std::string,std::pair<int,double>> host_to_rank;
188 for (const auto& [rank,hostname_and_rss] : rank_to_host) {
189 accumulate_left(host_to_rank[hostname_and_rss.first],std::pair<int,double>(rank,hostname_and_rss.second));
190 }
191 return host_to_rank;
192 }
193
194
195 /// accumulate the memory usage of all objects of all worlds for this rank per host
196
197 /// integrate out world and dim from MemKey, result lives on rank 0 only
198 std::vector<std::pair<std::pair<std::string,long>,double>> memory_per_host_and_rank(World& world) const {
199
200 std::map<std::pair<std::string,long>,double> memory_per_host;
201 for (const auto& [memkey,memval] : world_memory_map) {
202 memory_per_host[{memkey.hostname,memkey.rank}]+=memval.memory_GB;
203 }
204
205 // turn map into vector and sort
206 std::vector<std::pair<std::pair<std::string,long>,double>> memory_per_host_vec(memory_per_host.begin(),memory_per_host.end());
207 std::sort(memory_per_host_vec.begin(),memory_per_host_vec.end(),[](const auto& a, const auto& b){return a.first<b.first;});
208
209 return memory_per_host_vec;
210 }
211
212 /// accumulate the memory usage of all objects of all worlds over all ranks per host
213
214 /// integrate out world, dim and rank, only hostname is left
215 std::vector<std::pair<std::string,double>> memory_per_host_all_ranks(
216 const std::vector<std::pair<std::pair<std::string,long>,double>>& mem_per_host_and_rank) const {
217 std::map<std::string,double> mem_per_host;
218 for (auto& [hostname_and_rank,memory] : mem_per_host_and_rank) {
219 auto hostname=hostname_and_rank.first;
220 mem_per_host[hostname]+=memory;
221 }
222 // turn map into vector
223 std::vector<std::pair<std::string,double>> mem_per_host_vec(mem_per_host.begin(),mem_per_host.end());
224 return mem_per_host_vec;
225 }
226
227 /// return the total memory usage over all hosts
228 static double total_memory(const MemInfoMapT& memmap) {
229 double total_memory=0.0;
230 for (const auto& [memkey,memval] : memmap) {
231 total_memory+=memval.memory_GB;
232 }
233 return total_memory;
234 }
235
236 /// return the maximum memory usage over all hosts
237 static double max_memory(const MemInfoMapT& memmap) {
238 double max_memory=0.0;
239 for (const auto& [memkey,memval] : memmap) {
240 if (memval.memory_GB>max_memory) max_memory=memval.memory_GB;
241 }
242 return max_memory;
243 }
244
245 /// return the minimum memory usage over all hosts
246 static double min_memory(const MemInfoMapT& memmap) {
247 double min_memory=std::numeric_limits<double>::max();
248 for (const auto& [memkey,memval] : memmap) {
249 if (memval.memory_GB<min_memory) min_memory=memval.memory_GB;
250 }
251 return min_memory;
252 }
253
254 /// @param[in] msg a message to print before the memory map
255 /// @param[in] world used only for clean printing
256 void print_memory_map(World& world, std::string msg="") {
257 reduce_map(world);
258 world.gop.fence();
259 if (world.rank()==0) {
260 print("final memory map:",msg);
261 print("hostname world rank DIM #funcs memory_GB");
262 }
263 constexpr std::size_t bufsize=256;
264 char line[bufsize];
265
266 // print all information
267 world.gop.fence();
268 // turn into vector
269 std::vector<std::pair<MemKey,MemInfo>> memory_vec(world_memory_map.begin(),world_memory_map.end());
270 std::sort(memory_vec.begin(),memory_vec.end(),[](const std::pair<MemKey,MemInfo>& a, const std::pair<MemKey,MemInfo>& b){return a.first<b.first;});
271 for (const auto& [memkey,memval] : memory_vec) {
272 snprintf(line, bufsize, "%20s %12lu %5lu %5lu %5lu %e", memkey.hostname.c_str(), memkey.world_id, memkey.rank, memkey.DIM, memval.num_functions, memval.memory_GB);
273 print(std::string(line));
274 }
275 snprintf(line, bufsize, "%20s %e", "all hosts", total_memory(world_memory_map));
276 world.gop.fence();
277
278
279 // print memory on each host
280 auto mem_per_host_and_rank=memory_per_host_and_rank(world);
281 auto host_to_nrank_and_rss=host_to_nrank_and_rss_map(world);
282 if (world.rank()==0) {
283 print("memory per host");
284 auto info=memory_per_host_all_ranks(mem_per_host_and_rank);
285 print("hostname memory_GB nrank(universe) rss_GB/host");
286 // print("hostname memory_GB");
287 for (const auto& [hostname,memory] : info) {
288 snprintf(line, bufsize, "%20s %e %d %e", hostname.c_str(), memory,
289 host_to_nrank_and_rss[hostname].first, host_to_nrank_and_rss[hostname].second);
290 print(std::string(line));
291 }
292 }
293 if (world.rank()==0) {
294 auto info=memory_per_host_all_ranks(mem_per_host_and_rank);
295 double total_mem=total_memory(world_memory_map);
296 double total_rss=0.0;
297 for (auto& [hostname,memory] : info) {
298 total_rss+=host_to_nrank_and_rss[hostname].second;
299 }
300 std::string word="all hosts";
301 snprintf(line, bufsize, "%20s %e %d %e",
302 word.c_str(), total_mem, world.size(), total_rss);
303 print(std::string(line));
304 }
305
306 }
307
308 };
309}
310
311#endif //MEMORY_MEASUREMENT_H
FunctionImpl holds all Function state to facilitate shallow copy semantics.
Definition funcimpl.h:1043
measure the memory usage of all FunctionImpl objects of all worlds
Definition memory_measurement.h:25
static std::string get_hostname()
get the hostname of this machine, rank-local
Definition memory_measurement.h:55
const FunctionImpl< T, NDIM > * cast_to_funcimpl_ptr(const uniqueidT obj_id)
Definition memory_measurement.h:106
static double min_memory(const MemInfoMapT &memmap)
return the minimum memory usage over all hosts
Definition memory_measurement.h:246
static double total_memory(const MemInfoMapT &memmap)
return the total memory usage over all hosts
Definition memory_measurement.h:228
std::vector< std::pair< std::string, double > > memory_per_host_all_ranks(const std::vector< std::pair< std::pair< std::string, long >, double > > &mem_per_host_and_rank) const
accumulate the memory usage of all objects of all worlds over all ranks per host
Definition memory_measurement.h:215
void print_memory_map(World &world, std::string msg="")
Definition memory_measurement.h:256
std::map< MemKey, MemInfo > MemInfoMapT
Definition memory_measurement.h:101
MemInfoMapT world_memory_map
keeps track of the memory usage of all objects of one or many worlds on this rank
Definition memory_measurement.h:115
static void release_free_memory()
Definition memory_measurement.h:43
void reduce_map(World &universe)
gather all information of the map on rank 0 of the universe
Definition memory_measurement.h:167
friend bool operator<(const MemKey &lhs, const MemKey &other)
Definition memory_measurement.h:83
static std::map< MemKey, MemInfo > measure_and_print(World &world)
measure the memory usage of all objects of all worlds
Definition memory_measurement.h:32
void clear_map()
reset the memory map
Definition memory_measurement.h:162
void search_world(World &world)
Definition memory_measurement.h:133
void add_memory_to_map(const FunctionImpl< T, NDIM > &f)
Definition memory_measurement.h:119
static std::map< std::string, std::pair< int, double > > host_to_nrank_and_rss_map(World &universe)
given the hostname, return number of ranks and total rss on that node
Definition memory_measurement.h:181
static double max_memory(const MemInfoMapT &memmap)
return the maximum memory usage over all hosts
Definition memory_measurement.h:237
void search_all_worlds()
Definition memory_measurement.h:150
bool debug
Definition memory_measurement.h:116
std::vector< std::pair< std::pair< std::string, long >, double > > memory_per_host_and_rank(World &world) const
accumulate the memory usage of all objects of all worlds for this rank per host
Definition memory_measurement.h:198
void fence(bool debug=false)
Synchronizes all processes in communicator AND globally ensures no pending AM or tasks.
Definition worldgop.cc:177
std::vector< T > concat0(const std::vector< T > &v, size_t bufsz=1024 *1024)
Concatenate an STL vector of serializable stuff onto node 0.
Definition worldgop.h:973
Implements most parts of a globally addressable object (via unique ID).
Definition world_object.h:491
A parallel world class.
Definition world.h:134
static World & get_default()
Default World object accessor.
Definition world.h:269
static World * world_from_id(std::uint64_t id)
Convert a World ID to a World pointer.
Definition world.h:516
std::vector< uniqueidT > get_object_ids() const
Returns a vector of all unique IDs in this World.
Definition world.h:492
ProcessID rank() const
Returns the process rank in this World (same as MPI_Comm_rank()).
Definition world.h:344
static std::vector< unsigned long > get_world_ids()
return a vector containing all world ids
Definition world.h:500
ProcessID size() const
Returns the number of processes in this World (same as MPI_Comm_size()).
Definition world.h:354
WorldGopInterface & gop
Global operations.
Definition world.h:216
static bool exists(World *world)
Check if the World exists in the registry.
Definition world.h:258
std::optional< T * > ptr_from_id(uniqueidT id) const
Look up a local pointer from a world-wide unique ID.
Definition world.h:440
Class for unique global IDs.
Definition uniqueid.h:53
unsigned long get_world_id() const
Access the World ID.
Definition uniqueid.h:90
const std::size_t bufsize
Definition derivatives.cc:16
#define MADNESS_EXCEPTION(msg, value)
Macro for throwing a MADNESS exception.
Definition madness_exception.h:119
Main include file for MADNESS and defines Function interface.
Runtime details on the configuration and version of MADNESS.
Definition madness.h:69
Namespace for all elements and tools of MADNESS.
Definition DFConvergence.h:9
NDIM & f
Definition mra.h:2817
std::map< long, std::pair< std::string, double > > rank_to_host_and_rss_map(World &universe)
return a mapping rank to hostname, return value on rank 0 only
Definition ranks_and_hosts.cpp:44
void print(const T &t, Ts &&... ts)
Print items to std::cout (items separated by spaces) and terminate with a new line.
Definition print.h:232
static const double b
Definition nonlinschro.cc:119
static const double a
Definition nonlinschro.cc:118
Definition memory_measurement.h:90
long num_functions
Definition memory_measurement.h:93
void serialize(Archive &ar) const
Definition memory_measurement.h:96
double memory_GB
Definition memory_measurement.h:94
MemInfo(const MemInfo &other)=default
Definition memory_measurement.h:62
MemKey(World &world)
Definition memory_measurement.h:68
unsigned long rank
Definition memory_measurement.h:64
MemKey(const MemKey &other)=default
std::size_t DIM
Definition memory_measurement.h:66
void serialize(Archive &ar) const
Definition memory_measurement.h:79
MemKey(const FunctionImpl< T, NDIM > &fimpl)
Definition memory_measurement.h:73
unsigned long world_id
Definition memory_measurement.h:63
std::string hostname
Definition memory_measurement.h:65
constexpr std::size_t NDIM
Definition testgconv.cc:54