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

<!DOCTYPE rfc SYSTEM "rfc2629.dtd" [
<!ENTITY RFC2544 SYSTEM "https://xml2rfc.tools.ietf.org/public/rfc/bibxml/reference.RFC.2544.xml">
]>

<?rfc toc="yes"?>
<?rfc sortrefs="yes"?>
<?rfc symrefs="yes"?>

<rfc ipr="trust200902" docName="draft-ietf-bmwg-mlrsearch-01" category="info">

  <front>
    <title>Multiple Loss Ratio Search for Packet Throughput (MLRsearch)</title>

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

    <date year="2021" month="July" day="12"/>

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

    <abstract>


<t>This document proposes changes to <xref target="RFC2544"></xref>, specifically to packet
throughput search methodology, by defining a new search algorithm
referred to as Multiple Loss Ratio search (MLRsearch for short). Instead
of relying on binary search with pre-set starting offered load, it
proposes a novel approach discovering the starting point in the initial
phase, and then searching for packet throughput based on defined packet
loss ratio (PLR) input criteria and defined final trial duration time.
One of the key design principles behind MLRsearch is minimizing the
total test duration and searching for multiple packet throughput rates
(each with a corresponding PLR) concurrently, instead of doing it
sequentially.</t>

<t>The main motivation behind MLRsearch is the new set of challenges and
requirements posed by NFV (Network Function Virtualization),
specifically software based implementations of NFV data planes. Using
<xref target="RFC2544"></xref> in the experience of the authors yields often not repetitive
and not replicable end results due to a large number of factors that are
out of scope for this draft. MLRsearch aims to address this challenge
in a simple way of getting the same result sooner, so more repetitions
can be done to describe the replicability.</t>



    </abstract>


  </front>

  <middle>


<section anchor="terminology" title="Terminology">

<t><list style="symbols">
  <t>Frame size: size of an Ethernet Layer-2 frame on the wire, including
any VLAN tags (dot1q, dot1ad) and Ethernet FCS, but excluding Ethernet
preamble and inter-frame gap. Measured in bytes (octets).</t>
  <t>Packet size: same as frame size, both terms used interchangeably.</t>
  <t>Device Under Test (DUT): In software networking, &quot;device&quot; denotes a
specific piece of software tasked with packet processing. Such device
is surrounded with other software components (such as operating system
kernel). It is not possible to run devices without also running the
other components, and hardware resources are shared between both. For
purposes of testing, the whole set of hardware and software components
is called &quot;system under test&quot; (SUT). As SUT is the part of the whole
test setup performance of which can be measured by <xref target="RFC2544"></xref> methods,
this document uses SUT instead of <xref target="RFC2544"></xref> DUT. Device under test
(DUT) can be re-introduced when analysing test results using whitebox
techniques, but this document sticks to blackbox testing.</t>
  <t>System Under Test (SUT): System under test (SUT) is a part of the
whole test setup whose performance is to be benchmarked. The complete
test setup contains other parts, whose performance is either already
established, or not affecting the benchmarking result.</t>
  <t>Bi-directional throughput tests: involve packets/frames flowing in
both transmit and receive directions over every tested interface of
SUT/DUT. Packet flow metrics are measured per direction, and can be
reported as aggregate for both directions and/or separately
for each measured direction. In most cases bi-directional tests
use the same (symmetric) load in both directions.</t>
  <t>Uni-directional throughput tests: involve packets/frames flowing in
only one direction, i.e. either transmit or receive direction, over
every tested interface of SUT/DUT. Packet flow metrics are measured
and are reported for measured direction.</t>
  <t>Packet Loss Ratio (PLR): ratio of packets received relative to packets
transmitted over the test trial duration, calculated using formula:
PLR = ( pkts_transmitted - pkts_received ) / pkts_transmitted.
For bi-directional throughput tests aggregate PLR is calculated based
on the aggregate number of packets transmitted and received.</t>
  <t>Effective loss ratio: A corrected value of measured packet loss ratio
chosen to avoid difficulties if SUT exhibits decreasing loss
with increasing load. Maximum of packet loss ratios measured at the same
duration on all loads smaller than (and including) the current one.</t>
  <t>Target loss ratio: A packet loss ratio value acting as an imput for search.
The search is finding tight enough lower and upper bound in intended load,
so that the lower bound has smaller or equal loss ratio, and upper bound
has strictly larger loss ratio. For the tighterst upper bound,
the effective loss ratio is the same as packet loss ratio.
For the tightest lower bound, the effective loss ratio can be higher
than the packet loss ratio, but still not larger than the target loss ratio.</t>
  <t>Packet Throughput Rate: maximum packet offered load DUT/SUT forwards
