2012年2月25日星期六

Gtk+ 入門

之前看過 jservGtk+ 程式設計初體驗, 玩了一下範例程式, 對 Gtk+ 的 OO 表達方式和處理事件的架構有概念。再來看《GTK 學習筆記》的前幾篇, 試一下範例, 知道怎麼重頭編寫。後來看到其中一篇提到 gtk-demo, 接下來就簡單許多。看一下範例, 挑自己要的出來改, 配合官方文件查幾個 API 用法, 就搞定要做的小東西了, 整個過程還算順利。

備忘:

  • 安裝: $ sudo apt-get install libgtk2.0-dev gtk2.0-examples
  • 編譯: $ gcc prog.c -o prog `pkg-config --cflags --libs gtk+-2.0`
  • 查範例程式: $ gtk-demo ( 點左側選單兩下會執行程式, 右側有程式碼)。若有需要, 也可用 apt-get source gtk-demo 取得原始碼, 更方便。
  • Scott 提到《Parasite: Firebug for GTK+》, 方便調整元件位置, 還沒用過, 先記著。

2012年2月21日星期二

設定 viewport 的寬度為 device-width 以支援各種 mobile browser

好歹也是花了一些時間看的東西, 備忘一下。

《The orientation media query》

  • orientation (landscape or portrait) 不是重點, 重點是螢幕寬度到底是幾 pixel
  • 結論: 用 device-width

《Mobile web design viewport size vs screen resolution - viewport META tag》

  • 詳述 viewport 為何, 覺得重述一次意思會不對, 還是請大家看原文吧
  • mobile device 的 viewport 大小不見得和 screen 大小一樣 (桌機則是一致)
  • 有些 mobile browser 藉由讓 html 畫在較寬的 viewport 上, 再將它縮放到符合螢幕寬度, 藉此顯示整個網頁的大概樣子 (有時稱為 overview mode)。也就是說, 網頁會依 viewport 的寬度來 render, 而不是 screen 寬度。對桌機來說兩者寬度一樣, 所以不會混淆
  • 各家 mobile browser 預設的 viewport 大小不同, 造成寫網頁的人的困擾
  • 可用 <meta name="viewport"content="width=1100"/> 改變預設 viewport 寬度
  • 可用 <meta name="viewport"content="width=device-width"/> 將 viewport 設為 device 寬度
  • 舊手機不支援上述語法, 該連結有提到其它備案

《device-width and how not to hate your users》

  • 可用 CSS 3 新語法 media-query 針對螢幕寬度決定使用的 CSS rules。對於桌機不同的螢幕寬度來說, 這是個好解法, 不用擔心使用者用 24" 寬螢幕還是 19" 一般螢幕。
  • mobile device 另有 viewport 大小不同 screen 大小的特色, 所以使用 media-query 的話, 要再配合限制 viewport 寬度為 device-width, 才可確保用對 CSS rules

2012年2月20日星期一

在 apache2 內顯示 symbolic link

要滿足以下三者才可以顯示 symbolic link

  • <Directory /path/to/dir/> 內要有 SymLinksIfOwnerMatch 外 (module userdir 預設就有設)
  • soft link 的擁有者要和連到的檔案是同一人, 這樣才安全, 也可避免 /、/home 之類的目錄被使用者亂連出去
  • soft link 目錄的整條路徑都要能讓 www daemon 存取, 若有個目錄是 750 之類的就不行

有錯時可看 /var/log/apache2/error.log, 若出現「Symbolic link not allowed or link target not accessible」, 大概上述其中一者沒設對。

2012年2月17日星期五

git staging area 的價值

之前用 mercurial 時一直很納悶, 為啥 git 的愛好者都如此推崇 staging area, 但我怎麼看就是看不懂, mercurial 沒這東西用起來也沒特別困擾, 反而要和別人解釋 staging area 時還會一直說不清楚 (畢竟自己也沒搞懂它的價值 ...)。

