xi_trace/
chrome_trace_dump.rs

1// Copyright 2018 The xi-editor Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#![allow(
16    clippy::if_same_then_else,
17    clippy::needless_bool,
18    clippy::needless_pass_by_value,
19    clippy::ptr_arg
20)]
21
22#[cfg(all(test, feature = "benchmarks"))]
23extern crate test;
24
25use super::Sample;
26use serde_json;
27use std::io::{Error as IOError, ErrorKind as IOErrorKind, Read, Write};
28
29#[derive(Debug)]
30pub enum Error {
31    Io(IOError),
32    Json(serde_json::Error),
33    DecodingFormat(String),
34}
35
36impl From<IOError> for Error {
37    fn from(e: IOError) -> Error {
38        Error::Io(e)
39    }
40}
41
42impl From<serde_json::Error> for Error {
43    fn from(e: serde_json::Error) -> Error {
44        Error::Json(e)
45    }
46}
47
48impl From<String> for Error {
49    fn from(e: String) -> Error {
50        Error::DecodingFormat(e)
51    }
52}
53
54impl Error {
55    pub fn already_exists() -> Error {
56        Error::Io(IOError::from(IOErrorKind::AlreadyExists))
57    }
58}
59
60#[derive(Clone, Debug, Deserialize)]
61#[serde(untagged)]
62enum ChromeTraceArrayEntries {
63    Array(Vec<Sample>),
64}
65
66/// This serializes the samples into the [Chrome trace event format](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0ahUKEwiJlZmDguXYAhUD4GMKHVmEDqIQFggpMAA&url=https%3A%2F%2Fdocs.google.com%2Fdocument%2Fd%2F1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU%2Fpreview&usg=AOvVaw0tBFlVbDVBikdzLqgrWK3g).
67///
68/// # Arguments
69/// `samples` - Something that can be converted into an iterator of sample
70/// references.
71/// `format` - Which trace format to save the data in.  There are four total
72/// formats described in the document.
73/// `output` - Where to write the serialized result.
74///
75/// # Returns
76/// A `Result<(), Error>` that indicates if serialization was successful or the
77/// details of any error that occured.
78///
79/// # Examples
80/// ```norun
81/// let samples = xi_trace::samples_cloned_sorted();
82/// let mut serialized = Vec::<u8>::new();
83/// serialize(samples.iter(), serialized);
84/// ```
85pub fn serialize<W>(samples: &Vec<Sample>, output: W) -> Result<(), Error>
86where
87    W: Write,
88{
89    serde_json::to_writer(output, samples).map_err(Error::Json)
90}
91
92pub fn to_value(samples: &Vec<Sample>) -> Result<serde_json::Value, Error> {
93    serde_json::to_value(samples).map_err(Error::Json)
94}
95
96pub fn decode(samples: serde_json::Value) -> Result<Vec<Sample>, Error> {
97    serde_json::from_value(samples).map_err(Error::Json)
98}
99
100pub fn deserialize<R>(input: R) -> Result<Vec<Sample>, Error>
101where
102    R: Read,
103{
104    serde_json::from_reader(input).map_err(Error::Json)
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110    #[cfg(feature = "json_payload")]
111    use crate::TracePayloadT;
112    #[cfg(feature = "benchmarks")]
113    use test::Bencher;
114
115    #[cfg(not(feature = "json_payload"))]
116    fn to_payload(value: &'static str) -> &'static str {
117        value
118    }
119
120    #[cfg(feature = "json_payload")]
121    fn to_payload(value: &'static str) -> TracePayloadT {
122        json!({ "test": value })
123    }
124
125    #[cfg(feature = "chrome_trace_event")]
126    #[test]
127    fn test_chrome_trace_serialization() {
128        use super::super::*;
129
130        let trace = Trace::enabled(Config::with_limit_count(10));
131        trace.instant("sample1", &["test", "chrome"]);
132        trace.instant_payload("sample2", &["test", "chrome"], to_payload("payload 2"));
133        trace.instant_payload("sample3", &["test", "chrome"], to_payload("payload 3"));
134        trace.closure_payload(
135            "sample4",
136            &["test", "chrome"],
137            || {
138                let _guard = trace.block("sample5", &["test,chrome"]);
139            },
140            to_payload("payload 4"),
141        );
142
143        let samples = trace.samples_cloned_unsorted();
144
145        let mut serialized = Vec::<u8>::new();
146
147        let result = serialize(&samples, &mut serialized);
148        assert!(result.is_ok(), "{:?}", result);
149
150        let decoded_result: Vec<serde_json::Value> = serde_json::from_slice(&serialized).unwrap();
151        assert_eq!(decoded_result.len(), 8);
152        assert_eq!(decoded_result[0]["name"].as_str().unwrap(), "process_name");
153        assert_eq!(decoded_result[1]["name"].as_str().unwrap(), "thread_name");
154        for i in 2..5 {
155            assert_eq!(decoded_result[i]["name"].as_str().unwrap(), samples[i].name);
156            assert_eq!(decoded_result[i]["cat"].as_str().unwrap(), "test,chrome");
157            assert_eq!(decoded_result[i]["ph"].as_str().unwrap(), "i");
158            assert_eq!(decoded_result[i]["ts"], samples[i].timestamp_us);
159            let nth_sample = &samples[i];
160            let nth_args = nth_sample.args.as_ref().unwrap();
161            assert_eq!(decoded_result[i]["args"]["xi_payload"], json!(nth_args.payload.as_ref()));
162        }
163        assert_eq!(decoded_result[5]["ph"], "B");
164        assert_eq!(decoded_result[6]["ph"], "E");
165        assert_eq!(decoded_result[7]["ph"], "X");
166    }
167
168    #[cfg(feature = "chrome_trace_event")]
169    #[test]
170    fn test_chrome_trace_deserialization() {
171        use super::super::*;
172
173        let trace = Trace::enabled(Config::with_limit_count(10));
174        trace.instant("sample1", &["test", "chrome"]);
175        trace.instant_payload("sample2", &["test", "chrome"], to_payload("payload 2"));
176        trace.instant_payload("sample3", &["test", "chrome"], to_payload("payload 3"));
177        trace.closure_payload("sample4", &["test", "chrome"], || (), to_payload("payload 4"));
178
179        let samples = trace.samples_cloned_unsorted();
180
181        let mut serialized = Vec::<u8>::new();
182        let result = serialize(&samples, &mut serialized);
183        assert!(result.is_ok(), "{:?}", result);
184
185        let deserialized_samples = deserialize(serialized.as_slice()).unwrap();
186        assert_eq!(deserialized_samples, samples);
187    }
188
189    #[cfg(all(feature = "chrome_trace_event", feature = "benchmarks"))]
190    #[bench]
191    fn bench_chrome_trace_serialization_one_element(b: &mut Bencher) {
192        use super::*;
193
194        let mut serialized = Vec::<u8>::new();
195        let samples = vec![super::Sample::new_instant("trace1", &["benchmark", "test"], None)];
196        b.iter(|| {
197            serialized.clear();
198            serialize(&samples, &mut serialized).unwrap();
199        });
200    }
201
202    #[cfg(all(feature = "chrome_trace_event", feature = "benchmarks"))]
203    #[bench]
204    fn bench_chrome_trace_serialization_multiple_elements(b: &mut Bencher) {
205        use super::super::*;
206        use super::*;
207
208        let mut serialized = Vec::<u8>::new();
209        let samples = vec![
210            Sample::new_instant("trace1", &["benchmark", "test"], None),
211            Sample::new_instant("trace2", &["benchmark"], None),
212            Sample::new_duration("trace3", &["benchmark"], Some(to_payload("some payload")), 0, 0),
213            Sample::new_instant("trace4", &["benchmark"], None),
214        ];
215
216        b.iter(|| {
217            serialized.clear();
218            serialize(&samples, &mut serialized).unwrap();
219        });
220    }
221}