MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
Macros | Functions | Variables
slotsmanager.c File Reference
#include <string.h>
#include "slotsmanager.h"
#include "partmanager.h"
#include "utils.h"
Include dependency graph for slotsmanager.c:

Go to the source code of this file.

Macros

#define SLOTS_ENABLED(ptype, sman)   (sman->info[ptype].enabled)
 
#define GARBAGE(i, ptype, pman, sman)   (sman ? BASESLOT_PI(i,ptype, sman)->ReverseLink > pman->MaxPart : pman->Base[i].IsGarbage)
 
#define PART(i, ptype, pman, sman)   (sman ? (void *) BASESLOT_PI(i, ptype, sman) : (void *) &pman->Base[i])
 

Functions

static int slots_gc_base (struct part_manager_type *pman)
 
static int slots_gc_slots (int *compact_slots, struct part_manager_type *pman, struct slots_manager_type *sman)
 
static void slots_connect_new_slot (int i, int pi, int type, struct part_manager_type *pman, struct slots_manager_type *sman)
 
int slots_convert (int parent, int ptype, int placement, struct part_manager_type *pman, struct slots_manager_type *sman)
 
int slots_split_particle (int parent, double childmass, struct part_manager_type *pman)
 
int slots_gc (int *compact_slots, struct part_manager_type *pman, struct slots_manager_type *sman)
 
static int slots_find_next_garbage (int start, int used, int ptype, struct part_manager_type *pman, struct slots_manager_type *sman)
 
static int slots_find_next_nongarbage (int start, int used, int ptype, struct part_manager_type *pman, struct slots_manager_type *sman)
 
static int slots_gc_compact (const int used, int ptype, struct part_manager_type *pman, struct slots_manager_type *sman)
 
static int slot_cmp_reverse_link (const void *b1in, const void *b2in)
 
static int slots_gc_mark (const struct part_manager_type *pman, const struct slots_manager_type *sman)
 
static int slots_gc_sweep (int ptype, struct part_manager_type *pman, struct slots_manager_type *sman)
 
static void slots_gc_collect (int ptype, struct part_manager_type *pman, struct slots_manager_type *sman)
 
static int order_by_type_and_key (const void *a, const void *b)
 
int slots_get_last_garbage (int nfirst, int nlast, int ptype, const struct part_manager_type *pman, const struct slots_manager_type *sman)
 
void slots_gc_sorted (struct part_manager_type *pman, struct slots_manager_type *sman)
 
size_t slots_reserve (int where, int64_t atleast[6], struct slots_manager_type *sman)
 
void slots_init (double increase, struct slots_manager_type *sman)
 
void slots_set_enabled (int ptype, size_t elsize, struct slots_manager_type *sman)
 
void slots_free (struct slots_manager_type *sman)
 
void slots_mark_garbage (int i, struct part_manager_type *pman, struct slots_manager_type *sman)
 
void slots_check_id_consistency (struct part_manager_type *pman, struct slots_manager_type *sman)
 
void slots_setup_topology (struct part_manager_type *pman, int64_t *NLocal, struct slots_manager_type *sman)
 
void slots_setup_id (const struct part_manager_type *pman, struct slots_manager_type *sman)
 

Variables

struct slots_manager_type SlotsManager [1]
 
MPI_Datatype MPI_TYPE_PARTICLE = 0
 
MPI_Datatype MPI_TYPE_PLAN_ENTRY = 0
 
MPI_Datatype MPI_TYPE_SLOT [6] = {0}
 
static struct sph_particle_dataGDB_SphP
 
static struct star_particle_dataGDB_StarP
 
static struct bh_particle_dataGDB_BhP
 

Macro Definition Documentation

◆ GARBAGE

#define GARBAGE (   i,
  ptype,
  pman,
  sman 
)    (sman ? BASESLOT_PI(i,ptype, sman)->ReverseLink > pman->MaxPart : pman->Base[i].IsGarbage)

Definition at line 164 of file slotsmanager.c.

◆ PART

#define PART (   i,
  ptype,
  pman,
  sman 
)    (sman ? (void *) BASESLOT_PI(i, ptype, sman) : (void *) &pman->Base[i])

Definition at line 165 of file slotsmanager.c.

◆ SLOTS_ENABLED

#define SLOTS_ENABLED (   ptype,
  sman 
)    (sman->info[ptype].enabled)

Definition at line 9 of file slotsmanager.c.

Function Documentation

◆ order_by_type_and_key()

static int order_by_type_and_key ( const void *  a,
const void *  b 
)
static

Definition at line 388 of file slotsmanager.c.

389 {
390  const struct particle_data * pa = (const struct particle_data *) a;
391  const struct particle_data * pb = (const struct particle_data *) b;
392 
393  if(pa->IsGarbage && !pb->IsGarbage)
394  return +1;
395  if(!pa->IsGarbage && pb->IsGarbage)
396  return -1;
397  if(pa->Type < pb->Type)
398  return -1;
399  if(pa->Type > pb->Type)
400  return +1;
401  if(pa->Key < pb->Key)
402  return -1;
403  if(pa->Key > pb->Key)
404  return +1;
405 
406  return 0;
407 }
peano_t Key
Definition: partmanager.h:66
unsigned int Type
Definition: partmanager.h:17
unsigned int IsGarbage
Definition: partmanager.h:19

