1use crate::error_from_metrics_error;
6use anyhow::Result;
7use attribution_processing::digest::{BucketDefinition, Digest};
8use attribution_processing::AttributionDataProvider;
9use cobalt_client::traits::{AsEventCode, AsEventCodes};
10use futures::stream::StreamExt;
11use futures::{try_join, TryFutureExt};
12use memory_metrics_registry::cobalt_registry;
13use std::sync::Arc;
14
15use cobalt_registry::MemoryLeakMigratedMetricDimensionTimeSinceBoot as TimeSinceBoot;
16use {fidl_fuchsia_kernel as fkernel, fidl_fuchsia_metrics as fmetrics};
17
18const UPTIME_LEVEL_INDEX: &[(zx::BootDuration, TimeSinceBoot)] = &[
20 (zx::BootDuration::from_minutes(1), TimeSinceBoot::Up),
21 (zx::BootDuration::from_minutes(30), TimeSinceBoot::UpOneMinute),
22 (zx::BootDuration::from_hours(1), TimeSinceBoot::UpThirtyMinutes),
23 (zx::BootDuration::from_hours(6), TimeSinceBoot::UpOneHour),
24 (zx::BootDuration::from_hours(12), TimeSinceBoot::UpSixHours),
25 (zx::BootDuration::from_hours(24), TimeSinceBoot::UpTwelveHours),
26 (zx::BootDuration::from_hours(48), TimeSinceBoot::UpOneDay),
27 (zx::BootDuration::from_hours(72), TimeSinceBoot::UpTwoDays),
28 (zx::BootDuration::from_hours(144), TimeSinceBoot::UpThreeDays),
29];
30
31fn bucket_name_to_dimension(
32 name: &str,
33) -> Option<cobalt_registry::MemoryMigratedMetricDimensionBucket> {
34 match name {
35 "TotalBytes" => Some(cobalt_registry::MemoryMigratedMetricDimensionBucket::TotalBytes),
36 "Free" => Some(cobalt_registry::MemoryMigratedMetricDimensionBucket::Free),
37 "Kernel" => Some(cobalt_registry::MemoryMigratedMetricDimensionBucket::Kernel),
38 "Orphaned" => Some(cobalt_registry::MemoryMigratedMetricDimensionBucket::Orphaned),
39 "Undigested" => Some(cobalt_registry::MemoryMigratedMetricDimensionBucket::Undigested),
40 "[Addl]PagerTotal" => {
41 Some(cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_PagerTotal)
42 }
43 "[Addl]PagerNewest" => {
44 Some(cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_PagerNewest)
45 }
46 "[Addl]PagerOldest" => {
47 Some(cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_PagerOldest)
48 }
49 "[Addl]DiscardableLocked" => {
50 Some(cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_DiscardableLocked)
51 }
52 "[Addl]DiscardableUnlocked" => {
53 Some(cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_DiscardableUnlocked)
54 }
55 "[Addl]ZramCompressedBytes" => {
56 Some(cobalt_registry::MemoryMigratedMetricDimensionBucket::__Addl_ZramCompressedBytes)
57 }
58 _ => None,
59 }
60}
61
62fn get_uptime_event_code(capture_time: zx::BootInstant) -> TimeSinceBoot {
64 let uptime = zx::Duration::from_nanos(capture_time.into_nanos());
65 UPTIME_LEVEL_INDEX
66 .into_iter()
67 .find(|&&(time, _)| uptime < time)
68 .map(|(_, code)| *code)
69 .unwrap_or(TimeSinceBoot::UpSixDays)
70}
71
72fn kmem_events(kmem_stats: &fkernel::MemoryStats) -> impl Iterator<Item = fmetrics::MetricEvent> {
73 use cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown as Breakdown;
74 let make_event = |code: Breakdown, value| {
75 Some(fmetrics::MetricEvent {
76 metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
77 event_codes: vec![code.as_event_code()],
78 payload: fmetrics::MetricEventPayload::IntegerValue(value? as i64),
79 })
80 };
81 vec![
82 make_event(Breakdown::TotalBytes, kmem_stats.total_bytes),
83 make_event(
84 Breakdown::UsedBytes,
85 (|| Some((kmem_stats.total_bytes? as i64 - kmem_stats.free_bytes? as i64) as u64))(),
86 ),
87 make_event(Breakdown::FreeBytes, kmem_stats.free_bytes),
88 make_event(Breakdown::VmoBytes, kmem_stats.vmo_bytes),
89 make_event(Breakdown::KernelFreeHeapBytes, kmem_stats.free_heap_bytes),
90 make_event(Breakdown::MmuBytes, kmem_stats.mmu_overhead_bytes),
91 make_event(Breakdown::IpcBytes, kmem_stats.ipc_bytes),
92 make_event(Breakdown::KernelTotalHeapBytes, kmem_stats.total_heap_bytes),
93 make_event(Breakdown::WiredBytes, kmem_stats.wired_bytes),
94 make_event(Breakdown::OtherBytes, kmem_stats.other_bytes),
95 ]
96 .into_iter()
97 .flatten()
98}
99
100fn kmem_events_with_uptime(
101 kmem_stats: &fkernel::MemoryStats,
102 capture_time: zx::BootInstant,
103) -> impl Iterator<Item = fmetrics::MetricEvent> {
104 use cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown as Breakdown;
105 let make_event = |code: Breakdown, value| {
106 Some(fmetrics::MetricEvent {
107 metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
108 event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
109 general_breakdown: code,
110 time_since_boot: get_uptime_event_code(capture_time),
111 }
112 .as_event_codes(),
113 payload: fmetrics::MetricEventPayload::IntegerValue(value? as i64),
114 })
115 };
116 vec![
117 make_event(Breakdown::TotalBytes, kmem_stats.total_bytes),
118 make_event(
119 Breakdown::UsedBytes,
120 (|| Some((kmem_stats.total_bytes? as i64 - kmem_stats.free_bytes? as i64) as u64))(),
121 ),
122 make_event(Breakdown::FreeBytes, kmem_stats.free_bytes),
123 make_event(Breakdown::VmoBytes, kmem_stats.vmo_bytes),
124 make_event(Breakdown::KernelFreeHeapBytes, kmem_stats.free_heap_bytes),
125 make_event(Breakdown::MmuBytes, kmem_stats.mmu_overhead_bytes),
126 make_event(Breakdown::IpcBytes, kmem_stats.ipc_bytes),
127 make_event(Breakdown::KernelTotalHeapBytes, kmem_stats.total_heap_bytes),
128 make_event(Breakdown::WiredBytes, kmem_stats.wired_bytes),
129 make_event(Breakdown::OtherBytes, kmem_stats.other_bytes),
130 ]
131 .into_iter()
132 .flatten()
133}
134
135fn digest_events(digest: Digest) -> impl Iterator<Item = fmetrics::MetricEvent> {
136 digest.buckets.into_iter().filter_map(|bucket| {
137 Some(fmetrics::MetricEvent {
138 metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
139 event_codes: vec![bucket_name_to_dimension(&bucket.name)?.as_event_code()],
140 payload: fmetrics::MetricEventPayload::IntegerValue(bucket.size as i64),
141 })
142 })
143}
144
145pub async fn collect_metrics_forever(
147 attribution_data_service: Arc<impl AttributionDataProvider + 'static>,
148 kernel_stats_proxy: fkernel::StatsProxy,
149 metric_event_logger: fmetrics::MetricEventLoggerProxy,
150 bucket_definitions: Arc<[BucketDefinition]>,
151) {
152 let mut timer = fuchsia_async::Interval::new(zx::Duration::from_minutes(5));
153 loop {
154 timer.next().await;
155
156 let result = collect_metrics_once(
157 &*attribution_data_service,
158 &kernel_stats_proxy,
159 &metric_event_logger,
160 &*bucket_definitions,
161 )
162 .await;
163
164 if let Err(e) = result {
165 log::error!("Metrics collection failed: {e}");
166 }
167 }
168}
169
170async fn collect_metrics_once(
171 attribution_data_service: &impl AttributionDataProvider,
172 kernel_stats_proxy: &fkernel::StatsProxy,
173 metric_event_logger: &fmetrics::MetricEventLoggerProxy,
174 bucket_definitions: &[BucketDefinition],
175) -> Result<()> {
176 let timestamp = zx::BootInstant::get();
177 let (kmem_stats, kmem_stats_compression) = try_join!(
178 kernel_stats_proxy.get_memory_stats().map_err(anyhow::Error::from),
179 kernel_stats_proxy.get_memory_stats_compression().map_err(anyhow::Error::from)
180 )?;
181 let digest = Digest::compute(
182 &*attribution_data_service,
183 &kmem_stats,
184 &kmem_stats_compression,
185 &bucket_definitions,
186 )?;
187
188 let events = kmem_events(&kmem_stats)
189 .chain(kmem_events_with_uptime(&kmem_stats, timestamp))
190 .chain(digest_events(digest));
191 metric_event_logger
192 .log_metric_events(&events.collect::<Vec<fmetrics::MetricEvent>>())
193 .await?
194 .map_err(error_from_metrics_error)?;
195 Ok(())
196}
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201 use anyhow::anyhow;
202 use attribution_processing::testing::FakeAttributionDataProvider;
203 use attribution_processing::{
204 Attribution, AttributionData, Principal, PrincipalDescription, PrincipalIdentifier,
205 PrincipalType, Resource, ResourceReference, ZXName,
206 };
207 use futures::task::Poll;
208 use futures::TryStreamExt;
209 use std::time::Duration;
210 use {fidl_fuchsia_memory_attribution_plugin as fplugin, fuchsia_async as fasync};
211
212 fn get_attribution_data_provider() -> Arc<impl AttributionDataProvider + 'static> {
213 let attribution_data = AttributionData {
214 principals_vec: vec![Principal {
215 identifier: PrincipalIdentifier(1),
216 description: PrincipalDescription::Component("principal".to_owned()),
217 principal_type: PrincipalType::Runnable,
218 parent: None,
219 }],
220 resources_vec: vec![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 resource_names: vec![ZXName::from_string_lossy("resource")],
235 attributions: vec![Attribution {
236 source: PrincipalIdentifier(1),
237 subject: PrincipalIdentifier(1),
238 resources: vec![ResourceReference::KernelObject(10)],
239 }],
240 };
241 Arc::new(FakeAttributionDataProvider { attribution_data })
242 }
243
244 async fn serve_kernel_stats(
245 mut request_stream: fkernel::StatsRequestStream,
246 ) -> Result<(), fidl::Error> {
247 while let Some(request) = request_stream.try_next().await? {
248 match request {
249 fkernel::StatsRequest::GetMemoryStats { responder } => {
250 responder
251 .send(&fkernel::MemoryStats {
252 total_bytes: Some(1),
253 free_bytes: Some(2),
254 wired_bytes: Some(3),
255 total_heap_bytes: Some(4),
256 free_heap_bytes: Some(5),
257 vmo_bytes: Some(6),
258 mmu_overhead_bytes: Some(7),
259 ipc_bytes: Some(8),
260 other_bytes: Some(9),
261 free_loaned_bytes: Some(10),
262 cache_bytes: Some(11),
263 slab_bytes: Some(12),
264 zram_bytes: Some(13),
265 vmo_reclaim_total_bytes: Some(14),
266 vmo_reclaim_newest_bytes: Some(15),
267 vmo_reclaim_oldest_bytes: Some(16),
268 vmo_reclaim_disabled_bytes: Some(17),
269 vmo_discardable_locked_bytes: Some(18),
270 vmo_discardable_unlocked_bytes: Some(19),
271 ..Default::default()
272 })
273 .unwrap();
274 }
275 fkernel::StatsRequest::GetMemoryStatsExtended { responder: _ } => {
276 unimplemented!("Deprecated call, should not be used")
277 }
278 fkernel::StatsRequest::GetMemoryStatsCompression { responder } => {
279 responder
280 .send(&fkernel::MemoryStatsCompression {
281 uncompressed_storage_bytes: Some(20),
282 compressed_storage_bytes: Some(21),
283 compressed_fragmentation_bytes: Some(22),
284 compression_time: Some(23),
285 decompression_time: Some(24),
286 total_page_compression_attempts: Some(25),
287 failed_page_compression_attempts: Some(26),
288 total_page_decompressions: Some(27),
289 compressed_page_evictions: Some(28),
290 eager_page_compressions: Some(29),
291 memory_pressure_page_compressions: Some(30),
292 critical_memory_page_compressions: Some(31),
293 pages_decompressed_unit_ns: Some(32),
294 pages_decompressed_within_log_time: Some([
295 40, 41, 42, 43, 44, 45, 46, 47,
296 ]),
297 ..Default::default()
298 })
299 .unwrap();
300 }
301 fkernel::StatsRequest::GetCpuStats { responder: _ } => unimplemented!(),
302 fkernel::StatsRequest::GetCpuLoad { duration: _, responder: _ } => unimplemented!(),
303 }
304 }
305 Ok(())
306 }
307
308 #[test]
309 fn test_periodic_metrics_collection() -> anyhow::Result<()> {
310 let mut exec = fasync::TestExecutor::new_with_fake_time();
312
313 let data_provider = get_attribution_data_provider();
315 let (stats_provider, stats_request_stream) =
316 fidl::endpoints::create_proxy_and_stream::<fkernel::StatsMarker>();
317 fasync::Task::spawn(async move {
318 serve_kernel_stats(stats_request_stream).await.unwrap();
319 })
320 .detach();
321 let bucket_definitions = Arc::new([]);
322
323 let (metric_event_logger, metric_event_request_stream) =
325 fidl::endpoints::create_proxy_and_stream::<fmetrics::MetricEventLoggerMarker>();
326
327 let mut metrics_collector = fuchsia_async::Task::spawn(collect_metrics_forever(
329 data_provider,
330 stats_provider,
331 metric_event_logger,
332 bucket_definitions,
333 ));
334
335 assert!(
337 exec.run_until_stalled(&mut metrics_collector).is_pending(),
338 "Metrics collection service returned unexpectedly early"
339 );
340
341 let mut metric_event_request_future = metric_event_request_stream.into_future();
343 assert!(
344 exec.run_until_stalled(&mut metric_event_request_future).is_pending(),
345 "Metrics collection service returned unexpectedly early"
346 );
347
348 assert!(
350 exec.run_until_stalled(&mut std::pin::pin!(fasync::TestExecutor::advance_to(
351 exec.now() + Duration::from_secs(5 * 60).into()
352 )))
353 .is_ready(),
354 "Failed to advance time"
355 );
356 let uptime = get_uptime_event_code(zx::BootInstant::get());
357
358 let Poll::Ready((event, metric_event_request_stream)) =
360 exec.run_until_stalled(&mut metric_event_request_future)
361 else {
362 panic!("Failed to receive metrics")
363 };
364 let event = event.ok_or_else(|| anyhow!("Metrics stream unexpectedly closed"))??;
365 match event {
366 fmetrics::MetricEventLoggerRequest::LogMetricEvents { events, .. } => {
367 assert_eq!(
369 &events[0..10],
370 vec![
371 fmetrics::MetricEvent {
372 metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
373 event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::TotalBytes.as_event_code()],
374 payload: fmetrics::MetricEventPayload::IntegerValue(1)
375 },
376 fmetrics::MetricEvent {
377 metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
378 event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::UsedBytes.as_event_code()],
379 payload: fmetrics::MetricEventPayload::IntegerValue(-1)
380 },
381 fmetrics::MetricEvent {
382 metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
383 event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::FreeBytes.as_event_code()],
384 payload: fmetrics::MetricEventPayload::IntegerValue(2)
385 },
386 fmetrics::MetricEvent {
387 metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
388 event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::VmoBytes.as_event_code()],
389 payload: fmetrics::MetricEventPayload::IntegerValue(6)
390 },
391 fmetrics::MetricEvent {
392 metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
393 event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::KernelFreeHeapBytes.as_event_code()],
394 payload: fmetrics::MetricEventPayload::IntegerValue(5)
395 },
396 fmetrics::MetricEvent {
397 metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
398 event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::MmuBytes.as_event_code()],
399 payload: fmetrics::MetricEventPayload::IntegerValue(7)
400 },
401 fmetrics::MetricEvent {
402 metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
403 event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::IpcBytes.as_event_code()],
404 payload: fmetrics::MetricEventPayload::IntegerValue(8)
405 },
406 fmetrics::MetricEvent {
407 metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
408 event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::KernelTotalHeapBytes.as_event_code()],
409 payload: fmetrics::MetricEventPayload::IntegerValue(4)
410 },
411 fmetrics::MetricEvent {
412 metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
413 event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::WiredBytes.as_event_code()],
414 payload: fmetrics::MetricEventPayload::IntegerValue(3)
415 },
416 fmetrics::MetricEvent {
417 metric_id: cobalt_registry::MEMORY_GENERAL_BREAKDOWN_MIGRATED_METRIC_ID,
418 event_codes: vec![cobalt_registry::MemoryGeneralBreakdownMigratedMetricDimensionGeneralBreakdown::OtherBytes.as_event_code()],
419 payload: fmetrics::MetricEventPayload::IntegerValue(9)
420 },]);
421 assert_eq!(
423 &events[10..20],
424 vec![
425 fmetrics::MetricEvent {
426 metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
427 event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
428 general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::TotalBytes, time_since_boot: uptime}.as_event_codes(),
429 payload: fmetrics::MetricEventPayload::IntegerValue(1)
430 },
431 fmetrics::MetricEvent {
432 metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
433 event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
434 general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::UsedBytes, time_since_boot:uptime}.as_event_codes(),
435 payload: fmetrics::MetricEventPayload::IntegerValue(-1)
436 },
437 fmetrics::MetricEvent {
438 metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
439 event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
440 general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::FreeBytes, time_since_boot:uptime}.as_event_codes(), payload: fmetrics::MetricEventPayload::IntegerValue(2)
441 },
442 fmetrics::MetricEvent {
443 metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
444 event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
445 general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::VmoBytes, time_since_boot:uptime}.as_event_codes(),
446 payload: fmetrics::MetricEventPayload::IntegerValue(6)
447 },
448 fmetrics::MetricEvent {
449 metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
450 event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
451 general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::KernelFreeHeapBytes, time_since_boot:uptime}.as_event_codes(),
452 payload: fmetrics::MetricEventPayload::IntegerValue(5)
453 },
454 fmetrics::MetricEvent {
455 metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
456 event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
457 general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::MmuBytes, time_since_boot:uptime}.as_event_codes(),
458 payload: fmetrics::MetricEventPayload::IntegerValue(7)
459 },
460 fmetrics::MetricEvent {
461 metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
462 event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
463 general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::IpcBytes, time_since_boot:uptime}.as_event_codes(),
464 payload: fmetrics::MetricEventPayload::IntegerValue(8)
465 },
466 fmetrics::MetricEvent {
467 metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
468 event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
469 general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::KernelTotalHeapBytes, time_since_boot:uptime}.as_event_codes(),
470 payload: fmetrics::MetricEventPayload::IntegerValue(4)
471 },
472 fmetrics::MetricEvent {
473 metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
474 event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
475 general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::WiredBytes, time_since_boot:uptime}.as_event_codes(),
476 payload: fmetrics::MetricEventPayload::IntegerValue(3)
477 },
478 fmetrics::MetricEvent {
479 metric_id: cobalt_registry::MEMORY_LEAK_MIGRATED_METRIC_ID,
480 event_codes: cobalt_registry::MemoryLeakMigratedEventCodes {
481 general_breakdown: cobalt_registry::MemoryLeakMigratedMetricDimensionGeneralBreakdown::OtherBytes, time_since_boot:uptime}.as_event_codes(),
482 payload: fmetrics::MetricEventPayload::IntegerValue(9)
483 },
484 ]
485 );
486 assert_eq!(
488 &events[20..],
489 vec![
490 fmetrics::MetricEvent {
491 metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
492 event_codes: vec![19],
493 payload: fmetrics::MetricEventPayload::IntegerValue(1024)
494 },
495 fmetrics::MetricEvent {
496 metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
497 event_codes: vec![18],
498 payload: fmetrics::MetricEventPayload::IntegerValue(6)
499 },
500 fmetrics::MetricEvent {
501 metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
502 event_codes: vec![17],
503 payload: fmetrics::MetricEventPayload::IntegerValue(31)
504 },
505 fmetrics::MetricEvent {
506 metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
507 event_codes: vec![16],
508 payload: fmetrics::MetricEventPayload::IntegerValue(2)
509 },
510 fmetrics::MetricEvent {
511 metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
512 event_codes: vec![32],
513 payload: fmetrics::MetricEventPayload::IntegerValue(14)
514 },
515 fmetrics::MetricEvent {
516 metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
517 event_codes: vec![33],
518 payload: fmetrics::MetricEventPayload::IntegerValue(15)
519 },
520 fmetrics::MetricEvent {
521 metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
522 event_codes: vec![34],
523 payload: fmetrics::MetricEventPayload::IntegerValue(16)
524 },
525 fmetrics::MetricEvent {
526 metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
527 event_codes: vec![35],
528 payload: fmetrics::MetricEventPayload::IntegerValue(18)
529 },
530 fmetrics::MetricEvent {
531 metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
532 event_codes: vec![36],
533 payload: fmetrics::MetricEventPayload::IntegerValue(19)
534 },
535 fmetrics::MetricEvent {
536 metric_id: cobalt_registry::MEMORY_MIGRATED_METRIC_ID,
537 event_codes: vec![76],
538 payload: fmetrics::MetricEventPayload::IntegerValue(21)
539 }
540 ]
541 )
542 }
543 _ => panic!("Unexpected metric event"),
544 }
545
546 assert!(exec
547 .run_until_stalled(&mut metric_event_request_stream.into_future())
548 .is_pending());
549 Ok(())
550 }
551}