Search documentation of runtime_tools

# scheduler (runtime_tools v2.4)

Copy Markdown View Source

Measure scheduler utilization

This module contains utility functions for easy measurement and calculation of scheduler utilization. It act as a wrapper around the more primitive API `erlang:statistics(scheduler_wall_time)`.

The simplest usage is to call the blocking `scheduler:utilization(Seconds)`.

For non blocking and/or continuous calculation of scheduler utilization, the recommended usage is:

- First call `erlang:system_flag(scheduler_wall_time, true)` to enable scheduler wall time measurements.
- Call `get_sample/0` to collect samples with some time in between.
- Call `utilization/2` to calculate the scheduler utilization in the interval between two samples.
- When done call `erlang:system_flag(scheduler_wall_time, false)` to disable scheduler wall time measurements and avoid unecessary CPU overhead.

To get correct values from `utilization/2`, it is important that `scheduler_wall_time` is kept enabled during the entire interval between the two samples. To ensure this, the process that called `erlang:system_flag(scheduler_wall_time, true)` must be kept alive, as `scheduler_wall_time` will automatically be disabled if it terminates.

## Summary

### Types

sched_id()
sched_sample()
sched_type()
sched_util_result()

A list of tuples containing results for individual schedulers as well as aggregated averages. `Util` is the scheduler utilization as a floating point value between 0.0 and 1.0. `Percent` is the same utilization as a more human readable string expressed in percent.

### Functions

get_sample()

Returns a scheduler utilization sample for normal and dirty-cpu schedulers. Returns `undefined` if system flag `scheduler_wall_time` has not been enabled.

get_sample_all()

Return a scheduler utilization sample for all schedulers, including dirty-io schedulers. Returns `undefined` if system flag `scheduler_wall_time` has not been enabled.

sample()

Return a scheduler utilization sample for normal and dirty-cpu schedulers. Will call `erlang:system_flag(scheduler_wall_time, true)` first if not already already enabled.

sample_all()

Return a scheduler utilization sample for all schedulers, including dirty-io schedulers. Will call `erlang:system_flag(scheduler_wall_time, true)` first if not already already enabled.

utilization/1

Measure utilization for normal and dirty-cpu schedulers during `Seconds` seconds, and then return the result.

utilization(Sample1, Sample2)

Calculates scheduler utilizations for the time interval between the two samples obtained from calling `get_sample/0` or `get_sample_all/0`.

## Types

# sched_id()

(not exported) (since OTP 21.0)

    -type sched_id() :: integer().

# sched_sample()

(since OTP 21.0)

    -opaque sched_sample()

# sched_type()

(not exported) (since OTP 21.0)

    -type sched_type() :: normal | cpu | io.

# sched_util_result()

(not exported) (since OTP 21.0)

    -type sched_util_result() ::
              [{sched_type(), sched_id(), float(), string()} |
               {total, float(), string()} |
               {weighted, float(), string()}].

A list of tuples containing results for individual schedulers as well as aggregated averages. `Util` is the scheduler utilization as a floating point value between 0.0 and 1.0. `Percent` is the same utilization as a more human readable string expressed in percent.

- `{normal, SchedulerId, Util, Percent}` - Scheduler utilization of a normal scheduler with number `SchedulerId`. Schedulers that are not online will also be included. Online schedulers have the lowest `SchedulerId`.

- `{cpu, SchedulerId, Util, Percent}` - Scheduler utilization of a dirty-cpu scheduler with number `SchedulerId`.

- `{io, SchedulerId, Util, Percent}` - Scheduler utilization of a dirty-io scheduler with number `SchedulerId`. This tuple will only exist if both samples were taken with `sample_all/0`.

- `{total, Util, Percent}` - Total utilization of all normal and dirty-cpu schedulers.

- `{weighted, Util, Percent}` - Total utilization of all normal and dirty-cpu schedulers, weighted against maximum amount of available CPU time.

## Functions

# get_sample()

(since OTP 24.3)

    -spec get_sample() -> sched_sample() | undefined.

Returns a scheduler utilization sample for normal and dirty-cpu schedulers. Returns `undefined` if system flag `scheduler_wall_time` has not been enabled.

# get_sample_all()

(since OTP 24.3)

    -spec get_sample_all() -> sched_sample() | undefined.

Return a scheduler utilization sample for all schedulers, including dirty-io schedulers. Returns `undefined` if system flag `scheduler_wall_time` has not been enabled.

# sample()

(since OTP 21.0)

    -spec sample() -> sched_sample().

Return a scheduler utilization sample for normal and dirty-cpu schedulers. Will call `erlang:system_flag(scheduler_wall_time, true)` first if not already already enabled.

#### Note

This function is not recommended as there is no way to detect if `scheduler_wall_time` already was enabled or not. If `scheduler_wall_time` has been disabled between two samples, passing them to `utilization/2` will yield invalid results.

Instead use `get_sample/0` together with `erlang:system_flag(scheduler_wall_time, _)`.

# sample_all()

(since OTP 21.0)

    -spec sample_all() -> sched_sample().

Return a scheduler utilization sample for all schedulers, including dirty-io schedulers. Will call `erlang:system_flag(scheduler_wall_time, true)` first if not already already enabled.

#### Note

This function is not recommended for same reason as `sample/0`. Instead use `get_sample_all/0` together with `erlang:system_flag(scheduler_wall_time,_)`.

# utilization/1

(since OTP 21.0)

    -spec utilization(Seconds) -> sched_util_result() when Seconds :: pos_integer();
                     (Sample) -> sched_util_result() when Sample :: sched_sample().

Measure utilization for normal and dirty-cpu schedulers during `Seconds` seconds, and then return the result.

Will automatically first enable and then disable `scheduler_wall_time`.

Calculate scheduler utilizations for the time interval from when `Sample` was taken and "now". The same as calling `scheduler:utilization(Sample, scheduler:sample_all())`.

#### Note

This function is not recommended as it's so easy to get invalid results without noticing. In particular do not do this:

    scheduler:utilization(scheduler:sample()). % DO NOT DO THIS!

The above example takes two samples in rapid succession and calculates the scheduler utilization between them. The resulting values will probably be more misleading than informative.

Instead use `scheduler:utilization/2` and call `get_sample/0` to get samples with some time in between.

# utilization(Sample1, Sample2)

(since OTP 21.0)

    -spec utilization(Sample1, Sample2) -> sched_util_result()
                         when Sample1 :: sched_sample(), Sample2 :: sched_sample().

Calculates scheduler utilizations for the time interval between the two samples obtained from calling `get_sample/0` or `get_sample_all/0`.

This function itself, does not need `scheduler_wall_time` to be enabled. However, for a correct result, `scheduler_wall_time` must have been enabled during the entire interval between the two samples.