Merge branch 'release-4-6'
[alexxy/gromacs.git] / src / gromacs / gmxlib / thread_mpi / profile.c
1 /*
2    This source code file is part of thread_mpi.
3    Written by Sander Pronk, Erik Lindahl, and possibly others.
4
5    Copyright (c) 2009, Sander Pronk, Erik Lindahl.
6    All rights reserved.
7
8    Redistribution and use in source and binary forms, with or without
9    modification, are permitted provided that the following conditions are met:
10    1) Redistributions of source code must retain the above copyright
11    notice, this list of conditions and the following disclaimer.
12    2) Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15    3) Neither the name of the copyright holders nor the
16    names of its contributors may be used to endorse or promote products
17    derived from this software without specific prior written permission.
18
19    THIS SOFTWARE IS PROVIDED BY US ''AS IS'' AND ANY
20    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22    DISCLAIMED. IN NO EVENT SHALL WE BE LIABLE FOR ANY
23    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30    If you want to redistribute modifications, please consider that
31    scientific software is very special. Version control is crucial -
32    bugs must be traceable. We will be happy to consider code for
33    inclusion in the official distribution, but derived work should not
34    be called official thread_mpi. Details are found in the README & COPYING
35    files.
36  */
37
38
39 /* the profiling functions */
40
41 #ifdef HAVE_TMPI_CONFIG_H
42 #include "tmpi_config.h"
43 #endif
44
45 #ifdef HAVE_CONFIG_H
46 #include "config.h"
47 #endif
48
49 #ifdef HAVE_UNISTD_H
50 #include <unistd.h>
51 #endif
52
53 #include <errno.h>
54 #include <stdlib.h>
55 #include <stdio.h>
56 #include <string.h>
57 #if !(defined( _WIN32 ) || defined( _WIN64 ) )
58 #include <sys/time.h>
59 #else
60 /* windows doesn't do standard C */
61 #define snprintf sprintf_s
62 #endif
63
64
65 #include "impl.h"
66
67 #ifdef TMPI_TRACE
68 #include <stdarg.h>
69 #endif
70
71 int tMPI_Profile_started = 0;
72
73
74 /* this must match the tmpi_functions enum: */
75 const char *tmpi_function_names[] =
76 {
77     "Send",
78     "Recv",
79     "Sendrecv",
80     "Isend",
81     "Irecv",
82     "Wait",
83     "Test",
84     "Waitall",
85     "Testall",
86     "Waitany",
87     "Testany",
88     "Waitsome",
89     "Testsome",
90
91     "Barrier",
92
93     "Bcast",
94     "Gather",
95     "Gatherv",
96     "Scatter",
97     "Scatterv",
98     "Alltoall",
99     "Alltoallv",
100     "Reduce",
101     "Allreduce",
102     "Scan"
103 };
104
105
106 /* this must match the tmpi_wait_functions enum: */
107 const char *tmpi_waitfn_names[] =
108 {
109     "P2p",
110     "P2p signal",
111     "Coll. send",
112     "Coll. recv",
113     "Barrier",
114     "(All)Reduce",
115 };
116
117
118
119 /* we intentionally only do the ifdef here; this supresses warnings at the link
120    stage about empty object files */
121 #ifdef TMPI_PROFILE
122
123 int tMPI_Profile_init(struct tmpi_profile *prof)
124 {
125     int i;
126
127     /* reset counters */
128     for (i = 0; i < TMPIFN_Nfunctions; i++)
129     {
130         prof->mpifn_calls[i] = 0;
131     }
132 #ifdef TMPI_CYCLE_COUNT
133     for (i = 0; i < TMPIFN_Nfunctions; i++)
134     {
135         prof->mpifn_cycles[i] = 0;
136     }
137     for (i = 0; i < TMPIWAIT_N; i++)
138     {
139         prof->wait_cycles[i] = 0;
140     }
141     prof->global_start = tMPI_Cycles_read();
142     prof->global_stop  = 0;
143     prof->wait_start   = 0;
144 #endif
145
146     prof->buffered_p2p_xfers  = 0;
147     prof->buffered_coll_xfers = 0;
148     prof->total_p2p_xfers     = 0;
149     prof->total_coll_xfers    = 0;
150     tMPI_Profile_started      = 1;
151
152     return TMPI_SUCCESS;
153 }
154
155
156 #if 0
157 void tMPI_Profile_destroy(struct tmpi_profile *prof)
158 {
159 }
160 #endif
161
162
163
164 void tMPI_Profile_stop(struct tmpi_profile *prof)
165 {
166 #ifdef TMPI_CYCLE_COUNT
167     prof->global_stop = tMPI_Cycles_read();
168 #endif
169     tMPI_Profile_started = 0;
170 }
171
172 /* output functions */
173 void tMPI_Profiles_summarize(int Nthreads, struct tmpi_thread *threads)
174 {
175     int i, j, len = 0;
176
177     printf("\nTMPI PROFILE:\n");
178     printf("%11s", " ");
179     len += 11;
180     for (j = 0; j < Nthreads; j++)
181     {
182         char thrn[128];
183         snprintf(thrn, sizeof(thrn), "Thread %d", j);
184         printf(" %10s", thrn);
185         len += 11;
186     }
187     printf(" %10s\n", "Total");
188     len += 11;
189
190     /* print line */
191     for (i = 0; i < len; i++)
192     {
193         printf("-");
194     }
195     printf("\n");
196
197     for (i = 0; i < TMPIFN_Nfunctions; i++)
198     {
199         long unsigned int total = 0;
200
201         printf("%11s", tmpi_function_names[i]);
202         for (j = 0; j < Nthreads; j++)
203         {
204             long unsigned int count = threads[j].profile.mpifn_calls[i];
205
206             total += count;
207             printf(" %10ld", (long)count);
208         }
209         printf(" %10ld\n", (long)total);
210     }
211
212     printf("\nFraction of buffered transfers:\n");
213     {
214         long unsigned int tot_buf   = 0;
215         long unsigned int tot_count = 0;
216         printf("%11s", "P2p");
217         for (j = 0; j < Nthreads; j++)
218         {
219             long unsigned int buf   = threads[j].profile.buffered_p2p_xfers;
220             long unsigned int count = threads[j].profile.total_p2p_xfers;
221
222             tot_buf   += buf;
223             tot_count += count;
224
225             printf(" %10.5f", (double)buf/(double)count);
226         }
227         printf(" %10.5f\n", (double)tot_buf/(double)tot_count);
228
229         tot_buf   = 0;
230         tot_count = 0;
231         printf("%11s", "Collective");
232         for (j = 0; j < Nthreads; j++)
233         {
234             long unsigned int buf   = threads[j].profile.buffered_coll_xfers;
235             long unsigned int count = threads[j].profile.total_coll_xfers;
236
237             tot_buf   += buf;
238             tot_count += count;
239
240             printf(" %10.5f", (double)buf/(double)count);
241         }
242         printf(" %10.5f\n", (double)tot_buf/(double)tot_count);
243     }
244
245
246 #ifdef TMPI_CYCLE_COUNT
247     printf("\nCall times as fraction of total run time:\n");
248     for (j = 0; j < Nthreads; j++)
249     {
250         threads[j].profile.totals = 0.;
251     }
252     for (i = 0; i < TMPIFN_Nfunctions; i++)
253     {
254         double tot_time = 0.;
255         double tot_diff = 0.;
256
257         printf("%11s", tmpi_function_names[i]);
258         for (j = 0; j < Nthreads; j++)
259         {
260             double time = (double)(threads[j].profile.global_stop -
261                                    threads[j].profile.global_start );
262             double diff = ((double)threads[j].profile.mpifn_cycles[i]);
263             tot_time                  += time;
264             tot_diff                  += diff;
265             threads[j].profile.totals += diff;
266             printf(" %10.5f", diff/time);
267         }
268         printf(" %10.5f\n", tot_diff/tot_time);
269     }
270     {
271         double tot_time = 0.;
272         double tot_diff = 0.;
273
274         printf("%11s", "Total");
275         for (j = 0; j < Nthreads; j++)
276         {
277             double time = (double)(threads[j].profile.global_stop -
278                                    threads[j].profile.global_start );
279             double diff = threads[j].profile.totals;
280
281             tot_time += time;
282             tot_diff += diff;
283             printf(" %10.5f", diff/time );
284         }
285         printf(" %10.5f\n", tot_diff/tot_time);
286     }
287
288
289     printf("\nWait times as fraction of total run time:\n");
290     for (j = 0; j < Nthreads; j++)
291     {
292         threads[j].profile.totals = 0.;
293     }
294
295     for (i = 0; i < TMPIWAIT_N; i++)
296     {
297         double tot_time = 0.;
298         double tot_diff = 0.;
299
300         printf("%11s", tmpi_waitfn_names[i]);
301         for (j = 0; j < Nthreads; j++)
302         {
303             double time = (double)(threads[j].profile.global_stop -
304                                    threads[j].profile.global_start );
305             double diff = ((double)threads[j].profile.wait_cycles[i]);
306             tot_time                  += time;
307             tot_diff                  += diff;
308             threads[j].profile.totals += diff;
309             printf(" %10.5f", diff/time);
310         }
311         printf(" %10.5f\n", tot_diff/tot_time);
312     }
313
314     {
315         double tot_time = 0.;
316         double tot_diff = 0.;
317
318         printf("%11s", "Total");
319         for (j = 0; j < Nthreads; j++)
320         {
321             double time = (double)(threads[j].profile.global_stop -
322                                    threads[j].profile.global_start );
323             double diff = threads[j].profile.totals;
324
325             tot_time += time;
326             tot_diff += diff;
327             printf(" %10.5f", diff/time );
328         }
329         printf(" %10.5f\n", tot_diff/tot_time);
330     }
331 #endif
332     /* print line */
333     for (i = 0; i < len; i++)
334     {
335         printf("-");
336     }
337     printf("\n");
338
339     /* here we make use of the fact that this is how we calculate tMPI_Wtime */
340     {
341         double wt   = tMPI_Wtime();
342         double wtck = tMPI_Wtick();
343         printf("\nTotal run time: %g +/- %g s.\n", wt, wtck);
344     }
345
346     printf("\n");
347
348 }
349
350 #endif