Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'smpi' of git+ssh://scm.gforge.inria.fr//gitroot//simgrid/simgrid into...
[simgrid.git] / src / smpi / smpi_bench.c
1 /* Copyright (c) 2007, 2009, 2010. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5   * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include "private.h"
8 #include "xbt/dict.h"
9 #include "xbt/sysdep.h"
10 #include "xbt/ex.h"
11 #include "surf/surf.h"
12
13 #include <sys/mman.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <stdio.h>
21
22 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_bench, smpi,
23                                 "Logging specific to SMPI (benchmarking)");
24
25 /* Shared allocations are handled through shared memory segments.
26  * Associated data and metadata are used as follows:
27  *
28  *                                                                    mmap #1
29  *    `allocs' dict                                                     ---- -.
30  *    ----------      shared_data_t               shared_metadata_t   / |  |  |
31  * .->| <name> | ---> -------------------- <--.   -----------------   | |  |  |
32  * |  ----------      | fd of <name>     |    |   | size of mmap  | --| |  |  |
33  * |                  | count (2)        |    |-- | data          |   \ |  |  |
34  * `----------------- | <name>           |    |   -----------------     ----  |
35  *                    --------------------    |   ^                           |
36  *                                            |   |                           |
37  *                                            |   |   `allocs_metadata' dict  |
38  *                                            |   |   ----------------------  |
39  *                                            |   `-- | <addr of mmap #1>  |<-'
40  *                                            |   .-- | <addr of mmap #2>  |<-.
41  *                                            |   |   ----------------------  |
42  *                                            |   |                           |
43  *                                            |   |                           |
44  *                                            |   |                           |
45  *                                            |   |                   mmap #2 |
46  *                                            |   v                     ---- -'
47  *                                            |   shared_metadata_t   / |  |
48  *                                            |   -----------------   | |  |
49  *                                            |   | size of mmap  | --| |  |
50  *                                            `-- | data          |   | |  |
51  *                                                -----------------   | |  |
52  *                                                                    \ |  |
53  *                                                                      ----
54  */
55
56 #define PTR_STRLEN (2 + 2 * sizeof(void*) + 1)
57
58 xbt_dict_t allocs = NULL;          /* Allocated on first use */
59 xbt_dict_t allocs_metadata = NULL; /* Allocated on first use */
60 xbt_dict_t samples = NULL;         /* Allocated on first use */
61 xbt_dict_t calls = NULL;           /* Allocated on first use */
62 __thread int smpi_current_rank = 0;      /* Updated after each MPI call */
63
64 typedef struct {
65   int fd;
66   int count;
67   char* loc;
68 } shared_data_t;
69
70 typedef struct  {
71   size_t size;
72   shared_data_t* data;
73 } shared_metadata_t;
74
75 static size_t shm_size(int fd) {
76   struct stat st;
77
78   if(fstat(fd, &st) < 0) {
79     xbt_die("Could not stat fd %d: %s", fd, strerror(errno));
80   }
81   return (size_t)st.st_size;
82 }
83
84 static void* shm_map(int fd, size_t size, shared_data_t* data) {
85   void* mem;
86   char loc[PTR_STRLEN];
87   shared_metadata_t* meta;
88
89   if(size > shm_size(fd)) {
90     if(ftruncate(fd, (off_t)size) < 0) {
91       xbt_die("Could not truncate fd %d to %zu: %s", fd, size, strerror(errno));
92     }
93   }
94   mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
95   if(mem == MAP_FAILED) {
96     xbt_die("Could not map fd %d: %s", fd, strerror(errno));
97   }
98   if(!allocs_metadata) {
99     allocs_metadata = xbt_dict_new();
100   }
101   snprintf(loc, PTR_STRLEN, "%p", mem);
102   meta = xbt_new(shared_metadata_t, 1);
103   meta->size = size;
104   meta->data = data;
105   xbt_dict_set(allocs_metadata, loc, meta, &free);
106   XBT_DEBUG("MMAP %zu to %p", size, mem);
107   return mem;
108 }
109
110 typedef struct {
111   int count;
112   double sum;
113   double sum_pow2;
114   double mean;
115   double relstderr;
116   int iters;
117   double threshold;
118   int started;
119 } local_data_t;
120
121 void smpi_bench_destroy(void)
122 {
123   if (allocs) {
124     xbt_dict_free(&allocs);
125   }
126   if (samples) {
127     xbt_dict_free(&samples);
128   }
129   if(calls) {
130     xbt_dict_free(&calls);
131   }
132 }
133
134 static void smpi_execute_flops(double flops)
135 {
136   smx_action_t action;
137   smx_host_t host;
138   host = SIMIX_host_self();
139
140   XBT_DEBUG("Handle real computation time: %f flops", flops);
141   action = SIMIX_req_host_execute("computation", host, flops, 1);
142 #ifdef HAVE_TRACING
143   SIMIX_req_set_category (action, TRACE_internal_smpi_get_category());
144 #endif
145   SIMIX_req_host_execution_wait(action);
146 }
147
148 static void smpi_execute(double duration)
149 {
150   if (duration >= xbt_cfg_get_double(_surf_cfg_set, "smpi/cpu_threshold")) {
151     XBT_DEBUG("Sleep for %f to handle real computation time", duration);
152     smpi_execute_flops(duration *
153                        xbt_cfg_get_double(_surf_cfg_set,
154                                           "smpi/running_power"));
155   }
156 }
157
158 void smpi_bench_begin(void)
159 {
160   xbt_os_timer_start(smpi_process_timer());
161   smpi_current_rank = smpi_process_index();
162 }
163
164 void smpi_bench_end(void)
165 {
166   xbt_os_timer_t timer = smpi_process_timer();
167
168   xbt_os_timer_stop(timer);
169   smpi_execute(xbt_os_timer_elapsed(timer));
170 }
171
172 unsigned int smpi_sleep(unsigned int secs)
173 {
174   smpi_execute((double) secs);
175   return secs;
176 }
177
178 int smpi_gettimeofday(struct timeval *tv, struct timezone *tz)
179 {
180   double now;
181   smpi_bench_end();
182   now = SIMIX_get_clock();
183   if (tv) {
184     tv->tv_sec = (time_t)now;
185     tv->tv_usec = (suseconds_t)((now - tv->tv_sec) * 1e6);
186   }
187   smpi_bench_begin();
188   return 0;
189 }
190
191 static char *sample_location(int global, const char *file, int line)
192 {
193   if (global) {
194     return bprintf("%s:%d", file, line);
195   } else {
196     return bprintf("%s:%d:%d", file, line, smpi_process_index());
197   }
198 }
199
200 int smpi_sample_1(int global, const char *file, int line, int iters, double threshold)
201 {
202   char *loc = sample_location(global, file, line);
203   local_data_t *data;
204
205   smpi_bench_end();     /* Take time from previous MPI call into account */
206   if (!samples) {
207     samples = xbt_dict_new();
208   }
209   data = xbt_dict_get_or_null(samples, loc);
210   if (!data) {
211     data = (local_data_t *) xbt_new(local_data_t, 1);
212     data->count = 0;
213     data->sum = 0.0;
214     data->sum_pow2 = 0.0;
215     data->iters = iters;
216     data->threshold = threshold;
217     data->started = 0;
218     xbt_dict_set(samples, loc, data, &free);
219     return 0;
220   }
221   free(loc);
222   return 1;
223 }
224
225 int smpi_sample_2(int global, const char *file, int line)
226 {
227   char *loc = sample_location(global, file, line);
228   local_data_t *data;
229
230   xbt_assert(samples, "You did something very inconsistent, didn't you?");
231   data = xbt_dict_get_or_null(samples, loc);
232   if (!data) {
233     xbt_assert(data, "Please, do thing in order");
234   }
235   if (!data->started) {
236     if ((data->iters > 0 && data->count >= data->iters)
237         || (data->count > 1 && data->threshold > 0.0 && data->relstderr <= data->threshold)) {
238       XBT_DEBUG("Perform some wait of %f", data->mean);
239       smpi_execute(data->mean);
240     } else {
241       data->started = 1;
242       data->count++;
243     }
244   } else {
245     data->started = 0;
246   }
247   free(loc);
248   smpi_bench_begin();
249   smpi_process_simulated_start();
250   return data->started;
251 }
252
253 void smpi_sample_3(int global, const char *file, int line)
254 {
255   char *loc = sample_location(global, file, line);
256   local_data_t *data;
257   double sample, n;
258
259   xbt_assert(samples, "You did something very inconsistent, didn't you?");
260   data = xbt_dict_get_or_null(samples, loc);
261   smpi_bench_end();
262   if(data && data->started && data->count < data->iters) {
263     sample = smpi_process_simulated_elapsed();
264     data->sum += sample;
265     data->sum_pow2 += sample * sample;
266     n = (double)data->count;
267     data->mean = data->sum / n;
268     data->relstderr = sqrt((data->sum_pow2 / n - data->mean * data->mean) / n) / data->mean;
269     XBT_DEBUG("Average mean after %d steps is %f, relative standard error is %f (sample was %f)", data->count,
270            data->mean, data->relstderr, sample);
271   }
272   free(loc);
273 }
274
275 void smpi_sample_flops(double flops)
276 {
277   smpi_execute_flops(flops);
278 }
279
280 void *smpi_shared_malloc(size_t size, const char *file, int line)
281 {
282   char *loc = bprintf("%zu_%s_%d", (size_t)getpid(), file, line);
283   size_t len = strlen(loc);
284   size_t i;
285   int fd;
286   void* mem;
287   shared_data_t *data;
288
289   for(i = 0; i < len; i++) {
290     /* Make the 'loc' ID be a flat filename */
291     if(loc[i] == '/') {
292       loc[i] = '_';
293     }
294   }
295   if (!allocs) {
296     allocs = xbt_dict_new();
297   }
298   data = xbt_dict_get_or_null(allocs, loc);
299   if(!data) {
300     fd = shm_open(loc, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
301     if(fd < 0) {
302       switch(errno) {
303         case EEXIST:
304           xbt_die("Please cleanup /dev/shm/%s", loc);
305         default:
306           xbt_die("An unhandled error occured while opening %s: %s", loc, strerror(errno));
307       }
308     }
309     data = xbt_new(shared_data_t, 1);
310     data->fd = fd;
311     data->count = 1;
312     data->loc = loc;
313     mem = shm_map(fd, size, data);
314     if(shm_unlink(loc) < 0) {
315       XBT_WARN("Could not early unlink %s: %s", loc, strerror(errno));
316     }
317     xbt_dict_set(allocs, loc, data, &free);
318     XBT_DEBUG("Mapping %s at %p through %d", loc, mem, fd);
319   } else {
320     mem = shm_map(data->fd, size, data);
321     data->count++;
322   }
323   XBT_DEBUG("Malloc %zu in %p (metadata at %p)", size, mem, data);
324   return mem;
325 }
326
327 void smpi_shared_free(void *ptr)
328 {
329   char loc[PTR_STRLEN];
330   shared_metadata_t* meta;
331   shared_data_t* data;
332
333   if (!allocs) {
334     XBT_WARN("Cannot free: nothing was allocated");
335     return;
336   }
337   if(!allocs_metadata) {
338     XBT_WARN("Cannot free: no metadata was allocated");
339   }
340   snprintf(loc, PTR_STRLEN, "%p", ptr);
341   meta = (shared_metadata_t*)xbt_dict_get_or_null(allocs_metadata, loc);
342   if (!meta) {
343     XBT_WARN("Cannot free: %p was not shared-allocated by SMPI", ptr);
344     return;
345   }
346   data = meta->data;
347   if(!data) {
348     XBT_WARN("Cannot free: something is broken in the metadata link");
349     return;
350   }
351   if(munmap(ptr, meta->size) < 0) {
352     XBT_WARN("Unmapping of fd %d failed: %s", data->fd, strerror(errno));
353   }
354   data->count--;
355   if (data->count <= 0) {
356     close(data->fd);
357     xbt_dict_remove(allocs, data->loc);
358     free(data->loc);
359   }
360 }
361
362 int smpi_shared_known_call(const char* func, const char* input) {
363    char* loc = bprintf("%s:%s", func, input);
364    xbt_ex_t ex;
365    int known;
366
367    if(!calls) {
368       calls = xbt_dict_new();
369    }
370    TRY {
371       xbt_dict_get(calls, loc); /* Succeed or throw */
372       known = 1;
373    }
374    CATCH(ex) {
375       if(ex.category == not_found_error) {
376          known = 0;
377          xbt_ex_free(ex);
378       } else {
379          RETHROW;
380       }
381    }
382    free(loc);
383    return known;
384 }
385
386 void* smpi_shared_get_call(const char* func, const char* input) {
387    char* loc = bprintf("%s:%s", func, input);
388    void* data;
389
390    if(!calls) {
391       calls = xbt_dict_new();
392    }
393    data = xbt_dict_get(calls, loc);
394    free(loc);
395    return data;
396 }
397
398 void* smpi_shared_set_call(const char* func, const char* input, void* data) {
399    char* loc = bprintf("%s:%s", func, input);
400
401    if(!calls) {
402       calls = xbt_dict_new();
403    }
404    xbt_dict_set(calls, loc, data, NULL);
405    free(loc);
406    return data;
407 }