mobench_sdk/
lib.rs

1//! # mobench-sdk
2//!
3//! A mobile benchmarking SDK for Rust that enables running performance benchmarks
4//! on real Android and iOS devices via BrowserStack App Automate.
5//!
6//! ## Overview
7//!
8//! `mobench-sdk` provides a simple, declarative API for defining benchmarks that can
9//! run on mobile devices. It handles the complexity of cross-compilation, FFI bindings,
10//! and mobile app packaging automatically.
11//!
12//! ## Quick Start
13//!
14//! ### 1. Add Dependencies
15//!
16//! ```toml
17//! [dependencies]
18//! mobench-sdk = "0.1"
19//! inventory = "0.3"  # Required for benchmark registration
20//! ```
21//!
22//! ### 2. Define Benchmarks
23//!
24//! Use the [`#[benchmark]`](macro@benchmark) attribute to mark functions for benchmarking:
25//!
26//! ```ignore
27//! use mobench_sdk::benchmark;
28//!
29//! #[benchmark]
30//! fn my_expensive_operation() {
31//!     let result = expensive_computation();
32//!     std::hint::black_box(result);  // Prevent optimization
33//! }
34//!
35//! #[benchmark]
36//! fn another_benchmark() {
37//!     for i in 0..1000 {
38//!         std::hint::black_box(i * i);
39//!     }
40//! }
41//! ```
42//!
43//! ### 3. Build and Run
44//!
45//! Use the `mobench` CLI to build and run benchmarks:
46//!
47//! ```bash
48//! # Install the CLI
49//! cargo install mobench
50//!
51//! # Build for Android (outputs to target/mobench/)
52//! cargo mobench build --target android
53//!
54//! # Build for iOS
55//! cargo mobench build --target ios
56//!
57//! # Run on BrowserStack
58//! cargo mobench run --target android --function my_expensive_operation \
59//!     --iterations 100 --warmup 10 --devices "Google Pixel 7-13.0"
60//! ```
61//!
62//! ## Architecture
63//!
64//! The SDK consists of several components:
65//!
66//! | Module | Description |
67//! |--------|-------------|
68//! | [`registry`] | Runtime discovery of `#[benchmark]` functions |
69//! | [`runner`] | Benchmark execution and timing infrastructure |
70//! | [`builders`] | Android and iOS build automation |
71//! | [`codegen`] | Mobile app template generation |
72//! | [`types`] | Common types and error definitions |
73//!
74//! ## Crate Ecosystem
75//!
76//! The mobench ecosystem consists of four crates:
77//!
78//! - **`mobench-sdk`** (this crate) - Core SDK library with build automation
79//! - **[`mobench`](https://crates.io/crates/mobench)** - CLI tool for building and running benchmarks
80//! - **[`mobench-macros`](https://crates.io/crates/mobench-macros)** - `#[benchmark]` proc macro
81//! - **[`mobench-runner`](https://crates.io/crates/mobench-runner)** - Lightweight timing harness
82//!
83//! ## Programmatic Usage
84//!
85//! You can also use the SDK programmatically:
86//!
87//! ### Using the Builder Pattern
88//!
89//! ```ignore
90//! use mobench_sdk::BenchmarkBuilder;
91//!
92//! let report = BenchmarkBuilder::new("my_benchmark")
93//!     .iterations(100)
94//!     .warmup(10)
95//!     .run()?;
96//!
97//! println!("Mean: {} ns", report.samples.iter()
98//!     .map(|s| s.duration_ns)
99//!     .sum::<u64>() / report.samples.len() as u64);
100//! ```
101//!
102//! ### Using BenchSpec Directly
103//!
104//! ```ignore
105//! use mobench_sdk::{BenchSpec, run_benchmark};
106//!
107//! let spec = BenchSpec {
108//!     name: "my_benchmark".to_string(),
109//!     iterations: 50,
110//!     warmup: 5,
111//! };
112//!
113//! let report = run_benchmark(spec)?;
114//! println!("Collected {} samples", report.samples.len());
115//! ```
116//!
117//! ### Discovering Benchmarks
118//!
119//! ```ignore
120//! use mobench_sdk::{discover_benchmarks, list_benchmark_names};
121//!
122//! // Get all registered benchmark names
123//! let names = list_benchmark_names();
124//! for name in names {
125//!     println!("Found benchmark: {}", name);
126//! }
127//!
128//! // Get full benchmark function info
129//! let benchmarks = discover_benchmarks();
130//! for bench in benchmarks {
131//!     println!("Benchmark: {}", bench.name);
132//! }
133//! ```
134//!
135//! ## Building Mobile Apps
136//!
137//! The SDK includes builders for automating mobile app creation:
138//!
139//! ### Android Builder
140//!
141//! ```ignore
142//! use mobench_sdk::builders::AndroidBuilder;
143//! use mobench_sdk::{BuildConfig, BuildProfile, Target};
144//!
145//! let builder = AndroidBuilder::new(".", "my-bench-crate")
146//!     .verbose(true)
147//!     .output_dir("target/mobench");  // Default
148//!
149//! let config = BuildConfig {
150//!     target: Target::Android,
151//!     profile: BuildProfile::Release,
152//!     incremental: true,
153//! };
154//!
155//! let result = builder.build(&config)?;
156//! println!("APK built at: {:?}", result.app_path);
157//! ```
158//!
159//! ### iOS Builder
160//!
161//! ```ignore
162//! use mobench_sdk::builders::{IosBuilder, SigningMethod};
163//! use mobench_sdk::{BuildConfig, BuildProfile, Target};
164//!
165//! let builder = IosBuilder::new(".", "my-bench-crate")
166//!     .verbose(true);
167//!
168//! let config = BuildConfig {
169//!     target: Target::Ios,
170//!     profile: BuildProfile::Release,
171//!     incremental: true,
172//! };
173//!
174//! let result = builder.build(&config)?;
175//! println!("xcframework built at: {:?}", result.app_path);
176//!
177//! // Package IPA for distribution
178//! let ipa_path = builder.package_ipa("BenchRunner", SigningMethod::AdHoc)?;
179//! ```
180//!
181//! ## Output Directory
182//!
183//! By default, all mobile artifacts are written to `target/mobench/`:
184//!
185//! ```text
186//! target/mobench/
187//! ├── android/
188//! │   ├── app/
189//! │   │   ├── src/main/jniLibs/     # Native .so libraries
190//! │   │   └── build/outputs/apk/    # Built APK
191//! │   └── ...
192//! └── ios/
193//!     ├── sample_fns.xcframework/   # Built xcframework
194//!     ├── BenchRunner/              # Xcode project
195//!     └── BenchRunner.ipa           # Packaged IPA
196//! ```
197//!
198//! This keeps generated files inside `target/`, following Rust conventions
199//! and preventing accidental commits of mobile project files.
200//!
201//! ## Platform Requirements
202//!
203//! ### Android
204//!
205//! - Android NDK (set `ANDROID_NDK_HOME` environment variable)
206//! - `cargo-ndk` (`cargo install cargo-ndk`)
207//! - Rust targets: `rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android`
208//!
209//! ### iOS
210//!
211//! - Xcode with command line tools
212//! - `uniffi-bindgen` (`cargo install uniffi-bindgen`)
213//! - `xcodegen` (optional, `brew install xcodegen`)
214//! - Rust targets: `rustup target add aarch64-apple-ios aarch64-apple-ios-sim`
215//!
216//! ## Best Practices
217//!
218//! ### Use `black_box` to Prevent Optimization
219//!
220//! Always wrap benchmark results with [`std::hint::black_box`] to prevent the
221//! compiler from optimizing away the computation:
222//!
223//! ```ignore
224//! #[benchmark]
225//! fn correct_benchmark() {
226//!     let result = expensive_computation();
227//!     std::hint::black_box(result);  // Result is "used"
228//! }
229//! ```
230//!
231//! ### Avoid Side Effects
232//!
233//! Benchmarks should be deterministic and avoid I/O operations:
234//!
235//! ```ignore
236//! // Good: Pure computation
237//! #[benchmark]
238//! fn good_benchmark() {
239//!     let data = vec![1, 2, 3, 4, 5];
240//!     let sum: i32 = data.iter().sum();
241//!     std::hint::black_box(sum);
242//! }
243//!
244//! // Avoid: File I/O adds noise
245//! #[benchmark]
246//! fn noisy_benchmark() {
247//!     let data = std::fs::read_to_string("data.txt").unwrap();  // Don't do this
248//!     std::hint::black_box(data);
249//! }
250//! ```
251//!
252//! ### Choose Appropriate Iteration Counts
253//!
254//! - **Warmup**: 5-10 iterations to warm CPU caches and JIT
255//! - **Iterations**: 50-100 for stable statistics
256//! - Mobile devices may have more variance than desktop
257//!
258//! ## Feature Flags
259//!
260//! Currently, `mobench-sdk` has no optional feature flags. All functionality
261//! is included by default.
262//!
263//! ## License
264//!
265//! MIT License - see repository for details.
266
267// Public modules
268pub mod builders;
269pub mod codegen;
270pub mod registry;
271pub mod runner;
272pub mod types;
273
274// Re-export the benchmark macro from bench-macros
275pub use mobench_macros::benchmark;
276
277// Re-export key types for convenience
278pub use registry::{BenchFunction, discover_benchmarks, find_benchmark, list_benchmark_names};
279pub use runner::{BenchmarkBuilder, run_benchmark};
280pub use types::{
281    BenchError, BenchSample, BenchSpec, BuildConfig, BuildProfile, BuildResult, InitConfig,
282    RunnerReport, Target,
283};
284
285// Re-export mobench-runner types for backward compatibility
286pub use mobench_runner;
287
288/// Library version, matching `Cargo.toml`.
289///
290/// This can be used to verify SDK compatibility:
291///
292/// ```
293/// assert!(!mobench_sdk::VERSION.is_empty());
294/// ```
295pub const VERSION: &str = env!("CARGO_PKG_VERSION");
296
297#[cfg(test)]
298mod tests {
299    use super::*;
300
301    #[test]
302    fn test_version_is_set() {
303        assert!(!VERSION.is_empty());
304    }
305
306    #[test]
307    fn test_discover_benchmarks_compiles() {
308        // This test just ensures the function is accessible
309        let _benchmarks = discover_benchmarks();
310    }
311}