Profiling tools overview
The NDK and Android platform provide several profiling tools:- Simpleperf - CPU profiling tool for native code, part of the NDK
- Android Studio Profiler - Visual profiling with native support
- Perfetto/Systrace - System-wide performance tracing
- Heapprofd - Native memory profiling
Preparing for profiling
Enable profiling in your build
Inbuild.gradle:
Frame pointers slightly increase binary size but provide much better profiling data.
CPU profiling with Simpleperf
Simpleperf is a command-line profiling tool that uses the CPU’s performance monitoring unit (PMU).Installing Simpleperf
Recording CPU profile
1
Push Simpleperf to device
2
Record profile data
3
Pull profile data
4
Generate report
Interpreting Simpleperf output
Text report shows function-level CPU usage:- Overhead - Percentage of CPU time spent in this function
- Symbol - Function name (symbolicated if debug symbols available)
Advanced Simpleperf options
Profiling with Android Studio
CPU profiler
1
Open the Profiler
View > Tool Windows > Profiler
2
Start CPU recording
Click CPU timeline, then click Record. Choose:
- Java/Kotlin Method Trace - For Java/Kotlin profiling
- System Trace - For native and system profiling
- Sampled (Native) - For native code sampling
3
Perform operations
Interact with your app to trigger the code you want to profile.
4
Stop and analyze
Click Stop. The profiler displays:
- Flame chart - Visualize call stack over time
- Top Down/Bottom Up - Function call hierarchy
- Call Chart - Timeline of function calls
Memory profiler
Profile native memory allocations:- Open Memory Profiler
- Click Record native allocations
- Perform operations
- Stop recording
- Analyze allocation call stacks
Native memory profiling requires Android 10+ (API level 29) and a profileable or debuggable app.
System-wide tracing with Perfetto
Perfetto (successor to systrace) provides system-wide performance traces.Recording a trace
Using command line
Using System Tracing app
- Install System Tracing app from Play Store
- Open app and tap Record trace
- Select categories and duration
- Perform operations in your app
- Stop recording and share trace file
Analyzing traces
Open trace at ui.perfetto.dev:- View thread activity over time
- Identify frame drops and jank
- Analyze scheduling and CPU usage
- Inspect native function calls
Adding custom trace points
Native tracing with ATrace
CMakeLists.txt:
Scoped tracing helper
Identifying performance bottlenecks
CPU bottlenecks
Look for:- Functions with high overhead in Simpleperf
- Long-running operations blocking UI thread
- Inefficient algorithms (O(n²) when O(n log n) possible)
Memory bottlenecks
Look for:- Frequent allocations in hot paths
- Memory leaks (growing memory usage)
- Cache misses
I/O bottlenecks
Look for:- File operations on main thread
- Synchronous network calls
- Excessive logging
Optimization techniques
Use NEON SIMD instructions
Enable compiler optimizations
Reduce memory allocations
Cache-friendly data structures
Benchmarking
Measure performance consistently:Automated benchmarking
Use Google Benchmark library:Best practices
- Profile on real devices - Emulator performance doesn’t match real hardware
- Profile release builds - Debug builds can be 10x slower
- Profile representative workloads - Test with realistic data and usage patterns
- Use frame pointers - Enable for better stack traces in profiling
- Focus on hot paths - Optimize code that runs frequently
- Measure before and after - Verify optimizations actually improve performance
- Consider battery impact - Balance performance with power consumption
- Test on low-end devices - Ensure acceptable performance on minimum-spec devices
Premature optimization is the root of all evil. Profile first, then optimize the actual bottlenecks.
Additional resources
- Simpleperf Documentation - Comprehensive Simpleperf guide
- Android Profiler - Android Studio profiling tools
- Perfetto Documentation - System tracing with Perfetto
- ARM NEON Reference - SIMD optimization guide