hz-simpleperf-debug

$npx mdskill add meta-quest/agentic-tools/hz-simpleperf-debug

Profiles CPU performance on Meta Quest devices using simpleperf.

  • Diagnoses whether an app is CPU-bound, memory-bound, or I/O-bound.
  • Depends on Bash tools for Meta VR and hzdb environments.
  • Uses hardware PMU counters to identify hotspots and kernel overhead.
  • Outputs hotspot functions and performance counter data for analysis.

SKILL.md

.github/skills/hz-simpleperf-debugView on GitHub ↗
---
name: hz-simpleperf-debug
license: Apache-2.0
description: Profiles Meta Quest and Horizon OS application CPU performance using simpleperf — workload classification, CPU hotspot recording, kernel overhead measurement. Use when diagnosing whether an app is CPU-bound, memory-bound, or I/O-bound on Quest devices.
allowed-tools: Bash(metavr:*) Bash(hzdb:*)
---

# Simpleperf Debug Skill

## When to Use

Use this skill when you need hardware-level CPU performance insights on Meta Quest devices:

- Classifying whether an app is CPU-bound, memory-bound, or I/O-bound
- Finding CPU hotspot functions consuming the most cycles
- Measuring kernel vs userspace CPU overhead per thread
- Identifying cache-thrashing or branch-prediction issues
- Supplementing Perfetto trace analysis with hardware PMU counter data

This skill complements `hz-perfetto-debug`. Perfetto shows *what* your app is doing over time. Simpleperf shows *where* the CPU is spending hardware cycles — cache misses, branch mispredictions, and instruction throughput that Perfetto can't see.

## VR Performance Context

Quest devices run on mobile ARM SoCs with strict thermal and power budgets. CPU-bound apps hit frame drops when:

| Refresh Rate | CPU Frame Budget | Notes |
|-------------|-----------------|-------|
| 120 Hz | 8.3 ms | Tight — simpleperf critical for finding hotspots |
| 90 Hz | 11.1 ms | Default target for most apps |
| 72 Hz | 13.9 ms | Fallback for heavier apps |

Simpleperf's hardware counters reveal bottlenecks invisible to software tracing.

## metavr Setup

Simpleperf profiling is powered by the metavr CLI. Invoke via `npx` — no install required:

```bash
npx -y metavr --version
```

Examples below use the bare `metavr` command for brevity. If `metavr` is not on PATH, invoke the same CLI via `npx -y metavr <args>` (the CLI is published under the npm package `metavr`). Connect your Quest via USB with developer mode enabled.

## Quick Start Workflow

### 1. Classify the Workload

Before optimizing, determine the bottleneck type:

```bash
# Classify the foreground app's workload (10-second sample)
metavr perf simpleperf classify

# Target a specific app
metavr perf simpleperf classify --app com.example.myapp

# Custom duration
metavr perf simpleperf classify --duration 15
```

Returns a classification with evidence:

| Classification | Indicator | Optimization Strategy |
|---------------|-----------|----------------------|
| **CPU-bound** | High IPC, low stall ratio | Optimize algorithms, reduce draw calls, batch work |
| **Memory-bound** | High stall ratio (stalled-cycles-backend / cpu-cycles) | Reduce cache misses, improve data locality, shrink working set |
| **I/O-bound** | High context switches per second | Reduce blocking I/O, use async, minimize thread contention |

### 2. Record CPU Hotspots

Capture a CPU cycle profile to find the most expensive functions:

```bash
# Record CPU hotspots for the foreground app
metavr perf simpleperf record

# Custom frequency and duration
metavr perf simpleperf record --frequency 4000 --duration 10

# Target a specific app
metavr perf simpleperf record --app com.example.myapp
```

The recording samples CPU cycles at the specified frequency (default 4000 Hz) and generates a profile showing which functions consume the most CPU time.

### 3. Measure Kernel Overhead

Determine how much CPU time is spent in kernel vs userspace per thread:

```bash
# Measure kernel overhead for the foreground app
metavr perf simpleperf kernel-overhead

# Custom duration
metavr perf simpleperf kernel-overhead --app com.example.myapp --duration 10
```

Returns per-thread breakdown of user-mode vs kernel-mode CPU cycles. High kernel overhead (>20%) in a thread suggests:

- Excessive syscalls (file I/O, memory allocation)
- Driver overhead (GPU command submission, sensor access)
- Lock contention in kernel synchronization primitives

## Analysis Workflow

### Step 1: Classify First

Always start with classification. This prevents wasting time optimizing the wrong thing.

```bash
metavr perf simpleperf classify --app com.example.myapp --duration 10
```

**Decision tree based on results:**

- **CPU-bound** → Record hotspots (Step 2a), look at top functions
- **Memory-bound** → Record with cache-miss events, check data access patterns
- **I/O-bound** → Check kernel overhead, look at thread contention in Perfetto

### Step 2a: CPU-Bound Apps — Find Hotspots

```bash
metavr perf simpleperf record --app com.example.myapp --duration 10
```

Review the top functions by CPU cycle consumption. Common VR hotspots:

