<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>Measuring the Performance Impact of Branching Instructions</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Lukas Beierlieb</string-name>
          <xref ref-type="aff" rid="aff2">2</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Lukas Ifländer Samuel Kounev</string-name>
          <email>samuel.kounev@uni-wuerzburg.de</email>
          <xref ref-type="aff" rid="aff2">2</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          ,
          <addr-line>Thomas Prantl</addr-line>
        </aff>
        <aff id="aff1">
          <label>1</label>
          <institution>Cybereason</institution>
          ,
          <addr-line>Theresienhöhe 28, München, 80339</addr-line>
          ,
          <country country="DE">Germany</country>
        </aff>
        <aff id="aff2">
          <label>2</label>
          <institution>University of Würzburg</institution>
          ,
          <addr-line>Am Hubland, Würzburg, 97074</addr-line>
          ,
          <country country="DE">Germany</country>
        </aff>
      </contrib-group>
      <abstract>
        <p>With the continuing rise of cloud technology, hypervisors play a vital role in the performance and reliability of current services. Hypervisors implement interfaces providing call-based connectivity to hosted virtualization-aware virtual machines. One of them is the hypercall interface, allowing hypervisor service requests from virtual machines. A hypercall injection tool measuring hypercall execution times must minimize internal overhead. Among other things, limiting logging to strictly required information is crucial. However, checks for values to log for every injection requires executing many branch instructions. We assess the performance diference between using and avoiding such branching, measured by the hypercall throughput of the injector tool.</p>
      </abstract>
      <kwd-group>
        <kwd>eol&gt;measurement</kwd>
        <kwd>performance</kwd>
        <kwd>branching</kwd>
      </kwd-group>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>1. Introduction</title>
      <p>
        Today, hypervisors are virtually omnipresent. They are widespread throughout data centers,
functioning as the backbone of cloud computing [
        <xref ref-type="bibr" rid="ref1">1</xref>
        ] by allowing for server consolidation with
huge benefits in eficiency and flexibility. Hypervisors are also prevalent in modern desktop and
workstation infrastructures [
        <xref ref-type="bibr" rid="ref2">2</xref>
        ]. This extends to Microsoft shipping their Hyper-V hypervisor
directly with many versions of the Windows Operating System (OS), and in some cases, even
activating it by default [
        <xref ref-type="bibr" rid="ref3">3</xref>
        ].
      </p>
      <p>Virtualization allows to create virtual instances of physical devices called Virtual Machines
(VMs). In a virtualized environment, governed by a hypervisor, VMs share resources.
Hypervisors implement interfaces providing call-based connectivity to virtualization-aware hosted
VMs. One of them is the hypercall interface, allowing for VMs to request services from the
hypervisor. Hypercalls are software traps from a VM to the hypervisor. Before introducing x86
hardware virtualization in 2006, hypercalls were one solution to run virtualized OSs. Nowadays,
while technically not required, hypercalls are still a common utility to improve eficiency or
ofer additional features.</p>
      <p>
        The crucial role that hypervisor play in today’s infrastructure requires robustness and high
performance, among other properties. We proposed a framework to help testing these
qualities [
        <xref ref-type="bibr" rid="ref4">4</xref>
        ]. On the one hand, the framework supports the logging of values and execution times if
required, on the other, it should be able to inject calls at a high rate, due to low overhead. In
this paper, we investigate whether or not there is a performance penalty to evaluating multiple
if statements for optional logging.
      </p>
      <p>
        Other works concentrate on reducing the cost of branches if that cannot be removed [
        <xref ref-type="bibr" rid="ref5 ref6 ref7">5, 6, 7</xref>
        ].
      </p>
      <p>The remainder of this paper is structured as follows: Section 2 presents background
knowledge about virtualization, Hyper-V, hypercalls, and branching in processors. Next, Section 3
introduces the measurement approach and environmental conditions during its realization;
Section 4 then presents and discusses the measurements. Finally, Section 5 concludes the paper.</p>
    </sec>
    <sec id="sec-2">
      <title>2. Background</title>
      <p>In a non-virtualized scenario, an OS manages physical hardware (i.e., processor, memory, and
IO devices) and provides and schedules physical resource accesses for applications running on
top. Virtualization describes the concept of introducing an abstraction layer above the hardware.
That layer, called the hypervisor or Virtual Machine Monitor (VMM), provides a set of virtual
resources, which can form multiple virtual machines managed by independent OSs.</p>
      <p>
        One way to classify hypervisors is by whether directly control the hardware or run on top of
