<?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.6.17 (Ruby 2.7.4) -->


<!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-03" 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="2022" month="November" day="09"/>

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

    <abstract>


<t>This document proposes improvements to <xref target="RFC2544"></xref> throughput search by
defining a new methodology called Multiple Loss Ratio search
(MLRsearch). The main objectives for MLRsearch are to minimize the
total test duration, search for multiple loss ratios and improve
results repeatibility and comparability.</t>

<t>The main motivation behind MLRsearch is the new set of challenges and
requirements posed by testing Network Function Virtualization
(NFV) systems and other software based network data planes.</t>

<t>MLRsearch offers several ways to address these challenges, giving user
configuration options to select their way.</t>



    </abstract>



  </front>

  <middle>



<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 throughput search methodology optimized for software
DUTs.</t>

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

<t><list style="symbols">
  <t>Binary search takes too long as most of trials are done far from the
eventually found throughput.</t>
  <t>The required final trial duration and pauses between trials also
prolong the overall search duration.</t>
  <t>Software DUTs show noisy trial results (noisy neighbor problem),
leading to big spread of possible discovered throughput values.</t>
  <t>Throughput requires loss of exactly zero packets, 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>MLRsearch aims to address these problems by applying the following set
of enhancements:</t>

<t><list style="symbols">
  <t>Allow searching with multiple loss ratio goals.
  <list style="symbols">
      <t>Each trial result can affect any search goal in principle
(trial reuse).</t>
    </list></t>
  <t>Multiple phases within one loss ratio goal search, middle ones need
to spend less time on trials.
  <list style="symbols">
      <t>Middle phases also aim at lesser precision.</t>
      <t>Use Forwarding Rate (FR) at maximum offered load
<xref target="RFC2285"></xref> (section 3.6.2) to initialize the first middle phase.</t>
    </list></t>
  <t>Take care when dealing with inconsistent trial results.
  <list style="symbols">
      <t>Loss ratios goals are handled in an order that precludes any
interference from later trials to earlier goals.</t>
    </list></t>
  <t>Apply several load selection heuristics to save even more time
by trying hard to avoid unnecessarily narrow intervals.</t>
</list></t>

