File size: 2,474 Bytes
1233ab7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
//! On-device benchmark entry point.
//!
//! A deliberately plain Android app: no OpenXR, no swapchain, no camera.
//! The only question it answers is how fast the Adreno runs a DINOv3
//! forward pass under meganeura, and mixing in the XR compositor would
//! only add noise to that.
//!
//! ```text
//! cargo apk run --manifest-path android/Cargo.toml --release --no-logcat
//! adb logcat -v time | grep -E "dinovision|RustStdoutStderr"
//! ```
//!
//! The run is one-shot: results go to logcat and the process stays alive so
//! the launcher does not report a crash.

#![cfg(target_os = "android")]

use android_activity::{AndroidApp, MainEvent, PollEvent};

#[unsafe(no_mangle)]
fn android_main(app: AndroidApp) {
    android_logger::init_once(
        android_logger::Config::default()
            .with_max_level(log::LevelFilter::Info)
            .with_tag("dinovision"),
    );

    // Vulkan initialization can fail on a device we have not accounted for;
    // a panic here would be reported as an opaque crash, so log the reason.
    std::panic::set_hook(Box::new(|info| {
        log::error!("panic: {info}");
    }));

    log::info!("=== dinovision benchmark ===");
    match std::panic::catch_unwind(run) {
        Ok(()) => log::info!("=== benchmark complete ==="),
        Err(_) => log::error!("=== benchmark aborted ==="),
    }

    // Stay responsive to the lifecycle instead of returning, which Android
    // treats as the activity dying.
    loop {
        app.poll_events(Some(std::time::Duration::from_millis(500)), |event| {
            if let PollEvent::Main(MainEvent::Destroy) = event {
                std::process::exit(0);
            }
        });
    }
}

fn run() {
    let gpu = match dinovision::init_context(None) {
        Ok(gpu) => gpu,
        Err(e) => {
            log::error!("GPU context init failed: {e:?}");
            return;
        }
    };

    let iters = std::env::var("DINOVISION_ITERS")
        .ok()
        .and_then(|s| s.parse::<usize>().ok())
        .unwrap_or(20);
    log::info!(
        "timing protocol: {} warmups, {iters} retained samples",
        std::env::var("DINOVISION_WARMUPS").unwrap_or_else(|_| "5".into())
    );
    let results = dinovision::bench::run_all(gpu, iters);

    log::info!("---- summary ----");
    for t in &results {
        log::info!("{t}");
        log::info!("DINOVISION_BENCH_JSON {}", t.json_line());
    }
}