夭壽慢的 Cygwin

在軍情緊急的昨天 (2009/6/27), 本來是要幫忙解 HDMI 的 bug. 但是事件卻如雪片般地飛來~~~ 前線的 Dylan 說我 build 給他的版本有問題; Mike 多次打電話來關切; 老婆中午叫我回去教做人做事的道理, 晚上叫我教女兒英文. 另外我們的 SPDIF 規格版本太舊了, 我還得抽空上網去買新版的 SPDIF spec. 再 download 下來給 Irene 看.

然而, 真正叫人喪氣的就是: Cygwin 變得超超慢, build 一個版本似乎要好幾個小時. 我想 Dylan 應該要瘋了~~~ 為了測底消滅這個問題, 我趁 make code 的時候, 整理 Cygwin 變慢的原因如下: 

根據網路搜尋的結果, 在 Cygwin 的官網這樣解釋:

4.2.

Why is Cygwin suddenly so slow?

 

If you recently upgraded and suddenly every command takes a very long time, then something is probably attempting to access a network share. You may have the obsolete //c notation in your PATH or startup files. This now means the network share c, which will slow things down tremendously if it does not exist.

Using //c (for C:) doesn’t work anymore. (Similarly for any drive letter, e.g. //z for Z:) This “feature" has long been deprecated, and no longer works at all in the latest release. As of release 1.3.3, //c now means the network share c. For a detailed discussion of why this change was made, and how deal with it now, refer to http://sources.redhat.com/ml/cygwin/2001-09/msg00014.html.

在討論串裡面, 有類似的說明:

http://www.mail-archive.com/cygwin@cygwin.com/msg85049.html

另外一個原因好像是 Windows 2000 的 hotfix Q8114993 改了 winsock 的處理方式.

www.cygwin.com/ml/cygwin/2003-05/msg00065.html

既然我的 cygwin 本來是快的, 原因很可能出在 Windows 的 upgrade. 可惜看來看去, 網路上說的 hotfix 竟然是 2003 年的事了, 現在的這些 hotfix 並不知道要懷疑誰好? (其中 IE 8 那一包至為可疑…, 我的 notebook 灌了它之後很會當!)

再回頭看看 Cygwin 的另外一個官網 http://cygwin.com/, 裡面提到了一些實際可行的做法. 整理如下:

1. 給 Cygwin 更多的記憶體. 這個例子可以給到 1024MB, 當然, 這是指 virtual memory. 只要 Windows 的分頁記憶體比它還大就可以了.

regtool -i set /HKLM/Software/Cygnus\ Solutions/Cygwin/heap_chunk_in_mb 1024
regtool -v list /HKLM/Software/Cygnus\ Solutions/Cygwin

執行結果如下:

mounts v2\ (Cygwin)
Program Options\ (cygnus)
heap_chunk_in_mb (REG_DWORD) = 0x00000400 (1024)

2. 用 strace 跑一次 make, 從這裡可以看到很多時間花在找 path, 因此把 cygwin 的目錄往前移. 修改的地方自然是在控制台 → 系統  → 進階  → 環境變數那裡.

此外, 我也看到一個令人心痛的事實, Cygwin 花了很多時間在確認執行檔的名稱. 它先找執行檔 XXX, 再依序找 XXX.exe, XXX.lnk, 和 XXX.exe.lnk. 原來我浪費了這麼多時間在做沒意義的傻事! 

   78  373674 [main] rsdk-elf-gcc 2440 mount_info::conv_to_win32_path: src_path /rsc/ct_wu/rsdk/release/rsdk-1.4.2/cygwin/newlib/rlx-elf/lib/specs, dst g:\cygwin\rsc\ct_wu\rsdk\release\rsdk-1.4.2\cygwin\newlib\rlx-elf\lib\specs, flags 0xA, rc 0
  127  373801 [main] rsdk-elf-gcc 2440 symlink_info::check: GetFileAttributes (g:\cygwin\rsc\ct_wu\rsdk\release\rsdk-1.4.2\cygwin\newlib\rlx-elf\lib\specs) failed
   83  373884 [main] rsdk-elf-gcc 2440 geterrno_from_win_error: windows error 3 == errno 2
  116  374000 [main] rsdk-elf-gcc 2440 symlink_info::check: GetFileAttributes (g:\cygwin\rsc\ct_wu\rsdk\release\rsdk-1.4.2\cygwin\newlib\rlx-elf\lib\specs.exe) failed
   81  374081 [main] rsdk-elf-gcc 2440 geterrno_from_win_error: windows error 3 == errno 2
  117  374198 [main] rsdk-elf-gcc 2440 symlink_info::check: GetFileAttributes (g:\cygwin\rsc\ct_wu\rsdk\release\rsdk-1.4.2\cygwin\newlib\rlx-elf\lib\specs.lnk) failed
   80  374278 [main] rsdk-elf-gcc 2440 geterrno_from_win_error: windows error 3 == errno 2
  117  374395 [main] rsdk-elf-gcc 2440 symlink_info::check: GetFileAttributes (g:\cygwin\rsc\ct_wu\rsdk\release\rsdk-1.4.2\cygwin\newlib\rlx-elf\lib\specs.exe.lnk) failed
   83  374478 [main] rsdk-elf-gcc 2440 geterrno_from_win_error: windows error 3 == errno 2
   79  374557 [main] rsdk-elf-gcc 2440 symlink_info::check: 0 = symlink.check (g:\cygwin\rsc\ct_wu\rsdk\release\rsdk-1.4.2\cygwin\newlib\rlx-elf\lib\specs, 0x22C450) (0xA)
   82  374639 [main] rsdk-elf-gcc 2440 mount_info::conv_to_win32_path: conv_to_win32_path (/rsc/ct_wu/rsdk/release/rsdk-1.4.2/cygwin/newlib/rlx-elf/lib)

