Compare commits
4
Commits
5736a21a3a
...
08b7d23e86
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
08b7d23e86 | ||
|
|
a116325991 | ||
|
|
f20e481358 | ||
|
|
16a5957aa7 |
Generated
+26
-26
@@ -1265,7 +1265,7 @@ checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
|
||||
|
||||
[[package]]
|
||||
name = "darkroom-android"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"android_logger",
|
||||
"dr-plat",
|
||||
@@ -1278,7 +1278,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darkroom-desktop"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dr-plat",
|
||||
@@ -1454,7 +1454,7 @@ checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
|
||||
|
||||
[[package]]
|
||||
name = "dr-bench"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dr-catalog",
|
||||
@@ -1471,7 +1471,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-catalog"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"dr-face",
|
||||
"dr-plat",
|
||||
@@ -1486,7 +1486,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-decode"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"dr-types",
|
||||
"env_logger",
|
||||
@@ -1500,7 +1500,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-denoise"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"dr-decode",
|
||||
"dr-gpu",
|
||||
@@ -1517,7 +1517,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-export"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"dr-decode",
|
||||
"dr-gpu",
|
||||
@@ -1536,7 +1536,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-face"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"dr-inference-engine",
|
||||
"env_logger",
|
||||
@@ -1549,7 +1549,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-film"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
@@ -1558,7 +1558,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-gpu"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"dr-decode",
|
||||
@@ -1576,7 +1576,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-inference-engine"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"env_logger",
|
||||
"libloading",
|
||||
@@ -1591,7 +1591,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-ingest"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"dr-plat",
|
||||
"dr-types",
|
||||
@@ -1603,7 +1603,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-lens"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"lensfun",
|
||||
"log",
|
||||
@@ -1611,7 +1611,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-pano"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"dr-decode",
|
||||
"dr-inference-engine",
|
||||
@@ -1625,7 +1625,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-pipeline"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"dr-types",
|
||||
"log",
|
||||
@@ -1634,7 +1634,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-plat"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"android-native-keyring-store",
|
||||
"dr-types",
|
||||
@@ -1650,7 +1650,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-preset-xmp"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"dr-pipeline",
|
||||
"log",
|
||||
@@ -1660,7 +1660,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-segment"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"dr-inference-engine",
|
||||
"env_logger",
|
||||
@@ -1673,7 +1673,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-sync"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"dr-plat",
|
||||
@@ -1687,7 +1687,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-sync-folder"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"dr-sync",
|
||||
@@ -1699,7 +1699,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-sync-nextcloud"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"dr-decode",
|
||||
@@ -1721,7 +1721,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-thumbs"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"dr-types",
|
||||
"jpeg-encoder",
|
||||
@@ -1733,7 +1733,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-types"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -1742,7 +1742,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-ui"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -1792,7 +1792,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dr-xmp"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"dr-types",
|
||||
"log",
|
||||
@@ -7126,7 +7126,7 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
|
||||
|
||||
[[package]]
|
||||
name = "traceability"
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"proc-macro2",
|
||||
|
||||
+9
-1
@@ -33,7 +33,7 @@ members = [
|
||||
exclude = ["third_party"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.22.0"
|
||||
version = "0.22.1"
|
||||
edition = "2021"
|
||||
rust-version = "1.92"
|
||||
license = "GPL-3.0-or-later"
|
||||
@@ -278,6 +278,14 @@ opt-level = 0
|
||||
lto = "thin"
|
||||
codegen-units = 1
|
||||
|
||||
# Except dr-ui. Slint expands the `.slint` files into ~27 MB of Rust
|
||||
# (`out/app.rs`), and at one codegen unit LLVM optimises all of it on a single
|
||||
# thread: 13.5 minutes of a release build with the other cores idle. The code
|
||||
# it holds is UI glue — property bindings and callbacks — not the image work,
|
||||
# which lives in the crates above that keep the single unit.
|
||||
[profile.release.package.dr-ui]
|
||||
codegen-units = 16
|
||||
|
||||
# A release build that can say where it panicked: line tables, so a crash
|
||||
# record's backtrace (`dr_plat::crash`) reads `file.rs:123` rather than bare
|
||||
# addresses. The macOS build uses it (docs/dev/macos.md) — no one here can
|
||||
|
||||
@@ -201,7 +201,7 @@ controls, its place in the chain and its tests.
|
||||
|
||||
## Where it stands
|
||||
|
||||
**0.22.0**, thirty-six tagged releases in. 193 numbered requirements in
|
||||
**0.22.1**, thirty-seven tagged releases in. 193 numbered requirements in
|
||||
scope, 85% of them claimed by code and [traced to it](docs/dev/traceability.md);
|
||||
the rest are written down rather than merely absent.
|
||||
|
||||
|
||||
@@ -73,6 +73,14 @@
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:supportsRtl="true">
|
||||
|
||||
<!-- The DSP's RPC library, which QNN's Hexagon stub loads. From API 31
|
||||
an app's linker namespace refuses a vendor library the manifest
|
||||
does not name, and QNN then fails to create its device
|
||||
(QNN_DEVICE_ERROR_INVALID_CONFIG) before it reaches the DSP:
|
||||
every model ran on the CPU on 0.22.0. Not required, so a device
|
||||
without one still installs and stays on the CPU. -->
|
||||
<uses-native-library android:name="libcdsprpc.so" android:required="false" />
|
||||
|
||||
<!-- NativeActivity rather than a Kotlin Activity: android-activity's
|
||||
glue loads libdarkroom.so and calls android_main. `android.app.lib_name`
|
||||
is how it learns which library to load, and must match [lib].name.
|
||||
|
||||
@@ -538,6 +538,19 @@ mod tests {
|
||||
Some(value.to_string())
|
||||
}
|
||||
|
||||
/// From API 31 the linker refuses a vendor library the manifest does not
|
||||
/// name, and QNN cannot create its Hexagon device without the DSP's RPC
|
||||
/// library: 0.22.0 ran every model on the CPU for want of this line.
|
||||
#[test]
|
||||
fn the_npu_can_reach_the_dsp() {
|
||||
assert!(
|
||||
manifest().contains(
|
||||
r#"<uses-native-library android:name="libcdsprpc.so" android:required="false" />"#
|
||||
),
|
||||
"libcdsprpc.so must be declared, and not required"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_gallery_can_open_a_photograph_in_this_app() {
|
||||
let manifest = manifest();
|
||||
|
||||
@@ -412,6 +412,12 @@ struct Cache {
|
||||
/// still reads.
|
||||
#[serde(default)]
|
||||
refused: BTreeSet<String>,
|
||||
/// Probes run under this fingerprint (`probe::run`): a fall-back to the
|
||||
/// CPU is re-probed until there have been `RETRIES`. Defaulted, so a
|
||||
/// cache from 0.22.0 or before — which may hold exactly such a verdict —
|
||||
/// probes again.
|
||||
#[serde(default)]
|
||||
attempts: u32,
|
||||
}
|
||||
|
||||
struct State {
|
||||
|
||||
@@ -31,6 +31,38 @@ fn ladder(ceiling: Option<Rung>) -> Vec<Rung> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Probes under one fingerprint that may end on the CPU after an
|
||||
/// accelerator failed or lost, before that answer is kept.
|
||||
const RETRIES: u32 = 3;
|
||||
|
||||
/// What a cached probe result is good for.
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum Reuse {
|
||||
/// Use it as it is.
|
||||
Keep,
|
||||
/// Probe again: it fell back to the CPU after this many probes.
|
||||
Again(u32),
|
||||
/// Another device, runtime or model set: probe from the start.
|
||||
Fresh,
|
||||
}
|
||||
|
||||
/// The CPU because an accelerator failed or lost is asked again on the next
|
||||
/// launches, a few times: a failure can be a moment's (QNN could not create
|
||||
/// its device on 0.22.0's first launch after the update), and keeping it for
|
||||
/// good left the tablet's every model on the CPU. Bounded, so a wedged
|
||||
/// driver costs a few launches, not all.
|
||||
fn reuse(cached: &Cache, fingerprint: &str) -> Reuse {
|
||||
if cached.fingerprint != fingerprint || cached.rung.is_none() {
|
||||
return Reuse::Fresh;
|
||||
}
|
||||
let fell_back = cached.rung == Some(Rung::Cpu) && !cached.failed.is_empty();
|
||||
if fell_back && cached.attempts < RETRIES {
|
||||
Reuse::Again(cached.attempts)
|
||||
} else {
|
||||
Reuse::Keep
|
||||
}
|
||||
}
|
||||
|
||||
/// The probe body. Sets the cache and clears `probing` when done; never
|
||||
/// panics out, because a failed probe is a result (the floor) and not an
|
||||
/// error.
|
||||
@@ -38,20 +70,33 @@ pub fn run(runtime: Runtime) {
|
||||
let cfg = state().lock().unwrap().config.clone();
|
||||
let fingerprint = fingerprint(&runtime, &cfg);
|
||||
|
||||
let mut attempts = 0;
|
||||
if let Some(cached) = read_cache(&cfg) {
|
||||
if cached.fingerprint == fingerprint && cached.rung.is_some() {
|
||||
log::info!(
|
||||
"inference: cached selection {} ({})",
|
||||
cached.rung.unwrap().label(),
|
||||
cached.reason
|
||||
);
|
||||
finish(cached);
|
||||
return;
|
||||
match reuse(&cached, &fingerprint) {
|
||||
Reuse::Keep => {
|
||||
log::info!(
|
||||
"inference: cached selection {} ({})",
|
||||
cached.rung.map_or("?", |r| r.label()),
|
||||
cached.reason
|
||||
);
|
||||
finish(cached);
|
||||
return;
|
||||
}
|
||||
Reuse::Again(n) => {
|
||||
attempts = n;
|
||||
log::info!(
|
||||
"inference: probing again after falling back to the CPU ({}), attempt {} of {RETRIES}",
|
||||
cached.reason,
|
||||
n + 1
|
||||
);
|
||||
}
|
||||
Reuse::Fresh => {}
|
||||
}
|
||||
}
|
||||
|
||||
let mut cache = Cache {
|
||||
fingerprint,
|
||||
attempts: attempts + 1,
|
||||
..Cache::default()
|
||||
};
|
||||
|
||||
@@ -212,8 +257,8 @@ fn time_rung(
|
||||
}
|
||||
let bytes = std::fs::read(&path).map_err(|e| e.to_string())?;
|
||||
let started = Instant::now();
|
||||
let mut session =
|
||||
crate::session::build(rung, role, &bytes, cfg).map_err(|e| first_line(&e.to_string()))?;
|
||||
let mut session = crate::session::build_probe(rung, role, &bytes, cfg)
|
||||
.map_err(|e| first_line(&e.to_string()))?;
|
||||
log::info!(
|
||||
"inference: {} session built in {:.1} s",
|
||||
rung.label(),
|
||||
@@ -494,4 +539,34 @@ mod tests {
|
||||
died_inside(&cfg, "probe TensorRT", 2);
|
||||
assert_eq!(attempt(&cfg, "probe CUDA", || 7), Ok(7));
|
||||
}
|
||||
|
||||
/// The tablet's cache after 0.22.0's first launch, as 0.22.0 wrote it:
|
||||
/// no `attempts`, the Hexagon "rejected", the CPU selected.
|
||||
const TABLET: &str = r#"{"fingerprint":"f","rung":"Cpu","reason":"Hexagon NPU 28.5 ms, slower than the CPU's 19.4 ms","compiled":[],"failed":[["Hexagon","28.5 ms, slower than the CPU's 19.4 ms"]]}"#;
|
||||
|
||||
#[test]
|
||||
fn a_fall_back_to_the_cpu_is_probed_again_a_few_times() {
|
||||
let mut cache: Cache = serde_json::from_str(TABLET).unwrap();
|
||||
assert_eq!(cache.attempts, 0, "a 0.22.0 cache reads as never retried");
|
||||
assert_eq!(reuse(&cache, "f"), Reuse::Again(0));
|
||||
cache.attempts = RETRIES - 1;
|
||||
assert_eq!(reuse(&cache, "f"), Reuse::Again(RETRIES - 1));
|
||||
cache.attempts = RETRIES;
|
||||
assert_eq!(reuse(&cache, "f"), Reuse::Keep, "then it is kept");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_accelerator_chosen_or_a_cpu_only_device_is_kept() {
|
||||
let mut cache: Cache = serde_json::from_str(TABLET).unwrap();
|
||||
cache.rung = Some(Rung::Hexagon);
|
||||
assert_eq!(reuse(&cache, "f"), Reuse::Keep);
|
||||
cache.rung = Some(Rung::Cpu);
|
||||
cache.failed.clear();
|
||||
assert_eq!(
|
||||
reuse(&cache, "f"),
|
||||
Reuse::Keep,
|
||||
"nothing failed: the only rung"
|
||||
);
|
||||
assert_eq!(reuse(&cache, "other"), Reuse::Fresh);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,30 @@ use crate::{Config, Role, Rung};
|
||||
/// its clock instead (§4): a provider that hands real work to the CPU is
|
||||
/// slower than the CPU floor and rejected by the same measurement.
|
||||
pub fn build(rung: Rung, role: Role, bytes: &[u8], cfg: &Config) -> ort::Result<Session> {
|
||||
build_with(rung, role, bytes, cfg, false)
|
||||
}
|
||||
|
||||
/// [`build`] for the probe: on the Hexagon, a session that cannot put the
|
||||
/// whole graph on the NPU fails instead of running the rest on the CPU.
|
||||
///
|
||||
/// The probe times a rung by its session, and a QNN provider that could not
|
||||
/// create its device still builds one — with every node on the CPU behind
|
||||
/// it. 0.22.0's first launch on the tablet timed that (28.5 ms against the
|
||||
/// CPU's own 19.4) and put every model on the CPU. Only the probe is strict:
|
||||
/// some shipped graphs keep a few nodes on the CPU on purpose
|
||||
/// (`tools/quantise-models.py`, `float_nodes`), and the probe's detector is
|
||||
/// not one of them.
|
||||
pub fn build_probe(rung: Rung, role: Role, bytes: &[u8], cfg: &Config) -> ort::Result<Session> {
|
||||
build_with(rung, role, bytes, cfg, rung == Rung::Hexagon)
|
||||
}
|
||||
|
||||
fn build_with(
|
||||
rung: Rung,
|
||||
role: Role,
|
||||
bytes: &[u8],
|
||||
cfg: &Config,
|
||||
strict: bool,
|
||||
) -> ort::Result<Session> {
|
||||
// No optimisation level named. ONNX Runtime's default is already its
|
||||
// fullest, and on tract any level but "disabled" means `into_optimized`,
|
||||
// whose optimiser divides by zero inside yolo26n-seg (tract-data
|
||||
@@ -22,6 +46,9 @@ pub fn build(rung: Rung, role: Role, bytes: &[u8], cfg: &Config) -> ort::Result<
|
||||
if crate::api::runtime().is_native() {
|
||||
b = with_runtime_log(b)?;
|
||||
}
|
||||
if strict {
|
||||
b = b.with_config_entry("session.disable_cpu_ep_fallback", "1")?;
|
||||
}
|
||||
// A Hexagon session loads the compiled context when there is one and
|
||||
// compiles it from the model when there is not; the engine thread is
|
||||
// what makes the second case rare (§6).
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
# makes `makepkg -si` in this directory install what you are actually working
|
||||
# on. Swap `source` for a tagged tarball when there is something to release.
|
||||
pkgname=darkroom
|
||||
pkgver=0.22.0
|
||||
pkgver=0.22.1
|
||||
# Back to 1 with the version: a new pkgver is a new archive name, so there is
|
||||
# nothing for makepkg to reuse and nothing for a release number to disambiguate.
|
||||
pkgrel=1
|
||||
|
||||
Reference in New Issue
Block a user