within the specified Packet Loss Ratio (PLR). In many cases the rate
depends on the frame size processed by DUT/SUT. Hence packet
throughput rate MUST be quoted with specific frame size as received by
DUT/SUT during the measurement. For bi-directional tests, packet
throughput rate should be reported as aggregate for both directions.
Measured in packets-per-second (pps) or frames-per-second (fps),
equivalent metrics.</t>
  <t>Bandwidth Throughput Rate: a secondary metric calculated from packet
throughput rate using formula: bw_rate = pkt_rate * (frame_size +
L1_overhead) * 8, where L1_overhead for Ethernet includes preamble (8
octets) and inter-frame gap (12 octets). For bi-directional tests,
bandwidth throughput rate should be reported as aggregate for both
directions. Expressed in bits-per-second (bps).</t>
  <t>Non Drop Rate (NDR): maximum packet/bandwith throughput rate sustained
by DUT/SUT at PLR equal zero (zero packet loss) specific to tested
frame size(s). MUST be quoted with specific packet size as received by
DUT/SUT during the measurement. Packet NDR measured in
packets-per-second (or fps), bandwidth NDR expressed in
bits-per-second (bps).</t>
  <t>Partial Drop Rate (PDR): maximum packet/bandwith throughput rate
sustained by DUT/SUT at PLR greater than zero (non-zero packet loss)
specific to tested frame size(s). MUST be quoted with specific packet
size as received by DUT/SUT during the measurement. Packet PDR
measured in packets-per-second (or fps), bandwidth PDR expressed in
bits-per-second (bps).</t>
  <t>Maximum Receive Rate (MRR): packet/bandwidth rate regardless of PLR
sustained by DUT/SUT under specified Maximum Transmit Rate (MTR)
packet load offered by traffic generator. MUST be quoted with both
specific packet size and MTR as received by DUT/SUT during the
measurement. Packet MRR measured in packets-per-second (or fps),
bandwidth MRR expressed in bits-per-second (bps).</t>
  <t>Trial: a single measurement step. See <xref target="RFC2544"></xref> section 23.</t>
  <t>Trial duration: amount of time over which packets are transmitted
in a single measurement step.</t>
</list></t>

</section>
<section anchor="mlrsearch-background" title="MLRsearch Background">

<t>Multiple Loss Ratio search (MLRsearch) is a packet throughput search
algorithm suitable for deterministic systems (as opposed to
probabilistic systems). MLRsearch discovers multiple packet throughput
rates in a single search, each rate is associated with a distinct
Packet Loss Ratio (PLR) criterion.</t>

<t>For cases when multiple rates need to be found, this property makes
MLRsearch more efficient in terms of time execution, compared to
traditional throughput search algorithms that discover a single packet
rate per defined search criteria (e.g. a binary search specified by
<xref target="RFC2544"></xref>). MLRsearch reduces execution time even further by relying on
shorter trial durations of intermediate steps, with only the final
measurements conducted at the specified final trial duration. This
results in the shorter overall search execution time when compared to a
traditional binary search, while guaranteeing the same results for
deterministic systems.</t>

<t>In practice two rates with distinct PLRs are commonly used for packet
throughput measurements of NFV systems: Non Drop Rate (NDR) with PLR=0
and Partial Drop Rate (PDR) with PLR&gt;0. The rest of this document
describes MLRsearch with NDR and PDR pair as an example.</t>

<t>Similarly to other throughput search approaches like binary search,
MLRsearch is effective for SUTs/DUTs with PLR curve that is
non-decreasing with growing offered load. It may not be as
effective for SUTs/DUTs with abnormal PLR curves, although
it will always converge to some value.</t>

<t>MLRsearch relies on traffic generator to qualify the received packet
stream as error-free, and invalidate the results if any disqualifying
errors are present e.g. out-of-sequence frames.</t>

<t>MLRsearch can be applied to both uni-directional and bi-directional
throughput tests.</t>

<t>For bi-directional tests, MLRsearch rates and ratios are aggregates of
both directions, based on the following assumptions:</t>

<t><list style="symbols">
  <t>Traffic transmitted by traffic generator and received by SUT/DUT
has the same packet rate in each direction,
in other words the offered load is symmetric.</t>
  <t>SUT/DUT packet processing capacity is the same in both directions,
resulting in the same packet loss under load.</t>
</list></t>

