Do not make the trustlet re-read the whole template on every claim
Selecting a group makes the trustlet reload every template in it from storage, and on this device that is 651276 bytes crossing the listener in chunks. Measured over ten verifications: eleven claims, eleven reloads, fifty-four chunk reads, twenty-six megabytes of round trips. All of it happens before the verify loop starts, so all of it lands in the latency a user feels while being invisible to the daemon's own timing -- which is how it survived this long. It is also unnecessary. The trustlet holds templates in memory once loaded; a successful authentication on stock produces no storage callbacks at all. A group that is already active does not need selecting again, so a repeat claim now answers from what the last real selection reported. Enrolment forces a real selection, because it adds a template and the reload is the point. Measured after: two claims, one real selection, one skipped, and the chunk reads drop from five per claim to two for the pair.
This commit is contained in:
parent
eb50e5b6fb
commit
231a1860ac
1 changed files with 25 additions and 3 deletions
|
|
@ -1206,8 +1206,25 @@ public:
|
|||
|
||||
// Select a group and count what loads. A template reload needs the init
|
||||
// chain to have run first -- Start() guarantees that.
|
||||
int SetActiveGroup(std::uint32_t gid) {
|
||||
// Selecting a group makes the trustlet RELOAD every template in it from
|
||||
// storage, and on this device that is 651276 bytes crossing the listener in
|
||||
// chunks -- about a megabyte of round trips per call. Measured 2026-09-05:
|
||||
// ten verifications cost eleven reloads and 26 MB, all of it before the
|
||||
// verify loop even starts, so all of it lands in the latency the user sees
|
||||
// while being invisible to the daemon's own timing.
|
||||
//
|
||||
// It is also unnecessary. The trustlet holds templates in memory once
|
||||
// loaded -- a successful authentication on stock produces no storage
|
||||
// callbacks at all -- so a group that is already active does not need
|
||||
// selecting again. `force` is for the cases that genuinely change the
|
||||
// store: an enrolment, or a template removed underneath us.
|
||||
int SetActiveGroup(std::uint32_t gid, bool force = false) {
|
||||
namespace ta = fingerprintd::ta;
|
||||
if (!force && gid == gid_ && templatesLoaded_ >= 0) {
|
||||
std::println("SET_ACTIVE_GROUP gid={} skipped (already active, {} template(s))",
|
||||
gid, templatesLoaded_);
|
||||
return templatesLoaded_;
|
||||
}
|
||||
auto sag = ta::BuildSetActiveGroup(gid, g_groupPath);
|
||||
std::println("SET_ACTIVE_GROUP gid={}", gid);
|
||||
auto g = SendCommand(app_, ta::Cmd::SetActiveGroup, sag);
|
||||
|
|
@ -1216,7 +1233,8 @@ public:
|
|||
Report(ta::Cmd::Enumerate, e);
|
||||
std::println(" templates loaded: {}", e.rc);
|
||||
gid_ = gid;
|
||||
return e.invoked ? e.rc : -1;
|
||||
templatesLoaded_ = e.invoked ? e.rc : -1;
|
||||
return templatesLoaded_;
|
||||
}
|
||||
|
||||
// ---- Enrolment
|
||||
|
|
@ -1244,7 +1262,8 @@ public:
|
|||
out.why = "store is read-only or RPMB writes disabled";
|
||||
return out;
|
||||
}
|
||||
if (gid != gid_) SetActiveGroup(gid);
|
||||
// An enrolment adds a template, so this one reloads for real.
|
||||
SetActiveGroup(gid, /*force*/ true);
|
||||
|
||||
// Stock's opening sequence. AUTHENTICATE is what arms the capture
|
||||
// session; CANCEL and RESET_LOCKOUT bracket it.
|
||||
|
|
@ -1755,6 +1774,9 @@ private:
|
|||
Sensor sensor_;
|
||||
fingerprintd::engine::Baseline baseline_;
|
||||
std::uint32_t gid_ = 0xFFFFFFFF;
|
||||
// What the last real SET_ACTIVE_GROUP reported, so a repeat claim can be
|
||||
// answered without making the trustlet re-read the store. -1 = unknown.
|
||||
int templatesLoaded_ = -1;
|
||||
// Set when a fold succeeded; cleared by the save.
|
||||
bool templateDirty_ = false;
|
||||
// Frames folded during the verify loop itself, carried into the harvest so
|
||||
|
|
|
|||
Loading…
Reference in a new issue