<?xml version="1.0" encoding="us-ascii"?>
  <?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
  <!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.7 (Ruby 3.1.2) -->


<!DOCTYPE rfc  [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">

<!ENTITY RFC1242 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.1242.xml">
<!ENTITY RFC2285 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2285.xml">
<!ENTITY RFC2544 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2544.xml">
<!ENTITY RFC9004 SYSTEM "https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9004.xml">
]>


<rfc ipr="trust200902" docName="draft-ietf-bmwg-mlrsearch-06" category="info" tocInclude="true" sortRefs="true" symRefs="true">
  <front>
    <title abbrev="MLRsearch">Multiple Loss Ratio Search</title>

    <author initials="M." surname="Konstantynowicz" fullname="Maciek Konstantynowicz">
      <organization>Cisco Systems</organization>
      <address>
        <email>mkonstan@cisco.com</email>
      </address>
    </author>
    <author initials="V." surname="Polak" fullname="Vratko Polak">
      <organization>Cisco Systems</organization>
      <address>
        <email>vrpolak@cisco.com</email>
      </address>
    </author>

    <date year="2024" month="March" day="04"/>

    <area>ops</area>
    <workgroup>Benchmarking Working Group</workgroup>
    <keyword>Internet-Draft</keyword>

    <abstract>


<?line 51?>

<t>This document proposes extensions to <xref target="RFC2544"></xref> throughput search by
defining a new methodology called Multiple Loss Ratio search
(MLRsearch). MLRsearch aims to minimize search duration,
support multiple loss ratio searches,
and enhance result repeatability and comparability.</t>

<t>The primary reason for extending <xref target="RFC2544"></xref> is to address the challenges
and requirements presented by the evaluation and testing
of software-based networking systems&#39; data planes.</t>

<t>To give users more freedom, MLRsearch provides additional configuration options
such as allowing multiple shorter trials per load instead of one large trial,
tolerating a certain percentage of trial results with higher loss,
and supporting the search for multiple goals with varying loss ratios.</t>



    </abstract>



  </front>

  <middle>


<?line 68?>


<section anchor="purpose-and-scope"><name>Purpose and Scope</name>

<t>The purpose of this document is to describe Multiple Loss Ratio search
(MLRsearch), a data plane throughput search methodology optimized for software
networking DUTs.</t>

<t>Applying vanilla <xref target="RFC2544"></xref> throughput bisection to software DUTs
results in several problems:</t>

<t><list style="symbols">
  <t>Binary search takes too long as most trials are done far from the
eventually found throughput.</t>
  <t>The required final trial duration and pauses between trials
prolong the overall search duration.</t>
  <t>Software DUTs show noisy trial results,
leading to a big spread of possible discovered throughput values.</t>
  <t>Throughput requires a loss of exactly zero frames, but the industry
frequently allows for small but non-zero losses.</t>
  <t>The definition of throughput is not clear when trial results are inconsistent.</t>
</list></t>

<t>To address the problems mentioned above,
the MLRsearch library employs the following enhancements:</t>

<t><list style="symbols">
  <t>Allow multiple shorter trials instead of one big trial per load.
  <list style="symbols">
      <t>Optionally, tolerate a percentage of trial results with higher loss.</t>
    </list></t>
  <t>Allow searching for multiple search goals, with differing loss ratios.
  <list style="symbols">
      <t>Any trial result can affect each search goal in principle.</t>
    </list></t>
  <t>Insert multiple coarse targets for each search goal, earlier ones need
to spend less time on trials.
  <list style="symbols">
      <t>Earlier targets also aim for lesser precision.</t>
      <t>Use Forwarding Rate (FR) at maximum offered load
<xref target="RFC2285"></xref> (section 3.6.2) to initialize the initial targets.</t>
    </list></t>
  <t>Take care when dealing with inconsistent trial results.
  <list style="symbols">
      <t>Reported throughput is smaller than the smallest load with high loss.</t>
      <t>Smaller load candidates are measured first.</t>
    </list></t>
  <t>Apply several load selection heuristics to save even more time
by trying hard to avoid unnecessarily narrow bounds.</t>
</list></t>

<t>Some of these enhancements are formalized as MLRsearch specification,
the remaining enhancements are treated as implementation details,
thus achieving high comparability without limiting future improvements.</t>

<t>MLRsearch configuration options are flexible enough to
support both conservative settings and aggressive settings.
Where the conservative settings lead to results
unconditionally compliant with <xref target="RFC2544"></xref>,
but longer search duration and worse repeatability.
Conversely, aggressive settings lead to shorter search duration
and better repeatability, but the results are not compliant with <xref target="RFC2544"></xref>.</t>

<t>No part of <xref target="RFC2544"></xref> is intended to be obsoleted by this document.</t>

</section>
<section anchor="identified-problems"><name>Identified Problems</name>

<t>This chapter describes the problems affecting usability
of various performance testing methodologies,
mainly a binary search for <xref target="RFC2544"></xref> unconditionally compliant throughput.</t>

<section anchor="long-search-duration"><name>Long Search Duration</name>

<t>The emergence of software DUTs, with frequent software updates and a
number of different frame processing modes and configurations,
has increased both the number of performance tests
required to verify the DUT update and the frequency of running those tests.
This makes the overall test execution time even more important than before.</t>

<t>The current <xref target="RFC2544"></xref> throughput definition restricts the potential
for time-efficiency improvements.
A more generalized throughput concept could enable further enhancements
while maintaining the precision of simpler methods.</t>

<t>The bisection method, when unconditionally compliant with <xref target="RFC2544"></xref>,
is excessively slow.
This is because a significant amount of time is spent on trials
with loads that, in retrospect, are far from the final determined throughput.</t>

<t><xref target="RFC2544"></xref> does not specify any stopping condition for throughput search,
so users already have an access to a limited trade-off
between search duration and achieved precision.
However, each full 60-second trials doubles the precision,
so not many trials can be removed without a substantial loss of precision.</t>

</section>
<section anchor="dut-in-sut"><name>DUT in SUT</name>

<t><xref target="RFC2285"></xref> defines:
- DUT as
  - The network forwarding device to which stimulus is offered and
    response measured <xref target="RFC2285"></xref> (section 3.1.1).
- SUT as
  - The collective set of network devices to which stimulus is offered
    as a single entity and response measured <xref target="RFC2285"></xref> (section 3.1.2).</t>

<t><xref target="RFC2544"></xref> specifies a test setup with an external tester stimulating the
networking system, treating it either as a single DUT, or as a system
of devices, an SUT.</t>

<t>In the case of software networking, the SUT consists of not only the DUT
as a software program processing frames, but also of
a server hardware and operating system functions,
with server hardware resources shared across all programs
and the operating system running on the same server.</t>

<t>Given that the SUT is a shared multi-tenant environment
encompassing the DUT and other components, the DUT might inadvertently
experience interference from the operating system
or other software operating on the same server.</t>

<t>Some of this interference can be mitigated.
For instance,
pinning DUT program threads to specific CPU cores
and isolating those cores can prevent context switching.</t>

<t>Despite taking all feasible precautions, some adverse effects may still impact
the DUT&#39;s network performance.
In this document, these effects are collectively
referred to as SUT noise, even if the effects are not as unpredictable
as what other engineering disciplines call noise.</t>

<t>DUT can also exhibit fluctuating performance itself, for reasons
not related to the rest of SUT; for example due to pauses in execution
as needed for internal stateful processing.
In many cases this
may be an expected per-design behavior, as it would be observable even
in a hypothetical scenario where all sources of SUT noise are eliminated.
Such behavior affects trial results in a way similar to SUT noise.
As the two phenomenons are hard to distinguish,
in this document the term &#39;noise&#39; is used to encompass
both the internal performance fluctuations of the DUT
and the genuine noise of the SUT.</t>

<t>A simple model of SUT performance consists of an idealized noiseless performance,
and additional noise effects.
For a specific SUT, the noiseless performance is assumed to be constant,
with all observed performance variations being attributed to noise.
The impact of the noise can vary in time, sometimes wildly,
even within a single trial.
The noise can sometimes be negligible, but frequently
it lowers the observed SUT performance as observed in trial results.</t>

<t>In this model, SUT does not have a single performance value, it has a spectrum.
One end of the spectrum is the idealized noiseless performance value,
the other end can be called a noiseful performance.
In practice, trial result
close to the noiseful end of the spectrum happens only rarely.
The worse the performance value is, the more rarely it is seen in a trial.
Therefore, the extreme noiseful end of the SUT spectrum is not observable
among trial results.
Also, the extreme noiseless end of the SUT spectrum
is unlikely to be observable, this time because some small noise effects
are likely to occur multiple times during a trial.</t>

<t>Unless specified otherwise, this document&#39;s focus is
on the potentially observable ends of the SUT performance spectrum,
as opposed to the extreme ones.</t>

<t>When focusing on the DUT, the benchmarking effort should ideally aim
to eliminate only the SUT noise from SUT measurements.
However,
this is currently not feasible in practice, as there are no realistic enough
models available to distinguish SUT noise from DUT fluctuations,
based on the author&#39;s experience and available literature.</t>

<t>Assuming a well-constructed SUT, the DUT is likely its
primary performance bottleneck.
In this case, we can define the DUT&#39;s
ideal noiseless performance as the noiseless end of the SUT performance spectrum,
especially for throughput.
However, other performance metrics, such as latency,
may require additional considerations.</t>

