顯示具有 dalvik 標籤的文章。 顯示所有文章
顯示具有 dalvik 標籤的文章。 顯示所有文章

加速 Android 的動態連結

就如人們所熟悉,Android 底層運作 Dalvik 虛擬機器,在 C Library 層面採用衍生自 NetBSD libc 的 bionic。與過往的 Java 為基礎的操作環境 (OE; Operating Environment,如 Transvirtual 的 PocketLinux / XOE) 不同的是,每個 VM instance 均為獨立的 Linux process,且由 Zygote 所「孵化」。就系統的角度來說,縱使底層對 system library 做了 prelink (透過工具 build/tools/apriori),但因語言實做的特性,需頻繁經由 JNI 去存取底層服務,也就是說,有大量的 dlopen()/dlsym() 操作,這些均無法透過 prelink 來縮減載入時間。

COSCUP 2010 的議程「打造特製的 Android Toolchain」中,小弟介紹了 0xlab 近來的幾項嘗試與改進項目,除了 GNU Toolchain (採用 gcc-4.4.4 搭配一系列的修改) 之外,就包含 Android bionic libc 與 prelink 的修改,企圖引入 DT_GNU_HASH 的機制 (也稱為 gnu hashstyle,或 gnu hash),以加速 Android 的動態連結。現在基礎工作大致完畢,陸續提交到 AOSP (Android Open Source Project) 的 Code Review,應該會納入 Android Gingerbread 以及後續的版本中。實驗平台採用 Qualcomm MSM7x25 (arm1136j-s),平均縮減 26% 的 ELF 動態連結時間,這對所有的 Android Activity (Java 程式) 與需要額外作 dlopen() 處理的系統函式庫,如 Qualcomm 的 camera HAL/service 或 Opencore/DSP,均可適用。

這過程中,讓小弟學習到頗多,從一開始的分析 (透過 oprofile 與開啟 bionic 裡頭 linker 的除錯資訊),觀察到 Android 的動態連結處理,有點類似 OpenOffice 所面臨的議題,於是嘗試引入 DT_GNU_HASH。背景知識可參考以下文獻:

gnu hashstyle 採用 Daniel J Bernstein 提出的 hash function,Jakub Jelinek 做了分析,比較原本 ELF hash:

The number of collisions in the 537403 symbols is:
name 2sym collision # 3sym collision # more than 3sym collision #
sysv 1749 5
libiberty 42
dcache 37
djb2 29
sdbm 39
djb3 31
rot 337 39 61
sax 34
fnv 40
oat 30

sysv 那項是原本的 hash function,而 djb2 則是 GNU Toolchain 採用的方案。就現有自由軟體的實做來看,包含 glibc, uClibc, dietlibc (前三者支援 GNU/Linux), FreeBSD libc 均提供 gnu hashstyle 的支援,但 Android 未正式在 bionic 提供。需留意的是,prelink 方案總是比 gnu hashstyle 帶來更快的動態連結時間,但付出的代價 (空間) 較高,而且不若後者有彈性。

read on
Posted 張貼者: jserv 於 晚上9:52 on 2010年10月19日 星期二 | 4 意見
Filed under: , , , , ,
 

在 Android/Dalvik 環境引入 precompiled class 的實驗

延續筆者去年的紀錄「當 Compiler 遇上 Mobile」,最近我們又獲得一些進展,是在 Android 的 Dalvik 虛擬機器環境中,引入 pre-compiled class 的實驗,除了可改善執行時期的效能、記憶體使用量外,另外就是避免在「反組譯並修改 Android 應用程式實例」一文可見的資訊保護議題。

其實十幾年前,在 Java 平台中就有相當多團隊提出可行的方案,而世界上第一個開放原始碼的 Kaffe 虛擬機器專案,早在 1999 年即提出實做 "Kaffe/GCJ integration",成功地將 GCJ (GCC for Java) 自 Java class/source 編譯得到的機械碼,當作 pre-compiled shared library,讓 Kaffee VM 讀取,預期可有效改善執行效能並縮減起始時間。GNU Classpath 專案主持人 Mark Wielaard 在 LWN 的文章 "GCJ - past, present, and future" 提到相關的歷史與技術背景,最早可回溯到 Cygnus solutions 時期 (RedHat 尚未併購) 的 GCJ 計畫提案 -- "A Gcc-based Java Implementation"。

