回覆列表
  • 1 # 機器之心Pro

    設定在深入到基準測試和效能分析之前,首先我們需要一個合適的環境。這意味著我們需要為這項任務配置我們的機器和作業系統。我的機器的規格如下:處理器:Intel(R) Xeon(R) CPU E5-2699 v3 @ 2.30GHz記憶體:32GB作業系統:Ubuntu 16.04 LTSKernel:4.4.0-75-generic我們的目標是得到可復現的結果,因此要確保我們的資料不會受到其它後臺程序、作業系統配置或任何其它硬體效能提升技術的影響。讓我們首先從配置用於效能分析的機器開始。

    硬體功能首先,禁用所有硬體效能功能,也就是說要禁用 Intel Turbo Boost 和 Hyper Threading from BIOS/UEFI。正如其官方網頁上說的那樣,Turbo Boost 是“一種在處理器核心執行,並可以在低於功耗、電流和溫度規格限制的情況下允許它們以高於額定頻率的速度執行的技術。”此外,Hyper Threading 是“一種可以更高效地利用處理器資源的技術,能使每個核心都能多執行緒執行。”這都是值得我們花錢購買的好東西。那為什麼要在效能分析/基準測試中禁用它們呢?因為使用這些技術會讓我們無法得到可靠的和可復現的結果。這會讓執行過程發生變化。讓我們看個小例子 primes.py,程式碼故意寫得很糟糕。

    這段程式碼可在 GitHub 上檢視:https://github.com/apatrascu/hunting-python-performance/blob/master/01.primes.py。你需要執行以下命令安裝一個依賴包:

    pip install statistics

    讓我們在一個啟用了 Turbo Boost 和 Hyper Threading 的系統中執行它:

    現在禁用該系統的睿頻加速(Turbo Boost) 和超執行緒(Hyper Threading),然後再次執行這段程式碼:

    看看第一個案例的標準差為15%。這是一個很大的值!假設我們的最佳化只能帶來 6% 的加速,那我們怎麼能將執行過程中的變化(run to run variation)和你的實現的差異區分開?相對而言,在第二個例子中,標準差減少到了大約 0.6%,我們的新最佳化方案效果清晰可見。

    CPU 節能

    禁用所有的 CPU 節能設定,並使用固定的 CPU 頻率。這可以透過在 Linux 功率調節器(power governor)中將 intel_pstate 改成 acpi_cpufreq 而實現。intel_pstate 驅動使用英特爾核心(Sandy Bridge 或更新)處理器的內部調節器實現了一個縮放驅動。 acpi_cpufreq 使用了 ACPI Processor Performance States。下面讓我們先來檢查一下:

    可以看到這裡所使用的調節器被設定成了節能模式,而 CPU 的頻率範圍在 1.20 GHz 到 3.60 GHz 之間。這個設定對日常應用來說是很不錯的,但卻會影響到基準測試的結果。那麼應該給調節器設定什麼值呢?如果我們瀏覽一下文件,我們可以看到我們可以使用以下設定:高效能(performance):以最大頻率執行 CPU節能(powersave):以最小頻率執行 CPU自定義(userspace ):按使用者指定的頻率執行 CPU按需(ondemand ):根據當前負載動態調節頻率。可能跳至最高頻率,空閒時又會降低保守(conservative):根據當前負載動態調節頻率。相比於按需模式,其頻率調節更加漸進我們要使用效能調節器(performance governor),並將頻率設定成 CPU 支援的最大頻率。如下所示:

    現在你已經使用效能調節器將頻率設定成了固定的 2.3 GHz。這是最大的可設定的值,沒有睿頻加速(Turbo Boost),它可以被用在 Xeon E5-2699 v3 上。要完成設定,請使用管理員許可權執行以下命令:

    如果你沒有 cpupower,可使用以下命令安裝:

    sudo apt-get install linux-tools-common linux-header-`uname -r` -y

    功率調節器對 CPU 的工作方式有很大的影響。該調節器的預設設定是自動調節頻率以減少功耗。我們不想要這樣的設定,所以從 GRUB 中禁用它。只需要編輯 /boot/grub/grub.cfg(但是如果你在 kernel 升級上很小心,那麼這將會消失)或在 /etc/grub.d/40_custom 中建立一個新的 kernel 入口。我們的 boot 行中必須包含這個 flag: intel_pstate=disable,如下所示:

    linux /boot/vmlinuz-4.4.0-78-generic.efi.signed root=UUID=86097ec1-3fa4-4d00-97c7-3bf91787be83 ro intel_pstate=disable quiet splash $vt_handoffASLR(地址空間配置隨機發生器)

    這個設定是有爭議的,參見 Victor Stinner 的部落格:https://haypo.github.io/journey-to-stable-benchmark-average.html。當我首次建議在基準測試時禁用 ASLR 時,那是為了進一步提升對那時在 CPython 中存在的 Profile Guided Optimizations 的支援。我為什麼要說這個呢?因為在上面給出的特定硬體上,禁用 ASLR 可以將執行之間的標準差降低至 0.4%。另一方面,根據在我的個人計算機(Intel Core i7 4710MQ )上的測試,禁用 ASLR 會導致 Victor 所提到的同樣的問題。在更小的 CPU(比如 Intel Atom)上的測試會帶來甚至更大的執行間標準差。因為這似乎並不是普遍適用的真理,而且很大程度上依賴於硬體/軟體配置,所以對於這個設定,我在啟用後測量一次,再禁用後測量一次,之後再進行比較。在我的機器上,我透過在 /etc/sysctl.conf. 中加入以下命令禁用了 ASLR。使用 sudo sysctl -p 進行應用。

    kernel.randomize_va_space = 0

    如果你想在執行時禁用它:

    sudo bash -c "echo 0 >| /proc/sys/kernel/randomize_va_space"

    如果你想重新啟用:

    sudo bash -c "echo 2 >| /proc/sys/kernel/randomize_va_space"二、記憶體分析

    我們為什麼要關心這個問題?為什麼我們不僅僅就關心效能?這些問題的答案相當複雜,但我會總結出來。PyPy 是一個可選的 Python 直譯器,其相對於 CPython 有一些巨大的優勢:速度(透過其 Just in Time 編譯器)、相容性(幾乎可以替代 CPython)和併發性(使用 stackless 和 greenlets)。PyPy 的一個缺點是因為其 JIT 和垃圾一樣的回收站實現,它通常會使用比 CPython 更多的記憶體。但是在某些案例中,其的記憶體消耗會比 CPython 少。下面我們來看看你可以如何測量你的應用使用了多少記憶體。

    診斷記憶體使用

    memory_profiler 是一個可用來測量直譯器執行一個負載時的記憶體用量的庫。你可以透過 pip 安裝它:

    pip install memory_profiler

    這個工具的優點是它會在一個 Python 指令碼中一行行地顯示記憶體消耗。這可以讓我們找到指令碼中可以被我們重寫的位置。但這種分析有一個缺點。你的程式碼的執行速度比一般指令碼慢 10 到 20 倍。怎麼使用它?你只需要在你需要測量的函式上直接加上 @profile() 即可。讓我們看看實際怎麼操作!我們將使用之前用過的素材指令碼作為模型,但做了一點修改,移除了統計部分。程式碼也可在 GitHub 檢視:https://github.com/apatrascu/hunting-python-performance/blob/master/02.primes-v1.py

    開始測量時,使用以下 PyPy 命令:

    pypy -m memory_profiler 02.primes-v3.py

    或者直接在指令碼中匯入 memory_profiler:

    pypy -m memory_profiler 02.primes-v3.py

    在執行完這行程式碼之後,我們可以看到 PyPy 得到這樣的結果:

    我們可以看到這個指令碼使用了 24.371094 MiB 的 RAM。讓我們簡單分析一下。我們看到其中大多數都用在了數值陣列的構建中。它排除了偶數數值,保留了所有其它數值。我們可以透過呼叫 range 函式而對其進行一點改進,其使用一個增量引數。在這個案例中,該指令碼看起來像是這樣:

    如果我們再次測量,我們可以得到以下結果:

    很好,現在我們的記憶體消耗下降到了 22.75 MiB。使用列表解析(list comprehension),我們還可以將消耗再降低一點。

    再次測量:

    我們最後的指令碼僅消耗 22.421875 MiB。相比於第一個版本,差不多下降了 10%。

  • 中秋節和大豐收的關聯?
  • 趙氏孤兒前後晉國卿族之間鬥爭是怎樣的?