@@ -6,6 +6,42 @@ using Random
66# Import from Base.Iterators
77import Base. Iterators: take, flatten
88
9+ """
10+ Generate a descriptive, unique name for a sampler type.
11+
12+ For DirectCall variants, extracts the Keep/Removal strategy and PrefixSearch type.
13+ For other samplers, returns the simple type name.
14+ """
15+ function sampler_name (sampler_type:: Type )
16+ type_str = string (sampler_type)
17+
18+ # For DirectCall, extract the variant information
19+ if occursin (" DirectCall" , type_str)
20+ # Extract KeyedRemovalPrefixSearch vs KeyedKeepPrefixSearch
21+ keep_strategy = if occursin (" KeyedRemoval" , type_str)
22+ " Removal"
23+ elseif occursin (" KeyedKeep" , type_str)
24+ " Keep"
25+ else
26+ " Unknown"
27+ end
28+
29+ # Extract BinaryTree vs CumSum
30+ prefix_type = if occursin (" BinaryTree" , type_str)
31+ " BinaryTree"
32+ elseif occursin (" CumSum" , type_str)
33+ " CumSum"
34+ else
35+ " Unknown"
36+ end
37+
38+ return " DirectCall_$(keep_strategy) _$(prefix_type) "
39+ end
40+
41+ # For other samplers, use simple name
42+ return string (nameof (sampler_type))
43+ end
44+
945"""
1046Create a distribution instance based on the distribution type symbol.
1147"""
@@ -70,24 +106,33 @@ function benchmark_step!(sampler, enabled_keys, key_strategy, n_changes, dist_ty
70106 end
71107
72108 # 4. Determine which keys to re-enable
73- if key_strategy == :dense
74- all_keys_to_enable = flatten ([[what_fire], disable_keys])
109+ # 4. Determine which keys to re-enable (always as Vector for type stability)
110+ all_keys_to_enable = if key_strategy == :dense
111+ vcat ([what_fire], disable_keys) # Concrete Vector{Int}
75112 elseif key_strategy == :sparse
76113 # Generate brand new random keys for sparse strategy
77- all_keys_to_enable = Int[]
78- sizehint! (all_keys_to_enable, n_changes)
79- while length (all_keys_to_enable) < n_changes
80- batch = rand (rng, 1 : typemax (Int32), 16 )
81- valid_keys = filter (k -> k ∉ enabled_keys && k ∉ all_keys_to_enable, batch)
82- needed = n_changes - length (all_keys_to_enable)
83- append! (all_keys_to_enable, first (valid_keys, min (needed, length (valid_keys))))
114+ new_keys = Int[]
115+ sizehint! (new_keys, n_changes)
116+ seen = Set {Int} (enabled_keys) # O(1) lookups
117+
118+ while length (new_keys) < n_changes
119+ batch_size = min (32 , (n_changes - length (new_keys)) * 2 )
120+ batch = rand (rng, 1 : typemax (Int), batch_size)
121+ for k in batch
122+ if k ∉ seen
123+ push! (new_keys, k)
124+ push! (seen, k)
125+ length (new_keys) == n_changes && break
126+ end
127+ end
84128 end
129+ new_keys
85130 else
86131 error (" Unknown key strategy: $key_strategy " )
87- end
132+ end :: Vector{Int} # Type assertion
88133
89134 # 5. Re-enable all n_changes clocks with new distributions
90- for k in first ( all_keys_to_enable, n_changes)
135+ for k in all_keys_to_enable
91136 dist = create_distribution (dist_type, rng)
92137 enable! (sampler, k, dist, when_fire, when_fire, rng)
93138 push! (enabled_keys, k)
@@ -102,15 +147,16 @@ Run a complete benchmark for a given sampler type and condition.
102147Returns (median_time_ns, median_memory_bytes).
103148"""
104149function benchmark_config (sampler, cond:: BenchmarkCondition )
105- # Set up the sampler
106- enabled_keys, rng, dist_type = setup_sampler (sampler, cond)
107- when = 0.0
108-
109- # Run the benchmark
110- result = @benchmark benchmark_step! (
111- $ sampler, $ enabled_keys, $ (cond. key_strategy), $ (cond. n_changes),
112- $ dist_type, $ rng, $ when
113- ) samples= 100
150+ # Run the benchmark with proper setup between samples
151+ result = @benchmark begin
152+ benchmark_step! (
153+ $ sampler, enabled_keys, $ (cond. key_strategy), $ (cond. n_changes),
154+ dist_type, rng, 0.0
155+ )
156+ end setup= begin
157+ reset! ($ sampler)
158+ enabled_keys, rng, dist_type = setup_sampler ($ sampler, $ cond)
159+ end samples= 100
114160
115161 return Int (round (median (result. times))), Int (round (median (result. memory)))
116162end
0 commit comments