this repo has no description
at fixPythonPipStalling 461 lines 15 kB view raw
1/* Copyright: � Copyright 2005 Apple Computer, Inc. All rights reserved. 2 3 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. 4 ("Apple") in consideration of your agreement to the following terms, and your 5 use, installation, modification or redistribution of this Apple software 6 constitutes acceptance of these terms. If you do not agree with these terms, 7 please do not use, install, modify or redistribute this Apple software. 8 9 In consideration of your agreement to abide by the following terms, and subject 10 to these terms, Apple grants you a personal, non-exclusive license, under Apple�s 11 copyrights in this original Apple software (the "Apple Software"), to use, 12 reproduce, modify and redistribute the Apple Software, with or without 13 modifications, in source and/or binary forms; provided that if you redistribute 14 the Apple Software in its entirety and without modifications, you must retain 15 this notice and the following text and disclaimers in all such redistributions of 16 the Apple Software. Neither the name, trademarks, service marks or logos of 17 Apple Computer, Inc. may be used to endorse or promote products derived from the 18 Apple Software without specific prior written permission from Apple. Except as 19 expressly stated in this notice, no other rights or licenses, express or implied, 20 are granted by Apple herein, including but not limited to any patent rights that 21 may be infringed by your derivative works or by other works in which the Apple 22 Software may be incorporated. 23 24 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO 25 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 26 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 28 COMBINATION WITH YOUR PRODUCTS. 29 30 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR 31 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 32 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION 34 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT 35 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN 36 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37*/ 38/*============================================================================= 39 auprofile.cpp 40 41=============================================================================*/ 42 43/* 44 auprofile 45 - takes a source audio file, an AU and processes this for performance metrics 46*/ 47 48#include "CAAUProcessor.h" 49#include "CAAudioFile.h" 50#include "CAXException.h" 51#include "CAHostTimeBase.h" 52#include "CAFilePathUtils.h" 53#include "CAAudioFileFormats.h" 54 55#if TARGET_OS_MAC 56 #include <pthread.h> 57 #include <mach/mach.h> 58#endif 59 60#if DEBUG 61 #define VERBOSE 0 62#endif 63 64UInt64 sLastReadTime = 0; 65Float64 sMinTime = 9999999999.; // too big a time! 66Float64 sMaxTime = 0; 67 68#pragma mark __print helpers 69 70void PerfResult(const char *toolname, int group, const char *testname, double value, const char *units, const char *fmt="%.3f") 71{ 72 printf("<result tool='%s' group='%d' test='%s' value='", toolname, group, testname); 73 printf(fmt, value); 74 printf("' units='%s' />\n", units); 75} 76 77#pragma mark __Inpput Callback Definitions 78 79 80// the file is read into memory - the input's role is to parse through this memory 81 82struct ReadBuffer { 83 AUOutputBL *readData; 84 UInt64 totalInputFrames; 85 UInt32 lastInputFrames; 86}; 87 88const int kEndOfInput = 12345; 89 90static OSStatus MemoryInputCallback (void *inRefCon, 91 AudioUnitRenderActionFlags *ioActionFlags, 92 const AudioTimeStamp *inTimeStamp, 93 UInt32 inBusNumber, 94 UInt32 inNumberFrames, 95 AudioBufferList *ioData) 96{ 97 UInt64 now = CAHostTimeBase::GetTheCurrentTime(); 98 OSStatus result = 0; 99 100 ReadBuffer *readBuffer = (ReadBuffer*)inRefCon; 101 if (inTimeStamp->mSampleTime >= readBuffer->totalInputFrames) { 102 #if VERBOSE 103 printf ("reading: %.0f past input: %.0f\n", inTimeStamp->mSampleTime, 104 (double)readBuffer->totalInputFrames); 105 #endif 106 result = kEndOfInput; 107 readBuffer->lastInputFrames = 0; 108 goto end; 109 } 110 111 // can get pulled multiple times 112 readBuffer->lastInputFrames += inNumberFrames; 113 114 if (UInt64(inTimeStamp->mSampleTime + inNumberFrames) > readBuffer->totalInputFrames) { 115 // first set this to zero as we're only going to read a partial number of frames 116 AudioBuffer *buf = ioData->mBuffers; 117 for (UInt32 i = ioData->mNumberBuffers; i--; ++buf) 118 memset((Byte *)buf->mData, 0, buf->mDataByteSize); 119 120 inNumberFrames = UInt32 (readBuffer->totalInputFrames - UInt64(inTimeStamp->mSampleTime)); 121 } 122 123 // copy data from the source to the ioData buffers 124 { 125 AudioBuffer *buf = ioData->mBuffers; 126 AudioBuffer *rBuf = readBuffer->readData->ABL()->mBuffers; 127 for (UInt32 i = ioData->mNumberBuffers; i--; ++buf, ++rBuf) { 128 AudioBuffer readB = *rBuf; 129 readB.mData = static_cast<Float32*>(rBuf->mData) + UInt32(inTimeStamp->mSampleTime); 130 memcpy (buf->mData, readB.mData, (inNumberFrames * sizeof(Float32))); 131 } 132 } 133 134end: 135 sLastReadTime += (CAHostTimeBase::GetTheCurrentTime() - now); 136 137 return result; 138} 139 140#pragma mark __Utility Helpers 141 142CFPropertyListRef ReadPresetFromPresetFile (char* filePath) 143{ 144 if (!filePath) 145 return NULL; 146 147 FSRef ref; 148 if (FSPathMakeRef((UInt8 *)filePath, &ref, NULL)) 149 return NULL; 150 151 CFDataRef resourceData = NULL; 152 CFPropertyListRef theData = NULL; 153 CFStringRef errString = NULL; 154 CFURLRef fileURL = CFURLCreateFromFSRef (kCFAllocatorDefault, &ref); 155 if (fileURL == NULL) { 156 goto home; 157 } 158 159 SInt32 result; 160 161 // Read the XML file. 162 Boolean status; status = CFURLCreateDataAndPropertiesFromResource (kCFAllocatorDefault, fileURL, 163 &resourceData, // place to put file data 164 NULL, NULL, &result); 165 if (status == false || result) { 166 goto home; 167 } 168 169 theData = CFPropertyListCreateFromXMLData (kCFAllocatorDefault, resourceData, 170 kCFPropertyListImmutable, &errString); 171 if (theData == NULL || errString) { 172 if (theData) 173 CFRelease (theData); 174 theData = NULL; 175 goto home; 176 } 177 178home: 179 if (fileURL) 180 CFRelease (fileURL); 181 if (resourceData) 182 CFRelease (resourceData); 183 if (errString) 184 CFRelease (errString); 185 186 return theData; 187} 188 189#pragma mark __the setup code 190 191#define OFFLINE_AU_CMD "[-au TYPE SUBTYPE MANU] The Audio Unit component description\n\t" 192#define INPUT_FILE "[-i /Path/To/File] The file that is to be processed.\n\t" 193#define AU_PRESET_CMD "[-p /Path/To/AUPreset/File] Specify an AU Preset File to establish the state of the AU\n\t" 194#define USE_MAX_FRAMES "[-f max_frames] default is 4096" 195 196static char* usageStr = "Usage: auprofile\n\t" 197 OFFLINE_AU_CMD 198 INPUT_FILE 199 AU_PRESET_CMD 200 USE_MAX_FRAMES; 201 202int main(int argc, const char * argv[]) 203{ 204#if TARGET_OS_MAC 205 { 206 thread_extended_policy_data_t theFixedPolicy; 207 theFixedPolicy.timeshare = false; // set to true for a non-fixed thread 208 thread_policy_set(pthread_mach_thread_np(pthread_self()), 209 THREAD_EXTENDED_POLICY, 210 (thread_policy_t)&theFixedPolicy, 211 THREAD_EXTENDED_POLICY_COUNT); 212 213 // We keep a reference to the spawning thread's priority around (initialized in the constructor), 214 // and set the importance of the child thread relative to the spawning thread's priority. 215 thread_precedence_policy_data_t thePrecedencePolicy; 216 217 thePrecedencePolicy.importance = 63 - 36; 218 thread_policy_set(pthread_mach_thread_np(pthread_self()), 219 THREAD_PRECEDENCE_POLICY, 220 (thread_policy_t)&thePrecedencePolicy, 221 THREAD_PRECEDENCE_POLICY_COUNT); 222 } 223#endif 224 225 226// These are the variables that are set up from the input parsing 227 char* srcFilePath = NULL; 228 char* auPresetFile = NULL; 229 OSType manu, subType, type = 0; 230 UInt32 numFrames = 4096; 231 232 for (int i = 1; i < argc; ++i) 233 { 234 if (strcmp (argv[i], "-au") == 0) { 235 if ( (i + 3) < argc ) { 236 StrToOSType (argv[i + 1], type); 237 StrToOSType (argv[i + 2], subType); 238 StrToOSType (argv[i + 3], manu); 239 i += 3; 240 } else { 241 printf ("Which Audio Unit:\n%s", usageStr); 242 exit(1); 243 } 244 } 245 else if (strcmp (argv[i], "-i") == 0) { 246 srcFilePath = const_cast<char*>(argv[++i]); 247 } 248 else if (strcmp (argv[i], "-p") == 0) { 249 auPresetFile = const_cast<char*>(argv[++i]); 250 } 251 else if (strcmp (argv[i], "-f") == 0) { 252 sscanf(argv[++i], "%ld", &numFrames); 253 } 254 else { 255 printf ("%s\n", usageStr); 256 exit(1); 257 } 258 } 259 260 if (!type || !srcFilePath) { 261 printf ("%s\n", usageStr); 262 exit(1); 263 } 264 265 CAComponentDescription desc(type, subType, manu); 266 267 CFPropertyListRef presetDict = ReadPresetFromPresetFile(auPresetFile); 268 269#pragma mark - 270#pragma mark __ The driving code 271#pragma mark - 272 273 try 274 { 275 CAComponent comp(desc); 276 277 // CAAUProcessor's constructor throws... so make sure the component is valid 278 if (comp.IsValid() == false) { 279 printf ("Can't Find Component\n"); 280 desc.Print(); 281 exit(1); 282 } 283 284 CAAUProcessor processor(comp); 285 processor.AU().Comp().Print(); 286 287 CAAudioFile srcFile; 288 289 srcFile.Open(srcFilePath); 290 291#if !CAAF_USE_EXTAUDIOFILE 292 UInt64 numInputSamples = srcFile.GetNumberPackets(); 293#else 294 UInt64 numInputSamples = srcFile.GetNumberFrames(); 295#endif 296 297 Float64 inputSecs = (numInputSamples / srcFile.GetFileDataFormat().mSampleRate); 298 299 CAStreamBasicDescription procFormat (srcFile.GetFileDataFormat()); 300 procFormat.SetCanonical (srcFile.GetFileDataFormat().NumberChannels(), false); 301 302 printf ("Processing file: %s, %.1f secs [proc: %ld frames]\n", srcFilePath, inputSecs, numFrames); 303 #if VERBOSE 304 printf("\t"); 305 procFormat.Print(); 306 #endif 307 308 srcFile.SetClientFormat (procFormat); 309 310 AUOutputBL outputList(procFormat); 311 312 // read the entire file into memory 313 ReadBuffer* readBuf = new ReadBuffer; 314 readBuf->readData = new AUOutputBL(procFormat); 315 readBuf->totalInputFrames = numInputSamples; 316 readBuf->readData->Allocate (numInputSamples); 317 readBuf->readData->Prepare(); 318 UInt32 readSamps = (UInt32)numInputSamples; 319 srcFile.Read (readSamps, readBuf->readData->ABL()); 320 321 AURenderCallbackStruct inputCallback; 322 inputCallback.inputProc = MemoryInputCallback; 323 inputCallback.inputProcRefCon = readBuf; 324 325 OSStatus result; 326 require_noerr (result = processor.EstablishInputCallback (inputCallback), home); 327 require_noerr (result = processor.SetMaxFramesPerRender (numFrames), home); 328 require_noerr (result = processor.Initialize (procFormat, numInputSamples), home); 329 if (presetDict) { 330 require_noerr (result = processor.SetAUPreset (presetDict), home); 331 CFRelease (presetDict); 332 } 333 // this does ALL of the preflighting.. could be specialise for an OfflineAU type 334 // to do this piecemeal and do a progress bar by using the OfflineAUPreflight method 335 readBuf->lastInputFrames = 0; 336 require_noerr (result = processor.Preflight (), home); 337 338 float mean; 339 340 // now do the processing.... 341 { 342 const int kThrasherSize = 4000000; 343 char* thrasher = new char[kThrasherSize]; 344 345 bool isDone = false; 346 347 UInt32 numMeasures = 0; 348 Float64 totalMSqrd; 349 Float64 totalM; 350 351 int i = 0; 352 int discardResults = 3; 353 354 // this is the render loop 355 while (!isDone) 356 { 357 bool isSilence, postProcess; 358 359 outputList.Prepare(); // have to do this every time... 360 readBuf->lastInputFrames = 0; 361 sLastReadTime = 0; 362 memset (thrasher, numMeasures, kThrasherSize); 363 364 UInt64 now = CAHostTimeBase::GetTheCurrentTime(); 365 require_noerr (result = processor.Render (outputList.ABL(), numFrames, isSilence, &isDone, &postProcess), home); 366 UInt64 renderTime = (CAHostTimeBase::GetTheCurrentTime() - now); 367 368 if (i++ < discardResults) continue; 369 if (!readBuf->lastInputFrames) break; 370 371 Float64 renderTimeSecs = CAHostTimeBase::ConvertToNanos (renderTime - sLastReadTime) / 1.0e9; 372 373 Float64 cpuTime = (renderTimeSecs / (readBuf->lastInputFrames / procFormat.mSampleRate)) * 100.; 374 numMeasures++; 375 376 totalMSqrd += (cpuTime * cpuTime); 377 totalM += cpuTime; 378 379 if (cpuTime > sMaxTime) 380 sMaxTime = cpuTime; 381 if (cpuTime < sMinTime) 382 sMinTime = cpuTime; 383 384#if VERBOSE 385// printf ("current measure: %.2f\n", cpuTime); 386 if (numMeasures % 5 == 0) { 387 Float64 mean = totalM / numMeasures; 388 // stdDev = (sum of Xsquared -((sum of X)*(sum of X)/N)) / (N-1)) 389 Float64 stdDev = sqrt ((totalMSqrd - ((totalM * totalM) / numMeasures)) / (numMeasures-1.0)); 390 printf ("ave: %.2f, min: %.2f, max: %.2f, stdev: %.2f, numMeasures: %ld, current: %f\n", 391 mean, sMinTime, sMaxTime, stdDev, numMeasures, cpuTime); 392 } 393#endif 394 } 395 delete [] thrasher; 396 397 mean = totalM / numMeasures; 398 // stdDev = (sum of Xsquared -((sum of X)*(sum of X)/N)) / (N-1)) 399 Float64 stdDev = sqrt ((totalMSqrd - ((totalM * totalM) / numMeasures)) / (numMeasures-1.0)); 400 401 printf ("ave: %.2f, min: %.2f, max: %.2f, sd: %.2f, sd / mean: %.2f%%\n", 402 mean, sMinTime, sMaxTime, stdDev, (stdDev / mean * 100.)); 403 } 404 405 // we don't care about post-processing 406 407home: 408 if (result) { 409 printf ("Exit with bad result:%ld\n", result); 410 exit(result); 411 } 412 413 if (readBuf) { 414 delete readBuf->readData; 415 delete readBuf; 416 } 417 418 419 CFStringRef str = comp.GetCompName(); 420 UInt32 compNameLen = CFStringGetLength (str); 421 422 CFStringRef presetName = NULL; 423 if (auPresetFile) { 424 CFPropertyListRef dict; 425 if (processor.AU().GetAUPreset (dict) == noErr) { 426 presetName = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)dict, CFSTR("name")); 427 CFRelease (dict); 428 } 429 } 430 431 UInt32 presetLen = presetName ? CFStringGetLength(presetName) : 0; 432 433 UInt32 groupID = comp.Desc().componentSubType; 434 435 char* cstr = (char*)malloc (compNameLen + presetLen + 2 + 1); 436 CFStringGetCString (str, cstr, (CFStringGetLength (str) + 1), kCFStringEncodingASCII); 437 if (presetName) { 438 cstr[compNameLen] = ':'; 439 cstr[compNameLen+1] = ':'; 440 CFStringGetCString (presetName, cstr + compNameLen + 2, (CFStringGetLength (presetName) + 1), kCFStringEncodingASCII); 441 int len = strlen(cstr); 442 for (int i = 0; i < len; ++i) 443 groupID += cstr[i]; 444 } 445 PerfResult("AU Profile", EndianU32_NtoB(groupID), cstr, mean, "%realtime"); 446 free (cstr); 447 448 } 449 catch (CAXException &e) { 450 char buf[256]; 451 printf("Error: %s (%s)\n", e.mOperation, e.FormatError(buf)); 452 exit(1); 453 } 454 catch (...) { 455 printf("An unknown error occurred\n"); 456 exit(1); 457 } 458 459 return 0; 460} 461