def Run()

in perfkitbenchmarker/linux_benchmarks/dpdk_testpmd_benchmark.py [0:0]


def Run(benchmark_spec: bm_spec.BenchmarkSpec) -> list[sample.Sample]:
  """Runs DPDK benchmarks.

  Args:
    benchmark_spec: The benchmark specification.

  Returns:
    A list of sample.Sample objects with the performance results.

  Raises:
    RunError: A run-stage error raised by an individual benchmark.
  """
  client_vm, server_vm = benchmark_spec.vms[:2]

  metadata = {
      'dpdk_burst': _DPDK_BURST.value,
      'dpdk_num_forwarding_cores': _DPDK_NB_CORES.value,
      'dpdk_forward_mode': _DPDK_FORWARD_MODE.value,
      'dpdk_txpkts': _DPDK_TXPKTS.value,
      'dpdk_txq': _DPDK_TXQ.value,
      'dpdk_rxq': _DPDK_RXQ.value,
      'dpdk_test_length': _DPDK_TEST_LENGTH.value,
  }

  dpdk_cmd = 'sudo dpdk-testpmd'

  client_cmd = (
      dpdk_cmd
      + f' -a {client_vm.secondary_nic_bus_info}'
      f' -l 0-{_DPDK_NB_CORES.value} --'
      f' --forward-mode={_DPDK_FORWARD_MODE.value[0]}'
      f' --tx-ip={client_vm.internal_ips[1]},{server_vm.internal_ips[1]}'
      f' --txpkts={_DPDK_TXPKTS.value}'
      f' --txq={_DPDK_TXQ.value}'
      f' --rxq={_DPDK_RXQ.value}'
      f' --nb-cores={_DPDK_NB_CORES.value}'
      f' --burst={_DPDK_BURST.value}'
      ' -i'
  )
  if client_vm.CLOUD == 'AWS':
    client_cmd += f' --eth-peer=0,{server_vm.secondary_mac_addr}'

  if _DPDK_TXONLY_MULTI_FLOW.value:
    client_cmd += ' --txonly-multi-flow'

  server_cmd = (
      dpdk_cmd
      + f' -a {server_vm.secondary_nic_bus_info}'
      f' -l 0-{_DPDK_NB_CORES.value} --'
      f' --txq={_DPDK_TXQ.value}'
      f' --rxq={_DPDK_RXQ.value}'
      f' --nb-cores={_DPDK_NB_CORES.value}'
      f' --forward-mode={_DPDK_FORWARD_MODE.value[1]}'
      f' --burst={_DPDK_BURST.value}'
      ' -i'
  )

  remote_stdout_stderrs = background_tasks.RunParallelThreads(
      [
          (
              lambda vm_: _CreateRemoteCommand(
                  vm_,
                  server_cmd,
                  _DPDK_TEST_LENGTH.value
                  + 10,  # Ensure server stops after client.
              ),
              [server_vm],
              {},
          ),
          (
              lambda vm_: _CreateRemoteCommand(
                  vm_, client_cmd, _DPDK_TEST_LENGTH.value
              ),
              [client_vm],
              {},
          ),
      ],
      max_concurrency=2,
      post_task_delay=5  # Ensure server starts before client.
  )

  output_samples = []
  server_stdout = remote_stdout_stderrs[0][0]
  client_stdout = remote_stdout_stderrs[1][0]

  tx_packet_last_match = re.findall(
      r'(TX-packets):[\s]+([0-9]+)[\s]+(TX-dropped):[\s]+([0-9]+)[\s]+',
      client_stdout,
  )[-1]
  rx_packet_last_match = re.findall(
      r'(RX-packets):[\s]+([0-9]+)[\s]+(RX-dropped):[\s]+([0-9]+)[\s]+',
      server_stdout,
  )[-1]

  for match in [
      tx_packet_last_match,
      rx_packet_last_match,
  ]:
    if not match:
      raise errors.Benchmarks.RunError('Failed to parse output.')
    (
        packets_label,
        packets_val,
        dropped_label,
        dropped_val,
    ) = match
    output_samples.extend([
        sample.Sample(packets_label, int(packets_val), 'packets', metadata),
        sample.Sample(
            packets_label + '-per-second',
            int(packets_val) // _DPDK_TEST_LENGTH.value,
            'packets/s',
            metadata,
        ),
        sample.Sample(dropped_label, int(dropped_val), 'dropped', metadata),
    ])
  tx_pps = None
  rx_pps = None
  for output_sample in output_samples:
    if output_sample.metric == 'TX-packets-per-second':
      tx_pps = output_sample.value
    elif output_sample.metric == 'RX-packets-per-second':
      rx_pps = output_sample.value
  if tx_pps is None or rx_pps is None:
    raise errors.Benchmarks.RunError('TX or RX packets-per-second not found.')
  output_samples.extend([
      sample.Sample(
          'packet-loss-per-second', tx_pps - rx_pps, 'packets/s', metadata
      ),
      sample.Sample(
          'packet-loss-rate', (tx_pps - rx_pps) / tx_pps, 'rate', metadata
      ),
  ])

  return output_samples