Coverage Report

Created: 2025-12-28 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/criterion-0.5.1/src/connection.rs
Line
Count
Source
1
use crate::report::BenchmarkId as InternalBenchmarkId;
2
use crate::Throughput;
3
use std::cell::RefCell;
4
use std::convert::TryFrom;
5
use std::io::{Read, Write};
6
use std::mem::size_of;
7
use std::net::TcpStream;
8
9
#[derive(Debug)]
10
pub enum MessageError {
11
    Deserialization(ciborium::de::Error<std::io::Error>),
12
    Serialization(ciborium::ser::Error<std::io::Error>),
13
    Io(std::io::Error),
14
}
15
impl From<ciborium::de::Error<std::io::Error>> for MessageError {
16
0
    fn from(other: ciborium::de::Error<std::io::Error>) -> Self {
17
0
        MessageError::Deserialization(other)
18
0
    }
19
}
20
impl From<ciborium::ser::Error<std::io::Error>> for MessageError {
21
0
    fn from(other: ciborium::ser::Error<std::io::Error>) -> Self {
22
0
        MessageError::Serialization(other)
23
0
    }
24
}
25
impl From<std::io::Error> for MessageError {
26
0
    fn from(other: std::io::Error) -> Self {
27
0
        MessageError::Io(other)
28
0
    }
29
}
30
impl std::fmt::Display for MessageError {
31
0
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32
0
        match self {
33
0
            MessageError::Deserialization(error) => write!(
34
0
                f,
35
0
                "Failed to deserialize message to Criterion.rs benchmark:\n{}",
36
                error
37
            ),
38
0
            MessageError::Serialization(error) => write!(
39
0
                f,
40
0
                "Failed to serialize message to Criterion.rs benchmark:\n{}",
41
                error
42
            ),
43
0
            MessageError::Io(error) => write!(
44
0
                f,
45
0
                "Failed to read or write message to Criterion.rs benchmark:\n{}",
46
                error
47
            ),
48
        }
49
0
    }
50
}
51
impl std::error::Error for MessageError {
52
0
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
53
0
        match self {
54
0
            MessageError::Deserialization(err) => Some(err),
55
0
            MessageError::Serialization(err) => Some(err),
56
0
            MessageError::Io(err) => Some(err),
57
        }
58
0
    }
59
}
60
61
// Use str::len as a const fn once we bump MSRV over 1.39.
62
const RUNNER_MAGIC_NUMBER: &str = "cargo-criterion";
63
const RUNNER_HELLO_SIZE: usize = 15 //RUNNER_MAGIC_NUMBER.len() // magic number
64
    + (size_of::<u8>() * 3); // version number
65
66
const BENCHMARK_MAGIC_NUMBER: &str = "Criterion";
67
const BENCHMARK_HELLO_SIZE: usize = 9 //BENCHMARK_MAGIC_NUMBER.len() // magic number
68
    + (size_of::<u8>() * 3) // version number
69
    + size_of::<u16>() // protocol version
70
    + size_of::<u16>(); // protocol format
