nodeconfig.py 26.9 KB
Newer Older
Antoine Kaufmann's avatar
Antoine Kaufmann committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Copyright 2021 Max Planck Institute for Software Systems, and
# National University of Singapore
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

23
24
from __future__ import annotations

25
import io
Jonas Kaufmann's avatar
Jonas Kaufmann committed
26
import tarfile
27
import typing as tp
28

29
30
from simbricks.orchestration.experiment.experiment_environment import ExpEnv

31

32
33
class AppConfig():
    """Defines the application to run on a node or host."""
34

35
    # pylint: disable=unused-argument
36
37
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
        """Commands to run for this application."""
38
39
        return []

40
41
    def prepare_pre_cp(self) -> tp.List[str]:
        """Commands to run to prepare this application before checkpointing."""
42
43
        return []

44
    def prepare_post_cp(self) -> tp.List[str]:
45
46
        """Commands to run to prepare this application after the checkpoint is
        restored."""
47
48
        return []

Jonas Kaufmann's avatar
Jonas Kaufmann committed
49
    def config_files(self) -> tp.Dict[str, tp.IO]:
50
        """
51
52
        Additional files to put inside the node, which are mounted under
        `/tmp/guest/`.
53

54
55
        Specified in the following format: `filename_inside_node`:
        `IO_handle_of_file`
56
        """
57
58
        return {}

59
    def strfile(self, s: str) -> io.BytesIO:
60
61
62
63
64
        """
        Helper function to convert a string to an IO handle for usage in
        `config_files()`.

        Using this, you can create a file with the string as its content on the
65
        simulated node.
66
        """
67
68
        return io.BytesIO(bytes(s, encoding='UTF-8'))

69

70
71
class NodeConfig():
    """Defines the configuration of a node or host."""
72

73
    def __init__(self) -> None:
74
        self.sim = 'qemu'
75
76
77
78
        """
        The concrete simulator that runs this node config. This is used to use
        execute different commands depending on the concrete simulator, e.g.,
        which command to use to end the simulation.
79
80

        TODO(Kaufi-Jonas): This is ugly. Refactor necessary commands to be
81
82
        provided by the simulator's class directly.
        """
83
84
85
86
87
        self.ip = '10.0.0.1'
        """IP address."""
        self.prefix = 24
        """IP prefix."""
        self.cores = 1
88
89
90
        """Number of CPU cores."""
        self.threads = 1
        """Number of threads per CPU core."""
91
        self.memory = 512
92
93
        """Amount of system memory in MB."""
        self.disk_image = 'base'
94
        """Name of disk image to use or absolute path to image."""
95
96
        self.mtu = 1500
        """Networking MTU."""
97
98
        self.tcp_congestion_control = 'bic'
        """TCP Congestion Control algorithm to use."""
99
        self.nockp = 0
100
101
        """
        Do not create a checkpoint in Gem5.
102
103
104
105
106

        TODO(Kaufi-Jonas): Seems we don't need this anymore since we specify
        whether to take a checkpoint experiment-wide. Otherwise, refactor this
        into simulator-specific class.
        """
107
        self.app: tp.Optional[AppConfig] = None
108
        """Application to run on simulated host."""
109
110
        self.kcmd_append = ''
        """String to be appended to kernel command line."""
111

112
    def config_str(self) -> str:
113
114
115
116
        if self.sim == 'gem5':
            cp_es = [] if self.nockp else ['m5 checkpoint']
            exit_es = ['m5 exit']
        else:
117
            cp_es = ['echo ready to checkpoint']
118
119
            exit_es = ['poweroff -f']

120
121
        es = self.prepare_pre_cp() + self.app.prepare_pre_cp() + cp_es + \
            self.prepare_post_cp() + self.app.prepare_post_cp() + \
122
123
124
            self.run_cmds() + self.cleanup_cmds() + exit_es
        return '\n'.join(es)

125
    def make_tar(self, env: ExpEnv, path: str) -> None:
126
127
128
129
130
131
132
133
134
135
136
137
        with tarfile.open(path, 'w:') as tar:
            # add main run script
            cfg_i = tarfile.TarInfo('guest/run.sh')
            cfg_i.mode = 0o777
            cfg_f = self.strfile(self.config_str())
            cfg_f.seek(0, io.SEEK_END)
            cfg_i.size = cfg_f.tell()
            cfg_f.seek(0, io.SEEK_SET)
            tar.addfile(tarinfo=cfg_i, fileobj=cfg_f)
            cfg_f.close()

            # add additional config files
138
            for (n, f) in self.config_files(env).items():
