File 3793-runtime_tools-Add-scheduler-get_sample-0-and-get_sam.patch of Package erlang
From 3ebb48c8c8e37987f71d02633ce8020af8d3ea9e Mon Sep 17 00:00:00 2001
From: Sverker Eriksson <sverker@erlang.org>
Date: Tue, 23 Nov 2021 21:29:13 +0100
Subject: [PATCH 3/3] runtime_tools: Add scheduler:get_sample/0 and
get_sample_all/0
And clarify documentation,
especially regarding erlang:system_flag(scheduler_wall_time,_).
---
lib/runtime_tools/doc/src/scheduler.xml | 153 +++++++++++++++++----
lib/runtime_tools/src/scheduler.erl | 32 ++++-
lib/runtime_tools/test/scheduler_SUITE.erl | 9 ++
3 files changed, 165 insertions(+), 29 deletions(-)
diff --git a/lib/runtime_tools/doc/src/scheduler.xml b/lib/runtime_tools/doc/src/scheduler.xml
index d539ccb1c6..7e18503d0f 100644
--- a/lib/runtime_tools/doc/src/scheduler.xml
+++ b/lib/runtime_tools/doc/src/scheduler.xml
@@ -35,12 +35,52 @@
<module>scheduler</module>
<modulesummary>Measure scheduler utilization</modulesummary>
<description>
- <p>This module contains utility functions for easier measurement and
- calculation of scheduler utilization, otherwise obtained from calling the
- more primitive <seealso marker="erts:erlang#statistics_scheduler_wall_time">
- <c>statistics(scheduler_wall_time)</c></seealso>.</p>
- <p>The simplest usage is to call <seealso marker="#utilization-1">
- <c>scheduler:utilization(Seconds)</c></seealso>.</p>
+ <p>
+ This module contains utility functions for easy measurement and
+ calculation of scheduler utilization. It act as a wrapper around the more
+ primitive API <seealso marker="erts:erlang#statistics_scheduler_wall_time">
+ <c>erlang:statistics(scheduler_wall_time)</c></seealso>.
+ </p>
+ <p>
+ The simplest usage is to call the blocking <seealso marker="#utilization/1">
+ <c>scheduler:utilization(Seconds)</c></seealso>.
+ </p>
+ <p>
+ For non blocking and/or continuous calculation of scheduler utilization,
+ the recommended usage is:
+ </p>
+ <list>
+ <item><p>
+ First call <seealso marker="erts:erlang#system_flag_scheduler_wall_time">
+ <c>erlang:system_flag(scheduler_wall_time,true)</c></seealso> to enable
+ scheduler wall time measurements.
+ </p></item>
+ <item><p>
+ Call <seealso marker="#get_sample/0"><c>get_sample/0</c></seealso> to
+ collect samples with some time in between.
+ </p></item>
+ <item><p>
+ Call <seealso marker="#utilization/2"><c>utilization/2</c></seealso> to
+ calculate the scheduler utilization in the interval between two
+ samples.
+ </p></item>
+ <item><p>
+ When done call
+ <seealso marker="erts:erlang#system_flag_scheduler_wall_time">
+ <c>erlang:system_flag(scheduler_wall_time,false)</c></seealso> to disable
+ scheduler wall time measurements and avoid unecessary cpu overhead.
+ </p></item>
+ </list>
+ <p>
+ To get correct values from
+ <seealso marker="#utilization/2"><c>utilization/2</c></seealso>, it is
+ important that <c>scheduler_wall_time</c> is kept enabled during the
+ entire interval between the two samples. To ensure this, the process
+ that called <seealso marker="erts:erlang#system_flag_scheduler_wall_time">
+ <c>erlang:system_flag(scheduler_wall_time,true)</c></seealso> must be
+ kept alive, as <c>scheduler_wall_time</c> will automatically be disabled
+ if it terminates.
+ </p>
</description>
<datatypes>
@@ -86,12 +126,54 @@
<funcs>
+ <func>
+ <name name="get_sample" arity="0"/>
+ <fsummary>Get scheduler utilization sample.</fsummary>
+ <desc>
+ <p>Returns a scheduler utilization sample for normal and dirty-cpu
+ schedulers. Returns <c>undefined</c> if system flag
+ <seealso marker="erts:erlang#system_flag_scheduler_wall_time">
+ <c>scheduler_wall_time</c></seealso> has not been enabled.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="get_sample_all" arity="0"/>
+ <fsummary>Get scheduler utilization sample.</fsummary>
+ <desc>
+ <p>Return a scheduler utilization sample for all schedulers,
+ including dirty-io schedulers. Returns <c>undefined</c> if system flag
+ <seealso marker="erts:erlang#system_flag_scheduler_wall_time">
+ <c>scheduler_wall_time</c></seealso> has not been enabled.</p>
+ </desc>
+ </func>
+
<func>
<name name="sample" arity="0"/>
<fsummary>Get scheduler utilization sample.</fsummary>
<desc>
- <p>Return a scheduler utilization sample for normal and dirty-cpu
- schedulers.</p>
+ <p>
+ Return a scheduler utilization sample for normal and dirty-cpu
+ schedulers. Will call
+ <seealso marker="erts:erlang#system_flag_scheduler_wall_time">
+ <c>erlang:system_flag(scheduler_wall_time,true)</c></seealso> first if
+ not already already enabled.
+ </p>
+ <note>
+ <p>
+ This function is <em>not recommended</em> as there is no way to detect if
+ <c>scheduler_wall_time</c> already was enabled or not. If
+ <c>scheduler_wall_time</c> has been disabled between two samples,
+ passing them to <seealso marker="#utilization/1"><c>utilization/2</c></seealso>
+ will yield invalid results.
+ </p>
+ <p>
+ Instead use <seealso marker="#get_sample/0">
+ <c>get_sample/0</c></seealso> together with
+ <seealso marker="erts:erlang#system_flag_scheduler_wall_time">
+ <c>erlang:system_flag(scheduler_wall_time,_)</c></seealso>.
+ </p>
+ </note>
</desc>
</func>
@@ -99,8 +181,22 @@
<name name="sample_all" arity="0"/>
<fsummary>Get scheduler utilization sample.</fsummary>
<desc>
- <p>Return a scheduler utilization sample for all schedulers,
- including dirty-io schedulers.</p>
+ <p>
+ Return a scheduler utilization sample for all schedulers,
+ including dirty-io schedulers. Will call
+ <seealso marker="erts:erlang#system_flag_scheduler_wall_time">
+ <c>erlang:system_flag(scheduler_wall_time,true)</c></seealso> first if
+ not already already enabled.
+ </p>
+ <note>
+ <p>
+ This function is <em>not recommended</em> for same reason as <c>sample/0</c>.
+ Instead use <seealso marker="#get_sample_all/0">
+ <c>get_sample_all/0</c></seealso> together with
+ <seealso marker="erts:erlang#system_flag_scheduler_wall_time">
+ <c>erlang:system_flag(scheduler_wall_time,_)</c></seealso>.
+ </p>
+ </note>
</desc>
</func>
@@ -108,8 +204,15 @@
<name name="utilization" arity="1" clause_i="1"/>
<fsummary>Measure scheduler utilizations during a period of time.</fsummary>
<desc>
- <p>Measure utilization for normal and dirty-cpu schedulers during
- <c><anno>Seconds</anno></c> seconds, and then return the result.</p>
+ <p>
+ Measure utilization for normal and dirty-cpu schedulers during
+ <c><anno>Seconds</anno></c> seconds, and then return the result.
+ </p>
+ <p>
+ Will automatically first enable and then disable
+ <seealso marker="erts:erlang#system_flag_scheduler_wall_time">
+ <c>scheduler_wall_time</c></seealso>.
+ </p>
</desc>
</func>
@@ -122,11 +225,8 @@
<c>scheduler:utilization(Sample, scheduler:sample_all())</c>.</p>
<note>
<p>
- Scheduler utilization is measured as an average value over a time
- interval, calculated as the difference between two samples. To get
- good useful utilization values at least a couple of seconds should
- have passed between the two samples. For this reason, you should not
- do
+ This function is <em>not recommended</em> as it's so easy to get invalid
+ results without noticing. In particular do not do this:
</p>
<pre>
scheduler:utilization(scheduler:sample()). % DO NOT DO THIS!
@@ -137,10 +237,10 @@ scheduler:utilization(scheduler:sample()). % DO NOT DO THIS!
probably be more misleading than informative.
</p>
<p>
- Instead use <seealso marker="#utilization/1">
- <c>scheduler:utilization(Seconds)</c></seealso> or let some time pass
- between <c>Sample=scheduler:sample()</c> and
- <c>scheduler:utilization(Sample)</c>.
+ Instead use <seealso marker="#utilization/2">
+ <c>scheduler:utilization/2</c></seealso> and call
+ <seealso marker="#get_sample/0"><c>get_sample/0</c></seealso> to get
+ samples with some time in between.
</p>
</note>
</desc>
@@ -152,8 +252,15 @@ scheduler:utilization(scheduler:sample()). % DO NOT DO THIS!
<desc>
<p>Calculates scheduler utilizations for the time interval between
the two samples obtained from calling
- <seealso marker="#sample-0"><c>sample/0</c></seealso> or
- <seealso marker="#sample_all-0"><c>sample_all/0</c></seealso>.</p>
+ <seealso marker="#sample-0"><c>get_sample/0</c></seealso> or
+ <seealso marker="#sample_all-0"><c>get_sample_all/0</c></seealso>.</p>
+ <p>
+ This function itself, does not need
+ <seealso marker="erts:erlang#system_flag_scheduler_wall_time">
+ <c>scheduler_wall_time</c></seealso> to be enabled. However, for
+ a correct result, <c>scheduler_wall_time</c> must have been enabled
+ during the entire interval between the two samples.
+ </p>
</desc>
</func>
diff --git a/lib/runtime_tools/src/scheduler.erl b/lib/runtime_tools/src/scheduler.erl
index cc4f26111a..114dfa17fe 100644
--- a/lib/runtime_tools/src/scheduler.erl
+++ b/lib/runtime_tools/src/scheduler.erl
@@ -23,8 +23,8 @@
-module(scheduler).
--export([sample/0,
- sample_all/0,
+-export([sample/0, get_sample/0,
+ sample_all/0, get_sample_all/0,
utilization/1,
utilization/2]).
@@ -54,12 +54,32 @@ sample(Stats) ->
sample(Stats);
List ->
- Sorted = lists:sort(List),
- Tagged = lists:map(fun({I, A, T}) -> {sched_tag(I), I, A, T} end,
- Sorted),
- {Stats, Tagged}
+ create_sample(Stats, List)
end.
+-spec get_sample() -> sched_sample() | undefined.
+get_sample() ->
+ get_sample(scheduler_wall_time).
+
+-spec get_sample_all() -> sched_sample() | undefined.
+get_sample_all() ->
+ get_sample(scheduler_wall_time_all).
+
+get_sample(Stats) ->
+ case erlang:statistics(Stats) of
+ undefined ->
+ undefined;
+ List ->
+ create_sample(Stats, List)
+ end.
+
+create_sample(Stats, List) ->
+ Sorted = lists:sort(List),
+ Tagged = lists:map(fun({I, A, T}) -> {sched_tag(I), I, A, T} end,
+ Sorted),
+ {Stats, Tagged}.
+
+
-type sched_util_result() ::
[{sched_type(), sched_id(), float(), string()} |
{total, float(), string()} |
diff --git a/lib/runtime_tools/test/scheduler_SUITE.erl b/lib/runtime_tools/test/scheduler_SUITE.erl
index 4f000c381b..fd1ec4cc8e 100644
--- a/lib/runtime_tools/test/scheduler_SUITE.erl
+++ b/lib/runtime_tools/test/scheduler_SUITE.erl
@@ -34,6 +34,15 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
basic(_Config) ->
+ undefined = scheduler:get_sample(),
+ undefined = scheduler:get_sample_all(),
+ false = erlang:system_flag(scheduler_wall_time, true),
+ GS1 = scheduler:get_sample(),
+ GS2 = scheduler:get_sample_all(),
+ check(scheduler:utilization(GS1, scheduler:get_sample())),
+ check(scheduler:utilization(GS2, scheduler:get_sample())),
+ true = erlang:system_flag(scheduler_wall_time, false),
+
S1 = scheduler:sample(),
S2 = scheduler:sample_all(),
--
2.31.1