<t>MLRsearch can be applied even without those assumptions,
but in that case the aggregate loss ratio is less useful as a metric.</t>

<t>MLRsearch can be used for network transactions consisting of more than
just one packet, or anything else that has intended load as input
and loss ratio as output (duration as input is optional).
This text uses mostly packet-centric language.</t>

</section>
<section anchor="mlrsearch-overview" title="MLRsearch Overview">

<t>The main properties of MLRsearch:</t>

<t><list style="symbols">
  <t>MLRsearch is a duration aware multi-phase multi-rate search algorithm:
  <list style="symbols">
      <t>Initial Phase determines promising starting interval for the search.</t>
      <t>Intermediate Phases progress towards defined final search criteria.</t>
      <t>Final Phase executes measurements according to the final search
criteria.</t>
      <t>Final search criteria are defined by following inputs:
      <list style="symbols">
          <t>Target PLRs (e.g. 0.0 and 0.005 when searching for NDR and PDR).</t>
          <t>Final trial duration.</t>
          <t>Measurement resolution.</t>
        </list></t>
    </list></t>
  <t>Initial Phase:
  <list style="symbols">
      <t>Measure MRR over initial trial duration.</t>
      <t>Measured MRR is used as an input to the first intermediate phase.</t>
    </list></t>
  <t>Multiple Intermediate Phases:
  <list style="symbols">
      <t>Trial duration:
      <list style="symbols">
          <t>Start with initial trial duration in the first intermediate phase.</t>
          <t>Converge geometrically towards the final trial duration.</t>
        </list></t>
      <t>Track all previous trial measurement results:
      <list style="symbols">
          <t>Duration, offered load and loss ratio are tracked.</t>
          <t>Effective loss ratios are tracked.
          <list style="symbols">
              <t>While in practice, real loss ratios can decrease with increasing load,
effective loss ratios never decrease. This is achieved by sorting
results by load, and using the effective loss ratio of the previous load
if the current loss ratio is smaller than that.</t>
            </list></t>
          <t>The algorithm queries the results to find best lower and upper bounds.
          <list style="symbols">
              <t>Effective loss ratios are always used.</t>
            </list></t>
          <t>The phase ends if all target loss ratios have tight enough bounds.</t>
        </list></t>
      <t>Search:
      <list style="symbols">
          <t>Iterate over target loss ratios in increasing order.</t>
          <t>If both upper and lower bound are in measurement results for this duration,
apply bisect until the bounds are tight enough,
and continue with next loss ratio.</t>
          <t>If a bound is missing for this duration, but there exists a bound
from the previous duration (compatible with the other bound
at this duration), re-measure at the current duration.</t>
          <t>If a bound in one direction (upper or lower) is missing for this duration,
and the previous duration does not have a compatible bound,
compute the current &quot;interval size&quot; from the second tightest bound
in the other direction (lower or upper respectively)
for the current duration, and choose next offered load for external search.</t>
          <t>The logic guarantees that a measurement is never repeated with both
duration and offered load being the same.</t>
          <t>The logic guarantees that measurements for higher target loss ratio
iterations (still within the same phase duration) do not affect validity
and tightness of bounds for previous target loss ratio iterations
(at the same duration).</t>
        </list></t>
      <t>Use of internal and external searches:
      <list style="symbols">
          <t>External search:
          <list style="symbols">
              <t>It is a variant of &quot;exponential search&quot;.</t>
              <t>The &quot;interval size&quot; is multiplied by a configurable constant
(powers of two work well with the subsequent internal search).</t>
            </list></t>
          <t>Internal search:
          <list style="symbols">
              <t>A variant of binary search that measures at offered load between
the previously found bounds.</t>
              <t>The interval does not need to be split into exact halves,
if other split can get to the target width goal faster.
              <list style="symbols">
                  <t>The idea is to avoid returning interval narrower than the current
width goal. See sample implementation details, below.</t>
                </list></t>
            </list></t>
        </list></t>
    </list></t>
  <t>Final Phase:
  <list style="symbols">
      <t>Executed with the final test trial duration, and the final width
goal that determines resolution of the overall search.</t>
    </list></t>
  <t>Intermediate Phases together with the Final Phase are called
Non-Initial Phases.</t>
  <t>The returned bounds stay within prescribed min_rate and max_rate.
  <list style="symbols">
      <t>When returning min_rate or max_rate, the returned bounds may be invalid.
      <list style="symbols">
          <t>E.g. upper bound at max_rate may come from a measurement
with loss ratio still not higher than the target loss ratio.</t>
        </list></t>
    </list></t>
</list></t>

