From c79a026360eaef3df5557c0c0e86e390a2c0087e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20Dur=C3=A1n?= Date: Wed, 30 Oct 2013 17:33:08 +0100 Subject: [PATCH] [profiler] Add bin/instruments which launches an app in Instruments.app --- .gitignore | 1 + bin/Rakefile | 19 ++++++--- bin/instruments.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 bin/instruments.c diff --git a/.gitignore b/.gitignore index ff24bb60..988d7529 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ bin/nfd bin/ios/deploy bin/ios/sim bin/osx/sim +bin/instruments data/ios data/osx diff --git a/bin/Rakefile b/bin/Rakefile index 718e24bf..0af369c7 100644 --- a/bin/Rakefile +++ b/bin/Rakefile @@ -2,9 +2,10 @@ verbose(true) NEED_STRIP = !ENV['DEBUG'] task :default => :all -task :all => [:files, :deploy, :sim, :nfd] +task :all => [:files, :deploy, :sim, :nfd, :instruments] STRIP = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/strip" +CLANG = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" task :files do bin = 'ruby' @@ -16,7 +17,7 @@ task :deploy do mkdir_p 'ios' bin = 'ios/deploy' if !File.exist?(bin) or File.mtime('deploy.m') > File.mtime(bin) or File.mtime('builtin_debugger_cmds.h') > File.mtime(bin) - sh "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -mmacosx-version-min=10.6 -I./src -std=c99 -Wall -O3 deploy.m -o \"#{bin}\" -framework Foundation -I." + sh "#{CLANG} -mmacosx-version-min=10.6 -I./src -std=c99 -Wall -O3 deploy.m -o \"#{bin}\" -framework Foundation -I." sh "#{STRIP} -x \"#{bin}\"" if NEED_STRIP end end @@ -27,7 +28,7 @@ task :sim do bin = File.join(template, 'sim') if !File.exist?(bin) or File.mtime('sim.m') > File.mtime(bin) or File.mtime('builtin_debugger_cmds.h') > File.mtime(bin) define = "-DSIMULATOR_#{template.upcase}" - sh "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang #{define} -mmacosx-version-min=10.6 -I./src -std=c99 -Wall -O3 sim.m -o \"#{bin}\" -framework Foundation -framework ApplicationServices -framework AppKit -L. -ledit -Wl,-rpath,/usr/lib -I." + sh "#{CLANG} #{define} -mmacosx-version-min=10.6 -I./src -std=c99 -Wall -O3 sim.m -o \"#{bin}\" -framework Foundation -framework ApplicationServices -framework AppKit -L. -ledit -Wl,-rpath,/usr/lib -I." sh "#{STRIP} -x \"#{bin}\"" if NEED_STRIP end end @@ -36,12 +37,20 @@ end task :nfd do bin = 'nfd' if !File.exist?(bin) or File.mtime('nfd.m') > File.mtime(bin) - sh "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -mmacosx-version-min=10.6 -I./src -std=c99 -Wall -O3 nfd.m -o \"#{bin}\" -framework Foundation -I." + sh "#{CLANG} -mmacosx-version-min=10.6 -I./src -std=c99 -Wall -O3 nfd.m -o \"#{bin}\" -framework Foundation -I." sh "#{STRIP} -x \"#{bin}\"" if NEED_STRIP end end +task :instruments do + bin = 'instruments' + src = bin + '.c' + if !File.exist?(bin) or File.mtime(src) > File.mtime(bin) + sh "#{CLANG} -mmacosx-version-min=10.6 -std=c99 -Wall -O3 #{src} -o \"#{bin}\" -framework CoreFoundation -framework ApplicationServices" + end +end + task :clean do - %w{ruby llc ios/deploy ios/sim osx/sim ndf}.each { |path| rm_rf(path) } + %w{ruby llc ios/deploy ios/sim osx/sim ndf instruments}.each { |path| rm_rf(path) } end diff --git a/bin/instruments.c b/bin/instruments.c new file mode 100644 index 00000000..f063f061 --- /dev/null +++ b/bin/instruments.c @@ -0,0 +1,98 @@ +// ### Inspect arguments for -[XRXcodeAnalysisService _launch:WithConfigFile:] +// +// $ gdb -p [Xcode PID] +// (gdb) b _launch:WithConfigFile: +// Breakpoint 1 at 0x1131fad3b +// (gdb) c +// Continuing. +// Breakpoint 1, 0x00000001131fad3b in -[XRXcodeAnalysisService _launch:WithConfigFile:] () +// (gdb) po $rdx +// /Applications/Xcode.app/Contents/Applications/Instruments.app +// (gdb) po $rcx +// /var/folders/bz/4w413_r9207ccmg9n_2whlh40000gn/T/pbxperfconfig.plist +// +// +// +// ### Disassembled pseudo code extracted from IDEInstrumentsService: +// +// function methImpl_XRXcodeAnalysisService__launch_WithConfigFile_ { +// var_72 = rdi; +// var_64 = rsi; +// r15 = *objc_retain; +// rax = [rdx retain]; +// r14 = rax; +// rax = [rcx retain]; +// rbx = rax; +// rax = CFURLCreateWithFileSystemPath(0x0, r14, 0x0, 0x1); +// r15 = rax; +// rax = CFURLCreateWithFileSystemPath(0x0, rbx, 0x0, 0x0); +// r12 = rax; +// [rbx release]; +// var_56 = r12; +// rax = CFArrayCreate(**kCFAllocatorSystemDefault, &var_56, 0x1, *kCFTypeArrayCallBacks); +// var_16 = r15; +// var_24 = rax; +// var_32 = 0x0; +// var_44 = 0x0; +// var_40 = 0x10001; +// rax = LSOpenFromURLSpec(&var_16, 0x0); +// if (rax != 0x0) { +// _DVTAssertionWarningHandler(&var_72, &var_64, "-[XRXcodeAnalysisService _launch:WithConfigFile:]", "/SourceCache/IDEDebugger/IDEDebugger-3528/PlugIns/Instruments/XRXcodeAnalysisService.m", 0x1ab, @"LSOpenFromURLSpec() returned %ld for trying to launch Instruments at path : %@"); +// } +// if (r15 != 0x0) { +// CFRelease(r15); +// } +// if (var_56 != 0x0) { +// CFRelease(rdi); +// } +// if (rbx != 0x0) { +// CFRelease(rbx); +// } +// rax = [r14 release]; +// return rax; +// } +// +// +// +// ### Observations +// +// * iOS Simulator: Instruments.app is responsible for (installing?) launching the built on the simulator. +// * iOS Device: Xcode installs the built on the device and Instruments.app launches it. +// * OS X: Nothing much needs to be done, Instruments.app launches the app. + + +#import +#import + +int main(int argc, char *argv[]) +{ + if (argc != 3) { + printf("Usage: %s path/to/Instruments.app path/to/pbxperfconfig.plist\n", argv[0]); + return -1; + } + + char *instrumentsPath = argv[1]; + char *configPath = argv[2]; + CFURLRef instrumentsURL = CFURLCreateFromFileSystemRepresentation(NULL, (UInt8 *)instrumentsPath, strlen(instrumentsPath), false); + CFURLRef configURL = CFURLCreateFromFileSystemRepresentation(NULL, (UInt8 *)configPath, strlen(configPath), false); + + CFArrayRef itemURLs = CFArrayCreate(NULL, (const void **)&configURL, 1, &kCFTypeArrayCallBacks); + + LSLaunchURLSpec spec; + spec.appURL = instrumentsURL; + spec.itemURLs = itemURLs; + spec.passThruParams = NULL; + spec.launchFlags = 0; + spec.asyncRefCon = NULL; + + OSStatus status = LSOpenFromURLSpec(&spec, NULL); + if (status != 0) { + fprintf(stderr, "Unable to launch Instruments: %d\n", status); + } + + CFRelease(instrumentsURL); + CFRelease(configURL); + CFRelease(itemURLs); + + return status; +}