summaryrefslogtreecommitdiffstats
path: root/modules-available/vmstore/inc/vmstorebenchmark.inc.php
blob: b819ef8aa6e11b85aea5d4bc3e1f73682146b964 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<?php

class VmStoreBenchmark
{

	const PROP_LIST_KEY = 'vmstore.benchmark';

	/**
	 * @param string[] $machineUuids List of UUIDs
	 * @return void
	 */
	public static function prepareSelectDialog(array $uuids)
	{
		Module::isAvailable('rebootcontrol');
		User::assertPermission('.vmstore.benchmark');
		$uuids = array_values(Request::post('uuid', Request::REQUIRED, 'array'));
		$machines = RebootUtils::getFilteredMachineList($uuids, '.vmstore.benchmark');
		if ($machines === false)
			return;
		$machines = array_column($machines, 'machineuuid');
		$id = Property::addToList(self::PROP_LIST_KEY,
			json_encode(['machines' => $machines]), 60);
		Util::redirect('?do=vmstore&show=benchmark&action=select&id=' . $id);
	}

	/**
	 * @param string $image relative path/name of image
	 * @param string $serverOrMode IP address of DNBD3 server, OR 'auto' for all servers known to client, or 'nfs' for NFS
	 * @param int $start timestamp when the clients should start
	 * @return ?string taskId, or null on error
	 */
	public static function start(string $id, array $machineUuids, string $image, string $serverOrMode, int &$start): ?string
	{
		Module::isAvailable('rebootcontrol');
		$clients = Database::queryAll('SELECT machineuuid, clientip FROM machine WHERE machineuuid IN (:uuids)',
			['uuids' => $machineUuids]);
		if (empty($clients)) {
			ErrorHandler::traceError('Cannot start benchmark: No matching clients');
		}
		// The more clients we have, the longer it takes to SSH into all of them.
		// As of 2022, RemoteExec processes 4 clients in parallel
		$start = ceil(count($clients) / 4 + 5 + time());
		if ($serverOrMode === 'nfs') {
			$modeOption = '--nfs';
		} elseif ($serverOrMode === 'auto') {
			$modeOption = '';
		} else {
			$modeOption = "--servers '$serverOrMode'";
		}
		// We fork off the benchmark into the background, and collect the results with another RemoteExec job
		// when we're done. This is because RemoteExec only does four concurrent SSH connections, so if we wanted to
		// do this the easy, synchronous way, we never could run more than four tests at the same time.
		$command = <<<COMMAND
(
  exec &> /dev/null < /dev/null
  setsid
  while true; do
    echo 3 > /proc/sys/vm/drop_caches
    sleep 1
  done &
  flush=\$!
  image_speedcheck --start $start --console $modeOption --file "$image" > "/tmp/speedcheck-$id"
  kill \$flush
) &
COMMAND;
		$task = RebootControl::runScript($clients, $command);
		return $task['id'] ?? null;
	}

	/**
	 * @return array{cpu: array, net: array}
	 */
	public static function parseBenchLine(string $line): array
	{
		$out = ['cpu' => [], 'net' => []];
		foreach (explode(',', $line) as $elem) {
			$elem = explode('+', $elem);
			$out['net'][] = ['x' => (int)$elem[0], 'y' => (int)$elem[1]];
			//$out['cpu'][] = ['x' => $elem[0], 'y' => $elem[2]];
		}
		return $out;
	}

}