KMR
kmrutil.c
Go to the documentation of this file.
1 /* kmrutil.c (2014-02-04) */
2 /* Copyright (C) 2012-2018 RIKEN R-CCS */
3 
4 /** \file kmrutil.c Utilities. */
5 
6 /* _GNU_SOURCE is needed for "strnlen()" (it is POSIX Issue 7
7  2006). */
8 
9 #if defined(__linux__)
10 #define _GNU_SOURCE
11 #endif
12 
13 #include <mpi.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <strings.h>
19 #include <time.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/resource.h>
26 #include "kmr.h"
27 #include "kmrimpl.h"
28 
29 #define MIN(a,b) (((a)<(b))?(a):(b))
30 #define MAX(a,b) (((a)>(b))?(a):(b))
31 #define NEVERHERE 0
32 
33 /* Copy of constant values to make accessible from dlopen(). */
34 
35 int kmr_kv_field_bad = KMR_KV_BAD;
36 int kmr_kv_field_opaque = KMR_KV_OPAQUE;
37 int kmr_kv_field_cstring = KMR_KV_CSTRING;
38 int kmr_kv_field_integer = KMR_KV_INTEGER;
39 int kmr_kv_field_float8 = KMR_KV_FLOAT8;
40 int kmr_kv_field_pointer_owned = KMR_KV_POINTER_OWNED;
41 int kmr_kv_field_pointer_unmanaged = KMR_KV_POINTER_UNMANAGED;
42 
43 /* Issues warning. MR can be null (then verbosity is 5). MASK is 1
44  to 9; 1 for printed always (unsuppressible), 5 or less for printed
45  normally, 9 for printed only at highest verbosity. */
46 
47 void
48 kmr_warning(KMR *mr, unsigned int mask, char *m)
49 {
50  assert(1 <= mask && mask <= 9);
51  int rank = 0;
52  _Bool print = 1;
53  if (mr != 0) {
54  rank = mr->rank;
55  print = (mask <= mr->verbosity);
56  } else {
57  int cc = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
58  assert(cc == MPI_SUCCESS);
59  print = (mask <= 5);
60  }
61 
62  if (print) {
63  fprintf(stderr, ";;KMR [%05d] warning: %s.\n", rank, m);
64  fflush(0);
65  }
66 }
67 
68 void
69 kmr_error_at_site(KMR *mr, char *m, struct kmr_code_line *site)
70 {
71  int rank;
72  if (mr != 0) {
73  rank = mr->rank;
74  } else {
75  rank = 0;
76  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
77  /* Ignore error. */
78  }
79 
80  if (site != 0) {
81  fprintf(stderr, ";;KMR [%05d] error: %s: %s; at %s:%d\n",
82  rank, site->func, m, site->file, site->line);
83  fflush(0);
84  } else {
85  fprintf(stderr, ";;KMR [%05d] error: %s.\n", rank, m);
86  fflush(0);
87  }
88 
89  if (mr != 0 && mr->std_abort) {
90  abort();
91  } else {
92  (void)MPI_Abort(MPI_COMM_WORLD, 1);
93  }
94 }
95 
96 /* Aborts after printing a message. MR can be null. */
97 
98 void
99 kmr_error(KMR *mr, char *m)
100 {
101  kmr_error_at_site(mr, m, 0);
102 }
103 
104 void
105 kmr_error2(KMR *mr, char *m,
106  const char *file, const int line, const char *func)
107 {
108  struct kmr_code_line site = {.file = file, .line = line, .func = func};
109  kmr_error_at_site(mr, m, &site);
110 }
111 
112 void
113 kmr_error_kvs_at_site(KMR *mr, char *m, KMR_KVS *kvs,
114  struct kmr_code_line *site)
115 {
116  int rank = 0;
117  if (mr != 0) {
118  rank = mr->rank;
119  } else {
120  int cc = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
121  assert(cc == MPI_SUCCESS);
122  }
123 
124  if (site != 0 && kvs->c.info_line0.file != 0) {
125  struct kmr_code_line *info = &kvs->c.info_line0;
126  fprintf(stderr, ";;KMR [%05d] error: %s: %s"
127  " (kvs allocated at %s:%d: %s); at %s:%d\n",
128  rank, site->func, m, info->file, info->line, info->func,
129  site->file, site->line);
130  fflush(0);
131  } else if (kvs->c.info_line0.file != 0) {
132  struct kmr_code_line *info = &kvs->c.info_line0;
133  fprintf(stderr, ";;KMR [%05d] error: %s"
134  " (kvs allocated at %s:%d: %s)\n",
135  rank, m, info->file, info->line, info->func);
136  fflush(0);
137  } else if (site != 0) {
138  fprintf(stderr, ";;KMR [%05d] error: %s: %s; at %s:%d\n",
139  rank, site->func, m, site->file, site->line);
140  fflush(0);
141  } else {
142  fprintf(stderr, ";;KMR [%05d] error: %s\n",
143  rank, m);
144  fflush(0);
145  }
146 
147  if (mr != 0 && mr->std_abort) {
148  abort();
149  } else {
150  (void)MPI_Abort(MPI_COMM_WORLD, 1);
151  }
152 }
153 
154 void
155 kmr_error_kvs(KMR *mr, char *m, KMR_KVS *kvs)
156 {
157  kmr_error_kvs_at_site(mr, m, kvs, 0);
158 }
159 
160 void
161 kmr_error_kvs2(KMR *mr, char *m, KMR_KVS *kvs,
162  const char *file, const int line, const char *func)
163 {
164  struct kmr_code_line site = {.file = file, .line = line, .func = func};
165  kmr_error_kvs_at_site(mr, m, kvs, &site);
166 }
167 
168 void
169 kmr_error_mpi(KMR *mr, char *m, int errorcode)
170 {
171  int rank = 0;
172  if (mr != 0) {
173  rank = mr->rank;
174  } else {
175  int cc = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
176  assert(cc == MPI_SUCCESS);
177  }
178 
179  int len;
180  char s[MPI_MAX_ERROR_STRING];
181  int cc = MPI_Error_string(errorcode, s, &len);
182  if (cc != MPI_SUCCESS) {
183  snprintf(s, MPI_MAX_ERROR_STRING, "(unknown MPI error)");
184  }
185  fprintf(stderr, ";;KMR [%05d] %s: %s\n", rank, m, s);
186  fflush(stderr);
187 }
188 
189 /** Modifies the string end with by "..." for indicating truncation,
190  used on the result of snprintf. */
191 
192 void
193 kmr_string_truncation(KMR *mr, size_t sz, char *s)
194 {
195  assert(sz >= 4);
196  size_t m = strlen(s);
197  if (m == (sz - 1)) {
198  s[sz - 4] = '.';
199  s[sz - 3] = '.';
200  s[sz - 2] = '.';
201  assert(s[sz - 1] == 0);
202  }
203 }
204 
205 /** Returns itself; this is for Fortran-binding. */
206 
207 char *
209 {
210  return s;
211 }
212 
213 char *
214 kmr_ptrstr_ff(char *s)
215 {
216  return s;
217 }
218 
219 long
220 kmr_ptrint_ff(void *p)
221 {
222  return (long)p;
223 }
224 
225 void *
226 kmr_intptr_ff(long p)
227 {
228  return (void *)p;
229 }
230 
231 long
232 kmr_dblint_ff(double v)
233 {
234  union {double d; long i;} vv = {.d = v};
235  return vv.i;
236 }
237 
238 double
239 kmr_intdbl_ff(long v)
240 {
241  union {double d; long i;} vv = {.i = v};
242  return vv.d;
243 }
244 
245 long
246 kmr_strint_ff(char *p)
247 {
248  /*printf("str->int(%lx,s=%s)\n", (long)p, p);*/
249  return (long)(void *)p;
250 }
251 
252 /** Fills the character array S by the contents at the pointer value
253  integer P by the length N. It returns the string length in C
254  limited by N. */
255 
256 int
257 kmr_intstr_ff(long p, char *s, int n)
258 {
259  /*printf("int->str(%lx,s=%s)\n", i, (char *)i);*/
260  char *x = (void *)p;
261  memcpy(s, x, (size_t)n);
262  return (int)strnlen(x, (size_t)n);
263 }
264 
265 static inline unsigned long
266 kmr_bitreverse(unsigned long bits)
267 {
268  bits = (((bits & 0xaaaaaaaaaaaaaaaaUL) >> 1)
269  | ((bits & 0x5555555555555555UL) << 1));
270  bits = (((bits & 0xccccccccccccccccUL) >> 2)
271  | ((bits & 0x3333333333333333UL) << 2));
272  bits = (((bits & 0xf0f0f0f0f0f0f0f0UL) >> 4)
273  | ((bits & 0x0f0f0f0f0f0f0f0fUL) << 4));
274  bits = (((bits & 0xff00ff00ff00ff00UL) >> 8)
275  | ((bits & 0x00ff00ff00ff00ffUL) << 8));
276  bits = (((bits & 0xffff0000ffff0000UL) >> 16)
277  | ((bits & 0x0000ffff0000ffffUL) << 16));
278  return ((bits >> 32) | (bits << 32));
279 }
280 
281 /** Fixes little-endian bits used in Fortran to host-endian. */
282 
283 unsigned long
284 kmr_fix_bits_endian_ff(unsigned long b)
285 {
286  static union {struct {_Bool b : 1;} s; unsigned long i;}
287  kmr_bitpos0 = {.s={.b=1}};
288  assert(kmr_bitpos0.i == 1 || kmr_bitpos0.i == 0x8000000000000000UL);
289  unsigned long optionbits;
290  if (kmr_bitpos0.i == 1) {
291  /* BIT-LE */
292  optionbits = b;
293  } else {
294  /* BIT-BE */
295  optionbits = kmr_bitreverse(b);
296  }
297  unsigned long optionmask = (kmr_optmask.bits
298  | kmr_foptmask.bits
299  | kmr_soptmask.bits);
300  assert((optionbits & ~optionmask) == 0);
301  return optionbits;
302 }
303 
304 int
305 kmr_get_nprocs(const KMR *mr)
306 {
307  assert(mr != 0);
308  return mr->nprocs;
309 }
310 
311 int
312 kmr_get_rank(const KMR *mr)
313 {
314  assert(mr != 0);
315  return mr->rank;
316 }
317 
318 int
319 kmr_get_nprocs_ff(const KMR_KVS *kvs)
320 {
321  assert(kvs != 0);
322  return kvs->c.mr->nprocs;
323 }
324 
325 int
326 kmr_get_rank_ff(const KMR_KVS *kvs)
327 {
328  assert(kvs != 0);
329  return kvs->c.mr->rank;
330 }
331 
332 int
333 kmr_get_key_type_ff(const KMR_KVS *kvs)
334 {
335  assert(kvs != 0);
336  return kvs->c.key_data;
337 }
338 
339 int
340 kmr_get_value_type_ff(const KMR_KVS *kvs)
341 {
342  assert(kvs != 0);
343  return kvs->c.value_data;
344 }
345 
346 /** Gets the number of key-value pairs locally on each rank. */
347 
348 int
350 {
351  kmr_assert_kvs_ok(kvs, 0, 1, 0);
352  assert(v != 0);
353  *v = kvs->c.element_count;
354  return MPI_SUCCESS;
355 }
356 
357 /** Returns a print string of a single option, to check the bits are
358  properly encoded in foreign language interfaces. */
359 
360 char *
362 {
363  if (o.nothreading) {
364  return "nothreading";
365  } else if (o.inspect) {
366  return "inspect";
367  } else if (o.keep_open) {
368  return "keep_open";
369  } else if (o.key_as_rank) {
370  return "key_as_rank";
371  } else if (o.rank_zero) {
372  return "rank_zero";
373  } else if (o.collapse) {
374  return "collapse";
375  } else if (o.take_ckpt) {
376  return "take_ckpt";
377  } else {
378  return 0;
379  }
380 }
381 
382 /** Returns a print string of a single option, to check the bits are
383  properly encoded in foreign language interfaces. */
384 
385 char *
387 {
388  if (o.each_rank) {
389  return "each_rank";
390  } else if (o.subdirectories) {
391  return "subdirectories";
392  } else if (o.list_file) {
393  return "list_file";
394  } else if (o.shuffle_names) {
395  return "shuffle_names";
396  } else {
397  return 0;
398  }
399 }
400 
401 /** Returns a print string of a single option, to check the bits are
402  properly encoded in foreign language interfaces. */
403 
404 char *
406 {
407  if (o.separator_space) {
408  return "separator_space";
409  } else if (o.reply_each) {
410  return "reply_each";
411  } else if (o.reply_root) {
412  return "reply_root";
413 #if 0 /*GOMI*/
414  } else if (o.one_by_one) {
415  return "one_by_one";
416 #endif
417  } else if (o.no_set_infos) {
418  return "no_set_infos";
419  } else if (o.take_ckpt) {
420  return "take_ckpt";
421  } else {
422  return 0;
423  }
424 }
425 
426 /* ================================================================ */
427 
428 static int
429 kmr_k_node_by_rank(KMR *mr, kmr_k_position_t p)
430 {
431  int rank;
432  int cc = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
433  assert(cc == MPI_SUCCESS);
434  p[0] = 0;
435  p[1] = (unsigned short)rank;
436  p[2] = 0;
437  p[3] = 0;
438  return MPI_SUCCESS;
439 }
440 
441 /** Gets TOFU position (physical coordinates) of the node. Errors are
442  fatal (aborts). */
443 
444 int
446 {
447 #ifndef __K
448  int cc = kmr_k_node_by_rank(mr, p);
449  return cc;
450 #elif 0
451  if (!mr->onk) {
452  int cc = kmr_k_node_by_rank(mr, p);
453  return cc;
454  } else {
455  /* This code is for GM-1.2.0-12 and later (it is already
456  available, but is not default yet -- 2013-04). */
457  int cc;
458  int rank;
459  int x, y, z, a, b, c;
460  cc = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
461  assert(cc == MPI_SUCCESS);
462  cc = FJMPI_Topology_sys_rank2xyzabc(rank, &x, &y, &z, &a, &b, &c);
463  assert(cc == MPI_SUCCESS);
464  p[0] = (unsigned short)x;
465  p[1] = (unsigned short)y;
466  p[2] = (unsigned short)z;
467  p[3] = (unsigned short)((a << 4) | (b << 2) | c);
468  printf("[%05d] Coord x=%d, y=%d, z=%d, a=%d, b=%d, c=%d\n",
469  rank, x, y, z, a, b, c);
470  return MPI_SUCCESS;
471  }
472 #else
473  if (!mr->onk) {
474  int cc = kmr_k_node_by_rank(mr, p);
475  return cc;
476  } else {
477  char *tofupos = "/proc/tofu/position";
478  char buf[128];
479  int fd;
480  do {
481  fd = open(tofupos, O_RDONLY, 0);
482  } while (fd == -1 && errno == EINTR);
483  if (fd == -1) {
484  char ee[80];
485  char *m = strerror(errno);
486  snprintf(ee, 80, "open(%s): %s", tofupos, m);
487  kmr_error(0, ee);
488  }
489  int cc = 0;
490  off_t rc = 0;
491  while (rc < sizeof(buf)) {
492  ssize_t cx;
493  do {
494  cx = read(fd, &buf[rc], (sizeof(buf) - rc));
495  } while (cx == -1 && errno == EINTR);
496  if (cx == 0) {
497  break;
498  }
499  if (cx == -1) {
500  char ee[80];
501  char *m = strerror(errno);
502  snprintf(ee, 80, "read(%s): %s", tofupos, m);
503  kmr_error(0, ee);
504  }
505  rc += cx;
506  }
507  do {
508  cc = close(fd);
509  } while (cc == -1 && errno == EINTR);
510  assert(rc > 18 && rc < sizeof(buf));
511  buf[rc] = 0;
512  unsigned int x, y, z, a, b, c;
513  char nl, gomi;
514  cc = sscanf(buf, "TOFU NODE ADDRESS:%d,%d,%d,%d,%d,%d%c%c",
515  &x, &y, &z, &a, &b, &c, &nl, &gomi);
516  assert(cc == 7 && nl == '\n');
517  assert(a <= 1 && b <= 2 && c <= 1);
518  p[0] = x;
519  p[1] = y;
520  p[2] = z;
521  p[3] = ((a << 4) | (b << 2) | c);
522  return MPI_SUCCESS;
523  }
524 #endif
525 }
526 
527 /* ================================================================ */
528 
529 /* Returns wall-time in sec. NEVER USE CLOCK_GETTIME(). It needs
530  "rt"-library and avoided. (It prefers POSIX clock_gettime() to
531  MPI_Wtime(), although Open-MPI reads CPU clock counter which may be
532  more precise. On K, the returned resolution is nsec, but it
533  actually changes at usec rate). */
534 
535 double
536 kmr_wtime()
537 {
538 #if 1
539  return MPI_Wtime();
540 #else
541 #ifdef CLOCK_REALTIME
542  static double t0 = 0.0;
543  struct timespec ts;
544  int cc;
545  if (t0 == 0.0) {
546  cc = clock_getres(CLOCK_REALTIME, &ts);
547  assert(cc == 0);
548  double timerres = (double)ts.tv_sec + ((double)ts.tv_nsec * 1e-9);
549  //printf("hr-timer resolution %e sec\n", timerres);
550  assert(timerres <= 1e-4);
551  cc = clock_gettime(CLOCK_REALTIME, &ts);
552  assert(cc == 0);
553  t0 = (double)ts.tv_sec + ((double)ts.tv_nsec * 1e-9);
554  assert(t0 != 0.0);
555  }
556  cc = clock_gettime(CLOCK_REALTIME, &ts);
557  assert(cc == 0);
558  double t1 = (double)ts.tv_sec + ((double)ts.tv_nsec * 1e-9);
559  return (t1 - t0);
560 #endif
561 #endif
562 }
563 
564 /** Searches a key entry like bsearch(3C), but returns a next greater
565  entry instead of null on no match. Thus, it may return a pointer
566  ((char *)base+(nel*size)) when a key is larger than all. */
567 
568 void *
569 kmr_bsearch(const void *key, const void *base, size_t nel, size_t size,
570  int (*compar)(const void *, const void *))
571 {
572  assert(key != 0 && base != 0 && compar != 0);
573  const char *lb = base;
574  size_t w = nel;
575  while (w != 0) {
576  const char *p = lb + (w >> 1) * size;
577  int r = (*compar)(key, p);
578  if (r == 0) {
579  return (void *)p;
580  } else if (r > 0) {
581  lb = p + size;
582  w--;
583  w >>= 1;
584  } else {
585  w >>= 1;
586  }
587  }
588  return (void *)lb;
589 }
590 
591 /* MISCELLANEOUS */
592 
593 /** STRDUP, but aborts on failure. */
594 
595 void *
596 kmr_strdup(char *s)
597 {
598  void *p = strdup(s);
599  if (p == 0) {
600  char ee[80];
601  char *m = strerror(errno);
602  snprintf(ee, 80, "strdup(%s): %s", s, m);
603  kmr_error(0, ee);
604  }
605  return p;
606 }
607 
608 /** Frees a string strduped. */
609 
610 void
612 {
613  if (s != 0) {
614  size_t sz = (strlen(s) + 1);
615  kmr_free(s, sz);
616  }
617 }
618 
619 //extern FILE *kmr_fopen(const char *n, const char *m);
620 //extern int kmr_fgetc(FILE *f);
621 
622 /** Does fopen, avoiding EINTR. */
623 
624 FILE *
625 kmr_fopen(const char *n, const char *m)
626 {
627  FILE *f = 0;
628  do {
629  f = fopen(n, m);
630  } while (f == 0 && errno == EINTR);
631  return f;
632 }
633 
634 /** Does fgetc, avoiding EINTR. */
635 
636 int
637 kmr_fgetc(FILE *f)
638 {
639  errno = 0;
640  int c;
641  do {
642  c = fgetc(f);
643  } while (c == EOF && errno == EINTR);
644  return c;
645 }
646 
647 /** Does getdtablesize(); it is defined, because it is not Posix. */
648 
649 int
651 {
652  int cc;
653  struct rlimit r;
654  cc = getrlimit(RLIMIT_NOFILE, &r);
655  int n;
656  if (cc == -1) {
657  char ee[80];
658  char *m = strerror(errno);
659  snprintf(ee, sizeof(ee), "getrlimit(RLIMIT_NOFILE) failed: %s", m);
660  kmr_warning(mr, 5, ee);
661  n = 20;
662  } else {
663  n = (int)r.rlim_cur;
664  }
665  return n;
666 }
667 
668 int
669 kmr_parse_int(char *s, int *r)
670 {
671  int v;
672  char gomi[sizeof(int)];
673  int cc = sscanf(s, "%d%c", &v, gomi);
674  if (cc == 1 && r != 0) {
675  *r = v;
676  }
677  return (cc == 1);
678 }
679 
680 int
681 kmr_parse_boolean(char *s, int *r)
682 {
683  int v = -1;
684  int vv;
685  char gomi[sizeof(int)];
686  if (strcasecmp(s, "true") == 0) {
687  v = 1;
688  } else if (strcasecmp(s, "false") == 0) {
689  v = 0;
690  } else if (sscanf(s, "%d%c", &vv, gomi) == 1) {
691  if (vv == 0 || vv == 1) {
692  v = vv;
693  }
694  }
695  if (v != -1 && r != 0) {
696  *r = v;
697  }
698  return (v != -1);
699 }
700 
701 static int
702 kmr_parse_size_t(char *s, size_t *r)
703 {
704  long v;
705  char gomi[sizeof(int)];
706  int cc = sscanf(s, "%ld%c", &v, gomi);
707  if (cc == 1 && r != 0) {
708  *r = (size_t)v;
709  }
710  return (cc == 1);
711 }
712 
713 /** Checks a key-value stream is sorted. When not LOCALLY, it
714  collects all the entries to rank-zero for checking. */
715 
716 int
717 kmr_assert_sorted(KMR_KVS *kvi, _Bool locally, _Bool shuffling, _Bool ranking)
718 {
719  int cc;
720  KMR *mr = kvi->c.mr;
721  int kcdc = kmr_ckpt_disable_ckpt(mr);
722  int rank = mr->rank;
723  kmr_sorter_t cmp = kmr_choose_sorter(kvi);
724  KMR_KVS *kvs1;
725  if (locally) {
726  kvs1 = kvi;
727  } else {
728  kvs1 = kmr_create_kvs(mr, kvi->c.key_data, kvi->c.value_data);
729  struct kmr_option rankzero = {.rank_zero = 1};
730  cc = kmr_replicate(kvi, kvs1, rankzero);
731  assert(cc == MPI_SUCCESS);
732  }
733  if (locally || rank == 0) {
734  long cnt = kvs1->c.element_count;
735  size_t evsz = (sizeof(struct kmr_kvs_entry *) * (size_t)cnt);
736  struct kmr_kvs_entry **ev = kmr_malloc(evsz);
737  cc = kmr_retrieve_kvs_entries(kvs1, ev, cnt);
738  assert(cc == MPI_SUCCESS);
739  for (long i = 1; i < cnt; i++) {
740  if (!shuffling) {
741  struct kmr_kv_box b0 = kmr_pick_kv(ev[i - 1], kvs1);
742  struct kmr_kv_box b1 = kmr_pick_kv(ev[i], kvs1);
743  assert(cmp(&b0, &b1) <= 0);
744  } else {
745  struct kmr_kv_box b0 = kmr_pick_kv(ev[i - 1], kvs1);
746  struct kmr_kv_box b1 = kmr_pick_kv(ev[i], kvs1);
747  int r0 = (ranking ? (int)b0.k.i : kmr_pitch_rank(b0, kvs1));
748  int r1 = (ranking ? (int)b1.k.i : kmr_pitch_rank(b1, kvs1));
749  assert(r0 <= r1);
750  }
751  }
752  kmr_free(ev, evsz);
753  }
754  if (!locally) {
755  assert(kvs1 != kvi);
756  cc = kmr_free_kvs(kvs1);
757  assert(cc == MPI_SUCCESS);
758  }
759  kmr_ckpt_enable_ckpt(mr, kcdc);
760  return MPI_SUCCESS;
761 }
762 
763 /* Scans a given string to find strings separated by nulls or
764  whitespaces, and returns the count and the strings. A string is
765  given by S and a length LEN (including null). The string will be
766  modified to change whitespaces to nulls. MAXARGC is the size of a
767  vector ARGV, limiting the maximum number of the arguments to
768  (MAXARGC-1), with one spare for a terminating null. ARGC is set to
769  the count and ARGV is filled with the arguments on return. ARGV
770  must have at least the size MAXARGC. When ARGV is null (and
771  MAXARGC is zero), it returns only the count in ARGC (without
772  counting a terminating null). The option WS means the separator
773  character is whatespaces instead of nulls. MSG is a message prefix
774  printed on errors. */
775 
776 int
777 kmr_scan_argv_strings(KMR *mr, char *s, size_t len, int maxargc,
778  int *argc, char **argv, _Bool ws, char *msg)
779 {
780  assert(s != 0 && len > 0);
781  assert(argc != 0 || argv != 0);
782  assert((maxargc != 0) == (argv != 0));
783  assert(!isblank('\0'));
784  if (s[len - 1] != 0) {
785  char ee[80];
786  snprintf(ee, sizeof(ee), ("%s: argument strings"
787  " not terminated with a null"), msg);
788  /*kmr_warning(mr, 5, ee);*/
789  kmr_error(mr, ee);
790  }
791  _Bool counting = (argv == 0);
792  char * const lim = &s[len - 1];
793  char *p = s;
794  int index = 0;
795  for (;;) {
796  while (p < lim && (ws && isblank(*p))) {
797  p++;
798  }
799  if (p == lim) {
800  break;
801  }
802  if (!counting && index < (maxargc - 1)) {
803  argv[index] = p;
804  }
805  index++;
806  while (p < lim && !(*p == 0 || (ws && isblank(*p)))) {
807  p++;
808  }
809  assert(p <= lim);
810  if (!counting && *p != 0) {
811  assert(ws && isblank(*p));
812  *p = 0;
813  }
814  if (p < lim) {
815  p++;
816  }
817  }
818  assert(p == lim);
819  if (!counting && index > (maxargc - 1)) {
820  char ee[80];
821  snprintf(ee, sizeof(ee),
822  ("%s: argument count exceeds the limit (%d)"), msg, maxargc);
823  kmr_error(mr, ee);
824  }
825  if (!counting && index < maxargc) {
826  argv[index] = 0;
827  }
828  if (argc != 0) {
829  *argc = index;
830  }
831  return MPI_SUCCESS;
832 }
833 
834 /* Sleeps for MSEC, but calls MPI_Testany() periodically. (It avoids
835  using MPI_STATUS_IGNORE in MPI_Testany() for a bug in some versions
836  of Open MPI (around 1.6.3)). */
837 
838 int
839 kmr_msleep(int msec, int interval)
840 {
841  assert(msec >= 1 && interval >= 1);
842  int gap = MIN(msec, interval);
843  double t0 = MPI_Wtime();
844  double t1 = (t0 + 1e-3 * msec);
845  for (;;) {
846  int index;
847  int ok;
848  MPI_Status st;
849  int cc = MPI_Testany(0, 0, &index, &ok, &st);
850  assert(cc == MPI_SUCCESS);
851  double t2 = MPI_Wtime();
852  if (t2 > t1) {
853  break;
854  }
855  usleep((useconds_t)(gap * 1000));
856  }
857  return MPI_SUCCESS;
858 }
859 
860 /* Frees memory by free() (3C). It is for calling free() safely from
861  users of the .so library, even if free() is substituted by
862  anything. */
863 
864 void
865 kmr_mfree(void *p, size_t sz)
866 {
867  kmr_free(p, sz);
868 }
869 
870 /* (mpi routines for python-ctypes) Returns a sizeof a MPI type given
871  by a string. */
872 
873 size_t
874 kmr_mpi_type_size(char *s)
875 {
876  if (strcasecmp(s, "MPI_Group") == 0) {
877  return sizeof(MPI_Group);
878  } else if (strcasecmp(s, "MPI_Comm") == 0) {
879  return sizeof(MPI_Comm);
880  } else if (strcasecmp(s, "MPI_Datatype") == 0) {
881  return sizeof(MPI_Datatype);
882  } else if (strcasecmp(s, "MPI_Request") == 0) {
883  return sizeof(MPI_Request);
884  } else if (strcasecmp(s, "MPI_Op") == 0) {
885  return sizeof(MPI_Op);
886  } else if (strcasecmp(s, "MPI_Errhandler") == 0) {
887  return sizeof(MPI_Errhandler);
888  } else if (strcasecmp(s, "MPI_Info") == 0) {
889  return sizeof(MPI_Info);
890  } else {
891  char ee[80];
892  snprintf(ee, sizeof(ee),
893  "kmr_mpi_type_size() unknown name (%s)", s);
894  kmr_warning(0, 5, ee);
895  return 0;
896  }
897 }
898 
899 /* (mpi routines for python-ctypes) Returns a value of some MPI named
900  constants given by a string. */
901 
902 uint64_t
903 kmr_mpi_constant_value(char *s)
904 {
905  assert(sizeof(MPI_Group) <= sizeof(uint64_t)
906  && sizeof(MPI_Comm) <= sizeof(uint64_t)
907  && sizeof(MPI_Datatype) <= sizeof(uint64_t)
908  && sizeof(MPI_Request) <= sizeof(uint64_t)
909  && sizeof(MPI_Op) <= sizeof(uint64_t)
910  && sizeof(MPI_Errhandler) <= sizeof(uint64_t)
911  && sizeof(MPI_Info) <= sizeof(uint64_t));
912 
913  if (strcasecmp(s, "MPI_COMM_WORLD") == 0) {
914  return (uint64_t)MPI_COMM_WORLD;
915  } else if (strcasecmp(s, "MPI_COMM_SELF") == 0) {
916  return (uint64_t)MPI_COMM_SELF;
917  } else if (strcasecmp(s, "MPI_COMM_NULL") == 0) {
918  return (uint64_t)MPI_COMM_NULL;
919  } else if (strcasecmp(s, "MPI_GROUP_NULL") == 0) {
920  return (uint64_t)MPI_GROUP_NULL;
921  } else if (strcasecmp(s, "MPI_DATATYPE_NULL") == 0) {
922  return (uint64_t)MPI_DATATYPE_NULL;
923  } else if (strcasecmp(s, "MPI_REQUEST_NULL") == 0) {
924  return (uint64_t)MPI_REQUEST_NULL;
925  } else if (strcasecmp(s, "MPI_OP_NULL") == 0) {
926  return (uint64_t)MPI_OP_NULL;
927  } else if (strcasecmp(s, "MPI_ERRHANDLER_NULL") == 0) {
928  return (uint64_t)MPI_ERRHANDLER_NULL;
929  } else if (strcasecmp(s, "MPI_GROUP_EMPTY") == 0) {
930  return (uint64_t)MPI_GROUP_EMPTY;
931  } else if (strcasecmp(s, "MPI_INFO_NULL") == 0) {
932  return (uint64_t)MPI_INFO_NULL;
933  } else {
934  char ee[80];
935  snprintf(ee, sizeof(ee),
936  "kmr_mpi_constant_value() unknown name (%s)", s);
937  kmr_warning(0, 5, ee);
938  return 0;
939  }
940 }
941 
942 /* ================================================================ */
943 
944 /** Copies the entry in the array. It should be used with the INSPECT
945  option for map, because the array entries may point into the input
946  key-value stream. It is a map-function. */
947 
948 int
950  const KMR_KVS *kvi, KMR_KVS *kvo, void *arg, const long i)
951 {
952  struct kmr_kv_box *v = arg;
953  v[i] = kv;
954  return MPI_SUCCESS;
955 }
956 
957 /* Reduces the argument integers to the maximum, only for a single
958  reduction (the all keys are the same). */
959 
960 int
961 kmr_imax_one_fn(const struct kmr_kv_box kv[], const long n,
962  const KMR_KVS *kvi, KMR_KVS *kvo, void *p)
963 {
964  assert(n > 0);
965  long *zz = p;
966  long m = 0;
967  for (long i = 0; i < n; i++) {
968  long v = kv[i].v.i;
969  m = MAX(v, m);
970  }
971  *zz = m;
972  return MPI_SUCCESS;
973 }
974 
975 int
976 kmr_isum_one_fn(const struct kmr_kv_box kv[], const long n,
977  const KMR_KVS *kvi, KMR_KVS *kvo, void *p)
978 {
979  assert(n > 0);
980  long *zz = p;
981  long m = 0;
982  for (long i = 0; i < n; i++) {
983  long v = kv[i].v.i;
984  m = v + m;
985  }
986  *zz = m;
987  return MPI_SUCCESS;
988 }
989 
990 /* ================================================================ */
991 
992 /* PREFERENCE/OPTIONS */
993 
994 /** Copies mpi-info entires into kvs. */
995 
996 int
997 kmr_copy_info_to_kvs(MPI_Info src, KMR_KVS *kvo)
998 {
999  kmr_assert_kvs_ok(0, kvo, 0, 1);
1000  assert(src != MPI_INFO_NULL);
1001  int cc;
1002  int nkeys;
1003  char key[MPI_MAX_INFO_KEY + 1];
1004  char value[MPI_MAX_INFO_VAL + 1];
1005  cc = MPI_Info_get_nkeys(src, &nkeys);
1006  assert(cc == MPI_SUCCESS);
1007  for (int i = 0; i < nkeys; i++) {
1008  int vlen;
1009  int flag;
1010  cc = MPI_Info_get_nthkey(src, i, key);
1011  assert(cc == MPI_SUCCESS);
1012  cc = MPI_Info_get_valuelen(src, key, &vlen, &flag);
1013  assert(cc == MPI_SUCCESS && flag != 0);
1014  assert(vlen <= MPI_MAX_INFO_VAL);
1015  cc = MPI_Info_get(src, key, MPI_MAX_INFO_VAL, value, &flag);
1016  assert(cc == MPI_SUCCESS && flag != 0);
1017  cc = kmr_add_string(kvo, key, value);
1018  assert(cc == MPI_SUCCESS);
1019  }
1020  cc = kmr_add_kv_done(kvo);
1021  assert(cc == MPI_SUCCESS);
1022  return MPI_SUCCESS;
1023 }
1024 
1025 static int
1026 kmr_set_info_fn(const struct kmr_kv_box kv,
1027  const KMR_KVS *kvi, KMR_KVS *kvo, void *p, const long i)
1028 {
1029  MPI_Info *dstp = p;
1030  MPI_Info dst = *dstp;
1031  char *k = (char *)kv.k.p;
1032  char *v = (char *)kv.v.p;
1033  if (k[0] == 0) {
1034  kmr_warning(0, 5, "empty key string for MPI_Info_set(), ignored");
1035  } else if (v[0] == 0) {
1036  /* OPEN MPI (1.6.4) DOES NOT ALLOW EMPTY VALUE. */
1037  kmr_warning(0, 5, "empty value string for MPI_Info_set(), ignored");
1038  } else {
1039  int cc = MPI_Info_set(dst, (char *)kv.k.p, (char *)kv.v.p);
1040  assert(cc == MPI_SUCCESS);
1041  }
1042  return MPI_SUCCESS;
1043 }
1044 
1045 /** Copies kvs entires into mpi-info. It assumes keys/values are
1046  strings (no checks). It consumes KVI. */
1047 
1048 int
1049 kmr_copy_kvs_to_info(KMR_KVS *kvi, MPI_Info dst)
1050 {
1051  kmr_assert_kvs_ok(kvi, 0, 1, 0);
1052  int cc;
1053  struct kmr_option nothreading = {.nothreading = 1};
1054  cc = kmr_map(kvi, 0, &dst, nothreading, kmr_set_info_fn);
1055  assert(cc == MPI_SUCCESS);
1056  return MPI_SUCCESS;
1057 }
1058 
1059 /* Loads configuration options from preferences into INFO.
1060  Preferences are taken from a file with a name specified by an
1061  environment variable "KMROPTION" on rank0. */
1062 
1063 int
1064 kmr_load_preference(KMR *mr, MPI_Info info)
1065 {
1066  int cc;
1067  MPI_Info inforank0;
1068  cc = MPI_Info_create(&inforank0);
1069  assert(cc == MPI_SUCCESS);
1070  do {
1071  if (mr->rank == 0) {
1072  char *name = getenv("KMROPTION");
1073  if (name == 0) {
1074  break;
1075  }
1076  cc = kmr_load_properties(inforank0, name);
1077  if (cc != MPI_SUCCESS) {
1078  break;
1079  }
1080  }
1081  } while (0);
1082  KMR_KVS *kvs0 = kmr_create_kvs(mr, KMR_KV_OPAQUE, KMR_KV_OPAQUE);
1083  cc = kmr_copy_info_to_kvs(inforank0, kvs0);
1084  assert(cc == MPI_SUCCESS);
1085  KMR_KVS *kvs1 = kmr_create_kvs(mr, KMR_KV_OPAQUE, KMR_KV_OPAQUE);
1086  cc = kmr_replicate(kvs0, kvs1, kmr_noopt);
1087  assert(cc == MPI_SUCCESS);
1088  cc = kmr_copy_kvs_to_info(kvs1, info);
1089  assert(cc == MPI_SUCCESS);
1090  MPI_Info_free(&inforank0);
1091  if (0) {
1092  char ee[80];
1093  snprintf(ee, sizeof(ee), "[%05d]", mr->rank);
1094  printf("%s dumpinfo info...\n", ee);
1095  kmr_dump_mpi_info(ee, info);
1096  }
1097  return MPI_SUCCESS;
1098 }
1099 
1100 /* Checks configuration options. It takes merges of two mpi-infos,
1101  one from preferences and one given. The given one overrides
1102  preferences. */
1103 
1104 int
1105 kmr_check_options(KMR *mr, MPI_Info info)
1106 {
1107  int cc;
1108  /* Check options. */
1109  int n;
1110  if (info == MPI_INFO_NULL) {
1111  n = 0;
1112  } else {
1113  cc = MPI_Info_get_nkeys(info, &n);
1114  assert(cc == MPI_SUCCESS);
1115  }
1116 
1117  for (int i = 0; i < n; i++) {
1118  char k[MPI_MAX_INFO_KEY + 1];
1119  char v[MPI_MAX_INFO_VAL + 1];
1120  int flag;
1121  cc = MPI_Info_get_nthkey(info, i, k);
1122  assert(cc == MPI_SUCCESS);
1123  cc = MPI_Info_get(info, k, MPI_MAX_INFO_VAL, v, &flag);
1124  assert(cc == MPI_SUCCESS && flag != 0);
1125  if (flag == 1) {
1126  kmr_set_option_by_strings(mr, k, v);
1127  } else {
1128  char ee[80];
1129  snprintf(ee, 80, "option \"%s\" ignored", k);
1130  kmr_warning(mr, 1, ee);
1131  }
1132  }
1133 
1134  if (mr->verbosity == 9) {
1135  int r = mr->rank;
1136  printf("[%05d] Dumping KMR options:\n", r);
1137  printf("[%05d] verbosity=%d\n", r, mr->verbosity);
1138  printf("[%05d] sort_threads_depth=%d\n", r, mr->sort_threads_depth);
1139  printf("[%05d] onk=%d\n", r, mr->onk);
1140  printf("[%05d] atoa_threshold=%ld\n", r, mr->atoa_threshold);
1141  printf("[%05d] atoa_size_limit=%ld\n", r, mr->atoa_size_limit);
1142  printf("[%05d] atoa_requests_limit=%d\n", r, mr->atoa_requests_limit);
1143  printf("[%05d] single_thread=%d\n", r, mr->single_thread);
1144  printf("[%05d] step_sync=%d\n", r, mr->step_sync);
1145  printf("[%05d] trace_file_io=%d\n", r, mr->trace_file_io);
1146  printf("[%05d] trace_map_ms=%d\n", r, mr->trace_map_ms);
1147  printf("[%05d] trace_map_spawn=%d\n", r, mr->trace_map_spawn);
1148  printf("[%05d] trace_alltoall=%d\n", r, mr->trace_alltoall);
1149  printf("[%05d] trace_kmrdp=%d\n", r, mr->trace_kmrdp);
1150  printf("[%05d] std_abort=%d\n", r, mr->std_abort);
1151  printf("[%05d] log_traces=%d\n", r, (mr->log_traces != 0));
1152  printf("[%05d] ckpt_enable=%d\n", r, mr->ckpt_enable);
1153  printf("[%05d] ckpt_selective=%d\n", r, mr->ckpt_selective);
1154  printf("[%05d] ckpt_no_fsync=%d\n", r, mr->ckpt_no_fsync);
1155  printf("[%05d] pushoff_block_size=%zd\n", r, mr->pushoff_block_size);
1156  printf("[%05d] pushoff_poll_rate=%d\n", r, mr->pushoff_poll_rate);
1157  printf("[%05d] pushoff_fast_notice=%d\n", r, mr->pushoff_fast_notice);
1158  printf("[%05d] kmrviz_trace=%d\n", r, mr->kmrviz_trace);
1159  printf("[%05d] map_ms_use_exec=%d\n", r, mr->map_ms_use_exec);
1160  printf("[%05d] map_ms_abort_on_signal=%d\n", r, mr->map_ms_abort_on_signal);
1161  }
1162  return MPI_SUCCESS;
1163 }
1164 
1165 /* Set an option in KMR context as given by a key and a value. */
1166 
1167 int
1168 kmr_set_option_by_strings(KMR *mr, char *k, char *v)
1169 {
1170  int x;
1171  if (strcasecmp("log_traces", k) == 0) {
1172  if (kmr_parse_boolean(v, &x)) {
1173  if (mr->log_traces == 0) {
1174  kmr_open_log(mr);
1175  }
1176  } else {
1177  kmr_warning(mr, 1, "option log_traces be boolean");
1178  }
1179  } else if (strcasecmp("sort_threads_depth", k) == 0) {
1180  if (kmr_parse_int(v, &x) && x >= 0) {
1181  mr->sort_threads_depth = x;
1182  } else {
1183  kmr_warning(mr, 1, ("option sort_threads_depth be"
1184  " non-negative integer"));
1185  }
1186  } else if (strcasecmp("verbosity", k) == 0) {
1187  if (kmr_parse_int(v, &x) && (1 <= x && x <= 9)) {
1188  mr->verbosity = (uint8_t)x;
1189  } else {
1190  kmr_warning(mr, 1, "option verbosity be 1-9");
1191  }
1192  } else if (strcasecmp("k", k) == 0) {
1193  if (kmr_parse_boolean(v, &x)) {
1194  mr->onk = (_Bool)x;
1195  } else {
1196  kmr_warning(mr, 1, "option k be boolean");
1197  }
1198  } else if (strcasecmp("single_thread", k) == 0) {
1199  if (kmr_parse_boolean(v, &x)) {
1200  mr->single_thread = (_Bool)x;
1201  } else {
1202  kmr_warning(mr, 1, "option single_thread be boolean");
1203  }
1204  } else if (strcasecmp("step_sync", k) == 0) {
1205  if (kmr_parse_boolean(v, &x)) {
1206  mr->step_sync = (_Bool)x;
1207  } else {
1208  kmr_warning(mr, 1, "option step_sync be boolean");
1209  }
1210  } else if (strcasecmp("trace_file_io", k) == 0) {
1211  if (kmr_parse_boolean(v, &x)) {
1212  mr->trace_file_io = (_Bool)x;
1213  } else {
1214  kmr_warning(mr, 1, "option trace_file_io be boolean");
1215  }
1216  } else if (strcasecmp("trace_map_ms", k) == 0) {
1217  if (kmr_parse_boolean(v, &x)) {
1218  mr->trace_map_ms = (_Bool)x;
1219  } else {
1220  kmr_warning(mr, 1, "option trace_map_ms be boolean");
1221  }
1222  } else if (strcasecmp("trace_map_spawn", k) == 0) {
1223  if (kmr_parse_boolean(v, &x)) {
1224  mr->trace_map_spawn = (_Bool)x;
1225  } else {
1226  kmr_warning(mr, 1, "option trace_map_spawn be boolean");
1227  }
1228  } else if (strcasecmp("std_abort", k) == 0) {
1229  if (kmr_parse_boolean(v, &x)) {
1230  mr->std_abort = (_Bool)x;
1231  } else {
1232  kmr_warning(mr, 1, "option std_abort be boolean");
1233  }
1234  } else if (strcasecmp("trace_alltoall", k) == 0) {
1235  if (kmr_parse_boolean(v, &x)) {
1236  mr->trace_alltoall = (_Bool)x;
1237  } else {
1238  kmr_warning(mr, 1, "option trace_alltoall be boolean");
1239  }
1240  } else if (strcasecmp("atoa_threshold", k) == 0) {
1241  if (kmr_parse_int(v, &x) && x >= 0) {
1242  mr->atoa_threshold = x;
1243  } else {
1244  kmr_warning(mr, 1, ("option atoa_threshold be"
1245  " non-negative integer"));
1246  }
1247  } else if (strcasecmp("atoa_size_limit", k) == 0) {
1248  if (kmr_parse_int(v, &x) && x >= 0) {
1249  mr->atoa_size_limit = (long)x * 1024 * 1024;
1250  } else {
1251  kmr_warning(mr, 1, ("option atoa_size_limit be"
1252  " non-negative integer (in MB)"));
1253  }
1254  } else if (strcasecmp("atoa_requests_limit", k) == 0) {
1255  if (kmr_parse_int(v, &x) && x >= 0) {
1256  mr->atoa_requests_limit = x;
1257  } else {
1258  kmr_warning(mr, 1, ("option atoa_requests_limit be"
1259  " non-negative integer"));
1260  }
1261  } else if (strcasecmp("map_ms_use_exec", k) == 0) {
1262  if (kmr_parse_boolean(v, &x)) {
1263  mr->map_ms_use_exec = (_Bool)x;
1264  } else {
1265  kmr_warning(mr, 1, "option map_ms_use_exec be"
1266  " boolean");
1267  }
1268  } else if (strcasecmp("map_ms_abort_on_signal", k) == 0) {
1269  if (kmr_parse_boolean(v, &x)) {
1270  mr->map_ms_abort_on_signal = (_Bool)x;
1271  } else {
1272  kmr_warning(mr, 1, "option map_ms_abort_on_signal be"
1273  " boolean");
1274  }
1275  } else if (strcasecmp("spawn_max_processes", k) == 0) {
1276  if (kmr_parse_int(v, &x) && x >= 0) {
1277  mr->spawn_max_processes = x;
1278  } else {
1279  kmr_warning(mr, 1, ("option spawn_max_processes be"
1280  " non-negative integer"));
1281  }
1282  } else if (strcasecmp("spawn_retry_limit", k) == 0) {
1283  if (kmr_parse_int(v, &x) && x >= 0) {
1284  mr->spawn_retry_limit = x;
1285  } else {
1286  kmr_warning(mr, 1, ("option spawn_retry_limit be"
1287  " non-negative integer"));
1288  }
1289  } else if (strcasecmp("spawn_retry_gap_msec", k) == 0) {
1290  if (kmr_parse_int(v, &x) && x >= 0) {
1291  mr->spawn_retry_gap_msec = x;
1292  } else {
1293  kmr_warning(mr, 1, ("option spawn_retry_gap_msec be"
1294  " non-negative integer"));
1295  }
1296  } else if (strcasecmp("ckpt_enable", k) == 0) {
1297  if (kmr_parse_boolean(v, &x)) {
1298  mr->ckpt_enable = (_Bool)x;
1299  } else {
1300  kmr_warning(mr, 1, "option ckpt_enable be boolean");
1301  }
1302  } else if (strcasecmp("ckpt_selective", k) == 0) {
1303  if (kmr_parse_boolean(v, &x)) {
1304  mr->ckpt_selective = (_Bool)x;
1305  } else {
1306  kmr_warning(mr, 1, "option ckpt_selective be boolean");
1307  }
1308  } else if (strcasecmp("ckpt_no_fsync", k) == 0) {
1309  if (kmr_parse_boolean(v, &x)) {
1310  mr->ckpt_no_fsync = (_Bool)x;
1311  } else {
1312  kmr_warning(mr, 1, "option ckpt_no_fsync be boolean");
1313  }
1314  } else if (strcasecmp("pushoff_block_size", k) == 0) {
1315  size_t z;
1316  if (kmr_parse_size_t(v, &z)) {
1317  mr->pushoff_block_size = z;
1318  }
1319  } else if (strcasecmp("pushoff_poll_rate", k) == 0) {
1320  if (kmr_parse_int(v, &x)) {
1321  mr->pushoff_poll_rate = x;
1322  }
1323  } else if (strcasecmp("pushoff_fast_notice", k) == 0) {
1324  if (kmr_parse_boolean(v, &x)) {
1325  mr->pushoff_fast_notice = (_Bool)x;
1326  } else {
1327  kmr_warning(mr, 1, "option pushoff_fast_notice be boolean");
1328  }
1329  } else if (strcasecmp("kmrviz_trace", k) == 0) {
1330  if (kmr_parse_boolean(v, &x)) {
1331  mr->kmrviz_trace = (_Bool)x;
1332  } else {
1333  kmr_warning(mr, 1, "option kmrviz_trace be boolean");
1334  }
1335  } else if (strcasecmp("swf_spawner_library", k) == 0) {
1336  mr->swf_spawner_library = kmr_strdup(v);
1337  } else if (strcasecmp("swf_args_size", k) == 0) {
1338  size_t z;
1339  if (kmr_parse_size_t(v, &z)) {
1340  mr->swf_args_size = z;
1341  }
1342  } else if (strcasecmp("swf_exec_so", k) == 0) {
1343  if (kmr_parse_boolean(v, &x)) {
1344  mr->swf_exec_so = (_Bool)x;
1345  } else {
1346  kmr_warning(mr, 1, "option swf_exec_so be boolean");
1347  }
1348  } else if (strcasecmp("swf_record_history", k) == 0) {
1349  if (kmr_parse_boolean(v, &x)) {
1350  mr->swf_record_history = (_Bool)x;
1351  } else {
1352  kmr_warning(mr, 1, "option swf_record_history be boolean");
1353  }
1354  } else if (strcasecmp("swf_debug_master", k) == 0) {
1355  if (kmr_parse_boolean(v, &x)) {
1356  mr->swf_debug_master = (_Bool)x;
1357  } else {
1358  kmr_warning(mr, 1, "option swf_debug_master be boolean");
1359  }
1360  } else {
1361  char ee[80];
1362  snprintf(ee, 80, "option \"%s\" ignored", k);
1363  kmr_warning(mr, 1, ee);
1364  }
1365  return MPI_SUCCESS;
1366 }
1367 
1368 /* ================================================================ */
1369 
1370 /* Checks if a COMMAND is found. If SEARCH=true, it checks in the
1371  PATH directories. Or, it checks just existence of a file. MSG is
1372  a string prefixing to the trace messages. */
1373 
1374 static _Bool
1375 kmr_check_command_existence(KMR *mr, char *command, _Bool search, char *msg)
1376 {
1377  int cc;
1378  char ss[256];
1379  _Bool tracing7 = (mr->trace_map_spawn && (7 <= mr->verbosity));
1380  if (!search) {
1381  if (tracing7) {
1382  fprintf(stderr, (";;KMR [%05d] %s:"
1383  " checking a watch-program: %s\n"),
1384  mr->rank, msg, command);
1385  fflush(0);
1386  }
1387  do {
1388  cc = access(command, X_OK);
1389  } while (cc != 0 && errno == EINTR);
1390  if (cc != 0 && !(errno == ENOENT || errno == EACCES)) {
1391  char ee[80];
1392  char *m = strerror(errno);
1393  snprintf(ee, sizeof(ee), "access() returned: %s", m);
1394  kmr_warning(mr, 1, ee);
1395  }
1396  return (cc == 0);
1397  } else {
1398  _Bool fixed = 0;
1399  for (char *p = command; *p != 0; p++) {
1400  if (*p == '/') {
1401  fixed = 1;
1402  break;
1403  }
1404  }
1405  char *path = getenv("PATH");
1406  if (fixed || path == 0) {
1407  _Bool ok = kmr_check_command_existence(mr, command, 0, msg);
1408  return ok;
1409  }
1410  size_t s = strlen(path);
1411  char *buf = kmr_malloc(s + (size_t)1);
1412  memcpy(buf, path, (s + 1));
1413  _Bool ok = 0;
1414  char *prefix = buf;
1415  char *p = buf;
1416  while (p < &buf[s]) {
1417  while (p < &buf[s] && *p != ':') {
1418  p++;
1419  }
1420  if (*p == ':') {
1421  *p = 0;
1422  p++;
1423  } else {
1424  assert(*p == 0);
1425  }
1426  cc = snprintf(ss, sizeof(ss), "%s/%s", prefix, command);
1427  assert(cc < (int)sizeof(ss));
1428  ok = kmr_check_command_existence(mr, ss, 0, msg);
1429  if (ok) {
1430  break;
1431  }
1432  prefix = p;
1433  }
1434  kmr_free(buf, (s + 1));
1435  return ok;
1436  }
1437 }
1438 
1439 /* Assures a watch-program is available as a command, and returns a
1440  command string to it. It installs a new watch-program file in the
1441  home directory when it is not available. Home is taken from "HOME"
1442  or "PJM_JOBDIR". It works on the rank0 only. MSG is a string
1443  prefixing to the trace messages. */
1444 
1445 static char *
1446 kmr_install_watch_program_on_rank0(KMR *mr, char *msg)
1447 {
1448  char *name = "kmrwatch0";
1449  assert(mr->rank == 0);
1450  int cc;
1451  static char command[256];
1452  _Bool ok = 0;
1453  cc = snprintf(command, sizeof(command), "%s", name);
1454  assert(cc < (int)sizeof(command));
1455  ok = kmr_check_command_existence(mr, command, 1, msg);
1456  if (ok) {
1457  return command;
1458  }
1459  if (mr->kmr_installation_path != 0) {
1460  char *prefix = mr->kmr_installation_path;
1461  cc = snprintf(command, sizeof(command), "%s/bin/%s", prefix, name);
1462  assert(cc < (int)sizeof(command));
1463  ok = kmr_check_command_existence(mr, command, 0, msg);
1464  if (ok) {
1465  return command;
1466  }
1467  cc = snprintf(command, sizeof(command), "%s/lib/%s", prefix, name);
1468  assert(cc < (int)sizeof(command));
1469  ok = kmr_check_command_existence(mr, command, 0, msg);
1470  if (ok) {
1471  return command;
1472  }
1473  }
1474  if (mr->spawn_watch_prefix != 0) {
1475  char *prefix = mr->spawn_watch_prefix;
1476  cc = snprintf(command, sizeof(command), "%s/%s", prefix, name);
1477  assert(cc < (int)sizeof(command));
1478  ok = kmr_check_command_existence(mr, command, 0, msg);
1479  if (ok) {
1480  return command;
1481  }
1482  } else {
1483  char *prefix = 0;
1484  prefix = getenv("HOME");
1485  if (prefix == 0) {
1486  /* On K, HOME is not set but PJM_JOBDIR is. */
1487  prefix = getenv("PJM_JOBDIR");
1488  }
1489  if (prefix == 0) {
1490  kmr_error(mr, ("installing a watch-program:"
1491  " environment variable HOME not set."
1492  " Try setting spawn_watch_prefix"));
1493  }
1494  cc = snprintf(command, sizeof(command), "%s/%s", prefix, name);
1495  assert(cc < (int)sizeof(command));
1496  ok = kmr_check_command_existence(mr, command, 0, msg);
1497  if (ok) {
1498  return command;
1499  }
1500  }
1501 #if !defined(KMRBINEMBED)
1502  {
1503  cc = snprintf(command, sizeof(command), "%s", name);
1504  assert(cc < (int)sizeof(command));
1505  return command;
1506  }
1507 #else /*KMRBINEMBEDH*/
1508  {
1509  extern unsigned char kmr_binary_kmrwatch0_start[];
1510  extern unsigned char *kmr_binary_kmrwatch0_end;
1511  extern unsigned long kmr_binary_kmrwatch0_size;
1512  char *p0 = (void *)kmr_binary_kmrwatch0_start;
1513  char *p1 = (void *)kmr_binary_kmrwatch0_end;
1514  size_t sz = kmr_binary_kmrwatch0_size;
1515  assert((p1 - p0) == (long)sz);
1516  int fd;
1517  do {
1518  mode_t mode = (S_IRWXU|S_IRWXG|S_IRWXO);
1519  fd = open(command, (O_WRONLY|O_CREAT|O_TRUNC), mode);
1520  } while (fd == -1 && errno == EINTR);
1521  if (fd == -1) {
1522  char ee[160];
1523  char *m = strerror(errno);
1524  snprintf(ee, sizeof(ee), "open(%s): %s", command, m);
1525  kmr_error(mr, ee);
1526  }
1527  size_t ss = 0;
1528  while (ss < sz) {
1529  ssize_t xx = write(fd, &p0[ss], (sz - ss));
1530  if (xx == -1) {
1531  char ee[160];
1532  char *m = strerror(errno);
1533  snprintf(ee, sizeof(ee), "write(%s): %s", command, m);
1534  kmr_error(mr, ee);
1535  }
1536  if (xx == 0) {
1537  char ee[160];
1538  snprintf(ee, sizeof(ee), "write(%s): write by zero size",
1539  command);
1540  kmr_error(mr, ee);
1541  }
1542  ss += (size_t)xx;
1543  }
1544  cc = close(fd);
1545  assert(cc == 0);
1546  char ee[80];
1547  snprintf(ee, sizeof(ee),
1548  "a watch-program for spawning has been installed (%s)",
1549  command);
1550  kmr_warning(mr, 5, ee);
1551  return command;
1552  }
1553 #endif /*KMRBINEMBED*/
1554 }
1555 
1556 /* Assures a watch-program is available as a command, and stores its
1557  file name in the context as SPAWN_WATCH_PROGRAM. */
1558 
1559 int
1560 kmr_install_watch_program(KMR *mr, char *msg)
1561 {
1562  int cc;
1563  if (mr->spawn_watch_program == 0) {
1564  KMR_KVS *kvs0 = kmr_create_kvs(mr, KMR_KV_OPAQUE, KMR_KV_OPAQUE);
1565  if (mr->rank == 0) {
1566  char *command = kmr_install_watch_program_on_rank0(mr, msg);
1567  assert(command != 0 && command[0] != 0);
1568  cc = kmr_add_string(kvs0, "", command);
1569  assert(cc == MPI_SUCCESS);
1570  }
1571  cc = kmr_add_kv_done(kvs0);
1572  assert(cc == MPI_SUCCESS);
1573  KMR_KVS *kvs1 = kmr_create_kvs(mr, KMR_KV_OPAQUE, KMR_KV_OPAQUE);
1574  cc = kmr_replicate(kvs0, kvs1, kmr_noopt);
1575  assert(cc == MPI_SUCCESS);
1576  struct kmr_kv_box kv;
1577  cc = kmr_take_one(kvs1, &kv);
1578  assert(cc == MPI_SUCCESS);
1579  char *b = kmr_malloc((size_t)kv.vlen);
1580  memcpy(b, kv.v.p, (size_t)kv.vlen);
1581  mr->spawn_watch_program = b;
1582  cc = kmr_free_kvs(kvs1);
1583  assert(cc == MPI_SUCCESS);
1584  }
1585  return MPI_SUCCESS;
1586 }
1587 
1588 /* ================================================================ */
1589 
1590 /* DUMPERS */
1591 
1592 /** Puts the string of the key or value field into a buffer BUF as
1593  printable string. */
1594 
1595 void
1596 kmr_dump_opaque(const char *p, int sz, char *buf, int buflen)
1597 {
1598  /* PRINTABLE indicates the content consists of printable
1599  characters (=1), printable characters but terminated in the
1600  middle (=2), or includes unprintable characters (=0). */
1601 
1602  int printable = 1;
1603  int seezero = 0;
1604  for (int i = 0; i < sz; i++) {
1605  if (p[i] == 0) {
1606  seezero = 1;
1607  } else if (!isprint((unsigned char)p[i])) {
1608  /* (Unprintable appears). */
1609  printable = 0;
1610  break;
1611  } else {
1612  if (seezero && printable == 1) {
1613  /* (null appears in the middle). */
1614  printable = 2;
1615  }
1616  }
1617  }
1618  if (printable == 1) {
1619  int z = (int)strnlen(p, (size_t)sz);
1620  int n = MIN(z, ((int)buflen - 5 - 1));
1621  snprintf(buf, (size_t)2, "\"");
1622  snprintf((buf + 1), (size_t)(n + 1), "%s", p);
1623  if (z == n) {
1624  snprintf((buf + n + 1), (size_t)2, "\"");
1625  buf[n + 2] = 0;
1626  } else {
1627  snprintf((buf + n + 1), (size_t)5, "...\"");
1628  buf[(n + 5)] = 0;
1629  }
1630  } else if (printable == 2) {
1631  int z = (int)strnlen(p, (size_t)sz);
1632  int n = MIN(z, (buflen - 5 - 1));
1633  snprintf(buf, (size_t)2, "\"");
1634  snprintf((buf + 1), (size_t)(n + 1), "%s", p);
1635  if (z == n) {
1636  snprintf((buf + n + 1), (size_t)5, "???\"");
1637  buf[(n + 5)] = 0;
1638  } else {
1639  snprintf((buf + n + 1), (size_t)5, "...\"");
1640  buf[(n + 5)] = 0;
1641  }
1642  } else {
1643  int n = MIN(sz, ((buflen - 3 - 1) / 3));
1644  char *q = buf;
1645  for (int i = 0; i < n; i++) {
1646  snprintf(q, 4, "%02x ", (p[i] & 0xff));
1647  q += 3;
1648  }
1649  if (n != sz) {
1650  snprintf(q, 4, "...");
1651  }
1652  }
1653 }
1654 
1655 void
1656 kmr_dump_slot(union kmr_unit_sized e, int len, enum kmr_kv_field data,
1657  char *buf, int buflen)
1658 {
1659  switch (data) {
1660  case KMR_KV_BAD:
1661  assert(data != KMR_KV_BAD);
1662  break;
1663  case KMR_KV_INTEGER:
1664  snprintf(buf, (size_t)buflen, "%ld", e.i);
1665  break;
1666  case KMR_KV_FLOAT8:
1667  snprintf(buf, (size_t)buflen, "%e", e.d);
1668  break;
1669  case KMR_KV_OPAQUE:
1670  case KMR_KV_CSTRING:
1671  case KMR_KV_POINTER_OWNED:
1672  case KMR_KV_POINTER_UNMANAGED:
1673  kmr_dump_opaque(e.p, len, buf, buflen);
1674  break;
1675  default:
1676  assert(NEVERHERE);
1677  break;
1678  }
1679 }
1680 
1681 /** Dumps contents of a key-value. */
1682 
1683 int
1684 kmr_dump_kv(const struct kmr_kv_box kv, const KMR_KVS *kvs,
1685  char *buf, int buflen)
1686 {
1687  char kbuf[48], vbuf[48];
1688  kmr_dump_slot(kv.k, kv.klen, kvs->c.key_data, kbuf, sizeof(kbuf));
1689  kmr_dump_slot(kv.v, kv.vlen, kvs->c.value_data, vbuf, sizeof(vbuf));
1690  snprintf(buf, (size_t)buflen, "k[%d]=%s;v[%d]=%s", kv.klen, kbuf, kv.vlen, vbuf);
1691  return MPI_SUCCESS;
1692 }
1693 
1694 static int
1695 kmr_dump_kvs_fn(const struct kmr_kv_box kv,
1696  const KMR_KVS *kvs, KMR_KVS *kvso, void *p, const long i)
1697 {
1698  char b[80];
1699  kmr_dump_kv(kv, kvs, b, sizeof(b));
1700  printf("[%05d][%ld] %s\n", kvs->c.mr->rank, i, b);
1701  return MPI_SUCCESS;
1702 }
1703 
1704 /** Dumps contents of a KVS to stdout. Argument FLAG is nothing, and
1705  ignored. It prints each content as a string or as a hex-dump.
1706  Each content is truncated to 45 characters. Ellipses may appear
1707  if the content is truncated, or, "???" appears if the content is a
1708  string but includes null in the middle. */
1709 
1710 int
1711 kmr_dump_kvs(KMR_KVS *kvs, int flag)
1712 {
1713  assert(kvs->c.magic != KMR_KVS_BAD);
1714  int rank = kvs->c.mr->rank;
1715  printf("[%05d] element_count=%ld\n", rank, kvs->c.element_count);
1716  struct kmr_option opt = {.inspect = 1, .nothreading = 1};
1717  int kcdc = kmr_ckpt_disable_ckpt(kvs->c.mr);
1718  int cc = kmr_map_rank_by_rank(kvs, 0, 0, opt, kmr_dump_kvs_fn);
1719  assert(cc == MPI_SUCCESS);
1720  kmr_ckpt_enable_ckpt(kvs->c.mr, kcdc);
1721  return MPI_SUCCESS;
1722 }
1723 
1724 #if 0
1725 static int
1726 kmr_dump_kvs2_fn(const struct kmr_kv_box kv,
1727  const KMR_KVS *kvs, KMR_KVS *kvso, void *p, const long i)
1728 {
1729  char kbuf[48], vbuf[48];
1730  assert(kvs->c.magic != KMR_KVS_BAD);
1731  int rank = kvs->c.mr->rank;
1732  kmr_dump_slot(kv.k, kv.klen, kvs->c.key_data, kbuf, sizeof(kbuf));
1733  //kmr_dump_slot(kv.v, kv.vlen, , vbuf, sizeof(vbuf));
1734  printf("[%05d] k[%d]=%s;v[%d]=%s\n", rank, kv.klen, kbuf, kv.vlen, vbuf);
1735  return MPI_SUCCESS;
1736 }
1737 #endif
1738 
1739 /** Dumps contents of a key-value stream, with values are pairs. */
1740 
1741 #if 0
1742 static int
1743 kmr_dump_kvs_pair_value(KMR_KVS *kvs, int flag)
1744 {
1745  assert(kvs->c.magic != KMR_KVS_BAD);
1746  assert(kvs->c.value_data == KMR_KV_OPAQUE
1747  || kvs->c.value_data == KMR_KV_CSTRING);
1748  int rank = kvs->c.mr->rank;
1749  printf("[%05d] element_count=%ld\n", rank, kvs->c.element_count);
1750  struct kmr_option opt = {.inspect = 1};
1751  int cc = kmr_map_rank_by_rank(kvs, 0, 0, opt, kmr_dump_kvs2_fn);
1752  assert(cc == MPI_SUCCESS);
1753  return MPI_SUCCESS;
1754 }
1755 #endif
1756 
1757 /** Prints the total number of key-value pairs. It prints on the
1758  rank0 only. */
1759 
1760 int
1761 kmr_dump_kvs_stats(KMR_KVS *kvs, int level)
1762 {
1763  long v;
1764  kmr_get_element_count(kvs, &v);
1765  if (kvs->c.mr->rank == 0) {
1766  printf("element_count=%ld\n", v);
1767  }
1768  return MPI_SUCCESS;
1769 }
1770 
1771 int
1772 kmr_dump_keyed_records(const struct kmr_keyed_record *ev, KMR_KVS *kvi)
1773 {
1774  long cnt = kvi->c.element_count;
1775  for (long i = 0; i < cnt; i++) {
1776  int rank = kvi->c.mr->rank;
1777  char kbuf[48], vbuf[48];
1778  struct kmr_kv_box kv = kmr_pick_kv(ev[i].e, kvi);
1779  kmr_dump_slot(kv.k, kv.klen, kvi->c.key_data, kbuf, sizeof(kbuf));
1780  kmr_dump_slot(kv.v, kv.vlen, kvi->c.value_data, vbuf, sizeof(vbuf));
1781  printf("[%05d] h=%ld;k[%d]=%s;v[%d]=%s\n", rank,
1782  ev[i].v, kv.klen, kbuf, kv.vlen, vbuf);
1783  }
1784  return MPI_SUCCESS;
1785 }
1786 
1787 void
1788 kmr_print_options(struct kmr_option opt)
1789 {
1790  printf(".nothreading=%d,"
1791  " .inspect=%d,"
1792  " .keep_open=%d,"
1793  " .key_as_rank=%d,"
1794  " .rank_zero=%d,"
1795  " .take_ckpt=%d,"
1796  " .collapse=%d\n",
1797  opt.nothreading,
1798  opt.inspect,
1799  opt.keep_open,
1800  opt.key_as_rank,
1801  opt.rank_zero,
1802  opt.collapse,
1803  opt.take_ckpt);
1804 }
1805 
1806 void
1807 kmr_print_file_options(struct kmr_file_option opt)
1808 {
1809  printf(".each_rank=%d,"
1810  " .subdirectories=%d,"
1811  " .list_file=%d,"
1812  " .shuffle_names=%d\n",
1813  opt.each_rank,
1814  opt.subdirectories,
1815  opt.list_file,
1816  opt.shuffle_names);
1817 }
1818 
1819 void
1820 kmr_print_spawn_options(struct kmr_spawn_option opt)
1821 {
1822  printf((".separator_space=%d,"
1823  " .reply_each=%d,"
1824  " .reply_root=%d,"
1825  /*" .one_by_one=%d,"*/
1826  " .no_set_infos=%d,"
1827  " .take_ckpt=%d\n"),
1828  opt.separator_space,
1829  opt.reply_each,
1830  opt.reply_root,
1831  /*opt.one_by_one,*/
1832  opt.no_set_infos,
1833  opt.take_ckpt);
1834 }
1835 
1836 void
1837 kmr_print_string(char *msg, char *s, int len)
1838 {
1839  /* LEN includes terminating zero. */
1840  assert(len >= 1);
1841  printf("%s(len=%d)=", msg, len);
1842  for (int i = 0; i < len; i++) {
1843  if (s[i] == 0) {
1844  printf("$");
1845  } else if (isblank(s[i])) {
1846  printf("_");
1847  } else if (isprint(s[i])) {
1848  printf("%c", s[i]);
1849  } else {
1850  printf("?");
1851  }
1852  }
1853  printf("\n");
1854 }
1855 
1856 /** Fills the string buffer with the argv strings for printing. */
1857 
1858 int
1859 kmr_make_printable_argv_string(char *s, size_t sz, char **argv)
1860 {
1861  assert(sz > 4);
1862 
1863  int cc;
1864 
1865  *s = 0;
1866 
1867  size_t cnt;
1868  cnt = 0;
1869  for (int i = 0; argv[i] != 0; i++) {
1870  cc = snprintf(&s[cnt], (sz - cnt), "%s%s",
1871  (i == 0 ? "" : ","), argv[i]);
1872  cnt += (size_t)cc;
1873  if (cnt >= sz) {
1874  snprintf(&s[sz - 4], 4, "...");
1875  return 0;
1876  }
1877  }
1878  return 0;
1879 }
1880 
1881 /** Fills the string buffer with the MPI_Info strings for printing. */
1882 
1883 int
1884 kmr_make_printable_info_string(char *s, size_t sz, MPI_Info info)
1885 {
1886  assert(sz > 4);
1887 
1888  char key[MPI_MAX_INFO_KEY + 1];
1889  char value[MPI_MAX_INFO_VAL + 1];
1890  int cc;
1891 
1892  /* Clear string in case INFO is empty. */
1893 
1894  *s = 0;
1895 
1896  int nkeys;
1897  cc = MPI_Info_get_nkeys(info, &nkeys);
1898  assert(cc == MPI_SUCCESS);
1899 
1900  size_t cnt;
1901  cnt = 0;
1902  for (int i = 0; i < nkeys; i++) {
1903  cc = MPI_Info_get_nthkey(info, i, key);
1904  assert(cc == MPI_SUCCESS);
1905  key[MPI_MAX_INFO_KEY] = 0;
1906  int flag;
1907  cc = MPI_Info_get(info, key, MPI_MAX_INFO_VAL, value, &flag);
1908  assert(cc == MPI_SUCCESS && flag != 0);
1909  value[MPI_MAX_INFO_VAL] = 0;
1910  cc = snprintf(&s[cnt], (sz - cnt), "%s%s=%s",
1911  (i == 0 ? "" : ","), key, value);
1912  cnt += (size_t)cc;
1913  if (cnt >= sz) {
1914  snprintf(&s[sz - 4], 4, "...");
1915  return 0;
1916  }
1917  }
1918  return 0;
1919 }
1920 
1921 /* Opens a file for trace logging. */
1922 
1923 void
1924 kmr_open_log(KMR *mr)
1925 {
1926  assert(mr->log_traces == 0);
1927  int cc;
1928  char file[256];
1929  cc = snprintf(file, sizeof(file), "./%s_%05d",
1930  KMR_TRACE_FILE_PREFIX, mr->rank);
1931  assert(cc < (int)sizeof(file));
1932  mr->log_traces = fopen(file, "w");
1933  if (mr->log_traces == 0) {
1934  char ee[80];
1935  char *m = strerror(errno);
1936  snprintf(ee, sizeof(ee),
1937  "Opening log file (%s) failed"
1938  " (disable tracing): %s",
1939  file, m);
1940  kmr_warning(mr, 1, ee);
1941  mr->log_traces = 0;
1942  }
1943  if (mr->log_traces != 0) {
1944  time_t ct = time(0);
1945  char *cs = ctime(&ct);
1946  fprintf(mr->log_traces, "kmr trace (%s)\n", cs);
1947  }
1948 }
1949 
1950 /* Trace Logging. */
1951 
1952 void
1953 kmr_log_map(KMR *mr, KMR_KVS *kvs, struct kmr_kv_box *ev,
1954  long i, long cnt, kmr_mapfn_t m, double dt)
1955 {
1956  assert(mr->log_traces != 0);
1957  if (mr->atwork != 0) {
1958  struct kmr_code_line *info = mr->atwork;
1959  char s[32];
1960  kmr_dump_slot(ev->k, ev->klen, kvs->c.key_data, s, sizeof(s));
1961  fprintf(mr->log_traces,
1962  "file:%s, line:%d, kmr_func:%s,"
1963  " user_func:%p, key:[%ld/%ld]%s, time:%.lf\n",
1964  info->file, info->line, info->func,
1965  (void *)(intptr_t)m, (i + 1), cnt, s, (dt * 1000.0));
1966  }
1967 }
1968 
1969 /* Trace Logging. */
1970 
1971 void
1972 kmr_log_reduce(KMR *mr, KMR_KVS *kvs, struct kmr_kv_box *ev,
1973  long n, kmr_redfn_t r, double dt)
1974 {
1975  assert(mr->log_traces != 0);
1976  if (mr->atwork != 0) {
1977  struct kmr_code_line *info = mr->atwork;
1978  char s[32];
1979  kmr_dump_slot(ev->k, ev->klen, kvs->c.key_data, s, sizeof(s));
1980  fprintf(mr->log_traces,
1981  "file:%s, line:%d, kmr_func:%s,"
1982  " user_func:%p, key:[%ld]%s, time:%.lf\n",
1983  info->file, info->line, info->func,
1984  (void *)(intptr_t)r, n, s, (dt * 1000.0));
1985  }
1986 }
1987 
1988 /* ================================================================ */
1989 
1990 /* CONFIGURATION */
1991 
1992 /* Puts property into MPI_Info. B points to the key, and &B[VALPOS]
1993  points to the value. END points to one past the 0-terminator. */
1994 
1995 static int
1996 kmr_put_property(MPI_Info info, char *b, int valpos, int end)
1997 {
1998  char *k = b;
1999  char *v = &b[valpos];
2000  /*printf("setting \"%s\"=\"%s\"\n", b, &b[valpos]);*/
2001  if (k[0] == 0) {
2002  kmr_warning(0, 5, "empty key string for MPI_Info_set(), ignored");
2003  } else if (v[0] == 0) {
2004  /* OPEN MPI (1.6.4) DOES NOT ALLOW EMPTY VALUE. */
2005  kmr_warning(0, 5, "empty value string for MPI_Info_set(), ignored");
2006  } else {
2007  int cc = MPI_Info_set(info, b, &b[valpos]);
2008  assert(cc == MPI_SUCCESS);
2009  }
2010  return MPI_SUCCESS;
2011 }
2012 
2013 /** Loads properties into MPI_Info (in Latin1 characters). It runs
2014  only on the main-thread. It returns MPI_SUCCESS normally. It
2015  stores only Latin1 strings because MPI_Info does. Refer to the
2016  JDK document "java.util.Properties.load()" for the ".properties"
2017  format. */
2018 
2019 int
2020 kmr_load_properties(MPI_Info info, char *filename)
2021 {
2022 #define CONTNL 0x010000
2023 #define kmr_load_properties_check_getc_error(C) \
2024  if ((C) == EOF && errno != 0) { \
2025  char *e = strerror(errno); \
2026  snprintf(ee, sizeof(ee), "loading properties (%s), fgetc(): %s", \
2027  filename, e); \
2028  kmr_warning(0, 1, ee); \
2029  fclose(f); \
2030  free(b); \
2031  return MPI_ERR_ARG; \
2032  }
2033 #define kmr_load_properties_reset() \
2034  {pos = -1; valpos = -1; scan = ForKey;}
2035 #define kmr_load_properties_grow() \
2036  if (pos >= (blen - 1)) { \
2037  blen *= 2; b = realloc(b, (size_t)blen); assert(b != 0); }
2038 #define kmr_load_properties_putc(C) { \
2039  assert(pos != -1); \
2040  b[pos++] = (char)(C); kmr_load_properties_grow(); }
2041 #define kmr_load_properties_hex(C) \
2042  (('0' <= (C) && (C) <= '9') \
2043  ? ((C) - '0') \
2044  : (('a' <= (C) && (C) <= 'f') \
2045  ? ((C) - 'a') : ((C) - 'A')))
2046 #define kmr_load_properties_replace_cr() \
2047  if (c == '\r') { \
2048  int c1 = kmr_fgetc(f); \
2049  kmr_load_properties_check_getc_error(c1); \
2050  if (c1 != '\n') { \
2051  ungetc(c1, f); \
2052  } \
2053  c = '\n'; \
2054  }
2055 
2056  char ee[160];
2057  int blen = 4096;
2058  char *b = kmr_malloc((size_t)blen);
2059 
2060  FILE *f = kmr_fopen(filename, "r");
2061  if (f == 0) {
2062  char *e = strerror(errno);
2063  char *cwd = getcwd(b, 64);
2064  snprintf(ee, sizeof(ee), "loading properties, fopen(%s): %s (cwd=%s)",
2065  filename, e, (cwd == 0 ? "?" : cwd));
2066  kmr_warning(0, 1, ee);
2067  return MPI_ERR_ARG;
2068  }
2069 
2070  errno = 0;
2071  enum {ForKey, Com, Key, KeySkp, ForSep, ForVal, Val, ValSkp} scan = ForKey;
2072  int pos = -1;
2073  int valpos = -1;
2074  kmr_load_properties_reset();
2075  int lines = 0;
2076 
2077  for (;;) {
2078  _Bool escaped = 0;
2079  int c = kmr_fgetc(f);
2080  kmr_load_properties_check_getc_error(c);
2081  if (c == EOF) {
2082  switch (scan) {
2083  case ForKey:
2084  assert(pos == -1 && valpos == -1);
2085  break;
2086  case Com:
2087  assert(pos == -1 && valpos == -1);
2088  break;
2089  case Key: case KeySkp:
2090  assert(pos != -1 && valpos == -1);
2091  kmr_put_property(info, b, valpos, pos);
2092  break;
2093  case ForSep: case ForVal: case Val: case ValSkp:
2094  assert(pos != -1 && valpos != -1);
2095  kmr_put_property(info, b, valpos, pos);
2096  break;
2097  }
2098  break;
2099  }
2100 
2101  /* Replace '\r\n' as a single '\n'. */
2102  kmr_load_properties_replace_cr();
2103 
2104  switch (c) {
2105  case '\\':
2106  {
2107  /* Look at a backslash. */
2108  escaped = 1;
2109  c = kmr_fgetc(f);
2110  kmr_load_properties_check_getc_error(c);
2111  if (c == EOF) {
2112  snprintf(ee, sizeof(ee),
2113  ("loading properties (%s),"
2114  " file ends with a backslash"), filename);
2115  kmr_warning(0, 1, ee);
2116  fclose(f);
2117  free(b);
2118  return MPI_ERR_ARG;
2119  }
2120  switch (c) {
2121  case '\n':
2122  lines++;
2123  c = CONTNL;
2124  break;
2125 
2126  case 'n': case 'r': case 't': case 'f':
2127  switch (c) {
2128  case 'n': c = '\n'; break;
2129  case 'r': c = '\r'; break;
2130  case 't': c = '\t'; break;
2131  case 'f': c = '\f'; break;
2132  }
2133  break;
2134 
2135  case 'u':
2136  {
2137  int c0 = kmr_fgetc(f);
2138  int c1 = kmr_fgetc(f);
2139  int c2 = kmr_fgetc(f);
2140  int c3 = kmr_fgetc(f);
2141  if (c1 == EOF || c2 == EOF || c3 == EOF) {
2142  if (errno != 0) {
2143  char *e = strerror(errno);
2144  snprintf(ee, sizeof(ee),
2145  ("loading properties (%s),"
2146  " fgetc(): %s"),
2147  filename, e);
2148  kmr_warning(0, 1, ee);
2149  fclose(f);
2150  free(b);
2151  return MPI_ERR_ARG;
2152  } else {
2153  snprintf(ee, sizeof(ee),
2154  ("loading properties (%s),"
2155  " file ends amid unicode (at line %d)"),
2156  filename, (lines + 1));
2157  kmr_warning(0, 1, ee);
2158  fclose(f);
2159  free(b);
2160  return MPI_ERR_ARG;
2161  }
2162  }
2163  if (!(isxdigit(c0) && isxdigit(c1)
2164  && isxdigit(c2) && isxdigit(c3))) {
2165  snprintf(ee, sizeof(ee),
2166  ("loading properties (%s),"
2167  " file includes bad character"
2168  " in unicode (at line %d)"),
2169  filename, (lines + 1));
2170  kmr_warning(0, 1, ee);
2171  fclose(f);
2172  free(b);
2173  return MPI_ERR_ARG;
2174  }
2175  c = (kmr_load_properties_hex(c0) << 12);
2176  c |= (kmr_load_properties_hex(c1) << 8);
2177  c |= (kmr_load_properties_hex(c2) << 4);
2178  c |= kmr_load_properties_hex(c3);
2179  assert(c >= 0);
2180  if (c >= 256) {
2181  snprintf(ee, sizeof(ee),
2182  ("loading properties (%s),"
2183  " file includes non-latin character"
2184  " in unicode (at line %d)"),
2185  filename, (lines + 1));
2186  kmr_warning(0, 1, ee);
2187  fclose(f);
2188  free(b);
2189  return MPI_ERR_ARG;
2190  }
2191  }
2192  break;
2193 
2194  default:
2195  break;
2196  }
2197 
2198  if (c == CONTNL) {
2199  switch (scan) {
2200  case ForKey:
2201  assert(pos == -1 && valpos == -1);
2202  break;
2203  case Com:
2204  assert(pos == -1 && valpos == -1);
2205  scan = ForKey;
2206  break;
2207  case Key: case KeySkp:
2208  assert(pos != -1 && valpos == -1);
2209  scan = KeySkp;
2210  break;
2211  case ForSep: case ForVal:
2212  assert(pos != -1 && valpos != -1);
2213  break;
2214  case Val: case ValSkp:
2215  assert(pos != -1 && valpos != -1);
2216  scan = ValSkp;
2217  break;
2218  }
2219  break;
2220  }
2221  }
2222  /*FALLTHRU*/
2223  /* Fall thru with reading c as an ordinary character. */
2224 
2225  default:
2226  /* Look at an ordinary character. */
2227  /* (c is not in {CONTNL, " \n\t\f#!=:"}) */
2228  if (iscntrl(c) && !escaped) {
2229  snprintf(ee, sizeof(ee),
2230  ("loading properties (%s),"
2231  " file includes bad control code (at line %d)"),
2232  filename, (lines + 1));
2233  kmr_warning(0, 1, ee);
2234  fclose(f);
2235  free(b);
2236  return MPI_ERR_ARG;
2237  }
2238  switch (scan) {
2239  case ForKey:
2240  assert(pos == -1 && valpos == -1);
2241  pos = 0;
2242  kmr_load_properties_putc(c);
2243  scan = Key;
2244  break;
2245  case Com:
2246  assert(pos == -1 && valpos == -1);
2247  /*skip*/
2248  break;
2249  case Key: case KeySkp:
2250  assert(pos != -1 && valpos == -1);
2251  kmr_load_properties_putc(c);
2252  scan = Key;
2253  break;
2254  case ForSep: case ForVal: case Val: case ValSkp:
2255  assert(pos != -1 && valpos != -1);
2256  kmr_load_properties_putc(c);
2257  scan = Val;
2258  break;
2259  }
2260  break;
2261 
2262  case '\n':
2263  lines++;
2264  switch (scan) {
2265  case ForKey:
2266  assert(pos == -1 && valpos == -1);
2267  /*skip*/
2268  break;
2269  case Com:
2270  assert(pos == -1 && valpos == -1);
2271  scan = ForKey;
2272  break;
2273  case Key: case KeySkp:
2274  assert(pos != -1 && valpos == -1);
2275  kmr_load_properties_putc('\0');
2276  valpos = pos;
2277  kmr_load_properties_putc('\0');
2278  kmr_put_property(info, b, valpos, pos);
2279  kmr_load_properties_reset();
2280  break;
2281  case ForSep: case ForVal: case Val: case ValSkp:
2282  assert(pos != -1 && valpos != -1);
2283  kmr_load_properties_putc('\0');
2284  kmr_put_property(info, b, valpos, pos);
2285  kmr_load_properties_reset();
2286  break;
2287  }
2288  break;
2289 
2290  case ' ': case '\t': case '\f':
2291  switch (scan) {
2292  case ForKey:
2293  assert(pos == -1 && valpos == -1);
2294  break;
2295  case Com:
2296  assert(pos == -1 && valpos == -1);
2297  break;
2298  case Key:
2299  assert(pos != -1 && valpos == -1);
2300  kmr_load_properties_putc('\0');
2301  valpos = pos;
2302  scan = ForSep;
2303  break;
2304  case KeySkp:
2305  assert(pos != -1 && valpos == -1);
2306  break;
2307  case ForSep: case ForVal:
2308  assert(pos != -1 && valpos != -1);
2309  break;
2310  case Val:
2311  assert(pos != -1 && valpos != -1);
2312  kmr_load_properties_putc(c);
2313  break;
2314  case ValSkp:
2315  assert(pos != -1 && valpos != -1);
2316  break;
2317  }
2318  break;
2319 
2320  case '#': case '!':
2321  switch (scan) {
2322  case ForKey:
2323  assert(pos == -1 && valpos == -1);
2324  scan = Com;
2325  break;
2326  case Com:
2327  assert(pos == -1 && valpos == -1);
2328  break;
2329  case Key: case KeySkp:
2330  assert(pos != -1 && valpos == -1);
2331  kmr_load_properties_putc(c);
2332  scan = Key;
2333  break;
2334  case ForSep: case ForVal: case Val: case ValSkp:
2335  assert(pos != -1 && valpos != -1);
2336  kmr_load_properties_putc(c);
2337  scan = Val;
2338  break;
2339  }
2340  break;
2341 
2342  case '=': case ':':
2343  switch (scan) {
2344  case ForKey:
2345  assert(pos == -1 && valpos == -1);
2346  pos = 0;
2347  kmr_load_properties_putc('\0');
2348  valpos = pos;
2349  scan = ForVal;
2350  break;
2351  case Com:
2352  assert(pos == -1 && valpos == -1);
2353  break;
2354  case Key: case KeySkp:
2355  assert(pos != -1 && valpos == -1);
2356  kmr_load_properties_putc('\0');
2357  valpos = pos;
2358  scan = ForVal;
2359  break;
2360  case ForSep:
2361  assert(pos != -1 && valpos != -1);
2362  scan = ForVal;
2363  break;
2364  case ForVal: case Val: case ValSkp:
2365  assert(pos != -1 && valpos != -1);
2366  kmr_load_properties_putc(c);
2367  scan = Val;
2368  break;
2369  }
2370  break;
2371  }
2372  }
2373 
2374  fclose(f);
2375  free(b);
2376  return MPI_SUCCESS;
2377 }
2378 
2379 /** Dumps simply contents in MPI_Info. */
2380 
2381 int
2382 kmr_dump_mpi_info(char *prefix, MPI_Info info)
2383 {
2384  int cc;
2385  int nkeys;
2386  cc = MPI_Info_get_nkeys(info, &nkeys);
2387  assert(cc == MPI_SUCCESS);
2388  for (int i = 0; i < nkeys; i++) {
2389  char key[MPI_MAX_INFO_KEY + 1];
2390  char value[MPI_MAX_INFO_VAL + 1];
2391  int vlen;
2392  int flag;
2393  cc = MPI_Info_get_nthkey(info, i, key);
2394  assert(cc == MPI_SUCCESS);
2395  cc = MPI_Info_get_valuelen(info, key, &vlen, &flag);
2396  assert(cc == MPI_SUCCESS && flag != 0);
2397  assert(vlen <= MPI_MAX_INFO_VAL);
2398  cc = MPI_Info_get(info, key, MPI_MAX_INFO_VAL, value, &flag);
2399  assert(cc == MPI_SUCCESS && flag != 0);
2400  printf("%s \"%s\"=\"%s\"\n", prefix, key, value);
2401  }
2402  return MPI_SUCCESS;
2403 }
2404 
2405 /** Copies contents of MPI_Info. The destination info is modified. */
2406 
2407 int
2408 kmr_copy_mpi_info(MPI_Info src, MPI_Info dst)
2409 {
2410  int cc;
2411  int nkeys;
2412  cc = MPI_Info_get_nkeys(src, &nkeys);
2413  assert(cc == MPI_SUCCESS);
2414  for (int i = 0; i < nkeys; i++) {
2415  char key[MPI_MAX_INFO_KEY + 1];
2416  char value[MPI_MAX_INFO_VAL + 1];
2417  int vlen;
2418  int flag;
2419  cc = MPI_Info_get_nthkey(src, i, key);
2420  assert(cc == MPI_SUCCESS);
2421  cc = MPI_Info_get_valuelen(src, key, &vlen, &flag);
2422  assert(cc == MPI_SUCCESS && flag != 0);
2423  assert(vlen <= MPI_MAX_INFO_VAL);
2424  cc = MPI_Info_get(src, key, MPI_MAX_INFO_VAL, value, &flag);
2425  assert(cc == MPI_SUCCESS && flag != 0);
2426  /*printf("\"%s\"=\"%s\"\n", key, value);*/
2427  cc = MPI_Info_set(dst, key, value);
2428  assert(cc == MPI_SUCCESS);
2429  }
2430  return MPI_SUCCESS;
2431 }
2432 
2433 /*
2434 Copyright (C) 2012-2018 RIKEN R-CCS
2435 This library is distributed WITHOUT ANY WARRANTY. This library can be
2436 redistributed and/or modified under the terms of the BSD 2-Clause License.
2437 */
Key-Value Stream (abstract).
Definition: kmr.h:632
char * kmr_stringify_options(struct kmr_option o)
Returns a print string of a single option, to check the bits are properly encoded in foreign language...
Definition: kmrutil.c:361
int kmr_local_element_count(KMR_KVS *kvs, long *v)
Gets the number of key-value pairs locally on each rank.
Definition: kmrutil.c:349
Utilities Private Part (do not include from applications).
Options to Mapping, Shuffling, and Reduction.
Definition: kmr.h:658
int kmr_load_properties(MPI_Info info, char *filename)
Loads properties into MPI_Info (in Latin1 characters).
Definition: kmrutil.c:2020
void kmr_free_string(char *s)
Frees a string strduped.
Definition: kmrutil.c:611
void * kmr_bsearch(const void *key, const void *base, size_t nel, size_t size, int(*compar)(const void *, const void *))
Searches a key entry like bsearch(3C), but returns a next greater entry instead of null on no match...
Definition: kmrutil.c:569
#define kmr_malloc(Z)
Allocates memory, or aborts when failed.
Definition: kmrimpl.h:177
#define KMR_TRACE_FILE_PREFIX
Prefix to Trace Files.
Definition: kmrimpl.h:101
int kmr_make_printable_info_string(char *s, size_t sz, MPI_Info info)
Fills the string buffer with the MPI_Info strings for printing.
Definition: kmrutil.c:1884
#define kmr_create_kvs(MR, KF, VF)
Makes a new key-value stream (of type KMR_KVS) with the specified field datatypes.
Definition: kmr.h:71
int kmr_dump_kvs_stats(KMR_KVS *kvs, int level)
Dumps contents of a key-value stream, with values are pairs.
Definition: kmrutil.c:1761
int kmr_retrieve_kvs_entries(KMR_KVS *kvs, struct kmr_kvs_entry **ev, long n)
Fills local key-value entries in an array for inspection.
Definition: kmrbase.c:2860
Keyed-Record for Sorting.
Definition: kmr.h:415
int kmr_add_kv_done(KMR_KVS *kvs)
Marks finished adding key-value pairs.
Definition: kmrbase.c:939
Definition: kmr.h:391
KMR Context.
Definition: kmr.h:247
FILE * kmr_fopen(const char *n, const char *m)
Does fopen, avoiding EINTR.
Definition: kmrutil.c:625
char * kmr_stringify_file_options(struct kmr_file_option o)
Returns a print string of a single option, to check the bits are properly encoded in foreign language...
Definition: kmrutil.c:386
int kmr_free_kvs(KMR_KVS *kvs)
Releases a key-value stream (type KMR_KVS).
Definition: kmrbase.c:679
unsigned short kmr_k_position_t[4]
Positions of node by (X,Y,Z,ABC), with ABC axes collapsed.
Definition: kmrimpl.h:126
int kmr_k_node(KMR *mr, kmr_k_position_t p)
Gets TOFU position (physical coordinates) of the node.
Definition: kmrutil.c:445
int kmr_copy_kvs_to_info(KMR_KVS *kvi, MPI_Info dst)
Copies kvs entires into mpi-info.
Definition: kmrutil.c:1049
kmr_kv_field
Datatypes of Keys or Values.
Definition: kmr.h:368
int kmr_take_one(KMR_KVS *kvi, struct kmr_kv_box *kv)
Extracts a single key-value pair locally in the key-value stream KVI.
Definition: kmrbase.c:1427
#define kmr_map(KVI, KVO, ARG, OPT, M)
Maps simply.
Definition: kmr.h:82
Handy Copy of a Key-Value Field.
Definition: kmr.h:401
Options to Mapping by Spawns.
Definition: kmr.h:708
int kmr_get_element_count(KMR_KVS *kvs, long *v)
Gets the total number of key-value pairs.
Definition: kmrmoreops.c:114
char * kmr_strptr_ff(char *s)
Returns itself; this is for Fortran-binding.
Definition: kmrutil.c:208
int kmr_ckpt_disable_ckpt(KMR *)
It temporally disables checkpoint/restart.
Definition: kmrckpt.c:2495
void * kmr_strdup(char *s)
STRDUP, but aborts on failure.
Definition: kmrutil.c:596
int kmr_copy_info_to_kvs(MPI_Info src, KMR_KVS *kvo)
Copies mpi-info entires into kvs.
Definition: kmrutil.c:997
int kmr_make_printable_argv_string(char *s, size_t sz, char **argv)
Fills the string buffer with the argv strings for printing.
Definition: kmrutil.c:1859
int kmr_getdtablesize(KMR *mr)
Does getdtablesize(); it is defined, because it is not Posix.
Definition: kmrutil.c:650
int kmr_fgetc(FILE *f)
Does fgetc, avoiding EINTR.
Definition: kmrutil.c:637
KMR Interface.
unsigned long kmr_fix_bits_endian_ff(unsigned long b)
Fixes little-endian bits used in Fortran to host-endian.
Definition: kmrutil.c:284
int kmr_map_rank_by_rank(KMR_KVS *kvi, KMR_KVS *kvo, void *arg, struct kmr_option opt, kmr_mapfn_t m)
Maps sequentially with rank by rank for debugging.
Definition: kmrbase.c:1397
Options to Mapping on Files.
Definition: kmr.h:683
int kmr_copy_mpi_info(MPI_Info src, MPI_Info dst)
Copies contents of MPI_Info.
Definition: kmrutil.c:2408
void kmr_dump_opaque(const char *p, int sz, char *buf, int buflen)
Puts the string of the key or value field into a buffer BUF as printable string.
Definition: kmrutil.c:1596
Unit-Sized Storage.
Definition: kmr.h:383
char * kmr_stringify_spawn_options(struct kmr_spawn_option o)
Returns a print string of a single option, to check the bits are properly encoded in foreign language...
Definition: kmrutil.c:405
int kmr_replicate(KMR_KVS *kvi, KMR_KVS *kvo, struct kmr_option opt)
Replicates key-value pairs to be visible on all ranks, that is, it has the effect of bcast or all-gat...
Definition: kmrbase.c:2240
int kmr_add_string(KMR_KVS *kvs, const char *k, const char *v)
Adds a key-value pair of strings.
Definition: kmrbase.c:971
int kmr_intstr_ff(long p, char *s, int n)
Fills the character array S by the contents at the pointer value integer P by the length N...
Definition: kmrutil.c:257
int kmr_dump_kv(const struct kmr_kv_box kv, const KMR_KVS *kvs, char *buf, int buflen)
Dumps contents of a key-value.
Definition: kmrutil.c:1684
static struct kmr_kv_box kmr_pick_kv(struct kmr_kvs_entry *e, KMR_KVS *kvs)
Returns a handle to a key-value entry – a reverse of kmr_poke_kv().
Definition: kmrimpl.h:551
int(* kmr_redfn_t)(const struct kmr_kv_box kv[], const long n, const KMR_KVS *kvi, KMR_KVS *kvo, void *arg)
Reduce-function Type.
Definition: kmr.h:747
int kmr_ckpt_enable_ckpt(KMR *, int)
It temporally enables checkpoint/restart which has been disabled by calling kmr_ckpt_disable_ckpt().
Definition: kmrckpt.c:2516
void kmr_string_truncation(KMR *mr, size_t sz, char *s)
Modifies the string end with by "..." for indicating truncation, used on the result of snprintf...
Definition: kmrutil.c:193
int kmr_copy_to_array_fn(const struct kmr_kv_box kv, const KMR_KVS *kvi, KMR_KVS *kvo, void *arg, const long i)
Copies the entry in the array.
Definition: kmrutil.c:949
Information of Source Code Line.
Definition: kmr.h:107
int(* kmr_mapfn_t)(const struct kmr_kv_box kv, const KMR_KVS *kvi, KMR_KVS *kvo, void *arg, const long index)
Map-function Type.
Definition: kmr.h:736
int kmr_dump_mpi_info(char *prefix, MPI_Info info)
Dumps simply contents in MPI_Info.
Definition: kmrutil.c:2382
int kmr_assert_sorted(KMR_KVS *kvi, _Bool locally, _Bool shuffling, _Bool ranking)
Checks a key-value stream is sorted.
Definition: kmrutil.c:717
int kmr_dump_kvs(KMR_KVS *kvs, int flag)
Dumps contents of a KVS to stdout.
Definition: kmrutil.c:1711