traces/
kernel.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4use anyhow::Result;
5use fuchsia_async::{Interval, MonotonicDuration};
6use fuchsia_trace::{category_enabled, counter};
7use futures::StreamExt;
8use log::debug;
9use std::ffi::CStr;
10
11use crate::watcher::Watcher;
12const CATEGORY_MEMORY_KERNEL: &'static CStr = c"memory:kernel";
13
14// Continuously monitors the 'memory:kernel' trace category.
15// Once enabled, it periodically records memory statistics until the category is disabled.
16// This function runs indefinitely
17pub async fn serve_forever(
18    mut trace_watcher: Watcher,
19    kernel_stats: impl fidl_fuchsia_kernel::StatsProxyInterface,
20) {
21    eprintln!("Start serving traces");
22    debug!("Start serving traces");
23    loop {
24        let delay_in_secs = 1;
25        let mut interval = Interval::new(MonotonicDuration::from_seconds(1));
26        while category_enabled(CATEGORY_MEMORY_KERNEL) {
27            if let Err(err) = publish_one_sample(&kernel_stats).await {
28                log::warn!("Failed to trace on category {:?} : {:?}", CATEGORY_MEMORY_KERNEL, err);
29            }
30            debug!("Wait for {} second(s)", delay_in_secs);
31            interval.next().await;
32        }
33        debug!("Trace category {:?} not active. Waiting.", CATEGORY_MEMORY_KERNEL);
34        trace_watcher.recv().await;
35        debug!("Trace event detected");
36    }
37}
38
39async fn publish_one_sample(
40    kernel_stats: &impl fidl_fuchsia_kernel::StatsProxyInterface,
41) -> Result<()> {
42    debug!("Publish trace records for category {:?}", CATEGORY_MEMORY_KERNEL);
43    let mem_stats = kernel_stats.get_memory_stats().await?;
44    // Statistics are split into two records to comply with the 15-argument limit.
45    counter!(CATEGORY_MEMORY_KERNEL, c"kmem_stats_a",0,
46        "total_bytes"=>mem_stats.total_bytes.unwrap_or_default(),
47        "free_bytes"=>mem_stats.free_bytes.unwrap_or_default(),
48        "free_loaned_bytes"=>mem_stats.free_loaned_bytes.unwrap_or_default(),
49        "wired_bytes"=>mem_stats.wired_bytes.unwrap_or_default(),
50        "total_heap_bytes"=>mem_stats.total_heap_bytes.unwrap_or_default(),
51        "free_heap_bytes"=>mem_stats.free_heap_bytes.unwrap_or_default(),
52        "vmo_bytes"=>mem_stats.vmo_bytes.unwrap_or_default(),
53        "mmu_overhead_bytes"=>mem_stats.mmu_overhead_bytes.unwrap_or_default(),
54        "ipc_bytes"=>mem_stats.ipc_bytes.unwrap_or_default(),
55        "cache_bytes"=>mem_stats.cache_bytes.unwrap_or_default(),
56        "slab_bytes"=>mem_stats.slab_bytes.unwrap_or_default(),
57        "zram_bytes"=>mem_stats.zram_bytes.unwrap_or_default(),
58        "other_bytes"=>mem_stats.other_bytes.unwrap_or_default()
59    );
60    counter!(CATEGORY_MEMORY_KERNEL, c"kmem_stats_b", 0,
61        "vmo_reclaim_total_bytes"=>mem_stats.vmo_reclaim_total_bytes.unwrap_or_default(),
62        "vmo_reclaim_newest_bytes"=>mem_stats.vmo_reclaim_newest_bytes.unwrap_or_default(),
63        "vmo_reclaim_oldest_bytes"=>mem_stats.vmo_reclaim_oldest_bytes.unwrap_or_default(),
64        "vmo_reclaim_disabled_bytes"=>mem_stats.vmo_reclaim_disabled_bytes.unwrap_or_default(),
65        "vmo_discardable_locked_bytes"=>mem_stats.vmo_discardable_locked_bytes.unwrap_or_default(),
66        "vmo_discardable_unlocked_bytes"=>mem_stats.vmo_discardable_unlocked_bytes.unwrap_or_default()
67    );
68    let cmp_stats = kernel_stats.get_memory_stats_compression().await?;
69    counter!(CATEGORY_MEMORY_KERNEL, c"kmem_stats_compression", 0,
70        "uncompressed_storage_bytes"=>cmp_stats.uncompressed_storage_bytes.unwrap_or_default(),
71        "compressed_storage_bytes"=>cmp_stats.compressed_storage_bytes.unwrap_or_default(),
72        "compressed_fragmentation_bytes"=>cmp_stats.compressed_fragmentation_bytes.unwrap_or_default(),
73        "compression_time"=>cmp_stats.compression_time.unwrap_or_default(),
74        "decompression_time"=>cmp_stats.decompression_time.unwrap_or_default(),
75        "total_page_compression_attempts"=>cmp_stats.total_page_compression_attempts.unwrap_or_default(),
76        "failed_page_compression_attempts"=>cmp_stats.failed_page_compression_attempts.unwrap_or_default(),
77        "total_page_decompressions"=>cmp_stats.total_page_decompressions.unwrap_or_default(),
78        "compressed_page_evictions"=>cmp_stats.compressed_page_evictions.unwrap_or_default(),
79        "eager_page_compressions"=>cmp_stats.eager_page_compressions.unwrap_or_default(),
80        "memory_pressure_page_compressions"=>cmp_stats.memory_pressure_page_compressions.unwrap_or_default(),
81        "critical_memory_page_compressions"=>cmp_stats.critical_memory_page_compressions.unwrap_or_default()
82    );
83
84    if let Some(pd) = cmp_stats.pages_decompressed_within_log_time {
85        counter!(
86            CATEGORY_MEMORY_KERNEL,
87            c"kmem_stats_compression_time",0,
88            "pages_decompressed_unit_ns"=>cmp_stats.pages_decompressed_unit_ns.unwrap_or_default(),
89            "pages_decompressed_within_log_time[0]"=>pd[0],
90            "pages_decompressed_within_log_time[1]"=>pd[1],
91            "pages_decompressed_within_log_time[2]"=>pd[2],
92            "pages_decompressed_within_log_time[3]"=>pd[3],
93            "pages_decompressed_within_log_time[4]"=>pd[4],
94            "pages_decompressed_within_log_time[5]"=>pd[5],
95            "pages_decompressed_within_log_time[6]"=>pd[6],
96            "pages_decompressed_within_log_time[7]"=>pd[7]
97        );
98    }
99    Ok(())
100}