Intel Arria10 SoC : 初期性能評価(ベンチマーク実装編)- 浮動小数点配列の整数変換処理 の計測設計
はじめに
本記事は、Arria10初期性能評価の実装面に絞った記録です。
- 対象は、浮動小数点配列を整数(long)配列へ切り捨て変換する処理(
truncate_float_vector_to_long)です。 - 測定対象は演算カーネル単体であり、FMC通信・DMA転送は含みません。
- 目的は「比較可能な条件で、環境差と最適化差を見て、どこへ演算を寄せるべきか判断する」ことです。
この記事の到達点
- 計測コードの設計意図を説明します。
- 比較の公平性を保つための条件を整理します。
- 途中に肝コードを載せ、末尾に全文コードを載せます。
測定対象と比較軸
測定対象
- 関数名:
truncate_float_vector_to_long - 処理内容:
float配列の要素をlongに切り捨て変換 - データ点数:
MEAS_POINT = 200 * 1000
比較軸
- 実行環境
- Intel Arria10 SoC Linux(Angstrom Linux)
- Intel Arria10 SoC ベアメタル
- 参照用PC環境
- コンパイル最適化
| オプション | 位置づけ | 補足 |
|---|---|---|
-O0 |
最適化なし | デバッグビルド向け。実行速度は最も遅いです。 |
-O1 |
基本的な最適化 | 実行時間を短縮しますが、コンパイル負荷は比較的軽めです。 |
-O2 |
バランス型の最適化 | 実用的な高速化を狙う標準的な比較候補です。 |
-O3 |
積極的な最適化 | コード展開やループ最適化を含み、実行速度を優先します。 |
-ffast-math |
浮動小数点高速化 | IEEE 準拠を一部緩めて速度を優先します。 |
-Ofast |
最速指向 |
-O3 と -ffast-math を含む、高速化を強く狙う設定です。 |
実装の肝1: 演算ループ
比較の中心は、このループです。
for(i = 0; i < n; i++) {
iy[i * iys] = (long)(u[i * ius]);
}
ポイント:
- 変換コストを純粋に見るため、処理は1行に限定しています。
-
ius/iysをパラメータ化して、配列ステップを変更できる構造にしています。
実装の肝2: 計測ループ
単発計測では誤差が出るため、反復実行で平均化しています。
int cnt = 200;
clock_t start, end;
start = clock();
for (i = 0; i < cnt; i++)
truncate_float_vector_to_long(_u, _ius, _iy, _iys, _n);
end = clock();
printf("one time = %.10lfusec\n", (double)(end - start) / CLOCKS_PER_SEC * 1000000.0 / cnt);
ポイント:
-
cnt回の合計時間を取り、1回あたりへ換算しています。 - 測定値は
usecとmsecを両方出力して確認しやすくしています。
この計測の流れを図にすると、次のようになります。
本記事の範囲
本記事は、演算カーネル単体の計測方法に絞っています。
- ここで扱う: ループ本体、反復回数、最適化オプション差の取り方
- ここで扱わない: AD入力、FMC通信、DMA転送、割り込み、キャッシュ条件差
この計測を入れている理由は、最終的に HPS 側の CPU0 へベアメタル演算を寄せ、CPU1 側 Linux へは結果受け渡しを寄せる構成が妥当かを判断する材料にしたいためです。
結果の読み解き(Linux/ベアメタル差の解釈や改善率の評価)は、結果解析編で扱います。
比較時に固定した条件
- 同一コードを環境ごとにビルド
- 同じ入力点数で実行
- 最適化オプションだけを切り替え
- 余計な処理(ログ大量出力など)を計測区間に入れない
測定手法の注意
clock() はCPU時間ベースであり、壁時計時間とは一致しない場合があります。
そのため、本記事の結果は「同一手法内での相対比較」として扱います。
より厳密な評価では、次の追加が有効です。
- 単調増加クロック(高分解能タイマ)の併用
- ウォームアップ実行を含めた計測
- キャッシュ影響を変えた条件セットの追加
まとめ
- 比較の本体は「変換ループ」と「反復平均の計測ループ」です。
- ベンチマーク実装は、条件固定と計測区間の明確化が重要です。
- 本実装は、結果解析編と実行基盤編へつなぐ一次評価の土台です。
付録: float配列をlong配列へ切り捨て変換する関数の掲載コード全文
#include <stdio.h>
#include <time.h>
#define MEAS_POINT (200*1000)
void truncate_float_vector_to_long(float *u, long ius, long *iy, long iys, long n);
/*!
* @brief
* 機能説明
* truncate_float_vector_to_long() は実数配列の小数点以下を切捨てて整数(long)に変換します。
*
* @param[in] u 入力実数配列。
* @param[in] ius 実数配列 u のステップ。
* @param[out] iy 出力整数配列。
* @param[in] iys 整数配列 iy のステップ。
* @param[in] n 演算数。
*/
void truncate_float_vector_to_long(float *u, long ius, long *iy, long iys, long n) {
long i = 0;
for(i = 0; i < n; i++) {
iy[i * iys] = (long)(u[i * ius]);
}
}
/// メイン関数
int main(int argc, char** argv) {
printf("TRUNCATE_FLOAT_VECTOR_TO_LONG Exec !\n");
float _u[MEAS_POINT] = { 1000.1123 };
long _iy[MEAS_POINT] = { 0 };
long _ius = 1;
long _iys = 1;
long _n = MEAS_POINT;
// input dummy
int i = 1;
for (i = 1; i < MEAS_POINT; i++)
_u[i] = 0.1 + i;
int cnt = 200;
clock_t start,end;
start = clock();
for (i = 0; i < cnt; i++)
truncate_float_vector_to_long(_u, _ius, _iy, _iys, _n);
end = clock();
printf("one time = %.10lfusec\n", (double)(end - start) / CLOCKS_PER_SEC * 1000000.0 / cnt);
printf("one time = %.10lfmsec\n", (double)(end - start) / CLOCKS_PER_SEC * 1000.0 / cnt);
printf("total time = %.10lfmsec\n", (double)(end - start) / CLOCKS_PER_SEC * 1000.0);
return 0;
}
関連記事
- 前の記事
- 次の記事
- 【future】
- 実行基盤編: Linux運用性とベアメタル性能のトレードオフ整理