看到《The Thing About Git》總算解開我多年來 (遠目...) 的疑惑, 要配合「只想 commit 檔案內部份修改」的情境才會突顯它的價值。

該文有範例說明, 有時我們會同時改到不同東西, 好死不死, 兩個東西的修改在同一個檔案裡。這時有幾個選擇:

  • 就給它 commit 下去, 在 commit log 裡順帶一提多 commit 的東西
  • 兩個功能一起 commit 進去, commit log 寫長一點, commit 內容比較雜
  • 回去原本的檔案「取消」不想 commit 的修改, 再回來 commit

身為一名良好市民, 大部份時候我是選第三個方案, 但是做得很辛苦。mercurial 好像有 extension 可以只 commit 部份內容 (hunk-by-hunk commit), 不過我懶得找。我後來的作法是:

  • thg 的 commit
  • 在 commit 視窗裡針對目標檔案按 "open shelve tool"
  • hunk-by-hunk 地 shelve 不想 commit 的內容
  • commit
  • unshelve all

還過得去就是了。

但是有 staging area 的話, 有不同的選擇。先 hunk-by-hunk 地將準備 commit 的內容加到 staging area (git add --patch), 接下來比對 repository 和 staging area 確認要 commit 的內容, 同時還可回頭比對 staging area 和 working directory 確定沒有漏東西。和 shelve 的作法相比, 比較直覺一些。

2012-02-18 Update

看到提到《A Git User's Guide to Mercurial Queues》 (ref.), 裡面有說明用 MQ 做到「多重 staring area」的效果, 看起來挺實用的。更新一個涉及多個模組的功能時, 個人偏向依各模組拆開 commit, 比較易讀。配合 MQ 可以更直覺地折解更新成多個 patch, 並保有隨時更新的彈性, 最後再一起 commit 成多個 changesets。

2012年2月16日星期四

配合 c++filt 讀程式

在用 gdb 追蹤程式前, 得先找到幾個關鍵中斷點, 才能著手進行。若有機會想到不錯的關鍵字的話, 除了用 grep 之類的工具大海撈針外, 有時從 binary 裡下手, 效果也不錯, 有機會減少搜尋範圍。畢竟程式碼中難免有一些平台或參數相關的設定, 讓部份程式碼根本沒有編進 binary。從 binary 回頭找, 可免除這層顧慮。

我目前試過的作法有兩種

  • string PROG | grep KEYWORD
  • nm PROG | grep KEYWORD | awk '{print $NF}' | xargs c++filt

第一個作法是配合程式輸出的訊息來找程式。

第二個作法則是從 binary 取出可能有關的的 symbol, 再用 c++filt demangle symbol, 找出它的 namespace、signature 等資訊。需要注意的是, 有可能因編譯器最佳化 (如 inline), 實際上沒有呼叫到函式。經 qrtt1 提醒, 保險起見, 可在編譯時加上 -O0 確保行為符合預期。

題外話, C 的 function name 反而無法 demangle 找出 signature(應該沒理解錯吧)。不過相對於 C++ 的複雜度, 讀 C 的程式時, 也許沒那麼需要吧。

2012年2月14日星期二

Linux process priorities and scheduling 心得

摘要一下讀了 TLPI 後的心得。

scheduling policy

POSIX 規定了幾種 scheduling policy, 它們的優先權如下:

SCHED_FIFO = SCHED_RR > SCHED_OTHER ~ SCHED_BATCH > SCHED_IDLE

舉例來說: SCHED_FIFO (99) > SCHED_FIFO (1) > SCHED_OTHER -20 (0) > SCHED_OTHER 19 (0) > SCHED_IDLE (0)

括號裡的數字是 process 的 static priority; -20 和 19 是 nice value, 見後文說明。

