-
Notifications
You must be signed in to change notification settings - Fork 54
Expand file tree
/
Copy pathoptimizer_event_publisher.cc
More file actions
126 lines (111 loc) · 4.66 KB
/
Copy pathoptimizer_event_publisher.cc
File metadata and controls
126 lines (111 loc) · 4.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "kv_cache_manager/event/optimizer_event_publisher.h"
#include <utility>
#include "kv_cache_manager/common/logger.h"
#include "kv_cache_manager/event/base_event.h"
#include "kv_cache_manager/event/spec_events/optimizer_event.h"
#include "kv_cache_manager/protocol/protobuf/optimizer_service.pb.h"
namespace kv_cache_manager {
OptimizerEventPublisher::OptimizerEventPublisher(std::shared_ptr<EventSink> sink,
const OptimizerEventPublisherConfig &config)
: sink_(std::move(sink)), config_(config) {}
OptimizerEventPublisher::~OptimizerEventPublisher() {
if (running_) {
Stop();
}
}
bool OptimizerEventPublisher::Init(const std::string & /*config*/) {
if (!sink_) {
KVCM_LOG_ERROR("OptimizerEventPublisher: no sink provided");
return false;
}
InitBasicQueue(config_.queue_size());
running_ = true;
worker_ = std::thread(&OptimizerEventPublisher::WorkerThread, this);
KVCM_LOG_INFO("OptimizerEventPublisher: initialized, queue_size=%zu", config_.queue_size());
return true;
}
bool OptimizerEventPublisher::Publish(const std::shared_ptr<BaseEvent> &event) {
if (!event || !running_) {
return false;
}
// Runs on a serving thread: enqueue and return, nothing else. A full queue
// drops the event (counted by the base class) without surfacing an expected
// best-effort drop as a publish failure and triggering a warning per request.
BasicEnqueue(event);
return true;
}
bool OptimizerEventPublisher::Stop() {
if (!running_) {
return true;
}
running_ = false;
ClearBasicQueue();
// Required, not belt-and-braces: BasicWait() blocks in
// condition_variable::wait(), whose predicate is only re-evaluated when it
// is notified. Clearing running_ alone leaves the worker asleep and join()
// below would never return.
if (basic_queue_) {
basic_queue_->queue_cv.notify_all();
}
if (worker_.joinable()) {
worker_.join();
}
if (sink_) {
sink_->Stop();
}
KVCM_LOG_INFO("OptimizerEventPublisher: stopped, forwarded=%zu skipped=%zu queue_dropped=%zu",
forwarded_.load(),
skipped_.load(),
BasicDroppedCount());
return true;
}
void OptimizerEventPublisher::WorkerThread() {
// A single worker keeps conversion and delivery off serving threads
// without adding synchronization between multiple consumers of the queue.
while (running_) {
BasicWait();
std::shared_ptr<BaseEvent> event;
while (BasicDequeue(event)) {
proto::optimizer::TraceQueryRequest request;
if (!Convert(event, &request)) {
skipped_.fetch_add(1);
continue;
}
if (sink_->Send(request)) {
forwarded_.fetch_add(1);
}
}
}
}
bool OptimizerEventPublisher::Convert(const std::shared_ptr<BaseEvent> &event,
proto::optimizer::TraceQueryRequest *out) {
// Every publisher registered with EventManager sees every event, so write
// and reclaim events arrive here too. Only cache reads can be replayed.
const auto *get_event = dynamic_cast<const CacheGetEvent *>(event.get());
if (get_event == nullptr) {
return false;
}
out->set_trace_id(get_event->trace_id());
// CacheGetEvent's source is the instance the request was served for.
out->set_instance_id(get_event->event_source());
for (const auto key : get_event->get_keys()) {
out->add_block_keys(key);
}
for (const auto &location_spec_name : get_event->location_spec_names()) {
out->add_location_spec_names(location_spec_name);
}
// The event carries microseconds; the replay works in nanoseconds.
out->set_timestamp_ns(get_event->event_trigger_time_us() * 1000);
// Only the token count is needed, never the ids. An empty tokens vector
// means the caller passed pre-computed keys instead, and then the exact
// input length is simply not known here: 0 says "unknown" and the
// consumer infers it from block count times block size. That inference
// loses the trailing partial block, which biases the hit rate upwards -
// the opposite direction from dropped events, so the two do not cancel.
out->set_input_token_len(static_cast<std::int64_t>(get_event->get_tokens().size()));
// An empty block_keys list is legitimate, not junk: a prompt shorter than
// one block has no complete block. Its input_token_len still belongs in
// the hit-rate denominator, so the event is forwarded as-is.
return true;
}
} // namespace kv_cache_manager