DABC (Data Acquisition Backbone Core)  2.9.9
timing.cxx
Go to the documentation of this file.
1 // $Id: timing.cxx 4752 2021-03-25 13:46:48Z linev $
2 
3 /************************************************************
4  * The Data Acquisition Backbone Core (DABC) *
5  ************************************************************
6  * Copyright (C) 2009 - *
7  * GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
8  * Planckstr. 1, 64291 Darmstadt, Germany *
9  * Contact: http://dabc.gsi.de *
10  ************************************************************
11  * This software can be used under the GPL license *
12  * agreements as stated in LICENSE.txt file *
13  * which is part of the distribution. *
14  ************************************************************/
15 
16 #include "dabc/timing.h"
17 
18 #include <ctime>
19 #include <cmath>
20 #include <unistd.h>
21 #include <cstring>
22 
23 bool dabc::TimeStamp::gFast = false;
24 
26 
28 
29 double dabc::TimeStamp::gFastClockMult = CalculateFastClockMult(); // coefficient for slow timing
30 
32 {
33  timespec tm;
34  clock_gettime(CLOCK_MONOTONIC, &tm);
35  return tm.tv_sec*1000000000LL + tm.tv_nsec;
36 }
37 
38 
40 {
41  // if we cannot define that TSC is available - not use it
42  if (!CheckLinuxTSC()) {
43  gFast = false;
44  return 1e-9;
45  }
46 
47  slowclock_t slow1, slow2;
48  fastclock_t fast1, fast2;
49 
50  double sum1(0.), sum2(0.), coef(0.);
51 
52  const int num = 10;
53 
54  double values[num];
55 
56  for (int n=0;n<num;n++) {
57 
58  slow1 = GetSlowClock();
59  fast1 = GetFastClock();
60 
61  // we will use 10 millisecond sleep to increase precision
62  dabc::Sleep(0.01);
63 
64  slow2 = GetSlowClock();
65  fast2 = GetFastClock();
66 
67  if (fast1 == fast2) {
68  gFast = false;
69  return 1e-9;
70  }
71 
72  coef = (slow2-slow1) * 1e-9 / (fast2 - fast1);
73 
74  values[n] = coef;
75 
76 // printf("Measurement %d koef = %8.2f %lld %llu\n", n, coef>0 ? 1/coef : -1., slow2-slow1, fast2-fast1);
77 
78  sum1 += coef;
79  }
80 
81  double aver = num/sum1;
82 
83  for (int n=0;n<num;n++) {
84  sum2 += (1/values[n] - aver)*(1/values[n] - aver);
85  }
86 
87  double deviat = sqrt(sum2/num);
88 
89 // printf("Frequency = %8.2f Hz Deviat = %8.2f (rel:%8.7f) hz\n", aver, deviat, deviat/aver);
90 
91  if (deviat/aver>0.0001) {
92 // printf("Cannot use TSC for time measurement\n");
93  gFast = false;
94  } else {
95  gFast = true;
96  }
97 
98  return 1./aver;
99 }
100 
101 
103 {
104  FILE* f = fopen("/proc/cpuinfo","r");
105  if (!f) return false;
106 
107  bool can_use_tsc = false;
108  bool isgsiamd = false;
109 
110  char buf[1024];
111 
112  while(fgets(buf, sizeof(buf), f)) {
113  if (strstr(buf,"AMD Opteron(tm) Processor 248")!=0) {
114  // this is known type of AMD Opteron, we can use it in time measurement
115  isgsiamd = true;
116  break;
117  }
118 
119  if (strstr(buf,"constant_tsc")!=0) {
120  can_use_tsc = true;
121  break;
122  }
123  }
124  fclose(f);
125 
126  return can_use_tsc || isgsiamd;
127 }
128 
129 void dabc::Sleep(double tm)
130 {
131  if (tm<=0) return;
132 
133  struct timespec t;
134  t.tv_sec = lrint(tm); /* Whole seconds */
135  if (t.tv_sec > tm) t.tv_sec--;
136  t.tv_nsec = lrint((tm - t.tv_sec)*1e9); /* nanoseconds */
137 
138  if (t.tv_sec==0)
139  usleep(t.tv_nsec / 1000);
140  else
141  nanosleep (&t, 0);
142 }
143 
144 // ====================================================
145 
146 
148 {
149  timespec tm;
150  clock_gettime(CLOCK_REALTIME, &tm);
151 
152  tv_sec = tm.tv_sec;
153  tv_nsec = tm.tv_nsec;
154 
155  return *this;
156 }
157 
158 uint64_t dabc::DateTime::AsJSDate() const
159 {
160  return ((uint64_t) tv_sec) * 1000 + tv_nsec / 1000000;
161 }
162 
163 
164 std::string dabc::DateTime::AsString(int ndecimal, bool localtime) const
165 {
166  if (null()) return std::string();
167 
168  time_t src = tv_sec;
169  int frac = 0;
170 
171  if ((ndecimal>0) && (tv_nsec>0)) {
172  if (ndecimal>9) ndecimal = 9;
173  frac = tv_nsec;
174  int maxfrac = 1000000000;
175  int dec_cnt = ndecimal;
176  while (dec_cnt++<9) {
177  // this is rounding rule - if last digit 5 or more, we must increment by 1
178  frac = frac / 10 + ((frac % 10 >= 5) ? 1 : 0);
179  maxfrac = maxfrac / 10;
180  // DOUT0("NSEC = %u FRAC = %d MAXFRAC = %d", tv_nsec, frac, maxfrac);
181  }
182  if (frac >= maxfrac) { src++; frac = 0; }
183  }
184 
185  struct tm res;
186 
187  if (localtime)
188  localtime_r(&src, &res);
189  else
190  gmtime_r(&src, &res);
191 
192  char sbuf[50];
193 
194  strftime(sbuf, sizeof(sbuf), "%Y-%m-%d %H:%M:%S", &res);
195 
196  if (frac>0) {
197  int rlen = strlen(sbuf);
198  int remain = (int)sizeof(sbuf) - rlen;
199  if (remain > ndecimal + 1)
200  snprintf(sbuf+rlen, remain, ".%0*d", ndecimal, frac);
201  }
202 
203  return std::string(sbuf);
204 }
205 
207 {
208  return tv_sec + tv_nsec*1e-9;
209 }
210 
211 
212 std::string dabc::DateTime::AsJSString(int ndecimal) const
213 {
214  if (null()) return std::string();
215  char sbuf[50];
216 
217  time_t src = tv_sec;
218  int frac = 0;
219 
220  if ((ndecimal>0) && (tv_nsec>0)) {
221  if (ndecimal>9) ndecimal = 9;
222  frac = tv_nsec;
223  int maxfrac = 1000000000;
224  int dec_cnt = ndecimal;
225  while (dec_cnt++<9) {
226  // this is rounding rule - if last digit 5 or more, we must increment by 1
227  frac = frac / 10 + ((frac % 10 >= 5) ? 1 : 0);
228  maxfrac = maxfrac / 10;
229  // DOUT0("NSEC = %u FRAC = %d MAXFRAC = %d", tv_nsec, frac, maxfrac);
230  }
231  if (frac >= maxfrac) { src++; frac = 0; }
232  }
233 
234  struct tm res;
235 
236  gmtime_r(&src, &res);
237 
238  strftime(sbuf, sizeof(sbuf), "%Y-%m-%dT%H:%M:%S", &res);
239 
240  if (frac > 0) {
241  int rlen = strlen(sbuf);
242  int remains = (int)sizeof(sbuf) - rlen;
243  if (remains - rlen > ndecimal + 1)
244  snprintf(sbuf+rlen, remains-1, ".%0*d", ndecimal, frac);
245  }
246 
247  int rlen = strlen(sbuf);
248  if (rlen >= (int)sizeof(sbuf)-1) return std::string();
249 
250  sbuf[rlen] = 'Z';
251  sbuf[rlen+1] = 0;
252 
253  return std::string(sbuf);
254 }
255 
256 
257 std::string dabc::DateTime::OnlyDateAsString(const char *separ, bool localtime) const
258 {
259  if (null()) return std::string();
260  time_t src = tv_sec;
261  struct tm res;
262  if (localtime)
263  localtime_r(&src, &res);
264  else
265  gmtime_r(&src, &res);
266  if (!separ) separ = "-";
267  std::string fmt = std::string("%Y") + separ + "%m" + separ + "%d";
268  char sbuf[200];
269  strftime(sbuf, sizeof(sbuf), fmt.c_str(), &res);
270  return std::string(sbuf);
271 }
272 
273 std::string dabc::DateTime::OnlyTimeAsString(const char *separ, bool localtime) const
274 {
275  if (null()) return std::string();
276  time_t src = tv_sec;
277  struct tm res;
278  if (localtime)
279  localtime_r(&src, &res);
280  else
281  gmtime_r(&src, &res);
282  if (!separ) separ = ":";
283  std::string fmt = std::string("%H") + separ + "%M" + separ + "%S";
284  char sbuf[200];
285  strftime(sbuf, sizeof(sbuf), fmt.c_str(), &res);
286  return std::string(sbuf);
287 }
288 
289 bool dabc::DateTime::SetOnlyDate(const char* sbuf)
290 {
291  if ((sbuf==0) || (strlen(sbuf)!=10)) return false;
292 
293  unsigned year(0), month(0), day(0);
294  if (sscanf(sbuf,"%4u-%02u-%02u", &year, &month, &day)!=3) return false;
295  if ((year<1970) || (year>2100) || (month>12) || (month==0) || (day>31) || (day==0)) return false;
296 
297  struct tm res;
298  time_t src = tv_sec;
299  gmtime_r(&src, &res);
300  res.tm_year = year - 1900;
301  res.tm_mon = month - 1;
302  res.tm_mday = day;
303  res.tm_isdst = 0;
304  tv_sec = timegm(&res); // SHOULD we implement timegm ourself??
305  return true;
306 }
307 
308 bool dabc::DateTime::SetOnlyTime(const char* sbuf)
309 {
310  if ((sbuf==0) || (strlen(sbuf)!=8)) return false;
311 
312  unsigned hour(0), min(0), sec(0);
313  if (sscanf(sbuf,"%02u:%02u:%02u", &hour, &min, &sec)!=3) return false;
314  if ((hour>23) || (min>59) || (sec>59)) return false;
315 
316  struct tm res;
317  if (null()) {
318  memset(&res, 0, sizeof(res));
319  } else {
320  time_t src = tv_sec;
321  gmtime_r(&src, &res);
322  }
323 
324  res.tm_hour = hour;
325  res.tm_min = min;
326  res.tm_sec = sec;
327 
328  tv_sec = timegm(&res); // SHOULD we implement timegm ourself??
329  return true;
330 }
331 
332 double dabc::DateTime::DistanceTo(const DateTime& pnt) const
333 {
334  if (null()) return pnt.AsDouble();
335  if (pnt.null()) return -1. * AsDouble();
336 
337  // to exclude precision lost, calculate sec and nanosec separately
338 
339  double res = (pnt.tv_sec >= tv_sec) ? 1.*(pnt.tv_sec - tv_sec) : -1. * (tv_sec - pnt.tv_sec);
340 
341  if (pnt.tv_nsec >= tv_nsec) res += 1e-9* (pnt.tv_nsec - tv_nsec);
342  else res -= 1e-9 * (tv_nsec - pnt.tv_nsec);
343 
344  return res;
345 }
346 
347 
Class for holding GMT time with precision of nanoseconds.
Definition: timing.h:190
unsigned tv_nsec
Definition: timing.h:193
bool SetOnlyTime(const char *sbuf)
Set only time part of DateTime.
Definition: timing.cxx:308
std::string OnlyTimeAsString(const char *separ=nullptr, bool localtime=false) const
Fills only time as string.
Definition: timing.cxx:273
bool null() const
Definition: timing.h:210
std::string AsJSString(int ndecimal=3) const
convert string into sec.frac format, can be interpret directly in JavaScript ISO 8601 standard is use...
Definition: timing.cxx:212
double AsDouble() const
Return date and time in seconds since 1.1.1970.
Definition: timing.cxx:206
uint64_t AsJSDate() const
Return date and time in JS format - number of millisecond since 1.1.1970.
Definition: timing.cxx:158
std::string AsString(int ndecimal=0, bool localtime=false) const
convert string into human-readable format, cannot be interpret directly in JavaScript
Definition: timing.cxx:164
DateTime & GetNow()
Definition: timing.cxx:147
double DistanceTo(const DateTime &src) const
Return distance in seconds to provided date.
Definition: timing.cxx:332
bool SetOnlyDate(const char *sbuf)
Set only date part from the string.
Definition: timing.cxx:289
std::string OnlyDateAsString(const char *separ=nullptr, bool localtime=false) const
Fills only date as string.
Definition: timing.cxx:257
unsigned tv_sec
Definition: timing.h:192
void Sleep(double tm)
Definition: timing.cxx:129
static slowclock_t GetSlowClock()
Definition: timing.cxx:31
static double gFastClockMult
Definition: timing.h:85
slowclock_t fastclock_t
Definition: timing.h:80
static double CalculateFastClockMult()
Definition: timing.cxx:39
static bool gFast
indicates if fast or slow method is used for time measurement
Definition: timing.h:47
static slowclock_t gSlowClockZero
Definition: timing.h:51
static fastclock_t GetFastClock()
Definition: timing.h:81
static fastclock_t gFastClockZero
Definition: timing.h:84
static bool CheckLinuxTSC()
Definition: timing.cxx:102
long long int slowclock_t
Definition: timing.h:49