[英]Profiling F# function — profiler doesn't see any of the calls of the function's body. Why?
我寫了以下函數
let getTriangles maxPerimeter =
let mutable count = 0
for c in 1..maxPerimeter do
let cc = (int64 (c*c))
for b in 1..Math.Min(c-1, maxPerimeter-c-1) do
let bb = (int64 (b*b))
for a in 1..Math.Min(maxPerimeter-c-b, (int (Math.Ceiling(Math.Sqrt(float (cc+1L-bb)))))) do
let aa = (int64 (a*a))
if cc + 1L = aa + bb then
count <- count + 1
count
現在是時候調整它了。
為此,我安裝了dot Trace Performance
並在我的應用程序上運行了一個非常大的maxPerimeter
,以確保程序需要一段時間才能運行。
這就是我得到的:
正如您可能想象的那樣,我實際想知道的是如何在 getTriangles'
函數體內分配使用時間,所以這似乎沒有特別的幫助。 我已經嘗試在“ Build
窗格中關閉代碼優化,但它似乎對我沒有幫助。
我擁有的所有分析經驗都是使用Java,因此我可能會對CLR世界有所了解。 我也涉足ANTS Performance,但結果是一樣的。
我不知道dotTrace,我使用ANTS Performance Profiler,因為我發現它與F#的效果非常好; 我最近一直在使用新版本(v8)來分析我的fsharp-tools項目。
在ANTS Performance Profiler中完成分析運行並顯示結果后,默認視圖僅顯示您擁有源的方法(即,您正在分析的.exe / .dll旁邊有一個.pdb,它指向您計算機上的某個有效源位置)。 您可以使用下拉列表(請參見屏幕截圖)顯示所有方法,這對F#代碼非常有用; 因為您正在傳遞函數,執行堆棧往往會進出您可能正在使用的庫,因此查看“所有方法”可以更好地了解代碼實際執行的操作以及外部庫中的代碼可能會影響代碼的性能。
那說 - F#有兩種不同的for
循環; 它們看起來很相似,但實際上卻完全不同。 你使用的那個( for x in y do
)大致相當於C#中的foreach
循環 - 也就是說,循環編譯成一個迭代器,它從某個值序列中提取每個值。 第二種,更快的循環( for i = x to y do
或者for i = x downto y do
)編譯成非常簡單的IL,就像你在C#,Java,C等中使用for
循環一樣。
這是你的函數的修改版本,它使用第二種for
循環。 在這種情況下,它只是稍微快一點( 13.749s
對13.520s
,我的筆記本電腦N = 5000
),但如果你在數字范圍內進行任何緊密循環,那么毫無疑問你想要編寫代碼的方式。
let getTriangles' maxPerimeter =
let mutable count = 0
for c = 1 to maxPerimeter do
let cc = int64 (c * c)
for b = 1 to min (c-1) (maxPerimeter-c-1) do
let bb = int64 (b * b)
for a = 1 to min (maxPerimeter-c-b) (int <| ceil (sqrt <| float (cc+1L-bb))) do
let aa = int64 (a * a)
if cc + 1L = aa + bb then
count <- count + 1
count
就功能中的行為而言,ANTS Performance Profiler還可以為您提供行級時序(但僅適用於您擁有源的方法)。 我編譯並分析了你的函數和我的修改版本( maxPerimeter = 2000
):
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.