MP-Gadget  5.0.1.dev1-76bc7d4726-dirty
slotsmanager.c
Go to the documentation of this file.
1 #include <string.h>
2 #include "slotsmanager.h"
3 #include "partmanager.h"
4 
5 #include "utils.h"
6 
8 
9 #define SLOTS_ENABLED(ptype, sman) (sman->info[ptype].enabled)
10 
11 MPI_Datatype MPI_TYPE_PARTICLE = 0;
12 MPI_Datatype MPI_TYPE_PLAN_ENTRY = 0;
13 MPI_Datatype MPI_TYPE_SLOT[6] = {0};
14 
15 static struct sph_particle_data * GDB_SphP;
16 static struct star_particle_data * GDB_StarP;
17 static struct bh_particle_data * GDB_BhP;
18 
19 static int
20 slots_gc_base(struct part_manager_type * pman);
21 
22 static int
23 slots_gc_slots(int * compact_slots, struct part_manager_type * pman, struct slots_manager_type * sman);
24 
25 /* Initialise a new slot with type at index pi
26  * for the particle at index i.
27  * This will modify both P[i] and the slot at pi in type.*/
28 static void
29 slots_connect_new_slot(int i, int pi, int type, struct part_manager_type * pman, struct slots_manager_type * sman)
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 }
40 
41 /* This will change a particle type. The original particle_data structure is preserved,
42  * but the old slot is made garbage and a new one (with the new type) is created.
43  * No data is copied, but the slot is created.
44  *
45  * Assumes the particle is protected by locks in threaded env.
46  *
47  * Note that the 'new particle' event is not emitted, as there is no new particle!
48  * If you do something on a new slot, this needs a new event.
49  *
50  * Arguments:
51  * parent - particle whose type is changing.
52  * ptype - type to change it to
53  * placement - if this is not -1, we use a specific numbered slot.
54  * if this is -1, get a new slot atomically from the pre-allocated heap.
55  * discardold - if this is true, the pre-conversion slot will be marked as garbage.
56  * If you are really converting then this should be true.
57  * If you are using this function on the output of slots_split_particle, it should be false.
58  * */
59 int
60 slots_convert(int parent, int ptype, int placement, struct part_manager_type * pman, struct slots_manager_type * sman)
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 }
85 
86 /* This will split a new particle out from an existing one, conserving mass.
87  * The type is the same and the slot PI on the new particle is set to -1.
88  * You should call slots_convert on the child afterwards to create a new slot.
89  *
90  * Assumes the particle is protected by locks in threaded env.
91  *
92  * The Generation of parent is incremented.
93  * The child carries the incremented generation number.
94  * The ID of the child is modified, with the new generation number set
95  * at the highest 8 bits.
96  *
97  * the new particle's index is returned.
98  *
99  * Its mass and ptype can be then adjusted using slots_convert.
100  * The 'new particle' event is emitted.
101  * */
102 int
103 slots_split_particle(int parent, double childmass, struct part_manager_type * pman)
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 }
139 
140 /* remove garbage particles, holes in sph chunk and holes in bh buffer.
141  * This algorithm is O(n), and shifts particles over the holes.
142  * compact_slots is a 6-member array, 1 if that slot should be compacted, 0 otherwise.
143  * As slots_gc_base preserves the order of the slots, one may usually skip compaction.*/
144 int
145 slots_gc(int * compact_slots, struct part_manager_type * pman, struct slots_manager_type * sman)
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 }
162 
163 
164 #define GARBAGE(i, ptype, pman, sman) (sman ? BASESLOT_PI(i,ptype, sman)->ReverseLink > pman->MaxPart : pman->Base[i].IsGarbage)
165 #define PART(i, ptype, pman, sman) (sman ? (void *) BASESLOT_PI(i, ptype, sman) : (void *) &pman->Base[i])
166 
167 /*Find the next garbage particle*/
168 static int
169 slots_find_next_garbage(int start, int used, int ptype, struct part_manager_type * pman, struct slots_manager_type * sman)
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 }
180 
181 /*Find the next non-garbage particle*/
182 static int
183 slots_find_next_nongarbage(int start, int used, int ptype, struct part_manager_type * pman, struct slots_manager_type * sman)
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 }
194 
195 /*Compaction algorithm*/
196 static int
197 slots_gc_compact(const int used, int ptype, struct part_manager_type * pman, struct slots_manager_type * sman)
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 }
232 
233 static int
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 }
254 
255 static int slot_cmp_reverse_link(const void * b1in, const void * b2in) {
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 }
260 
261 static int
262 slots_gc_mark(const struct part_manager_type * pman, const struct slots_manager_type * sman)
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 }
305 
306 /* sweep removes unused entries in the slot list. */
307 static int
308 slots_gc_sweep(int ptype, struct part_manager_type * pman, struct slots_manager_type * sman)
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 }
319 
320 /* update new pointers. */
321 static void
322 slots_gc_collect(int ptype, struct part_manager_type * pman, struct slots_manager_type * sman)
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 }
342 
343 
344 static int
345 slots_gc_slots(int * compact_slots, struct part_manager_type * pman, struct slots_manager_type * sman)
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 }
386 
387 static int
388 order_by_type_and_key(const void *a, const void *b)
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 }
408 
409 /*Returns the number of non-Garbage particles in an array with garbage sorted to the end.
410  * The index returned always points to a garbage particle.
411  * If ptype < 0, find the last garbage particle in the P array.
412  * If ptype >= 0, find the last garbage particle in the slot associated with ptype. */
413 int
414 slots_get_last_garbage(int nfirst, int nlast, int ptype, const struct part_manager_type * pman, const struct slots_manager_type * sman)
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 }
436 
437 /* Sort the particles and their slots by type and peano order.
438  * This does a gc by sorting the Garbage to the end of the array and then trimming.
439  * It is a different algorithm to slots_gc, somewhat slower,
440  * but delivers a spatially compact sort. It always compacts the slots*/
441 void
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 }
473 
474 size_t
475 slots_reserve(int where, int64_t atleast[6], struct slots_manager_type * sman)
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 }
548 
549 void
550 slots_init(double increase, struct slots_manager_type * sman)
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 }
558 
559 void
560 slots_set_enabled(int ptype, size_t elsize, struct slots_manager_type * sman)
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 }
567 
568 
569 void
571 {
572  myfree(sman->Base);
573 }
574 
575 /* mark the i-th base particle as a garbage. */
576 void
577 slots_mark_garbage(int i, struct part_manager_type * pman, struct slots_manager_type * sman)
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 }
585 
586 void
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 }
621 
622 /* this function needs the Type of P[i] to be setup */
623 void
624 slots_setup_topology(struct part_manager_type * pman, int64_t * NLocal, struct slots_manager_type * sman)
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 }
651 
652 void
653 slots_setup_id(const struct part_manager_type * pman, struct slots_manager_type * sman)
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 }
void message(int where, const char *fmt,...)
Definition: endrun.c:175
void endrun(int where, const char *fmt,...)
Definition: endrun.c:147
int event_emit(EventSpec *eh, EIBase *event)
Definition: event.c:44
EventSpec EventSlotsFork
Definition: event.c:54
#define add(fmt,...)
#define mymalloc(name, size)
Definition: mymalloc.h:15
#define myrealloc(ptr, size)
Definition: mymalloc.h:18
#define myfree(x)
Definition: mymalloc.h:19
static int slots_gc_base(struct part_manager_type *pman)
Definition: slotsmanager.c:234
void slots_setup_id(const struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:653
size_t slots_reserve(int where, int64_t atleast[6], struct slots_manager_type *sman)
Definition: slotsmanager.c:475
MPI_Datatype MPI_TYPE_SLOT[6]
Definition: slotsmanager.c:13
#define SLOTS_ENABLED(ptype, sman)
Definition: slotsmanager.c:9
static struct bh_particle_data * GDB_BhP
Definition: slotsmanager.c:17
MPI_Datatype MPI_TYPE_PARTICLE
Definition: slotsmanager.c:11
void slots_set_enabled(int ptype, size_t elsize, struct slots_manager_type *sman)
Definition: slotsmanager.c:560
void slots_mark_garbage(int i, struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:577
static int slots_gc_mark(const struct part_manager_type *pman, const struct slots_manager_type *sman)
Definition: slotsmanager.c:262
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
static int slots_gc_slots(int *compact_slots, struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:345
void slots_free(struct slots_manager_type *sman)
Definition: slotsmanager.c:570
static int slots_gc_compact(const int used, int ptype, struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:197
#define GARBAGE(i, ptype, pman, sman)
Definition: slotsmanager.c:164
static void slots_gc_collect(int ptype, struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:322
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
static int slots_gc_sweep(int ptype, struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:308
void slots_setup_topology(struct part_manager_type *pman, int64_t *NLocal, struct slots_manager_type *sman)
Definition: slotsmanager.c:624
#define PART(i, ptype, pman, sman)
Definition: slotsmanager.c:165
MPI_Datatype MPI_TYPE_PLAN_ENTRY
Definition: slotsmanager.c:12
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
int slots_gc(int *compact_slots, struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:145
void slots_check_id_consistency(struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:587
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
void slots_gc_sorted(struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:442
static struct sph_particle_data * GDB_SphP
Definition: slotsmanager.c:15
static struct star_particle_data * GDB_StarP
Definition: slotsmanager.c:16
void slots_init(double increase, struct slots_manager_type *sman)
Definition: slotsmanager.c:550
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
int slots_convert(int parent, int ptype, int placement, struct part_manager_type *pman, struct slots_manager_type *sman)
Definition: slotsmanager.c:60
int slots_split_particle(int parent, double childmass, struct part_manager_type *pman)
Definition: slotsmanager.c:103
#define BASESLOT_PI(PI, ptype, sman)
Definition: slotsmanager.h:132
Definition: event.h:8
struct particle_data * Base
Definition: partmanager.h:74
MyIDType ID
Definition: partmanager.h:38
peano_t Key
Definition: partmanager.h:66
unsigned int Type
Definition: partmanager.h:17
unsigned int IsGarbage
Definition: partmanager.h:19
unsigned char Generation
Definition: partmanager.h:23
size_t elsize
Definition: slotsmanager.h:13
int64_t maxsize
Definition: slotsmanager.h:11
int64_t size
Definition: slotsmanager.h:12
char * ptr
Definition: slotsmanager.h:10
struct slot_info info[6]
Definition: slotsmanager.h:112
static int64_t atomic_fetch_and_add_64(int64_t *ptr, int64_t value)
Definition: system.h:68
#define MPI_INT64
Definition: system.h:12
#define qsort_openmp
Definition: test_exchange.c:14
static enum TransferType ptype
Definition: zeldovich.c:146