an OS [
        <xref ref-type="bibr" rid="ref8">8</xref>
        ]. The former approach is called a Type-1 or bare-metal hypervisor and can utilize its
full control for increased performance. Type-2 or hosted hypervisors, on the other hand, can
reduce their complexity by relying on the OS to take care of most of the hardware management.
      </p>
      <p>
        Para-virtualization applies changes to the source code of OSs themselves. These
modifications allow the hypervisor and VMs to interact more eficiently, e.g., by using abstract IO
interfaces instead of emulating existing, physical devices, reducing overhead and improving
performance [
        <xref ref-type="bibr" rid="ref9">9</xref>
        ].
      </p>
      <p>
        Hyper-V is an x86_64 hypervisor developed by Microsoft [
        <xref ref-type="bibr" rid="ref10">10</xref>
        ]. It is a Type-1 hypervisor.
Thus, it directly controls the hardware. However, to avoid limiting it to specific hardware
configurations or bloat the code base with countless device drivers, Hyper-V uses a
microkernelbased architecture. A specialized VM called the root partition always runs an instance of
Windows on top of Hyper-V to provide management features and device drivers. Guest VMs (also
called guest partitions) can run para-virtualized if they support it but also can use unmodified
OSs, in which case Hyper-V provides emulated devices.
      </p>
      <p>
        Hyper-V ofers various interfaces for VM-Hypervisor and VM-VM communication [
        <xref ref-type="bibr" rid="ref11">11</xref>
        ]:
Privileged register and memory accesses, emulation of privileged instructions, IO ports,
interVM communication via the VMBUS, and hypercalls. Similar to applications requesting services
from the OS by issuing system calls, guest OSs can call into the hypervisor with hypercalls.
      </p>
      <p>Hypercalls are triggered by special processor instructions that transfers execution control
from VM to hypervisor. Hyper-V expects a call code present in a specified register beforehand.
Also, parameters for the call can be placed in registers and memory, depending on the calling
convention. After processing a hypercall, Hyper-V returns a result value, which indicates either
a successful execution or an error code (e.g., missing privilege, out of memory).</p>
      <p>
        Apart from virtualization terms, some background knowledge about CPU execution is
required to understand the goal of this paper. Modern processors try to execute as many
instructions as possible at a time. Branching instructions are problematic because the processor does
not know which instructions follow until the branch is fully executed. CPUs deploy branch
prediction to guess and speculatively execute further instructions, which helps to keep the
performance penalty down for well predictable branches [
        <xref ref-type="bibr" rid="ref6">6</xref>
        ].
      </p>
    </sec>
    <sec id="sec-3">
      <title>3. Methodology</title>
      <p>The hypercall injector consists of three parts. There has to be a description of the hypercall
workload, called the campaign file. It consists of binary data, describing which hypercalls with
which parameters should be executed, and also if any delays should be waited between calls.
A Windows kernel driver, the so-called injector module, executes the campaign. It loads the
campaign into memory, executes the call and delay instructions one by one, and in between
logging values if required and storing them in a file in the end. These two are connected
by a desktop application. It takes the path to the campaign file as an argument, along with
which values to log. Then, it prepares and loads the injector kernel module, and passes all the
information required to execute the campaign correctly.</p>
      <p>We support the logging of timestamp pairs for each action (hypercall, delay), execution times
(diference between the timestamps), as well as result values and all output values. Hyper-V
stores output values on a dedicated memory pages. Saving these values therefore requires
storing 4MB of data, which is slow. Thus, always storing all values is not viable; the slowdown
would be too big for a test campaign, e.g., a stress test ignoring log values and injecting hypercalls
as fast as possible. That is why the required log values are passed to the desktop application. Yet,
there are two diferent ways of handling optional logging values during execution. Firstly, the
probably more natural approach is too place if statements in the main injection loop. Listing 1
shows a pseudo-C-code of this approach. The loop works through the actions of the campaign.
We are interested in issuing as many calls as possible, so there must not be any delays in the
workload. Accordingly, we can skip the handling of delays. Without any logging, hypercalls
need their parameters prepared in memory and the processor registers, and the call must be
invoked. Additionally, depending on the requested log values, the loop has to optionally take
timestamps, calculate execution time, and store values to the log bufer. These if statements
introduce a lot of branches. It has to be noted however that they always take the same branch
as the requested log values cannot change during the campaign. The speculative execution
engine of the processor should have no problem getting the branch right.</p>
      <p>The alternative approach is the implementation of the loop for every combination of log
values, which does not require any ifs. This still requires branching depending on the log values,
but only once at the start. As a drawback, this approach causes lots of duplicate code, increasing
driver size (not really an issue at this scale) but also drastically hurts maintainability. To test</p>
      <p>Listing 1: Main injection loop with if statements
