Expand description
§mobench-sdk
A mobile benchmarking SDK for Rust that provides the runtime, builders, and
generated mobile runners used by the mobench CLI for local execution,
BrowserStack benchmark runs, and local native profiling.
§Overview
mobench-sdk provides a simple, declarative API for defining benchmarks that can
run on mobile devices. It handles the timing/runtime layer, cross-compilation,
FFI bindings, template generation, and mobile app packaging used by the CLI.
§Quick Setup Checklist
Before using mobench-sdk, ensure your project is configured correctly:
§Required Cargo.toml entries
[dependencies]
mobench-sdk = "0.1"
inventory = "0.3" # Required for benchmark registration
[lib]
# Required for mobile FFI - produces .so (Android) and .a (iOS)
crate-type = ["cdylib", "staticlib", "lib"]§When UniFFI is needed
If you’re creating custom FFI types for your benchmarks (custom errors, specs, etc.), you’ll also need UniFFI:
[dependencies]
uniffi = { version = "0.28", features = ["cli"] }
thiserror = "1.0" # For custom error types
serde = { version = "1.0", features = ["derive"] } # For serialization
[build-dependencies]
uniffi = { version = "0.28", features = ["build"] }For most use cases, the SDK’s built-in types are sufficient and UniFFI setup
is handled automatically by cargo mobench build.
§Troubleshooting
If benchmarks aren’t being discovered:
- Ensure functions are annotated with
#[benchmark] - Ensure functions are
pub(public visibility) - Ensure functions take no parameters and return
() - Use the
debug_benchmarks!macro to print registered benchmarks
For complete integration instructions, see BENCH_SDK_INTEGRATION.md
§Quick Start
§1. Add Dependencies
[dependencies]
mobench-sdk = "0.1"
inventory = "0.3" # Required for benchmark registration§2. Define Benchmarks
Use the #[benchmark] attribute to mark functions for benchmarking:
use mobench_sdk::benchmark;
#[benchmark]
fn my_expensive_operation() {
let result = expensive_computation();
std::hint::black_box(result); // Prevent optimization
}
#[benchmark]
fn another_benchmark() {
for i in 0..1000 {
std::hint::black_box(i * i);
}
}§3. Build and Run
Use the mobench CLI to build and run benchmarks:
# Install the CLI
cargo install mobench
# Build for Android (outputs to target/mobench/)
cargo mobench build --target android
# Build for iOS
cargo mobench build --target ios
# Run on BrowserStack (use --release for smaller APK uploads)
cargo mobench run --target android --function my_expensive_operation \
--iterations 100 --warmup 10 --devices "Google Pixel 7-13.0" --release
# Or capture a local native profile
cargo mobench profile run --target android --provider local \
--backend android-native --function my_expensive_operation§Architecture
The SDK consists of several components:
| Module | Description |
|---|---|
timing | Core timing infrastructure (always available) |
registry | Runtime discovery of #[benchmark] functions (requires full feature) |
runner | Benchmark execution engine (requires full feature) |
builders | Android and iOS build automation (requires full feature) |
codegen | Mobile app template generation (requires full feature) |
types | Common types and error definitions |
§Crate Ecosystem
The mobench ecosystem consists of three published crates:
mobench-sdk(this crate) - Core SDK library with timing harness and build automationmobench- CLI tool for building and running benchmarksmobench-macros-#[benchmark]proc macro
Note: The mobench-runner crate has been consolidated into this crate as the timing module.
§Feature Flags
| Feature | Default | Description |
|---|---|---|
full | Yes | Full SDK with build automation, templates, and registry |
runner-only | No | Minimal timing-only mode for mobile binaries |
For mobile binaries where binary size matters, use runner-only:
[dependencies]
mobench-sdk = { version = "0.1", default-features = false, features = ["runner-only"] }§Programmatic Usage
You can also use the SDK programmatically:
§Using the Builder Pattern
use mobench_sdk::BenchmarkBuilder;
let report = BenchmarkBuilder::new("my_benchmark")
.iterations(100)
.warmup(10)
.run()?;
println!("Mean: {} ns", report.samples.iter()
.map(|s| s.duration_ns)
.sum::<u64>() / report.samples.len() as u64);§Using BenchSpec Directly
use mobench_sdk::{BenchSpec, run_benchmark};
let spec = BenchSpec {
name: "my_benchmark".to_string(),
iterations: 50,
warmup: 5,
};
let report = run_benchmark(spec)?;
println!("Collected {} samples", report.samples.len());§Discovering Benchmarks
use mobench_sdk::{discover_benchmarks, list_benchmark_names};
// Get all registered benchmark names
let names = list_benchmark_names();
for name in names {
println!("Found benchmark: {}", name);
}
// Get full benchmark function info
let benchmarks = discover_benchmarks();
for bench in benchmarks {
println!("Benchmark: {}", bench.name);
}§Building Mobile Apps
The SDK includes builders for automating mobile app creation:
§Android Builder
use mobench_sdk::builders::AndroidBuilder;
use mobench_sdk::{BuildConfig, BuildProfile, Target};
let builder = AndroidBuilder::new(".", "my-bench-crate")
.verbose(true)
.output_dir("target/mobench"); // Default
let config = BuildConfig {
target: Target::Android,
profile: BuildProfile::Release,
incremental: true,
};
let result = builder.build(&config)?;
println!("APK built at: {:?}", result.app_path);§iOS Builder
use mobench_sdk::builders::{IosBuilder, SigningMethod};
use mobench_sdk::{BuildConfig, BuildProfile, Target};
let builder = IosBuilder::new(".", "my-bench-crate")
.verbose(true);
let config = BuildConfig {
target: Target::Ios,
profile: BuildProfile::Release,
incremental: true,
};
let result = builder.build(&config)?;
println!("xcframework built at: {:?}", result.app_path);
// Package IPA for distribution
let ipa_path = builder.package_ipa("BenchRunner", SigningMethod::AdHoc)?;§Output Directory
By default, all mobile artifacts are written to target/mobench/:
target/mobench/
├── android/
│ ├── app/
│ │ ├── src/main/jniLibs/ # Native .so libraries
│ │ └── build/outputs/apk/ # Built APK
│ └── ...
└── ios/
├── sample_fns.xcframework/ # Built xcframework
├── BenchRunner/ # Xcode project
└── BenchRunner.ipa # Packaged IPAThis keeps generated files inside target/, following Rust conventions
and preventing accidental commits of mobile project files.
§Platform Requirements
§Android
- Android NDK (set
ANDROID_NDK_HOMEenvironment variable) cargo-ndk(cargo install cargo-ndk)- Rust targets:
rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android
§iOS
- Xcode with command line tools
uniffi-bindgen(cargo install --git https://github.com/mozilla/uniffi-rs --tag <uniffi-tag> uniffi-bindgen-cli --bin uniffi-bindgen)xcodegen(optional,brew install xcodegen)- Rust targets:
rustup target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios
§Best Practices
§Use black_box to Prevent Optimization
Always wrap benchmark results with std::hint::black_box to prevent the
compiler from optimizing away the computation:
#[benchmark]
fn correct_benchmark() {
let result = expensive_computation();
std::hint::black_box(result); // Result is "used"
}§Avoid Side Effects
Benchmarks should be deterministic and avoid I/O operations:
// Good: Pure computation
#[benchmark]
fn good_benchmark() {
let data = vec![1, 2, 3, 4, 5];
let sum: i32 = data.iter().sum();
std::hint::black_box(sum);
}
// Avoid: File I/O adds noise
#[benchmark]
fn noisy_benchmark() {
let data = std::fs::read_to_string("data.txt").unwrap(); // Don't do this
std::hint::black_box(data);
}§Choose Appropriate Iteration Counts
- Warmup: 5-10 iterations to warm CPU caches and JIT
- Iterations: 50-100 for stable statistics
- Mobile devices may have more variance than desktop
§License
MIT License - see repository for details.
Re-exports§
pub use registry::BenchFunction;fullpub use registry::discover_benchmarks;fullpub use registry::find_benchmark;fullpub use registry::list_benchmark_names;fullpub use runner::BenchmarkBuilder;fullpub use runner::run_benchmark;fullpub use types::BenchError;pub use types::BenchSample;pub use types::BenchSpec;pub use types::RunnerReport;pub use types::BuildConfig;fullpub use types::BuildProfile;fullpub use types::BuildResult;fullpub use types::InitConfig;fullpub use types::NativeLibraryArtifact;fullpub use types::Target;fullpub use timing::BenchSummary;pub use timing::SemanticPhase;pub use timing::TimingError;pub use timing::profile_phase;pub use timing::run_closure;pub use inventory;full
Modules§
- builders
full - Build automation for mobile platforms.
- codegen
full - Code generation and template management
- ffi
- Unified FFI module for UniFFI integration.
- registry
full - Benchmark function registry
- runner
full - Benchmark execution runtime
- timing
- Lightweight benchmarking harness for mobile platforms.
- types
- Core types for mobench-sdk.
- uniffi_
types - UniFFI integration helpers for generating mobile bindings.
Macros§
- debug_
benchmarks full - Generates a debug function that prints all discovered benchmarks.
Constants§
- VERSION
- Library version, matching
Cargo.toml.
Functions§
- black_
box - Re-export of
std::hint::black_boxfor preventing compiler optimizations.
Attribute Macros§
- benchmark
full - Marks a function as a benchmark for mobile execution.