139
140
141
142
143
144
145
                f_i = tarfile.TarInfo('guest/' + n)
                f_i.mode = 0o777
                f.seek(0, io.SEEK_END)
                f_i.size = f.tell()
                f.seek(0, io.SEEK_SET)
                tar.addfile(tarinfo=f_i, fileobj=f)
                f.close()
146

147
148
    def prepare_pre_cp(self) -> tp.List[str]:
        """Commands to run to prepare node before checkpointing."""
149
        return [
150
            'set -x',
151
152
153
154
155
156
            'export HOME=/root',
            'export LANG=en_US',
            'export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:' + \
                '/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"'
        ]

157
158
    def prepare_post_cp(self) -> tp.List[str]:
        """Commands to run to prepare node after checkpoint restore."""
159
160
        return []

161
162
    def run_cmds(self) -> tp.List[str]:
        """Commands to run on node."""
163
164
        return self.app.run_cmds(self)

165
166
    def cleanup_cmds(self) -> tp.List[str]:
        """Commands to run to cleanup node."""
167
168
        return []

169
170
    # pylint: disable=unused-argument
    def config_files(self, env: ExpEnv) -> tp.Dict[str, tp.IO]:
171
        """
172
173
        Additional files to put inside the node, which are mounted under
        `/tmp/guest/`.
174

175
176
        Specified in the following format: `filename_inside_node`:
        `IO_handle_of_file`
177
        """
178
        return self.app.config_files()
179

180
    def strfile(self, s: str) -> io.BytesIO:
181
182
183
184
185
        """
        Helper function to convert a string to an IO handle for usage in
        `config_files()`.

        Using this, you can create a file with the string as its content on the
186
        simulated node.
187
        """
188
        return io.BytesIO(bytes(s, encoding='UTF-8'))
189

190
191
192

class LinuxNode(NodeConfig):

193
    def __init__(self) -> None:
194
195
        super().__init__()
        self.ifname = 'eth0'
196
197
        self.drivers: tp.List[str] = []
        self.force_mac_addr: tp.Optional[str] = None
198

199
    def prepare_post_cp(self) -> tp.List[str]:
200
201
202
203
204
205
        l = []
        for d in self.drivers:
            if d[0] == '/':
                l.append('insmod ' + d)
            else:
                l.append('modprobe ' + d)
206
        if self.force_mac_addr:
Jonas Kaufmann's avatar
Jonas Kaufmann committed
207
208
209
210
            l.append(
                'ip link set dev ' + self.ifname + ' address ' +
                self.force_mac_addr
            )
211
        l.append('ip link set dev ' + self.ifname + ' up')
212
        l.append(f'ip addr add {self.ip}/{self.prefix} dev {self.ifname}')
213
214
        return super().prepare_post_cp() + l

Jonas Kaufmann's avatar
Jonas Kaufmann committed
215

216
class I40eLinuxNode(LinuxNode):
Jonas Kaufmann's avatar
Jonas Kaufmann committed
217

218
    def __init__(self) -> None:
219
220
221
        super().__init__()
        self.drivers.append('i40e')

Jonas Kaufmann's avatar
Jonas Kaufmann committed
222

223
class CorundumLinuxNode(LinuxNode):
Jonas Kaufmann's avatar
Jonas Kaufmann committed
224

225
    def __init__(self) -> None:
226
227
228
        super().__init__()
        self.drivers.append('/tmp/guest/mqnic.ko')

229
    # pylint: disable=consider-using-with
230
231
232
    def config_files(self, env: ExpEnv) -> tp.Dict[str, tp.IO]:
        m = {'mqnic.ko': open(f'{env.repodir}/images/mqnic/mqnic.ko', 'rb')}
        return {**m, **super().config_files(env)}
233

Jonas Kaufmann's avatar
Jonas Kaufmann committed
234

235
class E1000LinuxNode(LinuxNode):
Jonas Kaufmann's avatar
Jonas Kaufmann committed
236

237
    def __init__(self) -> None:
238
239
        super().__init__()
        self.drivers.append('e1000')
240
241
242


class MtcpNode(NodeConfig):
243

244
    def __init__(self) -> None:
245
246
247
248
249
        super().__init__()
        self.disk_image = 'mtcp'
        self.pci_dev = '0000:00:02.0'
        self.memory = 16 * 1024
        self.num_hugepages = 4096
250

251
    def prepare_pre_cp(self) -> tp.List[str]:
252
253
254
255
256
257
        return super().prepare_pre_cp() + [
            'mount -t proc proc /proc',
            'mount -t sysfs sysfs /sys',
            'mkdir -p /dev/hugepages',
            'mount -t hugetlbfs nodev /dev/hugepages',
            'mkdir -p /dev/shm',
258
            'mount -t tmpfs tmpfs /dev/shm',
259
260
261
262
            'echo ' + str(self.num_hugepages) + ' > /sys/devices/system/' + \
                    'node/node0/hugepages/hugepages-2048kB/nr_hugepages',
        ]

