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, DebugAnnotationNestedValue, 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 = TestConfigDummyFieldsFieldNumber::FieldUint32 as u32;
const INT32_ID: u32 = TestConfigDummyFieldsFieldNumber::FieldInt32 as u32;
const UINT64_ID: u32 = TestConfigDummyFieldsFieldNumber::FieldUint64 as u32;
const INT64_ID: u32 = TestConfigDummyFieldsFieldNumber::FieldInt64 as u32;
const FIXED64_ID: u32 = TestConfigDummyFieldsFieldNumber::FieldFixed64 as u32;
const SFIXED64_ID: u32 = TestConfigDummyFieldsFieldNumber::FieldSfixed64 as u32;
const FIXED32_ID: u32 = TestConfigDummyFieldsFieldNumber::FieldFixed32 as u32;
const SFIXED32_ID: u32 = TestConfigDummyFieldsFieldNumber::FieldSfixed32 as u32;
const DOUBLE_ID: u32 = TestConfigDummyFieldsFieldNumber::FieldDouble as u32;
const FLOAT_ID: u32 = TestConfigDummyFieldsFieldNumber::FieldFloat as u32;
const SINT64_ID: u32 = TestConfigDummyFieldsFieldNumber::FieldSint64 as u32;
const SINT32_ID: u32 = TestConfigDummyFieldsFieldNumber::FieldSint32 as u32;
const STRING_ID: u32 = TestConfigDummyFieldsFieldNumber::FieldString as u32;
const BYTES_ID: u32 = TestConfigDummyFieldsFieldNumber::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 setup_data = 1234;
let test_configs: Arc<Mutex<[Option<TestConfig>; 8]>> =
Arc::new(Mutex::new([None, None, None, None, None, None, None, None]));
let test_configs_for_on_setup = Arc::clone(&test_configs);
let stop_guards: Arc<Mutex<[Option<StopGuard>; 8]>> =
Arc::new(Mutex::new([None, None, None, None, None, None, None, None]));
let stop_guards_for_on_stop = Arc::clone(&stop_guards);
let data_source_args = DataSourceArgsBuilder::new()
.on_setup(move |inst_id, config, _| {
let mut test_configs = test_configs_for_on_setup.lock().unwrap();
let mut test_config = TestConfig::default();
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);
}
}
test_configs[inst_id as usize] = Some(test_config);
println!("OnSetup id: {} data: {}", inst_id, setup_data);
})
.on_start(move |inst_id, _| {
println!(
"OnStart id: {} {:?}",
inst_id,
test_configs.lock().unwrap()[inst_id as usize]
);
})
.on_stop(move |inst_id, args| {
let mut stop_guards = stop_guards_for_on_stop.lock().unwrap();
stop_guards[inst_id as usize] = Some(args.postpone());
println!("OnStop id: {}", inst_id);
});
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 TestEventTestPayload| {
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 DebugAnnotationNestedValue| {
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");
}
});
});
});
if let Some(stop_guard) = stop_guards.lock().unwrap()[inst_id as usize].take() {
ctx.add_packet(|packet: &mut TracePacket| {
packet
.set_timestamp(10)
.set_for_testing(|for_testing: &mut TestEvent| {
for_testing
.set_str(format!("Asynchronous stop for inst_id: {}", inst_id));
});
});
ctx.flush(|| {});
drop(stop_guard);
}
});
std::thread::sleep(std::time::Duration::from_secs(1));
}
}