pub struct Registry { /* private fields */ }Expand description
Parent and child levels use this exact type. 父级和子级使用完全相同的类型。
Implementations§
Source§impl Registry
impl Registry
Sourcepub fn overlay(
&self,
plan: &GraftPlan,
external: &Registry,
) -> Result<Registry, Box<RegistryError>>
pub fn overlay( &self, plan: &GraftPlan, external: &Registry, ) -> Result<Registry, Box<RegistryError>>
Build an effective tree by overlaying external graft implementations.
Neither self nor external is moved or edited. Each cut addresses a
logical path in the base tree; the selected external face occupies that
slot while the target’s untouched siblings and child registry remain.
从外部 graft 实现生成有效注册树;不会移动或编辑原树、外部树。每个 cut
指向原树逻辑路径,外部实现只覆盖该槽位,兄弟和未覆盖子树继续继承。
Sourcepub fn overlay_static(
&self,
cuts: &[StaticGraftCut],
external: &Registry,
) -> Result<Registry, Box<RegistryError>>
pub fn overlay_static( &self, cuts: &[StaticGraftCut], external: &Registry, ) -> Result<Registry, Box<RegistryError>>
Apply build-captured selectors directly from read-only data.
This skips GraftPlan, Vec, and selector String construction. The
returned effective Registry remains a runtime object because an
external implementation may be loaded after the binary was built.
直接应用构建阶段捕获的只读 selector;不会构造 GraftPlan、Vec 或
selector String。由于外部实现可能在二进制生成后才加载,返回的有效
Registry 仍属于运行时对象。
Source§impl Registry
impl Registry
Sourcepub fn overlay_recorded(
&self,
records: &[RecordedGraft],
declared: &[StaticGraftCut],
external: &Registry,
) -> Result<RecordedOverlay, Box<RegistryError>>
pub fn overlay_recorded( &self, records: &[RecordedGraft], declared: &[StaticGraftCut], external: &Registry, ) -> Result<RecordedOverlay, Box<RegistryError>>
Apply graft records over the declarations that keep their slots alive. 在这些保持槽位活着的声明之上施加嫁接记录。
Precedence policy / 优先级策略:
The record is the newest, most specific artifact and the build is
explicitly written never to apply it, so it wins over a string-form
declaration (StaticGraftCut::cut() is CutTarget::Path) and reports
RecordReport::DeclarationOverridden. A typed-form declaration
(CutTarget::Id, emitted from cut(...)) is the host saying “this exact
linked crate face”; the compiler resolved it and the binary linked it, so
a text file must not defeat it: the declaration stays final and the
record is reported with RecordReport::TypedDeclarationKept. A record
whose selector the external registry cannot resolve falls back to the
declaration and reports RecordReport::RecordSelectorUnresolved, so a
bad record can never break a graft the declaration could satisfy.
记录是最新、最具体的产物,而构建被明确写成永不应用它,因此它胜过字符串形式
声明(StaticGraftCut::cut() 为 CutTarget::Path),并报告
RecordReport::DeclarationOverridden。类型化形式声明(CutTarget::Id,
由 cut(...) 发射)是宿主在说“就是这个已链接的 crate 注册面”;编译器解析了它、
二进制链接了它,因此文本文件不得击败它:声明保持最终,记录以
RecordReport::TypedDeclarationKept 报告。外部注册机解析不出记录选择器时回退
到声明并报告 RecordReport::RecordSelectorUnresolved,坏记录因此永远不会破坏
声明本可满足的嫁接。
Why the obvious approach is wrong / 显而易见的做法为何不对:
Two obvious readings both fail. “Let the record always win” lets an
unreviewed, machine-local .nichlink/ file re-route shipped behavior and
defeats a linked, compiler-resolved face. “Let the declaration always
win” leaves the record’s graft with no production reader at all — the
feature is wired but unobservable. Splitting by declaration form keeps the
dynamic-by-name trust the string form already grants
(resolution.rs::resolve_node) while refusing to defeat the typed form.
两种直觉读法都不成立。“总让记录赢”会让未经审查、机器本地的 .nichlink/ 文件
重新路由已发布行为,并击败已链接、编译器解析过的注册面;“总让声明赢”则让记录的
graft 完全没有生产读者——功能接了线却不可观测。按声明形式区分,既保留了字符串
形式本就授予的“按名字动态解析”的信任(resolution.rs::resolve_node),又拒绝
击败类型化形式。
Boundary / 边界: a record can never resurrect a pruned slot (the declared
set is the arbiter), can never select a face the loaded external registry
lacks, and is reported on every overlay. Hard failures from
overlay_cuts (ambiguous selector, contract mismatch, duplicate cut) stay
byte-identical to an ordinary overlay because this function delegates to
the same private path with one GraftPlan.
边界:记录永远不能复活被剪掉的槽位(声明的集合才是仲裁者),永远不能选中已加载
外部注册机里没有的面,并且每次 overlay 都会报告。overlay_cuts 的硬失败
(选择器歧义、合同不匹配、重复切口)与普通 overlay 逐字节相同,因为本函数用同一
份 GraftPlan 委派给同一条私有路径。
Pinned by record_tests::a_string_declaration_yields_to_the_record,
record_tests::a_typed_declaration_stays_final,
record_tests::an_unresolved_record_selector_falls_back_to_the_declaration,
record_tests::granularity_is_overridden_as_one_atomic_record, and
run_method/tests/graft_record.rs::a_record_on_disk_reaches_overlay.
由 record_tests::a_string_declaration_yields_to_the_record、
record_tests::a_typed_declaration_stays_final、
record_tests::an_unresolved_record_selector_falls_back_to_the_declaration、
record_tests::granularity_is_overridden_as_one_atomic_record 与
run_method/tests/graft_record.rs::a_record_on_disk_reaches_overlay 钉住。
Source§impl Registry
impl Registry
Sourcepub fn resolve_record(
&self,
record: &RecordedGraft,
) -> Result<ResolvedRecord, Box<RegistryError>>
pub fn resolve_record( &self, record: &RecordedGraft, ) -> Result<ResolvedRecord, Box<RegistryError>>
Reconcile one record’s stored identity and stored path against this tree. 把一条记录存储的身份与路径同本树对账。
The record is applied at the face’s current logical path
(self.path_for), never at the stored target_path.
记录施加在注册面的当前逻辑路径(self.path_for)上,而绝不是存储的
target_path 上。
Why the obvious approach is wrong / 显而易见的做法为何不对:
The intuitive reading is “the record already stores target_path, so use
it as the cut selector”. That text was written when the plan was created,
and a GraftCut.cut is a string resolve_path must match exactly —
there is no leniency for a renamed face. A record that survives one file
rename would therefore miss the very slot it still names by identity, and
the host would silently overlay nothing. The identity is the durable half;
the path is the human half. So the path is re-derived from the identity,
and the stored text is only used when the identity no longer resolves.
直觉读法是“记录本来就存了 target_path,拿它当切口选择器即可”。那段文本是
计划创建时写下的,而 GraftCut.cut 是 resolve_path 必须精确匹配的字符串,
对改过名的注册面没有任何宽容。于是记录只要经历一次文件改名,就会错过它仍以身份
命名的那个槽位,宿主便静默地什么都没覆盖。身份是耐久的一半,路径是给人看的一半。
因此路径从身份重新推导,存储的文本只在身份不再可解析时才使用。
Boundary / 边界: identity and path agreeing is clean; one missing is drift
(applied, reported); both missing is Unkept (skipped, reported); each of
the two silent-intent-change cases is an Err — identity and path naming
different faces, and a directory selector disagreeing with the plan’s
graft — because picking either candidate would silently change the
author’s intent.
边界:身份与路径一致为干净;缺一个为漂移(应用并报告);两个都缺为 Unkept
(跳过并报告);两种“会静默改变作者本意“的情形都是 Err——身份与路径指向不同的
面,以及目录选择器与计划里的 graft 不一致——因为任选其一都会静默改变作者的
本意。
Pinned by record_tests::identity_and_path_agree_resolves_to_the_target,
record_tests::a_missing_identity_resolves_by_path_with_drift,
record_tests::contradictory_identity_and_path_are_refused,
record_tests::a_record_with_no_live_slot_is_skipped_not_fatal, and
record_tests::a_directory_that_disagrees_with_its_plan_is_refused.
由 record_tests::identity_and_path_agree_resolves_to_the_target、
record_tests::a_missing_identity_resolves_by_path_with_drift、
record_tests::contradictory_identity_and_path_are_refused、
record_tests::a_record_with_no_live_slot_is_skipped_not_fatal 与
record_tests::a_directory_that_disagrees_with_its_plan_is_refused 钉住。
Source§impl Registry
impl Registry
Sourcepub fn validate_snapshot_migration(
&self,
current: NodeId,
replacements: Vec<RegistrationSnapshot>,
) -> Result<(), Box<RegistryError>>
pub fn validate_snapshot_migration( &self, current: NodeId, replacements: Vec<RegistrationSnapshot>, ) -> Result<(), Box<RegistryError>>
Validate a source-path migration by replacing one whole subtree in a staged registry. The live registry is untouched. 在暂存注册树中校验整个源码路径子树迁移,实时注册树不会被修改。
Sourcepub fn validate_replacement(
&self,
current: NodeId,
info: RegistrationInfo,
) -> Result<(), Box<RegistryError>>
pub fn validate_replacement( &self, current: NodeId, info: RegistrationInfo, ) -> Result<(), Box<RegistryError>>
Validate an authored replacement without committing it, by way of its snapshot form. 校验作者侧替换但不提交,经由其快照形式完成。
Sourcepub fn validate_snapshot_replacement(
&self,
current: NodeId,
info: RegistrationSnapshot,
) -> Result<(), Box<RegistryError>>
pub fn validate_snapshot_replacement( &self, current: NodeId, info: RegistrationSnapshot, ) -> Result<(), Box<RegistryError>>
Validate an authored replacement without committing it. 校验 authored 替换,但不修改当前注册树。
Sourcepub fn apply_snapshot_replacement(
&mut self,
current: NodeId,
info: RegistrationSnapshot,
) -> Result<(), Box<RegistryError>>
pub fn apply_snapshot_replacement( &mut self, current: NodeId, info: RegistrationSnapshot, ) -> Result<(), Box<RegistryError>>
Commit one already-authored replacement after validating it against the same structural and connector rules used by registration. 使用与注册相同的结构和连接校验,提交一个已经生成的替换快照。
Source§impl Registry
impl Registry
Sourcepub fn storage_stats(&self) -> RegistryStorageStats
pub fn storage_stats(&self) -> RegistryStorageStats
Count how many pages and entries this registry tree occupies. 统计该注册树占用的页数与条目数。
Examples found in repository?
93fn main() {
94 let sizes = std::env::args()
95 .skip(1)
96 .map(|value| value.parse::<usize>().expect("size must be an integer"))
97 .collect::<Vec<_>>();
98 let sizes = if sizes.is_empty() {
99 vec![10_000, 100_000]
100 } else {
101 sizes
102 };
103 println!(
104 "nodes\tregister_ms\tregister_budget_ms\tindex_ms\tindex_budget_ms\tentries\tpages\tstatic_face_bytes"
105 );
106 // 40 µs and 20 µs per node: roughly eight times the 5.2 µs and 2.6 µs measured
107 // for 100 000 nodes when this budget was added.
108 // 每节点 40 µs 与 20 µs:约等于加入本预算时 100 000 个节点实测 5.2 µs 与 2.6 µs 的八倍。
109 let register_ceiling = ceiling("NICHLINK_SCALE_REGISTER_US", 40);
110 let index_ceiling = ceiling("NICHLINK_SCALE_INDEX_US", 20);
111 for size in sizes {
112 let namespace = format!("scale-{size}");
113 let root = Registry::root_for_namespace(FrameworkId::new("nichlink.scale"), &namespace);
114 let parent = root_node_id(&namespace);
115 let submissions = (0..size)
116 .map(|index| snapshot(&namespace, index, parent))
117 .collect::<Vec<_>>();
118 let mut registry = root;
119 let register_start = Instant::now();
120 registry
121 .register_snapshot_batch(submissions)
122 .expect("generated scale batch must register");
123 let register_ms = register_start.elapsed().as_millis();
124 let index_start = Instant::now();
125 let index = registry.index();
126 let index_ms = index_start.elapsed().as_millis();
127 let stats = registry.storage_stats();
128 let register_budget_ms = register_ceiling * size as u128 / 1000;
129 let index_budget_ms = index_ceiling * size as u128 / 1000;
130 println!(
131 "{size}\t{register_ms}\t{register_budget_ms}\t{index_ms}\t{index_budget_ms}\t{}\t{}\t{}",
132 index.len(),
133 stats.pages,
134 size * std::mem::size_of::<nichlink::StaticFace>()
135 );
136 assert!(
137 register_ms <= register_budget_ms,
138 "registering {size} nodes took {register_ms} ms, over the {register_budget_ms} ms budget ({register_ceiling} µs per node); raise NICHLINK_SCALE_REGISTER_US if this machine is simply slower, and update docs/performance-baseline.md if the baseline moved"
139 );
140 assert!(
141 index_ms <= index_budget_ms,
142 "indexing {size} nodes took {index_ms} ms, over the {index_budget_ms} ms budget ({index_ceiling} µs per node); raise NICHLINK_SCALE_INDEX_US if this machine is simply slower, and update docs/performance-baseline.md if the baseline moved"
143 );
144 let extra = snapshot(&namespace, size, parent);
145 registry
146 .register_snapshot_batch([extra])
147 .expect("incremental transaction must register");
148 assert_eq!(registry.index().len(), size + 2);
149 }
150}Sourcepub fn index(&self) -> RegistryIndex
pub fn index(&self) -> RegistryIndex
Build a flattened lookup index over this registry and every descendant. 为该注册机及其全部后代构建扁平查找索引。
Examples found in repository?
93fn main() {
94 let sizes = std::env::args()
95 .skip(1)
96 .map(|value| value.parse::<usize>().expect("size must be an integer"))
97 .collect::<Vec<_>>();
98 let sizes = if sizes.is_empty() {
99 vec![10_000, 100_000]
100 } else {
101 sizes
102 };
103 println!(
104 "nodes\tregister_ms\tregister_budget_ms\tindex_ms\tindex_budget_ms\tentries\tpages\tstatic_face_bytes"
105 );
106 // 40 µs and 20 µs per node: roughly eight times the 5.2 µs and 2.6 µs measured
107 // for 100 000 nodes when this budget was added.
108 // 每节点 40 µs 与 20 µs:约等于加入本预算时 100 000 个节点实测 5.2 µs 与 2.6 µs 的八倍。
109 let register_ceiling = ceiling("NICHLINK_SCALE_REGISTER_US", 40);
110 let index_ceiling = ceiling("NICHLINK_SCALE_INDEX_US", 20);
111 for size in sizes {
112 let namespace = format!("scale-{size}");
113 let root = Registry::root_for_namespace(FrameworkId::new("nichlink.scale"), &namespace);
114 let parent = root_node_id(&namespace);
115 let submissions = (0..size)
116 .map(|index| snapshot(&namespace, index, parent))
117 .collect::<Vec<_>>();
118 let mut registry = root;
119 let register_start = Instant::now();
120 registry
121 .register_snapshot_batch(submissions)
122 .expect("generated scale batch must register");
123 let register_ms = register_start.elapsed().as_millis();
124 let index_start = Instant::now();
125 let index = registry.index();
126 let index_ms = index_start.elapsed().as_millis();
127 let stats = registry.storage_stats();
128 let register_budget_ms = register_ceiling * size as u128 / 1000;
129 let index_budget_ms = index_ceiling * size as u128 / 1000;
130 println!(
131 "{size}\t{register_ms}\t{register_budget_ms}\t{index_ms}\t{index_budget_ms}\t{}\t{}\t{}",
132 index.len(),
133 stats.pages,
134 size * std::mem::size_of::<nichlink::StaticFace>()
135 );
136 assert!(
137 register_ms <= register_budget_ms,
138 "registering {size} nodes took {register_ms} ms, over the {register_budget_ms} ms budget ({register_ceiling} µs per node); raise NICHLINK_SCALE_REGISTER_US if this machine is simply slower, and update docs/performance-baseline.md if the baseline moved"
139 );
140 assert!(
141 index_ms <= index_budget_ms,
142 "indexing {size} nodes took {index_ms} ms, over the {index_budget_ms} ms budget ({index_ceiling} µs per node); raise NICHLINK_SCALE_INDEX_US if this machine is simply slower, and update docs/performance-baseline.md if the baseline moved"
143 );
144 let extra = snapshot(&namespace, size, parent);
145 registry
146 .register_snapshot_batch([extra])
147 .expect("incremental transaction must register");
148 assert_eq!(registry.index().len(), size + 2);
149 }
150}Source§impl Registry
impl Registry
Sourcepub fn health_check(
&self,
node: NodeId,
value: &RuntimeValue,
call_path: Vec<CallSite>,
) -> Result<(), Box<RegistryError>>
pub fn health_check( &self, node: NodeId, value: &RuntimeValue, call_path: Vec<CallSite>, ) -> Result<(), Box<RegistryError>>
Validate one observed runtime value against the checks a registry face declares. 用注册面声明的检查校验一个观测到的运行期取值。
This is a host API: the kernel never observes a value, so the caller owns the boundary.
Call it where a host-side value crosses into a plugin or consumer, with the NodeId of
the face whose runtime_checks: list applies, the RuntimeValue the host built, and the
current call path.
这是宿主 API:内核从不观测取值,边界由调用方拥有。请在宿主侧取值跨入插件或消费者的
那一点调用它,传入适用该取值的注册面 NodeId、宿主构造的 RuntimeValue 与当前调用路径。
call_path is CallTrace::current_path() when a trace is active; a host that does not
trace passes Vec::new(). The kernel never synthesizes a call path.
有活动 trace 时传 CallTrace::current_path();不接 trace 的宿主传 Vec::new()。
内核从不合成调用路径。
An empty runtime_checks: list passes for any value. On failure the error aggregates one
child per failed check, each carrying the face’s declaration source and the value’s
provenance; render it with Display. Presence or absence is the host’s decision signal:
the registry does not choose whether a failed check is fatal.
runtime_checks: 为空的面对任何取值都通过。失败时按每条失败的检查聚合子错误,各自携带
声明源与来源链;用 Display 渲染。存在与否就是宿主的决策信号:注册机不替宿主决定是否致命。
The aggregate keeps the four essential facts readable: node(), path(), source(),
and message(), plus children() with one entry per failed check, so a host that has to
branch on which check failed does not parse Display.
聚合错误保留四项必要事实的可读读取器:node()、path()、source()、message(),
以及每条失败检查一项的 children();因此必须按“哪条检查失败”分支的宿主无需解析
Display。
let value = RuntimeValue::number(0.5, Provenance::default().push(node, "Slider", "measure", "0.5"));
if let Err(error) = registry.health_check(node, &value, Vec::new()) {
// The aggregate names the face and path; each child names the failed check.
eprintln!("{} {} {}: {}", error.node(), error.path(), error.source(), error.message());
for failure in error.children() {
eprintln!("{} [{}]", failure.message(), failure.source());
}
}Sourcepub fn dump(&self) -> String
pub fn dump(&self) -> String
Render the registration tree as a human-readable multi-line report. 把注册树渲染成多行的人类可读报告。
Sourcepub fn dump_effective(
&self,
cuts: &[StaticGraftCut],
external: &Registry,
) -> Result<String, Box<RegistryError>>
pub fn dump_effective( &self, cuts: &[StaticGraftCut], external: &Registry, ) -> Result<String, Box<RegistryError>>
Render the effective tree an overlay produces, without mutating either input. 渲染一次覆盖产生的有效树,不修改任一输入。
The overlay result used to have no way out of the library except the
caller reading fields off the returned Registry; this is the output
path for the same question Registry::dump answers about a base tree.
A host that holds the real base_registry() and external_registry()
calls this with the build-captured builtin_static_plan().grafts(); a
command outside the host cannot, because neither registry is linked into
it.
覆盖结果过去除了调用方读取返回的 Registry 字段外没有出口;这就是
Registry::dump 对基树回答的同一个问题的输出路径。持有真实
base_registry() 与 external_registry() 的宿主用它搭配构建捕获的
builtin_static_plan().grafts();宿主之外的命令做不到,因为两棵注册树都没有
链接进它。
Source§impl Registry
impl Registry
Sourcepub fn path(&self) -> &str
pub fn path(&self) -> &str
The logical path this registry occupies in the tree. 该注册机在树中占据的逻辑路径。
Sourcepub fn registry_count(&self) -> usize
pub fn registry_count(&self) -> usize
Number of registries in this subtree, including this one. 本子树中的注册机数量,含自身。
Sourcepub fn node_count(&self) -> usize
pub fn node_count(&self) -> usize
Number of faces registered below this registry. 本注册机之下注册的面数量。
Sourcepub fn check_count(&self) -> usize
pub fn check_count(&self) -> usize
Total runtime checks declared below this registry. 本注册机之下声明的运行期检查总数。
Source§impl Registry
impl Registry
Sourcepub fn port_index(&self) -> PortIndex
pub fn port_index(&self) -> PortIndex
Build the port surface of this tree. 构建这棵树的端口面。
The walk is the only part that needs the tree; every rule lives in
PortIndex, so a caller can also assemble an index from declarations
it already has (the build does) without walking anything.
只有遍历需要树;所有规则都住在 PortIndex 里,因此调用方也可以用手上已有的声明直接
组装索引(构建步骤就是这样),不必遍历。
Source§impl Registry
impl Registry
Sourcepub fn registry(&self, wanted: NodeId) -> Option<&Registry>
pub fn registry(&self, wanted: NodeId) -> Option<&Registry>
Find the registry with this identity anywhere in the subtree. 在本子树中查找具有该身份的注册机。
Sourcepub fn find(&self, id: NodeId) -> Option<&RegistrationSnapshot>
pub fn find(&self, id: NodeId) -> Option<&RegistrationSnapshot>
Look up the registration snapshot of one face by identity. 按身份查找某个注册面的注册快照。
Sourcepub fn path_for(&self, id: NodeId) -> Option<String>
pub fn path_for(&self, id: NodeId) -> Option<String>
Return the current logical path of a face, derived from the live tree. 返回某个注册面的当前逻辑路径,由现存树推导。
Sourcepub fn node_path(&self, id: NodeId) -> Option<Vec<NodeId>>
pub fn node_path(&self, id: NodeId) -> Option<Vec<NodeId>>
Return the identity chain from this registry’s root down to a face. 返回从本注册机根到某个注册面的身份链。
Sourcepub fn find_kind(&self, kind: &str) -> Vec<&RegistrationSnapshot>
pub fn find_kind(&self, kind: &str) -> Vec<&RegistrationSnapshot>
Collect every face of one kind, in depth-first order. 按深度优先顺序收集某一 kind 的全部注册面。
Sourcepub fn find_where(
&self,
predicate: impl Fn(&RegistrationSnapshot) -> bool,
) -> Vec<&RegistrationSnapshot>
pub fn find_where( &self, predicate: impl Fn(&RegistrationSnapshot) -> bool, ) -> Vec<&RegistrationSnapshot>
Collect every face the predicate accepts, in depth-first order. 按深度优先顺序收集谓词接受的全部注册面。
Sourcepub fn depth_first(&self) -> Vec<&RegistrationSnapshot>
pub fn depth_first(&self) -> Vec<&RegistrationSnapshot>
Flatten the subtree into a depth-first list of registration snapshots. 把子树展平成深度优先的注册快照列表。
Source§impl Registry
impl Registry
Sourcepub fn register_batch<I>(
&mut self,
submissions: I,
) -> Result<(), Box<RegistryError>>where
I: IntoIterator<Item = RegistrationInfo>,
pub fn register_batch<I>(
&mut self,
submissions: I,
) -> Result<(), Box<RegistryError>>where
I: IntoIterator<Item = RegistrationInfo>,
Submit one batch atomically. Failure leaves the receiver unchanged. 一批提交作为原子事务处理,失败时接收者完全不变。
Sourcepub fn register_all(
&mut self,
registrations: &[RegistrationInfo],
) -> Result<(), Box<RegistryError>>
pub fn register_all( &mut self, registrations: &[RegistrationInfo], ) -> Result<(), Box<RegistryError>>
Register a borrowed slice of compiled declarations atomically. 原子注册一个借用的编译期声明切片。
Sourcepub fn register_snapshot_batch<I>(
&mut self,
submissions: I,
) -> Result<(), Box<RegistryError>>where
I: IntoIterator<Item = RegistrationSnapshot>,
pub fn register_snapshot_batch<I>(
&mut self,
submissions: I,
) -> Result<(), Box<RegistryError>>where
I: IntoIterator<Item = RegistrationSnapshot>,
Atomically attach file-backed snapshots without borrowing or leaking their metadata. 原子挂载文件快照,不借用也不泄漏快照中的元数据。
Examples found in repository?
93fn main() {
94 let sizes = std::env::args()
95 .skip(1)
96 .map(|value| value.parse::<usize>().expect("size must be an integer"))
97 .collect::<Vec<_>>();
98 let sizes = if sizes.is_empty() {
99 vec![10_000, 100_000]
100 } else {
101 sizes
102 };
103 println!(
104 "nodes\tregister_ms\tregister_budget_ms\tindex_ms\tindex_budget_ms\tentries\tpages\tstatic_face_bytes"
105 );
106 // 40 µs and 20 µs per node: roughly eight times the 5.2 µs and 2.6 µs measured
107 // for 100 000 nodes when this budget was added.
108 // 每节点 40 µs 与 20 µs:约等于加入本预算时 100 000 个节点实测 5.2 µs 与 2.6 µs 的八倍。
109 let register_ceiling = ceiling("NICHLINK_SCALE_REGISTER_US", 40);
110 let index_ceiling = ceiling("NICHLINK_SCALE_INDEX_US", 20);
111 for size in sizes {
112 let namespace = format!("scale-{size}");
113 let root = Registry::root_for_namespace(FrameworkId::new("nichlink.scale"), &namespace);
114 let parent = root_node_id(&namespace);
115 let submissions = (0..size)
116 .map(|index| snapshot(&namespace, index, parent))
117 .collect::<Vec<_>>();
118 let mut registry = root;
119 let register_start = Instant::now();
120 registry
121 .register_snapshot_batch(submissions)
122 .expect("generated scale batch must register");
123 let register_ms = register_start.elapsed().as_millis();
124 let index_start = Instant::now();
125 let index = registry.index();
126 let index_ms = index_start.elapsed().as_millis();
127 let stats = registry.storage_stats();
128 let register_budget_ms = register_ceiling * size as u128 / 1000;
129 let index_budget_ms = index_ceiling * size as u128 / 1000;
130 println!(
131 "{size}\t{register_ms}\t{register_budget_ms}\t{index_ms}\t{index_budget_ms}\t{}\t{}\t{}",
132 index.len(),
133 stats.pages,
134 size * std::mem::size_of::<nichlink::StaticFace>()
135 );
136 assert!(
137 register_ms <= register_budget_ms,
138 "registering {size} nodes took {register_ms} ms, over the {register_budget_ms} ms budget ({register_ceiling} µs per node); raise NICHLINK_SCALE_REGISTER_US if this machine is simply slower, and update docs/performance-baseline.md if the baseline moved"
139 );
140 assert!(
141 index_ms <= index_budget_ms,
142 "indexing {size} nodes took {index_ms} ms, over the {index_budget_ms} ms budget ({index_ceiling} µs per node); raise NICHLINK_SCALE_INDEX_US if this machine is simply slower, and update docs/performance-baseline.md if the baseline moved"
143 );
144 let extra = snapshot(&namespace, size, parent);
145 registry
146 .register_snapshot_batch([extra])
147 .expect("incremental transaction must register");
148 assert_eq!(registry.index().len(), size + 2);
149 }
150}Source§impl Registry
impl Registry
Sourcepub fn root_for(framework: FrameworkId) -> Registry
pub fn root_for(framework: FrameworkId) -> Registry
Create a root for one framework namespace. 为一个框架命名空间创建根注册机。
Sourcepub fn root_for_namespace(
framework: FrameworkId,
namespace: impl Into<String>,
) -> Registry
pub fn root_for_namespace( framework: FrameworkId, namespace: impl Into<String>, ) -> Registry
Create an isolated root for one package or application namespace.
Examples found in repository?
93fn main() {
94 let sizes = std::env::args()
95 .skip(1)
96 .map(|value| value.parse::<usize>().expect("size must be an integer"))
97 .collect::<Vec<_>>();
98 let sizes = if sizes.is_empty() {
99 vec![10_000, 100_000]
100 } else {
101 sizes
102 };
103 println!(
104 "nodes\tregister_ms\tregister_budget_ms\tindex_ms\tindex_budget_ms\tentries\tpages\tstatic_face_bytes"
105 );
106 // 40 µs and 20 µs per node: roughly eight times the 5.2 µs and 2.6 µs measured
107 // for 100 000 nodes when this budget was added.
108 // 每节点 40 µs 与 20 µs:约等于加入本预算时 100 000 个节点实测 5.2 µs 与 2.6 µs 的八倍。
109 let register_ceiling = ceiling("NICHLINK_SCALE_REGISTER_US", 40);
110 let index_ceiling = ceiling("NICHLINK_SCALE_INDEX_US", 20);
111 for size in sizes {
112 let namespace = format!("scale-{size}");
113 let root = Registry::root_for_namespace(FrameworkId::new("nichlink.scale"), &namespace);
114 let parent = root_node_id(&namespace);
115 let submissions = (0..size)
116 .map(|index| snapshot(&namespace, index, parent))
117 .collect::<Vec<_>>();
118 let mut registry = root;
119 let register_start = Instant::now();
120 registry
121 .register_snapshot_batch(submissions)
122 .expect("generated scale batch must register");
123 let register_ms = register_start.elapsed().as_millis();
124 let index_start = Instant::now();
125 let index = registry.index();
126 let index_ms = index_start.elapsed().as_millis();
127 let stats = registry.storage_stats();
128 let register_budget_ms = register_ceiling * size as u128 / 1000;
129 let index_budget_ms = index_ceiling * size as u128 / 1000;
130 println!(
131 "{size}\t{register_ms}\t{register_budget_ms}\t{index_ms}\t{index_budget_ms}\t{}\t{}\t{}",
132 index.len(),
133 stats.pages,
134 size * std::mem::size_of::<nichlink::StaticFace>()
135 );
136 assert!(
137 register_ms <= register_budget_ms,
138 "registering {size} nodes took {register_ms} ms, over the {register_budget_ms} ms budget ({register_ceiling} µs per node); raise NICHLINK_SCALE_REGISTER_US if this machine is simply slower, and update docs/performance-baseline.md if the baseline moved"
139 );
140 assert!(
141 index_ms <= index_budget_ms,
142 "indexing {size} nodes took {index_ms} ms, over the {index_budget_ms} ms budget ({index_ceiling} µs per node); raise NICHLINK_SCALE_INDEX_US if this machine is simply slower, and update docs/performance-baseline.md if the baseline moved"
143 );
144 let extra = snapshot(&namespace, size, parent);
145 registry
146 .register_snapshot_batch([extra])
147 .expect("incremental transaction must register");
148 assert_eq!(registry.index().len(), size + 2);
149 }
150}Sourcepub fn framework(&self) -> FrameworkId
pub fn framework(&self) -> FrameworkId
The framework this registry was created under. 该注册机创建时所用的框架。