263
    def prepare_post_cp(self) -> tp.List[str]:
264
265
266
        return super().prepare_post_cp() + [
            'insmod /root/mtcp/dpdk/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko',
            '/root/mtcp/dpdk/usertools/dpdk-devbind.py -b igb_uio ' +
Jonas Kaufmann's avatar
Jonas Kaufmann committed
267
            self.pci_dev,
268
269
270
            'insmod /root/mtcp/dpdk-iface-kmod/dpdk_iface.ko',
            '/root/mtcp/dpdk-iface-kmod/dpdk_iface_main',
            'ip link set dev dpdk0 up',
271
            f'ip addr add {self.ip}/{self.prefix} dev dpdk0'
272
273
        ]

274
    def config_files(self, env: ExpEnv) -> tp.Dict[str, tp.IO]:
Jonas Kaufmann's avatar
Jonas Kaufmann committed
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
        m = {
            'mtcp.conf':
                self.strfile(
                    'io = dpdk\n'
                    'num_cores = ' + str(self.cores) + '\n'
                    'num_mem_ch = 4\n'
                    'port = dpdk0\n'
                    'max_concurrency = 4096\n'
                    'max_num_buffers = 4096\n'
                    'rcvbuf = 8192\n'
                    'sndbuf = 8192\n'
                    'tcp_timeout = 10\n'
                    'tcp_timewait = 0\n'
                    '#stat_print = dpdk0\n'
                )
        }
291

292
        return {**m, **super().config_files(env)}
293

Jonas Kaufmann's avatar
Jonas Kaufmann committed
294

295
class TASNode(NodeConfig):
296

297
    def __init__(self) -> None:
298
299
300
301
302
303
304
        super().__init__()
        self.disk_image = 'tas'
        self.pci_dev = '0000:00:02.0'
        self.memory = 16 * 1024
        self.num_hugepages = 4096
        self.fp_cores = 1
        self.preload = True
305

306
    def prepare_pre_cp(self) -> tp.List[str]:
307
308
309
310
311
312
        return super().prepare_pre_cp() + [
            'mount -t proc proc /proc',
            'mount -t sysfs sysfs /sys',
            'mkdir -p /dev/hugepages',
            'mount -t hugetlbfs nodev /dev/hugepages',
            'mkdir -p /dev/shm',
313
            'mount -t tmpfs tmpfs /dev/shm',
314
315
316
317
            'echo ' + str(self.num_hugepages) + ' > /sys/devices/system/' + \
                    'node/node0/hugepages/hugepages-2048kB/nr_hugepages',
        ]

318
    def prepare_post_cp(self) -> tp.List[str]:
319
        cmds = super().prepare_post_cp() + [
320
            'insmod /root/dpdk/lib/modules/5.4.46/extra/dpdk/igb_uio.ko',
321
322
            '/root/dpdk/sbin/dpdk-devbind -b igb_uio ' + self.pci_dev,
            'cd /root/tas',
323
324
325
326
            (
                f'tas/tas --ip-addr={self.ip}/{self.prefix}'
                f' --fp-cores-max={self.fp_cores} --fp-no-ints &'
            ),
327
            'sleep 1'
328
329
        ]

330
        if self.preload:
Jonas Kaufmann's avatar
Jonas Kaufmann committed
331
            cmds += ['export LD_PRELOAD=/root/tas/lib/libtas_interpose.so']
332
333
        return cmds

334

Hejing Li's avatar
Hejing Li committed
335
class I40eDCTCPNode(NodeConfig):
Jonas Kaufmann's avatar
Jonas Kaufmann committed
336

337
    def prepare_pre_cp(self) -> tp.List[str]:
Hejing Li's avatar
Hejing Li committed
338
339
340
341
342
343
        return super().prepare_pre_cp() + [
            'mount -t proc proc /proc',
            'mount -t sysfs sysfs /sys',
            'sysctl -w net.core.rmem_default=31457280',
            'sysctl -w net.core.rmem_max=31457280',
            'sysctl -w net.core.wmem_default=31457280',
Hejing Li's avatar
Hejing Li committed
344
345
346
347
348
349
            'sysctl -w net.core.wmem_max=31457280',
            'sysctl -w net.core.optmem_max=25165824',
            'sysctl -w net.ipv4.tcp_mem="786432 1048576 26777216"',
            'sysctl -w net.ipv4.tcp_rmem="8192 87380 33554432"',
            'sysctl -w net.ipv4.tcp_wmem="8192 87380 33554432"',
            'sysctl -w net.ipv4.tcp_congestion_control=dctcp',
Hejing Li's avatar
Hejing Li committed
350
351
352
            'sysctl -w net.ipv4.tcp_ecn=1'
        ]

