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

openSUSE Build Service is sponsored by