use perfetto_sdk::{
data_source::*,
pb_decoder::*,
producer::*,
protos::{
config::{data_source_config::*, test_config::*},
trace::{
test_event::*,
trace_packet::TracePacket,
track_event::debug_annotation::{DebugAnnotation, NestedValue, NestedValueNestedType},
},
},
};
use std::{
error::Error,
sync::{Arc, Mutex},
};
#[derive(Debug, Default)]
struct DummyFields {
field_uint32: Option<u32>,
field_int32: Option<i32>,
field_uint64: Option<u64>,
field_int64: Option<i64>,
field_fixed64: Option<u64>,
field_sfixed64: Option<i64>,
field_fixed32: Option<u32>,
field_sfixed32: Option<i32>,
field_double: Option<f64>,
field_float: Option<f32>,
field_sint64: Option<i64>,
field_sint32: Option<i32>,
field_string: Option<String>,
field_bytes: Vec<u8>,
}
impl DummyFields {
fn decode(&mut self, data: &[u8]) -> &mut Self {
use PbDecoderField::*;
const UINT32_ID: u32 = DummyFieldsFieldNumber::FieldUint32 as u32;
const INT32_ID: u32 = DummyFieldsFieldNumber::FieldInt32 as u32;
const UINT64_ID: u32 = DummyFieldsFieldNumber::FieldUint64 as u32;
const INT64_ID: u32 = DummyFieldsFieldNumber::FieldInt64 as u32;
const FIXED64_ID: u32 = DummyFieldsFieldNumber::FieldFixed64 as u32;
const SFIXED64_ID: u32 = DummyFieldsFieldNumber::FieldSfixed64 as u32;
const FIXED32_ID: u32 = DummyFieldsFieldNumber::FieldFixed32 as u32;
const SFIXED32_ID: u32 = DummyFieldsFieldNumber::FieldSfixed32 as u32;
const DOUBLE_ID: u32 = DummyFieldsFieldNumber::FieldDouble as u32;
const FLOAT_ID: u32 = DummyFieldsFieldNumber::FieldFloat as u32;
const SINT64_ID: u32 = DummyFieldsFieldNumber::FieldSint64 as u32;
const SINT32_ID: u32 = DummyFieldsFieldNumber::FieldSint32 as u32;
const STRING_ID: u32 = DummyFieldsFieldNumber::FieldString as u32;
const BYTES_ID: u32 = DummyFieldsFieldNumber::FieldBytes as u32;
for item in PbDecoder::new(data) {
match item.as_ref().unwrap_or_else(|e| panic!("Error: {}", e)) {
(UINT32_ID, Varint(v)) => self.field_uint32 = Some(*v as u32),
(INT32_ID, Varint(v)) => self.field_int32 = Some(*v as i32),
(UINT64_ID, Varint(v)) => self.field_uint64 = Some(*v),
(INT64_ID, Varint(v)) => self.field_int64 = Some(*v as i64),
(FIXED64_ID, Fixed64(v)) => self.field_fixed64 = Some(*v),
(SFIXED64_ID, Fixed64(v)) => self.field_sfixed64 = Some(*v as i64),
(FIXED32_ID, Fixed32(v)) => self.field_fixed32 = Some(*v),
(SFIXED32_ID, Fixed32(v)) => self.field_sfixed32 = Some(*v as i32),
(DOUBLE_ID, Fixed64(v)) => self.field_double = Some(f64::from_bits(*v)),
(FLOAT_ID, Fixed32(v)) => self.field_float = Some(f32::from_bits(*v)),
(SINT64_ID, Varint(v)) => self.field_sint64 = Some(*v as i64),
(SINT32_ID, Varint(v)) => self.field_sint32 = Some(*v as i32),
(STRING_ID, Delimited(v)) => {
self.field_string = Some(String::from_utf8(v.to_vec()).unwrap())
}
(BYTES_ID, Delimited(v)) => self.field_bytes = v.to_vec(),
_ => println!("WARNING: unknown DummyFields field: {:?}", item),
}
}
self
}
}
#[derive(Debug, Default)]
struct TestConfig {
message_count: Option<u32>,
max_messages_per_second: Option<u32>,
seed: Option<u32>,
message_size: Option<u32>,
send_batch_on_register: Option<bool>,
dummy_fields: Option<DummyFields>,
}
impl TestConfig {
fn decode(&mut self, data: &[u8]) -> &mut Self {
use PbDecoderField::*;
const MESSAGE_COUNT_ID: u32 = TestConfigFieldNumber::MessageCount as u32;
const MAX_MESSAGES_PER_SECOND_ID: u32 = TestConfigFieldNumber::MaxMessagesPerSecond as u32;
const SEED_ID: u32 = TestConfigFieldNumber::Seed as u32;
const MESSAGE_SIZE_ID: u32 = TestConfigFieldNumber::MessageSize as u32;
const SEND_BATCH_ON_REGISTER_ID: u32 = TestConfigFieldNumber::SendBatchOnRegister as u32;
const DUMMY_FIELDS_ID: u32 = TestConfigFieldNumber::DummyFields as u32;
for item in PbDecoder::new(data) {
match item.as_ref().unwrap_or_else(|e| panic!("Error: {}", e)) {
(MESSAGE_COUNT_ID, Varint(v)) => self.message_count = Some(*v as u32),
(MAX_MESSAGES_PER_SECOND_ID, Varint(v)) => {
self.max_messages_per_second = Some(*v as u32)
}
(SEED_ID, Varint(v)) => self.seed = Some(*v as u32),
(MESSAGE_SIZE_ID, Varint(v)) => self.message_size = Some(*v as u32),
(SEND_BATCH_ON_REGISTER_ID, Varint(v)) => {
self.send_batch_on_register = Some(*v != 0)
}
(DUMMY_FIELDS_ID, Delimited(v)) => {
let mut dummy_fields = DummyFields::default();
dummy_fields.decode(v);
self.dummy_fields = Some(dummy_fields);
}
_ => println!("WARNING: unknown TestConfig field: {:?}", item),
}
}
self
}
}
fn main() -> Result<(), Box<dyn Error>> {
const FOR_TESTING_ID: u32 = DataSourceConfigFieldNumber::ForTesting as u32;
let producer_args = ProducerInitArgsBuilder::new().backends(Backends::SYSTEM);
Producer::init(producer_args.build());
let mut data_source = DataSource::new();
let test_config = Arc::new(Mutex::new(TestConfig::default()));
let test_config_for_setup = Arc::clone(&test_config);
let setup_data = 1234;
let stop_data = 4321;
let data_source_args = DataSourceArgsBuilder::new()
.on_setup(move |inst_id, config| {
let mut test_config = test_config_for_setup.lock().unwrap();
for item in PbDecoder::new(config) {
if let (FOR_TESTING_ID, PbDecoderField::Delimited(value)) =
item.unwrap_or_else(|e| panic!("Error: {}", e))
{
test_config.decode(value);
}
}
println!("OnSetup id: {} data: {}", inst_id, setup_data);
})
.on_start(move |inst_id| {
println!("OnStart id: {} {:?}", inst_id, test_config.lock().unwrap());
})
.on_stop(move |inst_id| {
println!("OnStop id: {} data: {}", inst_id, stop_data);
});
data_source.register("com.example.custom_data_source", data_source_args.build())?;
loop {
data_source.trace(|ctx: &mut TraceContext| {
let inst_id = ctx.instance_index();
ctx.with_incremental_state(|ctx: &mut TraceContext, state| {
if state.was_cleared {
ctx.add_packet(|packet: &mut TracePacket| {
packet
.set_timestamp(10)
.set_for_testing(|for_testing: &mut TestEvent| {
for_testing.set_str(format!(
"Incremental state was cleared for inst_id: {}",
inst_id
));
});
});
state.was_cleared = false;
}
});
ctx.add_packet(|packet: &mut TracePacket| {
packet
.set_timestamp(42)
.set_for_testing(|for_testing: &mut TestEvent| {
for_testing.set_str("This is a long string");
for_testing.set_counter(10);
for_testing.set_payload(|payload: &mut TestPayload| {
payload.set_debug_annotations(
|debug_annotation: &mut DebugAnnotation| {
debug_annotation.set_name("This is a payload debug annotation");
debug_annotation.set_nested_value(
|nested_value: &mut NestedValue| {
nested_value.set_nested_type(
NestedValueNestedType::Unspecified,
);
nested_value.set_string_value(
"This is a nested debug annotation value",
);
},
);
},
);
for _ in 0..10 {
payload.set_str("nested");
}
});
});
});
ctx.flush(|| {});
});
std::thread::sleep(std::time::Duration::from_secs(1));
}
}