1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
//! # mobench-sdk
//!
//! [](https://crates.io/crates/mobench-sdk)
//! [](https://docs.rs/mobench-sdk)
//! [](https://github.com/worldcoin/mobile-bench-rs/blob/main/LICENSE)
//!
//! 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
//!
//! ```toml
//! [dependencies]
//! mobench-sdk = "0.1.37"
//! 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:
//!
//! ```toml
//! [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:
//! 1. Ensure functions are annotated with `#[benchmark]`
//! 2. Ensure functions are `pub` (public visibility)
//! 3. Ensure functions take no parameters and return `()`
//! 4. Use the [`debug_benchmarks!`] macro to print registered benchmarks
//!
//! For complete integration instructions, see
//! [BENCH_SDK_INTEGRATION.md](https://github.com/worldcoin/mobile-bench-rs/blob/main/BENCH_SDK_INTEGRATION.md)
//!
//! ## Quick Start
//!
//! ### 1. Add Dependencies
//!
//! ```toml
//! [dependencies]
//! mobench-sdk = "0.1.37"
//! inventory = "0.3" # Required for benchmark registration
//! ```
//!
//! ### 2. Define Benchmarks
//!
//! Use the [`#[benchmark]`](macro@benchmark) attribute to mark functions for benchmarking:
//!
//! ```ignore
//! 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:
//!
//! ```bash
//! # 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 `registry` or `full` feature) |
//! | [`runner`] | Benchmark execution engine (requires `registry` or `full` feature) |
//! | [`builders`] | Android and iOS build automation (requires `builders` or `full` feature) |
//! | [`codegen`] | Mobile app template generation (requires `codegen`, `builders`, or `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 automation
//! - **[`mobench`](https://crates.io/crates/mobench)** - CLI tool for building and running benchmarks
//! - **[`mobench-macros`](https://crates.io/crates/mobench-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 |
//! | `registry` | No | Benchmark macro, inventory registry, and runtime execution without build tooling |
//! | `builders` | No | Android/iOS build automation; enables `codegen` |
//! | `codegen` | No | Project and mobile app template generation |
//! | `runner-only` | No | Minimal timing-only mode for mobile binaries |
//!
//! For mobile binaries where binary size matters, use `runner-only`:
//!
//! ```toml
//! [dependencies]
//! mobench-sdk = { version = "0.1.37", default-features = false, features = ["runner-only"] }
//! ```
//!
//! ## Programmatic Usage
//!
//! You can also use the SDK programmatically:
//!
//! ### Using the Benchmark Builder Pattern
//!
//! Requires the `registry` or `full` feature.
//!
//! ```ignore
//! use mobench_sdk::BenchmarkBuilder;
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let report = BenchmarkBuilder::new("my_benchmark")
//! .iterations(100)
//! .warmup(10)
//! .run()?;
//!
//! println!("Mean: {} ns", report.mean_ns());
//! Ok(())
//! }
//! ```
//!
//! ### Using BenchSpec With Registry Dispatch
//!
//! Requires the `registry` or `full` feature. With `runner-only`, use
//! [`run_closure`] or [`timing::run_closure`] for manual dispatch instead.
//!
//! ```ignore
//! use mobench_sdk::{BenchSpec, run_benchmark};
//!
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let spec = BenchSpec::new("my_benchmark", 50, 5)?;
//!
//! let report = run_benchmark(spec)?;
//! println!("Collected {} samples", report.samples.len());
//! Ok(())
//! }
//! ```
//!
//! ### Discovering Benchmarks
//!
//! Requires the `registry` or `full` feature.
//!
//! ```ignore
//! use mobench_sdk::{discover_benchmarks, list_benchmark_names};
//!
//! fn main() {
//! // 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
//!
//! ```ignore
//! 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
//!
//! ```ignore
//! 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/`:
//!
//! ```text
//! 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 IPA
//! ```
//!
//! This keeps generated files inside `target/`, following Rust conventions
//! and preventing accidental commits of mobile project files.
//!
//! ## Platform Requirements
//!
//! ### Android
//!
//! - Android NDK (set `ANDROID_NDK_HOME` environment variable)
//! - `cargo-ndk` (`cargo install cargo-ndk`)
//! - Rust targets: `rustup target add aarch64-linux-android`
//! - Optional extra ABI targets only when configured explicitly
//!
//! ### 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:
//!
//! ```ignore
//! #[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:
//!
//! ```ignore
//! // 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.
// Core timing module - always available
// UniFFI integration helpers
// This module provides template types and conversion traits for UniFFI integration
// Unified FFI module for UniFFI integration
// Build automation modules - only with builder/codegen features
// Registry runtime modules - available without build tooling
// Re-export the benchmark macro from bench-macros (only with registry feature)
pub use benchmark;
// Re-export inventory so users don't need to add it as a separate dependency
pub use inventory;
// Re-export key registry types for convenience
pub use ;
pub use ;
// Re-export types that are always available
pub use ;
// Re-export build/config types. These are plain data types and do not pull in
// build automation dependencies by themselves.
pub use ;
// Re-export timing types at the crate root for convenience
pub use ;
/// Re-export of [`std::hint::black_box`] for preventing compiler optimizations.
///
/// Use this to ensure the compiler doesn't optimize away benchmark computations.
pub use black_box;
/// Library version, matching `Cargo.toml`.
///
/// This can be used to verify SDK compatibility:
///
/// ```
/// assert!(!mobench_sdk::VERSION.is_empty());
/// ```
pub const VERSION: &str = env!;
/// Generates a debug function that prints all discovered benchmarks.
///
/// This macro is useful for debugging benchmark registration issues.
/// It creates a function `_debug_print_benchmarks()` that you can call
/// to see which benchmarks have been registered via `#[benchmark]`.
///
/// # Example
///
/// ```ignore
/// use mobench_sdk::{benchmark, debug_benchmarks};
///
/// #[benchmark]
/// fn my_benchmark() {
/// std::hint::black_box(42);
/// }
///
/// // Generate the debug function
/// debug_benchmarks!();
///
/// fn main() {
/// // Print all registered benchmarks
/// _debug_print_benchmarks();
/// // Output:
/// // Discovered benchmarks:
/// // - my_crate::my_benchmark
/// }
/// ```
///
/// # Troubleshooting
///
/// If no benchmarks are printed:
/// 1. Ensure functions are annotated with `#[benchmark]`
/// 2. Ensure functions are `pub` (public visibility)
/// 3. Ensure the crate with benchmarks is linked into the binary
/// 4. Check that `inventory` crate is in your dependencies