diff options
author | Sverker Eriksson <sverker@erlang.org> | 2022-01-11 23:14:21 +0100 |
---|---|---|
committer | Sverker Eriksson <sverker@erlang.org> | 2022-01-11 23:14:21 +0100 |
commit | 70a36dc442feda69eef375a7ffb15d4a7fb98269 (patch) | |
tree | 430e816276ba7b266c377da10a7f1a8d4c6560e0 /lib | |
parent | f518b5d3a9bde82ebcd16697f01ed2fd1fcfd0cb (diff) | |
parent | d33bb24ef66be325282fc75bee00dec066e6c11c (diff) | |
download | erlang-70a36dc442feda69eef375a7ffb15d4a7fb98269.tar.gz |
Merge branch 'maint'
Diffstat (limited to 'lib')
-rw-r--r-- | lib/runtime_tools/doc/src/scheduler.xml | 153 | ||||
-rw-r--r-- | lib/runtime_tools/src/scheduler.erl | 41 | ||||
-rw-r--r-- | lib/runtime_tools/test/scheduler_SUITE.erl | 25 |
3 files changed, 181 insertions, 38 deletions
diff --git a/lib/runtime_tools/doc/src/scheduler.xml b/lib/runtime_tools/doc/src/scheduler.xml index 5dd721e357..e8024e00ce 100644 --- a/lib/runtime_tools/doc/src/scheduler.xml +++ b/lib/runtime_tools/doc/src/scheduler.xml @@ -35,12 +35,52 @@ <module since="OTP 21.0">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 <seeerl marker="erts:erlang#statistics_scheduler_wall_time"> - <c>statistics(scheduler_wall_time)</c></seeerl>.</p> - <p>The simplest usage is to call <seemfa marker="#utilization/1"> - <c>scheduler:utilization(Seconds)</c></seemfa>.</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 <seeerl marker="erts:erlang#statistics_scheduler_wall_time"> + <c>erlang:statistics(scheduler_wall_time)</c></seeerl>. + </p> + <p> + The simplest usage is to call the blocking <seemfa marker="#utilization/1"> + <c>scheduler:utilization(Seconds)</c></seemfa>. + </p> + <p> + For non blocking and/or continuous calculation of scheduler utilization, + the recommended usage is: + </p> + <list> + <item><p> + First call <seeerl marker="erts:erlang#system_flag_scheduler_wall_time"> + <c>erlang:system_flag(scheduler_wall_time,true)</c></seeerl> to enable + scheduler wall time measurements. + </p></item> + <item><p> + Call <seemfa marker="#get_sample/0"><c>get_sample/0</c></seemfa> to + collect samples with some time in between. + </p></item> + <item><p> + Call <seemfa marker="#utilization/2"><c>utilization/2</c></seemfa> to + calculate the scheduler utilization in the interval between two + samples. + </p></item> + <item><p> + When done call + <seeerl marker="erts:erlang#system_flag_scheduler_wall_time"> + <c>erlang:system_flag(scheduler_wall_time,false)</c></seeerl> to disable + scheduler wall time measurements and avoid unecessary cpu overhead. + </p></item> + </list> + <p> + To get correct values from + <seemfa marker="#utilization/2"><c>utilization/2</c></seemfa>, 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 <seeerl marker="erts:erlang#system_flag_scheduler_wall_time"> + <c>erlang:system_flag(scheduler_wall_time,true)</c></seeerl> must be + kept alive, as <c>scheduler_wall_time</c> will automatically be disabled + if it terminates. + </p> </description> <datatypes> @@ -87,11 +127,53 @@ <funcs> <func> + <name name="get_sample" arity="0" since="OTP @OTP-17830@"/> + <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 + <seeerl marker="erts:erlang#system_flag_scheduler_wall_time"> + <c>scheduler_wall_time</c></seeerl> has not been enabled.</p> + </desc> + </func> + + <func> + <name name="get_sample_all" arity="0" since="OTP @OTP-17830@"/> + <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 + <seeerl marker="erts:erlang#system_flag_scheduler_wall_time"> + <c>scheduler_wall_time</c></seeerl> has not been enabled.</p> + </desc> + </func> + + <func> <name name="sample" arity="0" since="OTP 21.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 + <seeerl marker="erts:erlang#system_flag_scheduler_wall_time"> + <c>erlang:system_flag(scheduler_wall_time,true)</c></seeerl> 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 <seemfa marker="#utilization/1"><c>utilization/2</c></seemfa> + will yield invalid results. + </p> + <p> + Instead use <seemfa marker="#get_sample/0"> + <c>get_sample/0</c></seemfa> together with + <seeerl marker="erts:erlang#system_flag_scheduler_wall_time"> + <c>erlang:system_flag(scheduler_wall_time,_)</c></seeerl>. + </p> + </note> </desc> </func> @@ -99,8 +181,22 @@ <name name="sample_all" arity="0" since="OTP 21.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 + <seeerl marker="erts:erlang#system_flag_scheduler_wall_time"> + <c>erlang:system_flag(scheduler_wall_time,true)</c></seeerl> 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 <seemfa marker="#get_sample_all/0"> + <c>get_sample_all/0</c></seemfa> together with + <seeerl marker="erts:erlang#system_flag_scheduler_wall_time"> + <c>erlang:system_flag(scheduler_wall_time,_)</c></seeerl>. + </p> + </note> </desc> </func> @@ -108,8 +204,15 @@ <name name="utilization" arity="1" clause_i="1" since="OTP 21.0"/> <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 + <seeerl marker="erts:erlang#system_flag_scheduler_wall_time"> + <c>scheduler_wall_time</c></seeerl>. + </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 <seemfa marker="#utilization/1"> - <c>scheduler:utilization(Seconds)</c></seemfa> or let some time pass - between <c>Sample=scheduler:sample()</c> and - <c>scheduler:utilization(Sample)</c>. + Instead use <seemfa marker="#utilization/2"> + <c>scheduler:utilization/2</c></seemfa> and call + <seemfa marker="#get_sample/0"><c>get_sample/0</c></seemfa> 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 - <seemfa marker="#sample/0"><c>sample/0</c></seemfa> or - <seemfa marker="#sample_all/0"><c>sample_all/0</c></seemfa>.</p> + <seemfa marker="#sample/0"><c>get_sample/0</c></seemfa> or + <seemfa marker="#sample_all/0"><c>get_sample_all/0</c></seemfa>.</p> + <p> + This function itself, does not need + <seeerl marker="erts:erlang#system_flag_scheduler_wall_time"> + <c>scheduler_wall_time</c></seeerl> 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 c896b671ac..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()} | @@ -70,16 +90,11 @@ sample(Stats) -> (Sample) -> sched_util_result() when Sample :: sched_sample(). utilization(Seconds) when is_integer(Seconds), Seconds > 0 -> - OldFlag = erlang:system_flag(scheduler_wall_time, true), + _ = erlang:system_flag(scheduler_wall_time, true), T0 = sample(), receive after Seconds*1000 -> ok end, T1 = sample(), - case OldFlag of - false -> - erlang:system_flag(scheduler_wall_time, OldFlag); - true -> - ok - end, + _ = erlang:system_flag(scheduler_wall_time, false), utilization(T0,T1); utilization({Stats, _}=T0) when Stats =:= scheduler_wall_time; diff --git a/lib/runtime_tools/test/scheduler_SUITE.erl b/lib/runtime_tools/test/scheduler_SUITE.erl index 1c80253371..fd1ec4cc8e 100644 --- a/lib/runtime_tools/test/scheduler_SUITE.erl +++ b/lib/runtime_tools/test/scheduler_SUITE.erl @@ -23,15 +23,26 @@ -export([suite/0, all/0]). %% Test cases --export([basic/1]). +-export([basic/1, + utilization_disable/1]). -all() -> [basic]. +all() -> [basic, + utilization_disable]. 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(), @@ -56,6 +67,16 @@ basic(_Config) -> ok. +%% OTP-17800: Test that utilization(Seconds) restores scheduler_wall_time flag +%% even when it already was globally enabled. +utilization_disable(_Config) -> + false = erlang:system_flag(scheduler_wall_time, true), + check(scheduler:utilization(1)), + true = erlang:system_flag(scheduler_wall_time, false), + + undefined = scheduler:get_sample(), + ok. + check([{total, Tf, Ts} | List]=U) -> io:format("\nU = ~p\n", [U]), |