cubecl_runtime/logging/
server.rs1use core::fmt::Display;
2
3use crate::config::memory::MemoryLogLevel;
4use crate::config::streaming::StreamingLogLevel;
5use crate::config::{Logger, compilation::CompilationLogLevel, profiling::ProfilingLogLevel};
6use alloc::format;
7use alloc::string::String;
8use alloc::string::ToString;
9use async_channel::{Receiver, Sender};
10use cubecl_common::future::spawn_detached_fut;
11use cubecl_common::profile::ProfileDuration;
12
13use super::{ProfileLevel, Profiled};
14
15enum LogMessage {
16 Execution(String),
17 Compilation(String),
18 Streaming(String),
19 Memory(String),
20 Profile(String, ProfileDuration),
21 ProfileSummary,
22}
23
24#[derive(Debug)]
26pub struct ServerLogger {
27 profile_level: Option<ProfileLevel>,
28 log_compile_info: bool,
29 log_compile_source: bool,
30 log_streaming: StreamingLogLevel,
31 log_channel: Option<Sender<LogMessage>>,
32 log_memory: MemoryLogLevel,
33}
34
35impl Default for ServerLogger {
36 fn default() -> Self {
37 let logger = Logger::new();
38
39 let disabled = matches!(
40 logger.config.compilation.logger.level,
41 CompilationLogLevel::Disabled
42 ) && matches!(
43 logger.config.profiling.logger.level,
44 ProfilingLogLevel::Disabled
45 ) && matches!(logger.config.memory.logger.level, MemoryLogLevel::Disabled)
46 && matches!(
47 logger.config.streaming.logger.level,
48 StreamingLogLevel::Disabled
49 );
50
51 if disabled {
52 return Self {
53 profile_level: None,
54 log_compile_info: false,
55 log_compile_source: false,
56 log_streaming: StreamingLogLevel::Disabled,
57 log_channel: None,
58 log_memory: MemoryLogLevel::Disabled,
59 };
60 }
61 let profile_level = match logger.config.profiling.logger.level {
62 ProfilingLogLevel::Disabled => None,
63 ProfilingLogLevel::Minimal => Some(ProfileLevel::ExecutionOnly),
64 ProfilingLogLevel::Basic => Some(ProfileLevel::Basic),
65 ProfilingLogLevel::Medium => Some(ProfileLevel::Medium),
66 ProfilingLogLevel::Full => Some(ProfileLevel::Full),
67 };
68
69 let log_compile_info = match logger.config.compilation.logger.level {
70 CompilationLogLevel::Disabled => false,
71 CompilationLogLevel::Basic => true,
72 CompilationLogLevel::Full => true,
73 };
74 let log_compile_source = matches!(
75 logger.config.compilation.logger.level,
76 CompilationLogLevel::Full
77 );
78 let log_streaming = logger.config.streaming.logger.level;
79 let log_memory = logger.config.memory.logger.level;
80
81 let (send, rec) = async_channel::unbounded();
82
83 let async_logger = AsyncLogger {
85 message: rec,
86 logger,
87 profiled: Default::default(),
88 };
89 spawn_detached_fut(async_logger.process());
91
92 Self {
93 profile_level,
94 log_compile_info,
95 log_compile_source,
96 log_streaming,
97 log_memory,
98 log_channel: Some(send),
99 }
100 }
101}
102
103impl ServerLogger {
104 pub fn profile_level(&self) -> Option<ProfileLevel> {
106 self.profile_level
107 }
108
109 pub fn compilation_activated(&self) -> bool {
111 self.log_compile_info
112 }
113
114 pub fn compilation_source_activated(&self) -> bool {
120 self.log_compile_source
121 }
122
123 pub fn log_compilation<I>(&self, arg: &I)
125 where
126 I: Display,
127 {
128 if let Some(channel) = &self.log_channel
129 && self.log_compile_info
130 {
131 let _ = channel.try_send(LogMessage::Compilation(arg.to_string()));
133 }
134 }
135
136 pub fn log_streaming<I: FnOnce() -> String, C: FnOnce(StreamingLogLevel) -> bool>(
138 &self,
139 cond: C,
140 format: I,
141 ) {
142 if let Some(channel) = &self.log_channel
143 && cond(self.log_streaming)
144 {
145 let _ = channel.try_send(LogMessage::Streaming(format()));
147 }
148 }
149
150 pub fn log_memory<I: FnOnce() -> String, C: FnOnce(MemoryLogLevel) -> bool>(
152 &self,
153 cond: C,
154 format: I,
155 ) {
156 if let Some(channel) = &self.log_channel
157 && cond(self.log_memory)
158 {
159 let _ = channel.try_send(LogMessage::Memory(format()));
161 }
162 }
163
164 pub fn register_execution(&self, name: impl Display) {
166 if let Some(channel) = &self.log_channel
167 && matches!(self.profile_level, Some(ProfileLevel::ExecutionOnly))
168 {
169 let _ = channel.try_send(LogMessage::Execution(name.to_string()));
171 }
172 }
173
174 pub fn register_profiled(&self, name: impl Display, duration: ProfileDuration) {
176 if let Some(channel) = &self.log_channel
177 && self.profile_level.is_some()
178 {
179 let _ = channel.try_send(LogMessage::Profile(name.to_string(), duration));
181 }
182 }
183
184 pub fn profile_summary(&self) {
186 if let Some(channel) = &self.log_channel
187 && self.profile_level.is_some()
188 {
189 let _ = channel.try_send(LogMessage::ProfileSummary);
191 }
192 }
193}
194
195struct AsyncLogger {
196 message: Receiver<LogMessage>,
197 logger: Logger,
198 profiled: Profiled,
199}
200
201impl AsyncLogger {
202 async fn process(mut self) {
203 while let Ok(msg) = self.message.recv().await {
204 match msg {
205 LogMessage::Compilation(msg) => {
206 self.logger.log_compilation(&msg);
207 }
208 LogMessage::Streaming(msg) => {
209 self.logger.log_streaming(&msg);
210 }
211 LogMessage::Memory(msg) => {
212 self.logger.log_memory(&msg);
213 }
214 LogMessage::Profile(name, profile) => {
215 let duration = profile.resolve().await.duration();
216 self.profiled.update(&name, duration);
217 self.logger
218 .log_profiling(&format!("| {duration:<10?} | {name}"));
219 }
220 LogMessage::Execution(name) => {
221 self.logger.log_profiling(&format!("Executing {name}"));
222 }
223 LogMessage::ProfileSummary => {
224 if !self.profiled.is_empty() {
225 self.logger.log_profiling(&self.profiled);
226 self.profiled = Profiled::default();
227 }
228 }
229 }
230 }
231 }
232}