<t>MLRsearch configuration options are flexible enough to
support both conservative settings (unconditionally compliant with <xref target="RFC2544"></xref>,
but longer search duration and worse repeatability) and aggressive
settings (shorter search duration and better repeatability but 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="problems"><name>Problems</name>

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

<t>Emergence of software DUTs, with frequent software updates and a
number of different packet processing modes and configurations, drives
the requirement of continuous test execution and bringing down the test
execution time.</t>

<t>In the context of characterising particular DUT&#39;s network performance, this
calls for improving the time efficiency of throughput search.
A vanilla bisection (at 60sec trial duration for unconditional <xref target="RFC2544"></xref>
compliance) is slow, because most trials spend time quite far from the
eventual throughput.</t>

<t><xref target="RFC2544"></xref> does not specify any stopping condition for throughput search,
so users can trade-off between search duration and precision goal.
But, due to exponential behavior of bisection, small improvement
in search duration needs relatively big sacrifice in the result precision.</t>

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

<t><xref target="RFC2285"></xref> defines:
- <em>DUT</em> as
  - The network forwarding device to which stimulus is offered and
    response measured <xref target="RFC2285"></xref> (section 3.1.1).
- <em>SUT</em> 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 case of software networking, the SUT consists of a software program
processing packets (device of interest, the DUT),
running on a server hardware and using operating system functions as appropriate,
with server hardware resources shared across all programs
and the operating system.</t>

<t>DUT is effectively &quot;nested&quot; within SUT.</t>

<t>Due to a shared multi-tenant nature of SUT, DUT is subject to
interference (noise) coming from the operating system and any other
software running on the same server. Some sources of noise can be
eliminated (e.g. by pinning DUT program threads to specific CPU cores
and isolating those cores to avoid context switching). But some
noise remains after all such reasonable precautions are applied. This
noise does negatively affect DUT&#39;s network performance. We refer to it
as an <em>SUT noise</em>.</t>

<t>DUT can also exhibit fluctuating performance itself, e.g. while performing
some &quot;stop the world&quot; 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. We use <em>noise</em> as a shorthand covering both <em>DUT fluctuations</em> and
genuine SUT noise.</t>

<t>A simple model of SUT performance consists of a baseline <em>noiseless performance</em>,
and an additional noise. The baseline is assumed to be constant (enough).
The noise varies in time, sometimes wildly. The noise can sometimes be negligible,
but frequently it lowers the observed SUT performance in a trial.</t>

<t>In this model, SUT does not have a single performance value, it has a spectrum.
One end of the spectrum is the noiseless baseline,
the other end is a <em>noiseful performance</em>. In practice, trial results
close to the noiseful end of the spectrum happen only rarely.
The worse performance, the more rarely it is seen.</t>

<t>Focusing on DUT, the benchmarking effort should aim
at eliminating only the SUT noise from SUT measurement.
But that is not really possible, as there are no realistic enough models
able to distinguish SUT noise from DUT fluctuations.</t>

<t>However, assuming that a well-constructed SUT has the DUT as its
performance bottleneck, the &quot;DUT noiseless performance&quot; can be defined
as the noiseless end of SUT performance spectrum. (At least for
throughput. For other quantities such as latency there will be an
additive difference.) By this definition, DUT noiseless performance
also minimizes the impact of DUT fluctuations.</t>

<t>In this document, we reduce the &quot;DUT within SUT&quot; problem to estimating
the noiseless end of SUT performance spectrum from a limited number of
trial results.</t>

<t>Any improvements to throughput search algorithm, aimed for better
dealing with software networking SUT and DUT setup, should employ
strategies recognizing the presence of SUT noise, and allow 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
throughput value, it cannot be determined how repeatable that value is.
In practice, poor repeatability is also the main cause of poor
comparability, e.g. different benchmarking teams can test the same DUT
but get different throughput values.</t>

<t><xref target="RFC2544"></xref> throughput requirements (60s trial, no tolerance to single frame loss)
force the search to converge around the noiseful end of SUT performance
spectrum. As that end is affected by rare trials of significantly low
performance, the resulting throughput repeatability is poor.</t>

<t>The repeatability problem is the problem of defining a search procedure
which reports more stable results
(even if they can no longer be called &quot;throughput&quot; in <xref target="RFC2544"></xref> sense).
According to baseline (noiseless) and noiseful model, better repeatability
will be at the noiseless end of the spectrum.
Therefore, solutions to the &quot;DUT within SUT&quot; 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 &quot;important&quot; tests, but it makes the search duration problem even
bigger.</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>and 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>Contrary to that, many benchmarking teams settle with non-zero
(small) loss ratio as the goal for a &quot;throughput rate&quot;.</t>

<t>Motivations are many: modern protocols tolerate frame loss better;
trials nowadays send way more frames within the same duration;
impact of rare noise bursts is smaller as the baseline performance
can compensate somewhat by keeping the loss ratio below the goal;
if SUT noise with &quot;ideal DUT&quot; is known, it can be set as the loss ratio goal.</t>

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

<t>Searching for multiple loss ratio goals also helps to describe the SUT
performance better than a single goal result. Repeated wide gap between
zero and non-zero loss loads indicates the noise has a large impact on
the overall SUT performance.</t>

<t>It is easy to modify the vanilla bisection to find a lower bound
for intended load that satisfies a non-zero-loss goal,
but it is not that obvious how to search for multiple goals at once,
hence the support for multiple loss 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 possibility if inconsistent trial results in two places.
The first place is section 24 where full trial durations are required, presumably
because they can be inconsistent with 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 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 packet loss ratio.</t>
  <t>a trial at higher load (same or different trial duration) results
in a smaller packet loss ratio.</t>
</list></t>

<t>Any robust throughput search algorithm needs to decide how to continue
the search in 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 quantity which both generalizes
throughput for non-zero-loss (and other possible repeatibility enhancements),
while being precise enough to force a specific way to resolve trial
inconsistencies.
But until such definition is agreed upon, the correct way to handle
inconsistent trial results remains an open problem.</t>

</section>
</section>
<section anchor="mlrsearch-approach"><name>MLRsearch Approach</name>

<t>The following description intentionally leaves out some important implementation
details. This is both to hide complexity that is not important for overall
understanding, and to allow future improvements in the implementation.</t>

<section anchor="terminology"><name>Terminology</name>

<t><list style="symbols">
  <t><em>trial duration</em>: Amount of time over which frames are transmitted
towards SUT and DUT in a single measurement step.
  <list style="symbols">
      <t><strong>MLRsearch input parameter</strong> for final MLRsearch measurements.</t>
    </list></t>
  <t><em>loss ratio</em>: Ratio of the count of frames lost to the count of frames
transmitted over a trial duration, a.k.a. packet loss ratio. Related
to packet loss rate <xref target="RFC1242"></xref> (section 3.6).
In MLRsearch loss ratio can mean either a trial result or a goal:
  <list style="symbols">
      <t><em>trial loss ratio</em>: Loss ratio measured during a trial.</t>
      <t><em>loss ratio goal</em>: <strong>MLRsearch input parameter</strong>.
      <list style="symbols">
          <t>If <em>trial loss ratio</em> is smaller or equal to this,
the trial <strong>satisfies</strong> the loss ratio goal.</t>
        </list></t>
    </list></t>
  <t><em>load</em>: Constant offered load stimulating the SUT and DUT. Consistent
with offered load <xref target="RFC2285"></xref> (section 3.5.2).
  <list style="symbols">
      <t>MLRsearch works with intended load instead, as it cannot deal with
situations where the offered load is considerably different than
intended load.</t>
    </list></t>
  <t><em>throughput</em>: The maximum load at which none of the offered frames are
dropped by the SUT and DUT. Consistent with <xref target="RFC1242"></xref> (section 3.17).</t>
  <t><em>conditional throughput</em>: The forwarding rate measured at the maximum
load at which a list of specified conditions are met i.e. loss ratio
goal and trial duration.
  <list style="symbols">
      <t>Throughput is then a special case of conditional throughput
for zero loss ratio goal and long enough trial duration.</t>
      <t>Conditional throughput is aligned with forwarding rate (FR)
<xref target="RFC2285"></xref> (section 3.6.1), adding trial duration to offered load
required when reporting FR.</t>
    </list></t>
  <t><em>lower bound</em>: One of values tracked by MLRsearch during the search runtime.
It is specific to the current trial duration and current loss ratio goal.
It represents a load value with at least one trial result available.
If the trial satisfies the current loss ratio goal,
it is a <em>valid</em> bound (else <em>invalid</em>).</t>
  <t><em>upper bound</em>: One of values tracked by MLRsearch during the search runtime.
It is specific to the current trial duration and current loss ratio goal.
It represents a load value with at least one trial result available.
If the trial satisfies the current loss ratio goal,
it is an <em>invalid</em> bound (else <em>valid</em>).</t>
  <t><em>interval</em>: The span between lower and upper bound loads.</t>
  <t><em>precision goal</em>: <strong>MLRsearch input parameter</strong>, acting as a search
stop condition, given as either absolute or relative width goal. An
interval meets precision goal if:
  <list style="symbols">
      <t>The difference of upper and lower bound loads (in pps)
is not more than the absolute width goal.</t>
      <t>The difference as above, divided by upper bound load (in pps)
is not more than the relative width goal.</t>
    </list></t>
</list></t>

</section>
<section anchor="description"><name>Description</name>

<t>The MLRsearch approach to address the identified problems is based
on the following main strategies:</t>

<t><list style="symbols">
  <t>MLRsearch main inputs include the following search goals and parameters:
  <list style="symbols">
      <t>One or more <strong>loss ratio goals</strong>.
      <list style="symbols">
          <t>e.g. a zero-loss goal and one (or more) non-zero-loss goals.</t>
        </list></t>
      <t><strong>Target trial duration</strong> condition governing required trial duration
for final measurements.</t>
      <t><strong>Target precision</strong> condition governing how close final lower and
upper bound load values must be to each other for final
measurements.</t>
    </list></t>
  <t>Search is executed as a sequence of phases:
  <list style="symbols">
      <t><em>Initial phase</em> initializes bounds for the first middle phase.</t>
      <t><em>Middle phase</em>s narrow down the bounds, using shorter trial
durations and lower precision goals. Several middle phases can
precede each final phase.</t>
      <t><em>Final phase</em> (one per loss ratio goal) finds bounds matching input
goals and parameters to serve as the overal search output.</t>
    </list></t>
  <t>Each search phase produces its <em>ending</em> upper bound and lower bound:
  <list style="symbols">
      <t>Initial phase may produce invalid bounds.</t>
      <t>Middle and final phases produce valid bounds.</t>
      <t>Middle or final phases needs at least two values to act as 
<em>starting</em> bounds (may be invalid).</t>
      <t>Each phase may perform several trial measurements, until phase&#39;s
ending conditions are all met.</t>
      <t>Trial results from previous phases may be re-used.</t>
    </list></t>
  <t>Initial phase establishes the starting values for bounds, using
forwarding rates (FR) <xref target="RFC2285"></xref> (section 3.6.1)
from a few trials of minimal duration, as follows:
  <list style="symbols">
      <t>1st trial is done at <em>maximum offered load (MOL)</em> <xref target="RFC2285"></xref> (section 3.5.3),
resulting in Forwarding rate at maximum offered load (FRMOL)
<xref target="RFC2285"></xref> (section 3.6.2).</t>
      <t>2nd trial is done at <em>FRMOL</em>, resulting in forwarding rate at FRMOL (FRFRMOL),
newly defined here.</t>
      <t>3rd trial is done at <em>FRFRMOL</em>, so its results are available for the next phase.</t>
      <t>By default, FRMOL is used as an upper bound, FRFRMOL as a lower bound.
      <list style="symbols">
          <t>Adjustments may apply here for some cases e.g. when 2nd trial got
zero loss or if FRFRMOL is too close to FRMOL.</t>
        </list></t>
    </list></t>
  <t>Middle phases are producing ending bounds by improving upon starting bounds:
  <list style="symbols">
      <t>Each middle phase uses the same loss ratio goal as the final phase it precedes.
      <list style="symbols">
          <t>Called <em>current loss ratio goal</em> for upper and lower bound purposes.</t>
        </list></t>
      <t>Each middle phase has its own <em>current trial duration</em>
and <em>current precision goal</em> parameters, computed from
MLRsearch input parameters.
As phases progress, these parameters approach MLRsearch main input values.
      <list style="symbols">
          <t>Current trial duration starts from a configurable minimum (e.g. 1 sec)
and increases in a geometric sequence.</t>
          <t>Current precision goal always allows twice as wide intervals
as the following phase.</t>
        </list></t>
      <t>The starting bounds are usually the ending bounds from the preceding phase.
      <list style="symbols">
          <t>Unless there are many previous trial results that are more promising.</t>
        </list></t>
      <t>Each middle phase operates in a sequence of four actions:
      <list style="numbers">
          <t>Perform trial at the load between the starting bounds.
  - Depending on the trial result this becomes the first
 new valid upper or lower bound for current phase.</t>
          <t>Re-measure at the remaining starting lower or upper (respectively) bound.</t>
          <t>If that did not result in a valid bound, start an <em>external search</em>.
  - That is a variant of exponential search.
          <list style="symbols">
              <t>The &quot;growth&quot; is given by input parameter <em>expansion_coefficient</em>.
      - This action ends when a new valid bound is found.</t>
              <t>Or if an already existing valid bound becomes close enough.</t>
            </list></t>
          <t>Repeatedly bisect the current interval until the bounds are close enough.</t>
        </list></t>
    </list></t>
  <t>Final search phase operates in exactly the same way as middle phases.
There are two reasons why it is named differently:
  <list style="symbols">
      <t>The current trial duration and current precision goal within the phase
are equal to the target trial duration and target precision input parameters.</t>
      <t>The forwarding rates of the ending bounds become the output of MLRsearch.
      <list style="symbols">
          <t>Specifically, the forwarding rates of the final lower bounds
are the conditional throughput values per given loss ratio goals.</t>
        </list></t>
    </list></t>
</list></t>

</section>
<section anchor="enhancement-multiple-trials-per-load"><name>Enhancement: Multiple trials per load</name>

<t>An enhancement of MLRsearch is to introduce a <em>noise tolerance</em> input parameter.
The idea is to perform several medium-length trials (instead of a single long trial)
and tolerate a configurable fraction of them to not-satisfy the loss ratio goal.</t>

<t>MLRsearch implementation with this enhancement exists in FD.io CSIT project
and test results of VPP and DPDK (testpmd, l3fwd) DUTs look promising.</t>

<t>This enhancement would make the description of MLRsearch approach
considerably more complicated, so this document version only describes
MLRsearch without this enhancement.</t>

</section>
</section>
<section anchor="how-the-problems-are-addressed"><name>How the problems are addressed</name>

<t>Configurable loss ratio goals are in direct support for non-zero-loss conditional througput.
In practice the conditional throughput results&#39; stability
increases with higher loss ratio goals.</t>

<t>Multiple trials with noise tolerance enhancement will also indirectly
increase result stability and it will allow MLRsearch
to add all the benefits of Binary Search with Loss Verification,
as recommended in <xref target="RFC9004"></xref> (section 6.2)
and specified in <xref target="TST009"></xref> (section 12.3.3).</t>

<t>The main factor improving the overall search time is the introduction
of middle phases. The full implementation can bring a large number of
heuristics related to how exactly should the next trial load be chosen,
but the impact of those is not as big.</t>

<t>The Description subsection lacks any details on how to handle inconsistent
trial results. In practice, there tend to be a three-way trade-off
between i) short overall search time, ii) result stability
and iii) how simple the definition of the returned conditional throughput can be.
The third one is important for comparability between different MLRsearch
implementations.</t>

