pretty code

2024年6月12日 星期三

關於 Verilog parser 這件事

連假都在盡最後努力讓自己的聖騎升上 97 級,再加上手上沒有那樣大的 netlist 檔案,所以放假三天就在打電動中渡過了XD

昨天一早就用 cProfile 確定最慢的執行函數是什麼?果不其然,前三名是 PLY yacc.py - parseopt_notrack、 PLY lex.py - token 以及 re.match,第四名 pyverilog parser.py - p_items 看起來貌似 constructor 沒錯?


光前三個就跑了 25 分鐘以上(cProfile 會增加程式執行時間,跑起來要更有耐心)。

要細究是哪個段落花時間只能 print message 了,但我想幫助不大,因為 PLY 應該已經是 Python 最有名的 lex/yacc solution 了,要優化應該也不是一天兩天的事。

順便實測其他 EDA tool 的花費時間,原來也不是我想的秒等級!

雖然這樣比有點不公平,比如 DC 還需要知道 cell library,還有不論是 DC or yosys,貌似 read_verilog 不只是 parsing 都還順便建立了 RTLIL 中介層,應該是比 pyverilog 只用一般資料結構儲存花時間,但也只能這樣比較了,畢竟我已經無法再細拆 command 了。

同樣的 netlist 檔案,花費秒數如下:

DC - 191
yosys - 380
pyverilog (建完語法樹) - 1546,離開程式 Python 釋放記憶體又花了至少 100 秒。

嗯,果然還是有一段差距。

2024/06/18 更新

透過 cProfile 分析得知,parser 花了很多時間做 match,撇開 C vs Python 語言差異不談,最快的解決方式就是只要處理 netlist 語法即可,不需要處理整個 Verilog 語法。

稍微查了一下,只有看到 C 語言版本的 netlist parser,再加上看 EDA 文件真的很 borning(EDA 文件都要真的操作才有感覺,還沒碰過的光看文件,坦白說收益不大),所以還是自己來吧。

從上星期五開始,扣掉家裡有事請假外,總共花了 16.5 小時使用 Python 實作。

概念也是非常簡單,我有一個函數負責取得以分號為結尾的字串或是 endmodule 關鍵字,這裡我稱呼它為工作字串,再來就是對工作字串做比對,只要分別針對 module,port,net,cell instance 處理並儲存結果即可。

目前暫時還沒想到 assign 要儲存啥以及偷懶不想處理一維陣列以上的情況,其餘我知道的語法都已處理完畢。

開發時間分析如下:

得到可以工作的字串 - 2.5 小時
使用 Rex 處理所有語法 - 8 小時
將儲存的資料結構轉成 pyverilog 的輸出格式 - 6 小時

程式碼行數:

得到工作字串 - 89 行
輸出 Verilog - 149 行
Rex 處理及其他 - 455 行

程式執行時間:

單純 parsing 及儲存 - 225 秒
輸出 Verilog - 56 秒

下面則是我的 netlist parser cProfile 結果:


目前還算滿意XD

雖然從結果來看,還是有進一步優化的可能性,但我覺得最多不可能再減少超過 50 秒?

就算再減少 50 秒也沒意義!我只有處理 netlist,不像 EDA Tool 處理整個 Verilog 語法,這樣的 parser 跟商用軟體比還是有段距離,但貌似我的工作大部分應該還是針對 netlist 做事?

個人還是覺得 lex/yacc 的方法比較正統,不像我的 code 為了解決縮排,使用者 Code 亂以及空白字元等問題,需要一些 if/else 來處理(取工作字串 89 行程式碼中,大部分都是在處理這些事情),這樣的 code 看起來也不開心XD

2024/06/21 更新

前天進公司後,想了一下還是加上多維陣列的功能,大概花了不到 5 分鐘吧。

沒想到這兩天拿它來試試其他手上有的 netlist,陸續又發現了一些問題,也順便修了 pin net 中,有 range 及 array 情況下,Rex 沒下好導致 capture group 抓取不正確的問題,昨天下午看了 Verilog 2001 Spec 後還發現我搞錯順序了,應該是先陣列才是 range,目前應該都沒問題了吧?

為了這個多維陣列,code 多了 30 幾行,程式執行時間也多了 20 幾秒,目前 parsing 大概要跑 245 秒左右。

單純 parsing


單純 parsing 加上處理多維陣列結果


最後想嘗試一下把我這個 parser 用到之前拔電路的小程式中,一般來說,我有兩個選擇:

