def METHOD_NAME(self, first_free_cpu):
    """Runs the performance test, using pinning the iperf3 servers to CPUs starting from `first_free_cpu`"""
    assert self._num_clients < CpuMap.len() - self._microvm.vcpus_count - 2
    for server_idx in range(self._num_clients):
        cmd = self.host_command(server_idx).build()
        assigned_cpu = CpuMap(first_free_cpu)
        utils.run_cmd(
            f"taskset --cpu-list {assigned_cpu} {self._microvm.jailer.netns_cmd_prefix()} {cmd}"
        )
        first_free_cpu += 1
    time.sleep(SERVER_STARTUP_TIME_SEC)
    with concurrent.futures.ThreadPoolExecutor() as executor:
        futures = []
        cpu_load_future = executor.submit(
            get_cpu_percent,
            self._microvm.jailer_clone_pid,
            # Ignore the final two data points as they are impacted by test teardown
            self._runtime - 2,
            self._omit,
        )
        for client_idx in range(self._num_clients):
            futures.append(executor.submit(self.spawn_iperf3_client, client_idx))
        data = {"cpu_load_raw": cpu_load_future.result(), "g2h": [], "h2g": []}
        for i, future in enumerate(futures):
            key = REV_MODE_MAP[MODE_MAP[self._mode][i % len(MODE_MAP[self._mode])]]
            data[key].append(json.loads(future.result()))
        return data