References particle_data::IsGarbage, particle_data::Key, and particle_data::Type.

Referenced by slots_gc_sorted().

Here is the caller graph for this function:

◆ slot_cmp_reverse_link()

static int slot_cmp_reverse_link ( const void *  b1in,
const void *  b2in 
)
static

Definition at line 255 of file slotsmanager.c.

255  {
256  const struct particle_data_ext * b1 = (struct particle_data_ext *) b1in;
257  const struct particle_data_ext * b2 = (struct particle_data_ext *) b2in;
258  return (b1->ReverseLink > b2->ReverseLink) - (b1->ReverseLink < b2->ReverseLink);
259 }

References particle_data_ext::ReverseLink.

Referenced by slots_gc_sorted().

Here is the caller graph for this function:

◆ slots_check_id_consistency()

void slots_check_id_consistency ( struct part_manager_type pman,
struct slots_manager_type sman 
)

Definition at line 587 of file slotsmanager.c.

588 {
589  int64_t used[6] = {0};
590  int64_t i;
591 
592  for(i = 0; i < pman->NumPart; i++) {
593  int type = pman->Base[i].Type;
594  if(pman->Base[i].IsGarbage)
595  continue;
596  struct slot_info info = sman->info[type];
597  if(!info.enabled)
598  continue;
599 
600  int PI = pman->Base[i].PI;
601  if(PI >= info.size) {
602  endrun(1, "slot PI consistency failed2\n");
603  }
604  if(BASESLOT_PI(PI, type, sman)->ID != pman->Base[i].ID) {
605  endrun(1, "slot id consistency failed2: i=%d PI=%d type = %d P.ID = %ld SLOT.ID=%ld\n",i, PI, pman->Base[i].Type, pman->Base[i].ID, BASESLOT_PI(PI, type, sman)->ID);
606  }
607  used[type] ++;
608  }
609  int64_t NTotal[6];
610 
611  MPI_Allreduce(used, NTotal, 6, MPI_INT64, MPI_SUM, MPI_COMM_WORLD);
612 
613  int ptype;
614  for(ptype = 0; ptype < 6; ptype ++) {
615  if(NTotal[ptype] > 0) {
616  /* Watch out: we print per rank here, but the condition must be global*/
617  message(0, "Task 0: GC: Used slots for type %d is %ld\n", ptype, used[ptype]);
618  }
619  }
620 }
void message(int where, const char *fmt,...)
Definition: endrun.c:175
void endrun(int where, const char *fmt,...)
Definition: endrun.c:147
#define BASESLOT_PI(PI, ptype, sman)
Definition: slotsmanager.h:132
struct particle_data * Base
Definition: partmanager.h:74
MyIDType ID
Definition: partmanager.h:38
int64_t size
Definition: slotsmanager.h:12
struct slot_info info[6]
Definition: slotsmanager.h:112
#define MPI_INT64
Definition: system.h:12
static enum TransferType ptype
Definition: zeldovich.c:146

References part_manager_type::Base, BASESLOT_PI, slot_info::enabled, endrun(), particle_data::ID, slots_manager_type::info, particle_data::IsGarbage, message(), MPI_INT64, part_manager_type::NumPart, particle_data::PI, ptype, slot_info::size, and particle_data::Type.

Referenced by domain_exchange_once(), slots_gc_slots(), slots_gc_sorted(), test_exchange(), test_exchange_uneven(), test_exchange_with_garbage(), test_exchange_zero_slots(), test_slots_gc(), and test_slots_gc_sorted().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ slots_connect_new_slot()

static void slots_connect_new_slot ( int  i,
int  pi,
int  type,
struct part_manager_type pman,
struct slots_manager_type sman 
)
static

Definition at line 29 of file slotsmanager.c.

30 {
31  /* Fill slot with a meaningless
32  * poison value ('e') so we will recognise
33  * if it is uninitialised.*/
34  memset(BASESLOT_PI(pi, type, sman), 101, sman->info[type].elsize);
35  /* book keeping ID: debug only */
36  BASESLOT_PI(pi, type, sman)->ID = pman->Base[i].ID;
37  /*Update the particle's pointer*/
38  pman->Base[i].PI = pi;
39 }
size_t elsize
Definition: slotsmanager.h:13

References part_manager_type::Base, BASESLOT_PI, slot_info::elsize, particle_data::ID, slots_manager_type::info, and particle_data::PI.

Referenced by slots_convert().

Here is the caller graph for this function:

◆ slots_convert()

int slots_convert ( int  parent,
int  ptype,
int  placement,
struct part_manager_type pman,
struct slots_manager_type sman 
)

Definition at line 60 of file slotsmanager.c.

