blob: 258241a0553da8bf223d90c229d8891677b26ea6 [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono9033e312005-11-21 02:08:39 +00005 *
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
Benny Prijono2a816342006-04-05 19:04:34 +000027#if defined(PJ_HAS_PENTIUM) && PJ_HAS_PENTIUM!=0 && \
28 defined(PJ_TIMESTAMP_USE_RDTSC) && PJ_TIMESTAMP_USE_RDTSC!=0 && \
29 defined(PJ_M_I386) && PJ_M_I386!=0 && \
30 defined(PJ_LINUX) && PJ_LINUX!=0
Benny Prijono9033e312005-11-21 02:08:39 +000031static int machine_speed_mhz;
32static pj_timestamp machine_speed;
33
34static __inline__ unsigned long long int rdtsc()
35{
36 unsigned long long int x;
37 __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
38 return x;
39}
40
41/* Determine machine's CPU MHz to get the counter's frequency.
42 */
43static int get_machine_speed_mhz()
44{
45 FILE *strm;
46 char buf[512];
47 int len;
48 char *pos, *end;
49
50 PJ_CHECK_STACK();
51
52 /* Open /proc/cpuinfo and read the file */
53 strm = fopen("/proc/cpuinfo", "r");
54 if (!strm)
55 return -1;
56 len = fread(buf, 1, sizeof(buf), strm);
57 fclose(strm);
58 if (len < 1) {
59 return -1;
60 }
61 buf[len] = '\0';
62
63 /* Locate the MHz digit. */
64 pos = strstr(buf, "cpu MHz");
65 if (!pos)
66 return -1;
67 pos = strchr(pos, ':');
68 if (!pos)
69 return -1;
70 end = (pos += 2);
71 while (isdigit(*end)) ++end;
72 *end = '\0';
73
74 /* Return the Mhz part, and give it a +1. */
75 return atoi(pos)+1;
76}
77
78PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
79{
80 if (machine_speed_mhz == 0) {
81 machine_speed_mhz = get_machine_speed_mhz();
82 if (machine_speed_mhz > 0) {
83 machine_speed.u64 = machine_speed_mhz * 1000000.0;
84 }
85 }
86
87 if (machine_speed_mhz == -1) {
88 ts->u64 = 0;
89 return -1;
90 }
91 ts->u64 = rdtsc();
92 return 0;
93}
94
95PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
96{
97 if (machine_speed_mhz == 0) {
98 machine_speed_mhz = get_machine_speed_mhz();
99 if (machine_speed_mhz > 0) {
100 machine_speed.u64 = machine_speed_mhz * 1000000.0;
101 }
102 }
103
104 if (machine_speed_mhz == -1) {
105 freq->u64 = 1; /* return 1 to prevent division by zero in apps. */
106 return -1;
107 }
108
109 freq->u64 = machine_speed.u64;
110 return 0;
111}
112
113#else
114#include <sys/time.h>
115#include <errno.h>
116
117#define USEC_PER_SEC 1000000
118
119PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
120{
121 struct timeval tv;
122
123 if (gettimeofday(&tv, NULL) != 0) {
124 return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
125 }
126
127 ts->u64 = tv.tv_sec;
128 ts->u64 *= USEC_PER_SEC;
129 ts->u64 += tv.tv_usec;
130
131 return PJ_SUCCESS;
132}
133
134PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
135{
136 freq->u32.hi = 0;
137 freq->u32.lo = USEC_PER_SEC;
138
139 return PJ_SUCCESS;
140}
141
142#endif
143