MADNESS 0.10.1
timers.h
Go to the documentation of this file.
1/*
2 This file is part of MADNESS.
3
4 Copyright (C) 2007,2010 Oak Ridge National Laboratory
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 For more information please contact:
21
22 Robert J. Harrison
23 Oak Ridge National Laboratory
24 One Bethel Valley Road
25 P.O. Box 2008, MS-6367
26
27 email: harrisonrj@ornl.gov
28 tel: 865-241-3937
29 fax: 865-572-0680
30*/
31
32/**
33 \file timers.h
34 \brief Wrappers around platform dependent timers and performance info.
35 \ingroup parallel_runtime
36*/
37
38#ifndef MADNESS_WORLD_TIMERS_H__INCLUDED
39#define MADNESS_WORLD_TIMERS_H__INCLUDED
40
41#include <chrono>
42#include <cstdint>
43#include <ctime>
44#include <time.h> // clock_gettime, CLOCK_PROCESS_CPUTIME_ID (POSIX, not in <ctime>)
45#include <sys/time.h>
46#include <unistd.h>
48
49#ifdef _CRAY
50#include <catamount/dclock.h>
51#endif
52
53#ifdef HAVE_IBMBGP
54# define BG_CYCLES_PER_MICROSECOND 850
55# define BG_SECONDS_PER_CYCLE 1.176470588235294033e-09
56# include </bgsys/drivers/ppcfloor/arch/include/bpcore/ppc450_inlines.h>
57#endif
58
59#ifdef HAVE_IBMBGQ
60# define BG_CYCLES_PER_MICROSECOND 1600
61# define BG_SECONDS_PER_CYCLE 6.25e-10
62# include <hwi/include/bqc/A2_inlines.h>
63#endif
64
65
66namespace madness {
67
68 /// Returns the wall time in seconds relative to an arbitrary origin.
69
70 /// As accurate and lightweight as we can get it, but may not
71 /// be any better than the gettime of day system call.
72 /// \return The wall time (in seconds).
73 double wall_time();
74
75 /// On some machines we have access to a cycle count.
76
77 /// For small intervals this is probably the most lightweight and accurate timer
78 /// but may not be meaningful over long intervals due to O/S scheduling,
79 /// migration to different cores, frequency shifts, etc. On x86 uses rtdsc.
80 /// Otherwise uses wall_time() in nanoseconds.
81 /// \return Timing, in cycle count.
82 static inline uint64_t cycle_count() {
83 uint64_t x;
84#if defined(HAVE_IBMBGP)
85 unsigned int rx, ry, rz;
86 do
87 {
88 asm volatile ( "mftbu %0" : "=r"(rx) );
89 asm volatile ( "mftb %0" : "=r"(ry) );
90 asm volatile ( "mftbu %0" : "=r"(rz) );
91 }
92 while ( rx != rz );
93 x = rx;
94 x = (x << 32) | ry;
95#elif defined(HAVE_IBMBGQ)
96/* Jeff could use the asm above but is pretending this is more portable */
97 x = GetTimeBase();
98#elif defined(X86_32)
99 __asm__ volatile(".byte 0x0f, 0x31" : "=A"(x));
100#elif defined(X86_64)
101 unsigned int a,d;
102 __asm__ volatile("rdtsc" : "=a"(a), "=d"(d));
103 x = ((uint64_t)a) | (((uint64_t)d)<<32);
104#else
105 x = wall_time()*1e9;
106#endif
107 return x;
108 }
109
110 /// Estimate the processor frequency, in Hz.
111
112 /// First call may take about 0.1s to execute. Subsequent
113 /// calls return the value, cached from the first call, so it does
114 /// not respond to changing processor frequency.
115 ///
116 /// If \c cycle_count() returns \c wall_time() in nanoseconds,
117 /// this will return 1GHz.
118 ///
119 /// If not available returns 0.
120 /// \return CPU frequency, in Hz.
121 double cpu_frequency();
122
123 /// Returns the cpu time in seconds relative to an arbitrary origin.
124
125 /// As accurate and lightweight as we can get it, but may not
126 /// be any better than the clock system call.
127 /// \return The cpu time, in second.
128 static inline double cpu_time() {
129#if defined(X86_32) || defined(X86_64) || defined(HAVE_IBMBGP)
130 static const double rfreq = 1.0/cpu_frequency();
131 return cycle_count()*rfreq;
132#elif defined(_CRAY)
133 return dclock();
134#elif defined(HAVE_IBMBGP)
136#elif defined(HAVE_IBMBGQ)
138#else
139 const auto now = std::chrono::steady_clock::now();
140 const auto nanoseconds_since_epoch = std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
141 return nanoseconds_since_epoch / 1e9;
142#endif
143 }
144
145 /// Returns the CPU time consumed by this process, in seconds.
146
147 /// Aggregated over all threads of the process, so a task's compute time can be
148 /// separated from its idle time. This is *not* what cpu_time() returns: that
149 /// reads a cycle counter on x86 and therefore measures elapsed time. An
150 /// instrumentation helper, not part of the documented timing API.
151 /// \return The process CPU time (in seconds).
152 static inline double process_cpu_time() {
153#if defined(CLOCK_PROCESS_CPUTIME_ID)
154 struct timespec ts;
156 return static_cast<double>(ts.tv_sec) + 1.0e-9 * static_cast<double>(ts.tv_nsec);
157 }
158#endif
159 return static_cast<double>(std::clock()) / static_cast<double>(CLOCKS_PER_SEC);
160 }
161
162
163 /// Do nothing and especially do not touch memory.
164
165 /// \todo Can we provide some context for this function?
166 inline void cpu_relax() {
167#if defined(X86_32) || defined(X86_64)
168 asm volatile("rep;nop" : : : "memory");
169#elif defined(HAVE_IBMBGP) || defined(HAVE_IBMBGQ)
170 asm volatile ("nop\n");
171#else
172 /* Jeff has no idea if this is actually portable.
173 * See https://en.wikipedia.org/wiki/NOP for details. */
174 asm volatile ("nop\n");
175#endif
176 }
177
178 /// Sleep or spin for specified number of microseconds.
179
180 /// Wrapper to ensure desired behavior across various platforms.
181 /// \param[in] us The number of microseconds.
182 static inline void myusleep(unsigned int us) {
183#if defined(HAVE_CRAYXT)
184 double secs = us*1e-6;
185 double start = cpu_time();
186 while (cpu_time()-start < secs) {
187 for (int i=0; i<100; ++i) cpu_relax();
188 }
189#elif defined(HAVE_IBMBGP) || defined(HAVE_IBMBGQ)
190 int count = BG_CYCLES_PER_MICROSECOND*us; // ??????
191 for (int i=0; i<count; i++) {
192 asm volatile ("nop\n");
193 }
194#else
195 usleep(us);
196#endif
197 }
198}
199
200#endif // MADNESS_WORLD_TIMERS_H__INCLUDED
Macros and tools pertaining to the configuration of MADNESS.
Namespace for all elements and tools of MADNESS.
Definition DFParameters.h:10
static double process_cpu_time()
Returns the CPU time consumed by this process, in seconds.
Definition timers.h:152
static double cpu_time()
Returns the cpu time in seconds relative to an arbitrary origin.
Definition timers.h:128
static void myusleep(unsigned int us)
Sleep or spin for specified number of microseconds.
Definition timers.h:182
double cpu_frequency()
Estimate the processor frequency, in Hz.
Definition timers.cc:79
double wall_time()
Returns the wall time in seconds relative to an arbitrary origin.
Definition timers.cc:48
void cpu_relax()
Do nothing and especially do not touch memory.
Definition timers.h:166
static uint64_t cycle_count()
On some machines we have access to a cycle count.
Definition timers.h:82
static XNonlinearSolver< std::vector< Function< T, NDIM > >, T, vector_function_allocator< T, NDIM > > nonlinear_vector_solver(World &world, const long nvec)
Definition nonlinsol.h:371
static const double d
Definition nonlinschro.cc:121
static const double a
Definition nonlinschro.cc:118
void e()
Definition test_sig.cc:75