<t>The main benefits of MLRsearch vs. binary search include:</t>

<t><list style="symbols">
  <t>In general MLRsearch is likely to execute more trials overall, but
likely less trials at a set final trial duration.</t>
  <t>In well behaving cases, e.g. when results do not depend on trial
duration, it greatly reduces (&gt;50%) the overall duration compared to a
single PDR (or NDR) binary search over duration, while finding
multiple drop rates.</t>
  <t>In all cases MLRsearch yields the same or similar results to binary
search.</t>
  <t>Note: both binary search and MLRsearch are susceptible to reporting
non-repeatable results across multiple runs for very bad behaving
cases.</t>
</list></t>

<t>Caveats:</t>

<t><list style="symbols">
  <t>Worst case MLRsearch can take longer than a binary search, e.g. in case of
drastic changes in behaviour for trials at varying durations.
  <list style="symbols">
      <t>Re-measurement at higher duration can trigger a long external search.
That never happens in binary search, which uses the final duration
from the start.</t>
    </list></t>
</list></t>

</section>
<section anchor="sample-implementation" title="Sample Implementation">

<t>Following is a brief description of a sample MLRsearch implementation,
which is a simplified version of the existing implementation.</t>

<section anchor="input-parameters" title="Input Parameters">

<t><list style="numbers">
  <t><spanx style="strong">max_rate</spanx> - Maximum Transmit Rate (MTR) of packets to
be used by external traffic generator implementing MLRsearch,
limited by the actual Ethernet link(s) rate, NIC model or traffic
generator capabilities.</t>
  <t><spanx style="strong">min_rate</spanx> - minimum packet transmit rate to be used for
measurements. MLRsearch fails if lower transmit rate needs to be
used to meet search criteria.</t>
  <t><spanx style="strong">final_trial_duration</spanx> - required trial duration for final rate
measurements.</t>
  <t><spanx style="strong">initial_trial_duration</spanx> - trial duration for initial MLRsearch phase.</t>
  <t><spanx style="strong">final_relative_width</spanx> - required measurement resolution expressed as
(lower_bound, upper_bound) interval width relative to upper_bound.</t>
  <t><spanx style="strong">packet_loss_ratios</spanx> - list of maximum acceptable PLR search criteria.</t>
  <t><spanx style="strong">number_of_intermediate_phases</spanx> - number of phases between the initial
phase and the final phase. Impacts the overall MLRsearch duration.
Less phases are required for well behaving cases, more phases
may be needed to reduce the overall search duration for worse behaving cases.</t>
</list></t>

</section>
<section anchor="initial-phase" title="Initial Phase">

<t><list style="numbers">
  <t>First trial measures at configured maximum transmit rate (MTR) and
discovers maximum receive rate (MRR).
  <list style="symbols">
      <t>IN: trial_duration = initial_trial_duration.</t>
      <t>IN: offered_transmit_rate = maximum_transmit_rate.</t>
      <t>DO: single trial.</t>
      <t>OUT: measured loss ratio.</t>
      <t>OUT: MRR = measured receive rate.
Received rate is computed as intended load multiplied by pass ratio
(which is one minus loss ratio). This is useful when loss ratio is computed
from a different metric than intended load. For example, intended load
can be in transactions (multiple packets each), but loss ratio is computed
on level of packets, not transactions.</t>
      <t>Example: If MTR is 10 transactions per second, and each transaction has
10 packets, and receive rate is 90 packets per second, then loss rate
is 10%, and MRR is computed to be 9 transactions per second.</t>
    </list>
If MRR is too close to MTR, MRR is set below MTR so that interval width
is equal to the width goal of the first intermediate phase.
If MRR is less than min_rate, min_rate is used.</t>
  <t>Second trial measures at MRR and discovers MRR2.
  <list style="symbols">
      <t>IN: trial_duration = initial_trial_duration.</t>
      <t>IN: offered_transmit_rate = MRR.</t>
      <t>DO: single trial.</t>
      <t>OUT: measured loss ratio.</t>
      <t>OUT: MRR2 = measured receive rate.
If MRR2 is less than min_rate, min_rate is used.
If loss ratio is less or equal to the smallest target loss ratio,
MRR2 is set to a value above MRR, so that interval width is equal
to the width goal of the first intermediate phase.
MRR2 could end up being equal to MTR (for example if both measurements so far
had zero loss), which was already measured, step 3 is skipped in that case.</t>
    </list></t>
  <t>Third trial measures at MRR2.
  <list style="symbols">
      <t>IN: trial_duration = initial_trial_duration.</t>
      <t>IN: offered_transmit_rate = MRR2.</t>
      <t>DO: single trial.</t>
      <t>OUT: measured loss ratio.</t>
      <t>OUT: MRR3 = measured receive rate.
