|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * Mach Operating System
27: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: */
52:
53: #include <cpus.h>
54: #include <stat_time.h>
55:
56: #include <mach/kern_return.h>
57: #include <mach/port.h>
58: #include <kern/queue.h>
59: #include <kern/thread.h>
60: #include <kern/sched_prim.h>
61: #include <mach/time_value.h>
62: #include <kern/timer.h>
63: #include <kern/cpu_number.h>
64:
65: #include <kern/assert.h>
66: #include <kern/macro_help.h>
67:
68: timer_t current_timer[NCPUS];
69: timer_data_t kernel_timer[NCPUS];
70:
71: /* Forwards */
72: void timer_grab(
73: timer_t timer,
74: timer_save_t save);
75:
76: void db_timer_grab(
77: timer_t timer,
78: timer_save_t save);
79:
80: void db_thread_read_times(
81: thread_t thread,
82: time_value_t *user_time_p,
83: time_value_t *system_time_p);
84:
85: /*
86: * init_timers initializes all non-thread timers and puts the
87: * service routine on the callout queue. All timers must be
88: * serviced by the callout routine once an hour.
89: */
90: void
91: init_timers(void)
92: {
93: register int i;
94: register timer_t this_timer;
95:
96: /*
97: * Initialize all the kernel timers and start the one
98: * for this cpu (master) slaves start theirs later.
99: */
100: this_timer = &kernel_timer[0];
101: for ( i=0 ; i<NCPUS ; i++, this_timer++) {
102: timer_init(this_timer);
103: current_timer[i] = (timer_t) 0;
104: }
105:
106: mp_disable_preemption();
107: start_timer(&kernel_timer[cpu_number()]);
108: mp_enable_preemption();
109: }
110:
111: /*
112: * timer_init initializes a single timer.
113: */
114: void
115: timer_init(
116: register timer_t this_timer)
117: {
118: this_timer->low_bits = 0;
119: this_timer->high_bits = 0;
120: this_timer->tstamp = 0;
121: this_timer->high_bits_check = 0;
122: }
123:
124: #if STAT_TIME
125: #else /* STAT_TIME */
126:
127: #ifdef MACHINE_TIMER_ROUTINES
128:
129: /*
130: * Machine-dependent code implements the timer routines.
131: */
132:
133: #else /* MACHINE_TIMER_ROUTINES */
134:
135: /*
136: * start_timer starts the given timer for this cpu. It is called
137: * exactly once for each cpu during the boot sequence.
138: */
139: void
140: start_timer(
141: register timer_t timer)
142: {
143: timer->tstamp = get_timestamp();
144: mp_disable_preemption();
145: current_timer[cpu_number()] = timer;
146: mp_enable_preemption();
147: }
148:
149: /*
150: * time_trap_uentry does trap entry timing. Caller must lock out
151: * interrupts and take a timestamp. ts is a timestamp taken after
152: * interrupts were locked out. Must only be called if trap was
153: * from user mode.
154: */
155: void
156: time_trap_uentry(
157: unsigned ts)
158: {
159: int elapsed;
160: int mycpu;
161: timer_t mytimer;
162:
163: mp_disable_preemption();
164:
165: /*
166: * Calculate elapsed time.
167: */
168: mycpu = cpu_number();
169: mytimer = current_timer[mycpu];
170: elapsed = ts - mytimer->tstamp;
171: #ifdef TIMER_MAX
172: if (elapsed < 0) elapsed += TIMER_MAX;
173: #endif /* TIMER_MAX */
174:
175: /*
176: * Update current timer.
177: */
178: mytimer->low_bits += elapsed;
179: mytimer->tstamp = 0;
180:
181: if (mytimer->low_bits & TIMER_LOW_FULL) {
182: timer_normalize(mytimer);
183: }
184:
185: /*
186: * Record new timer.
187: */
188: mytimer = &(current_thread()->system_timer);
189: current_timer[mycpu] = mytimer;
190: mytimer->tstamp = ts;
191:
192: mp_enable_preemption();
193: }
194:
195: /*
196: * time_trap_uexit does trap exit timing. Caller must lock out
197: * interrupts and take a timestamp. ts is a timestamp taken after
198: * interrupts were locked out. Must only be called if returning to
199: * user mode.
200: */
201: void
202: time_trap_uexit(
203: unsigned ts)
204: {
205: int elapsed;
206: int mycpu;
207: timer_t mytimer;
208:
209: mp_disable_preemption();
210:
211: /*
212: * Calculate elapsed time.
213: */
214: mycpu = cpu_number();
215: mytimer = current_timer[mycpu];
216: elapsed = ts - mytimer->tstamp;
217: #ifdef TIMER_MAX
218: if (elapsed < 0) elapsed += TIMER_MAX;
219: #endif /* TIMER_MAX */
220:
221: /*
222: * Update current timer.
223: */
224: mytimer->low_bits += elapsed;
225: mytimer->tstamp = 0;
226:
227: if (mytimer->low_bits & TIMER_LOW_FULL) {
228: timer_normalize(mytimer); /* SYSTEMMODE */
229: }
230:
231: mytimer = &(current_thread()->user_timer);
232:
233: /*
234: * Record new timer.
235: */
236: current_timer[mycpu] = mytimer;
237: mytimer->tstamp = ts;
238:
239: mp_enable_preemption();
240: }
241:
242: /*
243: * time_int_entry does interrupt entry timing. Caller must lock out
244: * interrupts and take a timestamp. ts is a timestamp taken after
245: * interrupts were locked out. new_timer is the new timer to
246: * switch to. This routine returns the currently running timer,
247: * which MUST be pushed onto the stack by the caller, or otherwise
248: * saved for time_int_exit.
249: */
250: timer_t
251: time_int_entry(
252: unsigned ts,
253: timer_t new_timer)
254: {
255: int elapsed;
256: int mycpu;
257: timer_t mytimer;
258:
259: mp_disable_preemption();
260:
261: /*
262: * Calculate elapsed time.
263: */
264: mycpu = cpu_number();
265: mytimer = current_timer[mycpu];
266:
267: elapsed = ts - mytimer->tstamp;
268: #ifdef TIMER_MAX
269: if (elapsed < 0) elapsed += TIMER_MAX;
270: #endif /* TIMER_MAX */
271:
272: /*
273: * Update current timer.
274: */
275: mytimer->low_bits += elapsed;
276: mytimer->tstamp = 0;
277:
278: /*
279: * Switch to new timer, and save old one on stack.
280: */
281: new_timer->tstamp = ts;
282: current_timer[mycpu] = new_timer;
283:
284: mp_enable_preemption();
285:
286: return(mytimer);
287: }
288:
289: /*
290: * time_int_exit does interrupt exit timing. Caller must lock out
291: * interrupts and take a timestamp. ts is a timestamp taken after
292: * interrupts were locked out. old_timer is the timer value pushed
293: * onto the stack or otherwise saved after time_int_entry returned
294: * it.
295: */
296: void
297: time_int_exit(
298: unsigned ts,
299: timer_t old_timer)
300: {
301: int elapsed;
302: int mycpu;
303: timer_t mytimer;
304:
305: mp_disable_preemption();
306:
307: /*
308: * Calculate elapsed time.
309: */
310: mycpu = cpu_number();
311: mytimer = current_timer[mycpu];
312: elapsed = ts - mytimer->tstamp;
313: #ifdef TIMER_MAX
314: if (elapsed < 0) elapsed += TIMER_MAX;
315: #endif /* TIMER_MAX */
316:
317: /*
318: * Update current timer.
319: */
320: mytimer->low_bits += elapsed;
321: mytimer->tstamp = 0;
322:
323: /*
324: * If normalization requested, do it.
325: */
326: if (mytimer->low_bits & TIMER_LOW_FULL) {
327: timer_normalize(mytimer);
328: }
329: if (old_timer->low_bits & TIMER_LOW_FULL) {
330: timer_normalize(old_timer);
331: }
332:
333: /*
334: * Start timer that was running before interrupt.
335: */
336: old_timer->tstamp = ts;
337: current_timer[mycpu] = old_timer;
338:
339: mp_enable_preemption();
340: }
341:
342: /*
343: * timer_switch switches to a new timer. The machine
344: * dependent routine/macro get_timestamp must return a timestamp.
345: * Caller must lock out interrupts.
346: */
347: void
348: timer_switch(
349: timer_t new_timer)
350: {
351: int elapsed;
352: int mycpu;
353: timer_t mytimer;
354: unsigned ts;
355:
356: mp_disable_preemption();
357:
358: /*
359: * Calculate elapsed time.
360: */
361: mycpu = cpu_number();
362: mytimer = current_timer[mycpu];
363: ts = get_timestamp();
364: elapsed = ts - mytimer->tstamp;
365: #ifdef TIMER_MAX
366: if (elapsed < 0) elapsed += TIMER_MAX;
367: #endif /* TIMER_MAX */
368:
369: /*
370: * Update current timer.
371: */
372: mytimer->low_bits += elapsed;
373: mytimer->tstamp = 0;
374:
375: /*
376: * Normalization check
377: */
378: if (mytimer->low_bits & TIMER_LOW_FULL) {
379: timer_normalize(mytimer);
380: }
381:
382: /*
383: * Record new timer.
384: */
385: current_timer[mycpu] = new_timer;
386: new_timer->tstamp = ts;
387:
388: mp_enable_preemption();
389: }
390:
391: #endif /* MACHINE_TIMER_ROUTINES */
392: #endif /* STAT_TIME */
393:
394: /*
395: * timer_normalize normalizes the value of a timer. It is
396: * called only rarely, to make sure low_bits never overflows.
397: */
398:
399: void
400: timer_normalize(
401: register timer_t timer)
402: {
403: unsigned int high_increment;
404:
405: /*
406: * Calculate high_increment, then write high check field first
407: * followed by low and high. timer_grab() reads these fields in
408: * reverse order so if high and high check match, we know
409: * that the values read are ok.
410: */
411:
412: high_increment = timer->low_bits/TIMER_HIGH_UNIT;
413: timer->high_bits_check += high_increment;
414: timer->low_bits %= TIMER_HIGH_UNIT;
415: timer->high_bits += high_increment;
416: }
417:
418: /*
419: * timer_grab() retrieves the value of a timer.
420: *
421: * Critical scheduling code uses TIMER_DELTA macro in timer.h
422: * (called from thread_timer_delta in sched.h).
423: *
424: * Keep coherent with db_time_grab below.
425: */
426:
427: void
428: timer_grab(
429: timer_t timer,
430: timer_save_t save)
431: {
432: #if MACH_ASSERT
433: unsigned int passes=0;
434: #endif
435: do {
436: (save)->high = (timer)->high_bits;
437: (save)->low = (timer)->low_bits;
438: /*
439: * If the timer was normalized while we were doing this,
440: * the high_bits value read above and the high_bits check
441: * value will not match because high_bits_check is the first
442: * field touched by the normalization procedure, and
443: * high_bits is the last.
444: *
445: * Additions to timer only touch low bits and
446: * are therefore atomic with respect to this.
447: */
448: #if MACH_ASSERT
449: passes++;
450: assert(passes < 10000);
451: #endif
452: } while ( (save)->high != (timer)->high_bits_check);
453: }
454:
455: /*
456: *
457: * Db_timer_grab(): used by db_thread_read_times. An nonblocking
458: * version of db_thread_get_times. Keep coherent with timer_grab
459: * above.
460: *
461: */
462: void
463: db_timer_grab(
464: timer_t timer,
465: timer_save_t save)
466: {
467: /* Don't worry about coherency */
468:
469: (save)->high = (timer)->high_bits;
470: (save)->low = (timer)->low_bits;
471: }
472:
473:
474: /*
475: * timer_read reads the value of a timer into a time_value_t. If the
476: * timer was modified during the read, retry. The value returned
477: * is accurate to the last update; time accumulated by a running
478: * timer since its last timestamp is not included.
479: */
480:
481: void
482: timer_read(
483: timer_t timer,
484: register time_value_t *tv)
485: {
486: timer_save_data_t temp;
487:
488: timer_grab(timer,&temp);
489: /*
490: * Normalize the result
491: */
492: #ifdef TIMER_ADJUST
493: TIMER_ADJUST(&temp);
494: #endif /* TIMER_ADJUST */
495: tv->seconds = temp.high + temp.low/1000000;
496: tv->microseconds = temp.low%1000000;
497: }
498:
499: /*
500: * thread_read_times reads the user and system times from a thread.
501: * Time accumulated since last timestamp is not included. Should
502: * be called at splsched() to avoid having user and system times
503: * be out of step. Doesn't care if caller locked thread.
504: *
505: * Needs to be kept coherent with thread_read_times ahead.
506: */
507: void
508: thread_read_times(
509: thread_t thread,
510: time_value_t *user_time_p,
511: time_value_t *system_time_p)
512: {
513: timer_save_data_t temp;
514: register timer_t timer;
515:
516: timer = &thread->user_timer;
517: timer_grab(timer, &temp);
518:
519: #ifdef TIMER_ADJUST
520: TIMER_ADJUST(&temp);
521: #endif /* TIMER_ADJUST */
522: user_time_p->seconds = temp.high + temp.low/1000000;
523: user_time_p->microseconds = temp.low % 1000000;
524:
525: timer = &thread->system_timer;
526: timer_grab(timer, &temp);
527:
528: #ifdef TIMER_ADJUST
529: TIMER_ADJUST(&temp);
530: #endif /* TIMER_ADJUST */
531: system_time_p->seconds = temp.high + temp.low/1000000;
532: system_time_p->microseconds = temp.low % 1000000;
533: }
534:
535: /*
536: * Db_thread_read_times: A version of thread_read_times that
537: * can be called by the debugger. This version does not call
538: * timer_grab, which can block. Please keep it up to date with
539: * thread_read_times above.
540: *
541: */
542: void
543: db_thread_read_times(
544: thread_t thread,
545: time_value_t *user_time_p,
546: time_value_t *system_time_p)
547: {
548: timer_save_data_t temp;
549: register timer_t timer;
550:
551: timer = &thread->user_timer;
552: db_timer_grab(timer, &temp);
553:
554: #ifdef TIMER_ADJUST
555: TIMER_ADJUST(&temp);
556: #endif /* TIMER_ADJUST */
557: user_time_p->seconds = temp.high + temp.low/1000000;
558: user_time_p->microseconds = temp.low % 1000000;
559:
560: timer = &thread->system_timer;
561: timer_grab(timer, &temp);
562:
563: #ifdef TIMER_ADJUST
564: TIMER_ADJUST(&temp);
565: #endif /* TIMER_ADJUST */
566: system_time_p->seconds = temp.high + temp.low/1000000;
567: system_time_p->microseconds = temp.low % 1000000;
568: }
569:
570: /*
571: * timer_delta takes the difference of a saved timer value
572: * and the current one, and updates the saved value to current.
573: * The difference is returned as a function value. See
574: * TIMER_DELTA macro (timer.h) for optimization to this.
575: */
576:
577: unsigned
578: timer_delta(
579: register timer_t timer,
580: timer_save_t save)
581: {
582: timer_save_data_t new_save;
583: register unsigned result;
584:
585: timer_grab(timer,&new_save);
586: result = (new_save.high - save->high) * TIMER_HIGH_UNIT +
587: new_save.low - save->low;
588: save->high = new_save.high;
589: save->low = new_save.low;
590: return(result);
591: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.