# Timing Distribution

Timing distributions are used to accumulate and store time measurement, for analyzing distributions of the timing data.

To measure the distribution of single timespans, see Timespans. To record absolute times, see Datetimes.

Timing distributions are recorded in a histogram where the buckets have an exponential distribution, specifically with 8 buckets for every power of 2. That is, the function from a value $$x$$ to a bucket index is:

$\lfloor 8 \log_2(x) \rfloor$

This makes them suitable for measuring timings on a number of time scales without any configuration.

Note Check out how this bucketing algorithm would behave on the Simulator.

Timings always span the full length between start and stopAndAccumulate. If the Glean upload is disabled when calling start, the timer is still started. If the Glean upload is disabled at the time stopAndAccumulate is called, nothing is recorded.

Multiple concurrent timings in different threads may be measured at the same time.

Timings are always stored and sent in the payload as nanoseconds. However, the time_unit parameter controls the minimum and maximum values that will recorded:

• nanosecond: 1ns <= x <= 10 minutes
• microsecond: 1μs <= x <= ~6.94 days
• millisecond: 1ms <= x <= ~19 years

Overflowing this range is considered an error and is reported through the error reporting mechanism. Underflowing this range is not an error and the value is silently truncated to the minimum value.

Additionally, when a metric comes from GeckoView (the geckoview_datapoint parameter is present), the time_unit parameter specifies the unit that the samples are in when passed to Glean. Glean will convert all of the incoming samples to nanoseconds internally.

## Recording API

### start

Start tracking time for the provided metric. Multiple timers can run simultaneously. Returns a unique TimerId for the new timer.

import mozilla.components.service.glean.GleanTimerId
import org.mozilla.yourApplication.GleanMetrics.Pages

val timerId : GleanTimerId

fun onPageStart(e: Event) {
}

import mozilla.components.service.glean.GleanTimerId;
import org.mozilla.yourApplication.GleanMetrics.Pages;

GleanTimerId timerId;

void onPageStart(Event e) {
}

import Glean

var timerId : GleanTimerId

func onPageStart() {
}

from glean import load_metrics

class PageHandler:
def __init__(self):
self.timer_id = None

def on_page_start(self, event):

use glean_metrics::pages;

fn on_page_start() {
}


C++

#include "mozilla/glean/GleanMetrics.h"



JavaScript

let timerId = Glean.pages.pageLoad.start();


### stopAndAccumulate

Stops tracking time for the provided metric and associated timer id.

Adds a count to the corresponding bucket in the timing distribution. This will record an error if start was not called.

import org.mozilla.yourApplication.GleanMetrics.Pages

}

import org.mozilla.yourApplication.GleanMetrics.Pages;

}

import Glean

}

from glean import load_metrics

class PageHandler:

use glean_metrics::pages;

}


C++

#include "mozilla/glean/GleanMetrics.h"



JavaScript

Glean.pages.pageLoad.stopAndAccumulate(timerId);


### measure

For convenience one can measure the time of a function or block of code.

import org.mozilla.yourApplication.GleanMetrics.Pages

}

import Glean

}

from glean import load_metrics



### cancel

Aborts a previous start call. No error is recorded if start was not called.

import org.mozilla.yourApplication.GleanMetrics.Pages

fun onPageError(e: Event) {
}

import org.mozilla.yourApplication.GleanMetrics.Pages;

fun onPageError(e: Event) {
}

import Glean

func onPageError() {
}

from glean import load_metrics

class PageHandler:
def on_page_error(self, event):

use glean_metrics::pages;

fn on_page_error() {
}


C++

#include "mozilla/glean/GleanMetrics.h"



JavaScript

Glean.pages.pageLoad.cancel(timerId);


## Testing API

### testGetValue

Gets the recorded value for a given timing distribution metric.
Returns a struct with counts per buckets and total sum if data is stored.
Returns a language-specific empty/null value if no data is stored.

import org.mozilla.yourApplication.GleanMetrics.Pages

// Get snapshot.

// Usually you don't know the exact timing values,
// but how many should have been recorded.
assertEquals(1L, snapshot.sum)

import org.mozilla.yourApplication.GleanMetrics.Pages;

// Get snapshot.

// Usually you don't know the exact timing values,
// but how many should have been recorded.
assertEquals(1L, snapshot.getSum());

// Get snapshot.

// Usually you don't know the exact timing values,
// but how many should have been recorded.
XCTAssertEqual(1, snapshot.sum)

from glean import load_metrics

# Get snapshot.

# Usually you don't know the exact timing values,
# but how many should have been recorded.
assert 1 == snapshot.sum

use glean::ErrorType;
use glean_metrics::pages;

// Get snapshot

// Usually you don't know the exact timing values,
// but how many should have been recorded.
assert_eq!(1, snapshot.values.len());


C++

#include "mozilla/glean/GleanMetrics.h"

// Does it have an expected values?
ASSERT_TRUE(data.sum > 0);


JavaScript

Assert.ok(Glean.pages.pageLoad.testGetValue().sum > 0);


### testGetNumRecordedErrors

Gets the number of errors recorded for a given timing distribution metric.

import org.mozilla.yourApplication.GleanMetrics.Pages

// Assert that no errors were recorded.
assertEquals(
0,
)

import org.mozilla.yourApplication.GleanMetrics.Pages;

// Assert that no errors were recorded.
assertEquals(
0,
);

// Assert that no errors were recorded.

from glean import load_metrics

# Assert that no errors were recorded.
ErrorType.INVALID_VALUE
)

use glean::ErrorType;
use glean_metrics::pages;

assert_eq!(
0,
);


## Metric parameters

Example timing distribution metric definition:

pages:
type: timing_distribution
time_unit: millisecond
description: >
Counts how long each page takes to load
bugs:
- https://bugzilla.mozilla.org/000000
data_reviews:
- https://bugzilla.mozilla.org/show_bug.cgi?id=000000#c3
- me@mozilla.com
expires: 2020-10-01


### Extra metric parameters

#### time_unit

Timing distributions have a required time_unit parameter to specify the smallest unit of resolution that the timespan will record. The allowed values for time_unit are:

• nanosecond
• microsecond
• millisecond
• second
• minute
• hour
• day

## Limits

• Timings are recorded in nanoseconds.

• The maximum timing value that will be recorded depends on the time_unit parameter:

• nanosecond: 1ns <= x <= 10 minutes
• microsecond: 1μs <= x <= ~6.94 days
• millisecond: 1ms <= x <= ~19 years

Longer times will be truncated to the maximum value and an error will be recorded.

## Data questions

• How long does it take a page to load?

## Simulator

Note The data provided, is assumed to be in the configured time unit. The data recorded, on the other hand, is always in nanoseconds. This means that, if the configured time unit is not nanoseconds, the data will be transformed before being recorded. Notice this, by using the select field above to change the time unit and see the mean of the data recorded changing.