If MRR3 is less than min_rate, min_rate is used.
If step 3 is not skipped, the first trial measurement is forgotten.
This is done because in practice (if MRR2 is above MRR), external search
from MRR and MRR2 is likely to lead to a faster intermediate phase
than a bisect between MRR2 and MTR.</t>
    </list></t>
</list></t>

</section>
<section anchor="non-initial-phases" title="Non-Initial Phases">

<t><list style="numbers">
  <t>Main phase loop:
  <list style="numbers">
      <t>IN: trial_duration for the current phase. Set to
initial_trial_duration for the first intermediate phase; to
final_trial_duration for the final phase; or to the element of
interpolating geometric sequence for other intermediate phases.
For example with two intermediate phases, trial_duration of the
second intermediate phase is the geometric average of
initial_trial_duration and final_trial_duration.</t>
      <t>IN: relative_width_goal for the current phase. Set to
final_relative_width for the final phase; doubled for each
preceding phase. For example with two intermediate phases, the
first intermediate phase uses quadruple of final_relative_width
and the second intermediate phase uses double of
final_relative_width.</t>
      <t>IN: Measurement results from the previous phase (previous duration).</t>
      <t>Internal target ratio loop:
      <list style="numbers">
          <t>IN: Target loss ratio for this iteration of ratio loop.</t>
          <t>IN: Measurement results from all previous ratio loop iterations
of current phase (current duration).</t>
          <t>DO: According to the procedure described in point 2:
          <list style="numbers">
              <t>either exit the phase (by jumping to 1.5),</t>
              <t>or exit loop iteration (by continuing with next target loss ratio,
jumping to 1.4.1),</t>
              <t>or calculate new transmit rate to measure with.</t>
            </list></t>
          <t>DO: Perform the trial measurement at the new transmit rate and
current trial duration, compute its loss ratio.</t>
          <t>DO: Add the result and go to next iteration (1.4.1),
including the added trial result in 1.4.2.</t>
        </list></t>
      <t>OUT: Measurement results from this phase.</t>
      <t>OUT: In the final phase, bounds for each target loss ratio
are extracted and returned.
      <list style="numbers">
          <t>If a valid bound does not exist, use min_rate or max_rate.</t>
        </list></t>
    </list></t>
  <t>New transmit rate (or exit) calculation (for point 1.4.3):
  <list style="numbers">
      <t>If the previous duration has the best upper and lower bound,
select the middle point as the new transmit rate.
      <list style="numbers">
          <t>See 2.5.3. below for the exact splitting logic.</t>
          <t>This can be a no-op if interval is narrow enough already,
in that case continue with 2.2.</t>
          <t>Discussion, assuming the middle point is selected and measured:
          <list style="numbers">
              <t>Regardless of loss rate measured, the result becomes
either best upper or best lower bound at current duration.</t>
              <t>So this condition is satisfied at most once per iteration.</t>
              <t>This also explains why previous phase has double width goal:
              <list style="numbers">
                  <t>We avoid one more bisection at previous phase.</t>
                  <t>At most one bound (per iteration) is re-measured
with current duration.</t>
                  <t>Each re-measurement can trigger an external search.</t>
                  <t>Such surprising external searches are the main hurdle
in achieving low overal search durations.</t>
                  <t>Even without 1.1, there is at most one external search
per phase and target loss ratio.</t>
                  <t>But without 1.1 there can be two re-measurements,
each coming with a risk of triggering external search.</t>
                </list></t>
            </list></t>
        </list></t>
      <t>If the previous duration has one bound best, select its transmit rate.
In deterministic case this is the last measurement needed this iteration.</t>
      <t>If only upper bound exists in current duration results:
      <list style="numbers">
          <t>This can only happen for the smallest target loss ratio.</t>
          <t>If the upper bound was measured at min_rate,
exit the whole phase early (not investigating other target loss ratios).</t>
          <t>Select new transmit rate using external search:
          <list style="numbers">
              <t>For computing previous interval size, use:
              <list style="numbers">
                  <t>second tightest bound at current duration,</t>
                  <t>or tightest bound of previous duration,
