|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: File: Timestamp.c
27:
28: Contains: Low-impact event timing function library
29:
30: Copyright: 1995-1997 by Apple Computer, Inc., all rights reserved.
31:
32: Version: 1.1
33:
34: Written by: Martin Minow
35:
36: Change History (most recent first):
37:
38: <1> 04/14/97 MM Conversion for Rhapsody SCSI from Copland Timestamp.c;8.
39: <2> 97.07.17 MM Radar 1669061 Convert PPC tick to nanoseconds for vector return, too.
40:
41: */
42:
43: #define USE_RAW_PPC_CLOCK 1
44:
45: #include "Timestamp.h"
46: #import <kernserv/prototypes.h>
47: #if USE_RAW_PPC_CLOCK
48: #include <machdep/ppc/powermac.h>
49: extern long long read_processor_clock(void);
50: #endif /* USE_RAW_PPC_CLOCK */
51: #ifndef FALSE
52: #define FALSE 0
53: #define TRUE 1
54: #endif
55: #ifndef NULL
56: #define NULL 0
57: #endif
58:
59: /*
60: * Values for the flags variable in the LogDataRecord. These are private to the
61: * LogData library and dcmd display routine.
62: */
63: enum {
64: kTimestampEnabledMask = (1L << 0), /* Enable logging if set */
65: kTimestampPreserveFirstMask = (1L << 1), /* Preserve first entry if set */
66: kTimestampWrapAroundMask = (1L << 2) /* Record has wrapped around once */
67: };
68:
69: struct TimestampRecord {
70: volatile UInt32 semaphore; /* In critical section if non-zero */
71: volatile UInt32 lostLockCounter; /* Can't enter critical section */
72: volatile UInt32 flags; /* Logging & lost data flags */
73: volatile UInt32 entryPutIndex; /* Where to store the next record */
74: volatile UInt32 entryGetIndex; /* Where to retrieve the next record */
75: volatile UInt32 entryMaxIndex; /* Actual number of log entries */
76: TimestampDataRecord entries[1]; /* Ring buffer of log entries */
77: };
78: typedef struct TimestampRecord TimestampRecord, *TimestampRecordPtr;
79:
80:
81:
82: #if 1 /* TEMP TEMP TEMP */
83: /*
84: * Temporary atomic instruction implementations
85: */
86: static inline SInt32 IncrementAtomicAligned(
87: volatile SInt32 *theValue
88: )
89: {
90: SInt32 result = *theValue;
91: ++(*theValue);
92: return (result);
93: }
94: static inline UInt32 BitAndAtomicAligned(
95: UInt32 theMask,
96: volatile UInt32 *theValue
97: )
98: {
99: SInt32 result = *theValue;
100: *theValue &= theMask;
101: return (result);
102: }
103: static inline Boolean CompareAndSwapAligned(
104: UInt32 oldValue,
105: UInt32 newValue,
106: volatile UInt32 *theValue
107: )
108: {
109: if (oldValue != (*theValue)) {
110: return (FALSE); /* False */
111: }
112: else {
113: *theValue = newValue;
114: return (TRUE);
115: }
116: }
117:
118: #endif
119:
120: typedef union TimestampTime {
121: long d[2];
122: long long ppcClock;
123: ns_time_t nsecTime;
124: } TimestampTime;
125:
126: static void StoreRawTimestamp(
127: UInt32 timestampTag,
128: UInt32 timestampValue,
129: const TimestampTime *timestampTime
130: );
131:
132: #if TIMESTAMP
133: static TimestampRecordPtr gTimestampRecordPtr;
134: #define LOG (*gTimestampRecordPtr)
135:
136: void
137: MakeTimestampRecord(
138: UInt32 nEntries
139: )
140: {
141: UInt32 areaSize;
142: UInt32 pageSize;
143:
144: if (gTimestampRecordPtr == NULL) {
145: areaSize = (nEntries * sizeof (TimestampDataRecord))
146: + sizeof (TimestampRecord)
147: - sizeof (TimestampDataRecord)
148: ;
149: /*
150: * Round up areaSize to a page size.
151: */
152: pageSize = 4096;
153: areaSize = (areaSize + pageSize - 1) & ~(pageSize - 1);
154: /*
155: * Recompute nEntries.
156: */
157: nEntries = (areaSize - sizeof (TimestampRecord))
158: / sizeof (TimestampDataRecord);
159: nEntries += 1;
160: gTimestampRecordPtr = (TimestampRecordPtr) kalloc(areaSize);
161: if (gTimestampRecordPtr != NULL) {
162: LOG.entryMaxIndex = nEntries;
163: LOG.flags = ( (1 * kTimestampEnabledMask) /* Enabled */
164: | (0 * kTimestampPreserveFirstMask) /* Save last */
165: | (0 * kTimestampWrapAroundMask) /* Always zero */
166: );
167: LOG.entryPutIndex = 0;
168: LOG.entryGetIndex = 0;
169: } /* If we created the area */
170: #if 0 /* Temp for initial debugging */
171: {
172: int i;
173: TimestampTime t;
174: TimestampTime x;
175: for (i = 0; i < 10; i++) {
176: t.ppcClock = read_processor_clock();
177: x.ppcClock = t.ppcClock;
178: x.ppcClock *= powermac_info.proc_clock_to_nsec_numerator;
179: x.ppcClock /= powermac_info.proc_clock_to_nsec_denominator;
180: IOLog("clock numerator %u, clock denominator %u, value %u %u -> %u %u\n",
181: powermac_info.proc_clock_to_nsec_numerator,
182: powermac_info.proc_clock_to_nsec_denominator,
183: t.d[0],
184: t.d[1],
185: x.d[0],
186: x.d[1]
187: );
188: }
189: }
190: #endif
191: } /* gTimestampRecordPtr == NULL */
192: }
193:
194:
195: void
196: StoreNSecTimestamp(
197: UInt32 timestampTag,
198: UInt32 timestampValue,
199: ns_time_t timestampEvent
200: )
201: {
202: TimestampTime timestampTime;
203:
204: timestampTime.nsecTime = timestampEvent;
205: #if USE_RAW_PPC_CLOCK
206: timestampTime.ppcClock *= powermac_info.proc_clock_to_nsec_denominator;
207: timestampTime.ppcClock /= powermac_info.proc_clock_to_nsec_numerator;
208: #endif
209: StoreRawTimestamp(
210: timestampTag,
211: timestampValue,
212: ×tampTime
213: );
214: }
215:
216: void
217: StoreTimestamp(
218: UInt32 timestampTag,
219: UInt32 timestampValue
220: )
221: {
222: TimestampTime timestampTime;
223: #if USE_RAW_PPC_CLOCK
224: timestampTime.ppcClock = read_processor_clock();
225: #else
226: IOGetTimestamp(×tampTime.nsecTime);
227: #endif
228: StoreRawTimestamp(
229: timestampTag,
230: timestampValue,
231: ×tampTime
232: );
233: }
234:
235: static void
236: StoreRawTimestamp(
237: UInt32 timestampTag,
238: UInt32 timestampValue,
239: const TimestampTime *timestampTime
240: )
241: {
242: UInt32 putIndex;
243: UInt32 getIndex;
244: TimestampDataPtr entryPtr;
245:
246: if (gTimestampRecordPtr != NULL
247: && (LOG.flags & kTimestampEnabledMask) != 0) {
248: if (CompareAndSwapAligned(0, 1, (UInt32 *) &LOG.semaphore) == FALSE) {
249: IncrementAtomicAligned((volatile SInt32 *) &LOG.lostLockCounter);
250: }
251: else { /* Nope, we got it */
252: /*
253: * The ring buffer is designed so that put == get implies empty
254: * and pointers are always incremented before use.
255: */
256: putIndex = LOG.entryPutIndex + 1;
257: if (putIndex >= LOG.entryMaxIndex) {
258: putIndex = 0;
259: LOG.flags |= kTimestampWrapAroundMask;
260: }
261: if (putIndex == LOG.entryGetIndex) { /* Did it fill? */
262: if ((LOG.flags & kTimestampPreserveFirstMask) != 0) {
263: ; /* Keeping first */
264: }
265: else {
266: /*
267: * We want to retain the latest entry. Do this by
268: * advancing the "get" pointer as if the earliest entry
269: * has been read. Then jump around the if bracket to store
270: * this datum.
271: */
272: getIndex = LOG.entryGetIndex + 1;
273: if (getIndex >= LOG.entryMaxIndex)
274: getIndex = 0;
275: LOG.entryGetIndex = getIndex;
276: goto storeDatum;
277: }
278: }
279: else {
280: storeDatum: entryPtr = &LOG.entries[putIndex];
281: LOG.entryPutIndex = putIndex;
282: entryPtr->eventTime = timestampTime->nsecTime;
283: entryPtr->timestampTag = timestampTag;
284: entryPtr->timestampValue = timestampValue;
285: }
286: LOG.semaphore = 0; /* Free semaphore */
287: }
288: }
289: }
290:
291: /**
292: * Returns the next timestamp, if any, in resultData.
293: * @param resultData Where to store the data
294: * @return TRUE Valid data returned
295: * FALSE No data is available.
296: */
297: Boolean
298: ReadTimestamp(
299: TimestampDataPtr resultData /* Result stored here */
300: )
301: {
302: UInt32 getIndex;
303: Boolean result = FALSE;
304:
305: if (resultData != NULL && gTimestampRecordPtr != NULL) {
306: /*
307: * Try to grab the semaphore.
308: */
309: if (CompareAndSwapAligned(0, 1, (UInt32 *) &LOG.semaphore) == FALSE) {
310: IncrementAtomicAligned((volatile SInt32 *) &LOG.lostLockCounter);
311: }
312: else { /* Nope, we got it */
313: getIndex = LOG.entryGetIndex;
314: if (getIndex != LOG.entryPutIndex) { /* Empty? */
315: result = TRUE; /* No: get some data */
316: if (++getIndex >= LOG.entryMaxIndex)
317: getIndex = 0;
318: *resultData = LOG.entries[getIndex];
319: LOG.entryGetIndex = getIndex;
320: }
321: LOG.semaphore = 0; /* Free semaphore */
322: }
323: }
324: #if USE_RAW_PPC_CLOCK
325: if (result) {
326: TimestampTime timestampTime;
327:
328: timestampTime.nsecTime = resultData->eventTime;
329: timestampTime.ppcClock *= powermac_info.proc_clock_to_nsec_numerator;
330: timestampTime.ppcClock /= powermac_info.proc_clock_to_nsec_denominator;
331: resultData->eventTime = timestampTime.nsecTime;
332: }
333: #endif
334: return (result);
335: }
336:
337: /**
338: * Return a vector of timestamps.
339: * @param resultVector Where to store the data
340: * @param count On entrance, this has the maximum number of elements
341: * to return. On exit, this will have the actual number
342: * of elements that were returned.
343: * Note that, if the semaphore is blocked, ReadTimestampVector will not return any
344: * data. Data cannot be collected while ReadTimestampVector is copying data
345: * to the user's buffer. Note that, since the user's buffer will typically be
346: * in pageable memory, pageing I/O that might otherwise be timestamped will
347: * be lost.
348: */
349: void
350: ReadTimestampVector(
351: TimestampDataPtr resultVector, /* -> Result buffer */
352: UInt32 *count /* -> Max count, <-actual */
353: )
354: {
355: UInt32 getIndex;
356: UInt32 i;
357:
358: if (resultVector != NULL
359: && gTimestampRecordPtr != NULL
360: && count != NULL) {
361: i = 0;
362: if (CompareAndSwapAligned(0, 1, (UInt32 *) &LOG.semaphore) == FALSE) {
363: IncrementAtomicAligned((volatile SInt32 *) &LOG.lostLockCounter);
364: }
365: else {
366: getIndex = LOG.entryGetIndex;
367: for (; i < *count && getIndex != LOG.entryPutIndex; i++) {
368: if (++getIndex >= LOG.entryMaxIndex)
369: getIndex = 0;
370: *resultVector = LOG.entries[getIndex];
371: #if USE_RAW_PPC_CLOCK
372: resultVector->eventTime =
373: (resultVector->eventTime * powermac_info.proc_clock_to_nsec_numerator)
374: / powermac_info.proc_clock_to_nsec_denominator;
375: #endif
376: resultVector++;
377: }
378: LOG.entryGetIndex = getIndex;
379: LOG.semaphore = 0; /* Free semaphore */
380: }
381: *count = i; /* Return actual count */
382: }
383: }
384:
385: Boolean
386: EnableTimestamp(
387: Boolean enableTimestamp /* True to enable timestamp */
388: )
389: {
390: UInt32 newFlags;
391: Boolean timestampsWereEnabled;
392:
393: if (gTimestampRecordPtr == NULL) {
394: timestampsWereEnabled = FALSE;
395: }
396: else {
397: do {
398: timestampsWereEnabled = (LOG.flags & kTimestampEnabledMask) != 0;
399: if (enableTimestamp)
400: newFlags = LOG.flags | kTimestampEnabledMask;
401: else {
402: newFlags = LOG.flags & ~kTimestampEnabledMask;
403: }
404: } while (CompareAndSwapAligned(LOG.flags, newFlags, &LOG.flags) == FALSE);
405: }
406: return (timestampsWereEnabled);
407: }
408:
409: Boolean
410: PreserveTimestamp(
411: Boolean preserveFirst /* TRUE to preserve start */
412: )
413: {
414: UInt32 newFlags;
415: Boolean wasFirst;
416:
417: if (gTimestampRecordPtr == NULL) {
418: wasFirst = FALSE;
419: }
420: else {
421: do {
422: wasFirst = (LOG.flags & kTimestampPreserveFirstMask) != 0;
423: if (preserveFirst)
424: newFlags = LOG.flags | kTimestampPreserveFirstMask;
425: else {
426: newFlags = LOG.flags & kTimestampPreserveFirstMask;
427: }
428: } while (CompareAndSwapAligned(LOG.flags, newFlags, &LOG.flags) == FALSE);
429: }
430: return (wasFirst);
431: }
432:
433: void
434: ResetTimestampIndex(void)
435: {
436: if (gTimestampRecordPtr != NULL) {
437: BitAndAtomicAligned(0, &LOG.entryPutIndex);
438: BitAndAtomicAligned(0, &LOG.entryGetIndex);
439: }
440: }
441:
442: UInt32
443: GetTimestampSemaphoreLostCounter(void)
444: {
445: UInt32 result;
446:
447: if (gTimestampRecordPtr == NULL) {
448: result = 0;
449: }
450: else {
451: do {
452: result = LOG.lostLockCounter;
453: } while (CompareAndSwapAligned(
454: result, result, (UInt32 *) &LOG.lostLockCounter) == FALSE);
455: }
456: return (result);
457: }
458: #endif /* TIMESTAMP */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.