71
const PROTOCOL_VERSION: u16 = 1;
72
const PROTOCOL_FORMAT: u16 = 1;
73
74
#[derive(Debug)]
75
struct InnerConnection {
76
    socket: TcpStream,
77
    receive_buffer: Vec<u8>,
78
    send_buffer: Vec<u8>,
79
    // runner_version: [u8; 3],
80
}
81
impl InnerConnection {
82
0
    pub fn new(mut socket: TcpStream) -> Result<Self, std::io::Error> {
83
        // read the runner-hello
84
0
        let mut hello_buf = [0u8; RUNNER_HELLO_SIZE];
85
0
        socket.read_exact(&mut hello_buf)?;
86
0
        assert_eq!(
87
0
            &hello_buf[0..RUNNER_MAGIC_NUMBER.len()],
88
0
            RUNNER_MAGIC_NUMBER.as_bytes(),
89
0
            "Not connected to cargo-criterion."
90
        );
91
92
0
        let i = RUNNER_MAGIC_NUMBER.len();
93
0
        let runner_version = [hello_buf[i], hello_buf[i + 1], hello_buf[i + 2]];
94
95
0
        info!("Runner version: {:?}", runner_version);
96
97
        // now send the benchmark-hello
98
0
        let mut hello_buf = [0u8; BENCHMARK_HELLO_SIZE];
99
0
        hello_buf[0..BENCHMARK_MAGIC_NUMBER.len()]
100
0
            .copy_from_slice(BENCHMARK_MAGIC_NUMBER.as_bytes());
101
0
        let mut i = BENCHMARK_MAGIC_NUMBER.len();
102
0
        hello_buf[i] = env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap();
103
0
        hello_buf[i + 1] = env!("CARGO_PKG_VERSION_MINOR").parse().unwrap();
104
0
        hello_buf[i + 2] = env!("CARGO_PKG_VERSION_PATCH").parse().unwrap();
105
0
        i += 3;
106
0
        hello_buf[i..i + 2].clone_from_slice(&PROTOCOL_VERSION.to_be_bytes());
107
0
        i += 2;
108
0
        hello_buf[i..i + 2].clone_from_slice(&PROTOCOL_FORMAT.to_be_bytes());
109
110
0
        socket.write_all(&hello_buf)?;
111
112
0
        Ok(InnerConnection {
113
0
            socket,
114
0
            receive_buffer: vec![],
115
0
            send_buffer: vec![],
116
0
            // runner_version,
117
0
        })
118
0
    }
119
120
    #[allow(dead_code)]
121
0
    pub fn recv(&mut self) -> Result<IncomingMessage, MessageError> {
122
0
        let mut length_buf = [0u8; 4];
123
0
        self.socket.read_exact(&mut length_buf)?;
124
0
        let length = u32::from_be_bytes(length_buf);
125
0
        self.receive_buffer.resize(length as usize, 0u8);
126
0
        self.socket.read_exact(&mut self.receive_buffer)?;
127
0
        let value = ciborium::de::from_reader(&self.receive_buffer[..])?;
128
0
        Ok(value)
129
0
    }
130
131
0
    pub fn send(&mut self, message: &OutgoingMessage) -> Result<(), MessageError> {
132
0
        self.send_buffer.truncate(0);
133
0
        ciborium::ser::into_writer(message, &mut self.send_buffer)?;
134
0
        let size = u32::try_from(self.send_buffer.len()).unwrap();
135
0
        let length_buf = size.to_be_bytes();
136
0
        self.socket.write_all(&length_buf)?;
137
0
        self.socket.write_all(&self.send_buffer)?;
138
0
        Ok(())
139
0
    }
140
}
141
142
/// This is really just a holder to allow us to send messages through a shared reference to the
143
/// connection.
144
#[derive(Debug)]
145
pub struct Connection {
146
    inner: RefCell<InnerConnection>,
147
}
148
impl Connection {
149
0
    pub fn new(socket: TcpStream) -> Result<Self, std::io::Error> {
150
        Ok(Connection {
151
0
            inner: RefCell::new(InnerConnection::new(socket)?),
152
        })
153
0
    }
154
155
    #[allow(dead_code)]
156
0
    pub fn recv(&self) -> Result<IncomingMessage, MessageError> {
157
0
        self.inner.borrow_mut().recv()
158
0
    }
159
160
0
    pub fn send(&self, message: &OutgoingMessage) -> Result<(), MessageError> {
161
0
        self.inner.borrow_mut().send(message)
162
0
    }
163
164
0
    pub fn serve_value_formatter(
165
0
        &self,
166
0
        formatter: &dyn crate::measurement::ValueFormatter,
167
0
    ) -> Result<(), MessageError> {
168
        loop {
169
0
            let response = match self.recv()? {
170
0
                IncomingMessage::FormatValue { value } => OutgoingMessage::FormattedValue {
171
0
                    value: formatter.format_value(value),
172
0
                },
173
0
                IncomingMessage::FormatThroughput { value, throughput } => {
174
0
                    OutgoingMessage::FormattedValue {
175
0
                        value: formatter.format_throughput(&throughput, value),
176
0
                    }
177
                }
178
                IncomingMessage::ScaleValues {
179
0
                    typical_value,
180
0
                    mut values,
181
                } => {
182
0
                    let unit = formatter.scale_values(typical_value, &mut values);
183
0
                    OutgoingMessage::ScaledValues {
184
0
                        unit,
185
0
                        scaled_values: values,
186
0
                    }
187
                }
188
                IncomingMessage::ScaleThroughputs {
189
0
                    typical_value,
190
0
                    throughput,
191
0
                    mut values,
192
                } => {
193
0
                    let unit = formatter.scale_throughputs(typical_value, &throughput, &mut values);
194
0
                    OutgoingMessage::ScaledValues {
195
0
                        unit,
196
0
                        scaled_values: values,
197
0
                    }
198
                }
199
0
                IncomingMessage::ScaleForMachines { mut values } => {
200
0
                    let unit = formatter.scale_for_machines(&mut values);
201
0
                    OutgoingMessage::ScaledValues {
202
0
                        unit,
203
0
                        scaled_values: values,
204
0
                    }
205
                }
206
0
                IncomingMessage::Continue => break,
207
0
                _ => panic!(),
208
            };
209
0
            self.send(&response)?;
210
        }
211
0
        Ok(())
212
0
    }
213
}
214
215
/// Enum defining the messages we can receive
216
#[derive(Debug, Deserialize)]
217
pub enum IncomingMessage {
218
    // Value formatter requests
219
    FormatValue {
220
        value: f64,
221
    },
222
    FormatThroughput {
223
        value: f64,
224
        throughput: Throughput,
225
    },
226
    ScaleValues {
227
        typical_value: f64,
228
        values: Vec<f64>,
229
    },
230
    ScaleThroughputs {
231
        typical_value: f64,
232
        values: Vec<f64>,
233
        throughput: Throughput,
234
    },
235
    ScaleForMachines {
236
        values: Vec<f64>,
237
    },
238
    Continue,
239
240
    __Other,
241
}
242
243
/// Enum defining the messages we can send
244
#[derive(Debug, Serialize)]
245
pub enum OutgoingMessage<'a> {
246
    BeginningBenchmarkGroup {
247
        group: &'a str,
248
    },
