Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_fixcpp/sys/src/9/port/tod.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include	"u.h"
2
#include	"../port/lib.h"
3
#include	"mem.h"
4
#include	"dat.h"
5
#include	"fns.h"
6
#include	"../port/error.h"
7
 
8
/*
9
 * Compute nanosecond epoch time from the fastest ticking clock
10
 * on the system.  Converting the time to nanoseconds requires
11
 * the following formula
12
 *
13
 *	t = (((1000000000<<31)/f)*ticks)>>31
14
 *
15
 *  where
16
 *
17
 *	'f'		is the clock frequency
18
 *	'ticks'		are clock ticks
19
 *
20
 *  to avoid too much calculation in todget(), we calculate
21
 *
22
 *	mult = (1000000000<<32)/f
23
 *
24
 *  each time f is set.  f is normally set by a user level
25
 *  program writing to /dev/fastclock.  mul64fract will then
26
 *  take that fractional multiplier and a 64 bit integer and
27
 *  return the resulting integer product.
28
 *
29
 *  We assume that the cpu's of a multiprocessor are synchronized.
30
 *  This assumption needs to be questioned with each new architecture.
31
 */
32
 
33
/* frequency of the tod clock */
34
#define TODFREQ		1000000000ULL
35
#define MicroFREQ	1000000ULL
36
 
37
struct {
38
	int	init;		/* true if initialized */
39
	ulong	cnt;
40
	Lock;
41
	uvlong	multiplier;	/* ns = off + (multiplier*ticks)>>31 */
42
	uvlong	divider;	/* ticks = (divider*(ns-off))>>31 */
43
	uvlong	umultiplier;	/* µs = (µmultiplier*ticks)>>31 */
44
	uvlong	udivider;	/* ticks = (µdivider*µs)>>31 */
45
	vlong	hz;		/* frequency of fast clock */
46
	vlong	last;		/* last reading of fast clock */
47
	vlong	off;		/* offset from epoch to last */
48
	vlong	lasttime;	/* last return value from todget */
49
	vlong	delta;	/* add 'delta' each slow clock tick from sstart to send */
50
	ulong	sstart;		/* ... */
51
	ulong	send;		/* ... */
52
} tod;
53
 
54
static void todfix(void);
55
 
56
void
57
todinit(void)
58
{
59
	if(tod.init)
60
		return;
61
	ilock(&tod);
62
	tod.init = 1;			/* prevent reentry via fastticks */
63
	tod.last = fastticks((uvlong *)&tod.hz);
64
	iunlock(&tod);
65
	todsetfreq(tod.hz);
66
	addclock0link(todfix, 100);
67
}
68
 
69
/*
70
 *  calculate multiplier
71
 */
72
void
73
todsetfreq(vlong f)
74
{
75
	if (f <= 0)
76
		panic("todsetfreq: freq %lld <= 0", f);
77
	ilock(&tod);
78
	tod.hz = f;
79
 
80
	/* calculate multiplier for time conversion */
81
	tod.multiplier = mk64fract(TODFREQ, f);
82
	tod.divider = mk64fract(f, TODFREQ) + 1;
83
	tod.umultiplier = mk64fract(MicroFREQ, f);
84
	tod.udivider = mk64fract(f, MicroFREQ) + 1;
85
	iunlock(&tod);
86
}
87
 
88
/*
89
 *  Set the time of day struct
90
 */
91
void
92
todset(vlong t, vlong delta, int n)
93
{
94
	if(!tod.init)
95
		todinit();
96
 
97
	ilock(&tod);
98
	if(t >= 0){
99
		tod.off = t;
100
		tod.last = fastticks(nil);
101
		tod.lasttime = 0;
102
		tod.delta = 0;
103
		tod.sstart = tod.send;
104
	} else {
105
		if(n <= 0)
106
			n = 1;
107
		n *= HZ;
108
		if(delta < 0 && n > -delta)
109
			n = -delta;
110
		if(delta > 0 && n > delta)
111
			n = delta;
112
		if (n == 0) {
113
			iprint("todset: n == 0, delta == %lld\n", delta);
114
			delta = 0;
115
		} else
116
			delta /= n;
117
		tod.sstart = MACHP(0)->ticks;
118
		tod.send = tod.sstart + n;
119
		tod.delta = delta;
120
	}
121
	iunlock(&tod);
122
}
123
 
124
/*
125
 *  get time of day
126
 */
