Hash a model's bytes once, at open, not on every acquire
A border fill acquires the filler once a tile, and each acquire hashed the 28 MB model twice — 60 ms a tile, a third of the tile's run on a throttled TensorRT. The Model keeps its hash from open.
This commit is contained in:
@@ -29,7 +29,12 @@ pub fn hash(bytes: &[u8]) -> u64 {
|
||||
|
||||
/// The cache entry for `bytes` compiled on `rung`.
|
||||
pub fn key(rung: Rung, bytes: &[u8]) -> String {
|
||||
format!("{}:{:016x}", rung.label(), hash(bytes))
|
||||
key_of(rung, hash(bytes))
|
||||
}
|
||||
|
||||
/// The same, from a hash already taken.
|
||||
pub fn key_of(rung: Rung, hash: u64) -> String {
|
||||
format!("{}:{:016x}", rung.label(), hash)
|
||||
}
|
||||
|
||||
/// Where QNN's compiled context for `bytes` lives.
|
||||
|
||||
@@ -185,6 +185,9 @@ pub struct Model {
|
||||
role: Role,
|
||||
form: Form,
|
||||
bytes: Arc<[u8]>,
|
||||
/// `engines::hash` of the bytes, taken once: an acquire per tile of a
|
||||
/// border fill must not hash 28 MB each time.
|
||||
hash: u64,
|
||||
}
|
||||
|
||||
/// A loaded session, held for one `run` and its output decoding.
|
||||
@@ -203,7 +206,7 @@ impl Model {
|
||||
/// one run; a scan and a develop click can want the same detector at
|
||||
/// once, and the second waits on the first.
|
||||
pub fn acquire(&self) -> Result<Acquired, Error> {
|
||||
acquire(self.role, self.form, &self.bytes)
|
||||
acquire(self.role, self.form, &self.bytes, self.hash)
|
||||
}
|
||||
|
||||
pub fn form(&self) -> Form {
|
||||
@@ -247,17 +250,17 @@ fn registry() -> &'static Mutex<Registry> {
|
||||
})
|
||||
}
|
||||
|
||||
fn acquire(role: Role, form: Form, bytes: &Arc<[u8]>) -> Result<Acquired, Error> {
|
||||
fn acquire(role: Role, form: Form, bytes: &Arc<[u8]>, hash: u64) -> Result<Acquired, Error> {
|
||||
api::ensure_installed();
|
||||
let (rung, cfg) = {
|
||||
let s = state().lock().unwrap();
|
||||
let selected = current_rung(&s);
|
||||
(
|
||||
effective_rung(&s, selected, role, form, bytes),
|
||||
effective_rung(&s, selected, role, form, hash),
|
||||
s.config.clone(),
|
||||
)
|
||||
};
|
||||
let key = format!("{role:?}:{}", engines::key(rung, bytes));
|
||||
let key = format!("{role:?}:{}", engines::key_of(rung, hash));
|
||||
|
||||
if let Some(entry) = registry().lock().unwrap().get(&key).cloned() {
|
||||
*entry.last_used.lock().unwrap() = Instant::now();
|
||||
@@ -456,20 +459,26 @@ pub fn form_suffix(form: Form) -> &'static str {
|
||||
/// this crate existed.
|
||||
pub fn open(role: Role, form: Form, bytes: &[u8]) -> Result<Model, Error> {
|
||||
let bytes: Arc<[u8]> = Arc::from(bytes);
|
||||
acquire(role, form, &bytes)?;
|
||||
Ok(Model { role, form, bytes })
|
||||
let hash = engines::hash(&bytes);
|
||||
acquire(role, form, &bytes, hash)?;
|
||||
Ok(Model {
|
||||
role,
|
||||
form,
|
||||
bytes,
|
||||
hash,
|
||||
})
|
||||
}
|
||||
|
||||
/// Where a request lands: the selected rung unless the role's precision rule,
|
||||
/// the form on offer, or a missing engine says one lower (§6 step 4).
|
||||
fn effective_rung(s: &State, selected: Rung, role: Role, form: Form, bytes: &[u8]) -> Rung {
|
||||
fn effective_rung(s: &State, selected: Rung, role: Role, form: Form, hash: u64) -> Rung {
|
||||
let mut rung = selected;
|
||||
if !rung.serves(role) || rung.form(role) != form {
|
||||
// The embedder on a Hexagon device, or an f32 detector where the int8
|
||||
// sibling was missing: neither can go to the NPU.
|
||||
rung = rung.fallback();
|
||||
}
|
||||
if rung.compiles() && !s.cache.compiled.contains(&engines::key(rung, bytes)) {
|
||||
if rung.compiles() && !s.cache.compiled.contains(&engines::key_of(rung, hash)) {
|
||||
rung = rung.fallback();
|
||||
}
|
||||
rung
|
||||
@@ -570,16 +579,34 @@ mod tests {
|
||||
wanted: 0,
|
||||
};
|
||||
assert_eq!(
|
||||
effective_rung(&s, Rung::Hexagon, Role::Embedder, Form::F32, b""),
|
||||
effective_rung(
|
||||
&s,
|
||||
Rung::Hexagon,
|
||||
Role::Embedder,
|
||||
Form::F32,
|
||||
engines::hash(b"")
|
||||
),
|
||||
Rung::Cpu
|
||||
);
|
||||
assert_eq!(
|
||||
effective_rung(&s, Rung::Hexagon, Role::Detector, Form::F32, b""),
|
||||
effective_rung(
|
||||
&s,
|
||||
Rung::Hexagon,
|
||||
Role::Detector,
|
||||
Form::F32,
|
||||
engines::hash(b"")
|
||||
),
|
||||
Rung::Cpu
|
||||
);
|
||||
// An int8 detector whose context is not compiled yet: also the CPU.
|
||||
assert_eq!(
|
||||
effective_rung(&s, Rung::Hexagon, Role::Detector, Form::Int8, b""),
|
||||
effective_rung(
|
||||
&s,
|
||||
Rung::Hexagon,
|
||||
Role::Detector,
|
||||
Form::Int8,
|
||||
engines::hash(b"")
|
||||
),
|
||||
Rung::Cpu
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user