<t>Note that by this definition, DUT noiseless performance
also minimizes the impact of DUT fluctuations, as much as realistically possible
for a given trial duration.</t>

<t>This document aims to solve the DUT in SUT problem
by estimating the noiseless end of the SUT performance spectrum
using a limited number of trial results.</t>

<t>Any improvements to the throughput search algorithm, aimed at better
dealing with software networking SUT and DUT setup, should employ
strategies recognizing the presence of SUT noise, allowing the discovery of
(proxies for) DUT noiseless performance
at different levels of sensitivity to SUT noise.</t>

</section>
<section anchor="repeatability-and-comparability"><name>Repeatability and Comparability</name>

<t><xref target="RFC2544"></xref> does not suggest to repeat throughput search.
And from just one
discovered throughput value, it cannot be determined how repeatable that value is.
Poor repeatability then leads to poor comparability,
as different benchmarking teams may obtain varying throughput values
for the same SUT, exceeding the expected differences from search precision.</t>

<t><xref target="RFC2544"></xref> throughput requirements (60 seconds trial and
no tolerance of a single frame loss) affect the throughput results
in the following way.
The SUT behavior close to the noiseful end of its performance spectrum
consists of rare occasions of significantly low performance,
but the long trial duration makes those occasions not so rare on the trial level.
Therefore, the binary search results tend to wander away from the noiseless end
of SUT performance spectrum, more frequently and more widely than shorter
trials would, thus causing poor throughput repeatability.</t>

<t>The repeatability problem can be addressed by defining a search procedure
that identifies a consistent level of performance,
even if it does not meet the strict definition of throughput in <xref target="RFC2544"></xref>.</t>

<t>According to the SUT performance spectrum model, better repeatability
will be at the noiseless end of the spectrum.
Therefore, solutions to the DUT in SUT problem
will help also with the repeatability problem.</t>

<t>Conversely, any alteration to <xref target="RFC2544"></xref> throughput search
that improves repeatability should be considered
as less dependent on the SUT noise.</t>

<t>An alternative option is to simply run a search multiple times, and report some
statistics (e.g. average and standard deviation).
This can be used
for a subset of tests deemed more important,
but it makes the search duration problem even more pronounced.</t>

</section>
<section anchor="throughput-with-non-zero-loss"><name>Throughput with Non-Zero Loss</name>

<t><xref target="RFC1242"></xref> (section 3.17) defines throughput as:
    The maximum rate at which none of the offered frames
    are dropped by the device.</t>

<t>Then, it says:
    Since even the loss of one frame in a
    data stream can cause significant delays while
    waiting for the higher level protocols to time out,
    it is useful to know the actual maximum data
    rate that the device can support.</t>

<t>However, many benchmarking teams accept a small,
non-zero loss ratio as the goal for their load search.</t>

<t>Motivations are many:</t>

<t><list style="symbols">
  <t>Modern protocols tolerate frame loss better,
compared to the time when <xref target="RFC1242"></xref> and <xref target="RFC2544"></xref> were specified.</t>
  <t>Trials nowadays send way more frames within the same duration,
increasing the chance of a small SUT performance fluctuation
being enough to cause frame loss.</t>
  <t>Small bursts of frame loss caused by noise have otherwise smaller impact
on the average frame loss ratio observed in the trial,
as during other parts of the same trial the SUT may work more closely
to its noiseless performance, thus perhaps lowering the trial loss ratio
below the goal loss ratio value.</t>
  <t>If an approximation of the SUT noise impact on the trial loss ratio is known,
it can be set as the goal loss ratio.</t>
</list></t>

<t>Regardless of the validity of all similar motivations,
support for non-zero loss goals makes any search algorithm more user-friendly.
<xref target="RFC2544"></xref> throughput is not user-friendly in this regard.</t>

<t>Furthermore, allowing users to specify multiple loss ratio values,
and enabling a single search to find all relevant bounds,
significantly enhances the usefulness of the search algorithm.</t>

<t>Searching for multiple search goals also helps to describe the SUT performance
spectrum better than the result of a single search goal.
For example, the repeated wide gap between zero and non-zero loss loads
indicates the noise has a large impact on the observed performance,
which is not evident from a single goal load search procedure result.</t>

<t>It is easy to modify the vanilla bisection to find a lower bound
for the intended load that satisfies a non-zero goal loss ratio.
But it is not that obvious how to search for multiple goals at once,
hence the support for multiple search goals remains a problem.</t>

</section>
<section anchor="inconsistent-trial-results"><name>Inconsistent Trial Results</name>

<t>While performing throughput search by executing a sequence of
measurement trials, there is a risk of encountering inconsistencies
between trial results.</t>

<t>The plain bisection never encounters inconsistent trials.
But <xref target="RFC2544"></xref> hints about the possibility of inconsistent trial results,
in two places in its text.
The first place is section 24, where full trial durations are required,
presumably because they can be inconsistent with the results
from shorter trial durations.
The second place is section 26.3, where two successive zero-loss trials
are recommended, presumably because after one zero-loss trial
there can be a subsequent inconsistent non-zero-loss trial.</t>

<t>Examples include:</t>

<t><list style="symbols">
  <t>A trial at the same load (same or different trial duration) results
in a different trial loss ratio.</t>
  <t>A trial at a higher load (same or different trial duration) results
in a smaller trial loss ratio.</t>
</list></t>

<t>Any robust throughput search algorithm needs to decide how to continue
the search in the presence of such inconsistencies.
Definitions of throughput in <xref target="RFC1242"></xref> and <xref target="RFC2544"></xref> are not specific enough
to imply a unique way of handling such inconsistencies.</t>

<t>Ideally, there will be a definition of a new quantity which both generalizes
throughput for non-zero-loss (and other possible repeatability enhancements),
while being precise enough to force a specific way to resolve trial result
inconsistencies.
But until such a definition is agreed upon, the correct way to handle
inconsistent trial results remains an open problem.</t>

</section>
</section>
<section anchor="mlrsearch-specification"><name>MLRsearch Specification</name>

<t>This chapter focuses on technical definitions needed for evaluating
whether a particular test procedure adheres to MLRsearch specification.</t>

<t>For motivations, explanations, and other comments see other chapters.</t>

<section anchor="mlrsearch-architecture"><name>MLRsearch Architecture</name>

<t>MLRsearch architecture consists of three main components:
the manager, the controller, and the measurer.
For definitions of the components, see the following sections.</t>

<t>The architecture also implies the presence of other components, such as the SUT.</t>

<t>These components can be seen as abstractions present in any testing procedure.</t>

<section anchor="measurer"><name>Measurer</name>

<t>The measurer is the component that performs one trial
as described in <xref target="RFC2544"></xref> section 23.</t>

<t>Specifically, one call to the measurer accepts a trial load value
and trial duration value, performs the trial, and returns
the measured trial loss ratio, and optionally a different duration value.</t>

<t>It is the responsibility of the measurer to uphold any requirements
and assumptions present in MLRsearch specification
(e.g. trial forwarding ratio not being larger than one).
Implementers have some freedom, for example in the way they deal with
duplicated frames, or what to return if the tester sent zero frames towards SUT.
Implementations are RECOMMENDED to document their behavior
related to such freedoms in as detailed a way as possible.</t>

<t>Implementations MUST document any deviations from RFC documents,
for example if the wait time around traffic
is shorter than what <xref target="RFC2544"></xref> section 23 specifies.</t>

</section>
<section anchor="controller"><name>Controller</name>

<t>The controller selects trial load and duration values
to achieve the search goals in the shortest expected time.</t>

<t>The controller calls the measurer multiple times,
receiving the trial result from each call.
After exit condition is met, the controller returns
the overall search results.</t>

<t>The controller&#39;s role in optimizing trial load and duration selection
distinguishes MLRsearch algorithms from simpler search procedures.</t>

<t>For controller inputs, see later section Controller Inputs.
For controller outputs, see later section Controller Outputs.</t>

</section>
<section anchor="manager"><name>Manager</name>

<t>The controller gets initiated by the manager once, and subsequently calls</t>

<t>The manager is the component that initializes SUT, the traffic generator
(tester in <xref target="RFC2544"></xref> terminology), the measurer and the controller
with intended configurations.
It then calls the controller once, and receives its outputs.</t>

<t>The manager is also responsible for creating reports in the appropriate format,
based on information in controller outputs.</t>

</section>
</section>
<section anchor="units"><name>Units</name>

<t>The specification deals with physical quantities, so it is assumed
each numeric value is accompanied by an appropriate physical unit.</t>

<t>The specification does not state which unit is appropriate,
but implementations MUST make it explicit which unit is used
for each value provided or received by the user.</t>

<t>For example, load quantities (including the conditional throughput)
returned by the controller are defined to be based on a single-interface
(unidirectional) loads.
For bidirectional traffic, users are likely
to expect bidirectional throughput quantities, so the manager is responsible
for making its report clear.</t>

</section>
<section anchor="sut"><name>SUT</name>

<t>As defined in <xref target="RFC2285"></xref>:
The collective set of network devices to which stimulus is offered
as a single entity and response measured.</t>

</section>
<section anchor="trial"><name>Trial</name>

