diff --git a/AGENT.md b/AGENT.md index aa97c452..a49f91f1 100644 --- a/AGENT.md +++ b/AGENT.md @@ -11,7 +11,7 @@ This reference is for AI agents and contributors working inside the AppleTrace r ## Repository Map - `appletrace/` — Core framework sources (`appletrace.xcodeproj`, Objective-C runtime hooks, exported headers). - `loader/` — Loader/packaging project plus `resign.sh` for re-signing the embedded `appletrace.framework`. -- `sample/ManualSectionDemo` and `sample/TraceAllMsgDemo` — Objective-C Xcode samples that show manual instrumentation and automatic `objc_msgSend` tracing. +- `sample/TraceAllMsgDemo` — Objective-C Xcode sample showing both manual instrumentation (`APTBeginSection`) and automatic `objc_msgSend` tracing. - `sample/AppleTraceSwiftDemo` — Swift sample (SwiftUI) that consumes the local SwiftPM package and demonstrates both Swift routes: the `@Traced`/`@TraceAll`/`withSpan` macros and the `AppleTraceAuto` SwiftTrace bridge. Build with `-destination` only (no `-sdk`, which would force the macro plugin onto the wrong SDK). - `springboard/AppleTraceSpringBoard` — Additional loader project for SpringBoard-focused experiments. - `hookzz/` — Legacy embedded HookZz dependency (the current `objc_msgSend` hook uses a direct symbol rebind instead). @@ -27,8 +27,8 @@ This reference is for AI agents and contributors working inside the AppleTrace r - Optional: `python3 -m pip install -r requirements.txt` for local test tooling. - Visualization is browser-based at [ui.perfetto.dev](https://ui.perfetto.dev); nothing to download. 2. **Build instrumentation** - - For manual tracing, open `appletrace/appletrace.xcodeproj`, build the framework, and embed it into your target (see `sample/ManualSectionDemo`). - - For automatic tracing, build the dynamic library (see `sample/TraceAllMsgDemo`). This mode runs on arm64 under LLDB. + - For Objective-C (manual sections and/or the `objc_msgSend` hook), open `appletrace/appletrace.xcodeproj`, build the framework, and embed it into your target (see `sample/TraceAllMsgDemo`). + - For Swift, add the SwiftPM package and use the `@Traced`/`@TraceAll`/`withSpan` macros (see `sample/AppleTraceSwiftDemo`). 3. **Collect data** - Run the instrumented app; trace segments are written to `/Library/appletracedata`. - Pull the folder from the Simulator or device. diff --git a/README.md b/README.md index a0451a73..0b28ff55 100644 --- a/README.md +++ b/README.md @@ -108,16 +108,16 @@ python3 -m pip install -r requirements.txt ### Try the Demo App (fastest way to see a trace) -`sample/ManualSectionDemo` is a self-contained showcase. Open it in Xcode, +`sample/AppleTraceSwiftDemo` is a self-contained showcase. Open it in Xcode, run it on a Simulator (or device), and tap **Generate Trace** — it runs a -curated, multi-threaded workload (app-startup sections, parallel +curated, multi-threaded workload (app-startup spans, parallel `ImageDecoder` / `NetworkClient` / `DatabaseWriter` threads, async download arcs, a 60-frame render loop with live FPS / memory counters) and writes a complete trace. The screen then shows the on-disk trace directory and the exact commands to merge and open it in Perfetto. ```bash -open sample/ManualSectionDemo/ManualSectionDemo.xcodeproj # then Run + tap "Generate Trace" +open sample/AppleTraceSwiftDemo/AppleTraceSwiftDemo.xcodeproj # then Run + tap "Generate Trace" # The app prints the trace directory; merge it and open Perfetto: python3 merge.py -d "" # → trace.json @@ -130,13 +130,12 @@ app container first (Xcode ▸ *Window ▸ Devices and Simulators ▸ Download Container*, or `xcrun devicectl device copy from …`) — the app shows the full command. -Three samples are included: +Two samples are included: | Sample | Language | Shows | |--------|----------|-------| -| `sample/ManualSectionDemo` | Objective-C | Manual `APTBeginSection` sections, counters, async, threads | -| `sample/AppleTraceSwiftDemo` | Swift | `@Traced` / `@TraceAll` / `withSpan` macros **and** the `AppleTraceAuto` SwiftTrace auto-hook | -| `sample/TraceAllMsgDemo` | Objective-C | Automatic `objc_msgSend` hook | +| `sample/AppleTraceSwiftDemo` | Swift | `withSpan` + `@Traced` / `@TraceAll` macros, counters / async, **and** the `AppleTraceAuto` SwiftTrace auto-hook | +| `sample/TraceAllMsgDemo` | Objective-C | Manual `APTBeginSection` sections **and** the automatic `objc_msgSend` hook | The Swift demo consumes the local SwiftPM package, so open it from the repo root (`open sample/AppleTraceSwiftDemo/AppleTraceSwiftDemo.xcodeproj`) and Xcode @@ -233,8 +232,8 @@ xcodebuild -project appletrace/appletrace.xcodeproj -scheme appletrace \ > deliberately fails to compile for arm64e. Build a plain arm64 slice. Embed the resulting `appletrace.framework` into your target (see -`sample/ManualSectionDemo` for manual mode and `sample/TraceAllMsgDemo` for the -auto-hook). For injecting into third-party apps, see the `loader/` project and +`sample/TraceAllMsgDemo` for both manual sections and the auto-hook). For +injecting into third-party apps, see the `loader/` project and run `loader/resign.sh` after swapping in a rebuilt framework. --- @@ -452,8 +451,8 @@ AppleTrace/ │ └── appletrace/src/ # Framework source + objc_msgSend hook ├── loader/ # Dynamic library loader + resign.sh ├── sample/ -│ ├── ManualSectionDemo/ # Manual instrumentation demo -│ └── TraceAllMsgDemo/ # Automatic objc_msgSend hook demo +│ ├── AppleTraceSwiftDemo/ # Swift demo: macros + SwiftTrace auto-hook +│ └── TraceAllMsgDemo/ # Objective-C demo: manual + objc_msgSend hook ├── scripts/ # CLI + smoke/stress test scripts │ └── appletrace_cli.py # Merge + open-in-Perfetto CLI ├── docs/ # Binary format & batching design notes diff --git a/README_CN.md b/README_CN.md index 42a38b4b..b62ffd0c 100644 --- a/README_CN.md +++ b/README_CN.md @@ -103,15 +103,15 @@ python3 -m pip install -r requirements.txt ### 体验 Demo App(最快看到一条 trace) -`sample/ManualSectionDemo` 是一个开箱即用的示例。用 Xcode 打开,在模拟器 +`sample/AppleTraceSwiftDemo` 是一个开箱即用的示例。用 Xcode 打开,在模拟器 (或真机)上运行,点击 **Generate Trace** 按钮——它会跑一段精心设计的多线程 -工作负载(App 启动 section、并行的 `ImageDecoder` / `NetworkClient` / +工作负载(App 启动 span、并行的 `ImageDecoder` / `NetworkClient` / `DatabaseWriter` 线程、async 下载弧、带实时 FPS / 内存 counter 的 60 帧渲染 循环)并写出一条完整的 trace。界面随后会显示磁盘上的 trace 目录,以及合并并在 Perfetto 中打开它的完整命令。 ```bash -open sample/ManualSectionDemo/ManualSectionDemo.xcodeproj # 运行后点击 "Generate Trace" +open sample/AppleTraceSwiftDemo/AppleTraceSwiftDemo.xcodeproj # 运行后点击 "Generate Trace" # App 会显示 trace 目录;合并它并打开 Perfetto: python3 merge.py -d "" # → trace.json @@ -123,13 +123,12 @@ sh go.sh "" Devices and Simulators ▸ Download Container*,或 `xcrun devicectl device copy from …`)——App 内会显示完整命令。 -仓库内含三个示例: +仓库内含两个示例: | 示例 | 语言 | 演示内容 | |------|------|---------| -| `sample/ManualSectionDemo` | Objective-C | 手动 `APTBeginSection`、counter、async、多线程 | -| `sample/AppleTraceSwiftDemo` | Swift | `@Traced` / `@TraceAll` / `withSpan` 宏,**以及** `AppleTraceAuto` 的 SwiftTrace 自动 hook | -| `sample/TraceAllMsgDemo` | Objective-C | 自动 `objc_msgSend` hook | +| `sample/AppleTraceSwiftDemo` | Swift | `withSpan` + `@Traced` / `@TraceAll` 宏、counter / async,**以及** `AppleTraceAuto` 的 SwiftTrace 自动 hook | +| `sample/TraceAllMsgDemo` | Objective-C | 手动 `APTBeginSection` section **以及**自动 `objc_msgSend` hook | Swift demo 依赖本地 SwiftPM 包,从仓库根目录打开 (`open sample/AppleTraceSwiftDemo/AppleTraceSwiftDemo.xcodeproj`),Xcode 会自动 @@ -224,8 +223,8 @@ xcodebuild -project appletrace/appletrace.xcodeproj -scheme appletrace \ > AppleTrace **仅支持 arm64**。arm64e 不在范围内:自动 hook 需要重绑定经过指针认证的 > GOT 表项,因此 hook 源码在 arm64e 下会刻意编译失败。请构建纯 arm64 slice。 -把生成的 `appletrace.framework` 嵌入你的目标(手动模式见 `sample/ManualSectionDemo`, -自动 hook 见 `sample/TraceAllMsgDemo`)。注入第三方 App 见 `loader/` 工程,替换重新 +把生成的 `appletrace.framework` 嵌入你的目标(手动 section 与自动 hook 都见 +`sample/TraceAllMsgDemo`)。注入第三方 App 见 `loader/` 工程,替换重新 构建的 framework 后运行 `loader/resign.sh`。 --- @@ -435,8 +434,8 @@ AppleTrace/ │ └── appletrace/src/ # framework 源码 + objc_msgSend hook ├── loader/ # 动态库 loader + resign.sh ├── sample/ -│ ├── ManualSectionDemo/ # 手动埋点示例 -│ └── TraceAllMsgDemo/ # 自动 objc_msgSend hook 示例 +│ ├── AppleTraceSwiftDemo/ # Swift 示例:宏 + SwiftTrace 自动 hook +│ └── TraceAllMsgDemo/ # OC 示例:手动 + objc_msgSend hook ├── scripts/ # CLI + smoke/压测脚本 │ └── appletrace_cli.py # 合并 + 打开 Perfetto 的 CLI ├── docs/ # 二进制格式与批量写入设计说明 diff --git a/Tutorial/index.html b/Tutorial/index.html index aa77b5b1..088cc3d0 100644 --- a/Tutorial/index.html +++ b/Tutorial/index.html @@ -143,7 +143,7 @@