353
    def prepare_post_cp(self) -> tp.List[str]:
Hejing Li's avatar
Hejing Li committed
354
355
356
        return super().prepare_post_cp() + [
            'modprobe i40e',
            'ethtool -G eth0 rx 4096 tx 4096',
357
            'ethtool -K eth0 tso off',
Hejing Li's avatar
Hejing Li committed
358
359
            'ip link set eth0 txqueuelen 13888',
            f'ip link set dev eth0 mtu {self.mtu} up',
360
            f'ip addr add {self.ip}/{self.prefix} dev eth0',
Hejing Li's avatar
Hejing Li committed
361
362
        ]

Jonas Kaufmann's avatar
Jonas Kaufmann committed
363

364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
class I40eTCPCongNode(NodeConfig):

    def prepare_pre_cp(self):
        return super().prepare_pre_cp() + [
            'mount -t proc proc /proc',
            'mount -t sysfs sysfs /sys',
            # 'sysctl -w net.core.rmem_default=31457280',
            # 'sysctl -w net.core.rmem_max=31457280',
            # 'sysctl -w net.core.wmem_default=31457280',
            # 'sysctl -w net.core.wmem_max=31457280',
            # 'sysctl -w net.core.optmem_max=25165824',
            # 'sysctl -w net.ipv4.tcp_mem="786432 1048576 26777216"',
            # 'sysctl -w net.ipv4.tcp_rmem="8192 87380 33554432"',
            # 'sysctl -w net.ipv4.tcp_wmem="8192 87380 33554432"',
            'sysctl -w net.ipv4.tcp_congestion_control=' +
            f'{self.tcp_congestion_control}',
            'sysctl -w net.ipv4.tcp_ecn=0'
        ]

    def prepare_post_cp(self):
        return super().prepare_post_cp() + [
            'modprobe i40e',
            'ethtool -G eth0 rx 4096 tx 4096',
387
            'ethtool -K eth0 tso off',  # 'ip link set eth0 txqueuelen 13888',
388
389
390
391
392
            f'ip link set dev eth0 mtu {self.mtu} up',
            f'ip addr add {self.ip}/{self.prefix} dev eth0',
        ]


Hejing Li's avatar
Hejing Li committed
393
class CorundumDCTCPNode(NodeConfig):
Jonas Kaufmann's avatar
Jonas Kaufmann committed
394

395
    def prepare_pre_cp(self) -> tp.List[str]:
Hejing Li's avatar
Hejing Li committed
396
397
398
399
400
401
        return super().prepare_pre_cp() + [
            'mount -t proc proc /proc',
            'mount -t sysfs sysfs /sys',
            'sysctl -w net.core.rmem_default=31457280',
            'sysctl -w net.core.rmem_max=31457280',
            'sysctl -w net.core.wmem_default=31457280',
Hejing Li's avatar
Hejing Li committed
402
403
404
405
406
407
            'sysctl -w net.core.wmem_max=31457280',
            'sysctl -w net.core.optmem_max=25165824',
            'sysctl -w net.ipv4.tcp_mem="786432 1048576 26777216"',
            'sysctl -w net.ipv4.tcp_rmem="8192 87380 33554432"',
            'sysctl -w net.ipv4.tcp_wmem="8192 87380 33554432"',
            'sysctl -w net.ipv4.tcp_congestion_control=dctcp',
Hejing Li's avatar
Hejing Li committed
408
409
410
            'sysctl -w net.ipv4.tcp_ecn=1'
        ]

411
    def prepare_post_cp(self) -> tp.List[str]:
Hejing Li's avatar
Hejing Li committed
412
413
414
        return super().prepare_post_cp() + [
            'insmod mqnic.ko',
            'ip link set dev eth0 up',
415
            f'ip addr add {self.ip}/{self.prefix} dev eth0',
Hejing Li's avatar
Hejing Li committed
416
417
        ]

418
419

class LinuxFEMUNode(NodeConfig):
Jonas Kaufmann's avatar
Jonas Kaufmann committed
420

421
    def __init__(self) -> None:
422
        super().__init__()
423
424
        self.drivers = ['nvme']

425
    def prepare_post_cp(self) -> tp.List[str]:
426
427
428
429
430
431
432
433
        l = ['lspci -vvvv']
        for d in self.drivers:
            if d[0] == '/':
                l.append('insmod ' + d)
            else:
                l.append('modprobe ' + d)
        return super().prepare_post_cp() + l

