Skip to content
YMK Must be Kidding
Go back

自己做的 terminal 覺得 Wi-Fi 很慢,結果是畫面慢,一萬行從 235 秒變 5 秒

這篇是叫 Claude 從我的筆記整理出來,事情真的發生過,字是他打的,連語氣也是叫他學我的,我只負責瞄一下的喔。

覺得網路慢的時候,先看看是不是自己畫得慢

先講這是什麼東西

前幾篇提過的 tang console,再講清楚一點。它是一塊 FPGA 板子,裡面用邏輯閘拼出一顆很小的 RISC-V 處理器來跑 Linux。有多小呢,76 MHz,cache 只有 8 KB,大概是三十年前電腦的等級。螢幕是 HDMI 直接輸出的文字畫面,Wi-Fi 是旁邊一顆 ESP32 小晶片用一條線接過來的。

畫字的程式叫 tangterm,是自己寫的。它底下用了一個叫 libvterm 的現成 library,負責看懂終端機那些控制碼,像是「游標往上兩格」「這行用紅色」「畫面往上捲一行」這種。

用法就是開機、接鍵盤、ssh 到我在東京的 VPS,然後在上面做事。很慢的電腦,很大的字,就是故意的。

症狀:畫面要等好久

ssh 上去之後 cat 一個長一點的檔案,或是開 neovim,畫面就會一行一行慢慢刷,刷好久。第一個反應當然是網路:Wi-Fi 慢吧?那條線慢吧?到東京本來就要一百多 ms 啊。大家都覺得是網路。

好,那就來量。用 seq 吐一萬行數字當測試,分段計時:

一萬行數字時間
從東京傳到板子上大概 1 秒
板子把這一萬行畫到螢幕上235 秒

一秒鐘就全部到了,然後花了快四分鐘畫出來,一顆 core 滿載。網路什麼事都沒有,是我們自己畫得慢。

板子上沒有工具,那就自己做一個

想知道那 235 秒花在哪裡。一般 Linux 上會用 perf 這類工具,它會每隔一小段時間偷看一下程式現在跑到哪一行,看個幾萬次,哪一行被看到最多次,時間就是花在那裡。可是這顆小 Linux 上放不下 perf。

那那,就自己寫一個最陽春的。tangterm 裡面掛一個 timer,每 10 ms 記一下現在跑到哪,收到一個訊號就把紀錄倒出來,拿回電腦上對回函式名稱。大概一百行吧,夠用了。

測試的時候資料是從板子自己的 serial 口直接餵進去的,完全不經過網路,這樣就沒有人可以再怪 Wi-Fi 了。

結果出來,77% 的時間都在 memcpy,就是搬記憶體。從 libvterm 裡面叫出去的。

原因一:每捲一行,就把整個螢幕搬一次

libvterm 在記憶體裡放了一份螢幕的內容,192 欄 × 54 列,每一格記著字、顏色、粗體這些,整份 500 KB。

它處理「畫面往上捲一行」的方式很直接:把整份往上搬一列。就像搬家,每天有一個新東西進門,就把全家的東西都往前挪一格。在這顆小 core 上搬一次 500 KB 大概要 10 ms,seq 每吐一行就搬一次,一萬行就搬了 5 GB。難怪。

修法是不要真的搬。給每一列一個編號的對照表,「畫面上的第一列」其實是「記憶體裡的第幾列」。往上捲一行,就只是把 54 個編號轉一圈,再把空出來的那一列清掉。東西都不用動,改標籤就好。

原因二:只捲一部分畫面的時候,整區重畫

第二個是 tangterm 自己的問題。硬體有一個很快的捲動功能,可是只會整個螢幕一起捲。如果只要捲螢幕的一部分,像 neovim 下面有一條狀態列不動、上面的內容在捲,或是 less,tangterm 就說「這個我不會」,交給 libvterm 的備案,而備案是把那一整塊區域一格一格重畫,一萬個格子,每捲一行就來一次。

後來改成:反正先用硬體把整個螢幕捲了,再把不該動的那幾列貼回去。一行從 23 ms 變 13 ms,再變 2 ms。

結果

測試修之前修之後
300 行彩色的 ls4 秒0.5 秒
300 行很長的純文字8 秒0.4 秒
3,000 行短行,整個螢幕捲5 秒1 秒
3,000 行只捲一部分畫面54 秒5 秒

Wi-Fi、那條線、ESP32 從頭到尾都沒有關係。現在打一個字到看到它出現,底線就是到東京那 140 ms 的來回,這個是物理,沒得修。

後來又慢回去 4 倍

兩天後加了往上捲看歷史的功能,然後一萬行又變成 15 秒了。再量一次,這次是三件小事疊起來:每捲走一行就把整行 192 格存進歷史,不管那行其實只有四個數字;歷史的空間太大,每存一行就碰到一塊新的記憶體;libvterm 每行要從頭到尾掃兩次 192 格,在這麼小的 cache 上也很有感。

一樣一個一個修,只存到那行最後一個有字的地方、歷史改成緊緊排在一起、每一列記住「這之後都是空白」讓掃描提早停。15 秒變 4 秒。新功能很會偷偷把速度吃回去喔。

路上踩到的

下次怎麼看

  1. 「畫面很慢」先分成「資料到了沒」跟「畫出來了沒」兩段,各自計時。這次一段 1 秒一段 235 秒,看一眼就知道該往哪邊走了。
  2. 沒有現成工具的環境,每 10 ms 記一下跑到哪,就夠找到大頭了。
  3. 測效能的時候把網路拿掉,直接餵資料,不然永遠有人可以說是 Wi-Fi。
  4. 修完過幾天再量一次,新功能很會偷偷把速度吃回去。

一秒鐘就到了,花了四分鐘畫出來,這不能怪東京啦


分享這篇:

Next Post
TS80 烙鐵接行動電源一直說 low volt,刷了 IronOS 之後 5V 也能焊,換條線就 9V 了喔