• <xmp id="om0om">
  • <table id="om0om"><noscript id="om0om"></noscript></table>
  • 數據中心/云端

    測量多流工作負載的 GPU 占用率

    隨著新一代產品的推出, NVIDIA GPU 的性能也變得越來越強大。這種提升通常有兩種形式。每個流多處理器 (SM) (GPU 的主力) 都可以更快地執行指令,而內存系統可以以越來越快的速度向 SM 傳輸數據。

    與此同時,SM 的數量通常也會隨著每一代的增加而增加,這增加了 GPU 可以支持的計算并發量。例如, NVIDIA Volta、 NVIDIA Ampere 和 NVIDIA Hopper GPU 分別支持 80、108 和 132 個 SM。

    在某些情況下,不斷增長的并發可能會帶來一個挑戰。在 GPU 上運行的工作負載必須公開相應的并發級別,才能使 GPU 資源得到充分利用。為此,一種常見的方法是使用多個流向 GPU 發送獨立的任務,或者類似地,使用 CUDA 的多進程服務

    本文介紹了一種確定這些方法是否成功占用 GPU 的方法。

    在 Santa Clara,我們遇到了一個問題,

    我們的 NVIDIA Nsight Systems 性能分析工具可用于確定稱為核函數的工作塊是否在 GPU 上執行。流通常包含一系列依次運行的核函數。每個流可以在其自己的 Nsight Systems 時間軸上查看,從而揭示不同流中的核函數之間的重疊。例如,圖 1 中的標記為“Stream 15”到“Stream 22”的行展示了重疊的核函數。

    This snapshot from Nsight Systems shows a close-up of timelines of partially overlapping kernel executions in 8 independent streams, in addition to a single, aggregated timeline of kernel executions in all 8 streams.
    圖 1.8 流工作負載的 Nsight Systems 時間線特寫

    或者,所有流都可以顯示在單個時間軸上,這樣可以全面了解 GPU 在執行工作負載期間的使用頻率 (圖 1,行標記為“所有流”)。

    標準 Nsight Systems 時間軸無法立即顯示 GPU 的 SM 數量。您可以在彈出視圖中突出顯示特定內核并檢查其屬性,包括每個線程塊中的線程數、網格大小 (屬于內核的線程塊總數),甚至理論占用率 (一個 SM 上可以容納的線程塊的最大數量)。

    您可以通過這些屬性計算執行內核所需的 SM 數量。如果該數量不是 GPU 上 SM 總數的整數倍,則可以將任何剩余的 SM (內核的“tail”) 分配給一個或多個其他內核的線程塊。

    通過使用多個流 (本文的重點) 啟用不同內核的并發執行。要概述整個多流工作負載平均使用 GPU 的情況,就需要在所有流的 Nsight Systems 時間軸中拼湊出并發內核的尾部。可以利用 Nsight Systems 的一些特殊功能來快速輕松地完成這個原本不重要的過程。

    通過 GPU 指標采樣來搶險

    工作負載或其特定部分的 Nsight Systems 報告可以標準化的 SQLite 數據庫文件形式提取數據。此 SQLite 文件也可以作為工作負載統計數據的副產品,并使用 Linux 命令 `nsys stats` (在本文中重點介紹 Linux 操作系統,但也可以在 Windows 上獲得類似的結果) 來匯總。

    在 CUDA 工具包 11.4 中引入 Nsight Systems 版本 2021.2.4 后,可以將特殊標志傳遞給工作負載分析命令,以幫助實現預期目標:

    nsys profile --gpu-metrics-device=N

    在這個標志中,N 代表要采樣的多 GPU 節點中 GPU 的序列號。如果您使用的是單個 GPU,則 N 等于 0。

    設置此標志后,Nsight Systems 將在默認頻率 10 KHz 或用戶指定的采樣頻率下記錄正在使用的所有 SM 的百分比(SM 有源)。此數量可以在其自己的時間軸上查看。

    圖 2 展示了特寫示例以及整個應用程序的概述。**源代碼可見**。這有助于更深入地了解 GPU 的使用情況,但需要打開 Nsight Systems 的圖形用戶界面。

    Snapshot of Nsight Systems shows the total application overview of a percentage of SMs in use.
    圖 2.Nsight Systems 總體應用程序概述的時間線
    Snapshot of Nsight Systems zooms into one of the blocks of activity to closer inspect SM utilization.
    圖 3.Nsight Systems 使用的 SM 百分比特寫 (SM 有源)

    最適合此任務的分析工具是 `nsys stats`,但僅使用此命令將僅顯示 CPU 和 GPU 活動的摘要,這可能不足以提供有價值的信息。更詳細的分析需要額外的說明。

    然而,通過數據庫查詢語言 (SQL) 結構化查詢語言,可以從 Nsight Systems 報告衍生的 SQLite 文件中提取所需的所有內容。SQLite 文件在邏輯上被結構化為表的集合,并可以使用簡單的 SQL 命令提取任何表列。與正在使用的 SM 百分比對應的列為 SM Active

    形式上,報告的數量是 SM 活動的平均值。50%可能意味著所有 SM 在 50%的時間內都處于活動狀態,或 50%的 SM 在 100%的時間內處于活動狀態,或者介于兩者之間的任何情況,但實際上,我們先前的定義優先。

    如果您不熟悉 SQL,請利用 Nsight Systems 版本 2023.4 中引入的 DataService 功能。它提供了一個方便的 Python 接口,用于查詢所收集報告中嵌入的 SQLite 數據庫。以下腳本使用 DataService 提取工作負載 SM 活動百分比列表,并導出幾個有用的數量。

    import sys
    import json
    import pandas as pd
    from nsys_recipe import data_service, log
    from nsys_recipe.data_service import DataService
     
    # To run this script, be sure to add the Nsight Systems package directory to your PYTHONPATH, similar to this:
    # export PYTHONPATH=/opt/nvidia/nsight-systems/2023.4.1/target-linux-x64/python/packages
     
    def compute_utilization(filename, freq=10000):
        service=DataService(filename)
        table_column_dict = {
            "GPU_METRICS": ["typeId", "metricId", "value"],
            "TARGET_INFO_GPU_METRICS": ["metricName", "metricId"],
            "META_DATA_CAPTURE": ["name", "value"]
        }
        hints={"format":"sqlite"}
        df_dict = service.read_tables(table_column_dict, hints=hints)
        df = df_dict.get("GPU_METRICS", None)
        if df is None:
            print(f"{filename} does not contain GPU metric data.")
            return
        tgtinfo_df = df_dict.get("TARGET_INFO_GPU_METRICS", None)
        if tgtinfo_df is None:
            print(f"{filename} does not contain TARGET_INFO_GPU_METRICS table.")
            return
        metadata_df = df_dict.get("META_DATA_CAPTURE", None)
        if metadata_df is not None:
            if "GPU_METRICS_OPTIONS:SAMPLING_FREQUENCY" in metadata_df['name'].values:
                report_freq = metadata_df.loc[ metadata_df['name']=='GPU_METRICS_OPTIONS:SAMPLING_FREQUENCY']['value'].iat[0]
                if isinstance(report_freq, (int,float)):
                    freq = report_freq
                    print("Setting GPU Metric sample frequency to value in report file. new frequency=",freq)                
          
        possible_smactive=['SMs Active', 'SM Active', 'SM Active [Throughput %]']
        smactive_name_mask = tgtinfo_df['metricName'].isin(possible_smactive)
        smactive_row = tgtinfo_df[smactive_name_mask]
        smactive_name = smactive_row['metricName'].iat[0]
        smactive_id = tgtinfo_df.loc[tgtinfo_df['metricName']==smactive_name,'metricId'].iat[0]
        smactive_df = df.loc[ df['metricId'] == smactive_id ]
          
        usage = smactive_df['value'].sum()
        count = len(smactive_df['value'])
        count_nonzero = len(smactive_df.loc[smactive_df['value']!=0])
        avg_gross_util = usage/count
        avg_net_util = usage/count_nonzero
        effective_util = usage/freq/100
          
        print(f"Avg gross GPU utilization:\t%lf %%" % avg_gross_util)
        print(f"Avg net GPU utilization:\t%lf %%" % avg_net_util)
        print(f"Effective GPU utilization time:\t%lf s" % effective_util)
        return metadata_df
          
    if __name__ == '__main__':
        if len(sys.argv)==2:
            compute_utilization(sys.argv[1])
        elif len(sys.argv)==3:
            compute_utilization(sys.argv[1], freq=float(sys.argv[2]))

    如果將所有百分比的總和(Sp)以及樣本數量(Ns)相除,則得到在整個工作負載期間使用的所有 SM 的平均百分比。這種平均百分比被稱為GPU 總利用率

    這可能正是所需的結果,但通常工作負載包含一些完全沒有啟動內核的部分。例如,數據從主機 CPU 復制到 GPU 時。通過自動監控采樣點的 SM 使用百分比是否大于零(讓該樣本數 Nsnz)和計算 Sp/Nsnz 在可測量的內核執行期間提供 SM 的平均使用百分比。我們將其稱為 *GPU 凈利用率*。

    最后,對于特定工作負載或部分工作負載,計算在壓縮所有樣本后 GPU 的有效使用時間可能很有用。例如,如果樣本顯示在 5 秒內 SM 利用率為 40%,則 GPU 的有效利用率為 0.4 × 5 秒 = 2 秒。可以將此時間與執行相關內核的 Nsight Systems 時間軸的持續時間進行比較。讓該持續時間代表深度學習,并讓有效 GPU 利用率的總和代表 Sdt/Dt,其中 Sdt 是相關窗口中的 SM 利用率,而 Dt 是窗口的持續時間。

    舉個例子

    以下場景展示了這三個量的效用,并將其應用于逼真的工作負載 (圖 4)。

    This snapshot from Nsight Systems shows an aggregated timeline of kernel executions of an entire workload, which reveals 5 concentrated windows of GPU activity, separated by periods of no GPU activity.
    圖 4.Nsight Systems 工作負載時間軸示例

    數量 Sp/Ns 表示在整個工作負載中使用 SM 的平均百分比,由圖 4 中的開放、黑色和雙頭箭頭表示,包括在沒有 SM 活動時圍繞密集的藍色內核執行塊的六個周期。對于此工作負載,該百分比為 70%。

    數量 Sdt/時間 = 100 表示在 GPU 繁忙時間使用 SM 的平均百分比,由圖 4 中的實心、紅色雙頭箭頭表示。這包括五個繁忙窗口中的短嵌入式部分,當時暫時沒有執行核函數(在表示整個工作負載的圖的比例上不可見)。對于此工作負載,該百分比為 77%。

    數量 Sp/Nsnz 表示在 Nsight Systems 確定至少有一個 SM 處于忙碌狀態時使用的 SM 的平均百分比。此百分比忽略了五個 GPU 忙碌期間沒有 SM 活動的任何短嵌入式周期。對于此工作負載,該百分比為 79%,

    未來

    NVIDIA 分析工具持續添加新功能。例如,最近的 NVIDIA 分析工具開發版本引入了新的,使分析集群級應用程序和性能回歸研究變得更輕松。

    NVIDIA 正在關注通過流行的 Python 腳本語言提供對 Nsight System GPU 性能詳細信息的訪問,以消除學習 C 或 SQL 等其他語言的需求。Nsight Systems 功能的其他近期新增功能包括:統計分析專家系統分析

    結束語

    對此示例工作負載的分析表明,在某些時間段內,SM 完全不使用,但總體 SM 空閑時間有限。

    在 SM 繁忙窗口期間,GPU 相當飽和,特別是考慮到網格和線程塊的大小差異很大,一些網格僅包含單個線程塊,因此只能占用單個 SM.因此,構成工作負載的多個流能夠很好地提高 GPU 利用率。

    我們毫不費力地得出了這一見解。用于確定本文中提到的三個利用率指標的 Python 腳本假設用戶為舊版 Nsight Systems 獲取的輸入報告明確提供采樣頻率,允許此類版本采用 10 KHz 的默認值,或者可以從較新版本 Nsight Systems 的輸入報告中提取樣本頻率。

    SM 利用率高并不意味著 SM 得到了高效利用。由于各種原因,在 SM 上執行的內核可能會出現嚴重甚至極端停滯。SM 利用率高的唯一事實是,大多數 GPU 的 SM 在大多數時候都處于活動狀態,這是獲得良好性能的前提。

    有關更多信息,請參閱以下資源:

    ?

    +1

    標簽

    人人超碰97caoporen国产