Jonas Kaufmann's avatar
Jonas Kaufmann committed
434

435
436
class IdleHost(AppConfig):

437
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
438
439
440
        return ['sleep infinity']


441
class NVMEFsTest(AppConfig):
Jonas Kaufmann's avatar
Jonas Kaufmann committed
442

443
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
Jonas Kaufmann's avatar
Jonas Kaufmann committed
444
445
446
447
448
449
450
        return [
            'mount -t proc proc /proc',
            'mkfs.ext3 /dev/nvme0n1',
            'mount /dev/nvme0n1 /mnt',
            'dd if=/dev/urandom of=/mnt/foo bs=1024 count=1024'
        ]

451

Hejing Li's avatar
Hejing Li committed
452
class DctcpServer(AppConfig):
Jonas Kaufmann's avatar
Jonas Kaufmann committed
453

454
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
Hejing Li's avatar
Hejing Li committed
455
456
        return ['iperf -s -w 1M -Z dctcp']

Jonas Kaufmann's avatar
Jonas Kaufmann committed
457

Hejing Li's avatar
Hejing Li committed
458
class DctcpClient(AppConfig):
459

460
    def __init__(self) -> None:
461
462
463
        super().__init__()
        self.server_ip = '192.168.64.1'
        self.is_last = False
Jonas Kaufmann's avatar
Jonas Kaufmann committed
464

465
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
466
        if self.is_last:
Jonas Kaufmann's avatar
Jonas Kaufmann committed
467
468
469
470
471
            return [
                'sleep 1',
                f'iperf -w 1M -c {self.server_ip} -Z dctcp -i 1',
                'sleep 2'
            ]
Hejing Li's avatar
Hejing Li committed
472
        else:
Jonas Kaufmann's avatar
Jonas Kaufmann committed
473
474
475
476
477
478
            return [
                'sleep 1',
                f'iperf -w 1M -c {self.server_ip} -Z dctcp -i 1',
                'sleep 20'
            ]

Hejing Li's avatar
Hejing Li committed
479

480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
class TcpCongServer(AppConfig):

    def run_cmds(self, node):
        return ['iperf -s -w 1M']


class TcpCongClient(AppConfig):

    def __init__(self):
        super().__init__()
        self.server_ip = '192.168.64.1'
        self.is_last = False

    def run_cmds(self, node):
        if self.is_last:
            return [
                'sleep 1',
                f'iperf -w 1M -c {self.server_ip} -i 1',
                'sleep 2',
            ]
        else:
            return [
                'sleep 1',
                f'iperf -w 1M -c {self.server_ip} -i 1',
                'sleep 20',
            ]


Hejing Li's avatar
Hejing Li committed
508
class PingClient(AppConfig):
509

510
    def __init__(self, server_ip: str = '192.168.64.1') -> None:
511
        super().__init__()
512
        self.server_ip = server_ip
Hejing Li's avatar
Hejing Li committed
513

514
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
515
        return [f'ping {self.server_ip} -c 10']
Hejing Li's avatar
Hejing Li committed
516

Jonas Kaufmann's avatar
Jonas Kaufmann committed
517

518
class IperfTCPServer(AppConfig):
Jonas Kaufmann's avatar
Jonas Kaufmann committed
519

520
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
521
522
        return ['iperf -s -l 32M -w 32M']

Jonas Kaufmann's avatar
Jonas Kaufmann committed
523

524
class IperfUDPServer(AppConfig):
Jonas Kaufmann's avatar
Jonas Kaufmann committed
525

526
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
527
528
        return ['iperf -s -u']

Jonas Kaufmann's avatar
Jonas Kaufmann committed
529

530
class IperfTCPClient(AppConfig):
531

532
    def __init__(self) -> None:
533
534
535
536
        super().__init__()
        self.server_ip = '10.0.0.1'
        self.procs = 1
        self.is_last = False
537

538
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
Jialin Li's avatar
Jialin Li committed
539

Jonas Kaufmann's avatar
Jonas Kaufmann committed
540
541
542
543
544
        cmds = [
            'sleep 1',
            'iperf -l 32M -w 32M  -c ' + self.server_ip + ' -i 1 -P ' +
            str(self.procs)
        ]
Hejing Li's avatar
Hejing Li committed
545
546
547
548
549
        if self.is_last:
            cmds.append('sleep 0.5')
        else:
            cmds.append('sleep 10')
        return cmds
550

Jonas Kaufmann's avatar
Jonas Kaufmann committed
551

552
class IperfUDPClient(AppConfig):
553

554
    def __init__(self) -> None:
555
556
557
558
        super().__init__()
        self.server_ip = '10.0.0.1'
        self.rate = '150m'
        self.is_last = False
559

560
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
Jonas Kaufmann's avatar
Jonas Kaufmann committed
561
562
563
564
        cmds = [
            'sleep 1',
            'iperf -c ' + self.server_ip + ' -i 1 -u -b ' + self.rate
        ]
Jialin Li's avatar
Jialin Li committed
565

Hejing Li's avatar
Hejing Li committed
566
567
568
        if self.is_last:
            cmds.append('sleep 0.5')
        else:
Hejing Li's avatar
Hejing Li committed
569
            cmds.append('sleep 10')
Jialin Li's avatar
Jialin Li committed
570

Hejing Li's avatar
Hejing Li committed
571
572
        return cmds

Jonas Kaufmann's avatar
Jonas Kaufmann committed
573

574
class IperfUDPShortClient(AppConfig):
575

576
    def __init__(self) -> None:
577
578
579
580
        super().__init__()
        self.server_ip = '10.0.0.1'
        self.rate = '150m'
        self.is_last = False
581

582
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
Jonas Kaufmann's avatar
Jonas Kaufmann committed
583
        cmds = ['sleep 1', 'iperf -c ' + self.server_ip + ' -u -n 1 ']
584
585
586

        return cmds

Jialin Li's avatar
Jialin Li committed
587

588
class IperfUDPClientSleep(AppConfig):
589

590
    def __init__(self) -> None:
591
592
593
        super().__init__()
        self.server_ip = '10.0.0.1'
        self.rate = '150m'
Jonas Kaufmann's avatar
Jonas Kaufmann committed
594

595
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
Jonas Kaufmann's avatar
Jonas Kaufmann committed
596
        return ['sleep 1', 'sleep 10']
597

Hejing Li's avatar
Hejing Li committed
598
599

class NoTraffic(AppConfig):
600

601
    def __init__(self) -> None:
602
603
604
        super().__init__()
        self.is_sleep = 1
        self.is_server = 0
Jonas Kaufmann's avatar
Jonas Kaufmann committed
605

606
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
Hejing Li's avatar
Hejing Li committed
607
        cmds = []
608
        if self.is_server:
Hejing Li's avatar
Hejing Li committed
609
610
            cmds.append('sleep infinity')
        else:
611
            if self.is_sleep:
Hejing Li's avatar
Hejing Li committed
612
                cmds.append('sleep 10')
Jialin Li's avatar
Jialin Li committed
613

Hejing Li's avatar
Hejing Li committed
614
            else:
Jialin Li's avatar
Jialin Li committed
615
                cmds.append('dd if=/dev/urandom of=/dev/null count=500000')
Hejing Li's avatar
Hejing Li committed
616
617
618

        return cmds

Jonas Kaufmann's avatar
Jonas Kaufmann committed
619

620
class NetperfServer(AppConfig):
Jonas Kaufmann's avatar
Jonas Kaufmann committed
621

622
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
Jonas Kaufmann's avatar
Jonas Kaufmann committed
623
624
        return ['netserver', 'sleep infinity']

625
626

class NetperfClient(AppConfig):
627

628
    def __init__(self) -> None:
629
630
631
632
        super().__init__()
        self.server_ip = '10.0.0.1'
        self.duration_tp = 10
        self.duration_lat = 10
Jonas Kaufmann's avatar
Jonas Kaufmann committed
633

634
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
635
636
637
638
639
640
641
642
643
        return [
            'netserver',
            'sleep 0.5',
            f'netperf -H {self.server_ip} -l {self.duration_tp}',
            (
                f'netperf -H {self.server_ip} -l {self.duration_lat} -t TCP_RR'
                ' -- -o mean_latency,p50_latency,p90_latency,p99_latency'
            )
        ]
644

Jonas Kaufmann's avatar
Jonas Kaufmann committed
645

Jialin Li's avatar
Jialin Li committed
646
class VRReplica(AppConfig):
647

648
    def __init__(self) -> None:
649
650
        super().__init__()
        self.index = 0
Jonas Kaufmann's avatar
Jonas Kaufmann committed
651

652
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
Jonas Kaufmann's avatar
Jonas Kaufmann committed
653
654
655
656
657
        return [
            '/root/nopaxos/bench/replica -c /root/nopaxos.config -i ' +
            str(self.index) + ' -m vr'
        ]

658

Jialin Li's avatar
Jialin Li committed
659
class VRClient(AppConfig):
660

661
    def __init__(self) -> None:
662
        super().__init__()
663
        self.server_ips: tp.List[str] = []
Jonas Kaufmann's avatar
Jonas Kaufmann committed
664