249
    FinishedBenchmarkGroup {
250
        group: &'a str,
251
    },
252
    BeginningBenchmark {
253
        id: RawBenchmarkId,
254
    },
255
    SkippingBenchmark {
256
        id: RawBenchmarkId,
257
    },
258
    Warmup {
259
        id: RawBenchmarkId,
260
        nanos: f64,
261
    },
262
    MeasurementStart {
263
        id: RawBenchmarkId,
264
        sample_count: u64,
265
        estimate_ns: f64,
266
        iter_count: u64,
267
    },
268
    MeasurementComplete {
269
        id: RawBenchmarkId,
270
        iters: &'a [f64],
271
        times: &'a [f64],
272
        plot_config: PlotConfiguration,
273
        sampling_method: SamplingMethod,
274
        benchmark_config: BenchmarkConfig,
275
    },
276
    // value formatter responses
277
    FormattedValue {
278
        value: String,
279
    },
280
    ScaledValues {
281
        scaled_values: Vec<f64>,
282
        unit: &'a str,
283
    },
284
}
285
286
// Also define serializable variants of certain things, either to avoid leaking
287
// serializability into the public interface or because the serialized form
288
// is a bit different from the regular one.
289
290
#[derive(Debug, Serialize)]
291
pub struct RawBenchmarkId {
292
    group_id: String,
293
    function_id: Option<String>,
294
    value_str: Option<String>,
295
    throughput: Vec<Throughput>,
296
}
297
impl From<&InternalBenchmarkId> for RawBenchmarkId {
298
0
    fn from(other: &InternalBenchmarkId) -> RawBenchmarkId {
299
0
        RawBenchmarkId {
300
0
            group_id: other.group_id.clone(),
301
0
            function_id: other.function_id.clone(),
302
0
            value_str: other.value_str.clone(),
303
0
            throughput: other.throughput.iter().cloned().collect(),
304
0
        }
305
0
    }
306
}
307
308
#[derive(Debug, Serialize)]
309
pub enum AxisScale {
310
    Linear,
311
    Logarithmic,
312
}
313
impl From<crate::AxisScale> for AxisScale {
314
0
    fn from(other: crate::AxisScale) -> Self {
315
0
        match other {
316
0
            crate::AxisScale::Linear => AxisScale::Linear,
317
0
            crate::AxisScale::Logarithmic => AxisScale::Logarithmic,
318
        }
319
0
    }
320
}
321
322
#[derive(Debug, Serialize)]
323
pub struct PlotConfiguration {
324
    summary_scale: AxisScale,
325
}
326
impl From<&crate::PlotConfiguration> for PlotConfiguration {
327
0
    fn from(other: &crate::PlotConfiguration) -> Self {
328
0
        PlotConfiguration {
329
0
            summary_scale: other.summary_scale.into(),
330
0
        }
331
0
    }
332
}
333
334
#[derive(Debug, Serialize)]
335
struct Duration {
336
    secs: u64,
337
    nanos: u32,
338
}
339
impl From<std::time::Duration> for Duration {
340
0
    fn from(other: std::time::Duration) -> Self {
341
0
        Duration {
342
0
            secs: other.as_secs(),
343
0
            nanos: other.subsec_nanos(),
344
0
        }
345
0
    }
346
}
347
348
#[derive(Debug, Serialize)]
349
pub struct BenchmarkConfig {
350
    confidence_level: f64,
351
    measurement_time: Duration,
352
    noise_threshold: f64,
353
    nresamples: usize,
354
    sample_size: usize,
355
    significance_level: f64,
356
    warm_up_time: Duration,
357
}
358
impl From<&crate::benchmark::BenchmarkConfig> for BenchmarkConfig {
359
0
    fn from(other: &crate::benchmark::BenchmarkConfig) -> Self {
360
0
        BenchmarkConfig {
361
0
            confidence_level: other.confidence_level,
362
0
            measurement_time: other.measurement_time.into(),
363
0
            noise_threshold: other.noise_threshold,
364
0
            nresamples: other.nresamples,
365
0
            sample_size: other.sample_size,
366
0
            significance_level: other.significance_level,
367
0
            warm_up_time: other.warm_up_time.into(),
368
0
        }
369
0
    }
370
}
371
372
/// Currently not used; defined for forwards compatibility with cargo-criterion.
373
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
374
pub enum SamplingMethod {
375
    Linear,
376
    Flat,
377
}
378
impl From<crate::ActualSamplingMode> for SamplingMethod {
379
0
    fn from(other: crate::ActualSamplingMode) -> Self {
380
0
        match other {
381
0
            crate::ActualSamplingMode::Flat => SamplingMethod::Flat,
382
0
            crate::ActualSamplingMode::Linear => SamplingMethod::Linear,
383
        }
384
0
    }
385
}