54template<std::
size_t Capacity>
58 return queue_.try_push(request);
61 std::optional<SampleStreamPageRequest>
try_pop() noexcept {
62 return queue_.try_pop();
66 return queue_.telemetry();
69 static constexpr std::size_t
capacity() noexcept {
return Capacity; }
83 if (capacity == 0)
return false;
85 pending_.reserve(capacity);
100 bool prepared() const noexcept {
return capacity_ != 0; }
104 if (!
prepared() || !valid(request)) {
105 ++stats_.rejected_invalid;
109 auto existing = std::find_if(pending_.begin(), pending_.end(),
111 return same_demand(candidate, request);
113 if (existing != pending_.end()) {
114 const auto stable_sequence = existing->sequence;
116 existing->sequence = stable_sequence;
121 if (pending_.size() >= capacity_) {
122 auto least = pending_.begin();
123 for (
auto candidate = std::next(least); candidate != pending_.end(); ++candidate) {
124 if (more_urgent(*least, *candidate)) least = candidate;
126 if (!strictly_more_urgent(request, *least)) {
127 ++stats_.rejected_full;
130 pending_.erase(least);
131 ++stats_.displaced_less_urgent;
133 if (next_sequence_ == 0) renumber_sequences();
134 request.sequence = next_sequence_++;
135 pending_.push_back(request);
140 template<std::
size_t Capacity>
142 std::size_t drained = 0;
143 while (
auto request = inbox.try_pop()) {
150 std::optional<SampleStreamPageRequest>
most_urgent() const noexcept {
156 template<
typename Predicate>
158 Predicate&& predicate)
const noexcept {
159 if (pending_.empty())
return std::nullopt;
160 auto best = pending_.end();
161 for (
auto candidate = pending_.begin(); candidate != pending_.end(); ++candidate) {
162 if (!predicate(*candidate))
continue;
163 if (best == pending_.end() || more_urgent(*candidate, *best)) best = candidate;
165 if (best == pending_.end())
return std::nullopt;
170 return std::any_of(pending_.begin(), pending_.end(),
172 return same_page(candidate, request);
177 const auto old_size = pending_.size();
179 return same_page(candidate, request);
181 const auto removed = old_size - pending_.size();
182 if (removed > 1) stats_.coalesced += removed - 1;
188 if (!request)
return std::nullopt;
194 std::uint64_t source_generation)
noexcept {
195 const auto old_size = pending_.size();
196 std::erase_if(pending_, [source_id, source_generation](
198 return request.source_id == source_id &&
199 request.source_generation == source_generation;
201 const auto removed = old_size - pending_.size();
202 stats_.cancelled += removed;
207 std::uint64_t requester_generation)
noexcept {
208 const auto old_size = pending_.size();
209 std::erase_if(pending_, [requester_id, requester_generation](
211 return request.requester_id == requester_id &&
212 request.requester_generation == requester_generation;
214 const auto removed = old_size - pending_.size();
215 stats_.cancelled += removed;
220 auto result = stats_;
221 result.
pending = pending_.size();
222 result.capacity = capacity_;
228 return request.source_id != 0 && request.source_generation != 0 &&
229 request.requester_id != 0 && request.requester_generation != 0 &&
230 request.frame_count != 0 &&
231 request.consumption_frames_per_second > 0.0 &&
232 std::isfinite(request.consumption_frames_per_second);
235 static bool same_page(
const SampleStreamPageRequest& left,
236 const SampleStreamPageRequest& right)
noexcept {
237 return left.source_id == right.source_id &&
238 left.source_generation == right.source_generation &&
239 left.page_index == right.page_index;
242 static bool same_demand(
const SampleStreamPageRequest& left,
243 const SampleStreamPageRequest& right)
noexcept {
244 return same_page(left, right) &&
245 left.requester_id == right.requester_id &&
246 left.requester_generation == right.requester_generation;
249 static bool more_urgent(
const SampleStreamPageRequest& left,
250 const SampleStreamPageRequest& right)
noexcept {
251 const long double left_scaled =
252 static_cast<long double>(
left.resident_source_frames) *
253 static_cast<long double>(
right.consumption_frames_per_second);
254 const long double right_scaled =
255 static_cast<long double>(
right.resident_source_frames) *
256 static_cast<long double>(
left.consumption_frames_per_second);
257 if (left_scaled != right_scaled)
return left_scaled < right_scaled;
258 if (
left.demand_class !=
right.demand_class)
259 return left.demand_class <
right.demand_class;
263 static bool strictly_more_urgent(
const SampleStreamPageRequest& left,
264 const SampleStreamPageRequest& right)
noexcept {
265 const long double left_scaled =
266 static_cast<long double>(
left.resident_source_frames) *
267 static_cast<long double>(
right.consumption_frames_per_second);
268 const long double right_scaled =
269 static_cast<long double>(
right.resident_source_frames) *
270 static_cast<long double>(
left.consumption_frames_per_second);
271 if (left_scaled != right_scaled)
return left_scaled < right_scaled;
272 return left.demand_class <
right.demand_class;
275 void renumber_sequences() noexcept {
276 std::sort(pending_.begin(), pending_.end(),
277 [](
const auto& left,
const auto& right)
noexcept {
278 return left.sequence < right.sequence;
280 std::uint64_t sequence = 1;
281 for (
auto& request : pending_)
request.sequence = sequence++;
282 next_sequence_ = sequence;
285 std::vector<SampleStreamPageRequest> pending_;
286 std::size_t capacity_ = 0;
287 std::uint64_t next_sequence_ = 1;
288 SampleStreamSchedulerStats stats_{};
Definition sample_stream_scheduler.hpp:55
runtime::SpscQueueTelemetry telemetry() const noexcept
Definition sample_stream_scheduler.hpp:65
std::optional< SampleStreamPageRequest > try_pop() noexcept
Definition sample_stream_scheduler.hpp:61
bool try_push(const SampleStreamPageRequest &request) noexcept
Definition sample_stream_scheduler.hpp:57
static constexpr std::size_t capacity() noexcept
Definition sample_stream_scheduler.hpp:69
Single-owner background scheduler for shared sample-cache page fills.
Definition sample_stream_scheduler.hpp:79
SampleStreamSchedulerStats stats() const noexcept
Definition sample_stream_scheduler.hpp:219
SampleStreamScheduleStatus submit_or_refresh(SampleStreamPageRequest request) noexcept
Definition sample_stream_scheduler.hpp:102
std::optional< SampleStreamPageRequest > most_urgent() const noexcept
Definition sample_stream_scheduler.hpp:150
std::optional< SampleStreamPageRequest > most_urgent_if(Predicate &&predicate) const noexcept
Definition sample_stream_scheduler.hpp:157
void reset() noexcept
Definition sample_stream_scheduler.hpp:93
bool prepared() const noexcept
Definition sample_stream_scheduler.hpp:100
bool prepare(std::size_t capacity)
Definition sample_stream_scheduler.hpp:81
std::size_t complete_page(const SampleStreamPageRequest &request) noexcept
Definition sample_stream_scheduler.hpp:176
std::size_t drain(SampleStreamRequestInbox< Capacity > &inbox) noexcept
Definition sample_stream_scheduler.hpp:141
std::size_t cancel_requester(std::uint64_t requester_id, std::uint64_t requester_generation) noexcept
Definition sample_stream_scheduler.hpp:206
bool has_page_interest(const SampleStreamPageRequest &request) const noexcept
Definition sample_stream_scheduler.hpp:169
std::size_t cancel_source_generation(std::uint64_t source_id, std::uint64_t source_generation) noexcept
Definition sample_stream_scheduler.hpp:193
std::optional< SampleStreamPageRequest > pop_most_urgent() noexcept
Definition sample_stream_scheduler.hpp:186
Definition spsc_queue.hpp:23
Definition analyzer_provider.hpp:12
SampleStreamDemandClass
Definition sample_stream_scheduler.hpp:15
@ Sustain
Definition sample_stream_scheduler.hpp:17
SampleStreamScheduleStatus
Definition sample_stream_scheduler.hpp:35
@ Inserted
Definition sample_stream_scheduler.hpp:36
@ Refreshed
Definition sample_stream_scheduler.hpp:37
@ Invalid
Definition sample_stream_scheduler.hpp:39
@ Full
Definition sample_stream_scheduler.hpp:38
@ Release
Definition instrument_envelope.hpp:14
@ Sustain
Definition instrument_envelope.hpp:13
@ Attack
Definition instrument_envelope.hpp:10
@ Invalid
Definition sample_mip_sidecar.hpp:13
@ right
Definition canvas.hpp:221
@ left
Definition canvas.hpp:221
Definition sample_stream_scheduler.hpp:42
std::uint64_t coalesced
Definition sample_stream_scheduler.hpp:50
std::size_t pending
Definition sample_stream_scheduler.hpp:43
std::uint64_t refreshed
Definition sample_stream_scheduler.hpp:46
std::uint64_t rejected_invalid
Definition sample_stream_scheduler.hpp:48
std::uint64_t inserted
Definition sample_stream_scheduler.hpp:45
std::uint64_t cancelled
Definition sample_stream_scheduler.hpp:51
std::uint64_t rejected_full
Definition sample_stream_scheduler.hpp:47
std::size_t capacity
Definition sample_stream_scheduler.hpp:44
std::uint64_t displaced_less_urgent
Definition sample_stream_scheduler.hpp:49
Definition spsc_queue.hpp:12