為了降低實做的複雜度,筆者最早採用 LLVMIcedTea 作為系統框架,不過一直到今年春節,整體進度還是陷入膠著的狀態。現在則引入 Java2C 搭配 PGO (Profile-Guided Optimization) 與統計模型,嘗試分析運行於 Dalvik VM 的 Android activity / system server,佔用系統資源最頻繁的項目,並預先編譯 (pre-compile) 這些 class/method,居中透過 JNI (Java Native Interface) 讓 Dalvik VM 存取。不過,實務上來說,不是將所有 class/method 都編譯為原生機械碼,就會帶來效能提昇,相反地,後者往往讓系統陷入更差的效能。目前 Eclair 裡面的 Dalvik VM 雖然沒有完整的 JIT compiler,但其 fast interpreter for ARM 的確做了頗多 threaded interpreter 的改進,考量到 I-cache, paging, 與 branch prediction,若我們不思量 Java / Android Dalvik 應用程式的執行時期行為,只是一味作編譯轉換,很可能只是編譯極少被執行,或者完全不會被執行到的程式碼,因此加重執行時期的負擔,而最該被優化的部份,受限於不完整的 source-to-source 轉換,有顧此失彼的疑慮。

於是,找出系統中最該被優化的部份,並考量到正確性與相容度,就是我們的首要研究議題,筆者採用知名的 SciMark 2.0 作為量化分析的指標。以下是在 Qualcomm MSM7x25 硬體平台 (arm1136j-s) 的效能評比,ARM11 的時脈是 528 MHz,ARM Linux 版本為 2.6.29.6-0xlab:
由上可見,在 SciMark 2.0 的各項評比中,Pre-compiled class 執行效能都較 Android Dalvik fast interpreter for ARM 給予一定程度的改良,並且透過 FDO (Feedback Directed Optimization),大多可進一步給予提昇。這僅是初步的整合實驗數據,還需要更多分析與進行實做。

read on
Posted 張貼者: jserv 於 凌晨1:01 on 2010年5月26日 星期三 | 8 意見
Filed under: , , , , , ,
 

反組譯並修改 Android 應用程式實例

為了某個實驗的動機,我們評估反編譯 Android 應用程式的可行性,本文即是筆者的心得與實際的範例,僅供參考。就筆者的認知,目前還沒有針對 Android 的 DEX to Java source 反編譯工具,可實際處理一般的 Android 應用程式,多半要繞幾圈,還會得到不甚理想的結果,不過,smali 這個反組譯工具,已是可用了,只是得對付類似 Jasmin 語法的 Dalvik 組合語言。筆者打包了 smaliFrozen Bubble for Android,作為示範:

在 GNU/Linux 環境中,首先取得 Android SDK,這裡採用 Eclair/2.1,工具執行檔的路徑是 android-sdk-linux_86/tools,將此路徑放入 $PATH 環境變數,如此一來,就可以操作 adb, aapt, apkbuilder 一類的工具程式。筆者提供的套件已包含 Frozen Bubble 執行檔,檔名為 "FrozenBubble-orig.apk"。一旦 Android emulator 啟動後,即可安裝進去執行:(後續的操作也需要 Emulator 持續開啟)
$ adb install -r FrozenBubble-orig.apk
以下是執行畫面:
當然,沒必要讓筆者置喙談如何玩這個經典遊戲,不過我們倒是想更改原本的行為。在進行之前,我們先來複習 Android APK 的建立,參考 "How to build Android application package (.apk) from the command line using the SDK tools + continuously integrated using CruiseControl." 一文,我們可從以下圖表知悉細部的流程:

假設我們完全無法取得原始程式碼,該如何進行呢?沒錯,就透過 smali,簡化繁瑣的流程,筆者包裝為 Makefile,所以只要先解開並反組譯:
$ make extract
這時候會看到兩個目錄:
  • smali-src : 存放反組譯的程式檔輸出
  • workspace : 原本 Frozen Bubble 的 Android resource files