665
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
666
667
        cmds = []
        for ip in self.server_ips:
668
            cmds.append('ping -c 2 ' + ip)
Jonas Kaufmann's avatar
Jonas Kaufmann committed
669
670
671
672
        cmds.append(
            '/root/nopaxos/bench/client -c /root/nopaxos.config ' +
            '-m vr -u 2 -h ' + node.ip
        )
673
674
        return cmds

Jonas Kaufmann's avatar
Jonas Kaufmann committed
675

Jialin Li's avatar
Jialin Li committed
676
class NOPaxosReplica(AppConfig):
677

678
    def __init__(self) -> None:
679
680
        super().__init__()
        self.index = 0
Jonas Kaufmann's avatar
Jonas Kaufmann committed
681

682
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
Jonas Kaufmann's avatar
Jonas Kaufmann committed
683
684
685
686
687
        return [
            '/root/nopaxos/bench/replica -c /root/nopaxos.config -i ' +
            str(self.index) + ' -m nopaxos'
        ]

Jialin Li's avatar
Jialin Li committed
688
689

class NOPaxosClient(AppConfig):
690

691
    def __init__(self) -> None:
692
        super().__init__()
693
        self.server_ips: tp.List[str] = []
694
695
        self.is_last = False
        self.use_ehseq = False
696

697
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
698
699
        cmds = []
        for ip in self.server_ips:
700
            cmds.append('ping -c 2 ' + ip)
Jialin Li's avatar
Jialin Li committed
701
702
703
704
705
        cmd = '/root/nopaxos/bench/client -c /root/nopaxos.config ' + \
                '-m nopaxos -u 2 -h ' + node.ip
        if self.use_ehseq:
            cmd += ' -e'
        cmds.append(cmd)
706
707
708
709
        if self.is_last:
            cmds.append('sleep 1')
        else:
            cmds.append('sleep infinity')
710
        return cmds
711

Jonas Kaufmann's avatar
Jonas Kaufmann committed
712

713
class NOPaxosSequencer(AppConfig):
Jonas Kaufmann's avatar
Jonas Kaufmann committed
714

715
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
716
717
718
719
        return [(
            '/root/nopaxos/sequencer/sequencer -c /root/nopaxos.config'
            ' -m nopaxos'
        )]
720
721
722


class RPCServer(AppConfig):
723

724
    def __init__(self) -> None:
725
726
727
728
729
        super().__init__()
        self.port = 1234
        self.threads = 1
        self.max_flows = 1234
        self.max_bytes = 1024
730

731
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
732
733
        exe = 'echoserver_linux' if not isinstance(node, MtcpNode) else \
            'echoserver_mtcp'
Jonas Kaufmann's avatar
Jonas Kaufmann committed
734
735
        return [
            'cd /root/tasbench/micro_rpc',
736
737
738
739
            (
                f'./{exe} {self.port} {self.threads} /tmp/guest/mtcp.conf'
                f' {self.max_flows} {self.max_bytes}'
            )
Jonas Kaufmann's avatar
Jonas Kaufmann committed
740
741
        ]

742
743

class RPCClient(AppConfig):
744

745
    def __init__(self) -> None:
746
747
748
749
750
751
752
753
754
755
756
        super().__init__()
        self.server_ip = '10.0.0.1'
        self.port = 1234
        self.threads = 1
        self.max_flows = 128
        self.max_bytes = 1024
        self.max_pending = 1
        self.openall_delay = 2
        self.max_msgs_conn = 0
        self.max_pend_conns = 8
        self.time = 25
757

758
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
759
760
        exe = 'testclient_linux' if not isinstance(node, MtcpNode) else \
            'testclient_mtcp'
Jonas Kaufmann's avatar
Jonas Kaufmann committed
761
762
        return [
            'cd /root/tasbench/micro_rpc',
763
764
765
766
767
            (
                f'./{exe} {self.server_ip} {self.port} {self.threads}'
                f' /tmp/guest/mtcp.conf {self.max_bytes} {self.max_pending}'
                f' {self.max_flows} {self.openall_delay} {self.max_msgs_conn}'
                f' {self.max_pend_conns} &'
Jonas Kaufmann's avatar
Jonas Kaufmann committed
768
            ),
769
            f'sleep {self.time}'
Jonas Kaufmann's avatar
Jonas Kaufmann committed
770
        ]
771
772
773
774


################################################################################

Jonas Kaufmann's avatar
Jonas Kaufmann committed
775

776
class HTTPD(AppConfig):
777

778
    def __init__(self) -> None:
779
780
781
782
783
        super().__init__()
        self.threads = 1
        self.file_size = 64
        self.mtcp_config = 'lighttpd.conf'
        self.httpd_dir = ''  # TODO added because doesn't originally exist