<t>A trial is the part of the test described in <xref target="RFC2544"></xref> section 23.</t>

<section anchor="trial-load"><name>Trial Load</name>

<t>The trial load is the intended constant load for a trial.</t>

<t>Load is the quantity implied by Constant Load of <xref target="RFC1242"></xref>,
Data Rate of <xref target="RFC2544"></xref> and Intended Load of <xref target="RFC2285"></xref>.
All three specify this value applies to one (input or output) interface.</t>

</section>
<section anchor="trial-duration"><name>Trial Duration</name>

<t>Trial duration is the intended duration of the traffic for a trial.</t>

<t>In general, this quantity does not include any preparation nor waiting
described in section 23 of <xref target="RFC2544"></xref>.</t>

<t>However, the measurer MAY return a duration value that deviates
from the intended duration.
This feature can be beneficial for users
who wish to manage the overall search duration,
rather than solely the traffic portion of it.
The manager MUST report
how the measurer computes the returned duration values in that case.</t>

</section>
<section anchor="trial-forwarding-ratio"><name>Trial Forwarding Ratio</name>

<t>The trial forwarding ratio is a dimensionless floating point value
that ranges from 0.0 to 1.0, inclusive.
It is calculated by dividing the number of frames
successfully forwarded by the SUT
by the total number of frames expected to be forwarded during the trial.</t>

<t>Note that, contrary to loads, frame counts used to compute
trial forwarding ratio are aggregates over all SUT output ports.</t>

<t>Questions around what is the correct number of frames
that should have been forwarded is outside of the scope of this document.
E.g. what should the measurer return when it detects
that the offered load differs significantly from the intended load.</t>

</section>
<section anchor="trial-loss-ratio"><name>Trial Loss Ratio</name>

<t>The trial loss ratio is equal to one minus the trial forwarding ratio.</t>

</section>
<section anchor="trial-forwarding-rate"><name>Trial Forwarding Rate</name>

<t>The trial forwarding rate is a derived quantity, calculated by
multiplying the trial load by the trial forwarding ratio.</t>

<t>It is important to note that while similar, this quantity is not identical
to the Forwarding Rate as defined in <xref target="RFC2285"></xref> section 3.6.1,
as the latter is specific to one output interface,
whereas the trial forwarding ratio is based
on frame counts aggregated over all SUT output interfaces.</t>

</section>
</section>
<section anchor="traffic-profile"><name>Traffic profile</name>

<t>Any other specifics (besides trial load and trial duration)
the measurer needs in order to perform the trial
are understood as a composite called the traffic profile.
All its attributes are assumed to be constant during the search,
and the composite is configured on the measurer by the manager
before the search starts.</t>

<t>The traffic profile is REQUIRED by <xref target="RFC2544"></xref>
to contain some specific quantities, for example frame size.
Several more specific quantities may be RECOMMENDED.</t>

<t>Depending on SUT configuration, e.g. when testing specific protocols,
additional values need to be included in the traffic profile
and in the test report.
See other IETF documents.</t>

</section>
<section anchor="search-goal"><name>Search Goal</name>

<t>The search goal is a composite consisting of several attributes,
some of them are required.
Implementations are free to add their own attributes.</t>

<t>A particular set of attribute values is called a search goal instance.</t>

<t>Subsections list all required attributes and one recommended attribute.
Each subsection contains a short informal description,
but see other chapters for more in-depth explanations.</t>

<t>The meaning of the attributes is formally given only by their effect
on the controller output attributes (defined in later in section Search Result).</t>

<t>Informally, later chapters give additional intuitions and examples
to the search goal attribute values.
Later chapters also give motivation to formulas of computation of the outputs.</t>

<section anchor="goal-final-trial-duration"><name>Goal Final Trial Duration</name>

<t>A threshold value for trial durations.
This attribute is REQUIRED, and the value MUST be positive.</t>

<t>Informally, while MLRsearch is allowed to perform trials shorter than this,
but results from such short trials have only limited impact on search results.</t>

<t>The full relation needs definitions is later subsections.
But for example, the conditional throughput
(definition in subsection Conditional Throughput)
for this goal will be computed only from trial results
from trials at least as long as this.</t>

</section>
<section anchor="goal-duration-sum"><name>Goal Duration Sum</name>

<t>A threshold value for a particular sum of trial durations.
This attribute is REQUIRED, and the value MUST be positive.</t>

<t>This uses the duration values returned by the measurer.</t>

<t>Informally, even when looking only at trials done at this goal&#39;s
final trial duration, MLRsearch may spend up to this time measuring
the same load value.
If the goal duration sum is larger than
the goal final trial duration, it means multiple trials need to be measured
at the same load.</t>

</section>
<section anchor="goal-loss-ratio"><name>Goal Loss Ratio</name>

<t>A threshold value for trial loss ratios.
REQUIRED attribute, MUST be non-negative and smaller than one.</t>

<t>Informally, if a load causes too many trials with trial loss ratios
larger than this, the conditional throughput for this goal
will be smaller than that load.</t>

</section>
<section anchor="goal-exceed-ratio"><name>Goal Exceed Ratio</name>

<t>A threshold value for a particular ratio of duration sums.
REQUIRED attribute, MUST be non-negative and smaller than one.</t>

<t>The duration sum values come from the duration values returned by the measurer.</t>

<t>Informally, the impact of lossy trials is controlled by this value.
The full relation needs definitions is later subsections.</t>

<t>But for example, the definition of the conditional throughput
(given later in subsection Conditional Throughput)
refers to a q-value for a quantile when selecting
which trial result gives the conditional throughput.
The goal exceed ratio acts as the q-value to use there.</t>

<t>Specifically, when the goal exceed ratio is 0.5 and MLRsearch happened
to use the whole goal duration sum (using full-length trials),
it means the conditional throughput is the median of trial forwarding rates.</t>

</section>
<section anchor="goal-width"><name>Goal Width</name>

<t>A value used as a threshold for telling when two trial load values
are close enough.</t>

<t>RECOMMENDED attribute, positive.
Implementations without this attribute
MUST give the manager other ways to control the search exit condition.</t>

<t>Absolute load difference and relative load difference are two popular choices,
but implementations may choose a different way to specify width.</t>

<t>Informally, this acts as a stopping condition, controlling the precision
of the search.
The search stops if every goal has reached its precision.</t>

</section>
</section>
<section anchor="controller-inputs"><name>Controller Inputs</name>

<t>The only REQUIRED input for controller is a set of search goal instances.
MLRsearch implementations MAY use additional input parameters for the controller.</t>

<t>The order of instances SHOULD NOT have a big impact on controller outputs,
but MLRsearch implementations MAY base their behavior on the order
of search goal instances.</t>

<t>The search goal instances SHOULD NOT be identical.
MLRsearch implementation MAY allow identical instances.</t>

</section>
<section anchor="goal-result"><name>Goal Result</name>

<t>Before defining the output of the controller,
it is useful to define what the goal result is.</t>

<t>The goal result is a composite object consisting of several attributes.
A particular set of attribute values is called a goal result instance.</t>

<t>Any goal result instance can be either regular or irregular.
MLRsearch specification puts requirements on regular goal result instances.
Any instance that does not meet the requirements is deemed irregular.</t>

<t>Implementations are free to define their own irregular goal results,
but the manager MUST report them clearly as not regular according to this section.</t>

<t>All attribute values in one goal result instance
are related to a single search goal instance,
referred to as the given search goal.</t>

<t>Some of the attributes of a regular goal result instance are required,
some are recommended, implementations are free to add their own.</t>

<t>The subsections define two required and one optional attribute
for a regular goal result.</t>

<t>A typical irregular result is when all trials at the maximal offered load
have zero loss, as the relevant upper bound does not exist in that case.</t>

<section anchor="relevant-upper-bound"><name>Relevant Upper Bound</name>

<t>The relevant upper bound is the smallest intended load value that is classified
at the end of the search as an upper bound (see Appendix A)
for the given search goal.
This is a REQUIRED attribute.</t>

<t>Informally, this is the smallest intended load that failed to uphold
all the requirements of the given search goal, mainly the goal loss ratio
in combination with the goal exceed ratio.</t>

</section>
<section anchor="relevant-lower-bound"><name>Relevant Lower Bound</name>

<t>The relevant lower bound is the largest intended load value
among those smaller than the relevant upper bound
that got classified at the end of the search
as a lower bound (see Appendix A) for the given search goal.
This is a REQUIRED attribute.</t>

<t>For a regular goal result, the distance between the relevant lower bound
and the relevant upper bound MUST NOT be larger than the goal width,
if the implementation offers width as a goal attribute.</t>

<t>Informally, this is the largest intended load that managed to uphold
all the requirements of the given search goal, mainly the goal loss ratio
in combination with the goal exceed ratio, while not being larger
than the relevant upper bound.</t>

</section>
<section anchor="conditional-throughput"><name>Conditional Throughput</name>

<t>The conditional throughput (see Appendix B)
as evaluated at the relevant lower bound of the given search goal
at the end of the search.
This is a RECOMMENDED attribute.</t>

<t>Informally, this is a typical forwarding rate expected to be seen
at the relevant lower bound of the given search goal.
But frequently just a conservative estimate thereof,
as MLRsearch implementations tend to stop gathering more data
as soon as they confirm the result cannot get worse than this estimate
within the goal duration sum.</t>

