原本我的 netlist_treeview 是要拿來當我的 gui tool 用,後來為了 report 加了一些額外的功能。
當遇到比較多 instance 的 netlist,居然要跑個 5 ~ 6 分鐘,這樣的速度不是很能接受!
於是做了一些修改,記錄一下自己的心得。
01. 減少 function call
原本的功能都是寫成函數,增加不同類別的檢查只要改變參數呼叫原本的 function 即可,為了加速,我把原本的函數複製了 3 份,貼在原本各自呼叫的地方,雖然程式碼很醜,但快了 20 幾秒有。
也減少了一直重複呼叫 array get 或是 array set,因為要將 array 傳進 proc 似乎要先 list 化?沒有直接傳進去的用法。
02. 遞迴函數減少參數傳遞,改用全域變數。
這樣的改動對於加速也是有感的,大概可以再快個幾秒,就不知道是否是雜訊就是了?
03. 減少 lreplace lappend 的呼叫
改完後感覺有時還變慢?不確定是不是為了這個,反而在遞迴中增加參數傳遞導致,但至少目前這個遞迴函數的行數比原本少了一半,看起來舒服多了。
另外,可以透過 override proc 和 trace 來將原本沒有計時的函數呼叫自動增加計時功能,但這樣一來執行速度會變得很慢,我要跑 5 ~ 6 分鐘的 case 根本沒辦法順利 profile 。
下面是網友的範例程式,記得要在程式結束前自己呼叫 TimingProfilerDump。
2025/03/14 更新
果然跟我想的一樣,問題是出在
遞迴上,加上下面 command 就可以解決問題。原本要跑 5 ~ 6 分鐘的程式,現在只要 15 秒,感覺合理多了。
interp recursionlimit {} 100000
另外,參考網友 callback 方式,改了一版自己的 monitor 程式,整體來說也比較好懂。
一般來說,遞迴函數一定會帶參數,這樣才能有條件來結束遞迴,我的 monitor 也能支持遞迴記錄。
array set ::debug_state {}
set fd [open "debug.log" w]
proc monitor {args} {
global debug_state
global fd
set proc [lindex [lindex $args 0] 0]
set index [lindex [lindex $args 0] end]
set type [lindex $args end]
set key "${proc}@${index}"
if {$type == "enter"} {
set debug_state($key) [clock clicks -milliseconds]
} else {
set end [clock clicks -milliseconds]
puts $fd "$key took: [expr {$end - $::debug_state($key)}]"
}
}
rename proc _proc
_proc proc {name arg body} {
_proc $name $arg $body
trace add execution $name enter monitor
trace add execution $name leave monitor
}
proc test {index} {
if {$index >= 5} {
return
}
after 500
puts "in test_${index}"
incr index
test $index
}
test 1
2025/03/14 晚上更新
雖然要跑 5 ~ 6 分鐘的 design 可以透過調整 stack 參數,變成只要 15 秒。但有一個需要跑 99 秒的 design 卻還是要花差不多的時間?
目前只能確定,還是因為多了一個要檢查的 cell 類別,導致在遞迴函數裡,需要多呼叫 4 ~ 5 萬次導致,如果拿掉這個 cell 類別的檢查,就又會回到 10 幾秒的水準。
之前猜測遞迴耗時的原因是因為動態調整 stack size 的緣故,而這個所謂調整的演算法一次增加的幅度應該不多,這才能解釋遇到過多的遞迴呼叫導致時間不合理增加。
改天還是要看看 source code 才能得知。
2025/03/16 更新
我越想越覺得不對?這個參數看起來超過限制就是會報錯,跟我的情況似乎搭不起來?
我開始懷疑我在耍白癡了?我的 netlist_treeview.tcl 會因為要檢查的 cell 類別檔案在不在而決定要不要檢查,感覺是影響我變慢的那一個 cell 類別檔案當時並不在同資料夾內,導致我以為我的更動有效的緣故?
明天去公司的第一件事要來檢查一番。
2025/03/17 更新
果然是我耍白癡,沒有把 sdff.txt 放在同一個資料夾,害我誤以為 recursionlimit 可以解決問題。
不過問題來了,那到底是哪邊有問題?
雖然早上停等紅燈,無故被推撞,導致一整天心緒不寧XD
終於還是在決定下班前請個 2 小時假去醫院做個檢查前找到問題。
在記錄問題前,先記錄一下相關數據。
我這個 netlist 裡面的 instance 大概有 111 萬個,sdff 全部則是 28 萬個,如果不檢查 sdff,在遞迴函數內全部只需要 5 秒鐘,比原本的 6 分多鐘少了很多。
之前做了一些調整後,最好時可以壓在 5 分鐘內。
OK,這個問題的本質是我有一些 Tcl Array,因為我在遞迴檢查時,如果符合某個 cell name 我要記錄他的 hierarchy 資訊,原本我的寫法是:
set tmp myarray($cell_name)
lappend tmp $my_hier_info
set myarray($cell_name) $tmp
原來我可以直接這樣寫就好了。
lappend myarray($cell_name) $my_hier_info
如果是這樣的話,全部就只要 5 秒鐘就好。
這樣改可以生效是因為我減少了很多不需要的賦值和設值動作。