1. 將我目前用的簡單資料結構轉成 pyverilog ast 結構再加上個別 class visit function,這樣我不用去改原本的 code。

2. 配合我 parser 用的簡單資料結構改寫我原本的 code。

目前是嘗試使用方法二,今天應該就能知道結果了。

對了,這個 600 多萬行的 Verilog,我的 parser 執行時會用掉 10G 多一點的記憶體,離開好像也是要花個幾秒等記憶體釋放。

跟之前用 pyverilog 的小程式比較,大概快了 35 分鐘,也不枉費我這幾天的努力XD


我的程式總共建了 9 條 Rex。

因為我的程式把行打散了,故我無法得知行數資訊,先前簡單用個 group 概念好讓自己的輸出接近 pyverilog 格式。

之前是用 yosys read_verilog + write_verilog 方式來驗證我的 parser 正確性,我們可以用 design -reset command 將兩個要比較的檔案寫在同一個 script 讓 yosys 幫忙轉檔,同一個檔案,讀加寫要花 30 分鐘(沒記錯的話,寫檔就花了 20 幾分鐘)。

由於之前就知道要怎麼改,故最後還是把 module.port_list 再包一層,裡面儲存另一個 list,這樣我就能讓同 group 的在同一行輸出,加上這個功能之後,我的輸出基本上就跟 pyverilog 一致,除了多維陣列還未驗證過 pyverilog 格式長怎樣。

也因為這樣輸出 verilog 函數行數再度減少,最終版本 parser 包含測試 main 函數只有 701 行(先前的行數統計也是包含 main)。

目前只剩一個謎題待解?

我能理解 pyverilog 因為比對緣故所以花了很多時間,但為什麼單純輸出 verilog 也要花上 10 來分鐘,對比我的 60 秒確實是有不小的差距!我猜 pyverilog 應該是使用 template file 方式產生 verilog,故浪費了很多時間在 File IO 。

其實 yosys 寫檔時間比 pyverilog 還更誇張,我能想到的就是它又二次轉了資料結構以利 verilog 輸出?

剛剛看了一下,輸出是在 yosys/backends/verilog/verilog_backend.cc 這支檔案,看起來是用 RTLIL::Design *design 來儲存整個 netlist,並直接用 std::ostream *&f 寫到 output,看來想知道事情緣由還是要把整個程式碼看過一遍才行。

2024/06/23 更新

快速的看了一下 yosys code,backend - write_verilog 呼叫順序為:

yosys/kernel/driver.cc - main 函數入口
中間未看…
yosys/kernel/register.cc - Backend::execute(這個應該沒有,因為被 verilog_backend 繼承了)
yosys/backends/verilog/verilog_backend.cc - execute,這裡會呼叫 Backends::extra_args,裡面會把 
原本是 NULL 的 std::ostream 在這裡開檔,之後便能寫檔了,這也是為什麼 execute 會接受一個 std::ostream *&f 的緣故,因為需要在這裡 new instance。

2024/06/25 更新

yosys 可以吃 tcl script file,故有用到 Tcl 提供的介面,script 裡面要執行的 command 其 callback 在 kernel/yosys.cc - tcl_yosys_cmd。

在 Pass::call 的過程中,便會呼叫到繼承 Pass 的相關 struct。

2024年6月8日 星期六

2024 week 23 新玩意

01. DC log level information

這兩天突然發現自己移植的 DC script 居然都沒原始專案的 log 輸出?明明該有的 output 檔案都在,但不論是螢幕還是 log 都看不到執行該 command 的顯示!

本來以為是自己多下了一個 tee -i 的參數,從 man 中又看不出有什麼關聯?

終於在昨天中午想通了,一般來說,我們會用 -f script 的方式來執行 DC,如果該 script 裡面有 DC command 便會顯示執行結果。

但我的 script 裡面又帶了一層 script,我真正的 command 都是位在第二層,所以當然什麼都看不到,也算是學了一課。

02. MBFF 

2010 我就有看到台大學生的論文在研究這個,所以應該不是新東西?難道 IC 產業是學術跑在實務前面?

03. Verilog Parser 待釐清事項

之前有簡單寫個用 Rex 來 parsing netlist 的 parser,雖然我只是測試抓取的部分,並未實際去產生對應的資料結構來儲存資料,實測的結果都不需要 3 分鐘。