</section>
</section>
<section anchor="search-result"><name>Search Result</name>

<t>The search result is a single composite object
that maps each search goal to a corresponding goal result.</t>

<t>In other words, search result is an unordered list of key-value pairs,
where no two pairs contain equal keys.
The key is a search goal instance, acting as the given search goal
for the goal result instance in the value portion of the key-value pair.</t>

<t>The search result (as a mapping)
MUST map from all the search goals present in the controller input.</t>

</section>
<section anchor="controller-outputs"><name>Controller Outputs</name>

<t>The search result is the only REQUIRED output
returned from the controller to the manager.</t>

<t>MLRsearch implementation MAY return additional data in the controller output.</t>

</section>
</section>
<section anchor="further-explanations"><name>Further Explanations</name>

<t>This chapter focuses on intuitions and motivations
and skips over some important details.</t>

<t>Familiarity with the MLRsearch specification is not required here,
so this chapter can act as an introduction.
For example, this chapter starts talking about the tightest lower bounds
before it is ready to talk about the relevant lower bound from the specification.</t>

<section anchor="mlrsearch-versions"><name>MLRsearch Versions</name>

<t>The MLRsearch algorithm has been developed in a code-first approach,
a Python library has been created, debugged, and used in production
before the first descriptions (even informal) were published.
In fact, multiple versions of the library were used in the production
over the past few years, and later code was usually not compatible
with earlier descriptions.</t>

<t>The code in (any version of) MLRsearch library fully determines
the search process (for given configuration parameters),
leaving no space for deviations.
MLRsearch, as a name for a broad class of possible algorithms,
leaves plenty of space for future improvements, at the cost
of poor comparability of results of different MLRsearch implementations.</t>

<t>There are two competing needs.
There is the need for standardization in areas critical to comparability.
There is also the need to allow flexibility for implementations
to innovate and improve in other areas.
This document defines the MLRsearch specification
in a manner that aims to fairly balances both needs.</t>

</section>
<section anchor="exit-condition"><name>Exit Condition</name>

<t><xref target="RFC2544"></xref> prescribes that after performing one trial at a specific offered load,
the next offered load should be larger or smaller, based on frame loss.</t>

<t>The usual implementation uses binary search.
Here a lossy trial becomes
a new upper bound, a lossless trial becomes a new lower bound.
The span of values between (including both) the tightest lower bound
and the tightest upper bound forms an interval of possible results,
and after each trial the width of that interval halves.</t>

<t>Usually the binary search implementation tracks only the two tightest bounds,
simply calling them bounds.
But the old values still B remain valid bounds,
just not as tight as the new ones.</t>

<t>After some number of trials, the tightest lower bound becomes the throughput.
<xref target="RFC2544"></xref> does not specify when (if ever) should the search stop.</t>

<t>MLRsearch library introduces a concept of goal width.
The search stops
when the distance between the tightest upper bound and the tightest lower bound
is smaller than a user-configured value, called goal width from now on.
In other words, the interval width at the end of the search
has to be no larger than the goal width.</t>

<t>This goal width value therefore determines the precision of the result.
As MLRsearch specification requires a particular structure of the result,
the result itself does contain enough information to determine its precision,
thus it is not required to report the goal width value.</t>

<t>This allows MLRsearch implementations to use exit conditions
different from goal width.</t>

</section>
<section anchor="load-classification"><name>Load Classification</name>

<t>MLRsearch keeps the basic logic of binary search (tracking tightest bounds,
measuring at the middle), perhaps with minor technical clarifications.
The algorithm chooses an intended load (as opposed to the offered load),
the interval between bounds does not need to be split
exactly into two equal halves,
and the final reported structure specifies both bounds.</t>

<t>The biggest difference is that to classify a load
as an upper or lower bound, MLRsearch may need more than one trial
(depending on configuration options) to be performed at the same intended load.</t>

<t>As a consequence, even if a load already does have few trial results,
it still may be classified as undecided, neither a lower bound nor an upper bound.</t>

<t>An explanation of the classification logic is given in the next chapter,
as it relies heavily on other sections of this chapter.</t>

<t>For repeatability and comparability reasons, it is important that
given a set of trial results, all implementations of MLRsearch
classify the load equivalently.</t>

</section>
<section anchor="loss-ratios"><name>Loss Ratios</name>

<t>The next difference is in the goals of the search.
<xref target="RFC2544"></xref> has a single goal,
based on classifying full-length trials as either lossless or lossy.</t>

<t>As the name suggests, MLRsearch can search for multiple goals,
differing in their loss ratios.
The precise definition of the goal loss ratio will be given later.
The <xref target="RFC2544"></xref> throughput goal then simply becomes a zero goal loss ratio.
Different goals also may have different goal widths.</t>

<t>A set of trial results for one specific intended load value
can classify the load as an upper bound for some goals, but a lower bound
for some other goals, and undecided for the rest of the goals.</t>

<t>Therefore, the load classification depends not only on trial results,
but also on the goal.
The overall search procedure becomes more complicated
(compared to binary search with a single goal),
but most of the complications do not affect the final result,
except for one phenomenon, loss inversion.</t>

</section>
<section anchor="loss-inversion"><name>Loss Inversion</name>

<t>In <xref target="RFC2544"></xref> throughput search using bisection, any load with a lossy trial
becomes a hard upper bound, meaning every subsequent trial has a smaller
intended load.</t>

<t>But in MLRsearch, a load that is classified as an upper bound for one goal
may still be a lower bound for another goal, and due to the other goal
MLRsearch will probably perform trials at even higher loads.
What to do when all such higher load trials happen to have zero loss?
Does it mean the earlier upper bound was not real?
Does it mean the later lossless trials are not considered a lower bound?
Surely we do not want to have an upper bound at a load smaller than a lower bound.</t>

<t>MLRsearch is conservative in these situations.
The upper bound is considered real, and the lossless trials at higher loads
are considered to be a coincidence, at least when computing the final result.</t>

<t>This is formalized using new notions, the relevant upper bound and
the relevant lower bound.
Load classification is still based just on the set of trial results
at a given intended load (trials at other loads are ignored),
making it possible to have a lower load classified as an upper bound,
and a higher load classified as a lower bound (for the same goal).
The relevant upper bound (for a goal) is the smallest load classified
as an upper bound.
But the relevant lower bound is not simply
the largest among lower bounds.
It is the largest load among loads
that are lower bounds while also being smaller than the relevant upper bound.</t>

<t>With these definitions, the relevant lower bound is always smaller
than the relevant upper bound (if both exist), and the two relevant bounds
are used analogously as the two tightest bounds in the binary search.
When they are less than the goal width apart,
the relevant bounds are used in the output.</t>

<t>One consequence is that every trial result can have an impact on the search result.
That means if your SUT (or your traffic generator) needs a warmup,
be sure to warm it up before starting the search.</t>

</section>
<section anchor="exceed-ratio"><name>Exceed Ratio</name>

<t>The idea of performing multiple trials at the same load comes from
a model where some trial results (those with high loss) are affected
by infrequent effects, causing poor repeatability of <xref target="RFC2544"></xref> throughput results.
See the discussion about noiseful and noiseless ends
of the SUT performance spectrum.
Stable results are closer to the noiseless end of the SUT performance spectrum,
so MLRsearch may need to allow some frequency of high-loss trials
to ignore the rare but big effects near the noiseful end.</t>

<t>MLRsearch can do such trial result filtering, but it needs
a configuration option to tell it how frequent can the infrequent big loss be.
This option is called the exceed ratio.
It tells MLRsearch what ratio of trials
(more exactly what ratio of trial seconds) can have a trial loss ratio
larger than the goal loss ratio and still be classified as a lower bound.
Zero exceed ratio means all trials have to have a trial loss ratio
equal to or smaller than the goal loss ratio.</t>

<t>For explainability reasons, the RECOMMENDED value for exceed ratio is 0.5,
as it simplifies some later concepts by relating them to the concept of median.</t>

</section>
<section anchor="duration-sum"><name>Duration Sum</name>

<t>When more than one trial is needed to classify a load,
MLRsearch also needs something that controls the number of trials needed.
Therefore, each goal also has an attribute called duration sum.</t>

<t>The meaning of a goal duration sum is that when a load has trials
(at full trial duration, details later)
whose trial durations when summed up give a value at least this long,
the load is guaranteed to be classified as an upper bound or a lower bound
for the goal.</t>

<t>As the duration sum has a big impact on the overall search duration,
and <xref target="RFC2544"></xref> prescribes wait intervals around trial traffic,
the MLRsearch algorithm is allowed to sum durations that are different
from the actual trial traffic durations.</t>

</section>
<section anchor="short-trials"><name>Short Trials</name>

<t>MLRsearch requires each goal to specify its final trial duration.
Full-length trial is a shorter name for a trial whose intended trial duration
is equal to (or longer than) the goal final trial duration.</t>

<t>Section 24 of <xref target="RFC2544"></xref> already anticipates possible time savings
when short trials (shorter than full-length trials) are used.
Full-length trials are the opposite of short trials,
so they may also be called long trials.</t>

<t>Any MLRsearch implementation may include its own configuration options
which control when and how MLRsearch chooses to use shorter trial durations.</t>