if the chaos of copy-pasted injection loops is worth it, we want to determine the maximum
hypercall throughput of both configurations.</p>
      <p>We tried focusing the workload to spend as much time as possible injecting hypercalls in
order to spot an eventually existing performance diference. By choosing an invalid hypercall
code (hypervisor detects quickly and returns with an error) and passing no parameters, time for
other tasks is reduced as much as possible. The measurements are performed on an Lenovo
ThinkPad P1 with an Intel i7 9850H CPU and 2 × 16GB of 2667MHz DDR4 RAM. Unfortunately,
the laptop form factor means that the CPU will probably thermally throttle under high load,
i.e., rapid hypercall injection. Maximum throughput during short burst as well as continuously
sustained high load throughput are of interest, so we chose the following methodology:</p>
      <p>A single test campaign contains 50 million invalid hypercalls. Each configuration starts with a
processor that has been idling for at least five minutes, to ensure fair starting temperatures in the
heat sink. The campaign is executed 35 times in a row without breaks. The desktop application
is adapted to log the execution time the kernel driver requires to perform the workload. Tested
configurations are of course the branching and branchless variants, each compiled once as
debug executables and once with Release optimizations by Microsoft’s C++ compiler. The next
section is now going to illustrate the measurement results.
iteration
30</p>
    </sec>
    <sec id="sec-4">
      <title>4. Results</title>
    </sec>
    <sec id="sec-5">
      <title>5. Conclusion</title>
      <p>In this work, we shared our findings regarding the cost of including if statements into the main
loop of a hypercall injector tool. Results showed that even though the same branches are always
taken, the penalty is high enough to make an significant diference in hypercall throughput. In
conclusion however, it should be stated that working dozens of slight variations of the same
loop is not practical if changes happen to the code occasionally. However, a compromise of
maintenance and performance should be achievable: In performance-critical cases that require
no logging or only time measurements, a dedicated, no-branch loop can be implemented. For
other scenarios, which are more concerned with values that hypercalls return, performance is
hindered by logging but usually not of great importance - here, a branching implementation
can save lots of duplicate code.</p>
    </sec>
    <sec id="sec-6">
      <title>Acknowledgments</title>
      <p>This work was written in Cooperation with SPEC RG Security. Lukas Ifländer made his initial
