KMR
testiolb1.c
1 /* testiolb1.c (2014-08-07) */
2 
3 /* A file read benchmark for testing locality-aware file assignment.
4 
5  This program reads files in a specified directory and measures the average
6  time for reading each file.
7 
8  This program can be run as the follow.
9 
10  1. crate a directory and files
11 
12  $ mkdir ./data
13  $ dd if=/dev/zero of=./data/file000 bs=1M count=100
14  $ dd if=/dev/zero of=./data/file001 bs=1M count=100
15  ...
16 
17  2. run by mpiexec
18 
19  $ mpiexec ./a.out ./data
20 
21  When '-s' option is given, it performs shuffle instead of locality-
22  aware file assignment.
23 */
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <dirent.h>
32 #include <assert.h>
33 #include <mpi.h>
34 #include "kmr.h"
35 
36 #define PATHLEN 256
37 #define READBUFSIZ 1048576 /* 1MB */
38 
39 /* KMR map function
40  It creates a kvs whose key is a sequential number starts from 0 and value
41  is a file name in the specified directory.
42 */
43 static int
44 read_files(const struct kmr_kv_box kv,
45  const KMR_KVS *kvi, KMR_KVS *kvo, void *p, long i_)
46 {
47  char *dirname = (char *)p;
48  DIR *dir = opendir(dirname);
49  assert(dir != NULL);
50  long seqno = 0;
51  for (struct dirent *dp = readdir(dir); dp != NULL; dp = readdir(dir)) {
52  assert(strlen(dp->d_name) > 0);
53  if (dp->d_name[0] == '.') {
54  continue;
55  }
56  char filepath[PATHLEN];
57  snprintf(filepath, PATHLEN, "%s/%s", dirname, dp->d_name);
58  struct kmr_kv_box nkv = { .klen = sizeof(long),
59  .vlen = (int)((strlen(filepath) + 1) * sizeof(char)),
60  .k.i = seqno,
61  .v.p = (void *)&filepath };
62  kmr_add_kv(kvo, nkv);
63  seqno += 1;
64  }
65  closedir(dir);
66  return MPI_SUCCESS;
67 }
68 
69 /* KMR map function
70  It measures times required for reading a file.
71 */
72 static int
73 benchmark(const struct kmr_kv_box kv,
74  const KMR_KVS *kvi, KMR_KVS *kvo, void *p, long i_)
75 {
76  char *filename = (char *)kv.v.p;
77  char buf[READBUFSIZ];
78 
79  double t1 = MPI_Wtime();
80  FILE *fp = fopen(filename, "r");
81  assert(fp != NULL);
82  size_t siz;
83  do {
84  siz = fread(buf, sizeof(char), READBUFSIZ, fp);
85  } while (siz != 0);
86  fclose(fp);
87  double t2 = MPI_Wtime();
88 
89  struct kmr_kv_box nkv = { .klen = sizeof(long),
90  .vlen = sizeof(double),
91  .k.i = 0,
92  .v.d = t2 - t1 };
93  kmr_add_kv(kvo, nkv);
94  return MPI_SUCCESS;
95 }
96 
97 /* KMR reduce function
98  It calculates the average file read time.
99 */
100 static int
101 summarize(const struct kmr_kv_box kv[], const long n,
102  const KMR_KVS *kvi, KMR_KVS *kvo, void *p)
103 {
104  double sum = 0.0;
105  for (long i = 0; i < n; i++) {
106  printf("%f\n", kv[i].v.d);
107  sum += kv[i].v.d;
108  }
109  double avg = sum / (double)n;
110  printf("Average read time: %f\n", avg);
111  fflush(stdout);
112  return MPI_SUCCESS;
113 }
114 
115 /*
116  It return 1 if the specified file path is a directory.
117  Otherwise it returns 0.
118 */
119 static _Bool
120 check_directory(const char *path)
121 {
122  struct stat s;
123  int ret = stat(path, &s);
124  if (ret != 0) {
125  return 0;
126  }
127  if (S_ISDIR(s.st_mode)) {
128  return 1;
129  }
130  return 0;
131 }
132 
133 static void
134 show_help(int rank)
135 {
136  if (rank == 0) {
137  fprintf(stderr, "Specify a directory.\n\n");
138  fprintf(stderr, "Usage: ./a.out [-s] DIRECTORY\n");
139  fprintf(stderr, " -s : perform shuffle to distribute files.\n");
140  }
141 }
142 
143 
144 int
145 main(int argc, char **argv)
146 {
147  int nprocs, rank;
148  _Bool noiolb = 0;
149  char *dirname = NULL;
150 
151  MPI_Init(&argc, &argv);
152  MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
153  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
154 
155  if (!(argc == 2 || argc == 3)) {
156  show_help(rank);
157  MPI_Finalize();
158  return 1;
159  } else if (argc == 2) {
160  dirname = argv[1];
161  if (!check_directory(dirname)) {
162  show_help(rank);
163  MPI_Finalize();
164  return 1;
165  }
166  } else if (argc == 3) {
167  int ret = strcmp(argv[1], "-s");
168  if (ret == 0) {
169  noiolb = 1;
170  }
171  dirname = argv[2];
172  if (!check_directory(dirname)) {
173  show_help(rank);
174  MPI_Finalize();
175  return 1;
176  }
177  }
178 
179  kmr_init();
180  KMR *mr = kmr_create_context(MPI_COMM_WORLD, MPI_INFO_NULL, 0);
181  mr->trace_iolb = 1;
182  mr->verbosity = 5;
183 
184  KMR_KVS *kvs_infiles = kmr_create_kvs(mr, KMR_KV_INTEGER, KMR_KV_OPAQUE);
185  kmr_map_once(kvs_infiles, (void *)dirname, kmr_noopt, 1, read_files);
186 
187  KMR_KVS *kvs_targets = kmr_create_kvs(mr, KMR_KV_INTEGER, KMR_KV_OPAQUE);
188  if (noiolb) {
189  /* perform shuffle */
190  kmr_shuffle(kvs_infiles, kvs_targets, kmr_noopt);
191  } else {
192  /* perform file distribution based on locality */
193  kmr_assign_file(kvs_infiles, kvs_targets, kmr_noopt);
194  }
195 
196  KMR_KVS *kvs_times = kmr_create_kvs(mr, KMR_KV_INTEGER, KMR_KV_FLOAT8);
197  kmr_map(kvs_targets, kvs_times, NULL, kmr_noopt, benchmark);
198 
199  KMR_KVS *kvs_all_times = kmr_create_kvs(mr, KMR_KV_INTEGER, KMR_KV_FLOAT8);
200  kmr_shuffle(kvs_times, kvs_all_times, kmr_noopt);
201 
202  kmr_reduce(kvs_all_times, NULL, NULL, kmr_noopt, summarize);
203 
204  kmr_free_context(mr);
205  kmr_fin();
206  MPI_Finalize();
207  return 0;
208 }
Key-Value Stream (abstract).
Definition: kmr.h:587
#define kmr_reduce(KVI, KVO, ARG, OPT, R)
Reduces key-value pairs.
Definition: kmr.h:88
int kmr_add_kv(KMR_KVS *kvs, const struct kmr_kv_box kv)
Adds a key-value pair.
Definition: kmrbase.c:751
int kmr_map_once(KMR_KVS *kvo, void *arg, struct kmr_option opt, _Bool rank_zero_only, kmr_mapfn_t m)
Maps once.
Definition: kmrbase.c:1402
#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_shuffle(KMR_KVS *kvi, KMR_KVS *kvo, struct kmr_option opt)
Shuffles key-value pairs to the appropriate destination ranks.
Definition: kmrbase.c:2036
KMR Context.
Definition: kmr.h:222
int kmr_assign_file(KMR_KVS *kvi, KMR_KVS *kvo, struct kmr_option opt)
Assigns files to ranks based on data locality.
Definition: kmriolb.c:257
#define kmr_map(KVI, KVO, ARG, OPT, M)
Maps simply.
Definition: kmr.h:82
Handy Copy of a Key-Value Field.
Definition: kmr.h:358
int kmr_fin(void)
Clears the environment.
Definition: kmrbase.c:124
#define kmr_init()
Sets up the environment.
Definition: kmr.h:747
int kmr_free_context(KMR *mr)
Releases a context created with kmr_create_context().
Definition: kmrbase.c:326
KMR Interface.
KMR * kmr_create_context(const MPI_Comm comm, const MPI_Info conf, const char *name)
Makes a new KMR context (a context has type KMR).
Definition: kmrbase.c:147