blob: 215589c03fa5ec5aab82686aa05f024be2cc9dde [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/* $Id: os_timestamp_posix.c 3553 2011-05-05 06:14:19Z nanang $ */
Tristan Matthews0a329cc2013-07-17 13:20:14 -04002/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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#include <pj/os.h>
21#include <pj/errno.h>
22#include <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25#include <ctype.h>
26
27#if defined(PJ_HAS_UNISTD_H) && PJ_HAS_UNISTD_H != 0
28# include <unistd.h>
29
30# if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && \
31 defined(_POSIX_MONOTONIC_CLOCK)
32# define USE_POSIX_TIMERS 1
33# endif
34
35#endif
36
37#if defined(PJ_HAS_PENTIUM) && PJ_HAS_PENTIUM!=0 && \
38 defined(PJ_TIMESTAMP_USE_RDTSC) && PJ_TIMESTAMP_USE_RDTSC!=0 && \
39 defined(PJ_M_I386) && PJ_M_I386!=0 && \
40 defined(PJ_LINUX) && PJ_LINUX!=0
41static int machine_speed_mhz;
42static pj_timestamp machine_speed;
43
44static __inline__ unsigned long long int rdtsc()
45{
46 unsigned long long int x;
47 __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
48 return x;
49}
50
51/* Determine machine's CPU MHz to get the counter's frequency.
52 */
53static int get_machine_speed_mhz()
54{
55 FILE *strm;
56 char buf[512];
57 int len;
58 char *pos, *end;
59
60 PJ_CHECK_STACK();
61
62 /* Open /proc/cpuinfo and read the file */
63 strm = fopen("/proc/cpuinfo", "r");
64 if (!strm)
65 return -1;
66 len = fread(buf, 1, sizeof(buf), strm);
67 fclose(strm);
68 if (len < 1) {
69 return -1;
70 }
71 buf[len] = '\0';
72
73 /* Locate the MHz digit. */
74 pos = strstr(buf, "cpu MHz");
75 if (!pos)
76 return -1;
77 pos = strchr(pos, ':');
78 if (!pos)
79 return -1;
80 end = (pos += 2);
81 while (isdigit(*end)) ++end;
82 *end = '\0';
83
84 /* Return the Mhz part, and give it a +1. */
85 return atoi(pos)+1;
86}
87
88PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
89{
90 if (machine_speed_mhz == 0) {
91 machine_speed_mhz = get_machine_speed_mhz();
92 if (machine_speed_mhz > 0) {
93 machine_speed.u64 = machine_speed_mhz * 1000000.0;
94 }
95 }
96
97 if (machine_speed_mhz == -1) {
98 ts->u64 = 0;
99 return -1;
100 }
101 ts->u64 = rdtsc();
102 return 0;
103}
104
105PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
106{
107 if (machine_speed_mhz == 0) {
108 machine_speed_mhz = get_machine_speed_mhz();
109 if (machine_speed_mhz > 0) {
110 machine_speed.u64 = machine_speed_mhz * 1000000.0;
111 }
112 }
113
114 if (machine_speed_mhz == -1) {
115 freq->u64 = 1; /* return 1 to prevent division by zero in apps. */
116 return -1;
117 }
118
119 freq->u64 = machine_speed.u64;
120 return 0;
121}
122
123#elif defined(PJ_DARWINOS) && PJ_DARWINOS != 0
124#include <mach/mach.h>
125#include <mach/clock.h>
126#include <errno.h>
127
128#define NSEC_PER_SEC 1000000000
129
130PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
131{
132 mach_timespec_t tp;
133 int ret;
134 clock_serv_t serv;
135
136 ret = host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &serv);
137 if (ret != KERN_SUCCESS) {
138 return PJ_RETURN_OS_ERROR(EINVAL);
139 }
140
141 ret = clock_get_time(serv, &tp);
142 if (ret != KERN_SUCCESS) {
143 return PJ_RETURN_OS_ERROR(EINVAL);
144 }
145
146 ts->u64 = tp.tv_sec;
147 ts->u64 *= NSEC_PER_SEC;
148 ts->u64 += tp.tv_nsec;
149
150 return PJ_SUCCESS;
151}
152
153PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
154{
155 freq->u32.hi = 0;
156 freq->u32.lo = NSEC_PER_SEC;
157
158 return PJ_SUCCESS;
159}
160
161#elif defined(USE_POSIX_TIMERS) && USE_POSIX_TIMERS != 0
162#include <sys/time.h>
163#include <time.h>
164#include <errno.h>
165
166#define NSEC_PER_SEC 1000000000
167
168PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
169{
170 struct timespec tp;
171
172 if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0) {
173 return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
174 }
175
176 ts->u64 = tp.tv_sec;
177 ts->u64 *= NSEC_PER_SEC;
178 ts->u64 += tp.tv_nsec;
179
180 return PJ_SUCCESS;
181}
182
183PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
184{
185 freq->u32.hi = 0;
186 freq->u32.lo = NSEC_PER_SEC;
187
188 return PJ_SUCCESS;
189}
190
191#else
192#include <sys/time.h>
193#include <errno.h>
194
195#define USEC_PER_SEC 1000000
196
197PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
198{
199 struct timeval tv;
200
201 if (gettimeofday(&tv, NULL) != 0) {
202 return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
203 }
204
205 ts->u64 = tv.tv_sec;
206 ts->u64 *= USEC_PER_SEC;
207 ts->u64 += tv.tv_usec;
208
209 return PJ_SUCCESS;
210}
211
212PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
213{
214 freq->u32.hi = 0;
215 freq->u32.lo = USEC_PER_SEC;
216
217 return PJ_SUCCESS;
218}
219
220#endif