shirobai 2026.0709.0000
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Cargo.lock +420 -0
- data/Cargo.toml +13 -0
- data/LICENSE.txt +21 -0
- data/crates/shirobai-core/Cargo.toml +20 -0
- data/crates/shirobai-core/src/bin/analysis_profile.rs +447 -0
- data/crates/shirobai-core/src/bin/bundle_profile.rs +656 -0
- data/crates/shirobai-core/src/bin/hotspot_profile.rs +596 -0
- data/crates/shirobai-core/src/bin/walk_profile.rs +191 -0
- data/crates/shirobai-core/src/lib.rs +1 -0
- data/crates/shirobai-core/src/rules/abc_size.rs +1475 -0
- data/crates/shirobai-core/src/rules/access_modifier_indentation.rs +450 -0
- data/crates/shirobai-core/src/rules/ambiguous_block_association.rs +528 -0
- data/crates/shirobai-core/src/rules/argument_alignment.rs +300 -0
- data/crates/shirobai-core/src/rules/arguments_forwarding.rs +1125 -0
- data/crates/shirobai-core/src/rules/array_alignment.rs +398 -0
- data/crates/shirobai-core/src/rules/assignment_indentation.rs +502 -0
- data/crates/shirobai-core/src/rules/block_alignment.rs +869 -0
- data/crates/shirobai-core/src/rules/block_delimiters.rs +1876 -0
- data/crates/shirobai-core/src/rules/block_length.rs +631 -0
- data/crates/shirobai-core/src/rules/block_nesting.rs +390 -0
- data/crates/shirobai-core/src/rules/bundle.rs +4433 -0
- data/crates/shirobai-core/src/rules/class_length.rs +531 -0
- data/crates/shirobai-core/src/rules/closing_parenthesis_indentation.rs +425 -0
- data/crates/shirobai-core/src/rules/code_length.rs +801 -0
- data/crates/shirobai-core/src/rules/colon_method_call.rs +285 -0
- data/crates/shirobai-core/src/rules/complexity.rs +585 -0
- data/crates/shirobai-core/src/rules/debugger.rs +438 -0
- data/crates/shirobai-core/src/rules/def_end_alignment.rs +485 -0
- data/crates/shirobai-core/src/rules/dispatch.rs +276 -0
- data/crates/shirobai-core/src/rules/dot_position.rs +276 -0
- data/crates/shirobai-core/src/rules/duplicate_magic_comment.rs +1001 -0
- data/crates/shirobai-core/src/rules/duplicate_methods.rs +1725 -0
- data/crates/shirobai-core/src/rules/else_alignment.rs +837 -0
- data/crates/shirobai-core/src/rules/empty_comment.rs +452 -0
- data/crates/shirobai-core/src/rules/empty_line_after_guard_clause.rs +1210 -0
- data/crates/shirobai-core/src/rules/empty_line_after_magic_comment.rs +166 -0
- data/crates/shirobai-core/src/rules/empty_line_between_defs.rs +731 -0
- data/crates/shirobai-core/src/rules/empty_lines.rs +432 -0
- data/crates/shirobai-core/src/rules/empty_lines_around_arguments.rs +298 -0
- data/crates/shirobai-core/src/rules/empty_lines_around_body.rs +1320 -0
- data/crates/shirobai-core/src/rules/end_alignment.rs +798 -0
- data/crates/shirobai-core/src/rules/file_null.rs +320 -0
- data/crates/shirobai-core/src/rules/first_argument_indentation.rs +643 -0
- data/crates/shirobai-core/src/rules/first_array_element_indentation.rs +644 -0
- data/crates/shirobai-core/src/rules/first_hash_element_indentation.rs +699 -0
- data/crates/shirobai-core/src/rules/frozen_string_literal_comment.rs +414 -0
- data/crates/shirobai-core/src/rules/hash_alignment.rs +1030 -0
- data/crates/shirobai-core/src/rules/hash_each_methods.rs +744 -0
- data/crates/shirobai-core/src/rules/hash_syntax.rs +1304 -0
- data/crates/shirobai-core/src/rules/hash_transform_keys.rs +909 -0
- data/crates/shirobai-core/src/rules/if_unless_modifier.rs +1494 -0
- data/crates/shirobai-core/src/rules/indentation_consistency.rs +585 -0
- data/crates/shirobai-core/src/rules/indentation_width.rs +1231 -0
- data/crates/shirobai-core/src/rules/leading_empty_lines.rs +365 -0
- data/crates/shirobai-core/src/rules/line_end_concatenation.rs +330 -0
- data/crates/shirobai-core/src/rules/line_index.rs +227 -0
- data/crates/shirobai-core/src/rules/line_length.rs +434 -0
- data/crates/shirobai-core/src/rules/line_length_breakable.rs +1454 -0
- data/crates/shirobai-core/src/rules/method_length.rs +438 -0
- data/crates/shirobai-core/src/rules/method_name.rs +565 -0
- data/crates/shirobai-core/src/rules/mod.rs +104 -0
- data/crates/shirobai-core/src/rules/module_length.rs +283 -0
- data/crates/shirobai-core/src/rules/multiline_method_call_brace_layout.rs +594 -0
- data/crates/shirobai-core/src/rules/multiline_method_call_indentation.rs +1444 -0
- data/crates/shirobai-core/src/rules/multiline_operation_indentation.rs +720 -0
- data/crates/shirobai-core/src/rules/nested_parenthesized_calls.rs +486 -0
- data/crates/shirobai-core/src/rules/opaque_mask.rs +164 -0
- data/crates/shirobai-core/src/rules/parentheses_as_grouped_expression.rs +410 -0
- data/crates/shirobai-core/src/rules/parse_cache.rs +116 -0
- data/crates/shirobai-core/src/rules/percent_literal_delimiters.rs +835 -0
- data/crates/shirobai-core/src/rules/perf_detect.rs +524 -0
- data/crates/shirobai-core/src/rules/perf_end_with.rs +368 -0
- data/crates/shirobai-core/src/rules/perf_start_with.rs +333 -0
- data/crates/shirobai-core/src/rules/perf_string_include.rs +399 -0
- data/crates/shirobai-core/src/rules/perf_times_map.rs +570 -0
- data/crates/shirobai-core/src/rules/predicate_prefix.rs +397 -0
- data/crates/shirobai-core/src/rules/punctuation_spacing.rs +725 -0
- data/crates/shirobai-core/src/rules/rails_app.rs +765 -0
- data/crates/shirobai-core/src/rules/rails_config.rs +80 -0
- data/crates/shirobai-core/src/rules/rails_dynamic_find_by.rs +447 -0
- data/crates/shirobai-core/src/rules/rails_pluck.rs +470 -0
- data/crates/shirobai-core/src/rules/rails_unknown_env.rs +362 -0
- data/crates/shirobai-core/src/rules/redundant_freeze.rs +550 -0
- data/crates/shirobai-core/src/rules/redundant_self.rs +691 -0
- data/crates/shirobai-core/src/rules/redundant_self_assignment.rs +530 -0
- data/crates/shirobai-core/src/rules/require_parentheses.rs +237 -0
- data/crates/shirobai-core/src/rules/rspec_dispatcher.rs +2010 -0
- data/crates/shirobai-core/src/rules/rspec_empty_line.rs +791 -0
- data/crates/shirobai-core/src/rules/rspec_language.rs +233 -0
- data/crates/shirobai-core/src/rules/safe_navigation_chain.rs +376 -0
- data/crates/shirobai-core/src/rules/self_assignment.rs +976 -0
- data/crates/shirobai-core/src/rules/semicolon.rs +492 -0
- data/crates/shirobai-core/src/rules/space_around_keyword.rs +881 -0
- data/crates/shirobai-core/src/rules/space_around_method_call_operator.rs +398 -0
- data/crates/shirobai-core/src/rules/space_before_block_braces.rs +380 -0
- data/crates/shirobai-core/src/rules/space_before_first_arg.rs +627 -0
- data/crates/shirobai-core/src/rules/space_inside_array_literal_brackets.rs +977 -0
- data/crates/shirobai-core/src/rules/space_inside_block_braces.rs +669 -0
- data/crates/shirobai-core/src/rules/space_inside_hash_literal_braces.rs +498 -0
- data/crates/shirobai-core/src/rules/space_inside_parens.rs +538 -0
- data/crates/shirobai-core/src/rules/space_inside_reference_brackets.rs +513 -0
- data/crates/shirobai-core/src/rules/space_scan.rs +136 -0
- data/crates/shirobai-core/src/rules/stabby_lambda_parentheses.rs +326 -0
- data/crates/shirobai-core/src/rules/string_literals.rs +611 -0
- data/crates/shirobai-core/src/rules/string_literals_in_interpolation.rs +244 -0
- data/crates/shirobai-core/src/rules/trailing_comma.rs +428 -0
- data/crates/shirobai-core/src/rules/trailing_comma_in_arguments.rs +502 -0
- data/crates/shirobai-core/src/rules/trailing_comma_in_array_literal.rs +210 -0
- data/crates/shirobai-core/src/rules/trailing_comma_in_hash_literal.rs +174 -0
- data/crates/shirobai-core/src/rules/trailing_empty_lines.rs +307 -0
- data/crates/shirobai-core/src/rules/unreachable_code.rs +719 -0
- data/crates/shirobai-core/src/rules/useless_access_modifier.rs +1087 -0
- data/crates/shirobai-core/src/rules/variable_number.rs +318 -0
- data/crates/shirobai-core/src/rules/void.rs +1328 -0
- data/ext/shirobai/Cargo.toml +16 -0
- data/ext/shirobai/src/lib.rs +4501 -0
- data/lib/shirobai/cop/base.rb +45 -0
- data/lib/shirobai/cop/layout/access_modifier_indentation.rb +117 -0
- data/lib/shirobai/cop/layout/argument_alignment.rb +86 -0
- data/lib/shirobai/cop/layout/array_alignment.rb +109 -0
- data/lib/shirobai/cop/layout/assignment_indentation.rb +73 -0
- data/lib/shirobai/cop/layout/block_alignment.rb +79 -0
- data/lib/shirobai/cop/layout/closing_parenthesis_indentation.rb +51 -0
- data/lib/shirobai/cop/layout/def_end_alignment.rb +114 -0
- data/lib/shirobai/cop/layout/dot_position.rb +63 -0
- data/lib/shirobai/cop/layout/else_alignment.rb +86 -0
- data/lib/shirobai/cop/layout/empty_comment.rb +75 -0
- data/lib/shirobai/cop/layout/empty_line_after_guard_clause.rb +116 -0
- data/lib/shirobai/cop/layout/empty_line_after_magic_comment.rb +82 -0
- data/lib/shirobai/cop/layout/empty_line_between_defs.rb +78 -0
- data/lib/shirobai/cop/layout/empty_lines.rb +70 -0
- data/lib/shirobai/cop/layout/empty_lines_around_arguments.rb +55 -0
- data/lib/shirobai/cop/layout/empty_lines_around_begin_body.rb +22 -0
- data/lib/shirobai/cop/layout/empty_lines_around_block_body.rb +28 -0
- data/lib/shirobai/cop/layout/empty_lines_around_body_shared.rb +58 -0
- data/lib/shirobai/cop/layout/empty_lines_around_class_body.rb +27 -0
- data/lib/shirobai/cop/layout/empty_lines_around_exception_handling_keywords.rb +24 -0
- data/lib/shirobai/cop/layout/empty_lines_around_method_body.rb +22 -0
- data/lib/shirobai/cop/layout/empty_lines_around_module_body.rb +26 -0
- data/lib/shirobai/cop/layout/end_alignment.rb +101 -0
- data/lib/shirobai/cop/layout/first_argument_indentation.rb +76 -0
- data/lib/shirobai/cop/layout/first_array_element_indentation.rb +89 -0
- data/lib/shirobai/cop/layout/first_hash_element_indentation.rb +104 -0
- data/lib/shirobai/cop/layout/hash_alignment.rb +135 -0
- data/lib/shirobai/cop/layout/indentation_consistency.rb +95 -0
- data/lib/shirobai/cop/layout/indentation_width.rb +141 -0
- data/lib/shirobai/cop/layout/leading_empty_lines.rb +72 -0
- data/lib/shirobai/cop/layout/line_length.rb +227 -0
- data/lib/shirobai/cop/layout/multiline_method_call_brace_layout.rb +126 -0
- data/lib/shirobai/cop/layout/multiline_method_call_indentation.rb +87 -0
- data/lib/shirobai/cop/layout/multiline_operation_indentation.rb +61 -0
- data/lib/shirobai/cop/layout/space_after_colon.rb +58 -0
- data/lib/shirobai/cop/layout/space_after_comma.rb +64 -0
- data/lib/shirobai/cop/layout/space_after_semicolon.rb +57 -0
- data/lib/shirobai/cop/layout/space_around_keyword.rb +69 -0
- data/lib/shirobai/cop/layout/space_around_method_call_operator.rb +55 -0
- data/lib/shirobai/cop/layout/space_before_block_braces.rb +150 -0
- data/lib/shirobai/cop/layout/space_before_comma.rb +63 -0
- data/lib/shirobai/cop/layout/space_before_comment.rb +56 -0
- data/lib/shirobai/cop/layout/space_before_first_arg.rb +65 -0
- data/lib/shirobai/cop/layout/space_before_semicolon.rb +57 -0
- data/lib/shirobai/cop/layout/space_inside_array_literal_brackets.rb +109 -0
- data/lib/shirobai/cop/layout/space_inside_block_braces.rb +116 -0
- data/lib/shirobai/cop/layout/space_inside_hash_literal_braces.rb +93 -0
- data/lib/shirobai/cop/layout/space_inside_parens.rb +67 -0
- data/lib/shirobai/cop/layout/space_inside_reference_brackets.rb +104 -0
- data/lib/shirobai/cop/layout/trailing_empty_lines.rb +104 -0
- data/lib/shirobai/cop/lint/ambiguous_block_association.rb +117 -0
- data/lib/shirobai/cop/lint/debugger.rb +44 -0
- data/lib/shirobai/cop/lint/duplicate_magic_comment.rb +67 -0
- data/lib/shirobai/cop/lint/duplicate_methods.rb +109 -0
- data/lib/shirobai/cop/lint/parentheses_as_grouped_expression.rb +54 -0
- data/lib/shirobai/cop/lint/require_parentheses.rb +35 -0
- data/lib/shirobai/cop/lint/safe_navigation_chain.rb +52 -0
- data/lib/shirobai/cop/lint/self_assignment.rb +105 -0
- data/lib/shirobai/cop/lint/unreachable_code.rb +48 -0
- data/lib/shirobai/cop/lint/useless_access_modifier.rb +61 -0
- data/lib/shirobai/cop/lint/void.rb +60 -0
- data/lib/shirobai/cop/metrics/abc_size.rb +61 -0
- data/lib/shirobai/cop/metrics/block_length.rb +139 -0
- data/lib/shirobai/cop/metrics/block_nesting.rb +62 -0
- data/lib/shirobai/cop/metrics/class_length.rb +88 -0
- data/lib/shirobai/cop/metrics/complexity_base.rb +35 -0
- data/lib/shirobai/cop/metrics/complexity_shared.rb +45 -0
- data/lib/shirobai/cop/metrics/cyclomatic_complexity.rb +30 -0
- data/lib/shirobai/cop/metrics/method_length.rb +70 -0
- data/lib/shirobai/cop/metrics/module_length.rb +83 -0
- data/lib/shirobai/cop/metrics/perceived_complexity.rb +30 -0
- data/lib/shirobai/cop/naming/method_name.rb +100 -0
- data/lib/shirobai/cop/naming/predicate_prefix.rb +107 -0
- data/lib/shirobai/cop/naming/variable_number.rb +72 -0
- data/lib/shirobai/cop/style/arguments_forwarding.rb +108 -0
- data/lib/shirobai/cop/style/block_delimiters.rb +164 -0
- data/lib/shirobai/cop/style/colon_method_call.rb +60 -0
- data/lib/shirobai/cop/style/file_null.rb +55 -0
- data/lib/shirobai/cop/style/frozen_string_literal_comment.rb +118 -0
- data/lib/shirobai/cop/style/hash_each_methods.rb +50 -0
- data/lib/shirobai/cop/style/hash_syntax.rb +147 -0
- data/lib/shirobai/cop/style/hash_transform_keys.rb +46 -0
- data/lib/shirobai/cop/style/if_unless_modifier.rb +207 -0
- data/lib/shirobai/cop/style/line_end_concatenation.rb +42 -0
- data/lib/shirobai/cop/style/nested_parenthesized_calls.rb +88 -0
- data/lib/shirobai/cop/style/percent_literal_delimiters.rb +113 -0
- data/lib/shirobai/cop/style/redundant_freeze.rb +75 -0
- data/lib/shirobai/cop/style/redundant_self.rb +50 -0
- data/lib/shirobai/cop/style/redundant_self_assignment.rb +62 -0
- data/lib/shirobai/cop/style/semicolon.rb +190 -0
- data/lib/shirobai/cop/style/stabby_lambda_parentheses.rb +75 -0
- data/lib/shirobai/cop/style/string_literals.rb +135 -0
- data/lib/shirobai/cop/style/string_literals_in_interpolation.rb +130 -0
- data/lib/shirobai/cop/style/trailing_comma_in_arguments.rb +127 -0
- data/lib/shirobai/cop/style/trailing_comma_in_array_literal.rb +127 -0
- data/lib/shirobai/cop/style/trailing_comma_in_hash_literal.rb +127 -0
- data/lib/shirobai/dispatch.rb +481 -0
- data/lib/shirobai/inject.rb +123 -0
- data/lib/shirobai/node_locator.rb +124 -0
- data/lib/shirobai/source_offsets.rb +43 -0
- data/lib/shirobai/version.rb +5 -0
- data/lib/shirobai.rb +5 -0
- metadata +271 -0
|
@@ -0,0 +1,596 @@
|
|
|
1
|
+
//! Hotspot decomposition profiler (MEASUREMENT ONLY — does not change real cops).
|
|
2
|
+
//!
|
|
3
|
+
//! Breaks the heavy cops (first_argument_indentation, indentation_width,
|
|
4
|
+
//! multiline_bundle, dot_position) into internal phases and measures each in
|
|
5
|
+
//! CPU time over the corpus, so we can attribute the pure-analysis cost to
|
|
6
|
+
//! specific helpers/structures rather than treating it as opaque.
|
|
7
|
+
//!
|
|
8
|
+
//! Phases measured per relevant cop:
|
|
9
|
+
//! * `parse` — parse-only baseline (P)
|
|
10
|
+
//! * `walk_noop` — dispatch::run with an empty rule (shared traversal cost:
|
|
11
|
+
//! parse-cache hit + tree walk + per-node virtual dispatch).
|
|
12
|
+
//! This is the *shared* walk cost 16 cops duplicate.
|
|
13
|
+
//! * `frame_<cop>` — walk + replicate that cop's per-node frame extraction
|
|
14
|
+
//! (prism accessors + the same Vec allocations) but NO
|
|
15
|
+
//! offense analysis. (full − frame) ≈ analysis body;
|
|
16
|
+
//! (frame − walk_noop) ≈ frame-construction overhead.
|
|
17
|
+
//! * `full_<cop>` — the real check_* (delegates to rules; unchanged logic).
|
|
18
|
+
//!
|
|
19
|
+
//! Microbenchmarks (`micro_*`) isolate the cost of the O(n)-prefix line/column
|
|
20
|
+
//! helpers as currently written vs. an O(1) precomputed line-index, by calling
|
|
21
|
+
//! them on the *real* offsets every CallNode in the corpus produces.
|
|
22
|
+
//!
|
|
23
|
+
//! Usage: hotspot_profile <mode> <corpus_dir> [iterations]
|
|
24
|
+
|
|
25
|
+
use std::path::PathBuf;
|
|
26
|
+
|
|
27
|
+
use ruby_prism::{Node, Visit, parse};
|
|
28
|
+
use shirobai_core::rules;
|
|
29
|
+
use shirobai_core::rules::dispatch::{self, Rule};
|
|
30
|
+
|
|
31
|
+
// ----------------- timing -----------------
|
|
32
|
+
|
|
33
|
+
#[cfg(unix)]
|
|
34
|
+
fn cpu_time_secs() -> f64 {
|
|
35
|
+
let mut ts = libc::timespec {
|
|
36
|
+
tv_sec: 0,
|
|
37
|
+
tv_nsec: 0,
|
|
38
|
+
};
|
|
39
|
+
// SAFETY: ts is a valid timespec.
|
|
40
|
+
unsafe { libc::clock_gettime(libc::CLOCK_PROCESS_CPUTIME_ID, &mut ts) };
|
|
41
|
+
ts.tv_sec as f64 + ts.tv_nsec as f64 / 1e9
|
|
42
|
+
}
|
|
43
|
+
#[cfg(not(unix))]
|
|
44
|
+
fn cpu_time_secs() -> f64 {
|
|
45
|
+
0.0
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fn collect_rb_files(dir: &str) -> Vec<Vec<u8>> {
|
|
49
|
+
let mut out = Vec::new();
|
|
50
|
+
let mut stack = vec![PathBuf::from(dir)];
|
|
51
|
+
while let Some(p) = stack.pop() {
|
|
52
|
+
let Ok(rd) = std::fs::read_dir(&p) else {
|
|
53
|
+
continue;
|
|
54
|
+
};
|
|
55
|
+
for entry in rd.flatten() {
|
|
56
|
+
let path = entry.path();
|
|
57
|
+
if path.is_dir() {
|
|
58
|
+
stack.push(path);
|
|
59
|
+
} else if path.extension().is_some_and(|e| e == "rb")
|
|
60
|
+
&& let Ok(bytes) = std::fs::read(&path)
|
|
61
|
+
{
|
|
62
|
+
out.push(bytes);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
out
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ----------------- a line index (the proposed O(1) replacement) -----------------
|
|
70
|
+
|
|
71
|
+
/// Precomputed sorted byte offsets of each line start. Built once per source
|
|
72
|
+
/// in O(n); answers line_of / line_start in O(log n) (or O(1) amortised).
|
|
73
|
+
struct LineIndex {
|
|
74
|
+
starts: Vec<usize>,
|
|
75
|
+
}
|
|
76
|
+
impl LineIndex {
|
|
77
|
+
fn build(src: &[u8]) -> Self {
|
|
78
|
+
let mut starts = Vec::with_capacity(src.len() / 24 + 1);
|
|
79
|
+
starts.push(0);
|
|
80
|
+
for (i, &b) in src.iter().enumerate() {
|
|
81
|
+
if b == b'\n' {
|
|
82
|
+
starts.push(i + 1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
LineIndex { starts }
|
|
86
|
+
}
|
|
87
|
+
/// 1-based line number of `off`.
|
|
88
|
+
fn line_of(&self, off: usize) -> usize {
|
|
89
|
+
// partition_point: index of first start > off == line number (1-based).
|
|
90
|
+
self.starts.partition_point(|&s| s <= off)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ----------------- current O(n)-prefix helpers (copied verbatim) -----------------
|
|
95
|
+
|
|
96
|
+
fn cur_line_of(src: &[u8], off: usize) -> usize {
|
|
97
|
+
src[..off].iter().filter(|&&b| b == b'\n').count() + 1
|
|
98
|
+
}
|
|
99
|
+
// ----------------- no-op rule (shared walk cost) -----------------
|
|
100
|
+
|
|
101
|
+
struct NoopRule;
|
|
102
|
+
impl Rule for NoopRule {
|
|
103
|
+
fn enter(&mut self, _node: &Node<'_>) {}
|
|
104
|
+
fn leave(&mut self) {}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ----------------- frame-only rules (walk + frame extraction, no analysis) -----
|
|
108
|
+
|
|
109
|
+
fn loc(l: &ruby_prism::Location<'_>) -> (usize, usize) {
|
|
110
|
+
(l.start_offset(), l.end_offset())
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/// Replicates first_argument_indentation::make_frame work (incl. name.to_vec()).
|
|
114
|
+
struct FrameFirstArg {
|
|
115
|
+
sink: usize,
|
|
116
|
+
stack: Vec<(usize, usize, Vec<u8>)>,
|
|
117
|
+
}
|
|
118
|
+
impl Rule for FrameFirstArg {
|
|
119
|
+
fn enter(&mut self, node: &Node<'_>) {
|
|
120
|
+
let l = node.location();
|
|
121
|
+
let name = if let Some(c) = node.as_call_node() {
|
|
122
|
+
let _paren = c
|
|
123
|
+
.opening_loc()
|
|
124
|
+
.map(|o| o.as_slice() == b"(")
|
|
125
|
+
.unwrap_or(false);
|
|
126
|
+
let _recv = c.receiver().map(|r| loc(&r.location()));
|
|
127
|
+
let _end = c.closing_loc().map(|cl| cl.start_offset());
|
|
128
|
+
c.name().as_slice().to_vec() // <-- per-call heap alloc in real code
|
|
129
|
+
} else if let Some(s) = node.as_super_node() {
|
|
130
|
+
let _ = s.lparen_loc().is_some();
|
|
131
|
+
let _ = s.rparen_loc().map(|cl| cl.start_offset());
|
|
132
|
+
Vec::new()
|
|
133
|
+
} else if node.as_splat_node().is_some() || node.as_assoc_splat_node().is_some() {
|
|
134
|
+
Vec::new()
|
|
135
|
+
} else {
|
|
136
|
+
let _ = node.as_arguments_node().is_some()
|
|
137
|
+
|| node.as_statements_node().is_some()
|
|
138
|
+
|| node.as_keyword_hash_node().is_some();
|
|
139
|
+
Vec::new()
|
|
140
|
+
};
|
|
141
|
+
self.sink = self.sink.wrapping_add(name.len());
|
|
142
|
+
self.stack.push((l.start_offset(), l.end_offset(), name));
|
|
143
|
+
}
|
|
144
|
+
fn leave(&mut self) {
|
|
145
|
+
if let Some((s, _, _)) = self.stack.pop() {
|
|
146
|
+
self.sink = self.sink.wrapping_add(s);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/// Replicates indentation_width::enter frame work, incl. the per-call
|
|
152
|
+
/// `line_of(receiver_end)` O(n) scan done DURING frame build.
|
|
153
|
+
struct FrameIndent<'s> {
|
|
154
|
+
src: &'s [u8],
|
|
155
|
+
sink: usize,
|
|
156
|
+
depth: usize,
|
|
157
|
+
}
|
|
158
|
+
impl<'s> Rule for FrameIndent<'s> {
|
|
159
|
+
fn enter(&mut self, node: &Node<'_>) {
|
|
160
|
+
if node.as_arguments_node().is_some() {
|
|
161
|
+
self.sink = self.sink.wrapping_add(1);
|
|
162
|
+
} else if let Some(c) = node.as_call_node() {
|
|
163
|
+
if c.receiver().is_none() {
|
|
164
|
+
self.sink = self.sink.wrapping_add(node.location().start_offset());
|
|
165
|
+
} else {
|
|
166
|
+
let _dot = c.call_operator_loc().map(|l| l.start_offset());
|
|
167
|
+
let _sel = c.message_loc().map(|l| l.start_offset());
|
|
168
|
+
// The real code does exactly this O(n) scan per call frame:
|
|
169
|
+
let rll = c
|
|
170
|
+
.receiver()
|
|
171
|
+
.map(|r| cur_line_of(self.src, r.location().end_offset().saturating_sub(1)));
|
|
172
|
+
self.sink = self.sink.wrapping_add(rll.unwrap_or(0));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
self.depth += 1;
|
|
176
|
+
}
|
|
177
|
+
fn leave(&mut self) {
|
|
178
|
+
self.depth = self.depth.saturating_sub(1);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/// Same as FrameIndent but uses a precomputed LineIndex for receiver_last_line.
|
|
183
|
+
struct FrameIndentIdx<'s> {
|
|
184
|
+
idx: &'s LineIndex,
|
|
185
|
+
sink: usize,
|
|
186
|
+
depth: usize,
|
|
187
|
+
}
|
|
188
|
+
impl<'s> Rule for FrameIndentIdx<'s> {
|
|
189
|
+
fn enter(&mut self, node: &Node<'_>) {
|
|
190
|
+
if node.as_arguments_node().is_some() {
|
|
191
|
+
self.sink = self.sink.wrapping_add(1);
|
|
192
|
+
} else if let Some(c) = node.as_call_node() {
|
|
193
|
+
if c.receiver().is_none() {
|
|
194
|
+
self.sink = self.sink.wrapping_add(node.location().start_offset());
|
|
195
|
+
} else {
|
|
196
|
+
let _dot = c.call_operator_loc().map(|l| l.start_offset());
|
|
197
|
+
let _sel = c.message_loc().map(|l| l.start_offset());
|
|
198
|
+
let rll = c.receiver().map(|r| {
|
|
199
|
+
self.idx
|
|
200
|
+
.line_of(r.location().end_offset().saturating_sub(1))
|
|
201
|
+
});
|
|
202
|
+
self.sink = self.sink.wrapping_add(rll.unwrap_or(0));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
self.depth += 1;
|
|
206
|
+
}
|
|
207
|
+
fn leave(&mut self) {
|
|
208
|
+
self.depth = self.depth.saturating_sub(1);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/// Replicates multiline_method_call_indentation::frame_for, incl. per-call
|
|
213
|
+
/// args Vec allocation.
|
|
214
|
+
struct FrameMc {
|
|
215
|
+
sink: usize,
|
|
216
|
+
stack: Vec<usize>,
|
|
217
|
+
}
|
|
218
|
+
impl Rule for FrameMc {
|
|
219
|
+
fn enter(&mut self, node: &Node<'_>) {
|
|
220
|
+
if let Some(c) = node.as_call_node() {
|
|
221
|
+
let _paren = match c.closing_loc() {
|
|
222
|
+
Some(close) if close.as_slice() == b")" => c
|
|
223
|
+
.opening_loc()
|
|
224
|
+
.map(|o| (o.start_offset(), close.end_offset())),
|
|
225
|
+
_ => None,
|
|
226
|
+
};
|
|
227
|
+
let args: Vec<(usize, usize)> = c
|
|
228
|
+
.arguments()
|
|
229
|
+
.map(|a| {
|
|
230
|
+
a.arguments()
|
|
231
|
+
.iter()
|
|
232
|
+
.map(|arg| loc(&arg.location()))
|
|
233
|
+
.collect()
|
|
234
|
+
})
|
|
235
|
+
.unwrap_or_default();
|
|
236
|
+
let _dot = c.call_operator_loc().map(|d| d.start_offset());
|
|
237
|
+
let _sel = c.message_loc().as_ref().map(loc);
|
|
238
|
+
self.sink = self.sink.wrapping_add(args.len());
|
|
239
|
+
}
|
|
240
|
+
self.stack.push(node.location().start_offset());
|
|
241
|
+
}
|
|
242
|
+
fn leave(&mut self) {
|
|
243
|
+
if let Some(s) = self.stack.pop() {
|
|
244
|
+
self.sink = self.sink.wrapping_add(s);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// dot_position has its own (non-dispatch) walk; replicate the bare traversal +
|
|
250
|
+
// the per-dotted-call work UP TO the early-bail, both with current O(n) helpers
|
|
251
|
+
// and with the line-index, to show the saving.
|
|
252
|
+
|
|
253
|
+
struct DotWalkCur<'s> {
|
|
254
|
+
src: &'s [u8],
|
|
255
|
+
sink: usize,
|
|
256
|
+
}
|
|
257
|
+
impl<'pr, 's> Visit<'pr> for DotWalkCur<'s> {
|
|
258
|
+
fn visit_call_node(&mut self, node: &ruby_prism::CallNode<'pr>) {
|
|
259
|
+
if let Some(dot) = node.call_operator_loc() {
|
|
260
|
+
let dt = &self.src[dot.start_offset()..dot.end_offset()];
|
|
261
|
+
if (dt == b"." || dt == b"&.")
|
|
262
|
+
&& node.receiver().is_some()
|
|
263
|
+
&& let Some(sel) = node
|
|
264
|
+
.message_loc()
|
|
265
|
+
.map(|m| m.start_offset())
|
|
266
|
+
.or_else(|| node.opening_loc().map(|o| o.start_offset()))
|
|
267
|
+
{
|
|
268
|
+
let recv_end = node.receiver().unwrap().location().end_offset();
|
|
269
|
+
// The real is_offense() O(n) prefix scans (two of them) before bail:
|
|
270
|
+
let a = cur_line_of(self.src, sel);
|
|
271
|
+
let b = cur_line_of(self.src, recv_end);
|
|
272
|
+
self.sink = self.sink.wrapping_add(a ^ b);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
ruby_prism::visit_call_node(self, node);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
struct DotWalkIdx<'s> {
|
|
280
|
+
idx: &'s LineIndex,
|
|
281
|
+
src: &'s [u8],
|
|
282
|
+
sink: usize,
|
|
283
|
+
}
|
|
284
|
+
impl<'pr, 's> Visit<'pr> for DotWalkIdx<'s> {
|
|
285
|
+
fn visit_call_node(&mut self, node: &ruby_prism::CallNode<'pr>) {
|
|
286
|
+
if let Some(dot) = node.call_operator_loc() {
|
|
287
|
+
let dt = &self.src[dot.start_offset()..dot.end_offset()];
|
|
288
|
+
if (dt == b"." || dt == b"&.")
|
|
289
|
+
&& node.receiver().is_some()
|
|
290
|
+
&& let Some(sel) = node
|
|
291
|
+
.message_loc()
|
|
292
|
+
.map(|m| m.start_offset())
|
|
293
|
+
.or_else(|| node.opening_loc().map(|o| o.start_offset()))
|
|
294
|
+
{
|
|
295
|
+
let recv_end = node.receiver().unwrap().location().end_offset();
|
|
296
|
+
let a = self.idx.line_of(sel);
|
|
297
|
+
let b = self.idx.line_of(recv_end);
|
|
298
|
+
self.sink = self.sink.wrapping_add(a ^ b);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
ruby_prism::visit_call_node(self, node);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ----------------- phase runners -----------------
|
|
306
|
+
|
|
307
|
+
fn run_parse(sources: &[Vec<u8>]) -> usize {
|
|
308
|
+
let mut sink = 0usize;
|
|
309
|
+
for s in sources {
|
|
310
|
+
let r = parse(s);
|
|
311
|
+
sink = sink.wrapping_add(r.node().location().end_offset());
|
|
312
|
+
}
|
|
313
|
+
sink
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
fn run_walk_noop(sources: &[Vec<u8>]) -> usize {
|
|
317
|
+
let mut sink = 0usize;
|
|
318
|
+
for s in sources {
|
|
319
|
+
let mut r = NoopRule;
|
|
320
|
+
dispatch::run(s, &mut [&mut r]);
|
|
321
|
+
sink = sink.wrapping_add(s.len());
|
|
322
|
+
}
|
|
323
|
+
sink
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
fn run_frame_firstarg(sources: &[Vec<u8>]) -> usize {
|
|
327
|
+
let mut sink = 0usize;
|
|
328
|
+
for s in sources {
|
|
329
|
+
let mut r = FrameFirstArg {
|
|
330
|
+
sink: 0,
|
|
331
|
+
stack: Vec::new(),
|
|
332
|
+
};
|
|
333
|
+
dispatch::run(s, &mut [&mut r]);
|
|
334
|
+
sink = sink.wrapping_add(r.sink);
|
|
335
|
+
}
|
|
336
|
+
sink
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
fn run_frame_indent(sources: &[Vec<u8>]) -> usize {
|
|
340
|
+
let mut sink = 0usize;
|
|
341
|
+
for s in sources {
|
|
342
|
+
let mut r = FrameIndent {
|
|
343
|
+
src: s,
|
|
344
|
+
sink: 0,
|
|
345
|
+
depth: 0,
|
|
346
|
+
};
|
|
347
|
+
dispatch::run(s, &mut [&mut r]);
|
|
348
|
+
sink = sink.wrapping_add(r.sink);
|
|
349
|
+
}
|
|
350
|
+
sink
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
fn run_frame_indent_idx(sources: &[Vec<u8>]) -> usize {
|
|
354
|
+
let mut sink = 0usize;
|
|
355
|
+
for s in sources {
|
|
356
|
+
let idx = LineIndex::build(s);
|
|
357
|
+
let mut r = FrameIndentIdx {
|
|
358
|
+
idx: &idx,
|
|
359
|
+
sink: 0,
|
|
360
|
+
depth: 0,
|
|
361
|
+
};
|
|
362
|
+
dispatch::run(s, &mut [&mut r]);
|
|
363
|
+
sink = sink.wrapping_add(r.sink);
|
|
364
|
+
}
|
|
365
|
+
sink
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
fn run_frame_mc(sources: &[Vec<u8>]) -> usize {
|
|
369
|
+
let mut sink = 0usize;
|
|
370
|
+
for s in sources {
|
|
371
|
+
let mut r = FrameMc {
|
|
372
|
+
sink: 0,
|
|
373
|
+
stack: Vec::new(),
|
|
374
|
+
};
|
|
375
|
+
dispatch::run(s, &mut [&mut r]);
|
|
376
|
+
sink = sink.wrapping_add(r.sink);
|
|
377
|
+
}
|
|
378
|
+
sink
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
fn run_dot_walk_cur(sources: &[Vec<u8>]) -> usize {
|
|
382
|
+
let mut sink = 0usize;
|
|
383
|
+
for s in sources {
|
|
384
|
+
let res = parse(s);
|
|
385
|
+
let mut v = DotWalkCur { src: s, sink: 0 };
|
|
386
|
+
v.visit(&res.node());
|
|
387
|
+
sink = sink.wrapping_add(v.sink);
|
|
388
|
+
}
|
|
389
|
+
sink
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
fn run_dot_walk_idx(sources: &[Vec<u8>]) -> usize {
|
|
393
|
+
let mut sink = 0usize;
|
|
394
|
+
for s in sources {
|
|
395
|
+
let res = parse(s);
|
|
396
|
+
let idx = LineIndex::build(s);
|
|
397
|
+
let mut v = DotWalkIdx {
|
|
398
|
+
idx: &idx,
|
|
399
|
+
src: s,
|
|
400
|
+
sink: 0,
|
|
401
|
+
};
|
|
402
|
+
v.visit(&res.node());
|
|
403
|
+
sink = sink.wrapping_add(v.sink);
|
|
404
|
+
}
|
|
405
|
+
sink
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// --- full real cops (unchanged logic) ---
|
|
409
|
+
|
|
410
|
+
fn run_full_firstarg(sources: &[Vec<u8>]) -> usize {
|
|
411
|
+
let mut sink = 0usize;
|
|
412
|
+
for s in sources {
|
|
413
|
+
sink = sink.wrapping_add(
|
|
414
|
+
rules::first_argument_indentation::check_first_argument_indentation(s, 0, 2, false)
|
|
415
|
+
.len(),
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
sink
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
fn run_full_indent(sources: &[Vec<u8>]) -> usize {
|
|
422
|
+
let cfg = rules::indentation_width::Config {
|
|
423
|
+
width: 2,
|
|
424
|
+
relative_to_receiver: false,
|
|
425
|
+
access_modifier_outdent: false,
|
|
426
|
+
indented_internal_methods: false,
|
|
427
|
+
end_align: 2,
|
|
428
|
+
def_end_align_def: false,
|
|
429
|
+
use_tabs: false,
|
|
430
|
+
};
|
|
431
|
+
let allowed: Vec<usize> = Vec::new();
|
|
432
|
+
let prior: Vec<(usize, usize)> = Vec::new();
|
|
433
|
+
let mut sink = 0usize;
|
|
434
|
+
for s in sources {
|
|
435
|
+
sink = sink.wrapping_add(
|
|
436
|
+
rules::indentation_width::check_indentation_width(s, cfg, &allowed, &prior).len(),
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
sink
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
fn run_full_bundle(sources: &[Vec<u8>]) -> usize {
|
|
443
|
+
let mut sink = 0usize;
|
|
444
|
+
for s in sources {
|
|
445
|
+
let (op, mc) = rules::bundle::check_multiline_bundle(s, 0, 2, 2, 0, 2, 2);
|
|
446
|
+
sink = sink.wrapping_add(op.len()).wrapping_add(mc.len());
|
|
447
|
+
}
|
|
448
|
+
sink
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
fn run_full_dot(sources: &[Vec<u8>]) -> usize {
|
|
452
|
+
let mut sink = 0usize;
|
|
453
|
+
for s in sources {
|
|
454
|
+
sink = sink.wrapping_add(rules::dot_position::check_dot_position(s, 0).len());
|
|
455
|
+
}
|
|
456
|
+
sink
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Microbench: count how many CallNode offsets a corpus produces and the
|
|
460
|
+
// total cost of cur_line_of vs index.line_of over ALL those offsets.
|
|
461
|
+
|
|
462
|
+
fn collect_call_offsets(sources: &[Vec<u8>]) -> Vec<(usize, Vec<usize>)> {
|
|
463
|
+
struct Collect {
|
|
464
|
+
offs: Vec<usize>,
|
|
465
|
+
}
|
|
466
|
+
impl<'pr> Visit<'pr> for Collect {
|
|
467
|
+
fn visit_call_node(&mut self, node: &ruby_prism::CallNode<'pr>) {
|
|
468
|
+
self.offs.push(node.as_node().location().start_offset());
|
|
469
|
+
if let Some(r) = node.receiver() {
|
|
470
|
+
self.offs.push(r.location().end_offset());
|
|
471
|
+
}
|
|
472
|
+
ruby_prism::visit_call_node(self, node);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
sources
|
|
476
|
+
.iter()
|
|
477
|
+
.map(|s| {
|
|
478
|
+
let res = parse(s);
|
|
479
|
+
let mut c = Collect { offs: Vec::new() };
|
|
480
|
+
c.visit(&res.node());
|
|
481
|
+
(s.len(), c.offs)
|
|
482
|
+
})
|
|
483
|
+
.collect()
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
fn run_mode(mode: &str, sources: &[Vec<u8>]) -> usize {
|
|
487
|
+
match mode {
|
|
488
|
+
"parse" => run_parse(sources),
|
|
489
|
+
"walk_noop" => run_walk_noop(sources),
|
|
490
|
+
"frame_firstarg" => run_frame_firstarg(sources),
|
|
491
|
+
"frame_indent" => run_frame_indent(sources),
|
|
492
|
+
"frame_indent_idx" => run_frame_indent_idx(sources),
|
|
493
|
+
"frame_mc" => run_frame_mc(sources),
|
|
494
|
+
"full_firstarg" => run_full_firstarg(sources),
|
|
495
|
+
"full_indent" => run_full_indent(sources),
|
|
496
|
+
"full_bundle" => run_full_bundle(sources),
|
|
497
|
+
"full_dot" => run_full_dot(sources),
|
|
498
|
+
"dot_walk_cur" => run_dot_walk_cur(sources),
|
|
499
|
+
"dot_walk_idx" => run_dot_walk_idx(sources),
|
|
500
|
+
other => {
|
|
501
|
+
eprintln!("unknown mode: {other}");
|
|
502
|
+
std::process::exit(2);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
fn time_mode(mode: &str, sources: &[Vec<u8>], iters: usize) -> f64 {
|
|
508
|
+
let mut times = Vec::with_capacity(iters);
|
|
509
|
+
let mut sink = 0usize;
|
|
510
|
+
for _ in 0..iters {
|
|
511
|
+
let t0 = cpu_time_secs();
|
|
512
|
+
sink = sink.wrapping_add(run_mode(mode, sources));
|
|
513
|
+
let t1 = cpu_time_secs();
|
|
514
|
+
times.push(t1 - t0);
|
|
515
|
+
}
|
|
516
|
+
times.sort_by(|a, b| a.partial_cmp(b).unwrap());
|
|
517
|
+
let median = times[times.len() / 2];
|
|
518
|
+
eprintln!("mode={mode} median={median:.6} sink={sink}");
|
|
519
|
+
median
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
fn main() {
|
|
523
|
+
let args: Vec<String> = std::env::args().collect();
|
|
524
|
+
if args.len() < 3 {
|
|
525
|
+
eprintln!("usage: hotspot_profile <mode|micro> <corpus_dir> [iterations]");
|
|
526
|
+
std::process::exit(2);
|
|
527
|
+
}
|
|
528
|
+
let mode = args[1].clone();
|
|
529
|
+
let dir = &args[2];
|
|
530
|
+
let iters: usize = args.get(3).and_then(|s| s.parse().ok()).unwrap_or(1);
|
|
531
|
+
let sources = collect_rb_files(dir);
|
|
532
|
+
if sources.is_empty() {
|
|
533
|
+
eprintln!("no .rb files under {dir}");
|
|
534
|
+
std::process::exit(1);
|
|
535
|
+
}
|
|
536
|
+
eprintln!("files={} iters={iters}", sources.len());
|
|
537
|
+
|
|
538
|
+
if mode == "micro" {
|
|
539
|
+
// Cost of line_of over EVERY callnode offset: current O(n) vs index O(log n).
|
|
540
|
+
let data = collect_call_offsets(&sources);
|
|
541
|
+
let total_offs: usize = data.iter().map(|(_, o)| o.len()).sum();
|
|
542
|
+
eprintln!("total callnode offsets={total_offs}");
|
|
543
|
+
|
|
544
|
+
// current
|
|
545
|
+
let mut sink = 0usize;
|
|
546
|
+
let t0 = cpu_time_secs();
|
|
547
|
+
for (_len, offs) in &data {
|
|
548
|
+
// We need the source; recompute via index of data position.
|
|
549
|
+
// (sources and data are parallel.)
|
|
550
|
+
let _ = offs;
|
|
551
|
+
}
|
|
552
|
+
// Re-pair with sources for correctness.
|
|
553
|
+
let t_cur = {
|
|
554
|
+
let mut s = 0usize;
|
|
555
|
+
let t0 = cpu_time_secs();
|
|
556
|
+
for (src, (_l, offs)) in sources.iter().zip(&data) {
|
|
557
|
+
for &o in offs {
|
|
558
|
+
s = s.wrapping_add(cur_line_of(src, o));
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
let t1 = cpu_time_secs();
|
|
562
|
+
sink = sink.wrapping_add(s);
|
|
563
|
+
t1 - t0
|
|
564
|
+
};
|
|
565
|
+
let _ = t0;
|
|
566
|
+
|
|
567
|
+
// index: build once per source then query
|
|
568
|
+
let t_idx_build;
|
|
569
|
+
let t_idx_query;
|
|
570
|
+
{
|
|
571
|
+
let mut s = 0usize;
|
|
572
|
+
let t0 = cpu_time_secs();
|
|
573
|
+
let indices: Vec<LineIndex> = sources.iter().map(|src| LineIndex::build(src)).collect();
|
|
574
|
+
let t1 = cpu_time_secs();
|
|
575
|
+
t_idx_build = t1 - t0;
|
|
576
|
+
let t2 = cpu_time_secs();
|
|
577
|
+
for (idx, (_l, offs)) in indices.iter().zip(&data) {
|
|
578
|
+
for &o in offs {
|
|
579
|
+
s = s.wrapping_add(idx.line_of(o));
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
let t3 = cpu_time_secs();
|
|
583
|
+
t_idx_query = t3 - t2;
|
|
584
|
+
sink = sink.wrapping_add(s);
|
|
585
|
+
}
|
|
586
|
+
eprintln!(
|
|
587
|
+
"micro line_of: current_Onprefix={t_cur:.6}s index_build={t_idx_build:.6}s index_query={t_idx_query:.6}s index_total={:.6}s sink={sink}",
|
|
588
|
+
t_idx_build + t_idx_query
|
|
589
|
+
);
|
|
590
|
+
println!("{t_cur:.6}\t{:.6}", t_idx_build + t_idx_query);
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
let m = time_mode(&mode, &sources, iters);
|
|
595
|
+
println!("{m:.6}");
|
|
596
|
+
}
|