<t>For explainability reasons, when exceed ratio of 0.5 is used,
it is recommended for the goal duration sum to be an odd multiple
of the full trial durations, so conditional throughput becomes identical to
a median of a particular set of forwarding rates.</t>

<t>The presence of shorter trial results complicates the load classification logic.
Full details are given later.
In short, results from short trials
may cause a load to be classified as an upper bound.
This may cause loss inversion, and thus lower the relevant lower bound
(below what would classification say when considering full-length trials only).</t>

<t>For explainability reasons, it is RECOMMENDED users use such configurations
that guarantee all trials have the same length.
Alas, such configurations are usually not compliant with <xref target="RFC2544"></xref> requirements,
or not time-saving enough.</t>

</section>
<section anchor="conditional-throughput-1"><name>Conditional Throughput</name>

<t>As testing equipment takes the intended load as an input parameter
for a trial measurement, any load search algorithm needs to deal
with intended load values internally.</t>

<t>But in the presence of goals with a non-zero loss ratio, the intended load
usually does not match the user&#39;s intuition of what a throughput is.
The forwarding rate (as defined in <xref target="RFC2285"></xref> section 3.6.1) is better,
but it is not obvious how to generalize it
for loads with multiple trial results and a non-zero goal loss ratio.</t>

<t>MLRsearch defines one such generalization, called the conditional throughput.
It is the forwarding rate from one of the trials performed at the load
in question.
Specification of which trial exactly is quite technical,
see the specification and Appendix B.</t>

<t>Conditional throughput is partially related to load classification.
If a load is classified as a lower bound for a goal,
the conditional throughput can be calculated,
and guaranteed to show an effective loss ratio
no larger than the goal loss ratio.</t>

<t>While the conditional throughput gives more intuitive-looking values
than the relevant lower bound, especially for non-zero goal loss ratio values,
the actual definition is more complicated than the definition of the relevant
lower bound.
In the future, other intuitive values may become popular,
but they are unlikely to supersede the definition of the relevant lower bound
as the most fitting value for comparability purposes,
therefore the relevant lower bound remains a required attribute
of the goal result structure, while the conditional throughput is only optional.</t>

<t>Note that comparing the best and worst case, the same relevant lower bound value
may result in the conditional throughput differing up to the goal loss ratio.
Therefore it is rarely needed to set the goal width (if expressed
as the relative difference of loads) below the goal loss ratio.
In other words, setting the goal width below the goal loss ratio
may cause the conditional throughput for a larger loss ratio to become smaller
than a conditional throughput for a goal with a smaller goal loss ratio,
which is counter-intuitive, considering they come from the same search.
Therefore it is RECOMMENDED to set the goal width to a value no smaller
than the goal loss ratio.</t>

</section>
<section anchor="search-time"><name>Search Time</name>

<t>MLRsearch was primarily developed to reduce the time
required to determine a throughput, either the <xref target="RFC2544"></xref> compliant one,
or some generalization thereof.
The art of achieving short search times
is mainly in the smart selection of intended loads (and intended durations)
for the next trial to perform.</t>

<t>While there is an indirect impact of the load selection on the reported values,
in practice such impact tends to be small,
even for SUTs with quite a broad performance spectrum.</t>

<t>A typical example of two approaches to load selection leading to different
relevant lower bounds is when the interval is split in a very uneven way.
Any implementation choosing loads very close to the current relevant lower bound
is quite likely to eventually stumble upon a trial result
with poor performance (due to SUT noise).
For an implementation choosing loads very close
to the current relevant upper bound, this is unlikely,
as it examines more loads that can see a performance
close to the noiseless end of the SUT performance spectrum.</t>

<t>However, as even splits optimize search duration at give precision,
MLRsearch implementations that prioritize minimizing search time
are unlikely to suffer from any such bias.</t>

<t>Therefore, this document remains quite vague on load selection
and other optimization details, and configuration attributes related to them.
Assuming users prefer libraries that achieve short overall search time,
the definition of the relevant lower bound
should be strict enough to ensure result repeatability
and comparability between different implementations,
while not restricting future implementations much.</t>

<t>Sadly, different implementations may exhibit their sweet spot of
the best repeatability for a given search duration
at different goals attribute values, especially concerning
any optional goal attributes such as the initial trial duration.
Thus, this document does not comment much on which configurations
are good for comparability between different implementations.
For comparability between different SUTs using the same implementation,
refer to configurations recommended by that particular implementation.</t>

</section>
<section anchor="rfc2544-compliance"><name><xref target="RFC2544"></xref> compliance</name>

<t>The following search goal ensures unconditional compliance with
<xref target="RFC2544"></xref> throughput search procedure:</t>

<t><list style="symbols">
  <t>Goal loss ratio: zero.</t>
  <t>Goal final trial duration: 60 seconds.</t>
  <t>Goal duration sum: 60 seconds.</t>
  <t>Goal exceed ratio: zero.</t>
</list></t>

<t>The presence of other search goals does not affect the compliance
of this goal result.
The relevant lower bound and the conditional throughput are in this case
equal to each other, and the value is the <xref target="RFC2544"></xref> throughput.</t>

<t>If the 60 second quantity is replaced by a smaller quantity in both attributes,
the conditional throughput is still conditionally compliant with
<xref target="RFC2544"></xref> throughput.</t>

</section>
</section>
<section anchor="logic-of-load-classification"><name>Logic of Load Classification</name>

<t>This chapter continues with explanations,
but this time more precise definitions are needed
for readers to follow the explanations.
The definitions here are wordy, implementers should read the specification
chapter and appendices for more concise definitions.</t>

<t>The two related areas of focus in this chapter are load classification
and the conditional throughput, starting with the latter.</t>

<t>The section Performance Spectrum contains definitions
needed to gain insight into what conditional throughput means.
The rest of the subsections discuss load classification,
they do not refer to Performance Spectrum, only to a few duration sums.</t>

<t>For load classification, it is useful to define good and bad trials.
A trial is called bad (according to a goal) if its trial loss ratio
is larger than the goal loss ratio.
The trial that is not bad is called good.</t>

<section anchor="performance-spectrum"><name>Performance Spectrum</name>

<t>There are several equivalent ways to explain
the conditional throughput computation.
One of the ways relies on an object called the performance spectrum.
First, two heavy definitions are needed.</t>

<t>Take an intended load value, a trial duration value, and a finite set
of trial results, all trials measured at that load value and duration value.
The performance spectrum is the function that maps
any non-negative real number into a sum of trial durations among all trials
in the set that has that number as their forwarding rate,
e.g. map to zero if no trial has that particular forwarding rate.</t>

<t>A related function, defined if there is at least one trial in the set,
is the performance spectrum divided by the sum of the durations
of all trials in the set.
That function is called the performance probability function, as it satisfies
all the requirements for probability mass function function
of a discrete probability distribution,
the one-dimensional random variable being the trial forwarding rate.</t>

<t>These functions are related to the SUT performance spectrum,
as sampled by the trials in the set.</t>

<t>As for any other probability function, we can talk about percentiles
of the performance probability function, including the median.
The conditional throughput will be one such quantile value
for a specifically chosen set of trials.</t>

<t>Take a set of all full-length trials performed at the relevant lower bound,
sorted by decreasing forwarding rate.
The sum of the durations of those trials
may be less than the goal duration sum, or not.
If it is less, add an imaginary trial result with zero forwarding rate,
such that the new sum of durations is equal to the goal duration sum.
This is the set of trials to use.
The q-value for the quantile
is the goal exceed ratio.
If the quantile touches two trials,
the larger forwarding rate (from the trial result sorted earlier) is used.
The resulting quantity is the conditional throughput of the goal in question.</t>

<t>First example.
For zero exceed ratio, when goal duration sum has been reached.
The conditional throughput is the smallest forwarding rate among the trials.</t>

<t>Second example.
For zero exceed ratio, when goal duration sum has not been reached yet.
Due to the missing duration sum, the worst case may still happen,
so the conditional throughput is zero.
This is not reported to the user,
as this load cannot become the relevant lower bound yet.</t>

<t>Third example.
Exceed ratio 50%, goal duration sum two seconds,
one trial present with the duration of one second and zero loss.
The imaginary trial is added with the duration
of one second and zero forwarding rate.
The median would touch both trials, so the conditional throughput
is the forwarding rate of the one non-imaginary trial.
As that had zero loss, the value is equal to the offered load.</t>

<t>Note that Appendix B does not take into account short trial results.</t>

<section anchor="summary"><name>Summary</name>

<t>While the conditional throughput is a generalization of the forwarding rate,
its definition is not an obvious one.</t>

<t>Other than the forwarding rate, the other source of intuition
is the quantile in general, and the median the the recommended case.</t>

<t>In future, different quantities may prove more useful,
especially when applying to specific problems,
but currently the conditional throughput is the recommended compromise,
especially for repeatability and comparability reasons.</t>

</section>
</section>
<section anchor="single-trial-duration"><name>Single Trial Duration</name>

<t>When goal attributes are chosen in such a way that every trial has the same
intended duration, the load classification is simpler.</t>

<t>The following description looks technical, but it follows the motivation
of goal loss ratio, goal exceed ratio, and goal duration sum.
If the sum of the durations of all trials (at the given load)
is less than the goal duration sum, imagine best case scenario
(all subsequent trials having zero loss) and worst case scenario
(all subsequent trials having 100% loss).
Here we assume there are as many subsequent trials as needed
to make the sum of all trials equal to the goal duration sum.
As the exceed ratio is defined just using sums of durations
(number of trials does not matter), it does not matter whether
the &quot;subsequent trials&quot; can consist of an integer number of full-length trials.</t>

