/*============================================================================= CAHALIOCycleTelemetryClient.cpp $Log: CAHALIOCycleTelemetryClient.cpp,v $ Revision 1.13 2005/02/10 08:27:52 jcm10 give the trace times some headroom Revision 1.12 2005/02/10 02:32:12 jcm10 initialize the latency tracing to off Revision 1.11 2005/02/09 02:42:47 jcm10 finish latency tracing support Revision 1.10 2005/02/03 07:40:06 jcm10 add latency logging Revision 1.9 2004/04/16 19:16:32 jcm10 fix warnings Revision 1.8 2004/02/24 02:27:06 jcm10 make it compile without a prefix header Revision 1.7 2003/07/24 22:44:08 jcm10 don't allow the telemetry port name to get too big Revision 1.6 2003/06/30 18:59:25 jcm10 more telemetry clean up and fixes Revision 1.5 2003/06/26 21:46:39 jcm10 add better detection of errors and signal present events Revision 1.4 2003/06/21 01:30:29 jcm10 add support for getting the IO cycle summary in a for suitable for AppleWorks spreadsheets Revision 1.3 2003/06/20 19:04:06 jcm10 clean up the telemetry Revision 1.2 2003/05/25 01:42:34 jcm10 change the overload telemetry to be bracket style Revision 1.1 2003/05/23 19:06:50 jcm10 first checked in Revision 0.0 Thu May 22 2003 15:57:09 US/Pacific moorf Created $NoKeywords: $ =============================================================================*/ //============================================================================= // Includes //============================================================================= // Self Include #include "CAHALIOCycleTelemetryClient.h" // PublicUtility Includes #include "CAAudioHardwareDevice.h" #include "CACFArray.h" #include "CACFData.h" #include "CACFDictionary.h" #include "CACFString.h" #include "CACFMessagePort.h" #include "CADebugMacros.h" #include "CAException.h" #include "CAHostTimeBase.h" #include "CALatencyLog.h" // System Includes #include // Standard Library Includes #include #include //============================================================================= // CAHALIOCycleTelemetryEvent //============================================================================= static inline SInt64 SubtractUInt64(UInt64 inX, UInt64 inY) { SInt64 theAnswer; if(inX >= inY) { theAnswer = inX - inY; } else { theAnswer = inY - inX; theAnswer *= -1; } return theAnswer; } static inline Float64 ConvertHostTimeToDisplayTime(SInt64 inHostTime) { // convert to milliseconds Float64 theAnswer = 0; if(inHostTime >= 0) { theAnswer = AudioConvertHostTimeToNanos(inHostTime); } else { theAnswer = AudioConvertHostTimeToNanos(-1 * inHostTime); theAnswer *= -1; } theAnswer /= 1000000.0; return theAnswer; } CAHALIOCycleTelemetry::CAHALIOCycleTelemetry() : mLastCycleEnd(), mRawEvents() { } CAHALIOCycleTelemetry::~CAHALIOCycleTelemetry() { } UInt32 CAHALIOCycleTelemetry::GetIOCycleNumber() const { UInt32 theAnswer = 0; if(mRawEvents.size() > 0) { theAnswer = mRawEvents.begin()->mIOCycleNumber; } return theAnswer; } UInt64 CAHALIOCycleTelemetry::GetIntendedStartTime() const { return mLastCycleEnd.mHostTime2; } UInt64 CAHALIOCycleTelemetry::GetStartTime() const { UInt64 theAnswer = 0; CAHALIOCycleRawTelemetryEvent theEvent; if(GetBeginRawEvent(theEvent)) { if(theEvent.mEventKind == kHALIOCycleTelemetryEventWorkLoopBegin) { // the time stamp in the data of the work loop begin event is more accurate theAnswer = theEvent.mHostTime1; } else { theAnswer = theEvent.mEventTime; } } return theAnswer; } UInt64 CAHALIOCycleTelemetry::GetEndTime() const { UInt64 theAnswer = 0; CAHALIOCycleRawTelemetryEvent theEvent; if(GetEndRawEvent(theEvent)) { if(theEvent.mEventKind == kHALIOCycleTelemetryEventWorkLoopEnd) { // the time stamp in the data of the work loop end event is more accurate theAnswer = theEvent.mHostTime1; } else { theAnswer = theEvent.mEventTime; } } return theAnswer; } Float64 CAHALIOCycleTelemetry::GetDuration() const { // find the start time UInt64 theStartTime = 0; CAHALIOCycleRawTelemetryEvent theEvent; if(GetBeginRawEvent(theEvent)) { if(theEvent.mEventKind == kHALIOCycleTelemetryEventWorkLoopBegin) { // the time stamp in the data of the work loop begin event is more accurate theStartTime = theEvent.mHostTime1; } else { theStartTime = theEvent.mEventTime; } } // find the end time UInt64 theEndTime = 0; if(GetEndRawEvent(theEvent)) { theEndTime = theEvent.mEventTime; } return ConvertHostTimeToDisplayTime(theEndTime - theStartTime); } Float64 CAHALIOCycleTelemetry::GetRateScalar() const { Float64 theAnswer = 0; // any of the events that provide an IOProc time stamp should be good for this info // except for the now time, since that is taken prior to the application of the // zero time stamp, so go for the end event CAHALIOCycleRawTelemetryEvent theEvent; if(GetRawEventByKind(kHALIOCycleTelemetryEventWorkLoopEnd, theEvent)) { theAnswer = theEvent.mRateScalar1; } return theAnswer; } void CAHALIOCycleTelemetry::GetIOProcTimes(AudioTimeStamp& outNow, AudioTimeStamp& outInputTime, AudioTimeStamp& outOutputTime) const { CAHALIOCycleRawTelemetryEvent theEvent; // now is with the work loop begin event memset(&outNow, 0, sizeof(AudioTimeStamp)); if(GetRawEventByKind(kHALIOCycleTelemetryEventWorkLoopBegin, theEvent)) { outNow.mRateScalar = theEvent.mRateScalar1; outNow.mSampleTime = theEvent.mSampleTime1; outNow.mHostTime = theEvent.mHostTime1; outNow.mFlags = kAudioTimeStampSampleTimeValid | kAudioTimeStampHostTimeValid | kAudioTimeStampRateScalarValid; } // input time is with the read begin event memset(&outInputTime, 0, sizeof(AudioTimeStamp)); if(GetRawEventByKind(kHALIOCycleTelemetryEventInputReadBegin, theEvent)) { outInputTime.mRateScalar = theEvent.mRateScalar1; outInputTime.mSampleTime = theEvent.mSampleTime1; outInputTime.mHostTime = theEvent.mHostTime1; outInputTime.mFlags = kAudioTimeStampSampleTimeValid | kAudioTimeStampHostTimeValid | kAudioTimeStampRateScalarValid; } // output time is with the write begin event memset(&outOutputTime, 0, sizeof(AudioTimeStamp)); if(GetRawEventByKind(kHALIOCycleTelemetryEventOutputWriteBegin, theEvent)) { outOutputTime.mRateScalar = theEvent.mRateScalar1; outOutputTime.mSampleTime = theEvent.mSampleTime1; outOutputTime.mHostTime = theEvent.mHostTime1; outOutputTime.mFlags = kAudioTimeStampSampleTimeValid | kAudioTimeStampHostTimeValid | kAudioTimeStampRateScalarValid; } } bool CAHALIOCycleTelemetry::HasError() const { bool theAnswer = false; RawEventList::const_iterator theIterator = mRawEvents.begin(); while(!theAnswer && (theIterator != mRawEvents.end())) { theAnswer = CAHALIOCycleTelemetryClient::IsRawEventError(*theIterator); std::advance(theIterator, 1); } return theAnswer; } bool CAHALIOCycleTelemetry::HasOverload() const { CAHALIOCycleRawTelemetryEvent theEvent; bool theAnswer = GetRawEventByKind(kHALIOCycleTelemetryEventWorkLoopOverloadBegin, theEvent); if(!theAnswer) { theAnswer = GetRawEventByKind(kHALIOCycleTelemetryEventWorkLoopOverloadEnd, theEvent); } return theAnswer; } bool CAHALIOCycleTelemetry::HasInputError() const { // the input error is stored with the read end event bool theAnswer = false; CAHALIOCycleRawTelemetryEvent theEvent; if(GetRawEventByKind(kHALIOCycleTelemetryEventInputReadEnd, theEvent)) { theAnswer = theEvent.mError != 0; } return theAnswer; } bool CAHALIOCycleTelemetry::HasOutputError() const { // the output error is stored with the write end event bool theAnswer = false; CAHALIOCycleRawTelemetryEvent theEvent; if(GetRawEventByKind(kHALIOCycleTelemetryEventOutputWriteEnd, theEvent)) { theAnswer = theEvent.mError != 0; } return theAnswer; } bool CAHALIOCycleTelemetry::HasZeroTime() const { bool theAnswer = false; CAHALIOCycleRawTelemetryEvent theEvent; theAnswer = GetRawEventByKind(kHALIOCycleTelemetryEventZeroTimeStampRecieved, theEvent); return theAnswer; } bool CAHALIOCycleTelemetry::HasSignal() const { bool theAnswer = false; CAHALIOCycleRawTelemetryEvent theEvent; theAnswer = GetRawEventByKind(kHALIOCycleTelemetryEventInputDataPresent, theEvent); if(!theAnswer) { theAnswer = GetRawEventByKind(kHALIOCycleTelemetryEventOutputDataPresent, theEvent); } return theAnswer; } bool CAHALIOCycleTelemetry::GetZeroTimeStamp(AudioTimeStamp& outZeroTime) const { bool theAnswer = false; CAHALIOCycleRawTelemetryEvent theEvent; if(GetRawEventByKind(kHALIOCycleTelemetryEventZeroTimeStampRecieved, theEvent)) { outZeroTime.mRateScalar = theEvent.mRateScalar1; outZeroTime.mSampleTime = theEvent.mSampleTime1; outZeroTime.mHostTime = theEvent.mHostTime1; outZeroTime.mFlags = kAudioTimeStampSampleTimeValid | kAudioTimeStampHostTimeValid | kAudioTimeStampRateScalarValid; theAnswer = true; } return theAnswer; } bool CAHALIOCycleTelemetry::GetNextWakeUpTime(AudioTimeStamp& outWakeTime) const { // the next wake up time is stored with the work loop end event bool theAnswer = false; CAHALIOCycleRawTelemetryEvent theEvent; if(GetRawEventByKind(kHALIOCycleTelemetryEventWorkLoopEnd, theEvent)) { outWakeTime.mRateScalar = theEvent.mRateScalar1; outWakeTime.mSampleTime = theEvent.mSampleTime1; outWakeTime.mHostTime = theEvent.mHostTime1; outWakeTime.mFlags = kAudioTimeStampSampleTimeValid | kAudioTimeStampHostTimeValid | kAudioTimeStampRateScalarValid; theAnswer = true; } return theAnswer; } Float64 CAHALIOCycleTelemetry::GetTotalLoad() const { return 0; } Float64 CAHALIOCycleTelemetry::GetSchedulingLoad() const { return 0; } Float64 CAHALIOCycleTelemetry::GetReadLoad() const { return 0; } Float64 CAHALIOCycleTelemetry::GetIOProcLoad() const { return 0; } Float64 CAHALIOCycleTelemetry::GetWriteLoad() const { return 0; } bool CAHALIOCycleTelemetry::AssimilateRawEvent(const CAHALIOCycleRawTelemetryEvent& inRawEvent) { bool theAnswer = false; if(mRawEvents.size() > 0) { // make sure the new one has the same IO cycle number if(inRawEvent.mIOCycleNumber == mRawEvents.begin()->mIOCycleNumber) { mRawEvents.push_back(inRawEvent); theAnswer = true; } } else { // first raw event presented for assimilation mRawEvents.push_back(inRawEvent); theAnswer = true; } return theAnswer; } void CAHALIOCycleTelemetry::SetLastCycleEnd(const CAHALIOCycleRawTelemetryEvent& inRawEvent) { mLastCycleEnd = inRawEvent; } bool CAHALIOCycleTelemetry::GetRawEventByKind(UInt32 inEventKind, CAHALIOCycleRawTelemetryEvent& outRawEvent) const { bool theAnswer = false; RawEventList::const_iterator theIterator = std::find_if(mRawEvents.begin(), mRawEvents.end(), CAHALIOCycleRawTelemetryEvent::MatchEventKind(inEventKind)); if(theIterator != mRawEvents.end()) { outRawEvent = *theIterator; theAnswer = true; } return theAnswer; } bool CAHALIOCycleTelemetry::GetBeginRawEvent(CAHALIOCycleRawTelemetryEvent& outRawEvent) const { bool theAnswer = false; CAHALIOCycleRawTelemetryEvent theEvent; if(GetRawEventByKind(kHALIOCycleTelemetryEventWorkLoopBegin, theEvent)) { outRawEvent = theEvent; theAnswer = true; } else if(GetRawEventByKind(kHALIOCycleTelemetryEventInitializeBegin, theEvent)) { outRawEvent = theEvent; theAnswer = true; } else if(mRawEvents.size() > 0) { outRawEvent = mRawEvents.front(); theAnswer = true; } return theAnswer; } bool CAHALIOCycleTelemetry::GetEndRawEvent(CAHALIOCycleRawTelemetryEvent& outRawEvent) const { bool theAnswer = false; CAHALIOCycleRawTelemetryEvent theEvent; if(GetRawEventByKind(kHALIOCycleTelemetryEventWorkLoopEnd, theEvent)) { outRawEvent = theEvent; theAnswer = true; } else if(mRawEvents.size() > 0) { outRawEvent = mRawEvents.back(); theAnswer = true; } return theAnswer; } UInt32 CAHALIOCycleTelemetry::GetNumberRawEvents() const { return mRawEvents.size(); } bool CAHALIOCycleTelemetry::GetRawEventByIndex(UInt32 inEventIndex, CAHALIOCycleRawTelemetryEvent& outRawEvent) const { bool theAnswer = false; RawEventList::const_iterator theIterator = mRawEvents.begin(); std::advance(theIterator, inEventIndex); if(theIterator != mRawEvents.end()) { outRawEvent = *theIterator; theAnswer = true; } return theAnswer; } //============================================================================= // CAHALIOCycleTelemetryClient //============================================================================= static void CAHALIOCycleTelemetryClient_MessagePortIsInvalid(CFMessagePortRef inMessagePort, void* inInfo); CAHALIOCycleTelemetryClient::CAHALIOCycleTelemetryClient(const char* inLatencyTraceFileName, const char* inLatencyTraceFileNameExtension) : mMessagePort(NULL), mServerIsFlipped(false), mRawTelemetry(), mIOCycleList(), mErrorCycleList(), mZerosCycleList(), mLatencyTraceFileName(inLatencyTraceFileName), mLatencyTraceFileNameExtension(inLatencyTraceFileNameExtension), mLatencyTracingEnabled(false), mTraceTaken(false), mLatencyLog(NULL), mIOThreadSchedulingLatencyTrigger(0), mIOCycleDurationTrigger(0), mOverloadTrigger(false) { } CAHALIOCycleTelemetryClient::~CAHALIOCycleTelemetryClient() { if(mLatencyLog != NULL) { delete mLatencyLog; mLatencyLog = NULL; } } bool CAHALIOCycleTelemetryClient::Initialize(pid_t inProcess, AudioDeviceID inDevice) { bool theAnswer = false; if(mMessagePort == NULL) { CAAudioHardwareDevice theDevice(inDevice); CACFString theUID(theDevice.CopyUID()); CACFString thePortName(CreatePortName(inProcess, theUID.GetCFString())); mMessagePort = new CACFRemoteMessagePort(thePortName.GetCFString(), (CFMessagePortInvalidationCallBack)CAHALIOCycleTelemetryClient_MessagePortIsInvalid); if(mMessagePort->IsValid()) { try { // get the endianness of the HAL bool theServerIsFlipped = false; OSStatus theError = GetServerIsFlippedFromServer(theServerIsFlipped); ThrowIfError(theError, CAException(theError), "CAHALIOCycleTelemetryClient::Initialize: couldn't get the endianness of the server"); mServerIsFlipped = theServerIsFlipped; // tell the HAL to enable telemetry theError = SetIsEnabledOnServer(true); ThrowIfError(theError, CAException(theError), "CAHALIOCycleTelemetryClient::Initialize: couldn't enable telemetry on the server"); // clear out the existing data Clear(); } catch(...) { delete mMessagePort; mMessagePort = NULL; } } else { delete mMessagePort; mMessagePort = NULL; } } mTraceTaken = false; return theAnswer; } void CAHALIOCycleTelemetryClient::Teardown() { Clear(); if(mMessagePort != NULL) { UInt32 theError = SetIsEnabledOnServer(false); ThrowIfError(theError, CAException(theError), "CAHALIOCycleTelemetryClient::Teardown: couldn't disable telemetry on the server"); delete mMessagePort; mMessagePort = NULL; } mTraceTaken = false; } static inline Float64 SwapFloat64(Float64 inNumber) { union FakeFloat64 { Float64 mFloat64; UInt64 mUInt64; } theAnswer; theAnswer.mFloat64 = inNumber; theAnswer.mUInt64 = CFSwapInt64(theAnswer.mUInt64); return theAnswer.mFloat64; } CFStringRef CAHALIOCycleTelemetryClient::CreatePortName(pid_t inProcessID, CFStringRef inUID) { // get the CFHash of the UID UInt32 theHashCode = CFHash(inUID); // sum all the characters in the UID UInt64 theSum = 0; UInt32 theNumberCharacters = CFStringGetLength(inUID); for(UInt32 theCharacterIndex = 0; theCharacterIndex < theNumberCharacters; ++theCharacterIndex) { UniChar theCharacter = CFStringGetCharacterAtIndex(inUID, theCharacterIndex); theSum += theCharacter; } // build a string out of the hash code and character sum CFStringRef thePortName = CFStringCreateWithFormat(NULL, NULL, CFSTR(kHALIOCycleTelemetryServerPortNameFormat), inProcessID, theHashCode, theSum); return thePortName; } bool CAHALIOCycleTelemetryClient::Update() { bool theAnswer = false; try { ThrowIfNULL(mMessagePort, CAException(kAudioHardwareIllegalOperationError), "CAHALIOCycleTelemetryClient::Update: no port"); UInt32 theNumberEvents = 0; do { // build the request CACFDictionary theMessageData(true); CACFData theMessageCFData(CFPropertyListCreateXMLData(NULL, theMessageData.GetCFDictionary())); // send the request to the HAL CFDataRef __theReturnCFData = NULL; SInt32 theError = mMessagePort->SendRequest(kHALTelemetryMessageGetTelemetry, theMessageCFData.GetCFData(), 10.0, 10.0, kCFRunLoopDefaultMode, __theReturnCFData); ThrowIfError(theError, CAException(theError), "CAHALIOCycleTelemetryClient::Update: sending the request failed"); ThrowIfNULL(__theReturnCFData, CAException(kAudioHardwareUnspecifiedError), "CAHALIOCycleTelemetryClient::Update: no return result from the server"); // the returned data is a buffer full of CAHALIOCycleRawTelemetryEvent structs CACFData theReturnCFData(__theReturnCFData); UInt32 theSize = theReturnCFData.GetSize(); theNumberEvents = theSize / sizeof(CAHALIOCycleRawTelemetryEvent); // catalog the new events for(UInt32 theEventIndex = 0; theEventIndex < theNumberEvents; ++theEventIndex) { // get the event out of the array CAHALIOCycleRawTelemetryEvent theEvent; theReturnCFData.CopyData(theEventIndex * sizeof(CAHALIOCycleRawTelemetryEvent), &theEvent, sizeof(CAHALIOCycleRawTelemetryEvent)); // flip it if necessary if(mServerIsFlipped) { theEvent.mEventTime = CFSwapInt64(theEvent.mEventTime); theEvent.mEventKind = CFSwapInt32(theEvent.mEventKind); theEvent.mIOCycleNumber = CFSwapInt32(theEvent.mIOCycleNumber); theEvent.mRateScalar1 = SwapFloat64(theEvent.mRateScalar1); theEvent.mRateScalar2 = SwapFloat64(theEvent.mRateScalar2); theEvent.mSampleTime1 = SwapFloat64(theEvent.mSampleTime1); theEvent.mSampleTime2 = SwapFloat64(theEvent.mSampleTime2); theEvent.mHostTime1 = CFSwapInt64(theEvent.mHostTime1); theEvent.mHostTime2 = CFSwapInt64(theEvent.mHostTime2); theEvent.mError = CFSwapInt64(theEvent.mError); theEvent.mFlags = CFSwapInt64(theEvent.mFlags); } // stick it into the list mRawTelemetry.push_back(theEvent); // figure out which cycle telemetry this raw event belongs to // starting with the last one on the list bool wasPlaced = false; if(mIOCycleList.size() > 0) { wasPlaced = mIOCycleList.back().AssimilateRawEvent(theEvent); } // didn't belong there if(!wasPlaced) { // so make a new one CAHALIOCycleTelemetry theIOCycle; // assimilate this event theIOCycle.AssimilateRawEvent(theEvent); // set the end event CAHALIOCycleRawTelemetryEvent theLastEvent; if(mIOCycleList.size() > 0) { wasPlaced = mIOCycleList.back().GetEndRawEvent(theLastEvent); } theIOCycle.SetLastCycleEnd(theLastEvent); // push it onto the list mIOCycleList.push_back(theIOCycle); } // do the latency tracing if(mLatencyTracingEnabled && (mLatencyLog != NULL) && !mTraceTaken) { // get some values we're about to use UInt64 theStartTime = mIOCycleList.back().GetStartTime(); UInt64 theEndTime = mIOCycleList.back().GetEndTime(); UInt64 theIntendedStartTime = mIOCycleList.back().GetIntendedStartTime(); bool hasOverload = mIOCycleList.back().HasOverload(); // check for a scheduling latency in the IO thread if((mIOThreadSchedulingLatencyTrigger != 0) && (theIntendedStartTime > 0)) { // calculate the lateness (in milliseconds) Float64 theLateness = ConvertHostTimeToDisplayTime(SubtractUInt64(theStartTime, theIntendedStartTime)); if(theLateness > mIOThreadSchedulingLatencyTrigger) { // log it mLatencyLog->Capture(theIntendedStartTime - CAHostTimeBase::ConvertFromNanos(10 * 1000 * 1000), theStartTime + CAHostTimeBase::ConvertFromNanos(1 * 1000 * 1000), true); // print how late we are DebugMessageN1("Woke up late by %f milliseconds, logging trace...", theLateness); mTraceTaken = true; } } // check to see if the cycle took too long if((mIOCycleDurationTrigger != 0) && (theStartTime != 0) && (theEndTime != 0)) { // get the duration of the cycle (in milliseconds) Float64 theDuration = mIOCycleList.back().GetDuration(); if(theDuration > mIOCycleDurationTrigger) { // log it mLatencyLog->Capture(theStartTime - CAHostTimeBase::ConvertFromNanos(1 * 1000 * 1000), theEndTime + CAHostTimeBase::ConvertFromNanos(1 * 1000 * 1000), true); // print how late we are DebugMessageN1("IO cycle took %f milliseconds, logging trace...", theDuration); mTraceTaken = true; } } // check to see if an overload took place if(mOverloadTrigger && hasOverload && (theStartTime != 0) && (theEndTime != 0)) { // log it mLatencyLog->Capture(theStartTime - CAHostTimeBase::ConvertFromNanos(1 * 1000 * 1000), theEndTime + CAHostTimeBase::ConvertFromNanos(1 * 1000 * 1000), true); // print how late we are DebugMessage("IO cycle had an overload, logging trace..."); mTraceTaken = true; } } } theAnswer = theAnswer || (theNumberEvents > 0); } while(theNumberEvents > 0); } catch(const CAException& inException) { } catch(...) { } return theAnswer; } void CAHALIOCycleTelemetryClient::Clear() { mRawTelemetry.clear(); mIOCycleList.clear(); mErrorCycleList.clear(); mZerosCycleList.clear(); ClearDataOnServer(); mTraceTaken = false; } UInt32 CAHALIOCycleTelemetryClient::GetNumberIOCycles() const { return mIOCycleList.size(); } UInt32 CAHALIOCycleTelemetryClient::GetPreviousErrorIOCycleIndex(UInt32 inCurrentIndex) const { UInt32 theAnswer = 0xFFFFFFFF; IOCycleList::const_iterator theIOCycleIterator = mIOCycleList.begin(); if(inCurrentIndex < mIOCycleList.size()) { std::advance(theIOCycleIterator, inCurrentIndex); } if(theIOCycleIterator->HasError()) { --inCurrentIndex; --theIOCycleIterator; } while((theAnswer == 0xFFFFFFFF) && (theIOCycleIterator != mIOCycleList.begin())) { if(theIOCycleIterator->HasError()) { theAnswer = inCurrentIndex; } else { --inCurrentIndex; --theIOCycleIterator; } } return theAnswer; } UInt32 CAHALIOCycleTelemetryClient::GetNextErrorIOCycleIndex(UInt32 inCurrentIndex) const { UInt32 theAnswer = 0xFFFFFFFF; IOCycleList::const_iterator theIOCycleIterator = mIOCycleList.begin(); if(inCurrentIndex < mIOCycleList.size()) { std::advance(theIOCycleIterator, inCurrentIndex); } if(theIOCycleIterator->HasError()) { ++inCurrentIndex; std::advance(theIOCycleIterator, 1); } while((theAnswer == 0xFFFFFFFF) && (theIOCycleIterator != mIOCycleList.end())) { if(theIOCycleIterator->HasError()) { theAnswer = inCurrentIndex; } else { ++inCurrentIndex; std::advance(theIOCycleIterator, 1); } } return theAnswer; } UInt32 CAHALIOCycleTelemetryClient::GetNumberEventsInIOCycle(UInt32 inIOCycleIndex) const { UInt32 theAnswer = 0; IOCycleList::const_iterator theIOCycleIterator = mIOCycleList.begin(); std::advance(theIOCycleIterator, inIOCycleIndex); if(theIOCycleIterator != mIOCycleList.end()) { theAnswer = theIOCycleIterator->GetNumberRawEvents(); } return theAnswer; } bool CAHALIOCycleTelemetryClient::IOCycleHasError(UInt32 inIOCycleIndex) const { bool theAnswer = false; IOCycleList::const_iterator theIOCycleIterator = mIOCycleList.begin(); std::advance(theIOCycleIterator, inIOCycleIndex); if(theIOCycleIterator != mIOCycleList.end()) { theAnswer = theIOCycleIterator->HasError(); } return theAnswer; } bool CAHALIOCycleTelemetryClient::IOCycleHasSignal(UInt32 inIOCycleIndex) const { bool theAnswer = false; IOCycleList::const_iterator theIOCycleIterator = mIOCycleList.begin(); std::advance(theIOCycleIterator, inIOCycleIndex); if(theIOCycleIterator != mIOCycleList.end()) { theAnswer = theIOCycleIterator->HasSignal(); } return theAnswer; } bool CAHALIOCycleTelemetryClient::EventInIOCycleHasError(UInt32 inIOCycleIndex, UInt32 inEventIndex) const { bool theAnswer = false; IOCycleList::const_iterator theIOCycleIterator = mIOCycleList.begin(); std::advance(theIOCycleIterator, inIOCycleIndex); if(theIOCycleIterator != mIOCycleList.end()) { CAHALIOCycleRawTelemetryEvent theEvent; if(theIOCycleIterator->GetRawEventByIndex(inEventIndex, theEvent)) { theAnswer = IsRawEventError(theEvent); } } return theAnswer; } bool CAHALIOCycleTelemetryClient::EventInIOCycleHasSignal(UInt32 inIOCycleIndex, UInt32 inEventIndex) const { bool theAnswer = false; IOCycleList::const_iterator theIOCycleIterator = mIOCycleList.begin(); std::advance(theIOCycleIterator, inIOCycleIndex); if(theIOCycleIterator != mIOCycleList.end()) { CAHALIOCycleRawTelemetryEvent theEvent; if(theIOCycleIterator->GetRawEventByIndex(inEventIndex, theEvent)) { theAnswer = IsRawEventSignal(theEvent); } } return theAnswer; } void CAHALIOCycleTelemetryClient::CreateSummaryHeaderForIOCycle(char* outSummary, bool inForSpreadSheet) const { if(!inForSpreadSheet) { sprintf(outSummary, " %12s (%7s %7s) %8s {%9s, %12s} {%9s, %12s} {%9s, %12s} {%9s, %12s} {%9s, %12s}", "Start", "Offset", "Late", "Rate", "Now:samp", "Now:host", "In:samp", "In:host", "Out:samp", "Out:host", "Wake:samp", "Wake:host", "Zero:samp", "Zero:host"); } else { sprintf(outSummary, "%s\t%7s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\r", "Start", "Offset", "Late", "Rate", "Now:samp", "Now:host", "In:samp", "In:host", "Out:samp", "Out:host", "Wake:samp", "Wake:host", "Zero:samp", "Zero:host"); } } void CAHALIOCycleTelemetryClient::CreateSummaryForIOCycle(UInt32 inIOCycleIndex, char* outSummary, bool inForSpreadSheet) const { UInt64 theAnchorTime = mRawTelemetry.front().mEventTime; IOCycleList::const_iterator theIOCycleIterator = mIOCycleList.begin(); std::advance(theIOCycleIterator, inIOCycleIndex); if(theIOCycleIterator != mIOCycleList.end()) { IOCycleList::const_iterator theIOCyclePreviousIterator = theIOCycleIterator; if(inIOCycleIndex > 0) { --theIOCyclePreviousIterator; } AudioTimeStamp theNow, theInput, theOutput, theNext; theIOCycleIterator->GetIOProcTimes(theNow, theInput, theOutput); theIOCycleIterator->GetNextWakeUpTime(theNext); Float64 theStartTime = ConvertHostTimeToDisplayTime(SubtractUInt64(theIOCycleIterator->GetStartTime(), theAnchorTime)); Float64 theOffsetFromPreviousStartTime = ConvertHostTimeToDisplayTime(SubtractUInt64(theIOCycleIterator->GetStartTime(), theIOCyclePreviousIterator->GetStartTime())); Float64 theLateness = (theIOCycleIterator->GetIntendedStartTime() > 0) ? ConvertHostTimeToDisplayTime(SubtractUInt64(theIOCycleIterator->GetStartTime(), theIOCycleIterator->GetIntendedStartTime())) : 0; Float64 theRateScalar = theIOCycleIterator->GetRateScalar(); Float64 theNowHostTime = ((theNow.mFlags & kAudioTimeStampHostTimeValid) != 0) ? ConvertHostTimeToDisplayTime(SubtractUInt64(theNow.mHostTime, theAnchorTime)) : 0; Float64 theInputHostTime = ((theInput.mFlags & kAudioTimeStampHostTimeValid) != 0) ? ConvertHostTimeToDisplayTime(SubtractUInt64(theInput.mHostTime, theAnchorTime)) : 0; Float64 theOutputHostTime = ((theOutput.mFlags & kAudioTimeStampHostTimeValid) != 0) ? ConvertHostTimeToDisplayTime(SubtractUInt64(theOutput.mHostTime, theAnchorTime)) : 0; Float64 theNextHostTime = ((theNext.mFlags & kAudioTimeStampHostTimeValid) != 0) ? ConvertHostTimeToDisplayTime(SubtractUInt64(theNext.mHostTime, theAnchorTime)) : 0; if(!theIOCycleIterator->HasZeroTime()) { if(!inForSpreadSheet) { sprintf(outSummary, "%12.3f (%+7.3f %+7.3f) %-9.6f {%9.0f, %12.3f} {%9.0f, %12.3f} {%9.0f, %12.3f} {%9.0f, %12.3f}", theStartTime, theOffsetFromPreviousStartTime, theLateness, theRateScalar, theNow.mSampleTime, theNowHostTime, theInput.mSampleTime, theInputHostTime, theOutput.mSampleTime, theOutputHostTime, theNext.mSampleTime, theNextHostTime); } else { sprintf(outSummary, "%.3f\t%.3f\t%.3f\t%.6f\t%.0f\t%.3f\t%.0f\t%.3f\t%.0f\t%.3f\t%.0f\t%.3f\r", theStartTime, theOffsetFromPreviousStartTime, theLateness, theRateScalar, theNow.mSampleTime, theNowHostTime, theInput.mSampleTime, theInputHostTime, theOutput.mSampleTime, theOutputHostTime, theNext.mSampleTime, theNextHostTime); } } else { AudioTimeStamp theZero; theIOCycleIterator->GetZeroTimeStamp(theZero); Float64 theZeroHostTime = ConvertHostTimeToDisplayTime(SubtractUInt64(theZero.mHostTime, theAnchorTime)); if(!inForSpreadSheet) { sprintf(outSummary, "%12.3f (%+7.3f %+7.3f) %-9.6f {%9.0f, %12.3f} {%9.0f, %12.3f} {%9.0f, %12.3f} {%9.0f, %12.3f} {%9.0f, %12.3f}", theStartTime, theOffsetFromPreviousStartTime, theLateness, theRateScalar, theNow.mSampleTime, theNowHostTime, theInput.mSampleTime, theInputHostTime, theOutput.mSampleTime, theOutputHostTime, theNext.mSampleTime, theNextHostTime, theZero.mSampleTime, theZeroHostTime); } else { sprintf(outSummary, "%.3f\t%.3f\t%.3f\t%.6f\t%.0f\t%.3f\t%.0f\t%.3f\t%.0f\t%.3f\t%.0f\t%.3f\t%.0f\t%.3f\r", theStartTime, theOffsetFromPreviousStartTime, theLateness, theRateScalar, theNow.mSampleTime, theNowHostTime, theInput.mSampleTime, theInputHostTime, theOutput.mSampleTime, theOutputHostTime, theNext.mSampleTime, theNextHostTime, theZero.mSampleTime, theZeroHostTime); } } } } void CAHALIOCycleTelemetryClient::CreateSummaryForEventInIOCycle(UInt32 inIOCycleIndex, UInt32 inEventIndex, char* outSummary) const { UInt64 theAnchorTime = mRawTelemetry.front().mEventTime; IOCycleList::const_iterator theIOCycleIterator = mIOCycleList.begin(); std::advance(theIOCycleIterator, inIOCycleIndex); if(theIOCycleIterator != mIOCycleList.end()) { CAHALIOCycleRawTelemetryEvent theEvent; if(theIOCycleIterator->GetRawEventByIndex(inEventIndex, theEvent)) { CAHALIOCycleRawTelemetryEvent thePreviousEvent = theEvent; if(inEventIndex > 0) { theIOCycleIterator->GetRawEventByIndex(inEventIndex - 1, thePreviousEvent); } CreateSummaryForRawEvent(theEvent, thePreviousEvent, theAnchorTime, outSummary); } } } UInt32 CAHALIOCycleTelemetryClient::GetNumberRawEvents() const { return mRawTelemetry.size(); } UInt32 CAHALIOCycleTelemetryClient::GetPreviousErrorRawEventIndex(UInt32 inCurrentIndex) const { UInt32 theAnswer = 0xFFFFFFFF; EventList::const_iterator theIOCycleIterator = mRawTelemetry.begin(); if(inCurrentIndex < mRawTelemetry.size()) { std::advance(theIOCycleIterator, inCurrentIndex); } if(IsRawEventError(*theIOCycleIterator)) { --inCurrentIndex; --theIOCycleIterator; } while((theAnswer == 0xFFFFFFFF) && (theIOCycleIterator != mRawTelemetry.begin())) { if(IsRawEventError(*theIOCycleIterator)) { theAnswer = inCurrentIndex; } else { --inCurrentIndex; --theIOCycleIterator; } } return theAnswer; } UInt32 CAHALIOCycleTelemetryClient::GetNextErrorRawEventIndex(UInt32 inCurrentIndex) const { UInt32 theAnswer = 0xFFFFFFFF; EventList::const_iterator theIOCycleIterator = mRawTelemetry.begin(); if(inCurrentIndex < mRawTelemetry.size()) { std::advance(theIOCycleIterator, inCurrentIndex); } if(IsRawEventError(*theIOCycleIterator)) { ++inCurrentIndex; std::advance(theIOCycleIterator, 1); } while((theAnswer == 0xFFFFFFFF) && (theIOCycleIterator != mRawTelemetry.end())) { if(IsRawEventError(*theIOCycleIterator)) { theAnswer = inCurrentIndex; } else { ++inCurrentIndex; std::advance(theIOCycleIterator, 1); } } return theAnswer; } bool CAHALIOCycleTelemetryClient::IsRawEventError(const CAHALIOCycleRawTelemetryEvent& inEvent) { bool theAnswer = false; switch(inEvent.mEventKind) { case kHALIOCycleTelemetryEventInitializeBegin: break; case kHALIOCycleTelemetryEventInitializeEnd: break; case kHALIOCycleTelemetryEventWorkLoopBegin: break; case kHALIOCycleTelemetryEventInputReadBegin: break; case kHALIOCycleTelemetryEventInputReadEnd: theAnswer = inEvent.mError != 0; break; case kHALIOCycleTelemetryEventIOProcsBegin: break; case kHALIOCycleTelemetryEventIOProcsEnd: break; case kHALIOCycleTelemetryEventOutputWriteBegin: break; case kHALIOCycleTelemetryEventOutputWriteEnd: theAnswer = inEvent.mError != 0; break; case kHALIOCycleTelemetryEventWorkLoopOverloadBegin: theAnswer = true; break; case kHALIOCycleTelemetryEventWorkLoopOverloadEnd: theAnswer = true; break; case kHALIOCycleTelemetryEventWorkLoopEnd: break; case kHALIOCycleTelemetryEventTeardownBegin: break; case kHALIOCycleTelemetryEventTeardownEnd: break; case kHALIOCycleTelemetryEventZeroTimeStampRecieved: break; case kHALIOCycleTelemetryEventZeroTimeStampApplied: break; case kHALIOCycleTelemetryEventEarlyZeroTimeStamp: theAnswer = true; break; case kHALIOCycleTelemetryEventOutOfBoundsZeroTimeStamp: theAnswer = true; break; case kHALIOCycleTelemetryEventTimelineReset: theAnswer = true; break; case kHALIOCycleTelemetryEventResynch: break; case kHALIOCycleTelemetryEventInputDataPresent: break; case kHALIOCycleTelemetryEventOutputDataPresent: break; case kHALIOCycleTelemetryEventStartHardware: theAnswer = inEvent.mError != 0; break; case kHALIOCycleTelemetryEventStopHardware: theAnswer = inEvent.mError != 0; break; case kHALIOCycleTelemetryEventHardwareStarted: break; case kHALIOCycleTelemetryEventHardwareStopped: break; case kHALIOCycleTelemetryEventHardwarePaused: break; case kHALIOCycleTelemetryEventHardwareResumed: break; case kHALIOCycleTelemetryEventFormatChangeBegin: break; case kHALIOCycleTelemetryEventFormatChangeEnd: break; case kHALIOCycleTelemetryEventMajorEngineChangeBegin: break; case kHALIOCycleTelemetryEventMajorEngineChangeEnd: break; }; return theAnswer; } bool CAHALIOCycleTelemetryClient::IsRawEventSignal(const CAHALIOCycleRawTelemetryEvent& inEvent) { return (inEvent.mEventKind == kHALIOCycleTelemetryEventInputDataPresent) || (inEvent.mEventKind == kHALIOCycleTelemetryEventOutputDataPresent); } bool CAHALIOCycleTelemetryClient::IsRawEventError(UInt32 inEventIndex) const { bool theAnswer = false; EventList::const_iterator theIterator = mRawTelemetry.begin(); std::advance(theIterator, inEventIndex); if(theIterator != mRawTelemetry.end()) { theAnswer = IsRawEventError(*theIterator); } return theAnswer; } bool CAHALIOCycleTelemetryClient::IsRawEventSignal(UInt32 inEventIndex) const { bool theAnswer = false; EventList::const_iterator theIterator = mRawTelemetry.begin(); std::advance(theIterator, inEventIndex); if(theIterator != mRawTelemetry.end()) { theAnswer = IsRawEventSignal(*theIterator); } return theAnswer; } void CAHALIOCycleTelemetryClient::CreateSummaryHeaderForRawEvent(char* outSummary) const { sprintf(outSummary, " Event %8s %8s (%8s) Data", "Cycle", "Time", "Offset"); } void CAHALIOCycleTelemetryClient::CreateSummaryForRawEvent(UInt32 inEventIndex, char* outSummary) const { UInt64 theAnchorTime = mRawTelemetry.front().mEventTime; EventList::const_iterator theIterator = mRawTelemetry.begin(); std::advance(theIterator, inEventIndex); if(theIterator != mRawTelemetry.end()) { CAHALIOCycleRawTelemetryEvent thePreviousEvent; if(theIterator != mRawTelemetry.begin()) { thePreviousEvent = *(theIterator - 1); } else { thePreviousEvent = *theIterator; } CreateSummaryForRawEvent(*theIterator, thePreviousEvent, theAnchorTime, outSummary); } } void CAHALIOCycleTelemetryClient::CreateSummaryForRawEvent(const CAHALIOCycleRawTelemetryEvent& inEvent, const CAHALIOCycleRawTelemetryEvent& inPreviousEvent, UInt64 inAnchorTime, char* outSummary) { Float64 theEventTime = ConvertHostTimeToDisplayTime(SubtractUInt64(inEvent.mEventTime, inAnchorTime)); Float64 theEventTimeDifference = ConvertHostTimeToDisplayTime(SubtractUInt64(inEvent.mEventTime, inPreviousEvent.mEventTime)); Float64 theEventHostTime1 = ConvertHostTimeToDisplayTime(SubtractUInt64(inEvent.mHostTime1, inAnchorTime)); Float64 theEventHostTime2 = ConvertHostTimeToDisplayTime(SubtractUInt64(inEvent.mHostTime2, inAnchorTime)); switch(inEvent.mEventKind) { case kHALIOCycleTelemetryEventInitializeBegin: sprintf(outSummary, "->Init: %8u %8.3f (%+8.3f)" , (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventInitializeEnd: sprintf(outSummary, "<-Init: %8u %8.3f (%+8.3f) Anchor: (%9.0f, %12.3f, %-9.6f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, inEvent.mSampleTime1, theEventHostTime1, inEvent.mRateScalar1); break; case kHALIOCycleTelemetryEventWorkLoopBegin: sprintf(outSummary, "->Cycle: %8u %8.3f (%+8.3f) Now: (%9.0f, %12.3f, %-9.6f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, inEvent.mSampleTime1, theEventHostTime1, inEvent.mRateScalar1); break; case kHALIOCycleTelemetryEventInputReadBegin: sprintf(outSummary, "->Read: %8u %8.3f (%+8.3f) Input: (%9.0f, %12.3f, %-9.6f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, inEvent.mSampleTime1, theEventHostTime1, inEvent.mRateScalar1); break; case kHALIOCycleTelemetryEventInputReadEnd: sprintf(outSummary, "<-Read: %8u %8.3f (%+8.3f) Error: 0x%X", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, (unsigned int)inEvent.mError); break; case kHALIOCycleTelemetryEventIOProcsBegin: sprintf(outSummary, "->IOProc: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventIOProcsEnd: sprintf(outSummary, "<-IOProc: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventOutputWriteBegin: sprintf(outSummary, "->Write: %8u %8.3f (%+8.3f) Output: (%9.0f, %12.3f, %-9.6f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, inEvent.mSampleTime1, theEventHostTime1, inEvent.mRateScalar1); break; case kHALIOCycleTelemetryEventOutputWriteEnd: sprintf(outSummary, "<-Write: %8u %8.3f (%+8.3f) Error: 0x%X", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, (unsigned int)inEvent.mError); break; case kHALIOCycleTelemetryEventWorkLoopOverloadBegin: sprintf(outSummary, "->Over: %8u %8.3f (%+8.3f) Current: (%9.0f, %12.3f, %-9.6f) Wake: (%9.0f, %12.3f, %-9.6f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, inEvent.mSampleTime1, theEventHostTime1, inEvent.mRateScalar1, inEvent.mSampleTime2, theEventHostTime2, inEvent.mRateScalar2); break; case kHALIOCycleTelemetryEventWorkLoopOverloadEnd: sprintf(outSummary, "<-Over: %8u %8.3f (%+8.3f) Anchor: (%9.0f, %12.3f, %-9.6f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, inEvent.mSampleTime1, theEventHostTime1, inEvent.mRateScalar1); break; case kHALIOCycleTelemetryEventWorkLoopEnd: sprintf(outSummary, "<-Cycle: %8u %8.3f (%+8.3f) Current: (%9.0f, %12.3f, %-9.6f) Wake: (%9.0f, %12.3f, %-9.6f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, inEvent.mSampleTime1, theEventHostTime1, inEvent.mRateScalar1, inEvent.mSampleTime2, theEventHostTime2, inEvent.mRateScalar2); break; case kHALIOCycleTelemetryEventTeardownBegin: sprintf(outSummary, "->Down: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventTeardownEnd: sprintf(outSummary, "<-Down: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventZeroTimeStampRecieved: sprintf(outSummary, "0 Receiv: %8u %8.3f (%+8.3f) Zero: (%9.0f, %12.3f, %-9.6f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, inEvent.mSampleTime1, theEventHostTime1, inEvent.mRateScalar1); break; case kHALIOCycleTelemetryEventZeroTimeStampApplied: sprintf(outSummary, "0 Apply: %8u %8.3f (%+8.3f) Zero: (%9.0f, %12.3f, %-9.6f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, inEvent.mSampleTime1, theEventHostTime1, inEvent.mRateScalar1); break; case kHALIOCycleTelemetryEventEarlyZeroTimeStamp: sprintf(outSummary, "0 Early: %8u %8.3f (%+8.3f) Zero: (%9.0f, %12.3f, %-9.6f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, inEvent.mSampleTime1, theEventHostTime1, inEvent.mRateScalar1); break; case kHALIOCycleTelemetryEventOutOfBoundsZeroTimeStamp: sprintf(outSummary, "0 OoB: %8u %8.3f (%+8.3f) Zero: (%9.0f, %12.3f, %-9.6f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, inEvent.mSampleTime1, theEventHostTime1, inEvent.mRateScalar1); break; case kHALIOCycleTelemetryEventTimelineReset: sprintf(outSummary, "reset: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventResynch: sprintf(outSummary, "resynch: %8u %8.3f (%+8.3f) Anchor: (%9.0f, %12.3f, %-9.6f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, inEvent.mSampleTime1, theEventHostTime1, inEvent.mRateScalar1); break; case kHALIOCycleTelemetryEventInputDataPresent: sprintf(outSummary, "sig in: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventOutputDataPresent: sprintf(outSummary, "sig out: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventStartHardware: sprintf(outSummary, "start hw: %8u %8.3f (%+8.3f) Error: 0x%X", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, (unsigned int)inEvent.mError); break; case kHALIOCycleTelemetryEventStopHardware: sprintf(outSummary, "stop hw: %8u %8.3f (%+8.3f) Error: 0x%X", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference, (unsigned int)inEvent.mError); break; case kHALIOCycleTelemetryEventHardwareStarted: sprintf(outSummary, "hw start: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventHardwareStopped: sprintf(outSummary, "hw stop: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventHardwarePaused: sprintf(outSummary, "hw pause: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventHardwareResumed: sprintf(outSummary, "hw resum: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventFormatChangeBegin: sprintf(outSummary, "->hw fmt: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventFormatChangeEnd: sprintf(outSummary, "<-hw fmt: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventMajorEngineChangeBegin: sprintf(outSummary, "->mec: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; case kHALIOCycleTelemetryEventMajorEngineChangeEnd: sprintf(outSummary, "<-mec: %8u %8.3f (%+8.3f)", (unsigned int)inEvent.mIOCycleNumber, theEventTime, theEventTimeDifference); break; }; } OSStatus CAHALIOCycleTelemetryClient::GetIsEnabledFromServer(bool& outIsEnabled) { UInt32 theError = 0; CFDataRef theReturnCFData = NULL; outIsEnabled = false; try { if(mMessagePort != NULL) { // build the request CACFDictionary theMessageData(true); theMessageData.AddUInt32(CFSTR(kHALIOCycleTelemetryPropertyIDKey), kHALTelemetryPropertyIsCapturing); CACFData theMessageCFData(CFPropertyListCreateXMLData(NULL, theMessageData.GetCFDictionary())); // send the request to the HAL theError = mMessagePort->SendRequest(kHALTelemetryMessageGetProperty, theMessageCFData.GetCFData(), 10.0, 10.0, kCFRunLoopDefaultMode, theReturnCFData); ThrowIfError(theError, CAException(theError), "CAHALIOCycleTelemetryClient::GetIsEnabledFromServer: sending the request failed"); ThrowIfNULL(theReturnCFData, CAException(kAudioHardwareUnspecifiedError), "CAHALIOCycleTelemetryClient::GetIsEnabledFromServer: no return result from the server"); // evaluate the returned data CACFDictionary theReturnData(static_cast(CFPropertyListCreateFromXMLData(NULL, theReturnCFData, kCFPropertyListImmutable, NULL)), true); // check the error theError = 0; ThrowIf(!theReturnData.GetUInt32(CFSTR(kHALIOCycleTelemetryReturnErrorKey), theError), CAException(kAudioHardwareUnspecifiedError), "CAHALIOCycleTelemetryClient::GetIsEnabledFromServer: no error in the return data"); ThrowIfError(theError, CAException(theError), "CAHALIOCycleTelemetryClient::GetIsEnabledFromServer: the return data contained an error"); // get the value of the property UInt32 thePropertyValue = 0; ThrowIf(!theReturnData.GetUInt32(CFSTR(kHALIOCycleTelemetryPropertyValueKey), thePropertyValue), CAException(kAudioHardwareUnspecifiedError), "CAHALIOCycleTelemetryClient::GetIsEnabledFromServer: no return value in the return data"); outIsEnabled = thePropertyValue != 0; } } catch(const CAException& inException) { theError = inException.GetError(); } catch(...) { theError = kAudioHardwareUnspecifiedError; } if(theReturnCFData != NULL) { CFRelease(theReturnCFData); } return theError; } OSStatus CAHALIOCycleTelemetryClient::SetIsEnabledOnServer(bool inIsEnabled) { UInt32 theError = 0; CFDataRef theReturnCFData = NULL; try { if(mMessagePort != NULL) { // build the request CACFDictionary theMessageData(true); theMessageData.AddUInt32(CFSTR(kHALIOCycleTelemetryPropertyIDKey), kHALTelemetryPropertyIsCapturing); theMessageData.AddUInt32(CFSTR(kHALIOCycleTelemetryPropertyValueKey), (inIsEnabled ? 1L : 0L)); CACFData theMessageCFData(CFPropertyListCreateXMLData(NULL, theMessageData.GetCFDictionary())); // send the request to the HAL theError = mMessagePort->SendRequest(kHALTelemetryMessageSetProperty, theMessageCFData.GetCFData(), 10.0, 10.0, kCFRunLoopDefaultMode, theReturnCFData); ThrowIfError(theError, CAException(theError), "CAHALIOCycleTelemetryClient::SetIsEnabledOnServer: sending the request failed"); ThrowIfNULL(theReturnCFData, CAException(kAudioHardwareUnspecifiedError), "CAHALIOCycleTelemetryClient::SetIsEnabledOnServer: no return result from the server"); // evaluate the returned data CACFDictionary theReturnData(static_cast(CFPropertyListCreateFromXMLData(NULL, theReturnCFData, kCFPropertyListImmutable, NULL)), true); // check the error theError = 0; ThrowIf(!theReturnData.GetUInt32(CFSTR(kHALIOCycleTelemetryReturnErrorKey), theError), CAException(kAudioHardwareUnspecifiedError), "CAHALIOCycleTelemetryClient::SetIsEnabledOnServer: no error in the return data"); ThrowIfError(theError, CAException(theError), "CAHALIOCycleTelemetryClient::SetIsEnabledOnServer: the return data contained an error"); } } catch(const CAException& inException) { theError = inException.GetError(); } catch(...) { theError = kAudioHardwareUnspecifiedError; } if(theReturnCFData != NULL) { CFRelease(theReturnCFData); } return theError; } OSStatus CAHALIOCycleTelemetryClient::GetServerIsFlippedFromServer(bool& outServerIsFlipped) { UInt32 theError = 0; CFDataRef theReturnCFData = NULL; outServerIsFlipped = false; try { if(mMessagePort != NULL) { // build the request CACFDictionary theMessageData(true); theMessageData.AddUInt32(CFSTR(kHALIOCycleTelemetryPropertyIDKey), kHALTelemetryPropertyEndianness); CACFData theMessageCFData(CFPropertyListCreateXMLData(NULL, theMessageData.GetCFDictionary())); // send the request to the HAL theError = mMessagePort->SendRequest(kHALTelemetryMessageGetProperty, theMessageCFData.GetCFData(), 10.0, 10.0, kCFRunLoopDefaultMode, theReturnCFData); ThrowIfError(theError, CAException(theError), "CAHALIOCycleTelemetryClient::GetServerIsFlippedFromServer: sending the request failed"); ThrowIfNULL(theReturnCFData, CAException(kAudioHardwareUnspecifiedError), "CAHALIOCycleTelemetryClient::GetServerIsFlippedFromServer: no return result from the server"); // evaluate the returned data CACFDictionary theReturnData(static_cast(CFPropertyListCreateFromXMLData(NULL, theReturnCFData, kCFPropertyListImmutable, NULL)), true); // check the error theError = 0; ThrowIf(!theReturnData.GetUInt32(CFSTR(kHALIOCycleTelemetryReturnErrorKey), theError), CAException(kAudioHardwareUnspecifiedError), "CAHALIOCycleTelemetryClient::GetServerIsFlippedFromServer: no error in the return data"); ThrowIfError(theError, CAException(theError), "CAHALIOCycleTelemetryClient::GetServerIsFlippedFromServer: the return data contained an error"); // get the value of the property UInt32 thePropertyValue = 0; ThrowIf(!theReturnData.GetUInt32(CFSTR(kHALIOCycleTelemetryPropertyValueKey), thePropertyValue), CAException(kAudioHardwareUnspecifiedError), "CAHALIOCycleTelemetryClient::GetServerIsFlippedFromServer: no return value in the return data"); #if TARGET_RT_BIG_ENDIAN outServerIsFlipped = thePropertyValue == kHALTelemetryServerIsLittleEndian; #else outServerIsFlipped = thePropertyValue == kHALTelemetryServerIsBigEndian; #endif } } catch(const CAException& inException) { theError = inException.GetError(); } catch(...) { theError = kAudioHardwareUnspecifiedError; } if(theReturnCFData != NULL) { CFRelease(theReturnCFData); } return theError; } OSStatus CAHALIOCycleTelemetryClient::ClearDataOnServer() { UInt32 theError = 0; CFDataRef theReturnCFData = NULL; try { if(mMessagePort != NULL) { // build the request CACFDictionary theMessageData(true); CACFData theMessageCFData(CFPropertyListCreateXMLData(NULL, theMessageData.GetCFDictionary())); // send the request to the HAL theError = mMessagePort->SendRequest(kHALTelemetryMessageClearTelemetry, theMessageCFData.GetCFData(), 10.0, 10.0, kCFRunLoopDefaultMode, theReturnCFData); ThrowIfError(theError, CAException(theError), "CAHALIOCycleTelemetryClient::ClearDataOnServer: sending the request failed"); } } catch(const CAException& inException) { theError = inException.GetError(); } catch(...) { theError = kAudioHardwareUnspecifiedError; } if(theReturnCFData != NULL) { CFRelease(theReturnCFData); } return theError; } static void CAHALIOCycleTelemetryClient_MessagePortIsInvalid(CFMessagePortRef /*inMessagePort*/, void* /*inInfo*/) { } bool CAHALIOCycleTelemetryClient::CanDoLatencyTracing() const { return CALatencyLog::CanUse(); } bool CAHALIOCycleTelemetryClient::IsLatencyTracingEnabled() const { return mLatencyTracingEnabled; } void CAHALIOCycleTelemetryClient::SetIsLatencyTracingEnabled(bool inIsEnabled) { if(inIsEnabled != mLatencyTracingEnabled) { mLatencyTracingEnabled = inIsEnabled; // allocate or deallocate the CALatencyLog as appropriate if(mLatencyTracingEnabled && (mLatencyLog == NULL)) { mLatencyLog = new CALatencyLog(mLatencyTraceFileName, mLatencyTraceFileNameExtension); } else if(!mLatencyTracingEnabled && (mLatencyLog != NULL)) { delete mLatencyLog; mLatencyLog = NULL; } } } Float64 CAHALIOCycleTelemetryClient::GetIOThreadSchedulingLatencyTrigger() const { // this is in milliseconds return mIOThreadSchedulingLatencyTrigger; } void CAHALIOCycleTelemetryClient::SetIOThreadSchedulingLatencyTrigger(Float64 inTrigger) { // this is in milliseconds mIOThreadSchedulingLatencyTrigger = inTrigger; } Float64 CAHALIOCycleTelemetryClient::GetIOCycleDurationTrigger() const { // this is in milliseconds return mIOCycleDurationTrigger; } void CAHALIOCycleTelemetryClient::SetIOCycleDurationTrigger(Float64 inTrigger) { // this is in milliseconds mIOCycleDurationTrigger = inTrigger; } bool CAHALIOCycleTelemetryClient::GetOverloadTrigger() const { return mOverloadTrigger; } void CAHALIOCycleTelemetryClient::SetOverloadTrigger(bool inTrigger) { mOverloadTrigger = inTrigger; }