|
|
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.