127
vlong
128
todget(vlong *ticksp)
129
{
130
	uvlong x;
131
	vlong ticks, diff;
132
	ulong t;
133
 
134
	if(!tod.init)
135
		todinit();
136
 
137
	/*
138
	 * we don't want time to pass twixt the measuring of fastticks
139
	 * and grabbing tod.last.  Also none of the vlongs are atomic so
140
	 * we have to look at them inside the lock.
141
	 */
142
	ilock(&tod);
143
	tod.cnt++;
144
	ticks = fastticks(nil);
145
 
146
	/* add in correction */
147
	if(tod.sstart != tod.send){
148
		t = MACHP(0)->ticks;
149
		if(t >= tod.send)
150
			t = tod.send;
151
		tod.off = tod.off + tod.delta*(t - tod.sstart);
152
		tod.sstart = t;
153
	}
154
 
155
	/* convert to epoch */
156
	diff = ticks - tod.last;
157
	if(diff < 0)
158
		diff = 0;
159
	mul64fract(&x, diff, tod.multiplier);
160
	x += tod.off;
161
 
162
	/* time can't go backwards */
163
	if(x < tod.lasttime)
164
		x = tod.lasttime;
165
	else
166
		tod.lasttime = x;
167
 
168
	iunlock(&tod);
169
 
170
	if(ticksp != nil)
171
		*ticksp = ticks;
172
 
173
	return x;
174
}
175
 
176
/*
177
 *  convert time of day to ticks
178
 */
179
uvlong
180
tod2fastticks(vlong ns)
181
{
182
	uvlong x;
183
 
184
	ilock(&tod);
185
	mul64fract(&x, ns-tod.off, tod.divider);
186
	x += tod.last;
187
	iunlock(&tod);
188
	return x;
189
}
190
 
191
/*
192
 *  called regularly to avoid calculation overflows
193
 */
194
static void
195
todfix(void)
196
{
197
	vlong ticks, diff;
198
	uvlong x;
199
 
200
	ticks = fastticks(nil);
201
 
202
	diff = ticks - tod.last;
203
	if(diff > tod.hz){
204
		ilock(&tod);
205
 
206
		/* convert to epoch */
207
		mul64fract(&x, diff, tod.multiplier);
208
if(x > 30000000000ULL) iprint("todfix %llud\n", x);
209
		x += tod.off;
210
 
211
		/* protect against overflows */
212
		tod.last = ticks;
213
		tod.off = x;
214
 
215
		iunlock(&tod);
216
	}
217
}
218
 
219
long
220
seconds(void)
221
{
222
	return (vlong)todget(nil) / TODFREQ;
223
}
224
 
225
uvlong
226
fastticks2us(uvlong ticks)
227
{
228
	uvlong res;
229
 
230
	if(!tod.init)
231
		todinit();
232
	mul64fract(&res, ticks, tod.umultiplier);
233
	return res;
234
}
235
 
236
uvlong
237
us2fastticks(uvlong us)
238
{
239
	uvlong res;
240
 
241
	if(!tod.init)
242
		todinit();
243
	mul64fract(&res, us, tod.udivider);
244
	return res;
245
}
246
 
247
/*
248
 *  convert milliseconds to fast ticks
249
 */
250
uvlong
251
ms2fastticks(ulong ms)
252
{
253
	if(!tod.init)
254
		todinit();
255
	return (tod.hz*ms)/1000ULL;
256
}
257
 
258
/*
259
 *  convert nanoseconds to fast ticks
260
 */
261
uvlong
262
ns2fastticks(uvlong ns)
263
{
264
	uvlong res;
265
 
266
	if(!tod.init)
267
		todinit();
268
	mul64fract(&res, ns, tod.divider);
269
	return res;
270
}
271
 
272
/*
273
 *  convert fast ticks to ns
274
 */
275
uvlong
276
fastticks2ns(uvlong ticks)
277
{
278
	uvlong res;
279
 
280
	if(!tod.init)
281
		todinit();
282
	mul64fract(&res, ticks, tod.multiplier);
283
	return res;
284
}
285
 
286
/*
287
 * Make a 64 bit fixed point number that has a decimal point
288
 * to the left of the low order 32 bits.  This is used with
289
 * mul64fract for converting twixt nanoseconds and fastticks.
290
 *
291
 *	multiplier = (to<<32)/from
292
 */
293
uvlong
294
mk64fract(uvlong to, uvlong from)
295
{
296
/*
297
	int shift;
298
 
299
	if(to == 0ULL)
300
		return 0ULL;
301
 
302
	shift = 0;
303
	while(shift < 32 && to < (1ULL<<(32+24))){
304
		to <<= 8;
305
		shift += 8;
306
	}
307
	while(shift < 32 && to < (1ULL<<(32+31))){
308
		to <<= 1;
309
		shift += 1;
310
	}
311
 
312
	return (to/from)<<(32-shift);
313
 */
314
	return (to<<32) / from;
315
}