この記事はPython Advent Calendar 2023 シリーズ3 21日目の投稿です。
概要
NVIDIAが開発、公開してるNSight Systemsというプロファイラーを利用して測定した結果を集計する時にExcelで集計しやすい形式に変換するツールを実装します。
事の起こり
業務でGPUアプリケーション(AIモデル)の性能測定を行っています。測定にはNSight Systemsを利用しています。このプロファイラーはなかなか優れ物で、機能も豊富、動作は鈍重、ということでGPUを利用するアプリケーションの性能測定には必須のツールです。GPUを搭載したサーバーで測定を実施後、自分の端末に結果ファイルをダウンロードしてGUIアプリケーション上で結果を見ている時に、CUDA GPU Kernel Summary等の数値を見たい時に、以下のウィンドウで数値を確認出来ます。
しかし、これらの結果数値を集計したい場合に困ったことが有ります。測定結果をクリップボードにコピーしてExcelにペーストすることが出来るのですが、以下の測定結果例からも分かる様に数値に単位が付いた状態になっています。この状態ではExcelでの集計に難儀します。。。集計しやすいフォーマットに編集するツールをPythonで実装すれば集計が楽になるだろうと思いました。どこか遠くから「サーバー上でnsysコマンドで*.nsys-repファイルを読み込んで。。。」という声が聞こえてきますが、再度コマンドを叩くなど面倒くさいことは出来ませんので何も聞かなかったことにします。
Time Total Time Instances Avg Med Min Max StdDev Name
13.8% 3.546 s 12657 280.184 μs 35.872 μs 20.896 μs 7.548 ms 615.988 μs ampere_sgemm_128x128_nn
10.3% 2.628 s 4038 650.846 μs 110.624 μs 4.193 μs 2.162 ms 825.565 μs void implicit_convolve_sgemm<float, float, (int)128, (int)5, (int)5, (int)3, (int)3, (int)3, (int)1, (bool)0, (bool)0, (bool)1>(int, int, int, const T1 *, int, T2 *, const T1 *, kernel_conv_params, unsigned long long, int, float, float, int, const T2 *, const T2 *, bool, int, int)
7.4% 1.894 s 2452 772.585 μs 654.246 μs 111.233 μs 17.555 ms 879.154 μs cudnn_infer_ampere_scudnn_128x64_relu_small_nn_v1
6.8% 1.736 s 2449 709.030 μs 543.556 μs 125.697 μs 17.277 ms 799.326 μs cudnn_infer_ampere_scudnn_128x128_relu_medium_nn_v1
6.4% 1.640 s 64 25.621 ms 4.978 ms 89.153 μs 344.814 ms 64.745 ms void cudnn::cnn::conv2d_grouped_direct_kernel<(bool)0, (bool)1, (bool)0, (bool)0, (bool)0, (bool)0, (int)0, (int)0, int, float, float, float, float, float, float>(cudnn::cnn::GroupedDirectFpropParams, const T11 *, const T13 *, T12 *, T14, T14, const T14 *, const T14 *, const T12 *, const T15 *, cudnnActivationStruct)
6.2% 1.579 s 19680 80.226 μs 25.825 μs 1.920 μs 436.131 μs 101.918 μs void tensorflow::functor::ShuffleInTensor3Simple<float, (int)2, (int)1, (int)0, (bool)0>(int, const T1 *, tensorflow::functor::Dimension<(int)3>, T1 *)
5.8% 1.475 s 101784 14.487 μs 4.128 μs 1.472 μs 782.022 μs 76.600 μs Mul_GPU_DT_FLOAT_DT_FLOAT_kernel
4.2% 1.066 s 4030 264.429 μs 278.626 μs 15.712 μs 987.111 μs 66.267 μs cudnn_infer_ampere_scudnn_winograd_128x128_ldg1_ldg4_relu_tile148t_nt_v1
環境情報
- Python 3.10.7
- pandas 2.1.4
- openpyxl 3.1.2
実装例
改良の余地は多々有りますが、一応所望の動作がするツールを実装出来たので、使いながら改良をしていくことにします。
import pandas as pd
class NsysConverter:
def __init__(self, file_path: str, sheet_name: str) -> None:
self.file_path = file_path
self.sheet_name = sheet_name
def convert(self, column_name: str) -> None:
print(f'File: {self.file_path}, Sheet: {self.sheet_name}, Column: {column_name}')
file = pd.read_excel(self.file_path, sheet_name=self.sheet_name, header=0)
col_edited = []
for data in file[column_name]:
col_edited.append(self._convert_num(data))
col = f'{column_name}_edited'
file[col] = pd.DataFrame(col_edited)
file.to_excel(self.file_path, index=False)
def _convert_num(self, data: str) -> float:
value, unit = data.split()
value = float(value)
if unit == 's':
return value
elif unit == 'ms':
return value * 0.001
elif unit == 'μs':
return value * 0.000001
else:
raise ValueError(f'Wrong value {value}!')
if __name__ == '__main__':
from argparse import ArgumentDefaultsHelpFormatter, ArgumentParser
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('--file_path', type=str, required=True, help='File path of Nsyight Systems')
parser.add_argument('--sheet_name', type=str, default='Sheet1', help='Sheet name of result file')
parser.add_argument('--column_name', type=str, required=True, help='Target column name for convert')
args = parser.parse_args()
nc = NsysConverter(args.file_path, args.sheet_name)
nc.convert(args.column_name)
実行結果
以下のコマンドでツールを実行してみました。
python nsys_converter.py --file_path nsys_results.xlsx --column_name "Total Time"
下図が実行結果です。改良したい部分は幾つか有りますが、今回はこれで一先ず完成としておきます。
まとめ
今回実装したツールは以下のGitHubで公開しています。
Reference