1.4. How To
1.4.1. Create and Run an Experiment
Experiments are defined in a declarative fashion inside Python modules using
classes. Basically, create a .py file and add a global variable
experiments
, a list which contains multiple instances of the class
simbricks.orchestration.experiments.Experiment
, each one describing a
standalone experiment. This is very helpful if you wish to evaluate your work in
different environments, for example, you may want to swap out some simulator or
investigate multiple topologies with different scale.
The class Experiment
provides
methods to add the simulators you wish to run. All available simulators can be
found in the module simbricks.orchestration.simulators
. Instantiating
HostSim
requires you to specify a
NodeConfig
, which contains the
configuration for your host, for example, its networking settings, how much
system memory it should have, and most importantly, which applications to run by
assigning an AppConfig
. You can
find predefined classes for node and app configs in the module
simbricks.orchestration.nodeconfig
. Feel free to add new ones or just
create a new class locally in your experiment’s module. For more details, see SimBricks Orchestration.
The last step to complete your virtual testbed is to specify which virtual
components connect to each other. You do this by invoking the respective methods
on the simulators you have instantiated. See the different simulator types’ base
classes in the module simulators
for more
information. A simple and complete experiment module in which a client host
pings a server can be found below.
If you plan to simulate a topology with multiple hosts, it may be helpful to
take a look at the module simbricks.orchestration.simulator_utils
in
which we provide some helper functions to reduce the amount of code you have to
write.
Finally, to run your experiment, invoke experiments/run.py
and provide the
path to your experiment module. In our docker containers, you can also just use
the following command from anywhere:
$ simbricks-run --verbose --force <path_to_your_module.py>
--verbose
prints all simulators’ output to the terminal and --force
forces execution even if there already exist result files for the experiment. If
simbricks-run
is not available, you can always do
$ cd experiments
$ python run.py --verbose --force <path_to_your_module.py>
While running, you can interrupt the experiment using Ctrl+C in your terminal.
This will cleanly stop all simulators and collect their output in a JSON file in
the directory experiments/out/<experiment_name>
. These are the necessary
basics to create and run your first experiment. Have fun.
1from simbricks.orchestration.experiments import Experiment
2from simbricks.orchestration.nodeconfig import (
3 I40eLinuxNode, IdleHost, PingClient
4)
5from simbricks.orchestration.simulators import Gem5Host, I40eNIC, SwitchNet
6
7e = Experiment(name='simple_ping')
8e.checkpoint = True # use checkpoint and restore to speed up simulation
9
10# create client
11client_config = I40eLinuxNode() # boot Linux with i40e NIC driver
12client_config.ip = '10.0.0.1'
13client_config.app = PingClient(server_ip='10.0.0.2')
14client = Gem5Host(client_config)
15client.name = 'client'
16client.wait = True # wait for client simulator to finish execution
17e.add_host(client)
18
19# attach client's NIC
20client_nic = I40eNIC()
21e.add_nic(client_nic)
22client.add_nic(client_nic)
23
24# create server
25server_config = I40eLinuxNode() # boot Linux with i40e NIC driver
26server_config.ip = '10.0.0.2'
27server_config.app = IdleHost()
28server = Gem5Host(server_config)
29server.name = 'server'
30e.add_host(server)
31
32# attach server's NIC
33server_nic = I40eNIC()
34e.add_nic(server_nic)
35server.add_nic(server_nic)
36
37# connect NICs over network
38network = SwitchNet()
39e.add_network(network)
40client_nic.set_network(network)
41server_nic.set_network(network)
42
43# set more interesting link latencies than default
44eth_latency = 500 * 10**3 # 500 us
45network.eth_latency = eth_latency
46client_nic.eth_latency = eth_latency
47server_nic.eth_latency = eth_latency
48
49experiments = [e]
1.4.2. Add a Node or Application Config
A host’s configuration and the workload to run are defined via
Node and App Config. SimBricks already comes with a few examples in the
module simbricks.orchestration.nodeconfig
. If they don’t fit your
use-case, you need to add your own by overriding the pre-defined member
functions of NodeConfig
and
AppConfig
. The most notably is
run_cmds()
, which defines
the commands to execute for your workload/application. Further information can
be found in the module simbricks.orchestration.nodeconfig
directly.
1.4.3. Add a Custom Image
1.4.4. Integrate a New Simulator
The first step when integrating a new simulator into SimBricks is to implement a
SimBricks adapter for it. You can find the necessary information in the
Simulator Adapters section. To then make running
experiments and setting up the communication channels with other simulators more
convenient, add a class for the simulator to the orchestration framework that
inherits from Simulator
or one of
the more specialized base classes in simbricks.orchestration.simulators
.
In this class you define the command to execute the simulator together with
further parameters, for example, to connect to the communication channels with
other simulators. Below is an example of what this looks like.
1class WireNet(NetSim):
2
3 def run_cmd(self, env):
4 connects = self.connect_sockets(env)
5 assert len(connects) == 2
6 cmd = (
7 f'{env.repodir}/sims/net/wire/net_wire {connects[0][1]}'
8 f' {connects[1][1]} {self.sync_mode} {self.sync_period}'
9 f' {self.eth_latency}'
10 )
11 if env.pcap_file:
12 cmd += ' ' + env.pcap_file
13
14 return cmd