</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>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'>

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


    </references>

    <references title='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://s3-docs.fd.io/csit/rls2110/report/introduction/methodology_data_plane_throughput/methodology_data_plane_throughput.html#mlrsearch-tests">
  <front>
    <title>FD.io CSIT Test Methodology - MLRsearch</title>
    <author >
      <organization></organization>
    </author>
    <date year="2021" month="November"/>
  </front>
</reference>
<reference anchor="PyPI-MLRsearch" target="https://pypi.org/project/MLRsearch/0.3.0/">
  <front>
    <title>MLRsearch 0.3.0, Python Package Index</title>
    <author >
      <organization></organization>
    </author>
    <date year="2021" month="April"/>
  </front>
</reference>


    </references>



  </back>

<!-- ##markdown-source:
H4sIAAAAAAAAA+1cbXPjNpL+zl+B8n5YWyXJHs9sLvF+OWcmczu1eZmKnWzV
bW2lIBGSsKZILUHao1zdf79+uhsgSMuT3H2+rbuKRySARqNfnn4BF4tF0fmu
cjfmu77q/KFy5tsmBPOj7Xxj7pxt17vCrlate6RXvv0xyC9ls67tnkaVrd10
C++6zWK1f9ou9lUrryyuXhel7eiV66vr68WrV4urr4rCH9ob07V96K6vrr66
ui5s6+yNaQ6heNremK9dvd7tbfvg6635WyP//Y+26Q/Fw9ON+VB3rq1dt3iH
VYu17W6MrzdNUaybkl69MX1Y2LD2vjj4G0P/+4NZ25p+dca2rT2ac78xtqrM
0YUL07RmZ8PO7FzrCmO6Zn2DB/RnaNqudZtww1OUbmOJOYHeiM+Pe3mMfxa2
73ZNe1MY/t9C/2uINHrju6X5a1OHztbdsW6e/PrX9Fw4+J1de/fw4ktNS9t6
68OaTuMYOrcP6ZHbW1/dmP2DDP33Nd5arpv9aUp+XpqPTWUfJuv/3NruoZk8
+u1VH9sDRmSLFnXT7klsHh1Y8eP7t6+u31zrn9fXX/4p/vmnN2/0z6+urujP
AkeYjby/uyfZEHZ2tt06OuVd1x3CzeXl09PT0nXBL4nAy9JVNKS9xA+/bMPl
9+9/XtDgy6urV79cffUV/Zf+//Xy6s2Sfvji6nIbftFX6Mnj1eurN1evDstD
uZGlRA3O6LGh52f04/t3vlm8vftwv0iSf5qs8HpBGhGWm3Lpm8t18N1lW4Xr
V6+uLlt3IGG69HXXNmW/Jq2qL/eOBKZsqmZ7/IV0xP5yqGztful2JOnb3aHv
fvuN5a7bV38YtK1zoQujfbx/R7QYUG/u6aH5bpjSLAZVPuNBSVNfkabSLx+P
Hz/81qYPx4Ocw6Ft/unW3WV6//JqSWy/HJGTHhp+OKcliJ7afLTrB7t1pNul
+/SMmKs3RbFYLIxdha61664o7nc+GGJ2v3d1Z2jpQxNcMH5Pfz46/Mh6+neV
tH+YgWdGCVgdC1JpX8O4WFO7J5OxmwxGVbnypDlU43ee9nKxNPc7Z0gjatOs
wAQSyGBInAcGk+VxoGhPC+79r/T3zhVd09nK4NBM2beYvJ5H8jB6H1evsDq/
EIyty7jPonWBTRKJl6OnK1/57shvkCoebGvllyUYpgTuG6KOlzIrt/P06kAj
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
8T/WzhNQ1lgAAA==

-->

</rfc>

