Flowgrind
Advanced TCP traffic generator
fg_time.c
Go to the documentation of this file.
1 
6 /*
7  * Copyright (C) 2014 Alexander Zimmermann <alexander.zimmermann@netapp.com>
8  * Copyright (C) 2010-2013 Christian Samsel <christian.samsel@rwth-aachen.de>
9  * Copyright (C) 2007-2008 Daniel Schaffrath <daniel.schaffrath@mac.com>
10  *
11  * This file is part of Flowgrind.
12  *
13  * Flowgrind is free software: you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation, either version 3 of the License, or
16  * (at your option) any later version.
17  *
18  * Flowgrind is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with Flowgrind. If not, see <http://www.gnu.org/licenses/>.
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif /* HAVE_CONFIG_H */
31 
32 #include <assert.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <time.h>
36 #include <stdbool.h>
37 
38 /* OS X hasn't defined POSIX clocks */
39 #if !defined(HAVE_CLOCK_GETTIME) && defined HAVE_CLOCK_GET_TIME
40 #include <mach/clock.h>
41 #include <mach/mach.h>
42 #endif /* !defined(HAVE_CLOCK_GETTIME) && defined HAVE_CLOCK_GET_TIME */
43 
44 #include "fg_time.h"
45 
46 
47 const char *ctimenow_r(char *buf, size_t size, bool ns)
48 {
49  struct timespec now;
50 
51  gettime(&now);
52 
53  return ctimespec_r(&now, buf, size, ns);
54 }
55 
56 const char *ctimenow(bool ns)
57 {
58  struct timespec now;
59 
60  gettime(&now);
61 
62  return ctimespec(&now, ns);
63 }
64 
65 
66 const char *ctimespec_r(const struct timespec *tp, char *buf, size_t size,
67  bool ns)
68 {
69  struct tm tm;
70 
71  /* Converts the calendar time to broken-down time representation,
72  * expressed relative to the user's specified timezone */
73  tzset();
74  localtime_r(&tp->tv_sec, &tm);
75 
76  /* Converts broken-down time representation into a string */
77  size_t len = strftime(buf, size, "%F-%T", &tm);
78 
79  /* Append nanoseconds to string */
80  if (ns)
81  snprintf(buf+len, size-len, ".%09ld", tp->tv_nsec);
82 
83  return buf;
84 }
85 
86 const char *ctimespec(const struct timespec *tp, bool ns)
87 {
88  static char buf[30];
89 
90  ctimespec_r(tp, buf, sizeof(buf), ns);
91 
92  return buf;
93 }
94 
95 double time_diff(const struct timespec *tp1, const struct timespec *tp2)
96 {
97  return (double) (tp2->tv_sec - tp1->tv_sec)
98  + (double) (tp2->tv_nsec - tp1->tv_nsec) / (long) NSEC_PER_SEC;
99 }
100 
101 double time_diff_now(const struct timespec *tp)
102 {
103  struct timespec now;
104 
105  gettime(&now);
106  return (double) (now.tv_sec - tp->tv_sec)
107  + (double) (now.tv_nsec - tp->tv_nsec) / (long) NSEC_PER_SEC;
108 }
109 
110 bool time_is_after(const struct timespec *tp1, const struct timespec *tp2)
111 {
112  if (tp1->tv_sec > tp2->tv_sec)
113  return true;
114  if (tp1->tv_sec < tp2->tv_sec)
115  return false;
116  return tp1->tv_nsec > tp2->tv_nsec;
117 }
118 
119 bool normalize_tp(struct timespec *tp)
120 {
121  bool normalized = true;
122 
123  while (tp->tv_nsec >= (long) NSEC_PER_SEC) {
124  tp->tv_nsec -= (long) NSEC_PER_SEC;
125  tp->tv_sec++;
126  normalized = false;
127  }
128  while (tp->tv_nsec < 0) {
129  tp->tv_nsec += (long) NSEC_PER_SEC;
130  tp->tv_sec--;
131  normalized = false;
132  }
133  return normalized;
134 }
135 
136 void time_add(struct timespec *tp, double seconds)
137 {
138  tp->tv_sec += (time_t) seconds;
139  tp->tv_nsec += (long) ((seconds - (time_t) seconds) * (long) NSEC_PER_SEC);
140  normalize_tp(tp);
141 }
142 
143 /* Linux and FreeBSD have POSIX clocks */
144 #if defined HAVE_CLOCK_GETTIME
145 int gettime(struct timespec *tp)
146 {
147  static struct timespec res = {.tv_sec = 0, .tv_nsec = 0};
148 
149  /* Find out clock resolution. Will only be retrieved on first call */
150  if (!res.tv_sec && !res.tv_nsec) {
151  clock_getres(CLOCK_REALTIME, &res);
152  /* Clock resolution is lower than expected (1ns) */
153  assert(res.tv_nsec == 1);
154  }
155 
156  /* Get wall-clock time */
157  return clock_gettime(CLOCK_REALTIME, tp);
158 }
159 /* OS X hasn't defined POSIX clocks, but clock_get_time() */
160 #elif defined HAVE_CLOCK_GET_TIME
161 int gettime(struct timespec *tp)
162 {
163  static struct timespec res = {.tv_sec = 0, .tv_nsec = 0};
164  clock_serv_t cclock;
165 
166  host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
167 
168  /* Find out clock resolution. Will only be retrieved on first call */
169  if (!res.tv_sec && !res.tv_nsec) {
170  natural_t attribute[4];
171  mach_msg_type_number_t count = sizeof(attribute)/sizeof(natural_t);
172  clock_get_attributes(cclock, CLOCK_GET_TIME_RES,
173  (clock_attr_t) &attribute, &count);
174  /* Clock resolution is lower than expected (1ns) */
175  assert(attribute[0] > 1);
176  }
177 
178  mach_timespec_t mts;
179  kern_return_t rc = clock_get_time(cclock, &mts);
180  mach_port_deallocate(mach_task_self(), cclock);
181 
182  tp->tv_sec = mts.tv_sec;
183  tp->tv_nsec = mts.tv_nsec;
184 
185  return (rc == KERN_SUCCESS ? 0 : -1);
186 }
187 #endif /* HAVE_CLOCK_GETTIME */
time_add
void time_add(struct timespec *tp, double seconds)
Add an amount of time seconds to a specific point in time tp.
Definition: fg_time.c:136
NSEC_PER_SEC
#define NSEC_PER_SEC
Number of nanoseconds per second.
Definition: fg_time.h:41
time_diff
double time_diff(const struct timespec *tp1, const struct timespec *tp2)
Returns the time difference between two the specific points in time tp1 and tp2.
Definition: fg_time.c:95
time_is_after
bool time_is_after(const struct timespec *tp1, const struct timespec *tp2)
Returns true if second point in time tp2 is chronologically after the first point in time tp1.
Definition: fg_time.c:110
time_diff_now
double time_diff_now(const struct timespec *tp)
Returns time difference between now and the specific point in time tp.
Definition: fg_time.c:101
ctimespec_r
const char * ctimespec_r(const struct timespec *tp, char *buf, size_t size, bool ns)
Converts timespec struct tp into a null-terminated string.
Definition: fg_time.c:66
normalize_tp
bool normalize_tp(struct timespec *tp)
Normalizes timespec struct tp.
Definition: fg_time.c:119
fg_time.h
Timing related routines used by Flowgrind.
config.h
ctimenow_r
const char * ctimenow_r(char *buf, size_t size, bool ns)
Returns the current wall-clock time as null-terminated string.
Definition: fg_time.c:47
ctimespec
const char * ctimespec(const struct timespec *tp, bool ns)
Converts timespec struct tp into a null-terminated string.
Definition: fg_time.c:86
gettime
int gettime(struct timespec *tp)
Returns the current wall-clock time with nanosecond precision.
Definition: fg_time.c:145
ctimenow
const char * ctimenow(bool ns)
Returns the current wall-clock time as null-terminated string.
Definition: fg_time.c:56