if compatible and giving a more narrow interval,</t>
                  <t>or target interval width if none of the above is available.</t>
                  <t>In any case increase to target interval width if smaller.</t>
                </list></t>
              <t>Quadruple the interval width.</t>
              <t>Use min_rate if the new transmit rate is lower.</t>
            </list></t>
        </list></t>
      <t>If only lower bound exists in current duration results:
      <list style="numbers">
          <t>If the lower bound was measured at max_rate,
exit this iteration (continue with next lowest target loss ratio).</t>
          <t>Select new transmit rate using external search:
          <list style="numbers">
              <t>For computing previous interval size, use:
              <list style="numbers">
                  <t>second tightest bound at current duration,</t>
                  <t>or tightest bound of previous duration,
if compatible and giving a more narrow interval,</t>
                  <t>or target interval width if none of the above is available.</t>
                  <t>In any case increase to target interval width if smaller.</t>
                </list></t>
              <t>Quadruple the interval width.</t>
              <t>Use max_rate if the new transmit rate is higher.</t>
            </list></t>
        </list></t>
      <t>The only remaining option is both bounds in current duration results.
      <list style="numbers">
          <t>This can happen in two ways, depending on how the lower bound
was chosen.
          <list style="numbers">
              <t>It could have been selected for the current loss ratio,
e.g. in re-measurement (2.2) or in initial bisect (2.1).</t>
              <t>It could have been found as an upper bound for the previous smaller
target loss ratio, in which case it might be too low.</t>
              <t>The algorithm does not track which one is the case,
as the decision logic works well regardless.</t>
            </list></t>
          <t>Compute &quot;extending down&quot; candidate transmit rate exactly as in 2.3.</t>
          <t>Compute &quot;bisecting&quot; candidate transmit rate:
          <list style="numbers">
              <t>Compute the current interval width from the two bounds.</t>
              <t>Express the width as a (float) multiple of the target width goal
for this phase.</t>
              <t>If the multiple is not higher than one, it means the width goal
is met. Exit this iteration and continue with next higher
target loss ratio.</t>
              <t>If the multiple is two or less, use half of that
for new width if the lower subinterval.</t>
              <t>Round the multiple up to nearest even integer.</t>
              <t>Use half of that for new width if the lower subinterval.</t>
              <t>Example: If lower bound is 2.0 and upper bound is 5.0, and width
goal is 1.0, the new candidate transmit rate will be 4.0.
This can save a measurement when 4.0 has small loss.
Selecting the average (3.5) would never save a measurement,
giving more narrow bounds instead.</t>
            </list></t>
          <t>If either candidate computation want to exit the iteration,
do as bisecting candidate computation says.</t>
          <t>The remaining case is both candidates wanting to measure at some rate.
Use the higher rate. This prefers external search down narrow enough
interval, competing with perfectly sized lower bisect subinterval.</t>
        </list></t>
    </list></t>
</list></t>

</section>
</section>
<section anchor="fdio-csit-implementation" title="FD.io CSIT Implementation">

<t>The only known working implementation of MLRsearch is in
the open-source code running in Linux Foundation
FD.io CSIT project <xref target="FDio-CSIT-MLRsearch"></xref> as part of
a Continuous Integration / Continuous Development (CI/CD) framework.</t>

<t>MLRsearch is also available as a Python package in <xref target="PyPI-MLRsearch"></xref>.</t>

<section anchor="additional-details" title="Additional details">

<t>This document so far has been describing a simplified version of
MLRsearch algorithm. The full algorithm as implemented in CSIT contains
additional logic, which makes some of the details (but not general
ideas) above incorrect. Here is a short description of the additional
logic as a list of principles, explaining their main differences from
(or additions to) the simplified description, but without detailing
their mutual interaction.</t>

<t><list style="numbers">
  <t>Logarithmic transmit rate.
  <list style="symbols">
      <t>In order to better fit the relative width goal, the interval
doubling and halving is done differently.</t>
      <t>For example, the middle of 2 and 8 is 4, not 5.</t>
    </list></t>
  <t>Timeout for bad cases.
  <list style="symbols">
      <t>The worst case for MLRsearch is when each phase converges to
intervals way different than the results of the previous phase.</t>
      <t>Rather than suffer total search time several times larger than pure
binary search, the implemented tests fail themselves when the
search takes too long (given by argument <spanx style="emph">timeout</spanx>).</t>
    </list></t>
  <t>Intended count.
  <list style="symbols">
      <t>The number of packets to send during the trial should be equal to
the intended load multiplied by the duration.
      <list style="symbols">
          <t>Also multiplied by a coefficient, if loss ratio is calculated
from a different metric.
          <list style="symbols">
              <t>Example: If a successful transaction uses 10 packets,
