1use anyhow::Result;
5use fuchsia_async::{Interval, MonotonicDuration};
6use fuchsia_trace::{category_enabled, counter};
7use fuchsia_trace_observer::TraceObserver;
8use futures::{StreamExt, select};
9use log::debug;
10use stalls::StallProvider;
11use stalls::refaults::RefaultProvider;
12use std::ffi::CStr;
13const CATEGORY_MEMORY_KERNEL: &'static CStr = c"memory:kernel";
14use futures::future::FutureExt;
15
16pub async fn serve_forever(
20 kernel_stats: impl fidl_fuchsia_kernel::StatsProxyInterface,
21 stall_provider: impl StallProvider,
22 page_refault_tracker: impl RefaultProvider,
23) {
24 fuchsia_trace_provider::trace_provider_create_with_fdio();
25 fuchsia_trace_provider::trace_provider_wait_for_init();
26 debug!("Start serving traces");
27 let trace_observer = TraceObserver::new();
28 loop {
29 let delay_in_secs = 1;
30 let mut interval = Interval::new(MonotonicDuration::from_seconds(1));
31 while category_enabled(CATEGORY_MEMORY_KERNEL) {
32 if let Err(err) = publish_one_sample(
33 &kernel_stats,
34 stall_provider.clone(),
35 page_refault_tracker.clone(),
36 )
37 .await
38 {
39 log::warn!("Failed to trace on category {:?} : {:?}", CATEGORY_MEMORY_KERNEL, err);
40 }
41 debug!("Wait for {} second(s)", delay_in_secs);
42 select! {
43 _ = interval.next() => (),
44 _ = trace_observer.on_state_changed().fuse() => (),
45 };
46 }
47 debug!("Trace category {:?} not active. Waiting.", CATEGORY_MEMORY_KERNEL);
48 let _ = trace_observer.on_state_changed().await;
49 debug!("Trace event detected");
50 }
51}
52
53async fn publish_one_sample(
54 kernel_stats: &impl fidl_fuchsia_kernel::StatsProxyInterface,
55 stall_provider: impl StallProvider,
56 page_refault_tracker: impl RefaultProvider,
57) -> Result<()> {
58 debug!("Publish trace records for category {:?}", CATEGORY_MEMORY_KERNEL);
59 let mem_stats = kernel_stats.get_memory_stats().await?;
60 counter!(CATEGORY_MEMORY_KERNEL, c"kmem_stats_a",0,
62 "total_bytes"=>mem_stats.total_bytes.unwrap_or_default(),
63 "free_bytes"=>mem_stats.free_bytes.unwrap_or_default(),
64 "free_loaned_bytes"=>mem_stats.free_loaned_bytes.unwrap_or_default(),
65 "wired_bytes"=>mem_stats.wired_bytes.unwrap_or_default(),
66 "total_heap_bytes"=>mem_stats.total_heap_bytes.unwrap_or_default(),
67 "free_heap_bytes"=>mem_stats.free_heap_bytes.unwrap_or_default(),
68 "vmo_bytes"=>mem_stats.vmo_bytes.unwrap_or_default(),
69 "mmu_overhead_bytes"=>mem_stats.mmu_overhead_bytes.unwrap_or_default(),
70 "ipc_bytes"=>mem_stats.ipc_bytes.unwrap_or_default(),
71 "cache_bytes"=>mem_stats.cache_bytes.unwrap_or_default(),
72 "slab_bytes"=>mem_stats.slab_bytes.unwrap_or_default(),
73 "zram_bytes"=>mem_stats.zram_bytes.unwrap_or_default(),
74 "other_bytes"=>mem_stats.other_bytes.unwrap_or_default()
75 );
76 counter!(CATEGORY_MEMORY_KERNEL, c"kmem_stats_b", 0,
77 "vmo_reclaim_total_bytes"=>mem_stats.vmo_reclaim_total_bytes.unwrap_or_default(),
78 "vmo_reclaim_newest_bytes"=>mem_stats.vmo_reclaim_newest_bytes.unwrap_or_default(),
79 "vmo_reclaim_oldest_bytes"=>mem_stats.vmo_reclaim_oldest_bytes.unwrap_or_default(),
80 "vmo_reclaim_disabled_bytes"=>mem_stats.vmo_reclaim_disabled_bytes.unwrap_or_default(),
81 "vmo_discardable_locked_bytes"=>mem_stats.vmo_discardable_locked_bytes.unwrap_or_default(),
82 "vmo_discardable_unlocked_bytes"=>mem_stats.vmo_discardable_unlocked_bytes.unwrap_or_default()
83 );
84 let cmp_stats = kernel_stats.get_memory_stats_compression().await?;
85 counter!(CATEGORY_MEMORY_KERNEL, c"kmem_stats_compression", 0,
86 "uncompressed_storage_bytes"=>cmp_stats.uncompressed_storage_bytes.unwrap_or_default(),
87 "compressed_storage_bytes"=>cmp_stats.compressed_storage_bytes.unwrap_or_default(),
88 "compressed_fragmentation_bytes"=>cmp_stats.compressed_fragmentation_bytes.unwrap_or_default(),
89 "compression_time"=>cmp_stats.compression_time.unwrap_or_default(),
90 "decompression_time"=>cmp_stats.decompression_time.unwrap_or_default(),
91 "total_page_compression_attempts"=>cmp_stats.total_page_compression_attempts.unwrap_or_default(),
92 "failed_page_compression_attempts"=>cmp_stats.failed_page_compression_attempts.unwrap_or_default(),
93 "total_page_decompressions"=>cmp_stats.total_page_decompressions.unwrap_or_default(),
94 "compressed_page_evictions"=>cmp_stats.compressed_page_evictions.unwrap_or_default(),
95 "eager_page_compressions"=>cmp_stats.eager_page_compressions.unwrap_or_default(),
96 "memory_pressure_page_compressions"=>cmp_stats.memory_pressure_page_compressions.unwrap_or_default(),
97 "critical_memory_page_compressions"=>cmp_stats.critical_memory_page_compressions.unwrap_or_default()
98 );
99
100 if let Some(pd) = cmp_stats.pages_decompressed_within_log_time {
101 counter!(
102 CATEGORY_MEMORY_KERNEL,
103 c"kmem_stats_compression_time",0,
104 "pages_decompressed_unit_ns"=>cmp_stats.pages_decompressed_unit_ns.unwrap_or_default(),
105 "pages_decompressed_within_log_time[0]"=>pd[0],
106 "pages_decompressed_within_log_time[1]"=>pd[1],
107 "pages_decompressed_within_log_time[2]"=>pd[2],
108 "pages_decompressed_within_log_time[3]"=>pd[3],
109 "pages_decompressed_within_log_time[4]"=>pd[4],
110 "pages_decompressed_within_log_time[5]"=>pd[5],
111 "pages_decompressed_within_log_time[6]"=>pd[6],
112 "pages_decompressed_within_log_time[7]"=>pd[7]
113 );
114 }
115
116 let stall_info = stall_provider.get_stall_info()?;
117 counter!(
118 CATEGORY_MEMORY_KERNEL,
119 c"memory_stall",0,
120 "stall_time_some_ns"=>u64::try_from(stall_info.some.as_nanos())?,
121 "stall_time_full_ns"=>u64::try_from(stall_info.full.as_nanos())?,
122 "page_refaults"=>page_refault_tracker.get_count()
123 );
124
125 Ok(())
126}