Swift Package (for Swift, and the cleanest path for new projects)

]

Framework embedding (Objective-C / C / C++)

-

Open appletrace/appletrace.xcodeproj, build the framework, and embed appletrace.framework into your target. See sample/ManualSectionDemo for a working setup.

+

Open appletrace/appletrace.xcodeproj, build the framework, and embed appletrace.framework into your target. See sample/TraceAllMsgDemo for a working setup.

@@ -282,12 +282,11 @@

Binary fragments (optional, smaller & faster)

Demo Apps

-

Three runnable samples, each a complete reference:

+

Two runnable samples, each a complete reference:

- - - + +
SampleLanguageDemonstrates
sample/ManualSectionDemoObjective-CManual sections, counters, async, threads
sample/AppleTraceSwiftDemoSwift@Traced/@TraceAll/withSpan + the AppleTraceAuto hook
sample/TraceAllMsgDemoObjective-CAutomatic objc_msgSend hook
sample/AppleTraceSwiftDemoSwiftwithSpan + @Traced/@TraceAll macros, counters/async, and the AppleTraceAuto hook
sample/TraceAllMsgDemoObjective-CManual APTBeginSection sections and the automatic objc_msgSend hook

Each guided app has a Generate Trace button, shows the trace directory, and prints the exact merge/Perfetto commands. The Swift demo consumes the local package, so open it from the repo so Xcode resolves the products automatically.

