2018年3月18日 星期日

實用的gdb 指令

最近工作上大量使用到 gdb,想說來整理一下一些常用的 gdb 使用方式,以及對應的場景;當然,這絕對不是 gdb 完整的功能介紹,只是目前我遇到比較多的使用方式而已。

檢視原始碼:
gdb 的文字介面可以顯示四種視窗:命令,原始碼,組合語言跟暫存器,與視窗相關的鍵盤組合:
Ctrl + x + a 它會分成上原始碼下命令兩個視窗
Ctrl + x + o 切換焦點所在的視窗,如果焦點視窗放在原始碼那邊,命令視窗的一些鍵會無效,例如上下鍵會變成原始碼視窗的上下瀏覽原始碼,得用 Ctrl + P (previous) 跟 Ctrl + N (next) 才能瀏覽歷史命令。
使用Ctrl + x + 1,Ctrl + x + 2 可以設定原始碼視窗分為一個或兩個,連續 Ctrl + x + 2 會依序在原始碼+組合語言、組合語言+暫存器、暫存器+組合語言三種組合中切換。
這功能可以直接看到現在執行到哪裡,特別是進到除錯熱區時,gdb 用 list 指令都會自動加10 行,要印出當下除錯的程式總有點難度,用這個可以徹底排除這個問題;不過我也覺得還沒到除錯熱區的時候,配合編輯器來看原始碼即可。

快捷鍵(這個不止是 gdb,而是大部分 shell 都適用):
除了上述的 Ctrl + p, Ctrl + n,Ctrl + l 可以清空目前的 buffer,Ctrl +w, Ctrl + u 可以刪除命令列上一個單字或全部內容,也滿好用的。特別是 gdb 裡面 shell 下清空 buffer 的指令 clear 沒有辦法用,Ctrl + l 使用機會滿大的(前提是原始碼視窗沒開)。

中斷點設置:
有關gdb 裡面的四個點:breakpoint, watchpoint, catchpoint跟tracepoint,到現在我也只用過前兩個,99 %都是 breakpoint:
breakpoint 又分為永久跟暫時,對應 break/tbreak 後面接要中斷的位置,可以用函數名稱或者 <sourcefile>:<linenum> 兩種格式。
還可以在 breakpoint 的後面加上條件,例如 break <function> if <var> == 10,就能開始 debug 某個狀況下的執行,這在除錯有迴圈或多次呼叫函式的程式時非常好用。
start 指令,自動設置 temporary breakpoint 在主程式開始處,C/C++ 就是 main。
Watchpoint 則是用watch/rwatch 指令設置,可以監看一個變數什麼時候被動過,指令監看的目標可以是變數、記憶體位置(如 watch *0x12345678)或是幾個變數的運算也可以。
watch、rwatch、awatch 分別監看變數寫入、讀取跟讀寫。

無論是breakpoint watchpoint其實都是… breakpoint(watchpoint 有時叫 data breakpoint),可以用 info break 看到所有相關設定,還有例如它已經碰到幾遍之類。
有一個相關的技巧如下,可以計算某個函數究竟遇到幾次:
break foo
ignore <breakpoint num> 100000 //大到遠超過可能執行的數量
continue
等程式執行完就能用 info break 看到這個 breakpoint 被碰幾次。

另外 debug 時,可以利用save breakpoints <filename>把設好的breakpoint 存到檔案裡,下次可以直接source它們,save 的 breakpoint 最好只設在函數名稱上面,行數可能在debug 時變化,下次source 時就會break在不同的地方了。
我習慣上會存成 gdbinit 這樣的檔案,一進 gdb 時 source gdbinit 即可。

修改執行:
執行中可以用
set var <variable name>=<value>
set <memory location>=<value
的方式修改變數/記憶體位址內容。
例如我們發現某個條件被跳掉會導致錯誤結果,可以在 gdb 內用 set 修改變數,使它符合條件,省去重新編譯的麻煩(甚至一些狀況下,修改程式可能動到本來的邏輯,或很難使它符合條件)

跳出函數執行:
指令 finish,執行直到離開當下函數(當然遇到 breakpoint 還是會被擋)。

介面
上面的功能,有些因為最近比較常用 ddd 而非 gdb,也就沒有常用到。
另外強者我同學強強林有推一款 web-based 的 gdb gui:https://github.com/niklasb/webgdb
,據說 vscode 的 debug 功能也滿生猛的,也許找時間都來試試看。

2018年3月11日 星期日