二話不說,當然是觀察反組譯的結果:
smali-src$ find
./org/jfedor/frozenbubble/FrozenBubble.smali
./org/jfedor/frozenbubble/R$id.smali
./org/jfedor/frozenbubble/GameView.smali
./org/jfedor/frozenbubble/SoundManager.smali
./org/jfedor/frozenbubble/LaunchBubbleSprite.smali
./org/jfedor/frozenbubble/Compressor.smali
./org/jfedor/frozenbubble/R$attr.smali
./org/jfedor/frozenbubble/BubbleFont.smali
./org/jfedor/frozenbubble/PenguinSprite.smali
./org/jfedor/frozenbubble/GameView$GameThread.smali
./org/jfedor/frozenbubble/BubbleSprite.smali./org/jfedor/frozenbubble/R$string.smali
./org/jfedor/frozenbubble/R$drawable.smali
./org/jfedor/frozenbubble/ImageSprite.smali
./org/jfedor/frozenbubble/BubbleManager.smali
./org/jfedor/frozenbubble/GameScreen.smali
./org/jfedor/frozenbubble/R.smali
./org/jfedor/frozenbubble/R$layout.smali
./org/jfedor/frozenbubble/BmpWrap.smali./org/jfedor/frozenbubble/FrozenGame.smali
./org/jfedor/frozenbubble/Sprite.smali
./org/jfedor/frozenbubble/LevelManager.smali
./org/jfedor/frozenbubble/R$raw.smali
就忠實地依據 Java package 的方式呈現,檔名結尾是 ".smali"。筆者的修改目標是,讓一開始的關卡 (Level) 從第一關直接跳躍到第五關。在 smali 原始程式碼 (注意:這完全不同於 Java 原始程式碼,而是極為貼近 Dalvik VM 所接受的 DEX 檔案的組合語言形式) 搜尋 "Level" 字眼,可發現主要的分佈就落於兩個檔案:
  • ./org/jfedor/frozenbubble/GameView$GameThread.smali
  • ./org/jfedor/frozenbubble/LevelManager.smali