diff --git a/Tutorial/zh.html b/Tutorial/zh.html index 454d0875..b6973f25 100644 --- a/Tutorial/zh.html +++ b/Tutorial/zh.html @@ -138,7 +138,7 @@

Swift Package(Swift 项目,也是新项目最干净的方式)

]

嵌入 framework(Objective-C / C / C++)

-

打开 appletrace/appletrace.xcodeproj 构建 framework,把 appletrace.framework 嵌入你的 target。可参考 sample/ManualSectionDemo

+

打开 appletrace/appletrace.xcodeproj 构建 framework,把 appletrace.framework 嵌入你的 target。可参考 sample/TraceAllMsgDemo

@@ -261,9 +261,8 @@

二进制片段(可选,更小更快)

示例 App

- - - + +
示例语言演示
sample/ManualSectionDemoObjective-C手动 section、counter、async、多线程
sample/AppleTraceSwiftDemoSwift@Traced/@TraceAll/withSpan + AppleTraceAuto hook
sample/TraceAllMsgDemoObjective-C自动 objc_msgSend hook
sample/AppleTraceSwiftDemoSwiftwithSpan + @Traced/@TraceAll 宏、counter/async,以及 AppleTraceAuto hook
sample/TraceAllMsgDemoObjective-C手动 APTBeginSection section 与自动 objc_msgSend hook

每个引导式 App 都有 Generate Trace 按钮,显示 trace 目录并打印合并/Perfetto 命令。Swift demo 依赖本地包,请从仓库内打开,让 Xcode 自动解析 product。

