Skip to main content

cobalt/
buckets.rs

1// Copyright 2025 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.
4
5use crate::error_from_metrics_error;
6use anyhow::Result;
7use attribution_processing::digest::{BucketDefinition, Digest};
8use cobalt_client::traits::{AsEventCode, AsEventCodes};
9use cobalt_registry::MemoryLeakMigratedMetricDimensionTimeSinceBoot as TimeSinceBoot;
10use fidl_fuchsia_kernel as fkernel;
11use fidl_fuchsia_metrics as fmetrics;
12use memory_metrics_registry::cobalt_registry;
13use std::collections::HashMap;
14
15/// Sorted list mapping durations to the largest event that is lower.
16const UPTIME_LEVEL_INDEX: &[(zx::BootDuration, TimeSinceBoot)] = &[
17    (zx::BootDuration::from_minutes(1), TimeSinceBoot::Up),
18    (zx::BootDuration::from_minutes(30), TimeSinceBoot::UpOneMinute),
19    (zx::BootDuration::from_hours(1), TimeSinceBoot::UpThirtyMinutes),
20    (zx::BootDuration::from_hours(6), TimeSinceBoot::UpOneHour),
21    (zx::BootDuration::from_hours(12), TimeSinceBoot::UpSixHours),
22    (zx::BootDuration::from_hours(24), TimeSinceBoot::UpTwelveHours),
23    (zx::BootDuration::from_hours(48), TimeSinceBoot::UpOneDay),
24    (zx::BootDuration::from_hours(72), TimeSinceBoot::UpTwoDays),
25    (zx::BootDuration::from_hours(144), TimeSinceBoot::UpThreeDays),
26];
27
28/// Convert an instant to the code corresponding to the largest uptime that is smaller.
29fn get_uptime_event_code(capture_time: zx::BootInstant) -> TimeSinceBoot {
30    let uptime = zx::Duration::from_nanos(capture_time.into_nanos());
31    UPTIME_LEVEL_INDEX
32        .into_iter()
33        .find(|&&(time, _)| uptime < time)
34        .map(|(_, code)| *code)
35        .unwrap_or(TimeSinceBoot::UpSixDays)
36}
37
38fn kmem_events(kmem_stats: &fkernel::MemoryStats) -> impl Iterator<Item = fmetrics::MetricEvent> {
39    use cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown as Breakdown;
40    let make_event = |code: Breakdown, value| {
41        Some(fmetrics::MetricEvent {
42            metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
43            event_codes: vec![code.as_event_code()],
44            payload: fmetrics::MetricEventPayload::IntegerValue(value? as i64),
45        })
46    };
47    vec![
48        make_event(Breakdown::TotalBytes, kmem_stats.total_bytes),
49        make_event(
50            Breakdown::UsedBytes,
51            (|| Some((kmem_stats.total_bytes? as i64 - kmem_stats.free_bytes? as i64) as u64))(),
52        ),
53        make_event(Breakdown::FreeBytes, kmem_stats.free_bytes),
54        make_event(Breakdown::VmoBytes, kmem_stats.vmo_bytes),
55        make_event(Breakdown::KernelFreeHeapBytes, kmem_stats.free_heap_bytes),
56        make_event(Breakdown::MmuBytes, kmem_stats.mmu_overhead_bytes),
57        make_event(Breakdown::IpcBytes, kmem_stats.ipc_bytes),
58        make_event(Breakdown::KernelTotalHeapBytes, kmem_stats.total_heap_bytes),
59        make_event(Breakdown::WiredBytes, kmem_stats.wired_bytes),
60        make_event(Breakdown::OtherBytes, kmem_stats.other_bytes),
61    ]
62    .into_iter()
63    .flatten()
64}
65
66fn kmem_events_with_uptime(
67    kmem_stats: &fkernel::MemoryStats,
68    capture_time: zx::BootInstant,
69) -> impl Iterator<Item = fmetrics::MetricEvent> {
70    use cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown as Breakdown;
71    let make_event = |code: Breakdown, value| {
72        Some(fmetrics::MetricEvent {
73            metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
74            event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
75                general_breakdown: code,
76                time_since_boot: get_uptime_event_code(capture_time),
77            }
78            .as_event_codes(),
79            payload: fmetrics::MetricEventPayload::IntegerValue(value? as i64),
80        })
81    };
82    vec![
83        make_event(Breakdown::TotalBytes, kmem_stats.total_bytes),
84        make_event(
85            Breakdown::UsedBytes,
86            (|| Some((kmem_stats.total_bytes? as i64 - kmem_stats.free_bytes? as i64) as u64))(),
87        ),
88        make_event(Breakdown::FreeBytes, kmem_stats.free_bytes),
89        make_event(Breakdown::VmoBytes, kmem_stats.vmo_bytes),
90        make_event(Breakdown::KernelFreeHeapBytes, kmem_stats.free_heap_bytes),
91        make_event(Breakdown::MmuBytes, kmem_stats.mmu_overhead_bytes),
92        make_event(Breakdown::IpcBytes, kmem_stats.ipc_bytes),
93        make_event(Breakdown::KernelTotalHeapBytes, kmem_stats.total_heap_bytes),
94        make_event(Breakdown::WiredBytes, kmem_stats.wired_bytes),
95        make_event(Breakdown::OtherBytes, kmem_stats.other_bytes),
96    ]
97    .into_iter()
98    .flatten()
99}
100
101fn digest_events<'a>(
102    digest: &'a Digest,
103    bucket_name_to_code: &'a HashMap<String, u32>,
104) -> impl 'a + Iterator<Item = fmetrics::MetricEvent> {
105    digest.buckets.iter().filter_map(|bucket| {
106        Some(fmetrics::MetricEvent {
107            metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
108            event_codes: vec![*bucket_name_to_code.get(&bucket.name)?],
109            payload: fmetrics::MetricEventPayload::IntegerValue(bucket.populated_size as i64),
110        })
111    })
112}
113
114pub fn prepare_bucket_codes(bucket_definitions: &[BucketDefinition]) -> HashMap<String, u32> {
115    let mut bucket_name_to_code = HashMap::from([
116        (
117            "TotalBytes".to_string(),
118            cobalt_registry::MemoryMigratedMetricDimensionBucket::TotalBytes.as_event_code(),
119        ),
120        (
121            "Free".to_string(),
122            cobalt_registry::MemoryMigratedMetricDimensionBucket::Free.as_event_code(),
123        ),
124        (
125            "Kernel".to_string(),
126            cobalt_registry::MemoryMigratedMetricDimensionBucket::Kernel.as_event_code(),
127        ),
128        (
129            "Orphaned".to_string(),
130            cobalt_registry::MemoryMigratedMetricDimensionBucket::Orphaned.as_event_code(),
131        ),
132        (
133            "Undigested".to_string(),
134            cobalt_registry::MemoryMigratedMetricDimensionBucket::Undigested.as_event_code(),
135        ),
136        (
137            "[Addl]PagerTotal".to_string(),
138            cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_PagerTotal.as_event_code(),
139        ),
140        (
141            "[Addl]PagerNewest".to_string(),
142            cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_PagerNewest
143                .as_event_code(),
144        ),
145        (
146            "[Addl]PagerOldest".to_string(),
147            cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_PagerOldest
148                .as_event_code(),
149        ),
150        (
151            "[Addl]DiscardableLocked".to_string(),
152            cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_DiscardableLocked
153                .as_event_code(),
154        ),
155        (
156            "[Addl]DiscardableUnlocked".to_string(),
157            cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_DiscardableUnlocked
158                .as_event_code(),
159        ),
160        (
161            "[Addl]ZramCompressedBytes".to_string(),
162            cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_ZramCompressedBytes
163                .as_event_code(),
164        ),
165        (
166            "[Addl]PopulatedAnonymousBytes".to_string(),
167            cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_PopulatedAnonymousBytes
168                .as_event_code(),
169        ),
170    ]);
171    bucket_definitions.iter().for_each(|bucket_definition| {
172        bucket_name_to_code
173            .entry(bucket_definition.name.clone())
174            .or_insert(bucket_definition.event_code as u32);
175    });
176    bucket_name_to_code
177}
178
179/// Upload cobalt data based on collected memory data.
180pub async fn upload_metrics(
181    timestamp: zx::BootInstant,
182    kmem_stats: &fkernel::MemoryStats,
183    metric_event_logger: &fmetrics::MetricEventLoggerProxy,
184    digest: &Digest,
185    bucket_codes: &HashMap<String, u32>,
186) -> Result<()> {
187    let events = kmem_events(kmem_stats)
188        .chain(kmem_events_with_uptime(kmem_stats, timestamp))
189        .chain(digest_events(digest, &bucket_codes));
190    metric_event_logger
191        .log_metric_events(&events.collect::<Vec<fmetrics::MetricEvent>>())
192        .await?
193        .map_err(error_from_metrics_error)?;
194    Ok(())
195}
196
197#[cfg(test)]
198mod tests {
199    use super::*;
200    use anyhow::anyhow;
201    use attribution_processing::{
202        Attribution, AttributionData, GlobalPrincipalIdentifier, Principal, PrincipalDescription,
203        PrincipalType, ProcessedAttributionData, Resource, ResourceReference, ZXName,
204        attribute_vmos,
205    };
206    use fidl_fuchsia_memory_attribution_plugin as fplugin;
207    use futures::{TryFutureExt, TryStreamExt, try_join};
208    use regex_lite::Regex;
209
210    fn get_data() -> ProcessedAttributionData {
211        let attribution_data = AttributionData {
212            principals_vec: vec![Principal {
213                identifier: GlobalPrincipalIdentifier::new_for_test(1),
214                description: Some(PrincipalDescription::Component("principal".to_owned())),
215                principal_type: PrincipalType::Runnable,
216                parent: None,
217            }],
218            resources_vec: vec![
219                // Orphaned VMO.
220                Resource {
221                    koid: 10,
222                    name_index: 0,
223                    resource_type: fplugin::ResourceType::Vmo(fplugin::Vmo {
224                        parent: None,
225                        private_committed_bytes: Some(1024),
226                        private_populated_bytes: Some(2048),
227                        scaled_committed_bytes: Some(1024),
228                        scaled_populated_bytes: Some(2048),
229                        total_committed_bytes: Some(1024),
230                        total_populated_bytes: Some(2048),
231                        ..Default::default()
232                    }),
233                },
234                // VMO belonging to bucket1.
235                Resource {
236                    koid: 20,
237                    name_index: 1,
238                    resource_type: fplugin::ResourceType::Vmo(fplugin::Vmo {
239                        parent: None,
240                        private_committed_bytes: Some(1024),
241                        private_populated_bytes: Some(2048),
242                        scaled_committed_bytes: Some(1024),
243                        scaled_populated_bytes: Some(2048),
244                        total_committed_bytes: Some(1024),
245                        total_populated_bytes: Some(2048),
246                        ..Default::default()
247                    }),
248                },
249                // Process owning bucket1's VMO.
250                Resource {
251                    koid: 30,
252                    name_index: 1,
253                    resource_type: fplugin::ResourceType::Process(fplugin::Process {
254                        vmos: Some(vec![20]),
255                        ..Default::default()
256                    }),
257                },
258            ],
259            resource_names: vec![
260                ZXName::from_string_lossy("resource"),
261                ZXName::from_string_lossy("bucket1_resource"),
262            ],
263            attributions: vec![Attribution {
264                source: GlobalPrincipalIdentifier::new_for_test(1),
265                subject: GlobalPrincipalIdentifier::new_for_test(1),
266                resources: vec![ResourceReference::KernelObject(10)],
267            }],
268        };
269        attribute_vmos(attribution_data)
270    }
271
272    fn get_kernel_stats() -> (fkernel::MemoryStats, fkernel::MemoryStatsCompression) {
273        (
274            fkernel::MemoryStats {
275                total_bytes: Some(1),
276                free_bytes: Some(2),
277                wired_bytes: Some(3),
278                total_heap_bytes: Some(4),
279                free_heap_bytes: Some(5),
280                vmo_bytes: Some(6),
281                mmu_overhead_bytes: Some(7),
282                ipc_bytes: Some(8),
283                other_bytes: Some(9),
284                free_loaned_bytes: Some(10),
285                cache_bytes: Some(11),
286                slab_bytes: Some(12),
287                zram_bytes: Some(13),
288                vmo_reclaim_total_bytes: Some(14),
289                vmo_reclaim_newest_bytes: Some(15),
290                vmo_reclaim_oldest_bytes: Some(16),
291                vmo_reclaim_disabled_bytes: Some(17),
292                vmo_discardable_locked_bytes: Some(18),
293                vmo_discardable_unlocked_bytes: Some(19),
294                ..Default::default()
295            },
296            fkernel::MemoryStatsCompression {
297                uncompressed_storage_bytes: Some(20),
298                compressed_storage_bytes: Some(21),
299                compressed_fragmentation_bytes: Some(22),
300                compression_time: Some(23),
301                decompression_time: Some(24),
302                total_page_compression_attempts: Some(25),
303                failed_page_compression_attempts: Some(26),
304                total_page_decompressions: Some(27),
305                compressed_page_evictions: Some(28),
306                eager_page_compressions: Some(29),
307                memory_pressure_page_compressions: Some(30),
308                critical_memory_page_compressions: Some(31),
309                pages_decompressed_unit_ns: Some(32),
310                pages_decompressed_within_log_time: Some([40, 41, 42, 43, 44, 45, 46, 47]),
311                ..Default::default()
312            },
313        )
314    }
315
316    #[fuchsia::test]
317    async fn test_upload_metrics() -> anyhow::Result<()> {
318        let bucket_definitions = [BucketDefinition {
319            name: "bucket1".to_string(),
320            vmo: Some(Regex::new("bucket1.*")?),
321            event_code: 1,
322            process: None,
323            principal: None,
324        }];
325
326        let (metric_event_logger, mut metric_event_request_stream) =
327            fidl::endpoints::create_proxy_and_stream::<fmetrics::MetricEventLoggerMarker>();
328
329        let (kmem_stats, kmem_stats_compression) = get_kernel_stats();
330        let digest = Digest::compute(
331            &get_data(),
332            &kmem_stats,
333            &kmem_stats_compression,
334            &bucket_definitions,
335            false,
336        )?;
337        let bucket_codes = prepare_bucket_codes(&bucket_definitions);
338        let upload = upload_metrics(
339            zx::BootInstant::get(),
340            &kmem_stats,
341            &metric_event_logger,
342            &digest,
343            &bucket_codes,
344        );
345        let uptime = get_uptime_event_code(zx::BootInstant::get());
346        try_join!(metric_event_request_stream.try_next().and_then(|event| async {
347            match event.unwrap() {
348                fmetrics::MetricEventLoggerRequest::LogMetricEvents { events, responder } => {
349                    responder.send(Ok(()))?;
350                    // Kernel metrics
351                    assert_eq!(
352                        &events[0..10],
353                        vec![
354                            fmetrics::MetricEvent {
355                                metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
356                                event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::TotalBytes.as_event_code()],
357                                payload: fmetrics::MetricEventPayload::IntegerValue(1)
358                            },
359                            fmetrics::MetricEvent {
360                                metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
361                                event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::UsedBytes.as_event_code()],
362                                payload: fmetrics::MetricEventPayload::IntegerValue(-1)
363                            },
364                            fmetrics::MetricEvent {
365                                metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
366                                event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::FreeBytes.as_event_code()],
367                                payload: fmetrics::MetricEventPayload::IntegerValue(2)
368                            },
369                            fmetrics::MetricEvent {
370                                metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
371                                event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::VmoBytes.as_event_code()],
372                                payload: fmetrics::MetricEventPayload::IntegerValue(6)
373                            },
374                            fmetrics::MetricEvent {
375                                metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
376                                event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::KernelFreeHeapBytes.as_event_code()],
377                                payload: fmetrics::MetricEventPayload::IntegerValue(5)
378                            },
379                            fmetrics::MetricEvent {
380                                metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
381                                event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::MmuBytes.as_event_code()],
382                                payload: fmetrics::MetricEventPayload::IntegerValue(7)
383                            },
384                            fmetrics::MetricEvent {
385                                metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
386                                event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::IpcBytes.as_event_code()],
387                                payload: fmetrics::MetricEventPayload::IntegerValue(8)
388                            },
389                            fmetrics::MetricEvent {
390                                metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
391                                event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::KernelTotalHeapBytes.as_event_code()],
392                                payload: fmetrics::MetricEventPayload::IntegerValue(4)
393                            },
394                            fmetrics::MetricEvent {
395                                metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
396                                event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::WiredBytes.as_event_code()],
397                                payload: fmetrics::MetricEventPayload::IntegerValue(3)
398                            },
399                            fmetrics::MetricEvent {
400                                metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
401                                event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::OtherBytes.as_event_code()],
402                                payload: fmetrics::MetricEventPayload::IntegerValue(9)
403                            },]);
404                    // Kernel metrics with uptime
405                    assert_eq!(
406                        &events[10..20],
407                        vec![
408                            fmetrics::MetricEvent {
409                                metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
410                                event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
411                                    general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::TotalBytes, time_since_boot: uptime}.as_event_codes(),
412                                payload: fmetrics::MetricEventPayload::IntegerValue(1)
413                            },
414                            fmetrics::MetricEvent {
415                                metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
416                                event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
417                                    general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::UsedBytes, time_since_boot:uptime}.as_event_codes(),
418                                payload: fmetrics::MetricEventPayload::IntegerValue(-1)
419                            },
420                            fmetrics::MetricEvent {
421                                metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
422                                event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
423                                    general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::FreeBytes, time_since_boot:uptime}.as_event_codes(),
424                                payload: fmetrics::MetricEventPayload::IntegerValue(2)
425                            },
426                            fmetrics::MetricEvent {
427                                metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
428                                event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
429                                    general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::VmoBytes, time_since_boot:uptime}.as_event_codes(),
430                                payload: fmetrics::MetricEventPayload::IntegerValue(6)
431                            },
432                            fmetrics::MetricEvent {
433                                metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
434                                event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
435                                    general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::KernelFreeHeapBytes, time_since_boot:uptime}.as_event_codes(),
436                                payload: fmetrics::MetricEventPayload::IntegerValue(5)
437                            },
438                            fmetrics::MetricEvent {
439                                metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
440                                event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
441                                    general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::MmuBytes, time_since_boot:uptime}.as_event_codes(),
442                                payload: fmetrics::MetricEventPayload::IntegerValue(7)
443                            },
444                            fmetrics::MetricEvent {
445                                metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
446                                event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
447                                    general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::IpcBytes, time_since_boot:uptime}.as_event_codes(),
448                                payload: fmetrics::MetricEventPayload::IntegerValue(8)
449                            },
450                            fmetrics::MetricEvent {
451                                metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
452                                event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
453                                    general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::KernelTotalHeapBytes, time_since_boot:uptime}.as_event_codes(),
454                                payload: fmetrics::MetricEventPayload::IntegerValue(4)
455                            },
456                            fmetrics::MetricEvent {
457                                metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
458                                event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
459                                    general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::WiredBytes, time_since_boot:uptime}.as_event_codes(),
460                                payload: fmetrics::MetricEventPayload::IntegerValue(3)
461                            },
462                            fmetrics::MetricEvent {
463                                metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
464                                event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
465                                    general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::OtherBytes, time_since_boot:uptime}.as_event_codes(),
466                                payload: fmetrics::MetricEventPayload::IntegerValue(9)
467                            },
468                        ]
469                    );
470                    // Digest metrics
471                    assert_eq!(
472                        &events[20..],
473                        vec![
474                            // Buckets with custom definitions
475                            fmetrics::MetricEvent {
476                                metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
477                                event_codes: vec![1], // Corresponds to the "bucket1" bucket
478                                payload: fmetrics::MetricEventPayload::IntegerValue(2048)
479                            },
480                            // Default buckets
481                            fmetrics::MetricEvent {
482                                metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
483                                event_codes: vec![cobalt_registry::MemoryMigratedMetricDimensionBucket::Undigested.as_event_code()],
484                                payload: fmetrics::MetricEventPayload::IntegerValue(2048)
485                            },
486                            fmetrics::MetricEvent {
487                                metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
488                                event_codes: vec![cobalt_registry::MemoryMigratedMetricDimensionBucket::Orphaned.as_event_code()],
489                                payload: fmetrics::MetricEventPayload::IntegerValue(0)
490                            },
491                            fmetrics::MetricEvent {
492                                metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
493                                event_codes: vec![cobalt_registry::MemoryMigratedMetricDimensionBucket::Kernel.as_event_code()],
494                                payload: fmetrics::MetricEventPayload::IntegerValue(54)
495                            },
496                            fmetrics::MetricEvent {
497                                metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
498                                event_codes: vec![cobalt_registry::MemoryMigratedMetricDimensionBucket::Free.as_event_code()],
499                                payload: fmetrics::MetricEventPayload::IntegerValue(2)
500                            },
501                            fmetrics::MetricEvent {
502                                metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
503                                event_codes: vec![cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_PagerTotal.as_event_code()],
504                                payload: fmetrics::MetricEventPayload::IntegerValue(14)
505                            },
506                            fmetrics::MetricEvent {
507                                metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
508                                event_codes: vec![cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_PagerNewest.as_event_code()],
509                                payload: fmetrics::MetricEventPayload::IntegerValue(15)
510                            },
511                            fmetrics::MetricEvent {
512                                metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
513                                event_codes: vec![cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_PagerOldest.as_event_code()],
514                                payload: fmetrics::MetricEventPayload::IntegerValue(16)
515                            },
516                            fmetrics::MetricEvent {
517                                metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
518                                event_codes: vec![cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_DiscardableLocked.as_event_code()],
519                                payload: fmetrics::MetricEventPayload::IntegerValue(18)
520                            },
521                            fmetrics::MetricEvent {
522                                metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
523                                event_codes: vec![cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_DiscardableUnlocked.as_event_code()],
524                                payload: fmetrics::MetricEventPayload::IntegerValue(19)
525                            },
526                            fmetrics::MetricEvent {
527                                metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
528                                event_codes: vec![cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_ZramCompressedBytes.as_event_code()],
529                                payload: fmetrics::MetricEventPayload::IntegerValue(21)
530                            },
531                            fmetrics::MetricEvent {
532                                metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
533                                event_codes: vec![cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_PopulatedAnonymousBytes.as_event_code()],
534                                payload: fmetrics::MetricEventPayload::IntegerValue(6)
535                            }
536                        ]
537                    )
538                }
539                _ => panic!("Unexpected metric event"),
540            }
541            Ok(())}).map_err(|err| anyhow!(err)), upload)?;
542        Ok(())
543    }
544}