IOR
utilities.c
Go to the documentation of this file.
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  */
4 /******************************************************************************\
5 * *
6 * Copyright (c) 2003, The Regents of the University of California *
7 * See the file COPYRIGHT for a complete copyright notice and license. *
8 * *
9 ********************************************************************************
10 *
11 * Additional utilities
12 *
13 \******************************************************************************/
14 
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
18 
19 #ifdef __linux__
20 # define _GNU_SOURCE /* Needed for O_DIRECT in fcntl */
21 #endif /* __linux__ */
22 
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <math.h> /* pow() */
29 #include <string.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <time.h>
33 
34 #ifndef _WIN32
35 # include <regex.h>
36 # ifdef __sun /* SunOS does not support statfs(), instead uses statvfs() */
37 # include <sys/statvfs.h>
38 # elif (defined __APPLE__)
39 # include <sys/param.h>
40 # include <sys/mount.h>
41 # else /* ! __sun or __APPLE__ */
42 # include <sys/statfs.h>
43 # endif /* __sun */
44 # include <sys/time.h> /* gettimeofday() */
45 #endif
46 
47 #include "utilities.h"
48 #include "aiori.h"
49 #include "ior.h"
50 
51 /************************** D E C L A R A T I O N S ***************************/
52 
53 extern int errno;
54 extern int numTasks;
55 
56 /* globals used by other files, also defined "extern" in utilities.h */
57 int rank = 0;
58 int rankOffset = 0;
59 int verbose = VERBOSE_0; /* verbose output */
60 MPI_Comm testComm;
61 MPI_Comm mpi_comm_world;
62 FILE * out_logfile;
65 
66 /***************************** F U N C T I O N S ******************************/
67 
68 void* safeMalloc(uint64_t size){
69  void * d = malloc(size);
70  if (d == NULL){
71  ERR("Could not malloc an array");
72  }
73  memset(d, 0, size);
74  return d;
75 }
76 
77 void FailMessage(int rank, const char *location, char *format, ...) {
78  char msg[4096];
79  va_list args;
80  va_start(args, format);
81  vsnprintf(msg, 4096, format, args);
82  va_end(args);
83  fprintf(out_logfile, "%s: Process %d: FAILED in %s, %s: %s\n",
84  PrintTimestamp(), rank, location, msg, strerror(errno));
85  fflush(out_logfile);
86  MPI_Abort(testComm, 1);
87 }
88 
89 size_t NodeMemoryStringToBytes(char *size_str)
90 {
91  int percent;
92  int rc;
93  long page_size;
94  long num_pages;
95  long long mem;
96 
97  rc = sscanf(size_str, " %d %% ", &percent);
98  if (rc == 0)
99  return (size_t) string_to_bytes(size_str);
100  if (percent > 100 || percent < 0)
101  ERR("percentage must be between 0 and 100");
102 
103 #ifdef HAVE_SYSCONF
104  page_size = sysconf(_SC_PAGESIZE);
105 #else
106  page_size = getpagesize();
107 #endif
108 
109 #ifdef _SC_PHYS_PAGES
110  num_pages = sysconf(_SC_PHYS_PAGES);
111  if (num_pages == -1)
112  ERR("sysconf(_SC_PHYS_PAGES) is not supported");
113 #else
114  ERR("sysconf(_SC_PHYS_PAGES) is not supported");
115 #endif
116  mem = page_size * num_pages;
117 
118  return mem / 100 * percent;
119 }
120 
122  if (options->setTimeStampSignature){
123  options->incompressibleSeed = options->setTimeStampSignature;
124  }
125 
126  if (options->buffer_type && options->buffer_type[0] != 0){
127  switch(options->buffer_type[0]) {
128  case 'i': /* Incompressible */
129  options->dataPacketType = incompressible;
130  break;
131  case 't': /* timestamp */
132  options->dataPacketType = timestamp;
133  break;
134  case 'o': /* offset packet */
135  options->storeFileOffset = TRUE;
136  options->dataPacketType = offset;
137  break;
138  default:
139  fprintf(out_logfile,
140  "Unknown argument for -l %s; generic assumed\n", options->buffer_type);
141  break;
142  }
143  }
144  if (options->memoryPerNodeStr){
146  }
147  const ior_aiori_t * backend = aiori_select(options->api);
148  if (backend == NULL)
149  ERR_SIMPLE("unrecognized I/O API");
150 
151  options->backend = backend;
152  /* copy the actual module options into the test */
153  options->backend_options = airoi_update_module_options(backend, global_options);
154  options->apiVersion = backend->get_version();
155 }
156 
157 /* Used in aiori-POSIX.c and aiori-PLFS.c
158  */
159 
160 void set_o_direct_flag(int *fd)
161 {
162 /* note that TRU64 needs O_DIRECTIO, SunOS uses directio(),
163  and everyone else needs O_DIRECT */
164 #ifndef O_DIRECT
165 # ifndef O_DIRECTIO
166  WARN("cannot use O_DIRECT");
167 # define O_DIRECT 000000
168 # else /* O_DIRECTIO */
169 # define O_DIRECT O_DIRECTIO
170 # endif /* not O_DIRECTIO */
171 #endif /* not O_DIRECT */
172 
173  *fd |= O_DIRECT;
174 }
175 
176 
177 /*
178  * Returns string containing the current time.
179  *
180  * NOTE: On some systems, MPI jobs hang while ctime() waits for a lock.
181  * This is true even though CurrentTimeString() is only called for rank==0.
182  * ctime_r() fixes this.
183  */
184 char *CurrentTimeString(void)
185 {
186  static time_t currentTime;
187  char* currentTimePtr;
188 
189  if ((currentTime = time(NULL)) == -1)
190  ERR("cannot get current time");
191 
192 #if (_POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE || _POSIX_SOURCE)
193  static char threadSafeBuff[32]; /* "must be at least 26 characters long" */
194  if ((currentTimePtr = ctime_r(&currentTime, threadSafeBuff)) == NULL) {
195  ERR("cannot read current time");
196  }
197 #else
198  if ((currentTimePtr = ctime(&currentTime)) == NULL) {
199  ERR("cannot read current time");
200  }
201 #endif
202  /* ctime string ends in \n */
203  return (currentTimePtr);
204 }
205 
206 /*
207  * Dump transfer buffer.
208  */
209 void DumpBuffer(void *buffer,
210  size_t size) /* <size> in bytes */
211 {
212  size_t i, j;
213  IOR_size_t *dumpBuf = (IOR_size_t *)buffer;
214 
215  /* Turns out, IOR_size_t is unsigned long long, but we don't want
216  to assume that it must always be */
217  for (i = 0; i < ((size / sizeof(IOR_size_t)) / 4); i++) {
218  for (j = 0; j < 4; j++) {
219  fprintf(out_logfile, IOR_format" ", dumpBuf[4 * i + j]);
220  }
221  fprintf(out_logfile, "\n");
222  }
223  return;
224 } /* DumpBuffer() */
225 
226 /* a function that prints an int array where each index corresponds to a rank
227  and the value is whether that rank is on the same host as root.
228  Also returns 1 if rank 1 is on same host and 0 otherwise
229 */
230 int QueryNodeMapping(MPI_Comm comm, int print_nodemap) {
231  char localhost[MAX_PATHLEN], roothost[MAX_PATHLEN];
232  int num_ranks;
233  MPI_Comm_size(comm, &num_ranks);
234  int *node_map = (int*)malloc(sizeof(int) * num_ranks);
235  if ( ! node_map ) {
236  FAIL("malloc");
237  }
238  if (gethostname(localhost, MAX_PATHLEN) != 0) {
239  FAIL("gethostname()");
240  }
241  if (rank==0) {
242  strncpy(roothost,localhost,MAX_PATHLEN);
243  }
244 
245  /* have rank 0 broadcast out its hostname */
246  MPI_Bcast(roothost, MAX_PATHLEN, MPI_CHAR, 0, comm);
247  //printf("Rank %d received root host as %s\n", rank, roothost);
248  /* then every rank figures out whether it is same host as root and then gathers that */
249  int same_as_root = strcmp(roothost,localhost) == 0;
250  MPI_Gather( &same_as_root, 1, MPI_INT, node_map, 1, MPI_INT, 0, comm);
251  if ( print_nodemap && rank==0) {
252  fprintf( out_logfile, "Nodemap: " );
253  for ( int i = 0; i < num_ranks; i++ ) {
254  fprintf( out_logfile, "%d", node_map[i] );
255  }
256  fprintf( out_logfile, "\n" );
257  }
258  int ret = 1;
259  if(num_ranks>1)
260  ret = node_map[1] == 1;
261  MPI_Bcast(&ret, 1, MPI_INT, 0, comm);
262  free(node_map);
263  return ret;
264 }
265 
266 /*
267  * There is a more direct way to determine the node count in modern MPI
268  * versions so we use that if possible.
269  *
270  * For older versions we use a method which should still provide accurate
271  * results even if the total number of tasks is not evenly divisible by the
272  * tasks on node rank 0.
273  */
274 int GetNumNodes(MPI_Comm comm) {
275  if (getenv("IOR_FAKE_NODES")){
276  int numNodes = atoi(getenv("IOR_FAKE_NODES"));
277  int rank;
278  MPI_Comm_rank(comm, & rank);
279  if(rank == 0){
280  printf("Fake number of node: using %d\n", numNodes);
281  }
282  return numNodes;
283  }
284 #if MPI_VERSION >= 3
285  MPI_Comm shared_comm;
286  int shared_rank = 0;
287  int local_result = 0;
288  int numNodes = 0;
289 
290  MPI_CHECK(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, &shared_comm),
291  "MPI_Comm_split_type() error");
292  MPI_CHECK(MPI_Comm_rank(shared_comm, &shared_rank), "MPI_Comm_rank() error");
293  local_result = shared_rank == 0? 1 : 0;
294  MPI_CHECK(MPI_Allreduce(&local_result, &numNodes, 1, MPI_INT, MPI_SUM, comm),
295  "MPI_Allreduce() error");
296  MPI_CHECK(MPI_Comm_free(&shared_comm), "MPI_Comm_free() error");
297 
298  return numNodes;
299 #else
300  int numTasks = 0;
301  int numTasksOnNode0 = 0;
302 
303  numTasks = GetNumTasks(comm);
304  numTasksOnNode0 = GetNumTasksOnNode0(comm);
305 
306  return ((numTasks - 1) / numTasksOnNode0) + 1;
307 #endif
308 }
309 
310 
311 int GetNumTasks(MPI_Comm comm) {
312  int numTasks = 0;
313 
314  MPI_CHECK(MPI_Comm_size(comm, &numTasks), "cannot get number of tasks");
315 
316  return numTasks;
317 }
318 
319 
320 /*
321  * It's very important that this method provide the same result to every
322  * process as it's used for redistributing which jobs read from which files.
323  * It was renamed accordingly.
324  *
325  * If different nodes get different results from this method then jobs get
326  * redistributed unevenly and you no longer have a 1:1 relationship with some
327  * nodes reading multiple files while others read none.
328  *
329  * In the common case the number of tasks on each node (MPI_Comm_size on an
330  * MPI_COMM_TYPE_SHARED communicator) will be the same. However, there is
331  * nothing which guarantees this. It's valid to have, for example, 64 jobs
332  * across 4 systems which can run 20 jobs each. In that scenario you end up
333  * with 3 MPI_COMM_TYPE_SHARED groups of 20, and one group of 4.
334  *
335  * In the (MPI_VERSION < 3) implementation of this method consistency is
336  * ensured by asking specifically about the number of tasks on the node with
337  * rank 0. In the original implementation for (MPI_VERSION >= 3) this was
338  * broken by using the LOCAL process count which differed depending on which
339  * node you were on.
340  *
341  * This was corrected below by first splitting the comm into groups by node
342  * (MPI_COMM_TYPE_SHARED) and then having only the node with world rank 0 and
343  * shared rank 0 return the MPI_Comm_size of its shared subgroup. This yields
344  * the original consistent behavior no matter which node asks.
345  *
346  * In the common case where every node has the same number of tasks this
347  * method will return the same value it always has.
348  */
349 int GetNumTasksOnNode0(MPI_Comm comm) {
350  if (getenv("IOR_FAKE_TASK_PER_NODES")){
351  int tasksPerNode = atoi(getenv("IOR_FAKE_TASK_PER_NODES"));
352  int rank;
353  MPI_Comm_rank(comm, & rank);
354  if(rank == 0){
355  printf("Fake tasks per node: using %d\n", tasksPerNode);
356  }
357  return tasksPerNode;
358  }
359 #if MPI_VERSION >= 3
360  MPI_Comm shared_comm;
361  int shared_rank = 0;
362  int tasks_on_node_rank0 = 0;
363  int local_result = 0;
364 
365  MPI_CHECK(MPI_Comm_split_type(comm, MPI_COMM_TYPE_SHARED, 0, MPI_INFO_NULL, &shared_comm),
366  "MPI_Comm_split_type() error");
367  MPI_CHECK(MPI_Comm_rank(shared_comm, &shared_rank), "MPI_Comm_rank() error");
368  if (rank == 0 && shared_rank == 0) {
369  MPI_CHECK(MPI_Comm_size(shared_comm, &local_result), "MPI_Comm_size() error");
370  }
371  MPI_CHECK(MPI_Allreduce(&local_result, &tasks_on_node_rank0, 1, MPI_INT, MPI_SUM, comm),
372  "MPI_Allreduce() error");
373  MPI_CHECK(MPI_Comm_free(&shared_comm), "MPI_Comm_free() error");
374 
375  return tasks_on_node_rank0;
376 #else
377 /*
378  * This version employs the gethostname() call, rather than using
379  * MPI_Get_processor_name(). We are interested in knowing the number
380  * of tasks that share a file system client (I/O node, compute node,
381  * whatever that may be). However on machines like BlueGene/Q,
382  * MPI_Get_processor_name() uniquely identifies a cpu in a compute node,
383  * not the node where the I/O is function shipped to. gethostname()
384  * is assumed to identify the shared filesystem client in more situations.
385  */
386  int size;
387  MPI_Comm_size(comm, & size);
388  /* for debugging and testing */
389  char localhost[MAX_PATHLEN],
391  int count = 1,
392  i;
393  MPI_Status status;
394 
395  if (( rank == 0 ) && ( verbose >= 1 )) {
396  fprintf( out_logfile, "V-1: Entering count_tasks_per_node...\n" );
397  fflush( out_logfile );
398  }
399 
400  if (gethostname(localhost, MAX_PATHLEN) != 0) {
401  FAIL("gethostname()");
402  }
403  if (rank == 0) {
404  /* MPI_receive all hostnames, and compares them to the local hostname */
405  for (i = 0; i < size-1; i++) {
406  MPI_Recv(hostname, MAX_PATHLEN, MPI_CHAR, MPI_ANY_SOURCE,
407  MPI_ANY_TAG, comm, &status);
408  if (strcmp(hostname, localhost) == 0) {
409  count++;
410  }
411  }
412  } else {
413  /* MPI_send hostname to root node */
414  MPI_Send(localhost, MAX_PATHLEN, MPI_CHAR, 0, 0, comm);
415  }
416  MPI_Bcast(&count, 1, MPI_INT, 0, comm);
417 
418  return(count);
419 #endif
420 }
421 
422 
423 /*
424  * Extract key/value pair from hint string.
425  */
426 void ExtractHint(char *settingVal, char *valueVal, char *hintString)
427 {
428  char *settingPtr, *valuePtr, *tmpPtr2;
429 
430  /* find the value */
431  settingPtr = (char *)strtok(hintString, " =");
432  valuePtr = (char *)strtok(NULL, " =\t\r\n");
433  /* is this an MPI hint? */
434  tmpPtr2 = (char *) strstr(settingPtr, "IOR_HINT__MPI__");
435  if (settingPtr == tmpPtr2) {
436  settingPtr += strlen("IOR_HINT__MPI__");
437  } else {
438  tmpPtr2 = (char *) strstr(hintString, "IOR_HINT__GPFS__");
439  /* is it an GPFS hint? */
440  if (settingPtr == tmpPtr2) {
441  settingPtr += strlen("IOR_HINT__GPFS__");
442  }else{
443  fprintf(out_logfile, "WARNING: Unable to set unknown hint type (not implemented.)\n");
444  return;
445  }
446  }
447  strcpy(settingVal, settingPtr);
448  strcpy(valueVal, valuePtr);
449 }
450 
451 /*
452  * Set hints for MPIIO, HDF5, or NCMPI.
453  */
454 void SetHints(MPI_Info * mpiHints, char *hintsFileName)
455 {
456  char hintString[MAX_STR];
457  char settingVal[MAX_STR];
458  char valueVal[MAX_STR];
459  extern char **environ;
460  int i;
461  FILE *fd;
462 
463  /*
464  * This routine checks for hints from the environment and/or from the
465  * hints files. The hints are of the form:
466  * 'IOR_HINT__<layer>__<hint>=<value>', where <layer> is either 'MPI'
467  * or 'GPFS', <hint> is the full name of the hint to be set, and <value>
468  * is the hint value. E.g., 'setenv IOR_HINT__MPI__IBM_largeblock_io true'
469  * or 'IOR_HINT__GPFS__hint=value' in the hints file.
470  */
471  MPI_CHECK(MPI_Info_create(mpiHints), "cannot create info object");
472 
473  /* get hints from environment */
474  for (i = 0; environ[i] != NULL; i++) {
475  /* if this is an IOR_HINT, pass the hint to the info object */
476  if (strncmp(environ[i], "IOR_HINT", strlen("IOR_HINT")) == 0) {
477  strcpy(hintString, environ[i]);
478  ExtractHint(settingVal, valueVal, hintString);
479  MPI_CHECK(MPI_Info_set(*mpiHints, settingVal, valueVal),
480  "cannot set info object");
481  }
482  }
483 
484  /* get hints from hints file */
485  if (hintsFileName != NULL && strcmp(hintsFileName, "") != 0) {
486 
487  /* open the hint file */
488  fd = fopen(hintsFileName, "r");
489  if (fd == NULL) {
490  WARN("cannot open hints file");
491  } else {
492  /* iterate over hints file */
493  while (fgets(hintString, MAX_STR, fd) != NULL) {
494  if (strncmp
495  (hintString, "IOR_HINT",
496  strlen("IOR_HINT")) == 0) {
497  ExtractHint(settingVal, valueVal,
498  hintString);
499  MPI_CHECK(MPI_Info_set
500  (*mpiHints, settingVal,
501  valueVal),
502  "cannot set info object");
503  }
504  }
505  /* close the hints files */
506  if (fclose(fd) != 0)
507  ERR("cannot close hints file");
508  }
509  }
510 }
511 
512 /*
513  * Show all hints (key/value pairs) in an MPI_Info object.
514  */
515 void ShowHints(MPI_Info * mpiHints)
516 {
517  char key[MPI_MAX_INFO_VAL];
518  char value[MPI_MAX_INFO_VAL];
519  int flag, i, nkeys;
520 
521  MPI_CHECK(MPI_Info_get_nkeys(*mpiHints, &nkeys),
522  "cannot get info object keys");
523 
524  for (i = 0; i < nkeys; i++) {
525  MPI_CHECK(MPI_Info_get_nthkey(*mpiHints, i, key),
526  "cannot get info object key");
527  MPI_CHECK(MPI_Info_get(*mpiHints, key, MPI_MAX_INFO_VAL - 1,
528  value, &flag),
529  "cannot get info object value");
530  fprintf(out_logfile, "\t%s = %s\n", key, value);
531  }
532 }
533 
534 /*
535  * Takes a string of the form 64, 8m, 128k, 4g, etc. and converts to bytes.
536  */
538 {
539  IOR_offset_t size = 0;
540  char range;
541  int rc;
542 
543  rc = sscanf(size_str, "%lld%c", &size, &range);
544  if (rc == 2) {
545  switch ((int)range) {
546  case 'k':
547  case 'K':
548  size <<= 10;
549  break;
550  case 'm':
551  case 'M':
552  size <<= 20;
553  break;
554  case 'g':
555  case 'G':
556  size <<= 30;
557  break;
558  }
559  } else if (rc == 0) {
560  size = -1;
561  }
562  return (size);
563 }
564 
565 /*
566  * Displays size of file system and percent of data blocks and inodes used.
567  */
568 void ShowFileSystemSize(char *fileSystem) // this might be converted to an AIORI call
569 {
570 #ifndef _WIN32 /* FIXME */
571  char realPath[PATH_MAX];
572  char *fileSystemUnitStr;
573  long long int totalFileSystemSize;
574  long long int freeFileSystemSize;
575  long long int totalInodes;
576  long long int freeInodes;
577  double totalFileSystemSizeHR;
578  double usedFileSystemPercentage;
579  double usedInodePercentage;
580 #ifdef __sun /* SunOS does not support statfs(), instead uses statvfs() */
581  struct statvfs statusBuffer;
582 #else /* !__sun */
583  struct statfs statusBuffer;
584 #endif /* __sun */
585 
586 #ifdef __sun
587  if (statvfs(fileSystem, &statusBuffer) != 0) {
588  WARN("unable to statvfs() file system");
589  return;
590  }
591 #else /* !__sun */
592  if (statfs(fileSystem, &statusBuffer) != 0) {
593  WARN("unable to statfs() file system");
594  return;
595  }
596 #endif /* __sun */
597 
598  /* data blocks */
599 #ifdef __sun
600  totalFileSystemSize = statusBuffer.f_blocks * statusBuffer.f_frsize;
601  freeFileSystemSize = statusBuffer.f_bfree * statusBuffer.f_frsize;
602 #else /* !__sun */
603  totalFileSystemSize = statusBuffer.f_blocks * statusBuffer.f_bsize;
604  freeFileSystemSize = statusBuffer.f_bfree * statusBuffer.f_bsize;
605 #endif /* __sun */
606 
607  usedFileSystemPercentage = (1 - ((double)freeFileSystemSize
608  / (double)totalFileSystemSize)) * 100;
609  totalFileSystemSizeHR =
610  (double)totalFileSystemSize / (double)(1<<30);
611  fileSystemUnitStr = "GiB";
612  if (totalFileSystemSizeHR > 1024) {
613  totalFileSystemSizeHR = (double)totalFileSystemSize / (double)((long long)1<<40);
614  fileSystemUnitStr = "TiB";
615  }
616 
617  /* inodes */
618  totalInodes = statusBuffer.f_files;
619  freeInodes = statusBuffer.f_ffree;
620  usedInodePercentage =
621  (1 - ((double)freeInodes / (double)totalInodes)) * 100;
622 
623  /* show results */
624  if (realpath(fileSystem, realPath) == NULL) {
625  WARN("unable to use realpath()");
626  return;
627  }
628 
630  fprintf(out_resultfile, "%-20s: %s\n", "Path", realPath);
631  fprintf(out_resultfile, "%-20s: %.1f %s Used FS: %2.1f%% ",
632  "FS", totalFileSystemSizeHR, fileSystemUnitStr,
633  usedFileSystemPercentage);
634  fprintf(out_resultfile, "Inodes: %.1f Mi Used Inodes: %2.1f%%\n",
635  (double)totalInodes / (double)(1<<20),
636  usedInodePercentage);
637  fflush(out_logfile);
638  }else if(outputFormat == OUTPUT_JSON){
639  fprintf(out_resultfile, " , \"Path\": \"%s\",", realPath);
640  fprintf(out_resultfile, "\"Capacity\": \"%.1f %s\", \"Used Capacity\": \"%2.1f%%\",",
641  totalFileSystemSizeHR, fileSystemUnitStr,
642  usedFileSystemPercentage);
643  fprintf(out_resultfile, "\"Inodes\": \"%.1f Mi\", \"Used Inodes\" : \"%2.1f%%\"\n",
644  (double)totalInodes / (double)(1<<20),
645  usedInodePercentage);
646  }else if(outputFormat == OUTPUT_CSV){
647 
648  }
649 
650 #endif /* !_WIN32 */
651 
652  return;
653 }
654 
655 /*
656  * Return match of regular expression -- 0 is failure, 1 is success.
657  */
658 int Regex(char *string, char *pattern)
659 {
660  int retValue = 0;
661 #ifndef _WIN32 /* Okay to always not match */
662  regex_t regEx;
663  regmatch_t regMatch;
664 
665  regcomp(&regEx, pattern, REG_EXTENDED);
666  if (regexec(&regEx, string, 1, &regMatch, 0) == 0) {
667  retValue = 1;
668  }
669  regfree(&regEx);
670 #endif
671 
672  return (retValue);
673 }
674 
675 /*
676  * Seed random generator.
677  */
678 void SeedRandGen(MPI_Comm testComm)
679 {
680  unsigned int randomSeed;
681 
682  if (rank == 0) {
683 #ifdef _WIN32
684  rand_s(&randomSeed);
685 #else
686  struct timeval randGenTimer;
687  gettimeofday(&randGenTimer, (struct timezone *)NULL);
688  randomSeed = randGenTimer.tv_usec;
689 #endif
690  }
691  MPI_CHECK(MPI_Bcast(&randomSeed, 1, MPI_INT, 0,
692  testComm), "cannot broadcast random seed value");
693  srandom(randomSeed);
694 }
695 
696 /*
697  * System info for Windows.
698  */
699 #ifdef _WIN32
700 int uname(struct utsname *name)
701 {
702  DWORD nodeNameSize = sizeof(name->nodename) - 1;
703 
704  memset(name, 0, sizeof(struct utsname));
705  if (!GetComputerNameEx
706  (ComputerNameDnsFullyQualified, name->nodename, &nodeNameSize))
707  ERR("GetComputerNameEx failed");
708 
709  strncpy(name->sysname, "Windows", sizeof(name->sysname) - 1);
710  /* FIXME - these should be easy to fetch */
711  strncpy(name->release, "-", sizeof(name->release) - 1);
712  strncpy(name->version, "-", sizeof(name->version) - 1);
713  strncpy(name->machine, "-", sizeof(name->machine) - 1);
714  return 0;
715 }
716 #endif /* _WIN32 */
717 
718 
720 double wall_clock_delta = 0;
721 
722 /*
723  * Get time stamp. Use MPI_Timer() unless _NO_MPI_TIMER is defined,
724  * in which case use gettimeofday().
725  */
726 double GetTimeStamp(void)
727 {
728  double timeVal;
729 #ifdef _NO_MPI_TIMER
730  struct timeval timer;
731 
732  if (gettimeofday(&timer, (struct timezone *)NULL) != 0)
733  ERR("cannot use gettimeofday()");
734  timeVal = (double)timer.tv_sec + ((double)timer.tv_usec / 1000000);
735 #else /* not _NO_MPI_TIMER */
736  timeVal = MPI_Wtime(); /* no MPI_CHECK(), just check return value */
737  if (timeVal < 0)
738  ERR("cannot use MPI_Wtime()");
739 #endif /* _NO_MPI_TIMER */
740 
741  /* wall_clock_delta is difference from root node's time */
742  timeVal -= wall_clock_delta;
743 
744  return (timeVal);
745 }
746 
747 /*
748  * Determine any spread (range) between node times.
749  */
750 static double TimeDeviation(void)
751 {
752  double timestamp;
753  double min = 0;
754  double max = 0;
755  double roottimestamp;
756 
757  MPI_CHECK(MPI_Barrier(mpi_comm_world), "barrier error");
758  timestamp = GetTimeStamp();
759  MPI_CHECK(MPI_Reduce(&timestamp, &min, 1, MPI_DOUBLE,
760  MPI_MIN, 0, mpi_comm_world),
761  "cannot reduce tasks' times");
762  MPI_CHECK(MPI_Reduce(&timestamp, &max, 1, MPI_DOUBLE,
763  MPI_MAX, 0, mpi_comm_world),
764  "cannot reduce tasks' times");
765 
766  /* delta between individual nodes' time and root node's time */
767  roottimestamp = timestamp;
768  MPI_CHECK(MPI_Bcast(&roottimestamp, 1, MPI_DOUBLE, 0, mpi_comm_world),
769  "cannot broadcast root's time");
770  wall_clock_delta = timestamp - roottimestamp;
771 
772  return max - min;
773 }
774 
775 void init_clock(){
776  /* check for skew between tasks' start times */
778 }
779 
780 char * PrintTimestamp() {
781  static char datestring[80];
782  time_t cur_timestamp;
783 
784  if (( rank == 0 ) && ( verbose >= 1 )) {
785  fprintf( out_logfile, "V-1: Entering PrintTimestamp...\n" );
786  }
787 
788  fflush(out_logfile);
789  cur_timestamp = time(NULL);
790  strftime(datestring, 80, "%m/%d/%Y %T", localtime(&cur_timestamp));
791 
792  return datestring;
793 }
794 
795 int64_t ReadStoneWallingIterations(char * const filename){
796  long long data;
797  if(rank != 0){
798  MPI_Bcast( & data, 1, MPI_LONG_LONG_INT, 0, mpi_comm_world);
799  return data;
800  }else{
801  FILE * out = fopen(filename, "r");
802  if (out == NULL){
803  data = -1;
804  MPI_Bcast( & data, 1, MPI_LONG_LONG_INT, 0, mpi_comm_world);
805  return data;
806  }
807  int ret = fscanf(out, "%lld", & data);
808  if (ret != 1){
809  return -1;
810  }
811  fclose(out);
812  MPI_Bcast( & data, 1, MPI_LONG_LONG_INT, 0, mpi_comm_world);
813  return data;
814  }
815 }
816 
817 void StoreStoneWallingIterations(char * const filename, int64_t count){
818  if(rank != 0){
819  return;
820  }
821  FILE * out = fopen(filename, "w");
822  if (out == NULL){
823  FAIL("Cannot write to the stonewalling file!");
824  }
825  fprintf(out, "%lld", (long long) count);
826  fclose(out);
827 }
828 
829 /*
830  * Sleep for 'delay' seconds.
831  */
832 void DelaySecs(int delay){
833  if (rank == 0 && delay > 0) {
834  if (verbose >= VERBOSE_1)
835  fprintf(out_logfile, "delaying %d seconds . . .\n", delay);
836  sleep(delay);
837  }
838 }
839 
840 
841 /*
842  * Convert IOR_offset_t value to human readable string. This routine uses a
843  * statically-allocated buffer internally and so is not re-entrant.
844  */
845 char *HumanReadable(IOR_offset_t value, int base)
846 {
847  static char valueStr[MAX_STR];
848  IOR_offset_t m = 0, g = 0, t = 0;
849  char m_str[8], g_str[8], t_str[8];
850 
851  if (base == BASE_TWO) {
852  m = MEBIBYTE;
853  g = GIBIBYTE;
854  t = GIBIBYTE * 1024llu;
855  strcpy(m_str, "MiB");
856  strcpy(g_str, "GiB");
857  strcpy(t_str, "TiB");
858  } else if (base == BASE_TEN) {
859  m = MEGABYTE;
860  g = GIGABYTE;
861  t = GIGABYTE * 1000llu;
862  strcpy(m_str, "MB");
863  strcpy(g_str, "GB");
864  strcpy(t_str, "TB");
865  }
866 
867  if (value >= t) {
868  if (value % t) {
869  snprintf(valueStr, MAX_STR-1, "%.2f %s",
870  (double)((double)value / t), t_str);
871  } else {
872  snprintf(valueStr, MAX_STR-1, "%d %s", (int)(value / t), t_str);
873  }
874  }else if (value >= g) {
875  if (value % g) {
876  snprintf(valueStr, MAX_STR-1, "%.2f %s",
877  (double)((double)value / g), g_str);
878  } else {
879  snprintf(valueStr, MAX_STR-1, "%d %s", (int)(value / g), g_str);
880  }
881  } else if (value >= m) {
882  if (value % m) {
883  snprintf(valueStr, MAX_STR-1, "%.2f %s",
884  (double)((double)value / m), m_str);
885  } else {
886  snprintf(valueStr, MAX_STR-1, "%d %s", (int)(value / m), m_str);
887  }
888  } else if (value >= 0) {
889  snprintf(valueStr, MAX_STR-1, "%d bytes", (int)value);
890  } else {
891  snprintf(valueStr, MAX_STR-1, "-");
892  }
893  return valueStr;
894 }
char * HumanReadable(IOR_offset_t value, int base)
Definition: utilities.c:845
MPI_Comm testComm
Definition: utilities.c:60
int GetNumTasks(MPI_Comm comm)
Definition: utilities.c:311
#define MEBIBYTE
Definition: iordef.h:87
void set_o_direct_flag(int *fd)
Definition: utilities.c:160
#define ERR(MSG)
Definition: iordef.h:184
void ShowHints(MPI_Info *mpiHints)
Definition: utilities.c:515
unsigned int incompressibleSeed
Definition: ior.h:149
#define VERBOSE_0
Definition: iordef.h:101
void * airoi_update_module_options(const ior_aiori_t *backend, options_all_t *opt)
Definition: aiori.c:85
static int size
Definition: mdtest.c:91
char *(* get_version)(void)
Definition: aiori.h:77
int rankOffset
Definition: utilities.c:58
int64_t ReadStoneWallingIterations(char *const filename)
Definition: utilities.c:795
OutputFormat_t
Definition: iordef.h:64
CURLcode rc
Definition: aiori-S3.c:121
enum OutputFormat_t outputFormat
Definition: utilities.c:64
size_t memoryPerNode
Definition: ior.h:152
int storeFileOffset
Definition: ior.h:136
int QueryNodeMapping(MPI_Comm comm, int print_nodemap)
Definition: utilities.c:230
char * apiVersion
Definition: ior.h:91
int numTasks
int setTimeStampSignature
Definition: ior.h:145
IOR_offset_t StringToBytes(char *size_str)
Definition: utilities.c:537
#define GIBIBYTE
Definition: iordef.h:88
#define ERR_SIMPLE(MSG)
Definition: iordef.h:190
int verbose
Definition: utilities.c:59
static double TimeDeviation(void)
Definition: utilities.c:750
void * backend_options
Definition: ior.h:158
char * PrintTimestamp()
Definition: utilities.c:780
void init_clock()
Definition: utilities.c:775
const ior_aiori_t * aiori_select(const char *api)
Definition: aiori.c:291
double wall_clock_delta
Definition: utilities.c:720
void ShowFileSystemSize(char *fileSystem)
Definition: utilities.c:568
static option_help options[]
Definition: aiori-CEPHFS.c:54
void SeedRandGen(MPI_Comm testComm)
Definition: utilities.c:678
char * CurrentTimeString(void)
Definition: utilities.c:184
#define MPI_CHECK(MPI_STATUS, MSG)
Definition: iordef.h:224
#define PATH_MAX
Definition: iordef.h:112
double wall_clock_deviation
Definition: utilities.c:719
void updateParsedOptions(IOR_param_t *options, options_all_t *global_options)
Definition: utilities.c:121
int GetNumNodes(MPI_Comm comm)
Definition: utilities.c:274
int rank
Definition: utilities.c:57
#define FAIL(...)
Definition: utilities.h:42
Definition: ior.h:48
FILE * out_resultfile
Definition: utilities.c:63
double GetTimeStamp(void)
Definition: utilities.c:726
static const ior_aiori_t * backend
Definition: ior.c:49
char ** environ
void StoreStoneWallingIterations(char *const filename, int64_t count)
Definition: utilities.c:817
static char hostname[MAX_PATHLEN]
Definition: mdtest.c:97
enum PACKET_TYPE dataPacketType
Definition: ior.h:156
static options_all_t * global_options
Definition: parse_options.c:43
#define GIGABYTE
Definition: iordef.h:84
long long int IOR_size_t
Definition: iordef.h:123
#define WARN(MSG)
Definition: iordef.h:144
char * buffer_type
Definition: ior.h:155
int64_t string_to_bytes(char *size_str)
Definition: option.c:13
Definition: ior.h:47
#define BASE_TWO
Definition: iordef.h:91
#define MAX_STR
Definition: iordef.h:108
void ExtractHint(char *settingVal, char *valueVal, char *hintString)
Definition: utilities.c:426
#define MAX_PATHLEN
Definition: utilities.h:33
#define O_DIRECT
int errno
const struct ior_aiori * backend
Definition: ior.h:85
void SetHints(MPI_Info *mpiHints, char *hintsFileName)
Definition: utilities.c:454
#define MEGABYTE
Definition: iordef.h:83
void FailMessage(int rank, const char *location, char *format,...)
Definition: utilities.c:77
#define BASE_TEN
Definition: iordef.h:92
void DelaySecs(int delay)
Definition: utilities.c:832
#define VERBOSE_1
Definition: iordef.h:102
MPI_Comm mpi_comm_world
Definition: utilities.c:61
int Regex(char *string, char *pattern)
Definition: utilities.c:658
char * api
Definition: ior.h:90
size_t NodeMemoryStringToBytes(char *size_str)
Definition: utilities.c:89
#define IOR_format
Definition: iordef.h:125
void DumpBuffer(void *buffer, size_t size)
Definition: utilities.c:209
char * memoryPerNodeStr
Definition: ior.h:153
FILE * out_logfile
Definition: utilities.c:62
long long int IOR_offset_t
Definition: iordef.h:122
int GetNumTasksOnNode0(MPI_Comm comm)
Definition: utilities.c:349
#define TRUE
Definition: iordef.h:75
void * safeMalloc(uint64_t size)
Definition: utilities.c:68
#define NULL
Definition: iordef.h:79