diff --git a/sample/ManualSectionDemo/ManualSectionDemo.xcodeproj/project.pbxproj b/sample/ManualSectionDemo/ManualSectionDemo.xcodeproj/project.pbxproj deleted file mode 100644 index 5f62ea64..00000000 --- a/sample/ManualSectionDemo/ManualSectionDemo.xcodeproj/project.pbxproj +++ /dev/null @@ -1,359 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - D17E9A471F72E1860034AAE7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D17E9A461F72E1860034AAE7 /* main.m */; }; - D17E9A4A1F72E1860034AAE7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D17E9A491F72E1860034AAE7 /* AppDelegate.m */; }; - D17E9A4D1F72E1860034AAE7 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D17E9A4C1F72E1860034AAE7 /* ViewController.m */; }; - D17E9A501F72E1860034AAE7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D17E9A4E1F72E1860034AAE7 /* Main.storyboard */; }; - D17E9A521F72E1860034AAE7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D17E9A511F72E1860034AAE7 /* Assets.xcassets */; }; - D17E9A551F72E1860034AAE7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D17E9A531F72E1860034AAE7 /* LaunchScreen.storyboard */; }; - D17E9A5E1F72E1D90034AAE7 /* ThreadTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D17E9A5D1F72E1D90034AAE7 /* ThreadTest.m */; }; - D17E9A6B1F72E51E0034AAE7 /* appletrace.mm in Sources */ = {isa = PBXBuildFile; fileRef = D17E9A6A1F72E51E0034AAE7 /* appletrace.mm */; }; -/* End PBXBuildFile section */ - -/* Begin PBXCopyFilesBuildPhase section */ - D17E9A671F72E2340034AAE7 /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - D17E9A421F72E1860034AAE7 /* ManualSectionDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ManualSectionDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - D17E9A461F72E1860034AAE7 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - D17E9A481F72E1860034AAE7 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - D17E9A491F72E1860034AAE7 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - D17E9A4B1F72E1860034AAE7 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; - D17E9A4C1F72E1860034AAE7 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; - D17E9A4F1F72E1860034AAE7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - D17E9A511F72E1860034AAE7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - D17E9A541F72E1860034AAE7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - D17E9A561F72E1860034AAE7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - D17E9A5C1F72E1D90034AAE7 /* ThreadTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadTest.h; sourceTree = ""; }; - D17E9A5D1F72E1D90034AAE7 /* ThreadTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ThreadTest.m; sourceTree = ""; }; - D17E9A691F72E51E0034AAE7 /* appletrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = appletrace.h; path = ../../../appletrace/appletrace/src/appletrace.h; sourceTree = ""; }; - D17E9A6A1F72E51E0034AAE7 /* appletrace.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = appletrace.mm; path = ../../../appletrace/appletrace/src/appletrace.mm; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - D17E9A3F1F72E1860034AAE7 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - D17E9A391F72E1860034AAE7 = { - isa = PBXGroup; - children = ( - D17E9A441F72E1860034AAE7 /* ManualSectionDemo */, - D17E9A431F72E1860034AAE7 /* Products */, - ); - sourceTree = ""; - }; - D17E9A431F72E1860034AAE7 /* Products */ = { - isa = PBXGroup; - children = ( - D17E9A421F72E1860034AAE7 /* ManualSectionDemo.app */, - ); - name = Products; - sourceTree = ""; - }; - D17E9A441F72E1860034AAE7 /* ManualSectionDemo */ = { - isa = PBXGroup; - children = ( - D17E9A6C1F72E5310034AAE7 /* external */, - D17E9A481F72E1860034AAE7 /* AppDelegate.h */, - D17E9A491F72E1860034AAE7 /* AppDelegate.m */, - D17E9A4B1F72E1860034AAE7 /* ViewController.h */, - D17E9A4C1F72E1860034AAE7 /* ViewController.m */, - D17E9A5C1F72E1D90034AAE7 /* ThreadTest.h */, - D17E9A5D1F72E1D90034AAE7 /* ThreadTest.m */, - D17E9A4E1F72E1860034AAE7 /* Main.storyboard */, - D17E9A511F72E1860034AAE7 /* Assets.xcassets */, - D17E9A531F72E1860034AAE7 /* LaunchScreen.storyboard */, - D17E9A561F72E1860034AAE7 /* Info.plist */, - D17E9A451F72E1860034AAE7 /* Supporting Files */, - ); - path = ManualSectionDemo; - sourceTree = ""; - }; - D17E9A451F72E1860034AAE7 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - D17E9A461F72E1860034AAE7 /* main.m */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - D17E9A6C1F72E5310034AAE7 /* external */ = { - isa = PBXGroup; - children = ( - D17E9A691F72E51E0034AAE7 /* appletrace.h */, - D17E9A6A1F72E51E0034AAE7 /* appletrace.mm */, - ); - name = external; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - D17E9A411F72E1860034AAE7 /* ManualSectionDemo */ = { - isa = PBXNativeTarget; - buildConfigurationList = D17E9A591F72E1860034AAE7 /* Build configuration list for PBXNativeTarget "ManualSectionDemo" */; - buildPhases = ( - D17E9A3E1F72E1860034AAE7 /* Sources */, - D17E9A3F1F72E1860034AAE7 /* Frameworks */, - D17E9A401F72E1860034AAE7 /* Resources */, - D17E9A671F72E2340034AAE7 /* CopyFiles */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ManualSectionDemo; - productName = ManualSectionDemo; - productReference = D17E9A421F72E1860034AAE7 /* ManualSectionDemo.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - D17E9A3A1F72E1860034AAE7 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0830; - ORGANIZATIONNAME = everettjf; - TargetAttributes = { - D17E9A411F72E1860034AAE7 = { - CreatedOnToolsVersion = 8.3; - DevelopmentTeam = YPV49M8592; - ProvisioningStyle = Automatic; - }; - }; - }; - buildConfigurationList = D17E9A3D1F72E1860034AAE7 /* Build configuration list for PBXProject "ManualSectionDemo" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = D17E9A391F72E1860034AAE7; - productRefGroup = D17E9A431F72E1860034AAE7 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - D17E9A411F72E1860034AAE7 /* ManualSectionDemo */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - D17E9A401F72E1860034AAE7 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - D17E9A551F72E1860034AAE7 /* LaunchScreen.storyboard in Resources */, - D17E9A521F72E1860034AAE7 /* Assets.xcassets in Resources */, - D17E9A501F72E1860034AAE7 /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - D17E9A3E1F72E1860034AAE7 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - D17E9A4D1F72E1860034AAE7 /* ViewController.m in Sources */, - D17E9A6B1F72E51E0034AAE7 /* appletrace.mm in Sources */, - D17E9A4A1F72E1860034AAE7 /* AppDelegate.m in Sources */, - D17E9A471F72E1860034AAE7 /* main.m in Sources */, - D17E9A5E1F72E1D90034AAE7 /* ThreadTest.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - D17E9A4E1F72E1860034AAE7 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - D17E9A4F1F72E1860034AAE7 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - D17E9A531F72E1860034AAE7 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - D17E9A541F72E1860034AAE7 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - D17E9A571F72E1860034AAE7 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - D17E9A581F72E1860034AAE7 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - D17E9A5A1F72E1860034AAE7 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = YPV49M8592; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = ManualSectionDemo/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.everettjf.ManualSectionDemo; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - D17E9A5B1F72E1860034AAE7 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - DEVELOPMENT_TEAM = YPV49M8592; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = ManualSectionDemo/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = com.everettjf.ManualSectionDemo; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - D17E9A3D1F72E1860034AAE7 /* Build configuration list for PBXProject "ManualSectionDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - D17E9A571F72E1860034AAE7 /* Debug */, - D17E9A581F72E1860034AAE7 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - D17E9A591F72E1860034AAE7 /* Build configuration list for PBXNativeTarget "ManualSectionDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - D17E9A5A1F72E1860034AAE7 /* Debug */, - D17E9A5B1F72E1860034AAE7 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = D17E9A3A1F72E1860034AAE7 /* Project object */; -} diff --git a/sample/ManualSectionDemo/ManualSectionDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/sample/ManualSectionDemo/ManualSectionDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index bb38b13b..00000000 --- a/sample/ManualSectionDemo/ManualSectionDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/sample/ManualSectionDemo/ManualSectionDemo/AppDelegate.h b/sample/ManualSectionDemo/ManualSectionDemo/AppDelegate.h deleted file mode 100644 index 13a1a6d5..00000000 --- a/sample/ManualSectionDemo/ManualSectionDemo/AppDelegate.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// AppDelegate.h -// ManualSectionDemo -// -// Created by everettjf on 21/09/2017. -// Copyright © 2017 everettjf. All rights reserved. -// - -#import - -@interface AppDelegate : UIResponder - -@property (strong, nonatomic) UIWindow *window; - - -@end - diff --git a/sample/ManualSectionDemo/ManualSectionDemo/AppDelegate.m b/sample/ManualSectionDemo/ManualSectionDemo/AppDelegate.m deleted file mode 100644 index dac8ff1f..00000000 --- a/sample/ManualSectionDemo/ManualSectionDemo/AppDelegate.m +++ /dev/null @@ -1,37 +0,0 @@ -// -// AppDelegate.m -// ManualSectionDemo -// -// Created by everettjf on 21/09/2017. -// Copyright © 2017 everettjf. All rights reserved. -// - -#import "AppDelegate.h" -#import "appletrace.h" - -@interface AppDelegate () - -@end - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - NSLog(@"AppleTrace trace directory: %s", APTGetTraceDirectory()); - // The actual showcase workload lives in ViewController (tap "Generate - // Trace"). Mark launch so the very first slice in the timeline is obvious. - APTInstant("app_did_launch"); - return YES; -} - -- (void)applicationDidEnterBackground:(UIApplication *)application { - // The trace writer batches events per thread and ships them on a size - // threshold, on APTFlush(), or at thread exit (docs/perf-batching-design.md). - // Flush here so a trace is always on disk when the app is backgrounded. - APTFlush(); -} - -- (void)applicationWillTerminate:(UIApplication *)application { - APTFlush(); -} - -@end diff --git a/sample/ManualSectionDemo/ManualSectionDemo/Assets.xcassets/AppIcon.appiconset/Contents.json b/sample/ManualSectionDemo/ManualSectionDemo/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 36d2c80d..00000000 --- a/sample/ManualSectionDemo/ManualSectionDemo/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "29x29", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "40x40", - "scale" : "3x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "2x" - }, - { - "idiom" : "iphone", - "size" : "60x60", - "scale" : "3x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "29x29", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "40x40", - "scale" : "2x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "1x" - }, - { - "idiom" : "ipad", - "size" : "76x76", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/sample/ManualSectionDemo/ManualSectionDemo/Base.lproj/LaunchScreen.storyboard b/sample/ManualSectionDemo/ManualSectionDemo/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index fdf3f97d..00000000 --- a/sample/ManualSectionDemo/ManualSectionDemo/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sample/ManualSectionDemo/ManualSectionDemo/Base.lproj/Main.storyboard b/sample/ManualSectionDemo/ManualSectionDemo/Base.lproj/Main.storyboard deleted file mode 100644 index 4529698c..00000000 --- a/sample/ManualSectionDemo/ManualSectionDemo/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sample/ManualSectionDemo/ManualSectionDemo/Info.plist b/sample/ManualSectionDemo/ManualSectionDemo/Info.plist deleted file mode 100644 index d0524738..00000000 --- a/sample/ManualSectionDemo/ManualSectionDemo/Info.plist +++ /dev/null @@ -1,45 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/sample/ManualSectionDemo/ManualSectionDemo/ThreadTest.h b/sample/ManualSectionDemo/ManualSectionDemo/ThreadTest.h deleted file mode 100644 index 639077d5..00000000 --- a/sample/ManualSectionDemo/ManualSectionDemo/ThreadTest.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// ThreadTest.h -// ManualSectionDemo -// -// Created by everettjf on 2017/9/19. -// Copyright © 2017年 everettjf. All rights reserved. -// - -#import - -@interface ThreadTest : NSObject - -- (void)go; - -@end diff --git a/sample/ManualSectionDemo/ManualSectionDemo/ThreadTest.m b/sample/ManualSectionDemo/ManualSectionDemo/ThreadTest.m deleted file mode 100644 index b9eb0d2f..00000000 --- a/sample/ManualSectionDemo/ManualSectionDemo/ThreadTest.m +++ /dev/null @@ -1,43 +0,0 @@ -// -// ThreadTest.m -// ManualSectionDemo -// -// Created by everettjf on 2017/9/19. -// Copyright © 2017年 everettjf. All rights reserved. -// - -#import "ThreadTest.h" -#import "appletrace.h" - -@implementation ThreadTest - -- (void)go{ - APTBegin; - usleep(20); - - [self goOne]; - - APTEnd; -} - -- (void)goOne{ - APTBegin; - [self goTwo]; - APTEnd; -} - -- (void)goTwo{ - APTBegin; - for(int i=0;i<10;i++){ - [self goLoop]; - } - APTEnd; -} - -- (void)goLoop{ - APTBegin; - usleep(20); - APTEnd; -} - -@end diff --git a/sample/ManualSectionDemo/ManualSectionDemo/ViewController.h b/sample/ManualSectionDemo/ManualSectionDemo/ViewController.h deleted file mode 100644 index 5911214a..00000000 --- a/sample/ManualSectionDemo/ManualSectionDemo/ViewController.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// ViewController.h -// ManualSectionDemo -// -// Created by everettjf on 21/09/2017. -// Copyright © 2017 everettjf. All rights reserved. -// - -#import - -@interface ViewController : UIViewController - - -@end - diff --git a/sample/ManualSectionDemo/ManualSectionDemo/ViewController.m b/sample/ManualSectionDemo/ManualSectionDemo/ViewController.m deleted file mode 100644 index b7eb8b48..00000000 --- a/sample/ManualSectionDemo/ManualSectionDemo/ViewController.m +++ /dev/null @@ -1,341 +0,0 @@ -// -// ViewController.m -// ManualSectionDemo -// -// Created by everettjf on 21/09/2017. -// Copyright © 2017 everettjf. All rights reserved. -// -// This view controller is the whole demo: tap "Generate Trace" to run a -// curated, multi-threaded workload that emits a rich AppleTrace timeline -// (nested sections, named worker threads, async flows, counters, instants), -// then follow the on-screen steps to merge and open it in Perfetto. - -#import "ViewController.h" -#import "appletrace.h" - -#import -#import -#import -#import - -#pragma mark - Trace workload - -// Thin wrappers that also count how many trace events the showcase emitted so -// the UI can report a number. Counting is atomic because the workload runs -// across several threads at once. -static atomic_uint gShowcaseEvents; - -static inline void TBegin(const char *name) { APTBeginSection(name); atomic_fetch_add(&gShowcaseEvents, 1); } -static inline void TEnd(const char *name) { APTEndSection(name); atomic_fetch_add(&gShowcaseEvents, 1); } -static inline void TInstant(const char *name) { APTInstant(name); atomic_fetch_add(&gShowcaseEvents, 1); } -static inline void TCounter(const char *name, double v) { APTCounter(name, v); atomic_fetch_add(&gShowcaseEvents, 1); } -static inline void TAsyncBegin(const char *name, uint64_t i) { APTAsyncBegin(name, i); atomic_fetch_add(&gShowcaseEvents, 1); } -static inline void TAsyncEnd(const char *name, uint64_t i) { APTAsyncEnd(name, i); atomic_fetch_add(&gShowcaseEvents, 1); } -static inline void TSleepMs(double ms) { usleep((useconds_t)(ms * 1000.0)); } - -static void *APTThreadTrampoline(void *ctx) { - void (^block)(void) = (__bridge_transfer void (^)(void))ctx; - block(); - return NULL; -} - -// Spawns a named pthread running `block`. The name shows up as the track name -// in Perfetto, which is what makes the timeline readable. -static pthread_t APTSpawnNamed(void (^block)(void)) { - pthread_t thread = NULL; - pthread_create(&thread, NULL, APTThreadTrampoline, (__bridge_retained void *)[block copy]); - return thread; -} - -// Runs the whole showcase and flushes. Returns the number of events emitted. -static NSUInteger APTGenerateShowcase(void) { - atomic_store(&gShowcaseEvents, 0); - pthread_setname_np("Showcase"); - - TInstant("scenario_start"); - - // Phase 1 — a believable app startup on the coordinator thread. - TBegin("App Launch"); - { - TBegin("Load Configuration"); - TSleepMs(8); - TCounter("Config Keys", 142); - TEnd("Load Configuration"); - - TBegin("Build View Hierarchy"); - { - TBegin("Inflate Storyboard"); TSleepMs(6); TEnd("Inflate Storyboard"); - TBegin("Apply Theme"); TSleepMs(4); TEnd("Apply Theme"); - } - TEnd("Build View Hierarchy"); - - TBegin("Warm Image Cache"); TSleepMs(5); TEnd("Warm Image Cache"); - } - TEnd("App Launch"); - TInstant("first_frame_ready"); - - // Phase 2 — three named workers run in parallel, so Perfetto shows three - // separate tracks with overlapping slices plus async download arcs. - pthread_t imageThread = APTSpawnNamed(^{ - pthread_setname_np("ImageDecoder"); - for (int i = 1; i <= 8; i++) { - char name[64]; - snprintf(name, sizeof(name), "Decode image #%d", i); - TBegin(name); - { - TBegin("Read bytes"); TSleepMs(2 + (i % 3)); TEnd("Read bytes"); - TBegin("Resize"); TSleepMs(3); TEnd("Resize"); - } - TEnd(name); - TCounter("Images Decoded", i); - } - }); - - pthread_t networkThread = APTSpawnNamed(^{ - pthread_setname_np("NetworkClient"); - TAsyncBegin("GET /feed.json", 1001); - { - TBegin("TLS Handshake"); TSleepMs(10); TEnd("TLS Handshake"); - - TAsyncBegin("GET /avatar.png", 1002); - TBegin("Download Body"); - TSleepMs(14); - TCounter("Bytes Received", 48 * 1024); - TEnd("Download Body"); - - TBegin("Parse JSON"); TSleepMs(6); TEnd("Parse JSON"); - TAsyncEnd("GET /avatar.png", 1002); - } - TAsyncEnd("GET /feed.json", 1001); - }); - - pthread_t dbThread = APTSpawnNamed(^{ - pthread_setname_np("DatabaseWriter"); - for (int b = 1; b <= 5; b++) { - char name[64]; - snprintf(name, sizeof(name), "Write batch #%d", b); - TBegin(name); - TSleepMs(4); - TCounter("Rows Written", b * 40); - TEnd(name); - } - }); - - pthread_join(imageThread, NULL); - pthread_join(networkThread, NULL); - pthread_join(dbThread, NULL); - - // Phase 3 — a 60-frame render loop with per-frame nested work and live - // FPS / memory counters that wobble, which draws nicely as graph tracks. - pthread_t renderThread = APTSpawnNamed(^{ - pthread_setname_np("RenderLoop"); - double memoryMB = 82.0; - for (int frame = 0; frame < 60; frame++) { - TBegin("Frame"); - { - TBegin("Handle Input"); TSleepMs(0.4); TEnd("Handle Input"); - TBegin("Layout"); TSleepMs(0.8); TEnd("Layout"); - TBegin("Tick Animations"); TSleepMs(0.5); TEnd("Tick Animations"); - TBegin("Draw"); TSleepMs(1.2); TEnd("Draw"); - TBegin("Composite"); TSleepMs(0.6); TEnd("Composite"); - } - TEnd("Frame"); - - double fps = 60.0; - if (frame % 7 == 0) fps -= 4.0; // occasional hitch - else if (frame % 3 == 0) fps -= 1.5; - TCounter("FPS", fps); - - memoryMB += (frame % 10 == 0) ? 6.0 : 0.6; - if (frame % 17 == 0) memoryMB -= 4.0; // a GC-like dip - TCounter("Memory (MB)", memoryMB); - - if (frame == 0) TInstant("first_rendered_frame"); - if (frame == 30) TInstant("user_scrolled"); - } - }); - pthread_join(renderThread, NULL); - - TInstant("scenario_complete"); - - // Required: the writer batches per thread, so flush before the trace is - // read off the device / simulator (docs/perf-batching-design.md). - APTFlush(); - - return atomic_load(&gShowcaseEvents); -} - -#pragma mark - View controller - -@interface ViewController () -@property (nonatomic, strong) UIButton *generateButton; -@property (nonatomic, strong) UILabel *statusLabel; -@property (nonatomic, strong) UITextView *pathView; -@end - -@implementation ViewController - -- (void)viewDidLoad { - [super viewDidLoad]; - self.view.backgroundColor = [UIColor colorWithWhite:0.97 alpha:1.0]; - [self buildUI]; -} - -- (void)viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - // Convenience for automation (smoke tests / CI): if APPLETRACE_AUTORUN is - // set, run the showcase once without a tap. Normal use is the button. - static BOOL autoran = NO; - if (!autoran && [[[NSProcessInfo processInfo] environment][@"APPLETRACE_AUTORUN"] boolValue]) { - autoran = YES; - [self generateTapped]; - } -} - -- (void)buildUI { - UIScrollView *scrollView = [[UIScrollView alloc] init]; - scrollView.translatesAutoresizingMaskIntoConstraints = NO; - [self.view addSubview:scrollView]; - - UIStackView *stack = [[UIStackView alloc] init]; - stack.axis = UILayoutConstraintAxisVertical; - stack.spacing = 16.0; - stack.translatesAutoresizingMaskIntoConstraints = NO; - [scrollView addSubview:stack]; - - UILayoutGuide *safe = self.view.safeAreaLayoutGuide; - const CGFloat inset = 20.0; - [NSLayoutConstraint activateConstraints:@[ - [scrollView.topAnchor constraintEqualToAnchor:safe.topAnchor], - [scrollView.leadingAnchor constraintEqualToAnchor:safe.leadingAnchor], - [scrollView.trailingAnchor constraintEqualToAnchor:safe.trailingAnchor], - [scrollView.bottomAnchor constraintEqualToAnchor:safe.bottomAnchor], - - [stack.topAnchor constraintEqualToAnchor:scrollView.contentLayoutGuide.topAnchor constant:inset], - [stack.bottomAnchor constraintEqualToAnchor:scrollView.contentLayoutGuide.bottomAnchor constant:-inset], - [stack.leadingAnchor constraintEqualToAnchor:scrollView.contentLayoutGuide.leadingAnchor constant:inset], - [stack.trailingAnchor constraintEqualToAnchor:scrollView.contentLayoutGuide.trailingAnchor constant:-inset], - [stack.widthAnchor constraintEqualToAnchor:scrollView.frameLayoutGuide.widthAnchor constant:-2 * inset], - ]]; - - // Title + subtitle. - UILabel *title = [self labelWithText:@"AppleTrace \U0001F34E" - font:[UIFont boldSystemFontOfSize:32.0] - color:[UIColor colorWithWhite:0.1 alpha:1.0]]; - UILabel *subtitle = [self labelWithText:@"Tap below to generate a sample Perfetto trace, then follow the steps on your Mac." - font:[UIFont systemFontOfSize:16.0] - color:[UIColor colorWithWhite:0.4 alpha:1.0]]; - [stack addArrangedSubview:title]; - [stack addArrangedSubview:subtitle]; - - // Generate button. - UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; - button.translatesAutoresizingMaskIntoConstraints = NO; - [button setTitle:@"▶︎ Generate Trace" forState:UIControlStateNormal]; - [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; - button.titleLabel.font = [UIFont boldSystemFontOfSize:18.0]; - button.backgroundColor = [UIColor systemBlueColor]; - button.layer.cornerRadius = 12.0; - [button addTarget:self action:@selector(generateTapped) forControlEvents:UIControlEventTouchUpInside]; - [button.heightAnchor constraintEqualToConstant:52.0].active = YES; - [stack addArrangedSubview:button]; - self.generateButton = button; - - // Status line. - self.statusLabel = [self labelWithText:@"Ready." - font:[UIFont systemFontOfSize:15.0] - color:[UIColor colorWithWhite:0.3 alpha:1.0]]; - [stack addArrangedSubview:self.statusLabel]; - - // Trace directory card (selectable so you can copy it). - [stack addArrangedSubview:[self sectionHeader:@"Trace directory on this build"]]; - self.pathView = [self monospaceCardWithText:[NSString stringWithUTF8String:APTGetTraceDirectory()]]; - [stack addArrangedSubview:self.pathView]; - - // Step-by-step guidance back on macOS. - [stack addArrangedSubview:[self sectionHeader:@"Next steps on your Mac"]]; - [stack addArrangedSubview:[self monospaceCardWithText:[self guidanceText]]]; -} - -- (UILabel *)labelWithText:(NSString *)text font:(UIFont *)font color:(UIColor *)color { - UILabel *label = [[UILabel alloc] init]; - label.numberOfLines = 0; - label.text = text; - label.font = font; - label.textColor = color; - label.translatesAutoresizingMaskIntoConstraints = NO; - return label; -} - -- (UILabel *)sectionHeader:(NSString *)text { - return [self labelWithText:text - font:[UIFont boldSystemFontOfSize:17.0] - color:[UIColor colorWithWhite:0.1 alpha:1.0]]; -} - -- (UITextView *)monospaceCardWithText:(NSString *)text { - UITextView *view = [[UITextView alloc] init]; - view.translatesAutoresizingMaskIntoConstraints = NO; - view.editable = NO; - view.scrollEnabled = NO; - view.font = [UIFont fontWithName:@"Menlo" size:12.0]; - view.textColor = [UIColor colorWithWhite:0.15 alpha:1.0]; - view.backgroundColor = [UIColor whiteColor]; - view.layer.cornerRadius = 8.0; - view.layer.borderWidth = 1.0; - view.layer.borderColor = [UIColor colorWithWhite:0.85 alpha:1.0].CGColor; - view.textContainerInset = UIEdgeInsetsMake(10, 8, 10, 8); - view.text = text; - return view; -} - -- (NSString *)guidanceText { - NSString *dir = [NSString stringWithUTF8String:APTGetTraceDirectory()]; -#if TARGET_OS_SIMULATOR - return [NSString stringWithFormat: - @"Running in the Simulator, so the trace is already on this Mac.\n\n" - @"1. Tap “Generate Trace” above.\n\n" - @"2. In the AppleTrace repo, merge the fragments:\n" - @" python3 merge.py -d \"%@\"\n" - @" (or: sh go.sh \"%@\" )\n\n" - @"3. Open https://ui.perfetto.dev and drag in:\n" - @" %@/trace.json\n\n" - @"Tip: set APPLETRACE_BINARY=1 in the scheme’s environment to try\n" - @"the compact binary fragment format — merge.py handles both.", - dir, dir, dir]; -#else - return - @"Running on a device, so copy the trace to your Mac first.\n\n" - @"1. Tap “Generate Trace” above.\n\n" - @"2. Pull the app’s container, either:\n" - @" • Xcode ▸ Window ▸ Devices and Simulators ▸\n" - @" select this app ▸ ⚙ ▸ Download Container, or\n" - @" • xcrun devicectl device copy from --device \\\n" - @" --domain-type appDataContainer \\\n" - @" --domain-identifier com.everettjf.ManualSectionDemo \\\n" - @" --source Library/appletracedata --destination ./trace\n\n" - @"3. Merge and open in Perfetto:\n" - @" python3 merge.py -d /Library/appletracedata\n" - @" then drag trace.json into https://ui.perfetto.dev"; -#endif -} - -- (void)generateTapped { - self.generateButton.enabled = NO; - self.statusLabel.textColor = [UIColor colorWithWhite:0.3 alpha:1.0]; - self.statusLabel.text = @"Generating trace…"; - - dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{ - NSUInteger events = APTGenerateShowcase(); - dispatch_async(dispatch_get_main_queue(), ^{ - self.generateButton.enabled = YES; - self.statusLabel.textColor = [UIColor colorWithRed:0.13 green:0.55 blue:0.13 alpha:1.0]; - self.statusLabel.text = [NSString stringWithFormat: - @"✅ Captured %lu trace events across 5 threads. Now follow the steps below.", - (unsigned long)events]; - self.pathView.text = [NSString stringWithUTF8String:APTGetTraceDirectory()]; - }); - }); -} - -@end diff --git a/sample/ManualSectionDemo/ManualSectionDemo/main.m b/sample/ManualSectionDemo/ManualSectionDemo/main.m deleted file mode 100644 index 3d61115f..00000000 --- a/sample/ManualSectionDemo/ManualSectionDemo/main.m +++ /dev/null @@ -1,16 +0,0 @@ -// -// main.m -// ManualSectionDemo -// -// Created by everettjf on 21/09/2017. -// Copyright © 2017 everettjf. All rights reserved. -// - -#import -#import "AppDelegate.h" - -int main(int argc, char * argv[]) { - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -}