|  | # Setup Xcode for GPU Frame Capture | 
|  |  | 
|  | Xcode needs to be able to attach to a process to be able to instrument and | 
|  | profile it. | 
|  |  | 
|  | As you are working on Impeller, it is easiest to set up an Xcode project just to | 
|  | bring Impeller artifacts up-to-date, launch the required test binary, enable | 
|  | Metal validation layer, and either capture a GPU frame or instrument the test | 
|  | case with Instruments. | 
|  |  | 
|  | If you are already somewhat familiar with Xcode, none of this is new. If not, | 
|  | follow along. | 
|  |  | 
|  | # Set Up an Xcode Project for Instrumentation | 
|  |  | 
|  | In Xcode, `File -> New -> Project…`, select an empty project. | 
|  |  | 
|  |  | 
|  |  | 
|  | Call it whatever you want, you are not going to check this into version control | 
|  | and the targets are going to be specific to your workflow. | 
|  |  | 
|  |  | 
|  |  | 
|  | Save it outside the source tree. Since you are not going to check this in, you | 
|  | don’t want to accidentally delete it via a `git clean -fdx` when regenerating | 
|  | the licenses (ask me how I know). | 
|  |  | 
|  | Create a new `External Build System` target in the empty project by clicking on | 
|  | the `+` icon at the bottom. | 
|  |  | 
|  |  | 
|  |  | 
|  | Click through the defaults (it wants you to use `make`) to create the target, we | 
|  | are going to be modifying it later. | 
|  |  | 
|  |  | 
|  |  | 
|  | Select the target you just created from the sidebar and in the `Info` tab, fill | 
|  | in the command you would use to bring the target up-to-date. In the example, I | 
|  | am building the Impeller unit-tests. | 
|  |  | 
|  |  | 
|  |  | 
|  | If you wanted to instrument multiple targets and switch between them, you would | 
|  | add them here. | 
|  |  | 
|  | Xcode still doesn’t know how to launch the executables generated by the targets | 
|  | however. You need to specify a Run Scheme for that. We’ll do that next. | 
|  |  | 
|  | Click the default scheme for the target. | 
|  |  | 
|  |  | 
|  |  | 
|  | In the Pop-Up, click `Edit Scheme`. | 
|  |  | 
|  |  | 
|  |  | 
|  | In the Info tab, select the executable you want to launch after the target has | 
|  | been updated by clicking on `Other…`. | 
|  |  | 
|  |  | 
|  |  | 
|  | I want to launch the unit-tests harness. Select it in the `out` directory. | 
|  |  | 
|  |  | 
|  |  | 
|  | Now, when you click `Product -> Run` in Xcode, the unit-tests target will be | 
|  | brought up to data and run. | 
|  |  | 
|  | # Enabling Metal Validation & GPU Frame Capture | 
|  |  | 
|  | Xcode doesn’t know that the executable you are trying to instrument is Metal | 
|  | enabled. You just asked it to launch a random executable it knows nothing about. | 
|  |  | 
|  | In the `Options` tab on the `Edit Scheme…` pop-up, in the `GPU Frame Capture` | 
|  | section, set API detection to `Metal` and check `Profile GPU trace after | 
|  | capture`. | 
|  |  | 
|  |  | 
|  |  | 
|  | Then, in the `Diagnostics` tab on the `Edit Scheme…` pop-up, in the `Metal` | 
|  | section, enable `API Validation` and `Shader Validation`. | 
|  |  | 
|  |  | 
|  |  | 
|  | On a side note, you may be tempted to enable all the other diagnostics. Be aware | 
|  | that some of those diagnostics need Xcode to be able to re-compile the | 
|  | translation units in the engine. But, it doesn’t know how to do that, only | 
|  | GN/Ninja does. So some of those will be unavailable. | 
|  |  | 
|  | Any Impeller test that sets up a Playground will now automatically have GPU | 
|  | frame capture enabled. | 
|  |  | 
|  | # Select the Playground Enabled Test to Profile | 
|  |  | 
|  | Tests that launch Playground instances are just Google Test cases. You just need | 
|  | to [pass the right Google Test | 
|  | flags](https://google.github.io/googletest/advanced.html#running-a-subset-of-the-tests) | 
|  | to the running executable as command line arguments. | 
|  |  | 
|  | To do this, in the `Options` tab on the `Edit Scheme…` pop-up, in the `Arguments | 
|  | Passed on Launch` section, add the right `--gtest_filter=` to launch, and | 
|  | instrument just the one test you want. | 
|  |  | 
|  | You also need to set the `--enable_playground` flag in order to do frame capturing. | 
|  |  | 
|  |  | 
|  |  | 
|  | This is also the spot where you will add other command line arguments that will | 
|  | aid in your debugging. In that example, `–timeout=-1` will disable the Flutter | 
|  | test hang watchdog which will kill your process if the test doesn’t complete in | 
|  | 30 seconds. I also like to set the observatory port to a known value so I can | 
|  | get to it and disable service auth codes so I can just refresh the page to | 
|  | launch the latest version of the observatory. |