load is given in transactions per second, byt loss ratio is calculated
from packets, the coefficient to get intended count of packets is 10.</t>
            </list></t>
        </list></t>
      <t>But in practice that does not work.
      <list style="symbols">
          <t>It could result in a fractional number of packets,</t>
          <t>so it has to be rounded in a way traffic generator chooses,</t>
          <t>which may depend on the number of traffic flows
and traffic generator worker threads.</t>
        </list></t>
    </list></t>
  <t>Attempted count. As the real number of intended packets is not known exactly,
the computation uses the number of packets traffic generator reports as sent.
Unless overriden by the next point.</t>
  <t>Duration stretching.
  <list style="symbols">
      <t>In some cases, traffic generator may get overloaded,
causing it to take significantly longer (than duration) to send all packets.</t>
      <t>The implementation uses an explicit stop,
      <list style="symbols">
          <t>causing lower attempted count in those cases.</t>
        </list></t>
      <t>The implementation tolerates some small difference between
attempted count and intended count.
      <list style="symbols">
          <t>10 microseconds worth of traffic is sufficient for our tests.</t>
        </list></t>
      <t>If the difference is higher, the unsent packets are counted as lost.
      <list style="symbols">
          <t>This forces the search to avoid the regions of high duration stretching.</t>
          <t>The final bounds describe the performance of not just SUT,
but of the whole system, including the traffic generator.</t>
        </list></t>
    </list></t>
  <t>Excess packets.
  <list style="symbols">
      <t>In some test (e.g. using TCP flows) Traffic generator reacts to packet loss
by retransmission. Usually, such packet loss is already affecting loss ratio.
If a test also wants to treat retransmissions due to heavily delayed packets
also as a failure, this is once again visible as a mismatch between
the intended count and the attempted count.</t>
      <t>The CSIT implementation simply looks at absolute value of the difference,
so it offes the same small tolerance before it start marking a &quot;loss&quot;.</t>
    </list></t>
  <t>For result processing, we use lower bounds and ignore upper bounds.</t>
</list></t>

<section anchor="fdio-csit-input-parameters" title="FD.io CSIT Input Parameters">

<t><list style="numbers">
  <t><spanx style="strong">max_rate</spanx> - Typical values: 2 * 14.88 Mpps for 64B
10GE link rate, 2 * 18.75 Mpps for 64B 40GE NIC (specific model).</t>
  <t><spanx style="strong">min_rate</spanx> - Value: 2 * 9001 pps (we reserve 9000 pps
for latency measurements).</t>
  <t><spanx style="strong">final_trial_duration</spanx> - Value: 30.0 seconds.</t>
  <t><spanx style="strong">initial_trial_duration</spanx> - Value: 1.0 second.</t>
  <t><spanx style="strong">final_relative_width</spanx> - Value: 0.005 (0.5%).</t>
  <t><spanx style="strong">packet_loss_ratios</spanx> - Value: 0.0, 0.005 (0.0% for NDR, 0.5% for PDR).</t>
  <t><spanx style="strong">number_of_intermediate_phases</spanx> - Value: 2.
The value has been chosen based on limited experimentation to date.
More experimentation needed to arrive to clearer guidelines.</t>
  <t><spanx style="strong">timeout</spanx> - Limit for the overall search duration (for one search).
If MLRsearch oversteps this limit, it immediatelly declares the test failed,
to avoid wasting even more time on a misbehaving SUT.
Value: 600.0 (seconds).</t>
  <t><spanx style="strong">expansion_coefficient</spanx> - Width multiplier for external search.
Value: 4.0 (interval width is quadroupled).
Value of 2.0 is best for well-behaved SUTs, but value of 4.0 has been found
to decrease overall search time for worse-behaved SUT configurations,
contributing more to the overall set of different SUT configurations tested.</t>
</list></t>

</section>
</section>
<section anchor="example-mlrsearch-run" title="Example MLRsearch Run">

<t>The following list describes a search from a real test run in CSIT
(using the default input values as above).</t>

<t><list style="symbols">
  <t>Initial phase, trial duration 1.0 second.</t>
</list></t>

<t>Measurement 1, intended load 18750000.0 pps (MTR),
measured loss ratio 0.7089514628479618 (valid upper bound for both NDR and PDR).</t>

<t>Measurement 2, intended load 5457160.071600716 pps (MRR),
measured loss ratio 0.018650817320118702 (new tightest upper bounds).</t>

<t>Measurement 3, intended load 5348832.933500009 pps (slightly less than MRR2
in preparation for first intermediate phase target interval width),
measured loss ratio 0.00964383362905351 (new tightest upper bounds).</t>

