<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">

<erlref>
  <header>
    <copyright>
      <year>2018</year><year>2022</year>
      <holder>Ericsson AB. All Rights Reserved.</holder>
    </copyright>
    <legalnotice>
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      See the License for the specific language governing permissions and
      limitations under the License.

    </legalnotice>

    <title></title>
    <prepared></prepared>
    <responsible></responsible>
    <docno>1</docno>
    <approved></approved>
    <checked></checked>
    <date></date>
    <rev></rev>
    <file>scheduler.xml</file>
  </header>
  <module since="OTP 21.0">scheduler</module>
  <modulesummary>Measure scheduler utilization</modulesummary>
  <description>
    <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>
    <datatype>
      <name name="sched_sample"/>
    </datatype>
    <datatype>
      <name name="sched_type"/>
    </datatype>
    <datatype>
      <name name="sched_id"/>
    </datatype>
    <datatype>
      <name name="sched_util_result"/>
      <desc>
	<p>A list of tuples containing results for individual schedulers
	as well as aggregated averages. <c>Util</c> is the scheduler utilization
	as a floating point value between 0.0 and 1.0. <c>Percent</c> is the
	same utilization as a more human readable string expressed in percent.</p>
	<taglist>
	  <tag><c>{normal, SchedulerId, Util, Percent}</c></tag>
	  <item>Scheduler utilization of a normal scheduler with number
	    <c>SchedulerId</c>. Schedulers that are not online will also be
	    included.
	    <seeerl marker="erts:erlang#system_info_schedulers_online">Online
	    schedulers</seeerl> have the lowest <c>SchedulerId</c>.</item>
	  <tag><c>{cpu, SchedulerId, Util, Percent}</c></tag>
	  <item>Scheduler utilization of a dirty-cpu scheduler with number
	    <c>SchedulerId</c>.</item>
	  <tag><c>{io, SchedulerId, Util, Percent}</c></tag>
	  <item>Scheduler utilization of a dirty-io scheduler with number
	    <c>SchedulerId</c>. This tuple will only exist if both samples were
	    taken with <seemfa marker="#sample_all/0"><c>sample_all/0</c></seemfa>.</item>
	  <tag><c>{total, Util, Percent}</c></tag>
	  <item>Total utilization of all normal and dirty-cpu schedulers.</item>
	  <tag><c>{weighted, Util, Percent}</c></tag>
	  <item>Total utilization of all normal and dirty-cpu schedulers,
	  weighted against maximum amount of available CPU time.</item>
	</taglist>
      </desc>
    </datatype>
  </datatypes>

  <funcs>

    <func>
      <name name="get_sample" arity="0" since="OTP 24.3"/>
      <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 24.3"/>
      <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. 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>

    <func>
      <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. 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>

    <func>
      <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>
	  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>

    <func>
      <name name="utilization" arity="1" clause_i="2" since="OTP 21.0"/>
      <fsummary>Measure scheduler utilizations since sample.</fsummary>
      <desc>
        <p>Calculate scheduler utilizations for the time interval from when
	<c><anno>Sample</anno></c> was taken and "now". The same as calling
	<c>scheduler:utilization(Sample, scheduler:sample_all())</c>.</p>
	<note>
	  <p>
	    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!
</pre>
          <p>
            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.
	  </p>
	  <p>
	    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>
    </func>

    <func>
      <name name="utilization" arity="2" since="OTP 21.0"/>
      <fsummary>Measure scheduler utilizations between two samples.</fsummary>
      <desc>
	<p>Calculates scheduler utilizations for the time interval between
	the two samples obtained from calling
	<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>

  </funcs>
 </erlref>