contributions as group leader with University of Würzburg.</p>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          [1]
          <string-name>
            <given-names>S.</given-names>
            <surname>Srivastava</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Singh</surname>
          </string-name>
          ,
          <article-title>A survey on virtualization and hypervisor-based technology in cloud computing environment</article-title>
          ,
          <source>International Journal of Advanced Research in Computer Engineering &amp; Technology (IJARCET) 5</source>
          (
          <year>2016</year>
          ).
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          [2]
          <string-name>
            <given-names>K.</given-names>
            <surname>Miller</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M.</given-names>
            <surname>Pegah</surname>
          </string-name>
          ,
          <article-title>Virtualization: virtually at the desktop</article-title>
          ,
          <source>in: Proceedings of the 35th annual ACM SIGUCCS fall conference, ACM</source>
          ,
          <year>2007</year>
          , pp.
          <fpage>255</fpage>
          -
          <lpage>260</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          [3]
          <string-name>
            <surname>Virtualization-Based</surname>
            <given-names>Security</given-names>
          </string-name>
          : Enabled by Default, https://techcommunity.microsoft.com/ t5/Virtualization/
          <article-title>Virtualization-Based-Security-Enabled-by-</article-title>
          <string-name>
            <surname>Default/</surname>
          </string-name>
          ba-p/
          <fpage>890167</fpage>
          , ???? Accessed:
          <fpage>2019</fpage>
          -10-27.
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          [4]
          <string-name>
            <given-names>L.</given-names>
            <surname>Beierlieb</surname>
          </string-name>
          ,
          <string-name>
            <given-names>L.</given-names>
            <surname>Iflander</surname>
          </string-name>
          ,
          <string-name>
            <given-names>A.</given-names>
            <surname>Milenkoski</surname>
          </string-name>
          ,
          <string-name>
            <given-names>S.</given-names>
            <surname>Kounev</surname>
          </string-name>
          ,
          <article-title>Towards Testing the Performance Influence of Hypervisor Hypercall Interface Behavior (</article-title>
          <year>2019</year>
          ).
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          [5]
          <string-name>
            <given-names>W.</given-names>
            <surname>Hwu</surname>
          </string-name>
          ,
          <string-name>
            <given-names>T. M.</given-names>
            <surname>Conte</surname>
          </string-name>
          ,
          <string-name>
            <given-names>P. P.</given-names>
            <surname>Chang</surname>
          </string-name>
          ,
          <article-title>Comparing software and hardware schemes for reducing the cost of branches</article-title>
          ,
          <source>ACM SIGARCH Computer Architecture News</source>
          <volume>17</volume>
          (
          <year>1989</year>
          )
          <fpage>224</fpage>
          -
          <lpage>233</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          [6]
          <string-name>
            <given-names>S.</given-names>
            <surname>McFarling</surname>
          </string-name>
          ,
          <string-name>
            <given-names>J.</given-names>
            <surname>Hennesey</surname>
          </string-name>
          ,
          <article-title>Reducing the cost of branches</article-title>
          ,
          <source>ACM SIGARCH Computer Architecture News</source>
          <volume>14</volume>
          (
          <year>1986</year>
          )
          <fpage>396</fpage>
          -
          <lpage>403</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          [7]
          <string-name>
            <given-names>H.</given-names>
            <surname>Kim</surname>
          </string-name>
          ,
          <string-name>
            <given-names>J. A.</given-names>
            <surname>Joao</surname>
          </string-name>
          ,
          <string-name>
            <given-names>O.</given-names>
            <surname>Mutlu</surname>
          </string-name>
          ,
          <string-name>
            <given-names>C. J.</given-names>
            <surname>Lee</surname>
          </string-name>
          ,
          <string-name>
            <given-names>Y. N.</given-names>
            <surname>Patt</surname>
          </string-name>
          ,
          <string-name>
            <given-names>R.</given-names>
            <surname>Cohn</surname>
          </string-name>
          ,
          <article-title>Vpc prediction: reducing the cost of indirect branches via hardware-based dynamic devirtualization</article-title>
          ,
          <source>ACM SIGARCH Computer Architecture News</source>
          <volume>35</volume>
          (
          <year>2007</year>
          )
          <fpage>424</fpage>
          -
          <lpage>435</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          [8]
          <string-name>
            <given-names>Z.</given-names>
            <surname>Gu</surname>
          </string-name>
          ,
          <string-name>
            <given-names>Q.</given-names>
            <surname>Zhao</surname>
          </string-name>
          ,
          <article-title>A State-of-the-art Survey on Real-time Issues in Embedded Systems Virtualization</article-title>
          ,
          <source>Journal of Software Engineering and Applications</source>
          <volume>05</volume>
          (
          <year>2012</year>
          )
          <fpage>277</fpage>
          -
          <lpage>290</lpage>
          . doi:
          <volume>10</volume>
          .4236/jsea.
          <year>2012</year>
          .
          <volume>54033</volume>
          .
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          [9]
          <string-name>
            <given-names>H.</given-names>
            <surname>Fayyad-Kazan</surname>
          </string-name>
          ,
          <string-name>
            <given-names>L.</given-names>
            <surname>Perneel</surname>
          </string-name>
          ,
          <string-name>
            <given-names>M.</given-names>
            <surname>Timmerman</surname>
          </string-name>
          ,
          <article-title>Full and para-virtualization with xen: a performance comparison</article-title>
          ,
          <source>Journal of Emerging Trends in Computing and Information Sciences</source>
          <volume>4</volume>
          (
          <year>2013</year>
          )
          <fpage>719</fpage>
          -
          <lpage>727</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref10">
        <mixed-citation>
          [10]
          <string-name>
            <given-names>H.</given-names>
            <surname>Fayyad-Kazan</surname>
          </string-name>
          ,
          <string-name>
            <given-names>L.</given-names>
            <surname>Perneel</surname>
          </string-name>
          ,
          <string-name>
            <surname>M.</surname>
          </string-name>
          <article-title>Timmerman, Benchmarking the performance of microsoft hyper-v server, vmware esxi and xen hypervisors</article-title>
          ,
          <source>Journal of Emerging Trends in Computing and Information Sciences</source>
          <volume>4</volume>
          (
          <year>2013</year>
          )
          <fpage>922</fpage>
          -
          <lpage>933</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref11">
        <mixed-citation>
          [11]
          <string-name>
            <surname>Hyper-V Top Level Function Specifications</surname>
          </string-name>
          ,
          <year>2019</year>
          . URL: https://docs.microsoft.com/en-us/ virtualization/hyper-v-on-windows/reference/tlfs, [
          <article-title>Online; accessed 5</article-title>
          . May.
          <year>2021</year>
          ].
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>