<t>In any of the two scenarios, we can compute the load exceed ratio,
As the duration sum of good trials divided by the duration sum of all trials,
in both cases including the assumed trials.</t>

<t>If even in the best case scenario the load exceed ratio would be larger
than the goal exceed ratio, the load is an upper bound.
If even in the worst case scenario the load exceed ratio would not be larger
than the goal exceed ratio, the load is a lower bound.</t>

<t>Even more specifically.
Take all trials measured at a given load.
The sum of the durations of all bad full-length trials is called the bad sum.
The sum of the durations of all good full-length trials is called the good sum.
The result of adding the bad sum plus the good sum is called the measured sum.
The larger of the measured sum and the goal duration sum is called the whole sum.
The whole sum minus the measured sum is called the missing sum.
The optimistic exceed ratio is the bad sum divided by the whole sum.
The pessimistic exceed ratio is the bad sum plus the missing sum,
that divided by the whole sum.
If the optimistic exceed ratio is larger than the goal exceed ratio,
the load is classified as an upper bound.
If the pessimistic exceed ratio is not larger than the goal exceed ratio,
the load is classified as a lower bound.
Else, the load is classified as undecided.</t>

<t>The definition of pessimistic exceed ratio is compatible with the logic in
the conditional throughput computation, so in this single trial duration case,
a load is a lower bound if and only if the conditional throughput
effective loss ratio is not larger than the goal loss ratio.
If it is larger, the load is either an upper bound or undecided.</t>

</section>
<section anchor="short-trial-scenarios"><name>Short Trial Scenarios</name>

<t>Trials with intended duration smaller than the goal final trial duration
are called short trials.
The motivation for load classification logic in the presence of short trials
is based around a counter-factual case: What would the trial result be
if a short trial has been measured as a full-length trial instead?</t>

<t>There are three main scenarios where human intuition guides
the intended behavior of load classification.</t>

<t>False good scenario.
The user had their reason for not configuring a shorter goal
final trial duration.
Perhaps SUT has buffers that may get full at longer
trial durations.
Perhaps SUT shows periodic decreases in performance
the user does not want to be treated as noise.
In any case, many good short trials may become bad full-length trials
in the counter-factual case.
In extreme cases, there are plenty of good short trials and no bad short trials.
In this scenario, we want the load classification NOT to classify the load
as a lower bound, despite the abundance of good short trials.
Effectively, we want the good short trials to be ignored, so they
do not contribute to comparisons with the goal duration sum.</t>

<t>True bad scenario.
When there is a frame loss in a short trial,
the counter-factual full-length trial is expected to lose at least as many
frames.
And in practice, bad short trials are rarely turning into
good full-length trials.
In extreme cases, there are no good short trials.
In this scenario, we want the load classification
to classify the load as an upper bound just based on the abundance
of short bad trials.
Effectively, we want the bad short trials
to contribute to comparisons with the goal duration sum,
so the load can be classified sooner.</t>

<t>Balanced scenario.
Some SUTs are quite indifferent to trial duration.
Performance probability function constructed from short trial results
is likely to be similar to the performance probability function constructed
from full-length trial results (perhaps with larger dispersion,
but without a big impact on the median quantiles overall).
For a moderate goal exceed ratio value, this may mean there are both
good short trials and bad short trials.
This scenario is there just to invalidate a simple heuristic
of always ignoring good short trials and never ignoring bad short trials.
That simple heuristic would be too biased.
Yes, the short bad trials
are likely to turn into full-length bad trials in the counter-factual case,
but there is no information on what would the good short trials turn into.
The only way to decide safely is to do more trials at full length,
the same as in scenario one.</t>

</section>
<section anchor="short-trial-logic"><name>Short Trial Logic</name>

<t>MLRsearch picks a particular logic for load classification
in the presence of short trials, but it is still RECOMMENDED
to use configurations that imply no short trials,
so the possible inefficiencies in that logic
do not affect the result, and the result has better explainability.</t>

<t>With that said, the logic differs from the single trial duration case
only in different definition of the bad sum.
The good sum is still the sum across all good full-length trials.</t>

<t>Few more notions are needed for defining the new bad sum.
The sum of durations of all bad full-length trials is called the bad long sum.
The sum of durations of all bad short trials is called the bad short sum.
The sum of durations of all good short trials is called the good short sum.
One minus the goal exceed ratio is called the inceed ratio.
The goal exceed ratio divided by the inceed ratio is called the exceed coefficient.
The good short sum multiplied by the exceed coefficient is called the balancing sum.
The bad short sum minus the balancing sum is called the excess sum.
If the excess sum is negative, the bad sum is equal to the bad long sum.
Otherwise, the bad sum is equal to the bad long sum plus the excess sum.</t>

<t>Here is how the new definition of the bad sum fares in the three scenarios,
where the load is close to what would the relevant bounds be
if only full-length trials were used for the search.</t>

<t>False good scenario.
If the duration is too short, we expect to see a higher frequency
of good short trials.
This could lead to a negative excess sum,
which has no impact, hence the load classification is given just by
full-length trials.
Thus, MLRsearch using too short trials has no detrimental effect
on result comparability in this scenario.
But also using short trials does not help with overall search duration,
probably making it worse.</t>

<t>True bad cenario.
Settings with a small exceed ratio
have a small exceed coefficient, so the impact of the good short sum is small,
and the bad short sum is almost wholly converted into excess sum,
thus bad short trials have almost as big an impact as full-length bad trials.
The same conclusion applies to moderate exceed ratio values
when the good short sum is small.
Thus, short trials can cause a load to get classified as an upper bound earlier,
bringing time savings (while not affecting comparability).</t>

<t>Balanced scenario.
Here excess sum is small in absolute value, as the balancing sum
is expected to be similar to the bad short sum.
Once again, full-length trials are needed for final load classification;
but usage of short trials probably means MLRsearch needed
a shorter overall search time before selecting this load for measurement,
thus bringing time savings (while not affecting comparability).</t>

<t>Note that in presence of short trial results,
the comparibility between the load classification
and the conditional throughput is only partial.
The conditional throughput still comes from a good long trial,
but a load higher than the relevant lower bound may also compute to a good value.</t>

</section>
<section anchor="longer-trial-durations"><name>Longer Trial Durations</name>

<t>If there are trial results with an intended duration larger
than the goal trial duration, the precise definitions
in Appendix A and Appendix B treat them in exactly the same way
as trials with duration equal to the goal trial duration.</t>

<t>But in configurations with moderate (including 0.5) or small
goal exceed ratio and small goal loss ratio (especially zero),
bad trials with longer than goal durations may bias the search
towards the lower load values, as the noiseful end of the spectrum
gets a larger probability of causing the loss within the longer trials.</t>

<t>For some users, this is an acceptable price
for increased configuration flexibility
(perhaps saving time for the related goals),
so implementations SHOULD allow such configurations.
Still, users are encouraged to avoid such configurations
by making all goals use the same final trial duration,
so their results remain comparable across implementations.</t>

</section>
</section>
<section anchor="addressed-problems"><name>Addressed Problems</name>

<t>Now when MLRsearch is clearly specified and explained,
it is possible to summarize how does MLRsearch specification help with problems.</t>

<t>Here, &quot;multiple trials&quot; is a shorthand for having the goal final trial duration
significantly smaller than the goal duration sum.
This results in MLRsearch performing multiple trials at the same load,
which may not be the case with other configurations.</t>

<section anchor="long-test-duration"><name>Long Test Duration</name>

<t>As shortening the overall search duration is the main motivation
of MLRsearch library development, the library implements
multiple improvements on this front, both big and small.</t>

<t>Most of implementation details are not constrained by the MLRsearch specification,
so that future implementations may keep shortening the search duration even more.</t>

<t>One exception is the impact of short trial results on the relevant lower bound.
While motivated by human intuition, the logic is not straightforward.
In practice, configurations with only one common trial duration value
are capable of achieving good overal search time and result repeatability
without the need to consider short trials.</t>

<section anchor="impact-of-goal-attribute-values"><name>Impact of goal attribute values</name>

<t>From the required goal attributes, the goal duration sum
remains the best way to get even shorter searches.</t>

<t>Usage of multiple trials can also save time,
depending on wait times around trial traffic.</t>

<t>The farther the goal exceed ratio is from 0.5 (towards zero or one),
the less predictable the overal search duration becomes in practice.</t>

<t>Width parameter does not change search duration much in practice
(compared to other, mainly optional goal attributes).</t>

</section>
</section>
<section anchor="dut-in-sut-1"><name>DUT in SUT</name>

<t>In practice, using multiple trials and moderate exceed ratios
often improves result repeatability without increasing the overall search time,
depending on the specific SUT and DUT characteristics.
Benefits for separating SUT noise are less clear though,
as it is not easy to distinguish SUT noise from DUT instability in general.</t>

<t>Conditional throughput has an intuitive meaning when described
using the performance spectrum, so this is an improvement
over existing simple (less configurable) search procedures.</t>

