GADGET-4
system.cc
Go to the documentation of this file.
1 /*******************************************************************************
2  * \copyright This file is part of the GADGET4 N-body/SPH code developed
3  * \copyright by Volker Springel. Copyright (C) 2014-2020 by Volker Springel
4  * \copyright (vspringel@mpa-garching.mpg.de) and all contributing authors.
5  *******************************************************************************/
6 
12 #include "gadgetconfig.h"
13 
14 #include <gsl/gsl_rng.h>
15 #include <math.h>
16 #include <mpi.h>
17 #include <signal.h>
18 #include <stdarg.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <strings.h>
23 #include <sys/resource.h>
24 #include <sys/statvfs.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <time.h>
28 #include <unistd.h>
29 
30 #include "../data/allvars.h"
31 #include "../data/dtypes.h"
32 #include "../data/mymalloc.h"
33 #include "../io/io.h"
34 #include "../logs/logs.h"
35 #include "../main/main.h"
36 #include "../main/simulation.h"
37 #include "../mpi_utils/mpi_utils.h"
38 #include "../system/system.h"
39 
40 gsl_rng *random_generator;
42 void init_rng(int thistask)
43 {
44  random_generator = gsl_rng_alloc(gsl_rng_ranlxd1);
45 
46  gsl_rng_set(random_generator, 42 + thistask); /* start-up seed, choose different on each rank */
47 }
48 
49 double get_random_number(void) { return gsl_rng_uniform(random_generator); }
50 
51 void subdivide_evenly(long long N, int pieces, int index_bin, long long *first, int *count)
52 {
53  if(N / pieces > INT_MAX)
54  Terminate("overflow");
55 
56  int nbase = N / pieces;
57  int additional = N % pieces;
58  *first = index_bin * ((long long)nbase) + ((index_bin < additional) ? index_bin : additional);
59  *count = nbase + (index_bin < additional);
60 }
61 
62 void subdivide_evenly(int N, int pieces, int index_bin, int *first, int *count)
63 {
64  int nbase = N / pieces;
65  int additional = N % pieces;
66  *first = index_bin * nbase + ((index_bin < additional) ? index_bin : additional);
67  *count = nbase + (index_bin < additional);
68 }
69 
70 void subdivide_evenly_get_bin(int N, int pieces, int index, int *bin)
71 {
72  int nbase = N / pieces;
73  int additional = N % pieces;
74 
75  if(index < additional * (nbase + 1))
76  *bin = index / (nbase + 1);
77  else
78  *bin = (index - additional) / nbase;
79 }
80 
81 void permutate_chunks_in_list(int ncount, int *list)
82 {
83 #define WALK_N_PIECES 32
84 #define WALK_N_SIZE 500
86  int nchunk = 1;
87  int nchunksize = ncount;
89  if(ncount > WALK_N_PIECES * WALK_N_SIZE)
90  {
91  nchunk = WALK_N_PIECES;
92  nchunksize = WALK_N_SIZE;
93  }
94 
95  int currentchunk = 0;
97  int *chunked_TargetList = (int *)Mem.mymalloc("chunked_TargetList", ncount * sizeof(int));
98  for(int n = 0, nextparticle = 0; n < ncount; n++)
99  {
100  int i = nextparticle;
101 
102  chunked_TargetList[n] = list[i];
103  if(i < ncount)
104  {
105  nextparticle++;
106 
107  if((nextparticle % nchunksize) == 0)
108  nextparticle += (nchunk - 1) * nchunksize;
109 
110  if(nextparticle >= ncount)
111  {
112  currentchunk++;
113  if(currentchunk < nchunk)
114  nextparticle = currentchunk * nchunksize;
115  }
116  }
117  }
118 
119  for(int n = 0; n < ncount; n++)
120  list[n] = chunked_TargetList[n];
121 
122  Mem.myfree(chunked_TargetList);
123 }
124 
125 void myflush(FILE *fstream)
126 {
127 #ifdef REDUCE_FLUSH
128  /* do nothing */
129  (void)fstream;
130 #else
131  fflush(fstream);
132 #endif
133 }
134 
135 #ifdef DEBUG
136 #include <fenv.h>
138 {
139 #if defined(DEBUG_ENABLE_FPU_EXCEPTIONS) && defined(__linux__)
140  /* enable floating point exceptions */
141 
142  extern int feenableexcept(int __excepts);
143  feenableexcept(FE_DIVBYZERO | FE_INVALID);
144 
145  /* Note: FPU exceptions appear not to work properly
146  * when the Intel C-Compiler for Linux is used
147  */
148 #endif
149 
150  /* set core-dump size to infinity */
151  rlimit rlim;
152  getrlimit(RLIMIT_CORE, &rlim);
153  rlim.rlim_cur = RLIM_INFINITY;
154  setrlimit(RLIMIT_CORE, &rlim);
155 
156  /* MPICH catches the signales SIGSEGV, SIGBUS, and SIGFPE....
157  * The following statements reset things to the default handlers,
158  * which will generate a core file.
159  */
160  signal(SIGSEGV, SIG_DFL);
161  signal(SIGBUS, SIG_DFL);
162  signal(SIGFPE, SIG_DFL);
163  signal(SIGINT, SIG_DFL);
164 }
165 #endif
166 
167 long long sim::report_comittable_memory(long long *MemTotal, long long *Committed_AS, long long *SwapTotal, long long *SwapFree)
168 {
169  FILE *fd;
170  char buf[1024];
171 
172  if((fd = fopen("/proc/meminfo", "r")))
173  {
174  while(1)
175  {
176  if(fgets(buf, 500, fd) != buf)
177  break;
178 
179  if(bcmp(buf, "MemTotal", 8) == 0)
180  {
181  *MemTotal = atoll(buf + 10);
182  }
183  if(strncmp(buf, "Committed_AS", 12) == 0)
184  {
185  *Committed_AS = atoll(buf + 14);
186  }
187  if(strncmp(buf, "SwapTotal", 9) == 0)
188  {
189  *SwapTotal = atoll(buf + 11);
190  }
191  if(strncmp(buf, "SwapFree", 8) == 0)
192  {
193  *SwapFree = atoll(buf + 10);
194  }
195  }
196  fclose(fd);
197  }
198 
199  return (*MemTotal - *Committed_AS);
200 }
201 
202 // returns kByte
204 {
205  struct statvfs buf;
206 
207  if(statvfs("/dev/shm", &buf) == 0)
208  {
209  return (1024.0 * (uint64_t)buf.f_bsize * ((uint64_t)(buf.f_bavail))) * TO_MBYTE_FAC;
210  }
211  else
212  return 0;
213 }
214 
216 {
217  long long *sizelist, maxsize[7], minsize[7];
218  double avgsize[7];
219  int i, imem, mintask[7], maxtask[7];
220  long long Mem[7];
221  char label[512];
222 
223  Mem[0] = report_comittable_memory(&Mem[1], &Mem[2], &Mem[3], &Mem[4]);
224  Mem[5] = Mem[1] - Mem[0];
225 
227 
228  MemoryOnNode = Mem[1];
229  SharedMemoryOnNode = Mem[6];
230 
231  for(imem = 0; imem < 7; imem++)
232  {
233  sizelist = (long long *)malloc(NTask * sizeof(long long));
234  MPI_Allgather(&Mem[imem], sizeof(long long), MPI_BYTE, sizelist, sizeof(long long), MPI_BYTE, Communicator);
235 
236  for(i = 1, mintask[imem] = 0, maxtask[imem] = 0, maxsize[imem] = minsize[imem] = sizelist[0], avgsize[imem] = sizelist[0];
237  i < NTask; i++)
238  {
239  if(sizelist[i] > maxsize[imem])
240  {
241  maxsize[imem] = sizelist[i];
242  maxtask[imem] = i;
243  }
244  if(sizelist[i] < minsize[imem])
245  {
246  minsize[imem] = sizelist[i];
247  mintask[imem] = i;
248  }
249  avgsize[imem] += sizelist[i];
250  }
251 
252  free(sizelist);
253  }
254 
255  if(ThisTask == 0)
256  {
257  printf(
258  "\n-------------------------------------------------------------------------------------------------------------------------"
259  "\n");
260  for(imem = 0; imem < 7; imem++)
261  {
262  switch(imem)
263  {
264  case 0:
265  sprintf(label, "AvailMem");
266  break;
267  case 1:
268  sprintf(label, "Total Mem");
269  break;
270  case 2:
271  sprintf(label, "Committed_AS");
272  break;
273  case 3:
274  sprintf(label, "SwapTotal");
275  break;
276  case 4:
277  sprintf(label, "SwapFree");
278  break;
279  case 5:
280  sprintf(label, "AllocMem");
281  break;
282  case 6:
283  sprintf(label, "avail /dev/shm");
284  break;
285  }
286  printf("%s:\t Largest = %10.2f Mb (on task=%4d), Smallest = %10.2f Mb (on task=%4d), Average = %10.2f Mb\n", label,
287  maxsize[imem] / (1024.0), maxtask[imem], minsize[imem] / (1024.0), mintask[imem], avgsize[imem] / (1024.0 * NTask));
288  }
289  printf(
290  "-------------------------------------------------------------------------------------------------------------------------"
291  "\n");
292  }
293 
294  char name[MPI_MAX_PROCESSOR_NAME];
295 
296  if(ThisTask == maxtask[2])
297  {
298  int len;
299  MPI_Get_processor_name(name, &len);
300  }
301 
302  MPI_Bcast(name, MPI_MAX_PROCESSOR_NAME, MPI_BYTE, maxtask[2], Communicator);
303 
304  if(ThisTask == 0)
305  {
306  printf("Task=%d has the maximum commited memory and is host: %s\n", ThisTask, name);
307  printf(
308  "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
309  "\n");
310  }
311 
312  fflush(stdout);
313 }
314 
315 /* the following function finds the last significant bit, as in the linux kernel */
316 int my_fls(unsigned int x)
317 {
318  int r = 32;
319 
320  if(!x)
321  return 0;
322  if(!(x & 0xffff0000u))
323  {
324  x <<= 16;
325  r -= 16;
326  }
327  if(!(x & 0xff000000u))
328  {
329  x <<= 8;
330  r -= 8;
331  }
332  if(!(x & 0xf0000000u))
333  {
334  x <<= 4;
335  r -= 4;
336  }
337  if(!(x & 0xc0000000u))
338  {
339  x <<= 2;
340  r -= 2;
341  }
342  if(!(x & 0x80000000u))
343  {
344  x <<= 1;
345  r -= 1;
346  }
347  return r;
348 }
long long MemoryOnNode
Definition: setcomm.h:42
int ThisTask
Definition: setcomm.h:33
int NTask
Definition: setcomm.h:32
MPI_Comm Communicator
Definition: setcomm.h:31
long long SharedMemoryOnNode
Definition: setcomm.h:43
long long report_free_size_in_tmpfs(void)
Definition: system.cc:203
void mpi_report_comittable_memory(void)
Definition: system.cc:215
long long report_comittable_memory(long long *MemTotal, long long *Committed_AS, long long *SwapTotal, long long *SwapFree)
Definition: system.cc:167
#define TO_MBYTE_FAC
Definition: constants.h:59
#define Terminate(...)
Definition: macros.h:19
memory Mem
Definition: main.cc:44
void subdivide_evenly_get_bin(int N, int pieces, int index, int *bin)
Definition: system.cc:70
void permutate_chunks_in_list(int ncount, int *list)
Definition: system.cc:81
gsl_rng * random_generator
Definition: system.cc:40
int my_fls(unsigned int x)
Definition: system.cc:316
void subdivide_evenly(long long N, int pieces, int index_bin, long long *first, int *count)
Definition: system.cc:51
void init_rng(int thistask)
Definition: system.cc:42
#define WALK_N_PIECES
void myflush(FILE *fstream)
Definition: system.cc:125
#define WALK_N_SIZE
double get_random_number(void)
Definition: system.cc:49
void enable_core_dumps_and_fpu_exceptions(void)