各 policy 的效果為:

  • 所有 policy 都是 preemptive, 也就是高優先權 process 想執行的時候, 會搶走執行中低優先權 process 的 CPU
  • SCHED_FIFOSCHED_RR 的 static priority 範圍必須落在 1 ~ 99, 剩下三個 (SCHED_OTHER、...) 只能設 priority = 0。達到的效果是 SCHED_FIFOSCHED_RR 永遠會比後幾種 policy 先執行
  • SCHED_FIFOSCHED_RR 是 real-time scheduling, 不過是 linux kernel 盡可能做到即時, 真的要做 real-time system (如汽車), 得用改過的 linux kernel
  • SCHED_OTHERSCHED_BATCH 的 static priority 都為 0, 所以會另外參考 dynamic priority 來決定順序, 這個值主要取決於 nice value (用 nice/renice 設), 只是參考值, 較低的 nice value 不會永遠表示較高的 dynamic priority
  • 沒做設定的話, 預設 policy 是 SCHED_OTHER
  • SCHED_BATCH 用在不需互動的程式, 會減少 wake-up 的頻率
  • nice value 對 SCHED_IDLE 無效, 這個 policy 會保證有最低優先權
  • 以上所有效果都會繼承到 sub-process

所以, 若用 SHCED_OTHER 配上 nice value, 可達到優先效果, 也不會有 process 餓死, 都搶不到 CPU。若用了 SCHED_FIFOSCHED_RR, 要小心搶光 CPU 資源的情況。用 SCHED_OTHER 配上負值 nice value 也要小心。

保險機制

做為保險, 可用 setrlimit(RLIMIT_CPU) 限制執行時間, 超過 soft limit 會收到 SIGXCPU, 預設會掛掉該 process。若沒掛的話, 之後每秒鐘會收到一次 SIGXCPU, 直到超過 hard limit 收到 SIGKILL, 保證掛掉該 process。在這之間就有操作空間來調整自己的優先權。

或用 setrlimit(RLIMIT_RTTIME), 來限制在 real-time scheduling policy 下最長執行的時間, 遇到 blocking system call 後會歸零, 可避免失控超時。超時後的行為和 setrlimit(RLIMIT_CPU) 相同。 setrlimit 也和設 scheduling 一樣, 會繼承到 sub-process。

Affinity

Linux 另有特別的 system call 可限制 process 只能跑在那些 CPU, 在 man sched_setaffinity 的 CONFORMING TO 該節有註明這是 linux-specific 的功能。

透過 set affinity, 可以滿足一些特殊需求:

  • 一台 8 core 的 server, 跑 8 個 process 限制它們各自用同一個 core 來服務大量 client, 讓 context switch 的次數降到最低
  • 限制某些類型的 process 只能用部份 CPU, 確保隨時有餘力服務其它 process。比方說留一個 CPU 不跑 real-time process, 至少失控時還能登入使用 shell 處理
  • 若 multi-thread 的程式沒寫好容易掛, 限制它們只跑在一個 core, 也許比較不會當 (這是我看 stackoverflow 裡某位路人提到他的用法 ...)

sched_setaffinity() 可以設在 process 也可設在 thread 上, 用的時候注意一下 man page 針對 pid 的說明。這個值也會繼承到 sub-process

另外, 經 wens 提醒, 還有 pthread_setaffinity_np() 可用來設 thread 的 affinity。查了一下 man page, 它是基於 sched_setaffinity() 的實作。待比較熟 multi-thread、pthread 的事情後, 大概會比較清楚為什麼要多包一個 pthread_setaffinity_np() 吧。

參考資料

  • TLPI ch35
  • man sched_setscheduler
  • man sched_setaffinity
  • man pthread_setaffinity_np

2012年2月11日星期六

使用 hg-svn

參照《WorkingWithSubversion - Mercurial》, 前置動作是要裝 python-subversion。用了一陣子覺得滿順的。不過得等 hg rebase --svn 出現 conflict, 看看有沒有無縫銜接 kdiff3 + resolve conflict, 才可以更放心使用。