2012年7月8日 星期日

導讀與心得:關於軟體的性能調校

今天來寫寫關於這兩篇文章的摘要跟心得:
http://coolshell.cn/articles/2967.html
http://coolshell.cn/articles/7490.html

第一篇文章裡面講的東西很簡單,卻很重要!用 profiler 跟看組語!我個人經常強調的一件事,就是在解決問題的時候一定要先找到問題在哪裡。以前我常用 debugger 來說明,但 debugger 最大的幫助其實不是找出問題,而是「快速的」找出問題。而透過 profiler,對於找出效能問題幾乎是最簡單的作法....(有一種相當土法煉鋼的方法是,在自己的程式碼裡面加上一大堆印出 timestamp 的程式碼,聰明一點的還會用夾擠來避免浪費太多時間。但是這個行為本身就是在浪費時間....)


這篇文章可說是支持了我的觀點,有時候「看起來好像很慢」的程式碼,實際上並不會浪費你太多時間。這是真的!這也是為什麼作者會說,做性能調校要注意兩個重點,一個是花很多時間的程式碼,另一個是被執行很多次的程式碼!看起來很花時間的程式碼,可能不花你很多時間,也不執行很多次!


第二篇文章講的就多了...但這四個步驟的核心觀念很好抓,先定義(效能)需求,然後做測試,接著找出問題,最後解決問題。聽起來很無趣,不是嗎?但常常見到的情況反而是,先看看程式碼,然後猜測問題,修改之後測試看看,最後接受結果。


常見的狀況都是這樣,我自己也是,但在我懂得使用 profiler 之後才終於知道該怎麼把效能問題的重點給抓出來。但這篇文章講得更多,第一步定義 throughput 與 latency,這兩個詞的差別常常被忽略,因為他們會互相影響,所以常被用「performance」給概括了,但其實是可以分開考慮的。


性能測試部份我就比較沒有經驗了,我只懂得使用 profiler 做簡單的分析,但文中所提到的 throughput 與 latency 測試分析,光用想的就很辛苦....更別提還要配合穩定性測試 (舉例來說,如果系統有 memory leak 問題,碰到高 throughput 狀況則可能很容易噴掉)


透過測試,我們可以知道系統效能狀況。可以從兩個角度來看:從外面看,看 CPU 與 IO 的使用率。從裡面看,看系統 profiling 的數據。但其實有個很尷尬的問題,profiler 會稍微降低系統效能,所以對於上線的(且忙碌的)系統來說,想抓到真實狀況又不想對系統造成影響真的很難.....orz


最後談到「解決問題」這就多了,因為不同的問題需要不同的解決方式,我認為文章裡每一條經驗都很值得參考!首先可能要改演算法,演算法對效能的影響,我想寫過 ICPC 比賽或是 UVa Online Judge 的人最清楚了!雖然有很多現實問題真的不是演算法解決的 (都是一些有的沒的雜事),但底下用到的每個演算法都有機會成為瓶頸,也就有可能是系統加速的關鍵。再來,底層會發生的問題也要注意!誰說寫程式不用知道底層?對底層知道的越多,越有可能寫出好程式,這個定律是不會變的...再來講到系統方面的最佳化,這也是對底層知道越多越有用的例子。後面則是講到資料庫...資料庫性能調校相對於系統或是程式語言底層實做來說,應該算是顯學了。但是顯學歸顯學,也不是每個人都了解資料庫,所以「亂調一通然後看看速度多快」反而變成最 popular 的技術了....= = 文章這部份也相當值得閱讀,首先要知道 DB 的 lock 還有其他實做問題,再來可以透過工具看到 SQL query 的 execution plan (這真的很有用!比亂猜好太多了!但有些 RDBMS 要看到 execution plan 相當麻煩= =)。最後則是常見的 SQL 性能問題,像是 full table scan、index 的使用不當,或是某些通常很花時間的功能...

簡單下個結論,軟體性能調校很重要,但是有些人常常沒有用對方法。建議好好讀過這兩篇文章,還有網路上的其他好文章,嘗試看看用比較好的方法做調整!:)

2012年7月3日 星期二

Vim: CamelCase to snake_case

這篇文章:http://fcamel-life.blogspot.tw/2010/03/vim-camel-case-underscore-based.html 提到用 vim 取代把 CamelCase 轉換成 snake_case 的作法,看到後有一點點小想法,特別紀錄一下 :P

作者提到的取代方式是:
:%s/\(\l\)\(\u\)/\1_\l\2/gc
但配合 very magic 可以變成這樣
:%s/\v(\l)(\u)/\1_\l\2/gc
短了一點點不是重點,重點是括號好看多了XD

另外作者稍微寫錯的部分是,\l\u 在 substitute pattern 中表示的的 小寫和大寫字元,而不是把下一個字變成大(小)寫,那是在後面做的事。可以 :help /character-classes 看到詳細的列表 (大心)。

既然這篇文章這麼短,那就提一下好了。今天找資料的時候不小心發現這位作者的 blog,實在看得我欲罷不能啊XD 而且他玩的東西好多,也玩系統、也寫程式,從 C 寫到 PHP、Python、Perl、Ruby.....太強了orz 還有很多有趣的東西,實在很好玩....太佩服 <(_ _)> 建議熱愛技術的人可以參考看看,我覺得很精采 :D

導讀:保持小而頻繁的 commit

今天讀到這篇文章 http://fcamel-life.blogspot.tw/2010/08/commit.html

這篇文章在講使用分散式版本控制系統 (DVCS) 時應該儘量保持小而頻繁的 commit 行為,我覺得值得一讀。

雖然作者使用的是 mercurial (hg),但其實跟 git 的觀念是很像的。

以下簡單導讀:
第一部分介紹這個做法的好處,像是可以很容易做 code review (就算是自己 review 自己的 code 也一樣容易)、容易知道現在做了那些修改 (使用 git diff 一目了然)。他還提到用二元搜尋法找到出錯的程式,可透過 git bisect 完成。而他有用到的 hg shelve 跟 hg revert 在 git 也都有對應的功能 (git stash 跟 git revert),前者是用來把目前 working copy 的修改「暫存」起來 (非 commit),之後可以再取出來繼續把它改完,後者則是可以還原特定 commit 的變更。也就是說,配合 revert,如果每個 commit 都很小的話,可以很輕鬆把特定修改還原。

第二部分講 DVCS 的好處,很重要的就是每個人可以自己搞自己的,又可以知道別人的脈絡。如果是在一人專案的狀況下,最基本上也可以省去跟遠端主機溝通的成本。但 DVCS 也有缺點,就是對於無法 merge (或根本不須 merge) 的檔案無法很好的處理。

後面部分,關於暫存的部分上面提過了,主要就是 git stash。而 hunk selection 在 git 中可用 git add -p 或是 git add -i (interactive) 做到,如果不小心一次寫了太多功能,可以利用這種方式分別 commit,才能保持 commit 小而頻繁,以獲得好處。

最後一個部分,列了幾個常見的無趣但重要的工作,偏重構方面的。作者建議把這些工作各自獨立成單一的 commit,而事實上這樣真的有很大的好處,看 log 跟 diff 的時候可以少花很多心思。