iperfに関するTips集

# はじめに
以前公開したiperf3を用いた測定方法に関する記事が、いいねやストックをもらえるようになったので、別記事で公開すると言ったTips集を公開します。

前回の記事:

https://qiita.com/Nenshu_agetai/items/743ac5e785b759bd0720

# 本記事の内容
- 実際に使うときはこういう使い方が多いという用法集
- いつも同じ様な事を調べているので覚書に近いかも
- そのほか、何か役に立ちそうなこと

:::note warn
注意
筆者の実務経験に基づき、時に調べて書いていきますが誤りを含む可能性があります。
適宜、指摘いただければ修正します。
:::

# 目次
1. [UDPでは終わり際に気をつける](#1UDPでは終わり際に気をつける)
2. [ファイルと標準出力を同時にやる](#2ファイルと標準出力を同時にやる)
3. [データ解析に役立つTips](#3データ解析に役立つTips)
4. [ぼくのかんがえたさいきょうのiperfコマンド](#4ぼくのかんがえたさいきょうのiperfコマンド)

# 1.UDPでは終わり際に気をつける
UDPで`--get-server-output`オプションを活用する場合、測定の最後に結果のやり取りが発生します。ここで、**通信環境が極端に悪いと測定結果がバグる**という話です。

はじめにおさらいをします。

- UDPでは受信側への到達確認を行わない
- 送信側は、とにかく指定された量のデータを送信し続ける
- 10Mbpd指定だと、**送信側の記録は常に10Mbpsとだけ記録される**
- 結果的に**受信側しか実際の通信帯域を記録しない**

※受信側は最終的に何Mbps分のデータが届いたかが分かり、実帯域が記録される

なので`--get-server-output`オプションをつけましょう。

- `--get-server-output`はサーバ/クライアント双方のデータ取得を行う
- 測定完了時にクライアントがサーバの結果を取り寄せる
- 結果は同一の出力に保存され解析が楽になる

```bash
iperf3 -t 10 -u -c localhost -b 20M --get-server-output
```

本題の注意点です。端的に言うと、**通信環境が悪いと、サーバ側の結果を取り寄せるときにエラー=取り寄せ失敗になる**場合があります。

- 実測定では**環境が悪いところで測定することが多い**
- 通信環境が悪すぎると、**タイムアウト/エラーなどが発生して結果が取り寄せられない**ことがある

:::note 
わざわざ環境が良いところで性能は測らないですよね
なんか速度が出ない、みたいなときに測ります
:::

以下の図はイメージです。

```plantuml
Client->Server: Control Port Open (TCP 3way Handshake)
Client<-Server: OK
Client->Server: Sending Measurmeant Data...
activate Client
activate Server
Client->Server: Sending Measurmeant Data...
...
Client->Server: Sending Measurmeant Data...
Client->Server: Measurmeant End
deactivate Client
deactivate Server
Client ->x Server: Request Result Data
note right : 送受信どちらかでエラー発生
Client x<- Server: Result Data
note left : 結果が届かない
```

上記が発生すると何が不便かと言うと…
- サーバの結果を含むデータと含まないデータが混ざる。結果を解析するときに場合分けが必要。
- サーバの結果を手動で書き写す必要がある。

ということで、私は`--get-server-output`オプションを使う際には以下を実践しています。
- 移動しながら測定をする場合(無線通信など)は測定完了時間が近づくと通信環境の良い場所に移動する。
- 環境が著しく悪い場合には`--get-server-output`オプションをあえて用いない
- 10秒程度のリハーサルを行い正常取得を確認する

:::note warn
注意
**通信環境の悪化は外部要因だけでなくiperf3の設定次第でも発生します。**
例：本来10Mbpsしか流せない経路に1Gbpsをぶち込む
この場合、間違いなく通信バッファが溢れます。
この状態で結果のやり取りをすると、バッファが詰まって結果が届かないこともあります。
:::

# 2.ファイルと標準出力を同時にやる
:::note warn
注意
Linux限定のTipsです。Windowsの人すみません…。
:::
測定後に結果の解析が必要になる場合があります。この場合、ファイルに結果を出力することになりますが、iperfでは意外と曲者です。

## 単純にiperfの結果をファイル出力する
コマンドで出力先をresult.txt にします。
```shell
iperf3 -t 10 -u -c localhost -b 20M --get-server-output > result.txt 
```
実際にやると分かりますが、測定時に画面の出力を見れません。
```sh
abc@abcde: iperf3 -u -c localhost -b 20M --get-server-output > result.txt
*** ここにログが出てほしいのに！（出ない） ***
```
result.txtもリアルタイムで更新されず、タイムラグの上、ファイルに書き込みされます。
つまり、**単純なファイル出力では、不備を測定中に確認できません。**

## iperfでファイルと標準出力を同時にやる方法
まず、teeコマンドでファイルと標準出力に分岐させます。
```shell
iperf3 -u -c localhost -b 20M --get-server-output | tee result.txt
```
これで**測定完了後に**、画面に出力が出るようになりました。いやいや、**リアルタイムに出力を見たいのですが…。**

ではなぜ、リアルタイムに画面出力されないのか。それは、バッファリングの上、まとめて結果を出そうとするからです。

以上の理由から、バッファリングを制御するコマンド(stdbuf)をつけます。
```shell
stdbuf -o 0 iperf3 -u -c localhost -b 20M --get-server-output | tee result.txt
```
※-o は出力のバッファリング設定。0にすることでバッファリングをしない。

このコマンドを実行すると、**リアルタイムに結果が画面出力されました**。 目標達成です！

# 3.データ解析に役立つTips
データを解析に回す観点から2点ほどのTipsです。

## Tips1: 詳細なログ出力には -V を使う
ログ解析をする上で、情報は多いに越したことはありません。
取得日時や取得条件など、記録は多いほど良いと思います。

iperfにも詳細なログを残す -V オプションが存在します。
```shell
iperf3 -u -c localhost -b 20M -V --get-server-output
```

:::note warn
注意
Windows版とLinux版で出力が違う
:::

**Windowsの場合**
```shell
iperf 3.1.3
CYGWIN_NT-10.0 *********
Time: Thu, 28 Dec 2023 03:46:54 GMT
Connecting to host localhost, port 5201
      Cookie: *********
[  4] local ::1 port 58139 connected to ::1 port 5201
Starting Test: protocol: UDP, 1 streams, 8192 byte blocks, omitting 0 seconds, 10 second test
```

**Ubuntuの場合**
```sh
iperf 3.9
Linux Ubuntu22 5.19.0-46-generic #47~22.04.1-Ubuntu SMP PREEMPT_DYNAMIC Wed Jun 21 15:35:31 UTC 2 x86_64
Control connection MSS 32768
Setting UDP block size to 32768
Time: Thu, 28 Dec 2023 03:42:10 GMT
Connecting to host localhost, port 5201
      Cookie: y77jy4yauxuc6u3jrargcpkfol7oqc2mtwpu
      Target Bitrate: 20000000
[  5] local 127.0.0.1 port 32786 connected to 127.0.0.1 port 5201
Starting Test: protocol: UDP, 1 streams, 32768 byte blocks, omitting 0 seconds, 10 second test, tos 0
```

解析時は、これらの情報を活用して測定条件などを特定しましょう。
ただし、コマンドは詳細な条件が記載されるため、記録した方が良いと思います。

## Tips2: タイムスタンプが欲しい場合
iperfの結果単体で解析をすることは稀です。基本的には、他の現象とスループットの変化を紐づけて解析を行うと思います。

この時、重要なのはタイムスタンプです。測定機器間で時刻を同期しておき、タイムスタンプを用いて他の現象とスループットの変化を紐づけます。

このため、タイムスタンプが欲しいですが、iperfはデフォルトで測定した時刻が出力されません。

私はファイル名にタイムスタンプをつけることで、測定時刻を記録しています。
```sh
iperf3 -u -c localhost -b 20M -V --get-server-output | tee $(date +%Y%m%d%H%M%S)_result.txt
```
※dateコマンドを利用。 date +format で文字列を出力している。

結果が出力されるファイル名は 20231228130140_result.txt の形になります。結果を解析するときは、以下の手順で実行します。
- iperf結果のファイル名を読み取って、開始時の絶対時刻を取得する
- ファイル内の相対時刻を取得して、毎秒の結果に絶対時刻のタイムスタンプをつける
- 他の結果と絶対時刻を使用して紐づける

このあたりの解析スクリプトは需要がありそうなら、別記事で実例を出したいと思います。

# 4.ぼくのかんがえたさいきょうのiperfコマンド
:::note
本節は完全に悪ふざけです。
:::

ここまでのTipsを経て、これなら間違いないコマンドを最後に残します。※Ubuntuで動作確認済みです。
```shell
stdbuf -o 0 iperf3 -u -c localhost -b 20M -V --get-server-output | tee $(date +%Y%m%d%H%M%S)_result.txt
```

以下ができます。
- UDPで帯域指定したiperf測定
- サーバの結果取得
- ファイル出力をしながらの結果標準出力
- 測定に関する詳細ログの追記
- 出力ファイルにタイムスタンプ付与

# さいごに
意外とiperfの記事を読んでもらえたので書きました。実はみんな同じことで困っているのかもしれないな、と思い細かい話を書いてみました。

遅筆ではありますが、今後もニッチかつやたら細かい記事を書いてみたいな、と思います。