<t>Multiple trials can save time also when the noisy end of
the preformance spectrum needs to be examined, e.g. for <xref target="RFC9004"></xref>.</t>

<t>Under some circumstances, testing the same DUT and SUT setup with different
DUT configurations can give some hints on what part of noise is SUT noise
and what part is DUT performance fluctuations.
In practice, both types of noise tend to be too complicated for that analysis.</t>

<t>MLRsearch enables users to search for multiple goals,
potentially providing more insight at the cost of a longer overall search time.
However, for a thorough and reliable examination of DUT-SUT interactions,
it is necessary to employ additional methods beyond black-box benchmarking,
such as collecting and analyzing DUT and SUT telemetry.</t>

</section>
<section anchor="repeatability-and-comparability-1"><name>Repeatability and Comparability</name>

<t>Multiple trials improve repeatability, depending on exceed ratio.</t>

<t>In practice, one-second goal final trial duration with exceed ratio 0.5
is good enough for modern SUTs.
However, unless smaller wait times around the traffic part of the trial
are allowed, too much of overal search time would be wasted on waiting.</t>

<t>It is not clear whether exceed ratios higher than 0.5 are better
for repeatability.
The 0.5 value is still preferred due to explainability using median.</t>

<t>It is possible that the conditional throughput values (with non-zero goal
loss ratio) are better for repeatability than the relevant lower bound values.
This is especially for implementations
which pick load from a small set of discrete values,
as that hides small variances in relevant lower bound values
other implementations may find.</t>

<t>Implementations focusing on shortening the overall search time
are automatically forced to avoid comparability issues due to load selection,
as they must prefer even splits wherever possible.
But this conclusion only holds when the same goals are used.
Larger adoption is needed before any further claims on comparability
between MLRsearch implementations can be made.</t>

</section>
<section anchor="throughput-with-non-zero-loss-1"><name>Throughput with Non-Zero Loss</name>

<t>Trivially suported by the goal loss ratio attribute.</t>

<t>In practice, usage of non-zero loss ratio values
improves the result repeatability
(exactly as expected based on results from simpler search methods).</t>

</section>
<section anchor="inconsistent-trial-results-1"><name>Inconsistent Trial Results</name>

<t>MLRsearch is conservative wherever possible.
This is built into the definition of conditional throughput,
and into the treatment of short trial results for load classification.</t>

<t>This is consistent with <xref target="RFC2544"></xref> zero loss tolerance motivation.</t>

<t>If the noiseless part of the SUT performance spectrum is of interest,
it should be enough to set small value for the goal final trial duration,
and perhaps also a large value for the goal exceed ratio.</t>

<t>Implementations may offer other (optional) configuration attributes
to become less conservative, but currently it is not clear
what impact would that have on repeatability.</t>

</section>
</section>
<section anchor="iana-considerations"><name>IANA Considerations</name>

<t>No requests of IANA.</t>

</section>
<section anchor="security-considerations"><name>Security Considerations</name>

<t>Benchmarking activities as described in this memo are limited to
technology characterization of a DUT/SUT using controlled stimuli in a
laboratory environment, with dedicated address space and the constraints
specified in the sections above.</t>

<t>The benchmarking network topology will be an independent test setup and
MUST NOT be connected to devices that may forward the test traffic into
a production network or misroute traffic to the test management network.</t>

<t>Further, benchmarking is performed on a &quot;black-box&quot; basis, relying
solely on measurements observable external to the DUT/SUT.</t>

<t>Special capabilities SHOULD NOT exist in the DUT/SUT specifically for
benchmarking purposes. Any implications for network security arising
from the DUT/SUT SHOULD be identical in the lab and in production
networks.</t>

</section>
<section anchor="acknowledgements"><name>Acknowledgements</name>

<t>Some phrases and statements in this document were created
with help of Mistral AI (mistral.ai).</t>

<t>Many thanks to Alec Hothan of the OPNFV NFVbench project for thorough
review and numerous useful comments and suggestions.</t>

<t>Special wholehearted gratitude and thanks to the late Al Morton for his
thorough reviews filled with very specific feedback and constructive
guidelines. Thank you Al for the close collaboration over the years,
for your continuous unwavering encouragement full of empathy and
positive attitude.
Al, you are dearly missed.</t>

</section>
<section anchor="appendix-a-load-classification"><name>Appendix A: Load Classification</name>

<t>This is the specification of how to perform the load classification.</t>

<t>Any intended load value can be classified, according to the given search goal.</t>

<t>The algorithm uses (some subsets of) the set of all available trial results
from trials measured at a given intended load at the end of the search.
All durations are those returned by the measurer.</t>

<t>The block at the end of this appendix holds pseudocode
which computes two values, stored in variables named optimistic and pessimistic.
The pseudocode happens to be a valid Python code.</t>

<t>If both values are computed to be true, the load in question
is classified as a lower bound according to the given search goal.
If both values are false, the load is classified as an upper bound.
Otherwise, the load is classified as undecided.</t>

<t>The pseudocode expects the following variables to hold values as follows:</t>

<t><list style="symbols">
  <t>goal_duration_sum: The duration sum value of the given search goal.</t>
  <t>goal_exceed_ratio: The exceed ratio value of the given search goal.</t>
  <t>good_long_sum: Sum of durations across trials with trial duration
at least equal to the goal final trial duration and with a trial loss ratio
not higher than the goal loss ratio.</t>
  <t>bad_long_sum: Sum of durations across trials with trial duration
at least equal to the goal final trial duration and with a trial loss ratio
higher than the goal loss ratio.</t>
  <t>good_short_sum: Sum of durations across trials with trial duration
shorter than the goal final trial duration and with a trial loss ratio
not higher than the goal loss ratio.</t>
  <t>bad_short_sum: Sum of durations across trials with trial duration
shorter than the goal final trial duration and with a trial loss ratio
higher than the goal loss ratio.</t>
</list></t>

<t>The code works correctly also when there are no trial results at the given load.</t>

<figure><sourcecode type="python"><![CDATA[
balancing_sum = good_short_sum * goal_exceed_ratio / (1.0 - goal_exceed_ratio)
effective_bad_sum = bad_long_sum + max(0.0, bad_short_sum - balancing_sum)
effective_whole_sum = max(good_long_sum + effective_bad_sum, goal_duration_sum)
quantile_duration_sum = effective_whole_sum * goal_exceed_ratio
optimistic = effective_bad_sum <= quantile_duration_sum
pessimistic = (effective_whole_sum - good_long_sum) <= quantile_duration_sum
]]></sourcecode></figure>

</section>
<section anchor="appendix-b-conditional-throughput"><name>Appendix B: Conditional Throughput</name>

<t>This is the specification of how to compute conditional throughput.</t>

<t>Any intended load value can be used as the basis for the following computation,
but only the relevant lower bound (at the end of the search)
leads to the value called the conditional throughput for a given search goal.</t>

<t>The algorithm uses (some subsets of) the set of all available trial results
from trials measured at a given intended load at the end of the search.
All durations are those returned by the measurer.</t>

<t>The block at the end of this appendix holds pseudocode
which computes a value stored as variable conditional_throughput.
The pseudocode happens to be a valid Python code.</t>

<t>The pseudocode expects the following variables to hold values as follows:</t>

<t><list style="symbols">
  <t>goal_duration_sum: The duration sum value of the given search goal.</t>
  <t>goal_exceed_ratio: The exceed ratio value of the given search goal.</t>
  <t>good_long_sum: Sum of durations across trials with trial duration
at least equal to the goal final trial duration and with a trial loss ratio
not higher than the goal loss ratio.</t>
  <t>bad_long_sum: Sum of durations across trials with trial duration
at least equal to the goal final trial duration and with a trial loss ratio
higher than the goal loss ratio.</t>
  <t>long_trials: An iterable of all trial results from trials with trial duration
at least equal to the goal final trial duration,
sorted by increasing the trial loss ratio.
A trial result is a composite with the following two attributes available:  <list style="symbols">
      <t>trial.loss_ratio: The trial loss ratio as measured for this trial.</t>
      <t>trial.duration: The trial duration of this trial.</t>
    </list></t>
</list></t>

<t>The code works correctly only when there if there is at least one
trial result measured at a given load.</t>

<figure><sourcecode type="python"><![CDATA[
all_long_sum = max(goal_duration_sum, good_long_sum + bad_long_sum)
remaining = all_long_sum * (1.0 - goal_exceed_ratio)
quantile_loss_ratio = None
for trial in long_trials:
    if quantile_loss_ratio is None or remaining > 0.0:
        quantile_loss_ratio = trial.loss_ratio
        remaining -= trial.duration
    else:
        break
else:
    if remaining > 0.0:
        quantile_loss_ratio = 1.0
conditional_throughput = intended_load * (1.0 - quantile_loss_ratio)
]]></sourcecode></figure>

</section>


  </middle>

  <back>


    <references title='Normative References' anchor="sec-normative-references">

&RFC1242;
&RFC2285;
&RFC2544;
&RFC9004;


    </references>

    <references title='Informative References' anchor="sec-informative-references">

<reference anchor="TST009" target="https://www.etsi.org/deliver/etsi_gs/NFV-TST/001_099/009/03.04.01_60/gs_NFV-TST009v030401p.pdf">
  <front>
    <title>TST 009</title>
    <author >
      <organization></organization>
    </author>
    <date year="n.d."/>
  </front>