<t><list style="symbols">
  <t>First intermediate phase starts, trial duration still 1.0 seconds.</t>
</list></t>

<t>Measurement 4, intended load 4936605.579021453 pps (no lower bound,
performing external search downwards, for NDR),
measured loss ratio 0.0 (valid lower bound for both NDR and PDR).</t>

<t>Measurement 5, intended load 5138587.208637197 pps (bisecting for NDR),
measured loss ratio 0.0 (new tightest lower bounds).</t>

<t>Measurement 6, intended load 5242656.244044665 pps (bisecting),
measured loss ratio 0.013523745379347257 (new tightest upper bounds).</t>

<t><list style="symbols">
  <t>Both intervals are narrow enough.</t>
  <t>Second intermediate phase starts, trial duration 5.477225575051661 seconds.</t>
</list></t>

<t>Measurement 7, intended load 5190360.904111567 pps (initial bisect for NDR),
measured loss ratio 0.0023533920869969953 (NDR upper bound, PDR lower bound).</t>

<t>Measurement 8, intended load 5138587.208637197 pps (re-measuring NDR lower bound),
measured loss ratio 1.2080222912800403e-06 (new tightest NDR upper bound).</t>

<t><list style="symbols">
  <t>The two intervals have separate bounds from now on.</t>
</list></t>

<t>Measurement 9, intended load 4936605.381062318 pps (external NDR search down),
measured loss ratio 0.0 (new valid NDR lower bound).</t>

<t>Measurement 10, intended load 5036583.888432355 pps (NDR bisect),
measured loss ratio 0.0 (new tightest NDR lower bound).</t>

<t>Measurement 11, intended load 5087329.903232804 pps (NDR bisect),
measured loss ratio 0.0 (new tightest NDR lower bound).</t>

<t><list style="symbols">
  <t>NDR interval is narrow enough, PDR interval not ready yet.</t>
</list></t>

<t>Measurement 12, intended load 5242656.244044665 pps (re-measuring PDR upper bound),
measured loss ratio 0.0101174866190136 (still valid PDR upper bound).</t>

<t><list style="symbols">
  <t>Also PDR interval is narrow enough, with valid bounds for this duration.</t>
  <t>Final phase starts, trial duration 30.0 seconds.</t>
</list></t>

<t>Measurement 13, intended load 5112894.3238511775 pps (initial bisect for NDR),
measured loss ratio 0.0 (new tightest NDR lower bound).</t>

<t>Measurement 14, intended load 5138587.208637197 (re-measuring NDR upper bound),
measured loss ratio 2.030389804256833e-06 (still valid PDR upper bound).</t>

<t><list style="symbols">
  <t>NDR interval is narrow enough, PDR interval not yet.</t>
</list></t>

<t>Measurement 15, intended load 5216443.04126728 pps (initial bisect for PDR),
measured loss ratio 0.005620871287975237 (new tightest PDR upper bound).</t>

<t>Measurement 16, intended load 5190360.904111567 (re-measuring PDR lower bound),
measured loss ratio 0.0027629971184465604 (still valid PDR lower bound).</t>

<t><list style="symbols">
  <t>PDR interval is also narrow enough.</t>
  <t>Returning bounds:</t>
  <t>NDR_LOWER = 5112894.3238511775 pps; NDR_UPPER = 5138587.208637197 pps;</t>
  <t>PDR_LOWER = 5190360.904111567 pps; PDR_UPPER = 5216443.04126728 pps.</t>
</list></t>

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

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

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

<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" title="Acknowledgements">

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

</section>


  </middle>

  <back>

    <references title='Normative References'>

&RFC2544;


    </references>

    <references title='Informative References'>

<reference anchor="FDio-CSIT-MLRsearch" target="https://docs.fd.io/csit/rls2101/report/introduction/methodology_data_plane_throughput/methodology_mlrsearch_tests.html">
  <front>
    <title>FD.io CSIT Test Methodology - MLRsearch</title>
    <author >
      <organization></organization>
    </author>
    <date year="2021" month="February"/>
  </front>
</reference>
<reference anchor="PyPI-MLRsearch" target="https://pypi.org/project/MLRsearch/0.4.0/">
  <front>
    <title>MLRsearch 0.4.0, Python Package Index</title>
    <author >
      <organization></organization>
    </author>
    <date year="2021" month="April"/>
  </front>
</reference>


    </references>



  </back>

<!-- ##markdown-source:
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

-->

</rfc>

