組み込み開発徒然日記3 CPU負荷が高すぎる!?
はじめに
組み込みエンジニアとして働く中で、点と点を線、面にしようと思って始めた本シリーズですが、CPU負荷に関して焦点を当てたいと思います。
今回は新たに獲得した知識というよりも、負荷試験において原因特定のために試行錯誤してみたので、その備忘となります。
CPU負荷の低減は組み込み機器だけでなく、クラウドシステムでもスケーリングはできてもコストがかかるので極力負荷を低減したい等の理由もあり共通の課題だと思います。
今回は負荷試験を行った際に気づいた課題や手法に関してまとめたいと思います。
前提条件
今回はShizen Connectで開発しているエッジデバイスであるShizen BoxのうちShizen Box 1 Industrialを対象に試験を行いました。
Shizen Box 1 Industrialはハードウェアとして、アットマークテクノ社製 「Armadillo-IoT G3」を使用しています。
Armadillo G3はArm Cortex-A7(996MHz)デュアルコアのSoC「i.MX 7Dual」(NXPセミコンダクターズ製)を採用しています。
目的
ここでは以下の様な点を目的として調査を行いました。
- どのくらいの接続台数まで安定した動作を維持できるかを確認すること
- 負荷の増加に応じて、CPU負荷を示す指標がどのように増加していくかを調査すること
CPU負荷を確認する上での指標やツールに関して
CPU使用率
CPU負荷の指標としてはどのようなOSでもCPU使用率はまず確認すると思います。
CPU負荷に関しては、どの程度スパイク的に増えるかや、どの程度余裕を持つ設計とするかによると思いますが、
常時80%や90%等高水準のCPU使用率となっていると、一時的な負荷上昇が生じた際に動作が不安定となってしまう可能性があるため、
適切なバッファーを持たせている必要があります。
ロードアベレージ
LinuxやMacではロードアベレージという指標も合わせて確認します。
ロードアベレージとは実行待ちおよびディスクI/O等の待機中のプロセス数の移動平均であり、CPUコア数程度以下に抑えることが推奨されています。
今回の調査対象であるArmadillo G3はデュアルコアであるため、ロードアベレージは2.0以下に抑えることが理想となります。
CPU負荷を確認するツール
他にもあるかとは思いますが、CPU負荷を調査する際の代表的なツールは以下の通りです。
Windows:タスクマネージャー
CPU使用率の確認はWindowsではタスクマネージャーで行うことができます。なお、Windowsにはロードアベレージに相当する指標はありません。
Linux/Mac : topコマンド
LinuxやMacではtopコマンドを使用することで、以下の様な内容を確認することができます。
top - 20:12:49 up 1:30, 2 users, load average: 0.20, 0.31, 0.23
Tasks: 77 total, 1 running, 76 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.2 us, 0.4 sy, 0.0 ni, 99.4 id, 0.0 wa, 0.0 hi, 0.1 si, 0.0 st
1行目の load average: に続く3つの数字がそれぞれ直近1分・5分・15分のロードアベレージを表しています。
%Cpu(s) に続く各指標の意味は以下の通りで、それぞれCPU時間の割合を表しています。
| 項目 | 意味 |
|---|---|
| us | ユーザーのアプリによる計算などのユーザープロセスで使用した時間 |
| sy | ファイル操作や、ネットワーク通信などシステムプロセスで使用した時間 |
| ni | nice値と呼ばれる、処理の優先度を変更したプロセスが使用した時間 |
| id | CPUが何もしていない時間 |
| wa | ファイルの読み書きを待機している時間 |
| hi | ハードウェアからの割り込みに使用した時間 |
| si | ソフトウェアからの割り込みに使用した時間 |
| st | 仮想環境以外ではあまり関係ないが、ホスト側に奪われた時間 |
Linux : sar
CPUやメモリの使用率を設定に従った間隔で取得、出力するツールとなります。
そのため、現在の状態だけでなく、過去の記録もさかのぼって確認を行うことができます。
こちらはsysstatというパッケージに含まれているコマンドとなります。
標準ではインストールされていないので、各ディストリビューションのパッケージマネージャーにてインストールを行ってください。
調査で見つかった課題
Shizen BoxはEMSとして蓄電池やPCS等のモニタリングと制御を行います。その性質上、接続台数を増やすことが簡単かつ重要な評価軸となると考え、接続台数を変化させながら調査を行いました。
接続台数の増加に伴う非線形な負荷の上昇
通常使用している範囲では多少接続デバイス数が増減した場合でもCPU負荷が大きく変化することはなく、問題のある値を示すこともありませんでした。
しかし、今回の試験において実運用上接続しうるデバイス数を超えて設定を行ったところ、明らかに非線形な負荷の上昇がみられました。
調査したところ、ループ処理において計算量がO(n2)となる処理を行っていることが分かりました。
デバイス数が少ないうちは通常動作している他の処理に埋もれていましたが、今回の調査のように接続台数を過度に増やしたことでO(n2)の非効率な処理が顕在化したと思われます。
ビッグオー記法
計算量をO(n)やO(n log n)等であらわすことはビッグオー記法と言い、入力nが大きくなるにつれて計算量がどのオーダーで増加するかを表します。
O(1)であれば、入力数に関わらず処理が一定であることを表し、O(n)であれば、入力数に比例する処理が発生することを示します。
O(n2)は非効率な処理量と評されることもあり、同様の結果をO(nlogn)で実現できるアルゴリズムがあれば、
効率的な処理となり多くの場合で推奨されています。
デバイスとの非接続状態での周期的な高負荷
多くの機器を登録しているが、Shizen Boxの対向デバイスから応答がない状況での試験を行いました。
この状況では、Shizen Boxから通信を行おうとするため、その点の負荷は変わりませんが、
機器から取得したデータを処理する部分ではほとんど負荷になっていないと考えられました。
しかし、データを処理する機能が動作したタイミングで明らかに負荷が上昇している様子が見られました。
この原因を確認したところ、登録機器数に比例した回数だけlocaltime_rやmktime等カーネルへのシステムコールを伴う処理が呼ばれていることが分かりました。
本来はシステムコールを使わず、算術演算のみで完結できる処理でした。
通常の台数では大きな負荷にはなりません。また、機器台数が増えた状態で正常に通信できている場合は、データ処理部分の負荷が支配的となるため、このような問題には気づきにくい側面があります。
一見問題ないと思われる処理であっても意外な負荷源になり得るという点は、新しい気付きでした。
システムコール
ファイルの読み書き、通信等カーネルに処理をさせたいときに呼び出されるものです。
このシステムコールを受けて、カーネルは依頼された処理を行います。
アプリケーションからカーネルに処理を渡して実行してもらう、という流れがあるため、
アプリケーション上で完結する算術処理に比較すると比較的重い処理となっています。
所感と今後の展望
通常の使用においては問題のない実装であっても、負荷テストを行ってみると非効率な実装があぶりだされるため、
将来的に接続台数が増えた場合でも安定的な動作を担保するために定期的な負荷テストは重要だと改めて思いました。
今後改善を行ったうえで改めて負荷試験を行い、高負荷状態での安定性が向上することを確認したいと思います。