blob: a2dcd8bdcbddcf9927f21b11d5f3e53ff05afa10 [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
Benny Prijonoa771a512007-02-19 01:13:53 +00003 * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org>
Benny Prijono9033e312005-11-21 02:08:39 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pj/os.h>
20#include <pj/errno.h>
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <ctype.h>
25
Benny Prijono2a816342006-04-05 19:04:34 +000026#if defined(PJ_HAS_PENTIUM) && PJ_HAS_PENTIUM!=0 && \
27 defined(PJ_TIMESTAMP_USE_RDTSC) && PJ_TIMESTAMP_USE_RDTSC!=0 && \
28 defined(PJ_M_I386) && PJ_M_I386!=0 && \
29 defined(PJ_LINUX) && PJ_LINUX!=0
Benny Prijono9033e312005-11-21 02:08:39 +000030static int machine_speed_mhz;
31static pj_timestamp machine_speed;
32
33static __inline__ unsigned long long int rdtsc()
34{
35 unsigned long long int x;
36 __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
37 return x;
38}
39
40/* Determine machine's CPU MHz to get the counter's frequency.
41 */
42static int get_machine_speed_mhz()
43{
44 FILE *strm;
45 char buf[512];
46 int len;
47 char *pos, *end;
48
49 PJ_CHECK_STACK();
50
51 /* Open /proc/cpuinfo and read the file */
52 strm = fopen("/proc/cpuinfo", "r");
53 if (!strm)
54 return -1;
55 len = fread(buf, 1, sizeof(buf), strm);
56 fclose(strm);
57 if (len < 1) {
58 return -1;
59 }
60 buf[len] = '\0';
61
62 /* Locate the MHz digit. */
63 pos = strstr(buf, "cpu MHz");
64 if (!pos)
65 return -1;
66 pos = strchr(pos, ':');
67 if (!pos)
68 return -1;
69 end = (pos += 2);
70 while (isdigit(*end)) ++end;
71 *end = '\0';
72
73 /* Return the Mhz part, and give it a +1. */
74 return atoi(pos)+1;
75}
76
77PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
78{
79 if (machine_speed_mhz == 0) {
80 machine_speed_mhz = get_machine_speed_mhz();
81 if (machine_speed_mhz > 0) {
82 machine_speed.u64 = machine_speed_mhz * 1000000.0;
83 }
84 }
85
86 if (machine_speed_mhz == -1) {
87 ts->u64 = 0;
88 return -1;
89 }
90 ts->u64 = rdtsc();
91 return 0;
92}
93
94PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
95{
96 if (machine_speed_mhz == 0) {
97 machine_speed_mhz = get_machine_speed_mhz();
98 if (machine_speed_mhz > 0) {
99 machine_speed.u64 = machine_speed_mhz * 1000000.0;
100 }
101 }
102
103 if (machine_speed_mhz == -1) {
104 freq->u64 = 1; /* return 1 to prevent division by zero in apps. */
105 return -1;
106 }
107
108 freq->u64 = machine_speed.u64;
109 return 0;
110}
111
112#else
113#include <sys/time.h>
114#include <errno.h>
115
116#define USEC_PER_SEC 1000000
117
118PJ_DEF(pj_status_t) pj_get_timestamp(pj_timestamp *ts)
119{
120 struct timeval tv;
121
122 if (gettimeofday(&tv, NULL) != 0) {
123 return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
124 }
125
126 ts->u64 = tv.tv_sec;
127 ts->u64 *= USEC_PER_SEC;
128 ts->u64 += tv.tv_usec;
129
130 return PJ_SUCCESS;
131}
132
133PJ_DEF(pj_status_t) pj_get_timestamp_freq(pj_timestamp *freq)
134{
135 freq->u32.hi = 0;
136 freq->u32.lo = USEC_PER_SEC;
137
138 return PJ_SUCCESS;
139}
140
141#endif
142