61 {
62  /*Explicitly mark old slot as garbage*/
63  int oldtype = pman->Base[parent].Type;
64  int oldPI = pman->Base[parent].PI;
65  if(oldPI >= 0 && SLOTS_ENABLED(oldtype, sman))
66  BASESLOT_PI(oldPI, oldtype, sman)->ReverseLink = pman->MaxPart + 100;
67 
68  /*Make a new slot*/
69  if(SLOTS_ENABLED(ptype, sman)) {
70  int newPI = placement;
71  /* if enabled, alloc a new Slot for secondary data */
72  if(placement < 0)
73  newPI = atomic_fetch_and_add_64(&sman->info[ptype].size, 1);
74 
75  /* There is no way clearly to safely grow the slots during this, because the memory may be deep in the heap.*/
76  if(newPI >= sman->info[ptype].maxsize) {
77  endrun(1, "Tried to use non-allocated slot %d (> %d)\n", newPI, sman->info[ptype].maxsize);
78  }
79  slots_connect_new_slot(parent, newPI, ptype, pman, sman);
80  }
81  /*Type changed after slot updated*/
82  pman->Base[parent].Type = ptype;
83  return parent;
84 }
#define SLOTS_ENABLED(ptype, sman)
Definition: slotsmanager.c:9
static void slots_connect_new_slot(int i, int pi, int type, struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:29
int64_t maxsize
Definition: slotsmanager.h:11
static int64_t atomic_fetch_and_add_64(int64_t *ptr, int64_t value)
Definition: system.h:68

References atomic_fetch_and_add_64(), part_manager_type::Base, BASESLOT_PI, endrun(), slots_manager_type::info, part_manager_type::MaxPart, slot_info::maxsize, particle_data::PI, ptype, slot_info::size, slots_connect_new_slot(), SLOTS_ENABLED, and particle_data::Type.

Referenced by blackhole_make_one(), make_particle_star(), test_slots_convert(), and test_slots_fork().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ slots_find_next_garbage()

static int slots_find_next_garbage ( int  start,
int  used,
int  ptype,
struct part_manager_type pman,
struct slots_manager_type sman 
)
static

Definition at line 169 of file slotsmanager.c.

170 {
171  int i, nextgc = used;
172  /*Find another garbage particle*/
173  for(i = start; i < used; i++)
174  if(GARBAGE(i, ptype, pman, sman)) {
175  nextgc = i;
176  break;
177  }
178  return nextgc;
179 }
#define GARBAGE(i, ptype, pman, sman)
Definition: slotsmanager.c:164

References GARBAGE, and ptype.

Referenced by slots_gc_compact().

Here is the caller graph for this function:

◆ slots_find_next_nongarbage()

static int slots_find_next_nongarbage ( int  start,
int  used,
int  ptype,
struct part_manager_type pman,
struct slots_manager_type sman 
)
static

Definition at line 183 of file slotsmanager.c.

184 {
185  int i, nextgc = used;
186  /*Find another garbage particle*/
187  for(i = start; i < used; i++)
188  if(!GARBAGE(i, ptype, pman, sman)) {
189  nextgc = i;
190  break;
191  }
192  return nextgc;
193 }

References GARBAGE, and ptype.

Referenced by slots_gc_compact().

Here is the caller graph for this function:

◆ slots_free()

void slots_free ( struct slots_manager_type sman)

Definition at line 570 of file slotsmanager.c.

571 {
572  myfree(sman->Base);
573 }
#define myfree(x)
Definition: mymalloc.h:19

References slots_manager_type::Base, and myfree.

Referenced by teardown_particles().

Here is the caller graph for this function:

◆ slots_gc()

int slots_gc ( int *  compact_slots,
struct part_manager_type pman,
struct slots_manager_type sman 
)

Definition at line 145 of file slotsmanager.c.

146 {
147  /* tree is invalidated if the sequence on P is reordered; */
148 
149  int tree_invalid = 0;
150 
151  /* TODO: in principle we can track this change and modify the tree nodes;
152  * But doing so requires cleaning up the TimeBin link lists, and the tree
153  * link lists first. likely worth it, since GC happens only in domain decompose
154  * and snapshot IO, both take far more time than rebuilding the tree. */
155  tree_invalid |= slots_gc_base(pman);
156  tree_invalid |= slots_gc_slots(compact_slots, pman, sman);
157 
158  MPI_Allreduce(MPI_IN_PLACE, &tree_invalid, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
159 
160  return tree_invalid;
161 }
static int slots_gc_base(struct part_manager_type *pman)
Definition: slotsmanager.c:234
static int slots_gc_slots(int *compact_slots, struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:345

References slots_gc_base(), and slots_gc_slots().

Referenced by domain_exchange_once(), run(), test_slots_gc(), and test_slots_zero().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ slots_gc_base()

static int slots_gc_base ( struct part_manager_type pman)
static

Definition at line 234 of file slotsmanager.c.

235 {
236  int64_t total0, total;
237 
238  MPI_Allreduce(&pman->NumPart, &total0, 1, MPI_INT64, MPI_SUM, MPI_COMM_WORLD);
239 
240  /*Compactify the P array: this invalidates the ReverseLink, so
241  * that ReverseLink is valid only within gc.*/
242  int64_t ngc = slots_gc_compact(pman->NumPart, -1, pman, NULL);
243 
244  pman->NumPart -= ngc;
245 
246  MPI_Allreduce(&pman->NumPart, &total, 1, MPI_INT64, MPI_SUM, MPI_COMM_WORLD);
247 
248  if(total != total0) {
249  message(0, "GC : Reducing Particle slots from %ld to %ld\n", total0, total);
250  return 1;
251  }
252  return 0;
253 }
static int slots_gc_compact(const int used, int ptype, struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:197

References message(), MPI_INT64, part_manager_type::NumPart, and slots_gc_compact().

Referenced by slots_gc().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ slots_gc_collect()

static void slots_gc_collect ( int  ptype,
struct part_manager_type pman,
struct slots_manager_type sman 
)
static

Definition at line 322 of file slotsmanager.c.

323 {
324  int64_t i;
325  if(!SLOTS_ENABLED(ptype, sman)) return;
326 
327  /* Now update the link in BhP */
328 #pragma omp parallel for
329  for(i = 0;
330  i < sman->info[ptype].size;
331  i ++) {
332 
333 #ifdef DEBUG
334  if(BASESLOT_PI(i, ptype, sman)->ReverseLink >= pman->MaxPart) {
335  endrun(1, "Shall not happen: i=%d ptype = %d\n", i,ptype);
336  }
337 #endif
338 
339  pman->Base[BASESLOT_PI(i, ptype, sman)->ReverseLink].PI = i;
340  }
341 }

References part_manager_type::Base, BASESLOT_PI, endrun(), slots_manager_type::info, part_manager_type::MaxPart, particle_data::PI, ptype, particle_data_ext::ReverseLink, slot_info::size, and SLOTS_ENABLED.

Referenced by slots_gc_slots(), and slots_gc_sorted().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ slots_gc_compact()

static int slots_gc_compact ( const int  used,
int  ptype,
struct part_manager_type pman,
struct slots_manager_type sman 
)
static

Definition at line 197 of file slotsmanager.c.

198 {
199  /*Find first garbage particle: can't use bisection here as not sorted.*/
200  int nextgc = slots_find_next_garbage(0, used, ptype, pman, sman);
201  size_t size = sizeof(struct particle_data);
202  if(sman)
203  size = sman->info[ptype].elsize;
204  int ngc = 0;
205  /*Note each particle is tested exactly once*/
206  while(nextgc < used) {
207  /*Now lastgc contains a garbage*/
208  int lastgc = nextgc;
209  /*Find a non-garbage after it*/
210  int src = slots_find_next_nongarbage(lastgc+1, used, ptype, pman, sman);
211  /*If no more non-garbage particles, don't bother copying, just add a skip*/
212  if(src == used) {
213  ngc += src - lastgc;
214  break;
215  }
216  /*Destination is shifted already*/
217  int dest = lastgc - ngc;
218 
219  /*Find another garbage particle*/
220  nextgc = slots_find_next_garbage(src + 1, used, ptype, pman, sman);
221 
222  /*Add number of particles we skipped*/
223  ngc += src - lastgc;
224  int nmove = nextgc - src +1;
225 // message(1,"i = %d, PI = %d-> %d, nm=%d\n",i, src, dest, nmove);
226  memmove(PART(dest, ptype, pman, sman),PART(src, ptype, pman, sman),nmove*size);
227  }
228  if(ngc > used)
229  endrun(1, "ngc = %d > used = %d!\n", ngc, used);
230  return ngc;
231 }
static int slots_find_next_garbage(int start, int used, int ptype, struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:169
#define PART(i, ptype, pman, sman)
Definition: slotsmanager.c:165
static int slots_find_next_nongarbage(int start, int used, int ptype, struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:183

References slot_info::elsize, endrun(), slots_manager_type::info, PART, ptype, slots_find_next_garbage(), and slots_find_next_nongarbage().

Referenced by slots_gc_base(), and slots_gc_sweep().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ slots_gc_mark()

static int slots_gc_mark ( const struct part_manager_type pman,
const struct slots_manager_type sman 
)
static

Definition at line 262 of file slotsmanager.c.

263 {
264  int64_t i;
265  if(!(sman->info[0].enabled ||
266  sman->info[1].enabled ||
267  sman->info[2].enabled ||
268  sman->info[3].enabled ||
269  sman->info[4].enabled ||
270  sman->info[5].enabled))
271  return 0;
272 
273 #ifdef DEBUG
274  int ptype;
275  /*Initially set all reverse links to an obviously invalid value*/
276  for(ptype = 0; ptype < 6; ptype++)
277  {
278  struct slot_info info = sman->info[ptype];
279  if(!info.enabled)
280  continue;
281  #pragma omp parallel for
282  for(i = 0; i < info.size; i++) {
283  struct particle_data_ext * sdata = (struct particle_data_ext * )(info.ptr + info.elsize * i);
284  sdata->ReverseLink = pman->MaxPart + 100;
285  }
286  }
287 #endif
288 
289 #pragma omp parallel for
290  for(i = 0; i < pman->NumPart; i++) {
291  struct slot_info info = sman->info[pman->Base[i].Type];
292  if(!info.enabled)
293  continue;
294  int sind = pman->Base[i].PI;
295  if(sind >= info.size || sind < 0)
296  endrun(1, "Particle %d, type %d has PI index %d beyond max slot size %d.\n", i, pman->Base[i].Type, sind, info.size);
297  struct particle_data_ext * sdata = (struct particle_data_ext * )(info.ptr + info.elsize * sind);
298  sdata->ReverseLink = i;
299  /* Make the PI of garbage particles invalid*/
300  if(pman->Base[i].IsGarbage)
301  sdata->ReverseLink = pman->MaxPart + 100;
302  }
303  return 0;
304 }
char * ptr
Definition: slotsmanager.h:10

References part_manager_type::Base, slot_info::elsize, slot_info::enabled, endrun(), slots_manager_type::info, particle_data::IsGarbage, part_manager_type::MaxPart, part_manager_type::NumPart, particle_data::PI, slot_info::ptr, ptype, particle_data_ext::ReverseLink, slot_info::size, and particle_data::Type.

Referenced by slots_gc_slots(), and slots_gc_sorted().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ slots_gc_slots()

static int slots_gc_slots ( int *  compact_slots,
struct part_manager_type pman,
struct slots_manager_type sman 
)
static

Definition at line 345 of file slotsmanager.c.

346 {
347  int ptype;
348 
349  int64_t total0[6];
350  int64_t total1[6];
351 
352  int disabled = 1;
353  for(ptype = 0; ptype < 6; ptype ++) {
354  MPI_Allreduce(&sman->info[ptype].size, &total0[ptype], 1, MPI_INT64, MPI_SUM, MPI_COMM_WORLD);
355  if(compact_slots[ptype])
356  disabled = 0;
357  }
358 
359 #ifdef DEBUG
360  slots_check_id_consistency(pman, sman);
361 #endif
362 
363  if(!disabled) {
364  slots_gc_mark(pman, sman);
365 
366  for(ptype = 0; ptype < 6; ptype++) {
367  if(!compact_slots[ptype])
368  continue;
369  slots_gc_sweep(ptype, pman, sman);
370  slots_gc_collect(ptype, pman, sman);
371  }
372  }
373 #ifdef DEBUG
374  slots_check_id_consistency(pman, sman);
375 #endif
376  for(ptype = 0; ptype < 6; ptype ++) {
377  MPI_Allreduce(&sman->info[ptype].size, &total1[ptype], 1, MPI_INT64, MPI_SUM, MPI_COMM_WORLD);
378 
379  if(total1[ptype] != total0[ptype])
380  message(0, "GC: Reducing number of slots for %d from %ld to %ld\n", ptype, total0[ptype], total1[ptype]);
381  }
382 
383  /* slot gc never invalidates the tree */
384  return 0;
385 }
static int slots_gc_mark(const struct part_manager_type *pman, const struct slots_manager_type *sman)
Definition: slotsmanager.c:262
static void slots_gc_collect(int ptype, struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:322
static int slots_gc_sweep(int ptype, struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:308
void slots_check_id_consistency(struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:587

References slots_manager_type::info, message(), MPI_INT64, ptype, slot_info::size, slots_check_id_consistency(), slots_gc_collect(), slots_gc_mark(), and slots_gc_sweep().

Referenced by slots_gc().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ slots_gc_sorted()

void slots_gc_sorted ( struct part_manager_type pman,
struct slots_manager_type sman 
)

Definition at line 442 of file slotsmanager.c.

443 {
444  int ptype;
445  /* Resort the particles such that those of the same type and key are close by.
446  * The locality is broken by the exchange. */
447  qsort_openmp(pman->Base, pman->NumPart, sizeof(struct particle_data), order_by_type_and_key);
448 
449  /*Remove garbage particles*/
450  pman->NumPart = slots_get_last_garbage(0, pman->NumPart -1 , -1, pman, NULL);
451 
452  /*Set up ReverseLink*/
453  slots_gc_mark(pman, sman);
454 
455  for(ptype = 0; ptype < 6; ptype++) {
456  if(!SLOTS_ENABLED(ptype, sman))
457  continue;
458  /* sort the used ones
459  * by their location in the P array */
460  qsort_openmp(sman->info[ptype].ptr,
461  sman->info[ptype].size,
462  sman->info[ptype].elsize,
464 
465  /*Reduce slots used*/
466  SlotsManager->info[ptype].size = slots_get_last_garbage(0, sman->info[ptype].size-1, ptype, pman, sman);
467  slots_gc_collect(ptype, pman, sman);
468  }
469 #ifdef DEBUG
470  slots_check_id_consistency(pman, sman);
471 #endif
472 }
struct slots_manager_type SlotsManager[1]
Definition: slotsmanager.c:7
static int order_by_type_and_key(const void *a, const void *b)
Definition: slotsmanager.c:388
int slots_get_last_garbage(int nfirst, int nlast, int ptype, const struct part_manager_type *pman, const struct slots_manager_type *sman)
Definition: slotsmanager.c:414
static int slot_cmp_reverse_link(const void *b1in, const void *b2in)
Definition: slotsmanager.c:255
#define qsort_openmp
Definition: test_exchange.c:14

References part_manager_type::Base, slot_info::elsize, slots_manager_type::info, part_manager_type::NumPart, order_by_type_and_key(), slot_info::ptr, ptype, qsort_openmp, slot_info::size, slot_cmp_reverse_link(), slots_check_id_consistency(), SLOTS_ENABLED, slots_gc_collect(), slots_gc_mark(), slots_get_last_garbage(), and SlotsManager.

Referenced by domain_decompose_full(), test_slots_gc_sorted(), and test_slots_zero().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ slots_gc_sweep()

static int slots_gc_sweep ( int  ptype,
struct part_manager_type pman,
struct slots_manager_type sman 
)
static

Definition at line 308 of file slotsmanager.c.

309 {
310  if(!SLOTS_ENABLED(ptype, sman)) return 0;
311  int64_t used = sman->info[ptype].size;
312 
313  int64_t ngc = slots_gc_compact(used, ptype, pman, sman);
314 
315  sman->info[ptype].size -= ngc;
316 
317  return ngc;
318 }

References slots_manager_type::info, ptype, slot_info::size, SLOTS_ENABLED, and slots_gc_compact().

Referenced by slots_gc_slots().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ slots_get_last_garbage()

int slots_get_last_garbage ( int  nfirst,
int  nlast,
int  ptype,
const struct part_manager_type pman,
const struct slots_manager_type sman 
)

Definition at line 414 of file slotsmanager.c.

415 {
416  /* Enforce that we don't get a negative number for an empty array*/
417  if(nlast < 0)
418  return 0;
419  /* nfirst is always not garbage, nlast is always garbage*/
420  if(GARBAGE(nfirst, ptype, pman, sman))
421  return nfirst;
422  if(!GARBAGE(nlast, ptype, pman, sman))
423  return nlast+1;
424  /*Bisection*/
425  do {
426  int nmid = (nfirst + nlast)/2;
427  if(GARBAGE(nmid, ptype, pman, sman))
428  nlast = nmid;
429  else
430  nfirst = nmid;
431  }
432  while(nlast - nfirst > 1);
433 
434  return nlast;
435 }

References GARBAGE, and ptype.

Referenced by slots_gc_sorted().

Here is the caller graph for this function:

◆ slots_init()

void slots_init ( double  increase,
struct slots_manager_type sman 
)

Definition at line 550 of file slotsmanager.c.

551 {
552  memset(sman, 0, sizeof(sman[0]));
553 
554  MPI_Type_contiguous(sizeof(struct particle_data), MPI_BYTE, &MPI_TYPE_PARTICLE);
555  MPI_Type_commit(&MPI_TYPE_PARTICLE);
556  sman->increase = increase;
557 }
MPI_Datatype MPI_TYPE_PARTICLE
Definition: slotsmanager.c:11

References slots_manager_type::increase, and MPI_TYPE_PARTICLE.

Referenced by begrun(), setup_density(), and setup_particles().

Here is the caller graph for this function:

◆ slots_mark_garbage()

void slots_mark_garbage ( int  i,
struct part_manager_type pman,
struct slots_manager_type sman 
)

Definition at line 577 of file slotsmanager.c.

578 {
579  pman->Base[i].IsGarbage = 1;
580  int type = pman->Base[i].Type;
581  if(SLOTS_ENABLED(type, sman)) {
582  BASESLOT_PI(pman->Base[i].PI, type, sman)->ReverseLink = pman->MaxPart + 100;
583  }
584 }

References part_manager_type::Base, BASESLOT_PI, particle_data::IsGarbage, part_manager_type::MaxPart, particle_data::PI, SLOTS_ENABLED, and particle_data::Type.

Referenced by blackhole_feedback_ngbiter(), domain_exchange_once(), test_exchange_with_garbage(), test_slots_gc(), test_slots_gc_sorted(), and test_slots_zero().

Here is the caller graph for this function:

◆ slots_reserve()

size_t slots_reserve ( int  where,
int64_t  atleast[6],
struct slots_manager_type sman 
)

Definition at line 475 of file slotsmanager.c.

476 {
477  int64_t newMaxSlots[6];
478  int ptype;
479  int good = 1;
480 
481  if(sman->Base == NULL) {
482  sman->Base = (char*) mymalloc("SlotsBase", sizeof(struct sph_particle_data));
483  /* This is so the ptr is never null! Avoid undefined behaviour. */
484  for(ptype = 5; ptype >= 0; ptype--) {
485  sman->info[ptype].ptr = sman->Base;
486  }
487  }
488 
489  int64_t add = sman->increase;
490  if (add < 8192) add = 8192;
491 
492  /* FIXME: allow shrinking; need to tweak the memmove later. */
493  for(ptype = 0; ptype < 6; ptype ++) {
494  newMaxSlots[ptype] = sman->info[ptype].maxsize;
495  if(!SLOTS_ENABLED(ptype, sman)) continue;
496  /* if current empty slots is less than half of add, need to grow */
497  if (newMaxSlots[ptype] <= atleast[ptype] + add / 2) {
498  newMaxSlots[ptype] = atleast[ptype] + add;
499  good = 0;
500  }
501  }
502 
503  size_t total_bytes = 0;
504  size_t offsets[6];
505  size_t bytes[6] = {0};
506 
507  for(ptype = 0; ptype < 6; ptype++) {
508  offsets[ptype] = total_bytes;
509  bytes[ptype] = sman->info[ptype].elsize * newMaxSlots[ptype];
510  total_bytes += bytes[ptype];
511  }
512  /* no need to grow, already have enough */
513  if (good) {
514  return total_bytes;
515  }
516  char * newSlotsBase = (char *) myrealloc(sman->Base, total_bytes);
517 
518  /* If we are using VALGRIND the allocator is system malloc, and so realloc may move the base pointer.
519  * Thus we need to also move the slots pointers before doing the memmove. If we are using our own
520  * memory allocator the base address never moves, so this is unnecessary (but we do it anyway).*/
521  for(ptype = 0; ptype < 6; ptype++) {
522  sman->info[ptype].ptr = sman->info[ptype].ptr - sman->Base + newSlotsBase;
523  }
524 
525  message(where, "SLOTS: Reserved %g MB for %ld sph, %ld stars and %ld BHs (disabled: %ld %ld %ld)\n", total_bytes / (1024.0 * 1024.0),
526  newMaxSlots[0], newMaxSlots[4], newMaxSlots[5], newMaxSlots[1], newMaxSlots[2], newMaxSlots[3]);
527 
528  /* move the last block first since we are only increasing sizes, moving items forward.
529  * No need to move the 0 block, since it is already moved to newSlotsBase in realloc.*/
530  for(ptype = 5; ptype > 0; ptype--) {
531  if(!SLOTS_ENABLED(ptype, sman)) continue;
532  memmove(newSlotsBase + offsets[ptype],
533  sman->info[ptype].ptr,
534  sman->info[ptype].elsize * sman->info[ptype].size);
535  }
536 
537  sman->Base = newSlotsBase;
538 
539  for(ptype = 0; ptype < 6; ptype++) {
540  sman->info[ptype].ptr = newSlotsBase + offsets[ptype];
541  sman->info[ptype].maxsize = newMaxSlots[ptype];
542  }
543  GDB_SphP = (struct sph_particle_data *) sman->info[0].ptr;
544  GDB_StarP = (struct star_particle_data *) sman->info[4].ptr;
545  GDB_BhP = (struct bh_particle_data *) sman->info[5].ptr;
546  return total_bytes;
547 }
#define add(fmt,...)
#define mymalloc(name, size)
Definition: mymalloc.h:15
#define myrealloc(ptr, size)
Definition: mymalloc.h:18
static struct bh_particle_data * GDB_BhP
Definition: slotsmanager.c:17
static struct sph_particle_data * GDB_SphP
Definition: slotsmanager.c:15
static struct star_particle_data * GDB_StarP
Definition: slotsmanager.c:16

References add, slots_manager_type::Base, slot_info::elsize, GDB_BhP, GDB_SphP, GDB_StarP, slots_manager_type::increase, slots_manager_type::info, slot_info::maxsize, message(), mymalloc, myrealloc, slot_info::ptr, ptype, slot_info::size, and SLOTS_ENABLED.

Referenced by domain_exchange_once(), fof_distribute_particles(), fof_seed(), init_alloc_particle_slot_memory(), setup_density(), setup_particles(), sfr_reserve_slots(), and test_slots_reserve().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ slots_set_enabled()

void slots_set_enabled ( int  ptype,
size_t  elsize,
struct slots_manager_type sman 
)

Definition at line 560 of file slotsmanager.c.

561 {
562  sman->info[ptype].enabled = 1;
563  sman->info[ptype].elsize = elsize;
564  MPI_Type_contiguous(sman->info[ptype].elsize, MPI_BYTE, &MPI_TYPE_SLOT[ptype]);
565  MPI_Type_commit(&MPI_TYPE_SLOT[ptype]);
566 }
MPI_Datatype MPI_TYPE_SLOT[6]
Definition: slotsmanager.c:13

References slot_info::elsize, slot_info::enabled, slots_manager_type::info, MPI_TYPE_SLOT, and ptype.

Referenced by begrun(), setup_density(), and setup_particles().

Here is the caller graph for this function:

◆ slots_setup_id()

void slots_setup_id ( const struct part_manager_type pman,
struct slots_manager_type sman 
)

Definition at line 653 of file slotsmanager.c.

654 {
655  int64_t i;
656  /* set up the cross check for child IDs */
657  #pragma omp parallel for
658  for(i = 0; i < pman->NumPart; i++)
659  {
660  struct slot_info info = sman->info[pman->Base[i].Type];
661  if(!info.enabled)
662  continue;
663 
664  int sind = pman->Base[i].PI;
665  if(sind >= info.size || sind < 0)
666  endrun(1, "Particle %d, type %d has PI index %d beyond max slot size %d.\n", i, pman->Base[i].Type, sind, info.size);
667  struct particle_data_ext * sdata = (struct particle_data_ext * )(info.ptr + info.elsize * (size_t) sind);
668  sdata->ReverseLink = i;
669  sdata->ID = pman->Base[i].ID;
670  }
671 }

References part_manager_type::Base, slot_info::elsize, slot_info::enabled, endrun(), particle_data::ID, particle_data_ext::ID, slots_manager_type::info, part_manager_type::NumPart, particle_data::PI, slot_info::ptr, particle_data_ext::ReverseLink, slot_info::size, and particle_data::Type.

Referenced by petaio_read_snapshot(), and setup_particles().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ slots_setup_topology()

void slots_setup_topology ( struct part_manager_type pman,
int64_t *  NLocal,
struct slots_manager_type sman 
)

Definition at line 624 of file slotsmanager.c.

625 {
626  /* initialize particle types */
627  int ptype;
628  int64_t offset = 0;
629  for(ptype = 0; ptype < 6; ptype ++) {
630  int64_t i;
631  struct slot_info info = sman->info[ptype];
632  #pragma omp parallel for
633  for(i = 0; i < NLocal[ptype]; i++)
634  {
635  size_t j = offset + i;
636  pman->Base[j].Type = ptype;
637  pman->Base[j].IsGarbage = 0;
638  if(info.enabled)
639  pman->Base[j].PI = i;
640  }
641  offset += NLocal[ptype];
642  }
643 
644  for(ptype = 0; ptype < 6; ptype ++) {
645  struct slot_info info = sman->info[ptype];
646  if(!info.enabled)
647  continue;
648  sman->info[ptype].size = NLocal[ptype];
649  }
650 }

References part_manager_type::Base, slot_info::enabled, slots_manager_type::info, particle_data::IsGarbage, particle_data::PI, ptype, slot_info::size, and particle_data::Type.

Referenced by init_alloc_particle_slot_memory(), and setup_particles().

Here is the caller graph for this function:

◆ slots_split_particle()

int slots_split_particle ( int  parent,
double  childmass,
struct part_manager_type pman 
)

When a new additional star particle is created, we can put it into the tree at the position of the spawning gas particle. Multipole moments of tree nodes need not be changed.

Definition at line 103 of file slotsmanager.c.

104 {
105  int64_t child = atomic_fetch_and_add_64(&pman->NumPart, 1);
106 
107  if(child >= pman->MaxPart)
108  endrun(8888, "Tried to spawn: NumPart=%ld MaxPart = %ld. Sorry, no space left.\n", child, pman->MaxPart);
109 
110  pman->Base[parent].Generation ++;
111  uint64_t g = pman->Base[parent].Generation;
112  pman->Base[child] = pman->Base[parent];
113 
114  /* change the child ID according to the generation. */
115  pman->Base[child].ID = (pman->Base[parent].ID & 0x00ffffffffffffffL) + (g << 56L);
116  if(g >= (1 << (64-56L)))
117  endrun(1, "Particle %d (ID: %ld) generated too many particles: generation %ld wrapped.\n", parent, pman->Base[parent].ID, g);
118 
119  pman->Base[child].Mass = childmass;
120  pman->Base[parent].Mass -= childmass;
121 
122  /*Invalidate the slot of the child. Call slots_convert soon afterwards!*/
123  pman->Base[child].PI = -1;
124 
129  /* emit event for forcetree to deal with the new particle */
130  EISlotsFork event = {
131  .parent = parent,
132  .child = child,
133  };
134 
135  event_emit(&EventSlotsFork, (EIBase *) &event);
136 
137  return child;
138 }
int event_emit(EventSpec *eh, EIBase *event)
Definition: event.c:44
EventSpec EventSlotsFork
Definition: event.c:54
Definition: event.h:8
unsigned char Generation
Definition: partmanager.h:23

References atomic_fetch_and_add_64(), part_manager_type::Base, endrun(), event_emit(), EventSlotsFork, particle_data::Generation, particle_data::ID, particle_data::Mass, part_manager_type::MaxPart, part_manager_type::NumPart, EISlotsFork::parent, and particle_data::PI.

Referenced by get_sfr_eeqos(), and test_slots_fork().

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ GDB_BhP

struct bh_particle_data* GDB_BhP
static

Definition at line 17 of file slotsmanager.c.

Referenced by slots_reserve().

◆ GDB_SphP

struct sph_particle_data* GDB_SphP
static

Definition at line 15 of file slotsmanager.c.

Referenced by slots_reserve().

◆ GDB_StarP

struct star_particle_data* GDB_StarP
static

Definition at line 16 of file slotsmanager.c.

Referenced by slots_reserve().

◆ MPI_TYPE_PARTICLE

MPI_Datatype MPI_TYPE_PARTICLE = 0

Definition at line 11 of file slotsmanager.c.

Referenced by domain_exchange_once(), and slots_init().

◆ MPI_TYPE_PLAN_ENTRY

MPI_Datatype MPI_TYPE_PLAN_ENTRY = 0

Definition at line 12 of file slotsmanager.c.

◆ MPI_TYPE_SLOT

MPI_Datatype MPI_TYPE_SLOT[6] = {0}

Definition at line 13 of file slotsmanager.c.

Referenced by domain_exchange_once(), and slots_set_enabled().

◆ SlotsManager

struct slots_manager_type SlotsManager[1]