| Function Pattern | Likely Cause | Fix |
|-----------------|-------------|-----|
| `Physics.*` / `PhysX` | Complex physics simulation | Reduce collider count, simplify meshes, increase fixed timestep |
| `Render*` / `Draw*` | Too many draw calls | Batch materials, use GPU instancing, reduce unique materials |
| `GC_*` / `gc_alloc` | Garbage collection pressure | Pool allocations, avoid per-frame allocations |
| `memcpy` / `memmove` | Large data copies | Use references, reduce buffer sizes, avoid unnecessary copies |
| `LZ4_*` / `compress` | Asset decompression | Pre-decompress, use lighter compression, cache results |

### Step 2b: Memory-Bound Apps — Check Cache Behavior

If classification shows memory-bound, the issue is likely cache misses or memory bandwidth:

- Large working sets thrashing L1/L2 cache
- Random access patterns defeating prefetcher
- False sharing between threads on adjacent cache lines

Use Perfetto `hz-perfetto-debug` to correlate memory-bound regions with specific code paths.

### Step 3: Measure Kernel Overhead

```bash
metavr perf simpleperf kernel-overhead --app com.example.myapp
```

**Interpreting results by thread:**

| Thread | Expected Kernel % | High Kernel % Indicates |
|--------|------------------|------------------------|
| Main/Game thread | < 5% | Excessive file I/O, logging, or allocations |
| Render thread | 5-15% | Normal (GPU driver overhead). >20% = driver issue |
| Worker threads | < 5% | Thread synchronization overhead |
| Audio thread | < 10% | Normal for audio HAL calls |

### Step 4: Combine with Perfetto

Simpleperf tells you *where* cycles go. Perfetto tells you *when* and in what context. Use together:

1. Simpleperf classification reveals the bottleneck type
2. Simpleperf hotspot recording identifies the expensive functions
3. Perfetto trace (`metavr perf capture`) shows when those functions run relative to frame boundaries
4. Use `metavr perf query` to correlate function timing with frame drops

## Common Pitfalls

- **Don't profile in thermal throttling.** Let the device cool before recording — throttled clocks distort cycle counts. Check thermal state first with `metavr device info`.
- **Sample duration matters.** Short recordings (<5s) may not capture representative behavior. Use at least 10 seconds for classification.
- **simpleperf requires shell access.** If `adb shell simpleperf` fails, ensure developer mode is enabled and USB debugging is authorized.
- **Frequency vs accuracy tradeoff.** Higher sampling frequency (>8000 Hz) can perturb the workload on mobile SoCs. Default 4000 Hz is a good balance.
- **Classification is a snapshot.** An app can be CPU-bound during gameplay and I/O-bound during scene loads. Profile the specific scenario you're optimizing.

## References

For detailed guides on specific topics, see:

- [Workload Classification](references/workload-classification.md) — PMU counter interpretation and bottleneck identification
- [CPU Hotspot Analysis](references/cpu-hotspot-analysis.md) — Recording and analyzing CPU cycle profiles
- [Kernel Overhead](references/kernel-overhead.md) — Measuring and reducing kernel-mode CPU usage

More from meta-quest/agentic-tools

SkillDescription
hz-android-2d-portingGuides porting existing Android 2D apps to Meta Quest and Horizon OS — input adaptation, panel layout, and design requirements. Use when adapting a mobile Android app for Quest.
hz-api-upgradeUpgrades Meta Quest apps to newer Horizon OS SDK versions — migration guides, deprecated API replacements, changelog. Use when updating SDK versions or fixing deprecated API warnings.
hz-immersive-designerGuides design of comfortable, intuitive VR/MR experiences for Meta Quest and Horizon OS — comfort guidelines, interaction patterns, spatial layout, accessibility. Use during UX design review or when evaluating comfort and accessibility.
hz-iwsdk-webxrBuilds WebXR experiences for Meta Quest and Horizon OS using the Immersive Web SDK (IWSDK) — ECS architecture, Three.js integration, spatial UI. Use when creating web-based VR/MR apps for Quest Browser.
hz-new-project-creationScaffolds new Meta Quest and Horizon OS projects with recommended settings for Unity, Unreal, Android/Spatial SDK, or WebXR. Use when creating a new Quest app from scratch.
hz-perfetto-debugAnalyzes Meta Quest and Horizon OS VR performance using Perfetto traces — frame timing, CPU/GPU bottlenecks, render pass analysis. Use when profiling frame drops, jank, or thermal issues on Quest devices.
hz-platform-sdkGuides integration of the Horizon Platform SDK for Meta Quest and Horizon OS Android/Kotlin apps — achievements, IAP, users, leaderboards, presence, notifications, abuse reporting, entitlements, asset files, application lifecycle, consent, device integrity, language packs, user age categories, and rate and review. Covers setup, initialization, API usage, data types, error handling, and best practices for all 17 public platform SDK packages.
hz-psdk-integrationFor 3P / EXTERNAL developers: guides interactive Horizon Platform SDK (PSDK) integration for Meta Quest and Horizon OS Android/Kotlin apps — analyzes the codebase, recommends public platform features, plans the integration, and validates on device. Uses the external toolchain (Gradle, metavr, a developers.meta.com / Rocksteady App ID). For 1P apps inside fbsource (buck, Chesterfield/ni, adb), use psdk_1p_onboarding_agent instead.
hz-quest-verify-first>-
hz-spatial-sdkBuilds spatial Android apps for Meta Quest and Horizon OS with Meta Spatial SDK — ECS architecture, 2D panels, 3D objects, hybrid experiences. Use when creating Kotlin-based spatial applications.