원클릭으로
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