<令人難以理解的軟體工程師生涯>心得

先前在 Facebook 上面看到這篇文章(因為怕有人沒 Facebook 權限,所以貼關鍵評論網的轉載),看了看有些心得,就打在這裡:
https://www.thenewslens.com/article/91122
話說回來,我看了關鍵評論網的引言<我們想讓你知道的是>,還是不知道它想讓我知道什麼……。
其實這篇文有點跟原文對幹的意思,身為資淺軟體工程師這麼做好像有點不識大體,不過…反正我這個小咖 blog 也沒人看,大概也沒差,而且大部分的內容,多半去看<人月神話>就有了XDD。

十倍軟體生產力是否存在?我的答案是:Yes,肯定的 Yes
這件事情不單純在軟體,各行各業都是如此,熟練的高手能得到比一般平庸的操作員數倍的生產力,軟體奇特之處在於,生產力可以高到十倍甚至更高之譜,遠超過其他行業頂尖高手和一般人之間的差距。
箇中原因,在人月神話裡面已經有解釋:軟體是人類有史以來發明過最複雜的東西,是邏輯和數學的直接表達,寫好軟體就是一次次表達腦中的虛擬結構,而頂尖的腦袋的虛擬能力,遠在一般腦袋之上;之前就有個<學長告誡>:不要去問數學高手(aka 拿了兩次數奧金牌)數學問題,他講的話你聽不懂--他們虛疑化的層次遠超過你,你要想三步的東西他一步就講完了。
學會寫程式之後(差不多就大學吧),認識的很多很強的高手,真的是活生生體會到所謂的十倍-百倍生產力這件事,這些人現在要不是在 Google 大殺四方就是創業去了。
自己有時多少也會懷疑自己到底能不能做到那個程度,而且我相信,諸位軟體工程師的生涯中,一定也遇到過非常多10倍生產力的高手,也因此原本這篇貼文,才會獲得了如此大的迴響。

於是我們回到文中的大哉問:如果已經有了頂尖、十倍生產力的軟體工程師,那為何需要平庸工程師(就像我這種)?
軟體世界不是人多好辦事,但人少不成事。
原作者用了三個月的時間,改寫數萬行的程式為數千行漂亮的程式碼,非常厲害。
但一個 LInux 核心到現在有兩千萬行程式碼,如果像他這樣三個月估且算一萬行好了,要花 6000 個月,也就是 500 年才能寫完,這是可以接受的嗎?chrome 瀏覽器 500 萬行,firefox 一千萬行,每個都要十倍工程師孜孜不倦花好幾年手工打造嗎?還不要提現下消費者是每半年到一年要看到一次改版噢。
https://www.quora.com/What-is-the-biggest-program-lines-of-code-ever-made
這還不算上自己腦袋打結的時間,更不用提即便是天才也會有他的盲點,學的知識的它的上限,懂CPU的不一定懂網路,會演算法的可能不善於實作,懂資訊安全的可能不會硬碟……,系統長大之後會出現許多測試整合的工作,單打獨鬥鐵定有一個上限存在。
大型軟體本來就要綜合眾人之力,這又回到本來的問題:集合眾人就要溝通問題本質的數學邏輯,然後發生誤解跟整合問題,就算團隊全部都是10倍生產力工程師也無可倖免,以前總以為一流的軟體公司,像什麼 Google, Amazon 什麼的,裡面的程式一定都是藝術品等級,後來問問任職的同學,才發現根本不是這回事,有點年紀的大公司,軟體總是變成一團屎,還聽說過有幾個檔案變成 magic code ,根本沒人敢動的。
在跟強者我同學一哥聊天時,就有說到:「公司花錢請你來是要解決問題,不是把公司的東西變藝術品」、「每家公司都有鳥事,所以沒方向的話就選薪水高的」聽起來很世儈,但現實如此。

