ワンクリックで
native-profiling
Native Rust profiling on Android and desktop with simpleperf, HWASan, and flamegraphs.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Native Rust profiling on Android and desktop with simpleperf, HWASan, and flamegraphs.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Use this skill to generate well-branded interfaces and assets for RIPDPI (an Android-native, Compose-first VPN and DPI-bypass app), either for production or throwaway prototypes/mocks/etc. Contains essential design guidelines, colors, type, fonts, brand-ship icons, and an interactive UI kit of every public composable from the live ui/components tree.
Use when managing the Rust workspace, adding/removing crates, editing workspace dependencies, running cargo nextest/audit/deny, configuring Cargo profiles for Android cross-compilation, debugging Cargo.lock churn, migrating crate edition, or wiring Gradle to cargo via the ripdpi.android.rust-native plugin.
Use when modifying the diagnostics scan pipeline, ScanRequest/ScanReport types, ProbeTask families, ripdpi-monitor-engine / ripdpi-diagnostics-* crates, strategy-probe candidates, the diagnostics catalog (packs/profiles), wire-schema contracts between Rust and Kotlin, DIAGNOSTICS_ENGINE_SCHEMA_VERSION, golden contract tests, or adding a new probe type / profile. Triggers on diagnostics scans, strategy probes, automatic audit, dpi-detector profiles, or anything in core/diagnostics or native/rust/crates/ripdpi-monitor-*.
Android-specific Rust build, verification, and packaging — per-target 16 KiB page alignment, size-optimized release profile, ELF symbol allowlist, .so size budgets, NDK 29 specifics. Use when modifying .cargo/config.toml for Android targets, the workspace [profile.release] / [profile.android-jni] block, or when verifying a built .so before release.
Telemetry and observability discipline for the RIPDPI Android Rust stack — control-plane vs data-plane logging, bounded flume event queues, atomic counters, snapshot polling, readiness callbacks, and deterministic JSON contracts. Use when authoring or modifying telemetry emission code, the bounded event ring, the Kotlin-side telemetry consumer, or any per-packet logging.
Custom detekt rules, DI/privacy/suppression guardrails, detekt.yml configuration, and false-positive triage.
| name | native-profiling |
| description | Native Rust profiling on Android and desktop with simpleperf, HWASan, and flamegraphs. |
CPU and memory profiling for Rust .so libraries running on Android devices and emulators, plus desktop profiling for ripdpi-cli.
| Requirement | Status | Location |
|---|---|---|
Frame pointers (-Cforce-frame-pointers=yes) | Enabled | native/rust/.cargo/config.toml |
| Debug symbols preserved in debug APK | Enabled | ripdpi.android.native convention plugin (keepDebugSymbols) |
| Panic hook with backtrace capture | Installed | android-support::install_panic_hook() in both JNI_OnLoad |
Unstripped .so for symbolication | Available | native/rust/target/<triple>/debug/ |
# Find the app PID
adb shell pidof com.poyka.ripdpi
# Record for 30 seconds with call-graph
adb shell simpleperf record \
-p $(adb shell pidof com.poyka.ripdpi) \
--call-graph dwarf \
--duration 30 \
-o /data/local/tmp/perf.data
# Pull to host
adb pull /data/local/tmp/perf.data
Use Inferno (bundled with the NDK):
python3 $ANDROID_NDK_HOME/simpleperf/inferno.py \
-sc --record_file perf.data
# Opens flamegraph.html in browser
Or with the standalone inferno Rust tool:
cargo install inferno
simpleperf report-sample --show-callchain perf.data | inferno-flamegraph > flame.svg
Without -Cforce-frame-pointers=yes, simpleperf cannot walk the stack reliably on ARM64. Flamegraphs show empty or truncated stacks. The flag is set for all four Android targets in native/rust/.cargo/config.toml.
The overhead is negligible -- one general-purpose register (x29 on ARM64) is reserved as the frame pointer.
Profile the CLI proxy on macOS or Linux without an Android device:
# Install cargo-flamegraph (uses dtrace on macOS, perf on Linux)
cargo install flamegraph
# Generate flamegraph while running the proxy
cd native/rust
cargo flamegraph --locked -p ripdpi-cli -- -p 1080 -x 1
# Send traffic through the proxy, then Ctrl+C
# Opens flamegraph.svg
# Requires nightly
cd native/rust
cargo +nightly run --locked -p ripdpi-cli \
--features dhat-heap -- -p 1080 -x 1
# Produces dhat-heap.json on exit
# Open at https://nnethercote.github.io/dh_view/dh_view.html
HWASan (Hardware Address Sanitizer) is the replacement for ASan, which is unsupported since NDK r26. Requires ARM64 device running Android 10+.
# Requires nightly Rust for -Zbuild-std
cd native/rust
RUSTFLAGS="-Zsanitizer=hwaddress" cargo +nightly build --locked \
-p ripdpi-android \
--target aarch64-linux-android \
-Zbuild-std \
--profile android-jni-dev
Create a wrap.sh script in the APK's lib directory:
#!/system/bin/sh
LD_HWASAN=1 exec "$@"
keepDebugSymbols in the convention plugin ensures the debug APK contains unstripped .so files with line-table info.
Stack traces in the native profiler require unstripped symbols. Debug builds have them; release builds need offline symbolication.
Symbolicates native crash logs from logcat:
adb logcat | $ANDROID_NDK_HOME/ndk-stack \
-sym native/rust/target/aarch64-linux-android/debug/
$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/*/bin/llvm-addr2line \
-e native/rust/target/aarch64-linux-android/debug/libripdpi_android.so \
0x29ba4
Use the unstripped .so from native/rust/target/<triple>/debug/, not the stripped copy in core/engine/build/generated/jniLibs/.
The global panic hook (android-support::install_panic_hook()) captures std::backtrace::Backtrace::force_capture() and logs it to logcat via log::error!. Filter with:
adb logcat -s ripdpi-native:E ripdpi-tunnel-native:E | grep -A 50 "PANIC:"
Backtraces in android-jni-dev profile show file/line info (debug = "line-tables-only"). Release profile backtraces show only addresses -- symbolicate offline with ndk-stack.
| Mistake | Fix |
|---|---|
| Flamegraph shows empty stacks | Verify -Cforce-frame-pointers=yes in .cargo/config.toml |
Symbolication shows <unknown> | Use unstripped .so from target/<triple>/debug/, not jniLibs/ |
| ASan build fails | ASan is unsupported since NDK r26; use HWASan instead |
| HWASan on x86_64 emulator | HWASan is ARM64-only; use a physical device or ARM64 emulator |
| Panic backtrace missing | Ensure install_panic_hook() is called after init_android_logging() |
simpleperf record permission denied | Run adb shell as root, or target a debuggable app (android:debuggable="true") |
| Profiling release build shows no symbols | Expected -- release profile strips symbols; profile with android-jni-dev build |
| Task | Command |
|---|---|
| Record CPU profile | adb shell simpleperf record -p $(adb shell pidof com.poyka.ripdpi) --call-graph dwarf --duration 30 -o /data/local/tmp/perf.data |
| Generate flamegraph | python3 $ANDROID_NDK_HOME/simpleperf/inferno.py -sc --record_file perf.data |
| Desktop flamegraph | cargo flamegraph --locked -p ripdpi-cli -- -p 1080 -x 1 |
| Symbolicate crash log | adb logcat | ndk-stack -sym native/rust/target/aarch64-linux-android/debug/ |
| Filter panic backtraces | adb logcat -s ripdpi-native:E | grep -A 50 "PANIC:" |
android-device-debug -- ADB commands, logcat filtering, crash/ANR debuggingnative-jni-development -- Build pipeline, JNI exports, lifecycle rules