Skip to content

Commit

Permalink
Bug 1677451 - Implement Memory Distribution in the RLB
Browse files Browse the repository at this point in the history
  • Loading branch information
chutten committed Dec 9, 2020
1 parent d77298d commit 5119f94
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 32 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,8 @@
# Unreleased changes

* Rust
* Introduce the Memory Distribution metric type in the RLB. [#1376](https://github.com/mozilla/glean/pull/1376)

[Full changelog](https://github.com/mozilla/glean/compare/v33.7.0...main)

# v33.7.0 (2020-12-07)
Expand Down
31 changes: 31 additions & 0 deletions docs/user/metrics/memory_distribution.md
Expand Up @@ -177,6 +177,37 @@ Assert.Equal(1, Memory.heapAllocated.TestGetNumRecordedErrors(ErrorType.InvalidV

</div>

<div data-lang="Rust" class="tab">

```rust
use glean_metrics;

fn allocate_memory(bytes: u64) {
memory::heap_allocated.accumulate(bytes / 1024);
}
```

There are test APIs available too:

```rust
use glean::{DistributionData, ErrorType};
use glean_metrics;

// Was anything recorded?
assert!(memory::heap_allocated.test_get_value(None).is_some());

// Is the sum as expected?
let data = memory::heap_allocated.test_get_value(None).unwrap();
assert!(11, data.sum)
// The actual buckets and counts live in `data.values`.

// Were there any errors?
assert!(1, memory::heap_allocated.test_get_num_recorded_errors(InvalidValue));

```

</div>

{{#include ../../tab_footer.md}}

## Limits
Expand Down
2 changes: 1 addition & 1 deletion glean-core/rlb/src/lib.rs
Expand Up @@ -48,7 +48,7 @@ use configuration::DEFAULT_GLEAN_ENDPOINT;
pub use core_metrics::ClientInfoMetrics;
pub use glean_core::{
global_glean,
metrics::{RecordedEvent, TimeUnit},
metrics::{DistributionData, MemoryUnit, RecordedEvent, TimeUnit},
setup_glean, CommonMetricData, Error, ErrorType, Glean, Lifetime, Result,
};
use private::RecordedExperimentData;
Expand Down
67 changes: 67 additions & 0 deletions glean-core/rlb/src/private/memory_distribution.rs
@@ -0,0 +1,67 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use inherent::inherent;
use std::sync::Arc;

use glean_core::metrics::{DistributionData, MemoryUnit, MetricType};
use glean_core::ErrorType;

use crate::dispatcher;

// We need to wrap the glean-core type: otherwise if we try to implement
// the trait for the metric in `glean_core::metrics` we hit error[E0117]:
// only traits defined in the current crate can be implemented for arbitrary
// types.

/// This implements the developer-facing API for recording memory distribution metrics.
///
/// Instances of this class type are automatically generated by the parsers
/// at build time, allowing developers to record values that were previously
/// registered in the metrics.yaml file.
#[derive(Clone)]
pub struct MemoryDistributionMetric(pub(crate) Arc<glean_core::metrics::MemoryDistributionMetric>);

impl MemoryDistributionMetric {
/// The public constructor used by automatically generated metrics.
pub fn new(meta: glean_core::CommonMetricData, memory_unit: MemoryUnit) -> Self {
Self(Arc::new(
glean_core::metrics::MemoryDistributionMetric::new(meta, memory_unit),
))
}
}

#[inherent(pub)]
impl glean_core::traits::MemoryDistribution for MemoryDistributionMetric {
fn accumulate(&self, sample: u64) {
let metric = Arc::clone(&self.0);
dispatcher::launch(move || crate::with_glean(|glean| metric.accumulate(glean, sample)));
}

fn test_get_value<'a, S: Into<Option<&'a str>>>(
&self,
ping_name: S,
) -> Option<DistributionData> {
dispatcher::block_on_queue();

let queried_ping_name = ping_name
.into()
.unwrap_or_else(|| &self.0.meta().send_in_pings[0]);

crate::with_glean(|glean| self.0.test_get_value(glean, queried_ping_name))
}

fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> i32 {
dispatcher::block_on_queue();

crate::with_glean_mut(|glean| {
glean_core::test_get_num_recorded_errors(&glean, self.0.meta(), error, ping_name.into())
.unwrap_or(0)
})
}
}
2 changes: 2 additions & 0 deletions glean-core/rlb/src/private/mod.rs
Expand Up @@ -8,6 +8,7 @@ mod boolean;
mod counter;
mod event;
mod labeled;
mod memory_distribution;
mod ping;
mod quantity;
mod recorded_experiment_data;
Expand All @@ -20,6 +21,7 @@ pub use boolean::BooleanMetric;
pub use counter::CounterMetric;
pub use event::EventMetric;
pub use labeled::{AllowLabeled, LabeledMetric};
pub use memory_distribution::MemoryDistributionMetric;
pub use ping::PingType;
pub use quantity::QuantityMetric;
pub use recorded_experiment_data::RecordedExperimentData;
Expand Down
42 changes: 11 additions & 31 deletions glean-core/src/traits/memory_distribution.rs
Expand Up @@ -3,6 +3,7 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use crate::metrics::DistributionData;
use crate::ErrorType;

/// A description for the `MemoryDistributionMetric` type.
///
Expand All @@ -22,34 +23,9 @@ pub trait MemoryDistribution {
/// and an `ErrorType::InvalidValue` error is recorded.
fn accumulate(&self, sample: u64);

/// Accumulates the provided signed samples in the metric.
///
/// This is required so that the platform-specific code can provide us with
/// 64 bit signed integers if no `u64` comparable type is available. This
/// will take care of filtering and reporting errors for any provided negative
/// sample.
///
/// Please note that this assumes that the provided samples are already in
/// the "unit" declared by the instance of the implementing metric type
/// (e.g. if the implementing class is a [MemoryDistribution] and the
/// instance this method was called on is using kilobyte, then `samples` are
/// assumed to be in that unit).
///
/// # Arguments
///
/// * `samples` - The vector holding the samples to be recorded by the metric.
///
/// ## Notes
///
/// Discards any negative value in `samples` and report an `ErrorType::InvalidValue`
/// for each of them.
/// Values bigger than 1 Terabyte (2<sup>40</sup> bytes) are truncated
/// and an `ErrorType::InvalidValue` error is recorded.
fn accumulate_samples_signed(&self, samples: Vec<i64>);

/// **Exported for test purposes.**
///
/// Gets the currently stored value as an integer.
/// Gets the currently stored value as a DistributionData of the serialized value.
///
/// This doesn't clear the stored value.
///
Expand All @@ -64,16 +40,20 @@ pub trait MemoryDistribution {

/// **Exported for test purposes.**
///
/// Gets the currently-stored histogram as a JSON String of the serialized value.
///
/// This doesn't clear the stored value.
/// Gets the number of recorded errors for the given error type.
///
/// # Arguments
///
/// * `error` - The type of error
/// * `ping_name` - represents the optional name of the ping to retrieve the
/// metric for. Defaults to the first value in `send_in_pings`.
fn test_get_value_as_json_string<'a, S: Into<Option<&'a str>>>(
///
/// # Returns
///
/// The number of errors recorded.
fn test_get_num_recorded_errors<'a, S: Into<Option<&'a str>>>(
&self,
error: ErrorType,
ping_name: S,
) -> Option<String>;
) -> i32;
}

0 comments on commit 5119f94

Please sign in to comment.