784

785
    def prepare_pre_cp(self) -> tp.List[str]:
786
787
788
789
790
791
792
        return [
            'mkdir -p /srv/www/htdocs/ /tmp/lighttpd/',
            (
                f'dd if=/dev/zero of=/srv/www/htdocs/file bs={self.file_size}'
                ' count=1'
            )
        ]
793

794
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
795
796
797
798
799
800
801
        return [
            f'cd {self.httpd_dir}/src/',
            (
                f'./lighttpd -D -f ../doc/config/{self.mtcp_config}'
                f' -n {self.threads} -m ./.libs/'
            )
        ]
802

Jonas Kaufmann's avatar
Jonas Kaufmann committed
803

804
class HTTPDLinux(HTTPD):
805

806
    def __init__(self) -> None:
807
808
        super().__init__()
        self.httpd_dir = '/root/mtcp/apps/lighttpd-mtlinux'
809

Jonas Kaufmann's avatar
Jonas Kaufmann committed
810

811
class HTTPDLinuxRPO(HTTPD):
812

813
    def __init__(self) -> None:
814
815
        super().__init__()
        self.httpd_dir = '/root/mtcp/apps/lighttpd-mtlinux-rop'
816

Jonas Kaufmann's avatar
Jonas Kaufmann committed
817

818
class HTTPDMtcp(HTTPD):
819

820
    def __init__(self) -> None:
821
822
823
        super().__init__()
        self.httpd_dir = '/root/mtcp/apps/lighttpd-mtcp'
        self.mtcp_config = 'm-lighttpd.conf'
824

825
    def prepare_pre_cp(self) -> tp.List[str]:
826
        return super().prepare_pre_cp() + [
827
828
829
830
831
832
            f'cp /tmp/guest/mtcp.conf {self.httpd_dir}/src/mtcp.conf',
            (
                'sed -i "s:^server.document-root =.*:server.document-root = '
                'server_root + \\"/htdocs\\":" '
                f'{self.httpd_dir}/doc/config/{self.mtcp_config}'
            )
833
834
835
836
        ]


class HTTPC(AppConfig):
837

838
    def __init__(self) -> None:
839
840
841
842
843
844
845
846
        super().__init__()
        self.server_ip = '10.0.0.1'
        self.conns = 1000
        #self.requests = 10000000
        self.requests = 10000
        self.threads = 1
        self.url = '/file'
        self.ab_dir = ''  # TODO added because doesn't originally exist
847

848
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
849
850
851
852
853
854
855
        return [
            f'cd {self.ab_dir}/support/',
            (
                f'./ab -N {self.threads} -c {self.conns} -n {self.requests}'
                f' {self.server_ip}{self.url}'
            )
        ]
856

Jonas Kaufmann's avatar
Jonas Kaufmann committed
857

858
class HTTPCLinux(HTTPC):
859

860
    def __init__(self) -> None:
861
862
        super().__init__()
        self.ab_dir = '/root/mtcp/apps/ab-linux'
863

Jonas Kaufmann's avatar
Jonas Kaufmann committed
864

865
class HTTPCMtcp(HTTPC):
866

867
    def __init__(self) -> None:
868
869
        super().__init__()
        self.ab_dir = '/root/mtcp/apps/ab-mtcp'
870

871
    def prepare_pre_cp(self) -> tp.List[str]:
872
        return super().prepare_pre_cp() + [
873
874
            f'cp /tmp/guest/mtcp.conf {self.ab_dir}/support/config/mtcp.conf',
            f'rm -f {self.ab_dir}/support/config/arp.conf'
875
876
877
        ]


878
class MemcachedServer(AppConfig):
Jonas Kaufmann's avatar
Jonas Kaufmann committed
879

880
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
881
882
        return ['memcached -u root -t 1 -c 4096']

Jonas Kaufmann's avatar
Jonas Kaufmann committed
883

884
class MemcachedClient(AppConfig):
885

886
    def __init__(self) -> None:
887
888
889
890
891
        super().__init__()
        self.server_ips = ['10.0.0.1']
        self.threads = 1
        self.concurrency = 1
        self.throughput = '1k'
Jonas Kaufmann's avatar
Jonas Kaufmann committed
892

893
    def run_cmds(self, node: NodeConfig) -> tp.List[str]:
894
895
        servers = [ip + ':11211' for ip in self.server_ips]
        servers = ','.join(servers)
896
897
898
899
900
        return [(
            f'memaslap --binary --time 10s --server={servers}'
            f' --thread={self.threads} --concurrency={self.concurrency}'
            f' --tps={self.throughput} --verbose'
        )]