</reference>
<reference anchor="FDio-CSIT-MLRsearch" target="https://csit.fd.io/cdocs/methodology/measurements/data_plane_throughput/mlr_search/">
  <front>
    <title>FD.io CSIT Test Methodology - MLRsearch</title>
    <author >
      <organization></organization>
    </author>
    <date year="2023" month="October"/>
  </front>
</reference>
<reference anchor="PyPI-MLRsearch" target="https://pypi.org/project/MLRsearch/1.2.1/">
  <front>
    <title>MLRsearch 1.2.1, Python Package Index</title>
    <author >
      <organization></organization>
    </author>
    <date year="2023" month="October"/>
  </front>
</reference>


    </references>



  </back>

<!-- ##markdown-source:
H4sIAAAAAAAAA+19bZPjRnLmd/wKhDYc6vaxOa2X3dsd355vpBnZE9abNa1V
+C4cCpAEm/CQABcAu6f34vzbL/PJzKqsAsgZ7W7c+YMd4dhREyjUS1a+Ppl5
c3NTFGMz7uvn5Ten/dgc93X5dTcM5Q/V2HTlm7rq17uiWq36+oEe+fqHQf6y
6dZtdaC3Nn21HW+aetzerA6P9zeHfS+P3Nz+pthUIz3y6e2nn9/cfnZz+3lR
NMf+eTn2p2H89Pb2d7efFlVfV8/L7jgUj/fPyy/qdr07VP3bpr0vf+rkf/+h
707H4u3j8/J1O9Z9W483L/mrxboan5dNu+2KYt1t6NHn5Wm4qYZ10xTH5nlJ
//ercl219Ne6rPq+eiqvmm1Z7fflUz1cl11f7qphV+7qvi7KcuzWz/kH+ufQ
9WNfb4fnGGJTbyvanIGesN+fDvIz/2dRncZd1z8vSvzfjf5vSVOjJ75Zlv/U
tcNYteNT2z026z+F32UHv6nWTf327ENdT8v6shnWdBpPw1gfhvBTfaia/fPy
8FZe/R9rfmq57g7zM/nDsvy+21dvs+//oa/Gt1320/u/+tAf+Q330aLt+gOR
zUPNW/HDV19+8unnn+o/P/30t7+2f/7688/1n7+7vaV/FnyE7s27N3dEG7Kd
Y9Xf13TKu3E8Ds+fPXt8fFzW49AsaYLPNvWeXumf8R9+vh+effvVH27o5We3
t5/8fPu739H/0v9/trz9fEl/+M3ts/vhZ32Efnm4/ez289tPjsvjZiufkmvw
Ef1c0u8f0R+/etl0N1++eX13Eyh/flrroRmX282y6Z6t6WoMzw41kcSm23f3
T/Tvajj19aFux+EZXYnq5+O+auufxx0R9v3ueBqf0a35WcZ/lszlq5c0ZMkz
KO/qYSy/icOWN/E6foSXwm377OaTW/rL90/fv37fxI9PR9nLY9/9W70en4Xn
n32y/HT5STqd8GOJHxf0CZpPW35frd9W9zXdz039bm4yxc3NTVmthrGv1mNR
3O2aoaR9OvGelPTpYzfUQ1m/G+t2aIia+ab9L6WVfy3jRpX6+dVTQZeyaZk9
VGVbP5Zuw+nK7/f1ZpahKfu6Ciu5XsZtLKvmgE8faORD86faPrc59fx2uyiG
0/FIvKE82Nh7Hrt3Y9fDoqjaTVm3u6pd12VfD/Qs/c+xpqNfNftmfCr5Aboy
x6rXvyx5U2raioa43xM9XQ20r3QtZFOYubkNaTDLarOhwemf9OJ6x2tu74kd
8dh9/cdToyRHg9YD/YN2ZPWEh+uHan/CgjCRkSiLxi+6LfG97fhILPlmVQ30
PLHaR2XCg3CBj/lgqxIEPPCku/Ke7iBz2H4oD11fl9u+rjfdYeH2lU74odnQ
CdOUG/5utaflt9vmXjeWBAD/z0D7y8cwMI8mNkjfDRs9EIsl7k/Co6n2tCj6
576rNszaxpr+l2bftXQeTODy0KIYu33NHwCVrOt+rJqW31zTdjC90jt4Ug9p
KB+bkcRBc7/D6IMepR46D8Pbp4viwwmzu+94Unj9gQ6QH42UwRvFF+DQbDb7
uij+9/PndPh8OP8Hd+UFvYktLP+prw6b7rHl46UNIuY20n52BxIS/Vv+YYEX
9OmRr9EjSTVahwlNHXgo227kUVZ1+dAMzYrmSGvn6fdETiTwNiK6lxjQ2AGJ
kfXbjj67pe1npv6sevb5p599+tlnv7vFg69JfNLIvD9EbQ1tOE2B5rJZhPnS
R21iz987+Ke3v/3tr3/321vak2dhT4pfld+feuYJoM836+5Y6/3QP/PBJTxE
bgSR2LpvaMkfdvUXRBWRnGfYjGcqTKHMEzY4eLsohbsiL3+845N+cTzuQQAP
Vdvs99U8I1s1A7FbJn2at42GIQojRjqvoabtIvqkC0QneBhIWN6UXzQt8wid
41i9rXnxHREc0znfQpIUek140A3fi23VCyXR2dGp0LjteKJb9kTLOTETCFNb
0ifuQCfgIbTehu+rXBTjhDiYY3Vitr2iLajrVj9Jg9NsMRemtg4L2OeclD/y
xq+a7/cjEW0zPKV3kil+Txcct4+YHu0ccSPiaXLniRyEujeshzyAsN02M6dj
RsVLCn/UldHuyCWlYep3JJhoM/5U9x3tEylGw6Jc0bO8hqbdkMLaP9FMtvwu
bR09ChY1CDUceIn8eNu1NxiDB7YP16UIK+F0Wz+/Ri7qmlbYl48728XAkHh7
mpau1tAQm2vpcMBzPes32ij5ItAXaAOqFe0EsT/6NTLhfbPqmW7qw3HfPcm7
2874rIor8A5Q2Qv+5Sz7zbgun4lM3Pgy85Wb8rujcPv906JUZkx3+hex4GWY
i6yDJ5uwXl0eOPBCXt80223dT5gwz+hFm9IX7IOKHl+PZV3ROG44voEkkds1
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
WJDY4uz2UcjJuplLERdr9hoP8Mtl7nnPOYXl6ciufejrXd+zo04/gl2ti/Ps
K0oDhqfXrZcJDmv/xmPtM9wzAmAMiyCCqte7FvCJjSMah++wBMv2nnatxh5X
UL2b9QlACPYIRzFdbfiwQdBncP+s2nWp1sle033VhjiFB0+JH3SoLXKsaxhE
BMZvvGB9i1bDkSmP56/c3xMUA+OXBEDrMFrPcd9IYSHTpLfzaceeEUD9IiCT
VT72omBt8utWJ6gvnnvqa1VubdIwmSK0Qr5wTYR6hus+hZRZzCliOe6AX4rP
RGuBaIVVNk1dxnQ1nxbMjPGjCmcP54ldpm3W9cp8bfUW/Q/fEl1IlY4BYkOE
BZtuqt9uEv9fFFyfsdZsdAK2wa8DAKXWdfisuAEGCzgL74bOL1iX1GesgYYw
q2hTql+Ltr0dCveFzYSdK02GDLBExKRfChqqCnRGkTq1JFkILex03HX7DTbf
O/4FP8PR1ePkoM7cq0JccTJ1h8YVk0giLEgjY4VdTQja4utl8dqya1jzgvkO
NEBIfva4MJVBYFaszyAGywpMsTkRza5hWxgAtOsF5Abeydts8DhDv/KKXJoi
PcizHoSSXydJP6Jg/fDqy++++ebVty9fvYTMdPippg9hi8Kh3HBBdCmC4xo0
fwigE14I/cXEBp9e9tlvfnxz58Ke7VN0bGpkh4g5PEDaZbJdW90ushfgHap6
SVHtK04QYJhG0PP4QLBdc7cjAov1Sn4Z2JJmLoT/1gywwd8OJqeUTgcW7ApF
91asWBzma8LckEyhYS1exHLyRb6mQ0rbmQ+ZjmRdNw+pL0WtV2wigO88zrJ4
AaWzfteMDp/PYKZ6zFlycn2z/NzU5IjvfEyXuhNS1kToJkSappsV0ukKh6qo
fVZb0OUs0KdpF7kJO6jkc7NvWlJoVEQwxfbhxOPxkpnHDy3zd8nu+YCXv5On
jI+LYJucH9IyJSXS1VZQMSgGq/j2g5a/l9IUg0oEfXJeIMTUyyGiQvQGqJI3
0qW9Uq6QyAcJCCNt/XqRiQEVxnEdheZqql2fJistmS8jShyp1W9nWKRQKhsn
rCiE/cvWCTkd+PseSY/l2rD6Ei0J9wjevyODETU5cnS4m1AyBv+eOWJRdX5s
GToj1p/n+2DBmmt83D0NUOZUneZkNA6NirdCQZQFrlpL/+xp/y2ozlKV3dlt
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

-->

</rfc>