其實這幾年來,一直覺得台灣軟體最大的問題,並不是我們沒有夠多的10倍生產力軟體工程師,10倍軟體工程師本身就是一個異數,也許培養一群人裡,比例也就這麼多;更何況,過度看重十倍軟體工程師,顯然把世界想得太簡單,以為不管什麼問題,只要派出一位10倍軟體工程師都能迎刃而解,但很多問題卻不是如此。
我覺得我們最缺的,是培育出許多平庸的軟體工程師之後,如何拉一位 10倍軟體工程師,把大家組織成部隊來打群架(順帶一提,所謂的平庸工程師, 是指:給定一個嚴謹的規格,可以四平八穩完成開發,不要寫出會 buffer overflow 之類的低級錯誤,足矣。),我們很喜歡強調個人能力不足,但現在這個時代,就是要靠打群架才能打勝仗,如何把 10 位平庸的工程師組織起來,搭配一位 10 倍生產力的工程師,變成 50 倍生產力的團隊?只靠單打獨鬥,我們要如何挑戰百萬行甚至千萬行的系統?
也許哪天我們會看到:原本千萬行的程式,大家一起重寫的只剩下百萬行,功能不變,效能更好,而且架構儼然。前幾天完成 Alpha 版之後,大家不禁開瓶慶祝,笑聲充斥整個辦公室。

這大概才是台灣要追求的方向。

話又說回來,其實寫程式就只是寫程式,就算不寫程式跑去教書,腦袋還是可以想程式邏輯;上班寫無聊的程式,下班還是可以繼續學有趣的東西;就算當管理職不寫程式,把軟體架構切好,交給下面的團隊幫忙開發,對專案就沒有任何助益?誰說只有寫程式,還要寫得快又寫得漂亮才能貢獻社會?
理論上我們可以用寫程式數倍的時間,一行一行驗證我們的程式碼有沒有問題,把程式改到完全不會出錯,但世界不鳥這些,<不吃飯不睡覺,打起精神數鈔票>比較重要,程式當掉資料飛了,跟客戶土下座就好,反正沒有一次土下座解決不了的問題,如果有,就兩次。
寫程式其實沒有這麼偉大。

我們持續寫下去,只是因為寫程式很快樂,解決問題很快樂,重新打造輪子很快樂(等等…),覺得自己又變厲害了很快樂,完成大系統裡的小螺絲,很快樂
每位程式設計師,其實都是無可救藥的樂觀主義者。

2018年3月4日 星期日

Coursera Introduction to Logic

前些日子開始修了 coursera 上 stanford 大學開的 Introduction to Logic,修完而且有學到東西,其實個人習慣上滿常亂加一些 coursera 上的課程,有些聽一聽覺得無聊就沒聽完,沒聽完的就不會在這裡推薦就是。

下面是基本資訊:
課程名稱:Introduction to Logic
開課學校:Stanford University
授課教授:Michael Genesereth
開課時間:10 周
教學方式:靜態講義
通過方式:每週完成指定的作業,下面會詳述作業內容。

課程內容涵蓋基礎邏輯的概念,符號介紹,邏輯證明跟歸納證明,沒有到太複雜的內容,如果在台灣的大學有修邏輯的話,應該也是差不多的內容,例如通識很熱門的<邏輯丙>,應該內容也差不多。
不像其他課程是教授親自上陣講課,這門課上課的方式是看靜態文字講義(似乎有簡體中文不過我是看英文的),講義看過之後會自動記錄看過,相對來說看靜態文字比看教授講解還要無聊一些,而且有點吃英文能力。
課程內容很大一塊是放在 fitch system,並且證明也都是用 fitch system 來證明,每周作業會出約莫 5 到 10 題的題目,有些是選擇題,選到正確的選項即可;有些則是證明題,要證出所要的結果;有幾週會加一些邏輯遊戲跟參考影片,例如邏輯踩地雷,或者看教授演示一個邏輯表達系統。
證明題使用的是一個 javascript 寫的證明系統,可以用滑鼠選擇敘述,還有要使用的運算來完成證明,一開始有一點難上手,不過熟練之後就會覺得設計真的非常厲害,For all 跟 Exist 的符號代換都會自動完成,點一點就發證明完成了。唯一卡比較大的是在第八週的歸納法,久違地動用紙筆在紙上釐清議義範例證明的思路,想通之後在系統上重現就清楚多了。

學完之後真心覺得有學到東西,我從來沒想過原來連 (p => q) => (~q => ~p), (p => q) => (~p | q) , (p | ~p) 這樣基礎的邏輯也可以證明,但是千真萬確,證過一次才知道這真的可以用邏輯推出來,所以以前說的那些:前題錯就可以推出任何東西,「如果月亮是起司做的,那麼月亮可以吃」都是真的。
其他要注意的事情:寫作業的系統不知道為什麼,用 chrome 開的話會有些問題,用 firefox 來操作就沒問題。
另外,我誠心建議大家睡前不要讀邏輯,讀邏輯當然要沐浴更衣正襟危坐有一次念完之後睡覺,結果在夢裡想歸納證明………,醒來累得半死。