在 strace 裡面看到做最久的一步是 entering. 換個目錄需要很長很長的時間. 因此我想到第三步: 硬碟重組!

3. 把硬碟重新整理一下, 執行重組! 既然 Cygwin 編譯時 CPU time 是如此地少, 可見得它是 IO bound. 此時 Memory 已經給很多了, 實際上用到的記憶體 800MB 都還不到實體記憶體 1GB 的 90%, 所以可以排除 memory bound 的可能.

4. 把防毒軟體的沒用的檢查關掉一點. 把安全的檔案夾都放到 exception 裡面.

5. 把 bash.exe 的 priority 從工作管理員裡面調升到 "標準以上". 不過, 我給 Dylan 的版本就是在調升 priority 以後 make 的, 我現在不是很敢動它. 尤其是調到 "即時" 等級的話, 根本就不能 make clean  再 make all 了.

用了這幾招之後, 感覺似乎有快一點. 至少 make 一次的時間可以在 5 分鐘以內了. 不知道是不是有 bug, 哈! 其中最好的一招好像是 3: 硬碟重組. 有人知道更厲害的絕招可以教我嗎?

 

Automake 如何把簡單的事情變複雜

 

由於聽過 automake 這個東西, 也看見它到處肆虐, 卻不知道怎麼玩? 所以就找了資料來試試看. 一試之下, 才發現這是個把簡單的事情變難的方法 ! 當然, 網路有教人家怎麼玩? 不過可千萬別信他們的, 可以輕輕鬆鬆產生 makefile. 以下就是我悲慘的遭遇.

 

首先要安裝好 cygwin, 這個大家都會, 不成問題. 後面就一步一步來囉  :

 

source code 的目錄底下, 執行 autoscan, 一般來說執行的是 /usr/bin/autoscan, which 指令就可以確認 .這時會產生一個 configure.scan 的檔案.

 

喔喔, 光是長相就和網路上長得不一樣了. 一定是 autoscan 版本的問題. AC_INIT 變成 3 個參數, AM_INIT_AUTOMAKE 卻不見了 .

 

無可奈何之下, 只好把前幾行改成這樣  :

 

因為它會生出一個 config.h 把我的 config.h 蓋過去!

 

此時會出現一些 configure.ac 的錯誤訊息, 不過不用管它. 那是因為舊的中間檔案在作祟吧!?

 

configure.scan copy confiqure.in . 做下一步的準備 .

 

執行 autoconf, 結果會得到 configure . 它會參考剛才的 configure.in . 這個檔案大約是幾百   KB.

 

執行 aclocal, 此時應該要產生 aclocal.m4, 不過實際上它是抱怨連連. 如何看到這一句     : Can't locate object method "path" via package "Autom4te::Request" at /usr/autotool/devel/bin/autom4te line 81.

 

那就執行一下 rm -r autom4te.cache, 後面一律比照辦理 .為了避免大家過於投入 debug 的細節, 我就只講對的做法吧 

 

!中間還要加入 AC_PROG_LIBTOOL 這一行, 不然後面過不了

 

.此時執行 libtoolize –force, 若沒有執行 libtoolize, 待會兒 automake 會找不到   ltmain.sh.接著執行 autoheader, 它會產生 config.h.in. 沒有這個 automake 會抱怨   .現在再做一次 aclocal 就平安無事了. alocal.m4 這個檔案也幾百 KB.

 

此時有個抱怨: You should add the contents of `/usr/share/aclocal/libtool.m4' to `aclocal.m4', 但據說不用理它 !

 

現在人工又要介入了, 我們得寫一個 makefile.am 的檔案, 裡面放這些東西  :

 

b.c 中間用空隔分開.

 

此時可以執行 automake -a . 當然它還會再抱怨, 包括叫我用 2.59 . 天啊! 我不就是 2.59 版嗎? 因此我回去把 configure.in 的第一行改成 2.57, 重跑第 N   .生出 configure 檔了!

 

什麼? 還不是 Makefile? 只好 run ./configure 再跑個半天   .終於等到 Makefile , 好久啊! 太恐佈了   !!

 

打下去! 程式的 bug 出來了, 終於可以 debug 了 .

 

為了避免大家不知道我說了什麼? 看看我這個醜不拉幾的 a.rc   !    (倒站後找不到 code 了!)