ralph_workflow/monitoring/memory_metrics/
snapshot.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct MemorySnapshot {
8 pub iteration: u32,
10 pub execution_history_len: usize,
12 pub execution_history_heap_bytes: usize,
17 pub checkpoint_count: u32,
19 pub timestamp: String,
21}
22
23impl MemorySnapshot {
24 #[must_use]
26 pub fn from_pipeline_state(state: &crate::reducer::PipelineState) -> Self {
27 let execution_history_heap_bytes = estimate_execution_history_heap_size(state);
28
29 Self {
30 iteration: state.iteration,
31 execution_history_len: state.execution_history_len(),
32 execution_history_heap_bytes,
33 checkpoint_count: state.checkpoint_saved_count,
34 timestamp: chrono::Utc::now().to_rfc3339(),
35 }
36 }
37}
38
39pub(super) fn estimate_execution_history_heap_size(state: &crate::reducer::PipelineState) -> usize {
44 use crate::checkpoint::execution_history::StepOutcome;
45
46 state
47 .execution_history()
48 .iter()
49 .map(|step| {
50 let modified_files_detail_size = step.modified_files_detail.as_ref().map_or(0, |d| {
51 let sum_list = |xs: &Option<Box<[String]>>| {
52 xs.as_ref()
53 .map_or(0, |v| v.iter().map(std::string::String::len).sum::<usize>())
54 };
55
56 sum_list(&d.added) + sum_list(&d.modified) + sum_list(&d.deleted)
57 });
58
59 let issues_summary_size = step
60 .issues_summary
61 .as_ref()
62 .and_then(|s| s.description.as_ref())
63 .map_or(0, std::string::String::len);
64
65 let base_size = step
68 .phase
69 .len()
70 .saturating_add(step.step_type.len())
71 .saturating_add(step.timestamp.len())
72 .saturating_add(step.agent.as_ref().map_or(0, |s| s.len()))
73 .saturating_add(
74 step.checkpoint_saved_at
75 .as_ref()
76 .map_or(0, std::string::String::len),
77 )
78 .saturating_add(
79 step.git_commit_oid
80 .as_ref()
81 .map_or(0, std::string::String::len),
82 )
83 .saturating_add(
84 step.prompt_used
85 .as_ref()
86 .map_or(0, std::string::String::len),
87 )
88 .saturating_add(modified_files_detail_size)
89 .saturating_add(issues_summary_size);
90
91 let outcome_size = match &step.outcome {
92 StepOutcome::Success {
93 output,
94 files_modified,
95 ..
96 } => output.as_ref().map_or(0, |s| s.len()).saturating_add(
97 files_modified.as_ref().map_or(0, |files| {
98 files.iter().map(std::string::String::len).sum::<usize>()
99 }),
100 ),
101 StepOutcome::Failure { error, signals, .. } => {
102 error
103 .len()
104 .saturating_add(signals.as_ref().map_or(0, |sigs| {
105 sigs.iter().map(std::string::String::len).sum::<usize>()
106 }))
107 }
108 StepOutcome::Partial {
109 completed,
110 remaining,
111 ..
112 } => completed.len().saturating_add(remaining.len()),
113 StepOutcome::Skipped { reason } => reason.len(),
114 };
115
116 base_size.saturating_add(outcome_size)
117 })
118 .sum()
119}