1#[cfg(feature = "collateral_manager")]
7use crate::collateral::{CollateralManager, CollateralTree, ItemPath, PVSS};
8use crate::errata::Errata;
9use crate::error::Error;
10use crate::node::Node;
11#[cfg(not(feature = "std"))]
12use alloc::{
13 fmt, format,
14 string::{String, ToString},
15 vec,
16 vec::Vec,
17};
18#[cfg(feature = "std")]
19use std::fmt;
20
21pub mod record_types {
25 pub const PMC: u8 = 0x1;
26 pub const PMC_FW_TRACE: u8 = 0x2;
27 pub const PUNIT: u8 = 0x3;
28 pub const PCORE: u8 = 0x4;
29 pub const ECORE: u8 = 0x6;
30 pub const UNCORE: u8 = 0x8;
31 pub const PMC_TRACE: u8 = 0x11;
32 pub const TCSS: u8 = 0x16;
33 pub const PMC_RST: u8 = 0x17;
34 pub const PCODE: u8 = 0x19;
35 pub const CRASHLOG_AGENT: u8 = 0x1C;
36 pub const BOX: u8 = 0x3D;
37 pub const MCA: u8 = 0x3E;
38}
39
40#[derive(Debug, Default, Clone)]
41pub enum HeaderType {
42 Type0,
43 #[default]
44 Type1,
45 Type2 {
46 timestamp: u64,
47 agent_version: u32,
48 reason: u32,
49 },
50 Type3 {
51 timestamp: u64,
52 agent_version: u32,
53 reason: u32,
54 completion_status: u32,
55 collection_complete: bool,
56 },
57 Type4 {
58 timestamp: u64,
59 agent_version: u32,
60 reason: u32,
61 whoami: u32,
62 misc: u32,
63 },
64 Type5 {
65 timestamp: u64,
66 agent_version: u32,
67 reason: u32,
68 completion_status: u32,
69 collection_complete: bool,
70 error_status: u32,
71 },
72 Type6 {
73 timestamp: u64,
74 agent_version: u32,
75 reason: u32,
76 die_id: u8,
77 socket_id: u8,
78 completion_status_size: u16,
79 completion_status: Vec<u32>,
80 collection_complete: bool,
81 },
82
83 Type0LegacyServer {
84 timestamp: u64,
85 agent_version: u32,
86 reason: u32,
87 die_id: u8,
88 socket_id: u8,
89 completion_status: u32,
90 collection_complete: bool,
91 },
92
93 Type0LegacyGpu {
94 timestamp: u64,
95 agent_version: u32,
96 reason: u32,
97 completion_status: u32,
98 collection_complete: bool,
99 },
100}
101
102impl HeaderType {
103 fn type2_from_slice(slice: &[u8]) -> Option<Self> {
104 let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
105 let agent_version = u32::from_le_bytes(slice.get(16..20)?.try_into().ok()?);
106 let reason = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
107
108 Some(HeaderType::Type2 {
109 timestamp,
110 agent_version,
111 reason,
112 })
113 }
114
115 fn type3_from_slice(slice: &[u8]) -> Option<Self> {
116 let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
117 let agent_version = u32::from_le_bytes(slice.get(16..20)?.try_into().ok()?);
118 let reason = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
119 let cs_data = u32::from_le_bytes(slice.get(24..28)?.try_into().ok()?);
120 let completion_status = cs_data & 0x7FFFFFFF;
121 let collection_complete = (cs_data >> 31) != 0;
122
123 Some(HeaderType::Type3 {
124 timestamp,
125 agent_version,
126 reason,
127 completion_status,
128 collection_complete,
129 })
130 }
131
132 fn type4_from_slice(slice: &[u8]) -> Option<Self> {
133 let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
134 let agent_version = u32::from_le_bytes(slice.get(16..20)?.try_into().ok()?);
135 let reason = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
136 let whoami = u32::from_le_bytes(slice.get(24..28)?.try_into().ok()?);
137 let misc = u32::from_le_bytes(slice.get(28..32)?.try_into().ok()?);
138
139 Some(HeaderType::Type4 {
140 timestamp,
141 agent_version,
142 reason,
143 whoami,
144 misc,
145 })
146 }
147
148 fn type5_from_slice(slice: &[u8]) -> Option<Self> {
149 let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
150 let agent_version = u32::from_le_bytes(slice.get(16..20)?.try_into().ok()?);
151 let reason = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
152 let cs_data = u32::from_le_bytes(slice.get(24..28)?.try_into().ok()?);
153 let completion_status = cs_data & 0x7FFFFFFF;
154 let collection_complete = (cs_data >> 31) != 0;
155 let error_status = u32::from_le_bytes(slice.get(28..32)?.try_into().ok()?);
156
157 Some(HeaderType::Type5 {
158 timestamp,
159 agent_version,
160 reason,
161 completion_status,
162 collection_complete,
163 error_status,
164 })
165 }
166
167 fn type6_from_slice(slice: &[u8]) -> Option<Self> {
168 let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
169 let agent_version = u32::from_le_bytes(slice.get(16..20)?.try_into().ok()?);
170 let reason = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
171 let die_skt_info = slice.get(24..28)?;
172
173 let die_id = die_skt_info[0];
174 let socket_id = die_skt_info[1];
175 let completion_status_size = u16::from_le_bytes(die_skt_info[2..4].try_into().ok()?) & 0x7F;
176 let collection_complete = (die_skt_info[3] & 0x80) != 0;
177
178 let completion_status = (0..completion_status_size)
179 .map(|dword| {
180 let index = (28 + dword * 4) as usize;
181 Some(u32::from_le_bytes(
182 slice.get(index..index + 4)?.try_into().ok()?,
183 ))
184 })
185 .collect::<Option<Vec<u32>>>()?;
186
187 Some(HeaderType::Type6 {
188 timestamp,
189 agent_version,
190 reason,
191 die_id,
192 socket_id,
193 completion_status_size,
194 completion_status,
195 collection_complete,
196 })
197 }
198
199 fn type0_legacy_server_from_slice(slice: &[u8]) -> Option<Self> {
200 let reason = u32::from_le_bytes(slice.get(4..8)?.try_into().ok()?);
201 let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
202 let agent_version = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
203 let socket_id = *slice.get(24)?;
204 let cs_data = u32::from_le_bytes(slice.get(28..32)?.try_into().ok()?);
205 let completion_status = cs_data & 0x7FFFFFFF;
206 let collection_complete = (cs_data >> 31) != 0;
207
208 let revision = slice.first()?;
210 let die_idx = revision & 0x3;
211
212 let die_id = if ((revision >> 7) & 1) == 1 {
213 die_idx + 9
214 } else {
215 die_idx << 2
216 };
217
218 Some(HeaderType::Type0LegacyServer {
219 timestamp,
220 agent_version,
221 reason,
222 die_id,
223 socket_id,
224 completion_status,
225 collection_complete,
226 })
227 }
228
229 fn type0_legacy_gpu_from_slice(slice: &[u8]) -> Option<Self> {
230 let reason = u32::from_le_bytes(slice.get(4..8)?.try_into().ok()?);
231 let timestamp = u64::from_le_bytes(slice.get(8..16)?.try_into().ok()?);
232 let agent_version = u32::from_le_bytes(slice.get(20..24)?.try_into().ok()?);
233 let cs_data = u32::from_le_bytes(slice.get(28..32)?.try_into().ok()?);
234 let completion_status = cs_data & 0x7FFFFFFF;
235 let collection_complete = (cs_data >> 31) != 0;
236
237 Some(HeaderType::Type0LegacyGpu {
238 timestamp,
239 agent_version,
240 reason,
241 completion_status,
242 collection_complete,
243 })
244 }
245
246 pub fn from_slice(header_type_value: u16, slice: &[u8]) -> Result<Self, Error> {
247 match header_type_value {
248 0 => Ok(HeaderType::Type0),
249 1 => Ok(HeaderType::Type1),
250 2 => Self::type2_from_slice(slice).ok_or(Error::InvalidHeader),
251 3 => Self::type3_from_slice(slice).ok_or(Error::InvalidHeader),
252 4 => Self::type4_from_slice(slice).ok_or(Error::InvalidHeader),
253 5 => Self::type5_from_slice(slice).ok_or(Error::InvalidHeader),
254 6 => Self::type6_from_slice(slice).ok_or(Error::InvalidHeader),
255 type_value => Err(Error::InvalidHeaderType(type_value)),
256 }
257 }
258
259 pub fn from_slice_type0_legacy_server(slice: &[u8]) -> Result<Self, Error> {
260 Self::type0_legacy_server_from_slice(slice).ok_or(Error::InvalidHeader)
261 }
262
263 pub fn from_slice_type0_legacy_gpu(slice: &[u8]) -> Result<Self, Error> {
264 Self::type0_legacy_gpu_from_slice(slice).ok_or(Error::InvalidHeader)
265 }
266}
267
268#[derive(Debug, Default, Clone)]
270pub struct Header {
271 pub version: Version,
273 pub size: RecordSize,
275 pub header_type: HeaderType,
277}
278
279impl Header {
280 pub fn from_slice(slice: &[u8]) -> Result<Option<Self>, Error> {
282 let Some(version) = Version::from_slice(slice) else {
283 return Ok(None);
285 };
286 let errata = Errata::from_version(&version);
287
288 let size = if errata.type0_legacy_server || errata.type0_legacy_gpu {
289 RecordSize::from_slice_type0_legacy(slice).ok_or(Error::InvalidHeader)?
290 } else {
291 RecordSize::from_slice(slice).ok_or(Error::InvalidHeader)?
292 };
293
294 let header_type = if errata.type0_legacy_server {
295 HeaderType::from_slice_type0_legacy_server(slice)?
296 } else if errata.type0_legacy_gpu {
297 HeaderType::from_slice_type0_legacy_gpu(slice)?
298 } else {
299 HeaderType::from_slice(version.header_type, slice)?
300 };
301
302 Ok(Some(Header {
303 version,
304 size,
305 header_type,
306 }))
307 }
308
309 #[inline]
311 fn record_size_granularity(&self) -> usize {
312 if self.version.errata().core_record_size_bytes {
313 return 1;
314 }
315 4
316 }
317
318 #[inline]
320 pub fn record_size(&self) -> usize {
321 (self.size.record_size as usize + self.size.extended_record_size as usize)
322 * self.record_size_granularity()
323 }
324
325 #[inline]
327 pub fn extended_record_offset(&self) -> Option<usize> {
328 if self.size.extended_record_size > 0 {
329 Some(self.size.record_size as usize * self.record_size_granularity())
330 } else {
331 None
332 }
333 }
334
335 #[inline]
337 pub fn revision(&self) -> u32 {
338 self.version.revision
339 }
340
341 #[inline]
343 pub fn product_id(&self) -> u32 {
344 self.version.product_id
345 }
346
347 #[cfg(feature = "collateral_manager")]
349 pub fn product<'a, T: CollateralTree>(
350 &self,
351 cm: &'a CollateralManager<T>,
352 ) -> Result<&'a str, Error> {
353 cm.target_info
354 .get(&self.product_id())
355 .map(|target_info| target_info.product.as_str())
356 .ok_or_else(|| Error::InvalidProductID(self.product_id()))
357 }
358
359 #[cfg(feature = "collateral_manager")]
361 pub fn variant<'a, T: CollateralTree>(&self, cm: &'a CollateralManager<T>) -> Option<&'a str> {
362 cm.target_info
363 .get(&self.product_id())
364 .map(|target_info| target_info.variant.as_str())
365 }
366
367 pub fn socket_id(&self) -> u8 {
369 match self.header_type {
370 HeaderType::Type6 { socket_id, .. } => socket_id,
371 HeaderType::Type0LegacyServer { socket_id, .. } => socket_id,
372 _ => 0,
373 }
374 }
375
376 pub fn die_id(&self) -> Option<u8> {
378 match self.header_type {
379 HeaderType::Type6 { die_id, .. } => Some(die_id),
380 HeaderType::Type0LegacyServer { die_id, .. } => Some(die_id),
381 _ => None,
382 }
383 }
384
385 #[cfg(feature = "collateral_manager")]
389 pub fn die<'a, T: CollateralTree>(&self, cm: &'a CollateralManager<T>) -> Option<&'a str> {
390 self.get_die_name(&self.die_id()?, cm)
391 }
392
393 #[cfg(feature = "collateral_manager")]
394 pub(crate) fn get_die_name<'a, T: CollateralTree>(
395 &self,
396 die_id: &u8,
397 cm: &'a CollateralManager<T>,
398 ) -> Option<&'a str> {
399 let target_info = cm.target_info.get(&self.product_id())?;
400 let die_name = target_info.die_id.get(die_id)?;
401 Some(die_name)
402 }
403
404 pub fn record_type(&self) -> Result<&'static str, Error> {
406 self.version.record_type_as_str()
407 }
408
409 #[cfg(feature = "collateral_manager")]
410 pub(super) fn decode_definitions_paths<T: CollateralTree>(
411 &self,
412 cm: &CollateralManager<T>,
413 ) -> Result<Vec<ItemPath>, Error> {
414 let record_type = self.record_type()?;
415 let revision = self.revision().to_string();
416
417 Ok(if let Some(die) = self.die(cm) {
418 let die_id = die.trim_end_matches(char::is_numeric);
419 vec![ItemPath::new([
420 "decode-defs",
421 record_type,
422 die_id,
423 &revision,
424 ])]
425 } else {
426 vec![
427 ItemPath::new(["decode-defs", record_type, &revision]),
428 ItemPath::new(["decode-defs", record_type, "all"]),
429 ]
430 })
431 }
432
433 #[cfg(feature = "collateral_manager")]
434 pub fn pvss<T: CollateralTree>(&self, cm: &CollateralManager<T>) -> Result<PVSS, Error> {
436 let product = match self.product(cm) {
437 Err(Error::InvalidProductID(0)) => "all",
438 res => res?,
439 };
440 let variant = self.variant(cm).unwrap_or("all");
441
442 Ok(PVSS {
443 product: product.into(),
444 variant: variant.into(),
445 ..PVSS::default()
446 })
447 }
448
449 pub fn header_size(&self) -> usize {
451 match self.header_type {
452 HeaderType::Type0 | HeaderType::Type1 => 8,
453 HeaderType::Type2 { .. } => 24,
454 HeaderType::Type3 { .. } => 28,
455 HeaderType::Type4 { .. } => 32,
456 HeaderType::Type5 { .. } => 32,
457 HeaderType::Type6 {
458 completion_status_size,
459 ..
460 } => 28 + completion_status_size as usize * 4,
461 HeaderType::Type0LegacyServer { .. } => 32,
462 HeaderType::Type0LegacyGpu { .. } => 32,
463 }
464 }
465
466 #[cfg(feature = "collateral_manager")]
467 pub(super) fn get_root_path_using_cm<T: CollateralTree>(
468 &self,
469 cm: &CollateralManager<T>,
470 ) -> Option<String> {
471 if let HeaderType::Type6 { socket_id, .. } | HeaderType::Type0LegacyServer { socket_id, .. } =
472 self.header_type
473 && let Some(die) = self.die(cm)
474 {
475 return Some(format!("processors.cpu{socket_id}.{die}"));
476 }
477
478 None
479 }
480
481 pub(super) fn get_root_path(&self) -> Option<String> {
482 if let HeaderType::Type6 {
483 socket_id, die_id, ..
484 }
485 | HeaderType::Type0LegacyServer {
486 socket_id, die_id, ..
487 } = self.header_type
488 {
489 return Some(format!("processors.cpu{socket_id}.die{die_id}"));
490 }
491
492 None
493 }
494}
495
496impl fmt::Display for Header {
497 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
498 let record_type = self.record_type().unwrap_or("RECORD");
499 let version = format!(
500 "product_id=0x{0:x}, record_type=0x{1:x}, revision=0x{2:x}",
501 self.version.product_id, self.version.record_type, self.version.revision
502 );
503 let header_type = match self.header_type {
504 HeaderType::Type6 {
505 socket_id, die_id, ..
506 }
507 | HeaderType::Type0LegacyServer {
508 socket_id, die_id, ..
509 } => {
510 format!("die_id={die_id}, socket_id={socket_id}")
511 }
512 _ => "..".to_string(),
513 };
514
515 write!(f, "{record_type} - ({version}, {header_type})")
516 }
517}
518
519#[derive(Clone, Debug, Default)]
521pub struct Version {
522 pub revision: u32,
524 pub header_type: u16,
526 pub product_id: u32,
528 pub record_type: u8,
530 pub consumed: bool,
532 pub cldic: bool,
534}
535
536impl Version {
537 pub fn from_slice(slice: &[u8]) -> Option<Self> {
539 let version = u32::from_le_bytes(slice.get(0..4)?.try_into().ok()?);
540 log::trace!("Decoding record version: {:#x}", version);
541
542 if version == 0 || version == 0xdeadbeef {
543 return None;
545 }
546
547 Some(Version {
548 cldic: (version >> 30) & 1 == 1,
549 consumed: (version >> 31) & 1 == 1,
550 revision: version & 0xFF,
551 header_type: ((version >> 8) & 0xF) as u16,
552 product_id: (version >> 12) & 0xFFF,
553 record_type: ((version >> 24) & 0x3F) as u8,
554 })
555 }
556
557 pub fn as_u32(&self) -> u32 {
558 ((self.consumed as u32) << 31)
559 | ((self.cldic as u32) << 30)
560 | ((self.record_type as u32) << 24)
561 | (self.product_id << 12)
562 | ((self.header_type as u32) << 8)
563 | self.revision
564 }
565
566 fn record_type_as_str(&self) -> Result<&'static str, Error> {
567 Ok(match self.record_type {
568 record_types::PMC => "PMC",
569 record_types::PMC_FW_TRACE => "PMC_FW_Trace",
570 record_types::PUNIT => "Punit",
571 record_types::PCORE => "PCORE",
572 record_types::ECORE => "ECORE",
573 record_types::UNCORE => "UNCORE",
574 record_types::PMC_TRACE => "PMC_TRACE",
575 record_types::TCSS => "TCSS",
576 record_types::PMC_RST => "PMC_RST",
577 record_types::PCODE => "PCODE",
578 record_types::CRASHLOG_AGENT => "CRASHLOG_AGENT",
579 record_types::BOX => "BOX",
580 record_types::MCA => "MCA",
581 rt => return Err(Error::InvalidRecordType(rt)),
582 })
583 }
584
585 pub fn errata(&self) -> Errata {
586 Errata::from_version(self)
587 }
588}
589
590impl fmt::Display for Version {
591 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
592 let record_type = self.record_type_as_str().unwrap_or("UNKNOWN");
593 write!(f, "{} revision {}", record_type, self.revision)
594 }
595}
596
597#[derive(Debug, Default, Clone)]
599pub struct RecordSize {
600 pub record_size: u16,
602 pub extended_record_size: u16,
604}
605
606impl RecordSize {
607 pub fn from_slice(slice: &[u8]) -> Option<Self> {
609 Some(RecordSize {
610 record_size: u16::from_le_bytes(slice.get(4..6)?.try_into().ok()?),
611 extended_record_size: u16::from_le_bytes(slice.get(6..8)?.try_into().ok()?),
612 })
613 }
614
615 pub fn from_slice_type0_legacy(slice: &[u8]) -> Option<Self> {
617 Some(RecordSize {
618 record_size: u16::from_le_bytes(slice.get(16..18)?.try_into().ok()?),
619 extended_record_size: 0,
620 })
621 }
622}
623
624impl From<&RecordSize> for Node {
625 fn from(size: &RecordSize) -> Self {
626 let mut node = Node::section("record_size");
627 node.add(Node::field("record_size", size.record_size as u64));
628 node.add(Node::field(
629 "extended_record_size",
630 size.extended_record_size as u64,
631 ));
632 node
633 }
634}
635
636impl From<&Version> for Node {
637 fn from(version: &Version) -> Self {
638 let mut node = Node::field("version", version.as_u32() as u64);
639 node.add(Node::field("revision", version.revision as u64));
640 node.add(Node::field("header_type", version.header_type as u64));
641 node.add(Node::field("product_id", version.product_id as u64));
642 node.add(Node::field("record_type", version.record_type as u64));
643 node
644 }
645}
646
647impl From<&Header> for Node {
648 fn from(header: &Header) -> Self {
649 let mut node = Node::section("hdr");
650 node.add(Node::from(&header.version));
651 node.add(Node::from(&header.size));
652
653 match header.header_type {
654 HeaderType::Type2 {
655 timestamp,
656 agent_version,
657 reason,
658 } => {
659 node.add(Node::field("timestamp", timestamp));
660 node.add(Node::field("agent_version", agent_version as u64));
661 node.add(Node::field("reason", reason as u64));
662 }
663 HeaderType::Type3 {
664 timestamp,
665 agent_version,
666 reason,
667 completion_status,
668 collection_complete,
669 } => {
670 node.add(Node::field("timestamp", timestamp));
671 node.add(Node::field("agent_version", agent_version as u64));
672 node.add(Node::field("reason", reason as u64));
673
674 let mut completion_status_node = Node::section("completion_status");
675 completion_status_node
676 .add(Node::field("completion_status", completion_status as u64));
677 completion_status_node.add(Node::field(
678 "record_collection_completed",
679 collection_complete as u64,
680 ));
681 node.add(completion_status_node);
682 }
683 HeaderType::Type4 {
684 timestamp,
685 agent_version,
686 reason,
687 whoami,
688 misc,
689 } => {
690 node.add(Node::field("timestamp", timestamp));
691 node.add(Node::field("agent_version", agent_version as u64));
692 node.add(Node::field("reason", reason as u64));
693 node.add(Node::field("whoami", whoami as u64));
694 node.add(Node::field("misc", misc as u64));
695 }
696 HeaderType::Type5 {
697 timestamp,
698 agent_version,
699 reason,
700 completion_status,
701 collection_complete,
702 error_status,
703 } => {
704 node.add(Node::field("timestamp", timestamp));
705 node.add(Node::field("agent_version", agent_version as u64));
706 node.add(Node::field("reason", reason as u64));
707 node.add(Node::field("error_status", error_status as u64));
708
709 let mut completion_status_node = Node::section("completion_status");
710 completion_status_node
711 .add(Node::field("completion_status", completion_status as u64));
712 completion_status_node.add(Node::field(
713 "record_collection_completed",
714 collection_complete as u64,
715 ));
716 node.add(completion_status_node);
717 }
718 HeaderType::Type6 {
719 timestamp,
720 agent_version,
721 reason,
722 die_id,
723 socket_id,
724 ref completion_status,
725 completion_status_size,
726 collection_complete,
727 } => {
728 node.add(Node::field("timestamp", timestamp));
729 node.add(Node::field("agent_version", agent_version as u64));
730 node.add(Node::field("reason", reason as u64));
731 let mut die_skt_info = Node::section("die_skt_info");
732 die_skt_info.add(Node::field("die_id", die_id as u64));
733 die_skt_info.add(Node::field("socket_id", socket_id as u64));
734 die_skt_info.add(Node::field(
735 "completion_status_size",
736 completion_status_size as u64,
737 ));
738 die_skt_info.add(Node::field(
739 "record_collection_completed",
740 collection_complete as u64,
741 ));
742 node.add(die_skt_info);
743
744 for (i, completion_status) in completion_status.iter().enumerate() {
745 node.add(Node::field(
746 &format!("completion_status{i}"),
747 *completion_status as u64,
748 ));
749 }
750 }
751 HeaderType::Type0LegacyServer {
752 timestamp,
753 agent_version,
754 reason,
755 die_id,
756 socket_id,
757 completion_status,
758 collection_complete,
759 } => {
760 node.add(Node::field("timestamp", timestamp));
761 node.add(Node::field("agent_version", agent_version as u64));
762 node.add(Node::field("reason", reason as u64));
763 node.add(Node::field("die_id", die_id as u64));
764 node.add(Node::field("socket_id", socket_id as u64));
765 node.add(Node::field("completion_status", completion_status as u64));
766 node.add(Node::field(
767 "record_collection_completed",
768 collection_complete as u64,
769 ));
770 }
771 HeaderType::Type0LegacyGpu {
772 timestamp,
773 agent_version,
774 reason,
775 completion_status,
776 collection_complete,
777 } => {
778 node.add(Node::field("timestamp", timestamp));
779 node.add(Node::field("agent_version", agent_version as u64));
780 node.add(Node::field("reason", reason as u64));
781 node.add(Node::field("completion_status", completion_status as u64));
782 node.add(Node::field(
783 "record_collection_completed",
784 collection_complete as u64,
785 ));
786 }
787 _ => (),
788 }
789
790 node
791 }
792}