前者就是 org/jfedor/frozenbubble/GameView.java 的編譯輸出,因為是 inner class,獨立編譯出 org/jfedor/frozenbubble/GameView.class$GameThread.smali,由這個 class 命名方式大概就可猜出其重要性,基本上只要能夠控制此 class 的實做,就掌握此 Android 應用程式的行為。而 class LevelManager 顧名思義,看來掌握了遊戲進行的程序控制。先觀察其 method 列表:
smali-src$ grep "\.method" org/jfedor/frozenbubble/LevelManager.smali
.method public constructor <init>([BI)V
.method private getLevel(Ljava/lang/String;)[[B
.method public getCurrentLevel()[[B
.method public getLevelIndex()I
.method public goToFirstLevel()V
.method public goToNextLevel()V.method public restoreState(Landroid/os/Bundle;)V
.method public saveState(Landroid/os/Bundle;)V
倘若我們以 "goToFirstLevel" 一類的關鍵字,在 org/jfedor/frozenbubble/GameView$GameThread.smali 檔案中搜尋,可找出有具體的呼叫行為:
smali-src$ grep -r goToFirstLevel *
org/jfedor/frozenbubble/GameView$GameThread.smali: invoke-virtual {v2}, Lorg/jfedor/frozenbubble/LevelManager;->goToFirstLevel()V
org/jfedor/frozenbubble/LevelManager.smali:.method public goToFirstLevel()V
由此更確定我們之前的猜想。其中組合語言寫為以下:
move-object/from16 v0, p0

iget-object v0, v0, Lorg/jfedor/frozenbubble/GameView$GameThread;->mLevelManager:Lorg/jfedor/frozenbubble/LevelManager;

move-object v2, v0

invoke-virtual {v2}, Lorg/jfedor/frozenbubble/LevelManager;->goToFirstLevel()V
不要被貌似複雜的語法嚇到了,基本上掌握 Java 程式語言的原則 "Everything is Object" (不過仍有提供 primitive type),組合語言仍會作 Java Object 的實體化 (instantialization),Dalvik 本身是 Register-based Virtual Machine,而扣除 static/class method 外,Java 中所有的 method invocation 多為 virtual function (對應於 C++ 的觀點,才能更具體用機械方式思考),所以組合語言的指令為 "invoke-virtual" (注意有連字號,此與 Java bytecode 不同),"{v2}" 表示第一受者的 Register,此為 Object 本體。接著,與 Java bytecode 一樣,"Lorg/jfedor/frozenbubble/LevelManager;" 就表示 Java 層面的 class "org.jfedor.frozenbubble.LevelManager",字母 "L" 即為 class 的識別,而 "->" 就很直觀了,自然是 method invocation,所以連貫來看,這一段組合語言的 Java 意思為:
objectLevelManager.goToFirstLevel();
其中 objectLevelManager 是一個 class LevelManager 的實例/實體 (instance)。倘若需要在 method invocation 時,帶入參數,那麼前述的 "{v2}" 一般會被替換為 "{v0, v1, v2, ...} 的 register 列表。關於詳細的狀況,可參考 Dalvik 非官方說明,另外 smali 的 wiki 也提供一些範例,可多加利用。

回到筆者剛剛設定的目標,我們既然知道 class org.jfedor.frozenbubble.GameView$GameThread 掌控了程式處理邏輯,自然一堆變數的傳遞、method 呼叫,都在此進行,那我們先試著用 "level" 字串去搜尋,想辦法找出常數定義,後者在 Dalvik 中,會集中保存於 constant pool 中,而 smali 的組合語言寫法大致是 "const" 開頭的宣告,端看其類型而定。以程式追蹤的目的來說,我們專注於以下兩種:
  • const-string : primitive string (不同於 java.lang.String) 表示
  • const/4 : 長度為 4 bytes (32 bit) 的整數表示
字串何其多,依據之前的推測來說,我們要找接近 "LevelManager" 字眼的組合語言程式碼,道理很明顯,從一般 Java programmer 的寫作邏輯去反推。經過一番搜尋,我們找到以下的反組譯程式碼: (位於檔案 org/jfedor/frozenbubble/GameView$GameThread.smali中)
const-string v3, "level"
const/4 v4, 0x0
move-object/from16 v0, v25 move-object v1, v3
move v2, v4
invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences;->getInt(Ljava/lang/String;I)I
move-result p4
new-instance v3, Lorg/jfedor/frozenbubble/LevelManager;
move-object v0, v3
move-object/from16 v1, v22
move/from16 v2, p4 invoke-direct {v0, v1, v2}, Lorg/jfedor/frozenbubble/LevelManager;-><init>([BI)V
在上述程式碼列表中,"Lorg/jfedor/frozenbubble/LevelManager;-><init>" 表示呼叫 class LevelManager 的 constructor,也就是 "<init>"。注意到 method invocation 方式就不同了,是 "invoke-direct",表示 class constructor,而這之前要有 "new-instance v3, Lorg/jfedor/frozenbubble/LevelManager;" 的組合語言指令宣告。

前面談過「倘若需要在 method invocation 時,帶入參數,一般會被替換為 "{v0, v1, v2, ...} 的 register 列表」這樣的概念,我們可推知,Register v1 與 v2 就是實際上 class org.jfedor.frozenbubble.LevelManager 的 constructor 參數。就程式設計的邏輯來看,class GameView 就是依據某個流程,要求 LevelManager 去改變狀態,所以這裡的兩個參數,其實就是初始值,非常的重要。

與 Register v1 相關的組合語言指令有這幾行:(用粗體字標示)
const-string v3, "level"
const/4 v4, 0x0
move-object/from16 v0, v25
move-object v1, v3
move v2, v4
invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences;->getInt(Ljava/lang/String;I)I
move-result p4
new-instance v3, Lorg/jfedor/frozenbubble/LevelManager;
move-object v0, v3
move-object/from16 v1, v22
move/from16 v2, p4
invoke-direct {v0, v1, v2}, Lorg/jfedor/frozenbubble/LevelManager;-><init>([BI)V
顯然,Register v1 還被帶入到 android.content.Shared.Preference.getInt() method,而更早以前,其內含值被設定為 Register v3 的值,也就是常數字串 (const-string) "level",這好像與我們的焦點不同。另外,像是 Register v22 這個編號較大的 register,表示 local variable,這點需要多留意,因為 Java 程式設計的規範來說,往往會將程式切割為若干 method,而 method 實做體中,又有極多的 local variable,於是往往可從組合語言反推 Java 原始碼的型態。

那麼,看看 Register v2 吧,同樣用粗體字標示相關的指令:
const-string v3, "level"
const/4 v4, 0x0
move-object/from16 v0, v25
move-object v1, v3
move v2, v4
invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences;->getInt(Ljava/lang/String;I)I
move-result p4
new-instance v3, Lorg/jfedor/frozenbubble/LevelManager;
move-object v0, v3
move-object/from16 v1, v22
move/from16 v2, p4
invoke-direct {v0, v1, v2}, Lorg/jfedor/frozenbubble/LevelManager;-><init>([BI)V
這個 Register v4 的內含值 "0x0" 會指派到 Register v2 中,而讓我們似乎找到方向了,回頭看看 class org.jfedor.frozenbubble.LevelManager 的 constructor 宣告方式: (之前 grep 結果的第一行)
smali-src$ grep "\.method" org/jfedor/frozenbubble/LevelManager.smali
.method public constructor <init>([BI)V
其中 "public" 是 ACL (存取權限) 的宣告,而 constructor 的符號規範為 "<init>",注意到括號 "(" 與 ")" 裡面的兩個大寫字母,表示接受兩個參數,對應的型態為:
  • B : byte
  • I : int
在 Java 與 Dalvik virtual machine 皆以同樣的形式作宣告,看到這裡,我們實在忍不住要動手修改了,當然,一切都是實驗性質。既然一開啟遊戲,畫面就顯示 Level 1,表示 LevelManager 一開始接受的 level 參數會是 "0",然後依據 GameView 的邏輯,逐一升級或中斷遊戲進行,那麼,如果要讓遊戲一起動就是 Level 5,是不是要把內含值改為 0x4 即可?也就是 "invoke-direct {v0, v1, v2}, Lorg/jfedor/frozenbubble/LevelManager;-><init>([BI)V" 的 Register v2 當時內含值該為 0x4,不就任務達成了嗎?想到此,不禁會心一笑。

不過,回顧稍早 Register v2 的相關程式碼輸出,其中有兩行需要留意 (以粗體字為主):
invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences;->getInt(Ljava/lang/String;I)I
move-result p4
new-instance v3, Lorg/jfedor/frozenbubble/LevelManager;
move-object v0, v3
move-object/from16 v1, v22
move/from16 v2, p4
"p4" 用以保存 method invocation 之後的回傳值,顯然,Register v2 受到 p4 的指派,也就是被更動為 android.content.Shared.Preference.getInt() method 的回傳值,這存在不確定性,於是,我們乾脆一口氣改掉: (修改的部份會用井字號 "#" 作註解)
# Modified from 0x0 to 0x4"
const/4 v4, 0x4
move-object/from16 v0, v25
move-object v1, v3
move v2, v4
# Modified: removed the following 2 lines
# invoke-interface {v0, v1, v2}, Landroid/content/SharedPreferences;->getInt(Ljava/lang/String;I)I
# move-result p4
new-instance v3, Lorg/jfedor/frozenbubble/LevelManager;
move-object v0, v3
move-object/from16 v1, v22
# Modified: removed the following 1 line
# move/from16 v2, p4
invoke-direct {v0, v1, v2}, Lorg/jfedor/frozenbubble/LevelManager;-><init>([BI)V
改好程式,當然要驗證,回到上一層目錄,透過 smali 提供的組譯器,重新產生 Dalvik DEX 輸出,為了簡化流程,筆者把 smali, apkbuilder, aapt, adb install 都一次整合進去,所以會直接讓 Android Emulator 生效,來看看我們的戰果吧:
注意到左下角,這表示我們成功了,完全不用取得 Java 原始程式碼,就可以作反組譯並且修改的動作。

read on
Posted 張貼者: jserv 於 晚上10:08 on 2010年5月21日 星期五 | 4 意見
Filed under: , , , , , ,
 

在 Beagleboard 上比較 Dalvik 與 CVM-jit 的效能

前文「對 String 操作的改進」與「Android Dalvik VM vs. Java VM」談及基於 CVM 引擎的 Java VM 與 Dalvik 的效能差異後,最近 0xlab 內部也因為挑選硬體平台,持續分析 Embedded CaffeineMark 一類量化效能的報告。參考的硬體組態是 OMAP3/ARMv7 500 MHz,粗略的效能評比如下圖:

Dalvik 取自 0xdroid (cupcake + backported from donut),而 CVM-jit 則源自 phoneME CVM svn r19264,整體分數為:

  • Dalvik VM : 1034
  • CVM + jit : 7526
CVM 的組態設定:
  • cached constant
  • cached constant inlining
  • array init bounds check elimination
  • Hardware fpu = NEON
  • AAPCS
當然 Just-In-Time compiler 不是萬靈丹,從上述效能評比可發現,CVM 在若干地方做了重要的微調,比方說透過 CNI 實做若干 class library 的關鍵 method,以及善用硬體 floating-point 操作 (注意:本組態未引入 ARMv6 與 ARMv7 的 Thumb2/Thumb-EE 指令集)。儘管 Android 團隊中 Dalvik 開發者 fadden 在郵件討論群組談及
Four String methods -- charAt, compareTo, equals, and length -- are
"inlined" by the VM, and are not going to get much faster.

There are probably a few others that could benefit from this
treatment, but I'm guessing that most string-centric processing in
Java will likely be dominated by the cost of String allocations. (The
above weren't inlined because of a measured performance need -- the
inlining was an experiment that needed a test subject.)
Dalvik 理論上可施加這些優化技術 (string allocation / native method inlining),不過目前開放的實做中,尚未引入 (至少在 donut branch 中)。即便在保持 pure interpreter 的架構下,現有 class library 與 GC (garbage collector) 仍可作些調整,以改善 Android 的應用程式執行效能與 (圖形應用導向的) 使用者互動反應表現。

read on
Posted 張貼者: jserv 於 上午10:54 on 2009年8月25日 星期二 | 4 意見
Filed under: , , , ,
 

對 String 操作的改進

之前的文章「Android Dalvik VM vs. Java VM」提及純 interpreter 的 Dalvik VM 與具備 Just-In-Time compiler 的 JBend JVM (基於 CVM 引擎) 的效能比較,以修改過的 Embedded CaffeineMark 作為量化的依據,可發現 String 測試項目差了一個數量級 (491 vs. 5109),整體的分數是 1:4.18 (1811:433)。稍早 ansoncat 做了初步分析:

「這部分應該是由於在 CVM 中,使用了 CNI 來實作 String class 的重要操作 ... 因為 String 的分數拉高了平均,其它 benchmark 的效能差異會比平均分數的差異大的多」
目前 0xdroid 在不更動 Dalvik VM 實做的前提 (後續再談改進的途徑),對 bionic libc 的 string 相關函式作調整,移植來自 CodeSourcery/ARM 的 ARMv7 Thumb2 優化實做,就 micro-benchmark 的角度來說,效能改進約有 25% (初步分析,要考慮到不同的環境配置),但整合到 Android/Dalvik 的表現又是如何呢?筆者的實驗結果如下: (score 大者為佳)

測試環境是 Beagleboard (500MHz) 運作 0xdroid,以 ARMv7 GNU Toolchain 編譯,"armv7" 是 bionic 更動前的數據,而 "armv7-opt" 則是更動後的表現。很顯然發現,String 一項的改進大幅受到壓抑 (score = 1898:2140),致使兩者最終僅有些微的落差,可見 JNI 帶來 overhead 的著實不小。又,大部分應用程式的效能瓶頸往往在於圖形處理、系統資源的調度、檔案讀寫等 I/O 操作,所以現階段我們的想法是儘量調整 native 的部份,針對 ARM core 與 SoC 的特性作調整,並提出可行的輕量級 native method invocation 實做。

read on
Posted 張貼者: jserv 於 凌晨4:40 on 2009年8月13日 星期四 | 0 意見
Filed under: , ,
 

Android Dalvik VM vs. Java VM

Google Android 開發團隊為了技術自主、迴避 Java 商標爭議等考量,建構了嶄新的 Dalvik Virtual Machine,骨子裡頭仍支援 Java 程式語言,但 Dalvik VM 設計稍異於典型 JVM,網路上已有豐富的比較,本文就不贅述,筆者想探討的,則是日本 eFlow 公司最近提出的 'Android™'s Dalvik VM on "Mobile Java"',目標就是讓原本的 Java 執行平台 (主要是 Java ME),得以運作針對 Android Dalvik VM 設計的應用程式。日前該專案已開放原始程式碼,主體依據 GNU GPLv2,以下是相關資訊:

目前的進度來說 (svn r22),支援以下功能:
至於是否能達到 eFlow 公司 CEO -- Koichi Makabe 所預期的效益:
"We believe this implementation will particularly benefit manufacturers currently developing Android-powered devices, with a number of which we are cooperating to port the Dalvik VM to their specific hardware and software architectures. By making this implementation available today as open source, and by accelerating our porting and development efforts, we have the firm intention to make a significant contribution to the broader Android community."
這裡無從得知,不過,該專案四月底時,一併將 dalvikvm_benchmark 釋出,伴隨內部的效能分析數據,非常有意思。從裡頭的資料來看,標的硬體平台有兩個:
前者無疑就是用來比較的基準,硬體是 Qualcomm 平台,軟體組態當然是跑 Dalvik VM,運作時脈為 528 MHz。後者就相當有意思,P905i 是日本 NTT 電信的第三代手機平台,以豐富的多媒體與超長待機時間著稱,硬體採用 Panasonic UniPhier 家族,運作時脈達 500MHz,軟體方面,則內建 JBlend 這個商業 Java ME CLDC/MIDP 執行環境。儘管軟硬體組態均大相逕庭,不過研究 android-dalvik-vm-on-java 提供的內部的效能分析數據,多少有參考的價值。筆者整理為以下圖表:
綠色部份 (靠右側者) 為 Google Dev Phone 1,紅色 (靠左側者) 則是 P905i,分數越高者越佳。在同一份 benchmark 測試方式來看,兩者有極為顯著的落差,整體表現數據為:
數字背後的意義則是,Dalvik VM 進一步優化的空間仍相當大,至於如何在 ARM11 平台,透過若干進階的技巧 (JIT, register allocation, ...),發揮 Dalvik 這個 register-based VM 的效能,是不少研究人員關心的議題。

read on
Posted 張貼者: jserv 於 晚上10:04 on 2009年5月10日 星期日 | 2 意見
Filed under: , , , ,
 

當 Compiler 遇上 Mobile

過去我們很難聯想進階的編譯器 (compiler) 技術到底與移動平台何涉,但隨著基礎建設的突破,我們就該有不同的思維。

從1960 年代發展至今,編譯器技術已是電腦科學最成熟的基礎之一,不斷地成長與蛻變,而透過 open source,GNU GCC 與 LLVM (Low Level Virtual Machine) 計畫獲得空前的成功,累積了驚人的編譯器技術。儘管 parser 仍是 compiler 的關鍵技術,但今日,我們會著重於打通任督二脈的技術展現,過去耳熟能詳卻貌似獨立的項目,比方說 virtual machine, binary translator, JIT compiler, HotSpot JVM, 等等,如今好似整合了金庸書中的武功精髓、淬湅出武術菁華,形成一套獨到的武功系統,透過 LLVM 一類的整合性技術而一瀉千里。

幾年前,知名的遊戲設計公司 id Software 在該公司靈魂人物 John Carmack 的主導下,將 Doom (毀滅戰士) 核心的遊戲引擎以 GNU GPL 開放授權釋出,自此開啟廣泛的平台移植與功能強化的的濫觴。早期的 Doom GPL 程式碼被 Sam Lantinga 移植到 SDL 圖形函式庫,藉由 SDL 優異的可攜性,眾多硬體環境得以運行 Doom 遊戲,儘管遊戲的資料檔並非自由軟體。另一方面,現在最火熱的移動平台,就屬 Google Android 開放源碼平台,為了迴避 Sun Microsystems 對 Java 的控制權 (logo + patent),該平台整合大部分 Apache Harmony 專案的成果,建立了一套貌似 Java 語言但執行環境大異於 Java 的嶄新虛擬機器 -- Dalvik,將原本 stack-based VM (JVM) 轉換為 register-based VM (Dalvik VM),而無論這裡頭有多少玄機,就 Android 的程式設計來說,Java 是唯一可用的程式語言,要不得搭配 Android framework / class library,不然就是透過 JNI 去呼叫 C/C++ 撰寫的動態函式庫。作為一個「慣 C 魔人」, 筆者反覆思考,是否能將以 C 語言搭配 SDL 函式庫撰寫的 Doom,透過編譯器轉換為 Android 平台可運作的 Dalvik bytecode 呢?此舉不僅讓 C/C++ 程式跨平台執行,還為移動平台提供了新的附加價值,於是,筆者就開始一系列的 hacking,現在有初步的成果,日前已發表於 OSDC.tw 2009 的「窮得只剩下 Compiler」議程中,請參考以下螢幕快照:
這可不是紙老虎或單純貼圖,電動玩具當然是設計來玩的:
詳細的資訊可參閱發表於 OSDC.tw 的議程簡報:

View more presentations from Jim Huang.
筆者同事 luse 嘗言:「現在是一個充滿編譯器的世界,身為一個工程師,每次聽到編譯器技術,覺得深不可測 (或是腦海忽然浮現起自動機的回憶) 而輕言放棄,實著可惜」。許多人印象中艱澀的 (dynamic) Compiler 技術,其實廣泛應用於我們電腦資訊產業中,以「到處都是 Compiler」來闡述現實,一點也不為過。如此的案例多如牛毛,比方說,現在 Web 2.0 與 Mobile web browser 正火熱,為了要能改善 Web 應用程式的效能,Google 與 Apple 兩家公司的工程團隊,各自推出 V8 與 SquirrelFish Extreme 等 Just-In-Time compiler for JavaScript,而 Mozilla Foundation 更是將高速的 JavaScript 引擎當作 Mozilla 2 的重要賣點,知名的自由軟體開發者 Jim Blandy 甚至離開專業 GNU Toolchain 開發公司 CodeSourcery,加入 Mozilla Corporation,就為了致力開發 ActionMonkey (整合 Mozilla 原有 SpiderMonkey 與 Adobe 貢獻的 Tamarin)。自此,這個在瀏覽器平台的戰役,從桌面系統延續到手機,又將從手機移轉到各種不同的資訊裝置上。

而,撇開 JavaScript 執行引擎不論,實際上,連 Firefox/Mozilla 底層的向量繪圖函式庫 Cairo,也透過 JIT compiler 技術,去提昇整體繪圖的效能與使用者體驗。日前,Dan Amelang 揭露他的開發成果,可參見郵件論壇的訊息 "JIT for pixman"。pixman 是提供給 X Window System 與 Cairo 使用的 pixel-manipulation 函式庫,顧名思義,就是處理 image compositing 與 trapezoid rasterization 等操作,而在 Dan Amelang 的論文 "Jitblt: Efficient Run-time Code Generation for Digital Compositing" 給予令人振奮的突破,無疑是個極佳的突破點,我們也可預見 (dynamic) compiler 技術在更多資訊領域的廣泛應用。

當編譯器技術走入新的層次時,就需要更強大且多元的 Toolkit,LLVM 專案的出現,在整個電腦技術典範移轉 (paradigm shift) 的衝擊下,以嶄新編譯器架構、自由軟體協同開發模式,給予我們突破限制的可能性,顯然,我們可確定 LLVM 應用於 Android 應用程式開發,僅是一個牛刀小試,好戲才要登場呢。

read on
Posted 張貼者: jserv 於 凌晨3:48 on 2009年4月26日 星期日 | 0 意見
Filed under: , , , ,
 
Developer at 0xlab.