昨天拿最近用 DC 跑完的 netlist 測試一下,速度依然很快,但在我只建 3 條表示式的 rule 中,就有兩條有些 statement 語句判斷不到,印象中我有處理 escaped identifier 這塊,DC 又有 rule command 可以避免使用奇怪的命名規則,理論應該會比 yosys netlist 來得好才對?改天 EDA 文件看煩了再來試試。

回到 pyverilog 本身,使用 lex/yacc 的方式應該是最正規了,問題是出在 match token 速度才那麼慢嗎?還是在 Python 建資料結構時 constructor 拖慢了速度?

明明其他 EDA parsing 都只花了不到 5 分鐘,難道只是 C/C++ vs Python 的差異?

昨天沒想到,現在 Profile 功能應該已經內建在 Python3,跑一下就知道原因發生在哪?

04. Windows 11 升級

最近微軟不知又發什麼神經,Team Classic 又要改版,偏偏新版又跟著作業系統,而我的電腦就是屬於需升級的那批。

之前為了加速開發,自己買了一顆 SSD 當作業碟,才發現空間已經用了快一半!既然現在已經轉部門半年了,很多軟體跟資料都用不到了,便趁此機會把軟體都移除,目前已用空間還有 15X G,但已經比之前好多了。

不過貌似 Windows 11 升級檢查軟體在 IT dc 環境下不能執行?所以我也不知道是否能升級,但單以 CPU 來看我的 10 年前電腦應該是不在支援清單中。

算了不升級也好,還要浪費半天時間不能做事,抱電腦回來又要再花半天整理工作環境,幸好目前部門我只需要 Vim,Python 跟遠端登入軟體即可,應該不用像以前一樣一堆東西要裝。

下次線上上課只能用 Team Web App,但要記得使用 FireFox,不要用 Chrome,不然就會像某年上資安課一樣一直斷線,被人事判斷沒有上課,導致一樣的課上了兩次,追根究柢都是微軟寫的軟體不好XD

2024年6月7日 星期五

AT 叛客

昨天差點被當成不法分子,真的是好氣又好笑,以後不那麼認真了XD

有鑒於 EDA 或是跟 IC Desing 有關的工具使用,動輒都是好幾個小時或是天起跳,連個 Verilog Parser 都要快半小時!

昨天不知為什麼突然想到(應該是一直看 EDA 文件很容易分心XD),既然純 Python code 很慢,用像是 PyInstaller 的工具包成執行檔後,執行速度是不是會比較快?

印象中之前有寫個等公車的小程式,裡面就有使用 PyInstaller,我就不用再去找參數怎麼用了,下載下來後,一執行安裝 batch,Windows Defender 就一直跳出警告,說是判斷有病毒,稍微查了一下應該是被當成惡意程式,調整了參數,還是會被誤判,後來去忙別的事我也就忘了XD

下午 4 點多時突然接到 IT 郵件,說是發現在執行惡意程式,於是寫信回復事情發生原由(突然想到,郵件裡有 CC 主管嗎?昨天沒特別注意,沒有的話要報告一下)。

原來我已經轉型成駭客我都不知道了XD

對了,昨天是自己耍白癡,PyInstaller 只是包成執行檔,並沒有重新編譯,應該是對執行時間沒有幫助,昨天不知道為什麼會突然覺得有用?一定是太久沒寫程式,腦袋都僵化了,來到新部門後,似乎還沒發現寫程式在這邊有甚麼用?可能是我還太嫩了吧,目前只感覺這些東西很吃經驗,至於能不能寫程式幫助其他同事,我還真的不太肯定XD

突然好懷念 AT 叛客這個暱稱,離開會計本業也快 20 年了,現在的路也不知道到底走得對不對?

後記

用家裡訂閱的小紅傘測試了一下,也是跳出差不多的警告,這樣我就放心了XD

俗話說的好,寧願錯殺也不要錯放,畢竟不管是家裡還是公司電腦,都是拿來做事的,最怕的是什麼都偵測不出來,這樣我才會害怕XD


話雖如此,昨天下班前還是不放心地針對整個 Python 安裝目錄掃瞄了一下,理所當然的是回報沒有問題?

唉,程式設計師不可能永遠自己造輪子,現在第三方函式庫又常有漏洞,除了有專門的團隊每天去追蹤這些資安資訊,一般程式設計師還記的自己用過什麼函式庫已經很厲害了,怎麼可能還定期去看是否有更新,自己沒待過像是 Google 這樣的大公司,不知道他們都是怎樣解決的?