2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2013, The GROMACS development team.
5 * Copyright (c) 2013,2014,2015,2016,2017, by the GROMACS development team, led by
6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 * and including many others, as listed in the AUTHORS file in the
8 * top-level source directory and at http://www.gromacs.org.
10 * GROMACS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * GROMACS is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with GROMACS; if not, see
22 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If you want to redistribute modifications to GROMACS, please
26 * consider that scientific software is very special. Version
27 * control is crucial - bugs must be traceable. We will be happy to
28 * consider code for inclusion in the official distribution, but
29 * derived work must not be called official GROMACS. Details are found
30 * in the README & COPYING files - if they are missing, get the
31 * official version at http://www.gromacs.org.
33 * To help us fund GROMACS development, we humbly ask that you cite
34 * the research papers on the package. Check out http://www.gromacs.org.
38 #include "walltime_accounting.h"
47 #ifdef HAVE_SYS_TIME_H
51 #include "gromacs/utility/basedefinitions.h"
52 #include "gromacs/utility/smalloc.h"
54 /* TODO in future: convert gmx_walltime_accounting to a class,
55 * resolve who should have responsibility for recording the number of
56 * steps done, consider whether parts of finish_time, print_perf,
57 * wallcycle_print belong in this module.
59 * If/when any kind of task parallelism is implemented (even OpenMP
60 * regions simultaneously assigned to different tasks), consider
61 * whether this data structure (and/or cycle counters) should be
62 * maintained on a per-OpenMP-thread basis.
64 * Consider also replacing this with std::chrono. */
66 /*! \brief Manages caching wall-clock time measurements for
68 typedef struct gmx_walltime_accounting {
69 //! Seconds since the epoch recorded at the start of the simulation
70 double start_time_stamp;
71 //! Seconds since the epoch recorded at the start of the simulation for this thread
72 double start_time_stamp_per_thread;
73 //! Total seconds elapsed over the simulation
75 //! Total seconds elapsed over the simulation running this thread
76 double elapsed_time_over_all_threads;
77 /*! \brief Number of OpenMP threads that will be launched by this
80 * This is used to scale elapsed_time_over_all_threads so
81 * that any combination of real MPI, thread MPI and OpenMP (even
82 * mdrun -ntomp_pme) processes/threads would (when run at maximum
83 * efficiency) return values such that the sum of
84 * elapsed_time_over_all_threads over all threads was constant
85 * with respect to parallelism implementation. */
87 //! Set by integrators to report the amount of work they did
88 gmx_int64_t nsteps_done;
89 //! Whether the simulation has finished in a way valid for walltime reporting.
91 } t_gmx_walltime_accounting;
93 /*! \brief Calls system timing routines (e.g. clock_gettime) to get
94 * the (fractional) number of seconds elapsed since the epoch when
95 * this thread was executing.
97 * This can be used to measure system load. This can be unreliable if
98 * threads migrate between sockets. If thread-specific timers are not
99 * supported by the OS (e.g. if the OS is not POSIX-compliant), this
100 * function is implemented by gmx_gettime. */
101 static double gmx_gettime_per_thread();
103 // TODO In principle, all this should get protected by checks that
104 // walltime_accounting is not null. In practice, that NULL condition
105 // does not happen, and future refactoring will likely enforce it by
106 // having the gmx_walltime_accounting_t object be owned by the runner
107 // object. When these become member functions, existence will be
110 gmx_walltime_accounting_t
111 walltime_accounting_init(int numOpenMPThreads)
113 gmx_walltime_accounting_t walltime_accounting;
115 snew(walltime_accounting, 1);
116 walltime_accounting->start_time_stamp = 0;
117 walltime_accounting->start_time_stamp_per_thread = 0;
118 walltime_accounting->elapsed_time = 0;
119 walltime_accounting->nsteps_done = 0;
120 walltime_accounting->numOpenMPThreads = numOpenMPThreads;
121 walltime_accounting->isValidFinish = false;
123 return walltime_accounting;
127 walltime_accounting_destroy(gmx_walltime_accounting_t walltime_accounting)
129 sfree(walltime_accounting);
133 walltime_accounting_start(gmx_walltime_accounting_t walltime_accounting)
135 walltime_accounting->start_time_stamp = gmx_gettime();
136 walltime_accounting->start_time_stamp_per_thread = gmx_gettime_per_thread();
137 walltime_accounting->elapsed_time = 0;
138 walltime_accounting->nsteps_done = 0;
142 walltime_accounting_end(gmx_walltime_accounting_t walltime_accounting)
144 double now, now_per_thread;
147 now_per_thread = gmx_gettime_per_thread();
149 walltime_accounting->elapsed_time = now - walltime_accounting->start_time_stamp;
150 walltime_accounting->elapsed_time_over_all_threads = now_per_thread - walltime_accounting->start_time_stamp_per_thread;
151 /* For thread-MPI, the per-thread CPU timer makes this just
152 * work. For OpenMP threads, the per-thread CPU timer measurement
153 * needs to be multiplied by the number of OpenMP threads used,
154 * under the current assumption that all regions ever opened
155 * within a process are of the same size, and each thread should
156 * keep one core busy.
158 walltime_accounting->elapsed_time_over_all_threads *= walltime_accounting->numOpenMPThreads;
162 walltime_accounting_get_current_elapsed_time(gmx_walltime_accounting_t walltime_accounting)
164 return gmx_gettime() - walltime_accounting->start_time_stamp;
168 walltime_accounting_get_elapsed_time(gmx_walltime_accounting_t walltime_accounting)
170 return walltime_accounting->elapsed_time;
174 walltime_accounting_get_elapsed_time_over_all_threads(gmx_walltime_accounting_t walltime_accounting)
176 return walltime_accounting->elapsed_time_over_all_threads;
180 walltime_accounting_get_start_time_stamp(gmx_walltime_accounting_t walltime_accounting)
182 return walltime_accounting->start_time_stamp;
186 walltime_accounting_get_nsteps_done(gmx_walltime_accounting_t walltime_accounting)
188 return walltime_accounting->nsteps_done;
192 walltime_accounting_set_nsteps_done(gmx_walltime_accounting_t walltime_accounting,
193 gmx_int64_t nsteps_done)
195 walltime_accounting->nsteps_done = nsteps_done;
201 /* Use clock_gettime only if we know linking the C run-time
202 library will work (which is not trivial on e.g. Crays), and its
203 headers claim sufficient support for POSIX (ie not Mac and
204 Windows), and it isn't BG/Q (whose compute node kernel only
205 supports gettimeofday, and bgclang doesn't provide a fully
206 functional implementation clock_gettime). */
207 #if HAVE_CLOCK_GETTIME && defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && !(defined __bgq__ && defined __clang__)
211 clock_gettime(CLOCK_REALTIME, &t);
212 seconds = static_cast<double>(t.tv_sec) + 1e-9*t.tv_nsec;
215 #elif HAVE_GETTIMEOFDAY
216 // Note that gettimeofday() is deprecated by POSIX, but since Mac
217 // and Windows do not yet support POSIX, we are still stuck.
218 // Also, this is the only supported API call on Bluegene/Q.
222 gettimeofday(&t, NULL);
223 seconds = static_cast<double>(t.tv_sec) + 1e-6*t.tv_usec;
229 seconds = time(NULL);
236 walltime_accounting_set_valid_finish(gmx_walltime_accounting_t walltime_accounting)
238 walltime_accounting->isValidFinish = true;
241 //! Return whether the simulation finished in a way valid for reporting walltime.
243 walltime_accounting_get_valid_finish(const gmx_walltime_accounting_t walltime_accounting)
245 return walltime_accounting->isValidFinish;
249 gmx_gettime_per_thread()
251 /* Use clock_gettime only if we know linking the C run-time
252 library will work (which is not trivial on e.g. Crays), and its
253 headers claim sufficient support for POSIX (ie not Mac and
254 Windows), and it isn't BG/Q (whose compute node kernel only
255 supports gettimeofday, and bgclang doesn't provide a fully
256 functional implementation clock_gettime). */
257 #if HAVE_CLOCK_GETTIME && defined(_POSIX_THREAD_CPUTIME) && _POSIX_THREAD_CPUTIME > 0 && !(defined __bgq__ && defined __clang__)
261 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t);
262 seconds = static_cast<double>(t.tv_sec) + 1e-9*t.tv_nsec;
266 return gmx_gettime();