發表文章

目前顯示的是有「Hacking 心得筆記」標籤的文章

有趣的洗牌演算法

圖片
最近因為一些專案,所以需要實做一些撲克牌的洗牌機制。雖然這個動作看起來簡單,但其實對於開發者來說相當有趣,因為真的除了做這種牌類遊戲之外,平常很少用到這樣演算法,也由於有太多種做法,不免著迷於其中。 洗牌目的就是讓結果隨機、不能預期,只不過雖然很多遊戲同樣都是圍繞在亂數產生上面,但撲克牌遊戲(或麻將遊戲)最大的不同,就是同一排組每次發出來的牌,一但發過了就不會再出現一次。這一點,和每次都可以出一到六點數的骰子遊戲,就完全不一樣,不是隨機出一個亂數就可以搞定。 準備工作:先準備個牌組 開始前,先準備四種花色、A 到 K 的牌組,使我們可以以 0 至 51 的號碼去取得任意一張牌。 const suits = [ 'S', 'H', 'D', 'C' ]; const points = [ 'A', 2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K' ]; const cards = []; for (let i = 0; i < 4; i++) { for (let j = 0; j < 13; j++) { cards.push(points[j] + suits[i]); } } console.log(cards[10]); // 10S(黑桃10) 方法一:硬幹 最直覺的方法,不外乎就是不斷產生 52 張牌的亂數(0 ~ 51),然後檢查這張牌發過沒,如果牌發過了就重新產生一個新的亂數,持續這個步驟。 let shuffledCards = []; while(shuffledCards.length != 52) { // 取得 0 ~ 51 的亂數 let idx = Math.floor(Math.random() * 51); let card = cards[idx]; // 檢查這張牌是否已經出現過 if (shuffledCards.indexOf(card) !== -1) continue; // 沒出現過則放入陣列 sh...

NAN:Node.js 與 io.js 的 Native Addon 開發利器

自從 Node.js v0.11 版之後,內建的 V8 引擎被更新了,於是 JavaScript 引擎的原生 API 大幅度改變,導致很多以 C/C++ 所撰寫的原生模組紛紛出現相容性問題。影響範圍包括了前陣子發佈的 Node.js v0.12 以及 io.js 1.0+,因為都使用了新版的 V8 JavaScript Engine,而有同樣的問題。 其實這樣的問題已經不是新鮮事,自從 Node.js v0.8 到 v0.10 就開始有些許不相容的問題,只是到了 v0.12 和 io.js 之後,出現了更多狀況。因此 Node.js 圈子內的知名開發者 Rod Vagg  建立了 NAN 專案,用來解決這樣 Native API 不相容的問題。 NAN 全名為 Native Abstractions for Node.js,目標是設計一系列通用 API 供 Native Add-on 開發者所使用,讓開發者可以使用這通用的 API,一次性開發出支援 v0.8、v0.10、v0.12 和 io.js 1.0+ 的原生模組,不必再為 V8 原生 API 相容性所苦。 若想要使用 NAN,可以直接以 NPM 下載: $ npm install nan 然後在 binding.gyp 中加入 include_dirs 的屬性設定,讓 Node.js 或 io.js 引入 NAN 模組: 'include_dirs': [     "<!(node -e \"require('nan')\")" ] 經過這樣的設定配置後,我們就可以在 C/C++ 程式裡面引入 NAN 的標頭檔,開始使用 NAN 的 API: #include <nan.h> NAN_METHOD(Hello) {     NanScope();     NanReturnUndefined();     // 或是這樣寫 NanReturnValue(Undefined()); } 上面的程式碼,代換成舊的版本(v0.8、v0.10),就等同於: Handle<Value> Hello(const Arguments& args) {...

【OSDC.TW 2014 簡報釋出】當 QML 娶了 Node.js

圖片
去年一年在萬里當兵,基隆對我來說就像旁邊的公園一樣,時常去走走逛逛,然後去廟口吃點東西,最後吹吹帶有奇怪味道的海風,然後依依不捨的回去萬里山中隱居。很遺憾,黃色小鴨在我退伍的第二天,才來到基隆,一直沒機會去看看牠,這也是為什麼我為這次的 Talk 取了一個這麼奇怪的題目。當然,在 OSDC 的活動上,大多數人無法理解這樣奇怪的主題,所以我也在場上直接換了一個時事標題,詳見已釋出的簡報檔: 本次簡報的主題,將提到如何使用 Node.js 開發一個 QML 應用程式,以及如何使用 Node.js 去括充 QML 的功能。QML 能讓開發者很快設計出極酷炫的 UI,但最大的問題是他擁有一個殘廢的 JavaScript 支援,所以任何額外的功能擴充,都必需學會 C/C++ 才能達成,相當的難以開發。 此外,在過去如果 QML 要與 Node.js 做橋接,通常都是以 Node.js 建一個本機的 HTTP Server,然後運用 QML 內建的仿 XHR(使用方式和 API 真的完全模仿),去本機 HTTP Server 要資料。或許這對很多 Web 開發者來說相當容易上手,但有趣的是,他不會有 jQuery,所以你要自己手刻 Ajax 的各種機制,甚至是 Long-polling,痛苦至極。 想一下,我們即便是要與本機溝通,取得或監聽機器上的一些資訊,都要使用 Long-polling,這未免也太小題大做,一點也不簡單和直接。所以這也是為什麼要做 Qtjs,讓我們可以用 Node.js 直接來開發 QML 的元件,直接與 QML 溝通和傳遞資料,而不必再透過 HTTP 的方式。 就以本次簡報的例子來說,我們用 QML 設計了一個 IRC 聊天室的前端,然後運用 Node.js 和第三方模組去連線到 IRC Server,最後把聊天內容收回來畫在 QML 的界面上。並使用 Node.js 設計了一個 QML 元件,使用方式如下: IRC {     onReceived: {         console.log(nickname + ': ' + message);     } } 註:過去開發 QML 元件必需使用 C/C++,...

【OSDC.tw 2012 Hackathon 成果分享】用 JavaScript 打電話囉!

圖片
以為 OSDC.tw 2012 在 4/15 號時就結束了嗎?其實並沒有。在活動的一個星期後,於 4/21 星期六,OSDC.tw 接著舉行了 Hackathon 的活動。很多人可能不知道 Hackathon 是什麼,有人叫他『駭客鬆』、『駭客松』或是『駭客爽』,其實總歸來說,就是讓開發人員盡情開發程式的活動。 這類活動的規則是,參加的開發者可以自由組隊,提交想法,然後當場實作。最後,在活動結束前,讓各隊伍一一上台展示成果。由於開發者的創意常常天馬行空,又能看到實際成果,所以這類活動都相當有意思。這次,OSDC.tw 提供了無限量供應的食物還有場地,活動時間是從當天早上 9:00 到下午 6:00,成果發表是從下午 4:30 開始,每個隊伍約有七個半小時實作自己的提案。 這次 Hackathon 活動,我與『魏藥』組隊,選的主題是『使用 JavaScript 打電話』,意即使用 JavaScript 開發出一支 Linux 應用程式,可以像手機一樣撥出電話並與對方通話。選這主題是因為我們的機器上剛好有 3G 數據卡(Modem),所以這個提案的目的,主要是撰寫一個 Node.js 模組『jsdx-ofono』,去提供控制 Modem 的 JavaScript API,讓開發者可以透過這組 APIs 撥打甚至是傳接 SMS/MMS 之類的訊息。最後,為了驗證並展示,運用了之前開發的『jsdx-toolkit』,用 JavaScript 撰寫了一個簡單的撥號介面『jsdx-app-voicecall』。 註:因為時間太趕,後來才發現,撥號 UI 忘了放倒退按鈕,所以撥錯號時要把程式重啟。:-P 如專案名,其主要整合了 oFone ,應用了之前開發的 node-dbus,所以省下了不少時間,最後再以 jsdx-toolkit 快速實作了一個 UI。原本希望,如果時間再充足一些,我們計劃幫 jsdx-ofono 加上 SMS/MMS 和讀寫 SIM 卡電話簿的功能,可惜最後沒來得及。 註:因為時間也不足,我們還來不及將 Linux 上的麥克風接上 oFone,所以目前接通後,只能聽到對方手機傳來的聲音。 此外,這次展示的兩個元件『jsdx-ofono』和『jsdx-app-voicecall』都有在 github 釋出,歡迎取用: https...

我的 Kinect 應用程式開發記錄

圖片
話說微軟(Microsoft) 這兩年為了 XBox 360 所推出的 Kinect 造成一股風潮,一夕之間,把 Wii 打的七零八落,取代了其體感遊戲機王者的地位,相比之下,Sony PS3 同一時期所推出的體感裝置,就顯得乏人問津 。 最近,筆者雖然忙錄,被很多麻煩的公事私事綁住,但每當睡前,仍抽空研究一些新技術。一方面是為了促使腦筋轉得更快,一方面是想加強許多 Idea 和 Business Model 的強度和完整性。於是,撿起丟在一旁生灰塵的 Kinect,嘗試著在上面開發一些應用。 由於『 OpenKinect 』眾高手的努力,所以驅動程式不是太大的問題,很久以前就已經能分別在 Linux、Windows 和 Mac 上驅動 Kinect。不過雖說如此,最困難的還是在於辨識演算法的相關設計,對於開發人員來說,你不過就是能得到攝影機的影像,就如同從 Webcam 上得到一樣,其他的圖學運算以及應用還是要自己動手。 當然,如果 Kinect 只是和一般 Webcam 一樣,那新聞媒體和許多人對他的誇讚,就太言過其實。其最大的不同在於,Kinect 有深度感測,這意味著我們可以得到實際的空間資訊,以工程的方式,大大減少辨識演算法的難度,並提升了辨識系統的精準度。 這次的嘗試,焦點放在辨識演算法之上,便開始思索各種方案。過程中,試了數種別人已經開發好的函式庫,都不甚滿意。倒不是效果不好,而是系統需求太大,開發語言大多採用  Java ,所以需要安裝一卡車的模組程式以及 JVM。有些更是對 Linux 的開發者不夠友善,或開發支援不夠完整。無論哪一種現有方案,都不足以讓筆者可以安心建構在上面然後開發下去,因為產品化和易移植性,對筆者來說是相當重要的考量,不是只要學術驗證而已。所以最後決定,自己手動設計演算法,採用 C/C++。 經過這幾天睡前的努力,可以看到開發過程中的截圖,演算法初步已經能辨識手掌,並抓取指尖位置,精準度已達可用的程度。接著,只要多做些簡單的開發,撰寫 X11 輸入裝置驅動程式,就能實際以多點操控的型式,操作螢幕上的所有應用程式。 此外,這裡有一些心得,Kinect 深度感測的數值範圍是 0 ~ 2047,至於得到的深度數值如何換算成實體距離,這邊有個公式可以換算成公尺(Meter)的型式: Real Dist...

Python之我見

圖片
對一個『慣C』人來說,[ Python ] 實在是讓人無法去接受的程式語言,無論是效能、速度還是所吃的系統資源,都讓人不滿意。但以一個類 Script 語言來看待它,又是個極度強大又好用的東西,開發時程也比其他傳統語言短相當多,開發完成之後,也有相當大的再擴展和加速的空間。所以,若是開發出來的東西,沒有絕對強烈的『即時』和『精巧』需求,用純 Python 來寫,會相當合理。 應用需求導向 若您是熟悉 Windows 的開發者,可將 Python 視為 [ Visual Basic ],是一個著重於『立即應用』的存在(當然在本質上不相同,後者相對簡陋且更著重於【可視化程式設計】)。他們最相似之處就是開發模式,因為長久下來,已經有太多人為 Python 寫出無數的模組、功能,以致開發者只需要懂得引入和使用這些模組,就能達成所有能想到的功能,這點與 Visual Basic 的『控制項』開發模式沒什麼不同。 在今天,由於太多人的貢獻成果,使 Python 開發者幾乎無所不能,再者,其已經跨足了許多平台。對開發者而言,同一支程式,只要注意引入模組是否能跨平台(大多數功能多半都有解決方案),就能輕易寫出能運行於不同平台上的應用軟體,稱之跨平台的 Visual Basic 可不為過。 但如同許多前端網頁開發者隨處濫用 JavaScript + HTML,濫用 Python 的人也有不少。由於 Python 過於易用,許多人在開發上只求達成功能,忘了效率的考量(這觸動了『慣C』人最大的忌諱),過去一些比較著名的例子就是: emesene(Linux 上常見的 MSN 軟體) 和 iBus(輸入法系統架構),速度慢或吃光系統資源還不打緊,甚至是造成系統鎖死當機的狀況。 獨特的語言特性 說到 Python 語言本身,它有極為結構化的設計,又支援各種先進的開發模式,物件導向等技術當然不會少,以致使用 Python 來開發大型專案是非常可行的。若要舉個實例,大概就是 Google 的各項網路服務。 Python 擁有獨特的語言規則,像是捨棄『{};』等包裝語法,並強迫對齊等設計。這使得開發者不得不簡化和編排自己的程式,不能再寫出長又難以維護的程式碼。當然,這會讓已經習慣傳統語言規則的開發者,會有困擾和不習慣,需要一些時間適應。不過,一旦接受了 Python 的設計...

Our Happy Travel for GNOME Summit in Vietnam

圖片
This is first time that we(ULLab guys) make speeches at international event oversea, so we're so exciting on this travel. Core Founders of ULLAB Before this travel, in fact that I didn't know anything about Vietnam. I was just under the impression that Vietnam is a highly unstable country in Asia as well as this place is uncomfortable for us. Everyone all over the world always talks about the war and the girls in a bad way when mention Vietnam, so we never get a good impression about this place. However I must acknowledge that I was wrong now, Vietnam is a good place for enjoying our life absolutely, and also there are many people try to be surviving and becoming better in the world. Actually, many students in there have lifelong ambition, it shames me who is a Taiwanese. When we arrived Vietnam, the first thing which is traffic made us crazy. The traffic in Vietnam was scaring me, I never see so many motorbikes all over the road. My new friends who are local...

Clutter Rotation 的惡行

由於之前已經寫過太多雜文說明,『 Clutter Toolkit 』的威力應該就不必要再多說。雖然說 Clutter 開發上很容易,但在真正開始開發程式後,就會發現有很多地方細節需要注意。 關於開發 Clutter 程式時,會碰到的大部份問題,都出在於其設計邏輯與其他 3D Engine 不同,而最不一樣的地方,就是演員制度。Clutter Toolkit 特別的演員制度邏輯,使開發者將不再以大場景和 3D 空間定位為考量重點,而是以一個個 Actor 的角度去實作一切行為。因此,通常開發者第一個會碰到的行為就是『向左走、向右走』,單單使 Actor 旋轉到我們要的角度,就會碰到些問題。 ClutterActor 定義了一系列 function 去實作各種行為,其中旋轉的部份: clutter_actor_set_rotation(ClutterActor *self,                                         ClutterRotateAxis axis,                                         gdouble angle,                                         gfloat x,                                ...

使用 ssh 挖洞走密道!半夜深入禁宮!

話說廣大的 Windows 使用者,還在不停尋找可以用的 Proxy Server 賺取農民幣,每找到一個新的 Proxy Server 可以用,就有如於大海之中抓到一塊救命浮木,可以開心一整天。其實,身為 Linux/BSD 的愛用者們,可以不用跟麻瓜們湊熱鬧,使用 ssh 的 SOCKSv4/SOCKSv5 來做跳板不就好了?讓 Web Browser 透過 ssh 連線到 Facebook 玩開心農場,多麼愉快呢! 使用 ssh 去建立 Tunnel 如下: ssh -D 5487 <USERNAME>@<SSH SERVER> 待密碼認證和登入後,就可以改 Web Browser 的 Proxy 設定,改成使用 SOCKS Host,主機設成 localhost,而 Port 設成 5487 即可。 後記 我知道一定有很多人用這招,現在一定想罵死我,因為這塊 ssh 國外主機處女地大概要淪陷了。

好用的 Trace 工具 cflow

自己寫軟體,自己的邏輯,自己的世界,往往不會有什麼困難,這也是很多人從學生時代一路爬上來的歷程,直到進入到職場後撰寫著商業軟體,更是只有自己的一片天。但寫軟體有如寫作文,言之有物前必先廣閱天下文章,否則若是能獨樹一格是好,不能便陳腔濫調且原地踏步。但是看懂別人的程式實在是很困難的一件事,除了要懂他人寫程式的風格和思維外,還要通盤了解架構,這必須要有見山不是山的能力才能勝任。一般人想單靠著程式碼上彎彎曲曲的豆芽菜,反推回去程式的原貌,真有如瞎子摸象。對於做為一般人的我們,這時便要借助些工具,以幫助我們更省時省力的去 Trace 程式碼。 講到閱讀程式碼,『 cflow 』就是不得不提到的方便工具之一,它能夠幫助我們確認程式的大架構,以及分析程式碼相互的關聯性。這裡是使用 cflow 去演示分析 Android Dalvik VM,分析的檔案是 dalvik/dalvikvm/Main.c: $ cflow dalvikvm/Main.c main() <int main (int argc,char *const argv[]) at dalvikvm/Main.c:141>: setvbuf() malloc() memset() strdup() strcmp() fprintf() assert() blockSigpipe() <void blockSigpipe () at dalvikvm/Main.c:31>: sigemptyset() sigaddset() sigprocmask() fprintf() JNI_CreateJavaVM() createStringArray() <jobjectArray createStringArray (JNIEnv *env,char *const argv[],int argc) at dalvikvm/Main.c:44>: FindClass() ExceptionCheck() fprintf() assert() NewObjectArray() NewStrin...

實作於 User-space 的 pppd

前些日子在『 Linux 下的網路連線整合 』曾提到 Linux 網路機制的實作情況,若要做大整合,PPP (Point-to-Point Protocol)是首要考量的目標之一,因此這兩天就花了一點時間,透過現有 user-space 的 pppd 實作 PPP 的狀態提取,初步得到了些成果。 由於 PPP 存在的架構特殊,深入了解 pppd 的原理是必要的,如此才能完整處理資訊。不過,PPP 所牽涉的範疇比較廣,不少相關機制交錯於 kernel-space/user-space 之間,還好實作在 kernel-space 的機制,我們都可以統一透過 ioctl 去操作(如:Network Interface),並無太大困難。可是, PPP 實作於 user-space 的另一半機制,就沒有一定的 syscall 可以保證達成全部操作。 為何 PPP 有 kernel-space/user-space 的設計,要從瞭解 PPP 是什麼東西開始。正確來說,PPP 只是一種通訊協定,讓兩端通訊點能夠在此通訊協定上,建立 TCP/IP 等網路連線,它與硬體絲毫不相干,硬體裝置對它來說只是種傳輸資料的媒介。而一般人會誤以為 PPP 也處理 Modem 的 AT Command,是因為在過去語音通訊的年代,PPP 總是被拿來做在舊式撥號連線的通訊協定,大部份相關應用都是搭配 AT Command 使用。 也因為 PPP 本身很單純,在 kernel-space 的設計,只負責資料壓縮、解壓縮、轉換以及 Network interface 的建立和對應,而真正在與 Modem 溝通的,則是透過 user-space 的 pppd 這支程式。pppd 透過開啟 /dev/tty* ,並使用 AT Command 和 Modem 交換資料,取得通訊後再將通訊資料傳回 kernel-space 實作做解壓縮、轉換等處理,最後以 virtual network interface(ppp0, ppp1...) 的形式出現。 整個流程之中,其實 PPP 的 kernel-space 實作並不曉得資料是從哪個裝置進來,也不經手網路設定,除資料處理和 interface 對應的操作外,全都由 user-space 的 pppd 負責, pppd 的工作包括記錄 ppp0 與 /dev/tt...

Linux 下的網路連線整合

比較有聯絡的朋友們,大概都知道我最近正在忙著開發 LXNM(Lightweight Network Manager),這也是為什麼現在一直研究行動通訊的東西,前些日子發表的『 GSM/GPRS/HSDPA Modem 總是告訴我你在哪裡 』就大致記錄了個研究開頭。 原則上,LXNM 的設計是可以輕易 cross-platform,但因為開發環境上仍然使用 Linux ,所以還是以『 Linux 上可以動』做為第一階段的主要開發目標。而過程中發現,Linux 下所有的網路連線都是統一透過 Network Interface 去做管理,如常見到的 eth0、wlan0 等等。這對一般的網路卡(Enternet)和無線網路裝置(Wireless)來說,我們可以認定 Interface 所直接對應的就是硬體裝置,但是,數據機(Modem)卻是一種例外,並不算是一個 Network Interface。這令人胡塗,就硬體角度來看,他們應該都算是一種通訊用的裝置,但在 Linux 下是是如此不一致被處理。 若要使用 Modem 連上TCP/IP網路,則需要有撥號的階段,透過 PPP(Point-to-Point Protocol),然後建立一個 Virtual Network Interface,因為最終的可用網路連線(Connection)還是必需為 Network Interface 型態。可是這種虛擬的介面,並非直接對應到 Modem ,必需透過其對應的 PPP kernel driver 才能循線得知 interface 與 Modem 的關聯性,在這部份的實作有些困難。 然而,我們便可以將所有 Network Interface 視為可用的網路連線(Connection)了嗎?並不是這樣的,一個常見於家庭中的應用就可以打破了這定義 - ADSL。目前廣為一般家庭用的 ADSL 網路,多半都使用 PPPoE(Point-to-Point Protocol over Ethernet)做為連線的方法,這意味著我們還是得像 Modem 一樣撥號連線,只是一般 Modem 可能是透過 Serial port(如:/dev/modem、/dev/ttyUSB0),而 ADSL Modem 是透過 Ethernet Device(也就是某個 Network Interface,如...

GSM/GPRS/HSDPA Modem 總是告訴我你在哪裡

圖片
通訊技術發展至今,仍無法完全擺脫古老規格的框架,凡舉常見的撥接、ADSL(with PPPoE)、手機、到近年來的 3G(HSDPA),仍然使用著老掉牙的 AT 指令集當做通訊協定,更或者是說當今人類最先進的『數位通訊技術』根本是建構在老式交換機之上,只是換藥不換湯。而令人興奮的是,橫行市場十多年的神秘 GSM/GPRS/HSDPA Modem,只要在我們深入了解 AT 指令集後,就能揭開許多其不為人知的秘密。 也許你有支手機,但不可能也不需要為了研究而輕易拆解他,因為最容易取得的 GSM/GPRS/HSDPA Modem 實驗品可能就在身邊,就是手邊的 3G 網卡(HSDPA Modem)。承襲了手機留傳下來的 GSM/GPRS 等規格,其一整套的 AT 指令集,在 HSDPA Modem 裡都有被留傳下來,你可以驗證 SIM Card 是否被鎖、是否有新簡訊或瀏覽 SIM Card 的通訊錄等等,只要是手機上有的功能,在 HSDPA Modem 也都一應具全。 當然,你也可以透過 Modem 去搜尋和取得電信服務商的名稱,如下(請開兩個 Terminal 以方便操作,並假設 /dev/ttyUSB0 為 HSDPA Modem,該範例使用遠傳電信 3G 服務和 Huawei E220 網卡): Terminal 1: cat /dev/ttyUSB0 Terminal 2: echo -e "AT+COPS?\r" > /dev/ttyUSB0 在 Terminal 1 的結果: AT+COPS? +COPS: 0,0,"Far EasTone", 2 OK 另一個例子更有趣,我們可以透過 AT 指令去取得『目前地區編號』和『已連上線的基地台之服務範圍編號』: Terminal 2: # 設 mode 為 2,使 Modem 接受和回傳基地台訊息 echo -e "AT+CREG=2\r" > /dev/ttyUSB0 # 取得目前資料 echo -e "AT+CREG?\r" > /dev/ttyUSB0 在 Terminal 1 的結果: AT+CREG=2 OK AT+CREG? +CREG: 2,1,2396,1A54AF9 其中『2396』為目前地區編號(...

FreedomHEC Taipei 2009 - Fastboot 簡報上線

今年的『 FreedomHEC Taipei 2009 』如期於 6 月 10 日開始,請來許多重量級的外國講者,傳授很多 Kernel Driver 以及硬體相關的寶貴實作開發經驗,有人還拿著『 Linux Device Driver』一書,去找講者簽名。 :-) 小弟很榮幸受『 資策會 』邀請,並於該活動給了一場主題為『Fastboot』的 talk。現在簡報檔上線有興趣的人可以參考: FreedomHEC Taipei 2009 - Fastboot [ PDF ] Fastboot 議題自從 Netbook 效應開始,就被廣泛提出討論,也不斷有不同的實作被發展出來,『快速開機』彷彿已經是個新一代消費性電子產品的必備標準。因此,就算該議題已經被討論和研究有許多時日,許多人仍對其非常有興趣。有更多的快訴開機方法,仍未被完善的發展出來,這也是值得我們探討的一部份。

Linux Kernel 記憶體管理機制之美

Linux Kernel 的穩定,有一部份可以歸功於它優良的記憶體管理機制,而探討該機制,有助於瞭解記憶體是如何被 Kernel 所使用,對開發 Linux Driver 的人來說,日後更有許多益處。最重要的是,Linux Kernel 之美是由此開始,優美的設計相當令人著迷。 Linux Kernel 的記憶體管理機制,主要由兩大部份組成: Buddy System Slab Allocator Buddy System(buddy allocator) 如一般的 Operating System Design,Linux Kernel 一樣是以 Page 為記憶體管理的單位,因此設計了一層針對 page(或稱分頁)的管理機制,該機制在 Linux Kernel 裡被稱為『Buddy System (buddy allocator,簡稱 buddy)』,buddy 是 Kernel 最底層的記憶體管理機制,日後所有的記憶體配置,最後都要經過 buddy 才能取得或釋放記憶體。 可以藉由觀察當前 /proc/buddyinfo ,了解目前的記憶體使用情況,當然,是以 page 為單位: $ cat /proc/buddyinfo Node 0, zone DMA 76 71 66 50 33 17 5 1 1 1 0 Node 0, zone Normal 22301 6425 45 0 1 1 1 1 1 1 0 Node 0, zone HighMem 97 13 6 10 3 0 2 0 0 0 0 如果沒有什麼意外,/proc/buddyinfo 列會出了三個 zone ,分別是 DMA、Normal、HighMem,這三種 zone 的分類,是以 Physical Memory 位置的範圍而區分,在 IA-32 架構上 為: DMA (16MB以下) Normal (16MB~896MB) HighMem (896MB以上) 不過,由於 Buddy ...

精簡縮小 Shared Library 的體積

針對一般的 Shared Library(*.so),可以直接用 strip 去精簡縮小,可是許多 Plugin 的實作,像是 Xserver 的 Driver 等,會因為 strip 而損毀,導致不能使用。但只要借助一些 Option ,就可以達成縮小又不損毀到重要 symbol 的目的: strip --strip-debug --remove-section=.note --remove-section=.comment *.so

再談 FastBoot 快速開機簡記

因為某些案子的關係,春節後多日被迫關在飯店當 L (Who's L? 請參閱死亡筆記本),果然,龍崎這角色不是人當的,再關下去真的連坐姿和行為都會變得和他一樣奇怪(話說那樣的坐姿真的會讓智商提高!好像有?!)。沒枉費多日的努力,一個使用 ubuntu 的標準 config 所編譯出來之 Kernel 已經可以達到 1 秒的速度,理論上,若是再修剪 built-in 的 driver 應該可以達到更快速度。當然,單單只是 Kernel 快很容易做到,但 X Server 必需要在第 1.3 秒左右啟動,並在 第 2 秒前看到畫面,最重要的是有可用系統狀態,才算有實用的意義。 而關於 Kernel 部份,2.6.28 已做過許多快速開機的處理,其啟動已經非常快速,但是還會慢的瓶頸在於 initrd 的檢查,和各 device 初始的等待。經過 patch 後,這兩部份依硬體不同,可減少近 1 秒左右甚至更多的消耗。此外,盡可能讓 Root Filesystem 先被 Mount 也是一種手段,尤其再配合 initram 可以在瞬間就上到 User Space 的 Early boot 甚至進到 X Server,一般使用者可以看到 boot loader 一消失,緊接著就出現 X 的背景圖和 Cursor。 X Server 的快速開機處理有些方法,主要的做法是減少緩慢 I/O 的 Input Device 的等待時間,甚至是拖出正常 Initializing Progress,讓畫面先啟動。另外的瓶頸是各家 Video Driver 的問題,減少許多多餘的檢查有助於加快初始化速度。全部 patch 過後,基本上 XServer 啟動速度可達到 1 秒出頭(測試環境中,配合使用新的 Intel Video Driver)。 到此,一切看起來都很好,但最後發現 EDID 吃掉大半時間,單單為這 Monitor 的 Detect 就會影響使用 0.5 秒以上的時間,對某些 Specific 的 Hardware 可直接拿掉,但如何提前甚至時移到 Kernel 去跑,才是比較正確的做法。 目前,Boot Loader 的速度太慢,變成主要瓶頸,尤其以 Grub 的速度更令人不敢恭維,Loading 的速度比用 USB Drive 上的 Syslinux 還慢,這是還有...

Linux 的 Real-time 排程支援

POSIX.1b 定義了一系列的系統呼叫,去提供即時(Real-time)需求的支援,實作細節和實際效能則由各作業系統自行負責。當然,Linux 也依循了這標準,讓各個 Process 有能力的在有限度的範圍內,調整自己的在系統上排程。這裡所講,並不只是一般常見的系統優先權機制,而是建構在其之上的進階排程實作。 首先,可以從 sched_getscheduler(pid_t pid) 的回傳值中,取得目前程式的排程方法,有助於了解當前的排程情形,其可能回傳值如下: SCHED_OTHER SCHED_FIFO SCHED_RR SCHED_BATCH 範例原始碼(sched_policy.c): #include <stdio.h> #include <sched.h> const char *sched_policy[] = { "SCHED_OTHER", "SCHED_FIFO", "SCHED_RR", "SCHED_BATCH" }; int main(int argc, char *argv[]) { printf("Scheduler Policy is %s.\n", sched_policy[sched_getscheduler(0)]); return 0; } Compiling it: gcc sched_policy.c -o sched_policy Results: Scheduler Policy is SCHED_OTHER 標準預設的排程方法是 SCHED_OTHER,意味 Kernel 並不會為這些一般性 Process 做特別的即時排程處理。因為,我們所寫的程式,都沒有被特殊設定,所得到的將都會是使用 SCHED_OTHER。 值得探討的是 SCHED_FIFO 和 SCHED_RR,這是為即時(Real-time)需求所設計的兩種排程類型,在運作規則上,其實兩者是同樣的東西,只是 SCHED_RR 擁有時段分配的制約機制。 SCHED_FIFO (First In-First Out) SCHED_FIFO 顧名思義就是『先進先出(First In First Out)』,一但 Procees 是 FI...

Linux Suspend 之記憶體機制

休眠(Suspend)現在已經是 Laptop 必備的電源管理機制之一,而 Suspend 又分為 s2ram(Suspen to RAM)和 s2disk(Suspend to Disk) 兩種模式。若是啟動 Suspend 的機制,可以看到 Operating System 神奇的被暫停,然後 Resume 叫醒回到之前的工作狀態。如果說想深入瞭解這樣一個機制,可以從 Linux 的休眠實作來著手,swsusp 就提供了這樣一個 User-space 的實作,我們可以研究它的sourcecode。 大體上來說,Suspend 機制不過就是儲存當時系統 Memory 狀態,然後再啟動時還原回去,在實作時,必需先鎖定當時系統下所有的記憶體空間,以確保記憶體內容不再變動,可以分別用 mlockall() 和 munlockall() 來達成這樣的任務。 #include <sys/mman.h> int mlockall(int flags); int munlockall(void); flags 又分成: MCL_CURRENT 鎖定全部現有的記憶體分頁 MCL_FUTURE 鎖定未來將被新增的記憶體分頁 此外,swsusp 利用了 /dev/snapshot 來對 User Space Process 和 Swap 的操作,以產生目前 System 的記憶體映像檔,/dev/snapshot 可以用 ioctl() 去控制,其命令: SNAPSHOT_FREEZE 鎖定使 User Space Processes 靜止 SNAPSHOT_UNFREEZE 解除 User Space Processes 的鎖定 SNAPSHOT_ATOMIC_SNAPSHOT 建立一個系統的記憶體快照映像檔 SNAPSHOT_ATOMIC_RESTORE 還原系統記憶體狀態 SNAPSHOT_FREE 釋放快照映像檔的記憶體 SNAPSHOT_SET_IMAGE_SIZE 設定映像檔最大 Size,如果無法達到指定的 Size,kernel 會盡可能建立最小的 image SNAPSHOT_AVAIL_SWAP 取得可用的 Swap 大小 SNAPSHOT_GET_SWAP_PAGE 建立一個 Swap 頁 SNAPSHOT_FREE_SWAP_PAGES 釋放所有...

心得分享簡報上線:桌面開發、快速開機、快速開發

本次分享活動應熱烈,差點沒把敝人搾乾。而簡報以『作中學』為主要訴求,對像以對程式開發有興趣的普通人為主,應要求,『領進門』是本次分享的重點,所以不談論太高深的進階內容,並附上些簡單上手之實例。 本次三個簡報和相關範例檔案可在此取得: 桌面開發 desktop_dev.pdf easy-ui-design.tgz 快速開機 fastboot.pdf 快速開發 fastdev.pdf fastdev.tgz Autotool 懶人包: project_example.tgz 若有更多疑問,可直接與本人連繫和交流,能力所及,將不吝答覆。