android c library: bionic 成長計畫

51
Android Native Runtime 成長計畫 Kito Cheng ( 程皇嘉 ) <[email protected]> Developer, 0xlab April 14, 2012 / OSDC.tw

Upload: kito-cheng

Post on 06-May-2015

6.531 views

Category:

Technology


8 download

DESCRIPTION

本議程主要探討 Android 的 C Library : Bionic , bionic 與一般 Linux 所使用的 C Library 有所不同,為達到輕薄短小, 因此相較下缺少部份功能的實做, 本議程將探討 bionic 何處尚可改善以及發表我們對於 bionic 所改善的部份, 其中改善包含 bionic 中的 Dynamic Linker 及對於 Profiling 的支援.

TRANSCRIPT

Page 1: Android C Library: Bionic 成長計畫

Android Native Runtime成長計畫

Kito Cheng ( 程皇嘉 ) <[email protected]>

Developer, 0xlabApril 14, 2012 / OSDC.tw

Page 2: Android C Library: Bionic 成長計畫

Rights to copy

Attribution – ShareAlike 3.0You are free✔ to copy, distribute, display, and perform the work✔ to make derivative works✔ to make commercial use of the workUnder the following conditions

Attribution. You must give the original author credit.Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under a license identical to this one.

● For any reuse or distribution, you must make clear to others the license terms of this work.

● Any of these conditions can be waived if you get permission from the copyright holder.Your fair use and other rights are in no way affected by the above.License text: http://creativecommons.org/licenses/by-sa/3.0/legalcode

© Copyright 2012 0xlabhttp://0xlab.org/

[email protected]

Corrections, suggestions, contributions and translations are welcome!

Latest update: Apr 17, 2012

Page 3: Android C Library: Bionic 成長計畫

Android Native Runtime 成長計畫:探討 0xlab 若干低階 Android 優化的開源項目

Page 4: Android C Library: Bionic 成長計畫

(4) 具備 S/L 大法的時間魔法陣

(1) 可解讀 GNU-stylehash 的帥氣墨鏡

(3) 針對 JNI 量測效能的機械錶 (2) 強化版 8-bit

prelink map

Android Native Runetime 成長計畫

Page 5: Android C Library: Bionic 成長計畫

可解讀 GNU-stylehash 的帥氣墨鏡

Page 6: Android C Library: Bionic 成長計畫

GNU-style Hash

• 在 ELF 程式載入時期,加速 ELF 符號查詢的機制

載入相關動態函式庫

執行檔讀入記憶體

更新符號位址(Relocation)

開始執行 !

在更新符號時,需要大量的符號查詢操作

printf, sin, cos, ...

libc / libm / libdvm...

Page 7: Android C Library: Bionic 成長計畫

ELF 程式載入範例

prog

libc libfoo

prog參照到 libc 與 libfoo的符號

Page 8: Android C Library: Bionic 成長計畫

ELF 程式載入範例

prog

libc libfoo

strtoumaxstatfswcsncmpdlmalloptprintf...strtoulgetutent

foobar...ox1ab

libc 及 libfoo 各自提供這些符號 (函數 /變數 )

prog參照到 libc 與 libfoo的符號

Page 9: Android C Library: Bionic 成長計畫

ELF 程式載入範例

prog

libc libfoo

strtoumaxstatfswcsncmpdlmalloptprintf...strtoulgetutent

foobar...ox1ab

libc 及 libfoo 各自提供這些符號 (函數 /變數 )

prog參照到 libc 與 libfoo的符號

假設 prog 只使用到 printf, foo, bar 等 3 個函數

Page 10: Android C Library: Bionic 成長計畫

ELF 程式載入範例

prog

libc libfoo

strtoumaxstatfswcsncmpdlmalloptprintf...strtoulgetutent

foobar...ox1ab

假設 prog 只使用到 printf, foo, bar 等 3 個函數

雖只用到 3 個符號 ,但在這個例子需要查詢

5 次符號

查詢符號次數複雜度 : O(n*m)n : 相依的函數庫數目m : 符號數

Page 11: Android C Library: Bionic 成長計畫

GNU-style Hash

• 原本 ELF已採用 hash 來加速查詢,但不盡理想

name 2sym collision # 3sym collision # 3+sym collision #sysv 1749 5libiberty 42dcache 37djb2 29sdbm 39djb3 31rot 337 39 61sax 34fnv 40oat 30

ELF 預設的 hash 方法

GNU-style hash 的方法

Experiment by Jakub Jelinek http://cygwin.com/ml/libc-alpha/2006-06/msg00098.html

Page 12: Android C Library: Bionic 成長計畫

GNU-style Hash

• 並使用 bloom filter 進一步加速整體查詢

Bit array

H = {x, y, z} = hash functions

v

號稱 (Jakub Jelinek ) 可加速 50% 的載入時間

Page 13: Android C Library: Bionic 成長計畫

GNU-style Hash 在 Android 的相容問題

• 某些 Android 程式自帶(修改自原本 bionic linker的) dynamic linker ,所以不支援– 如: Unity 3D, Mozilla/Android (B2G)

• 因此要採用向後相容方案, 新舊的 hash table 都要在 linker 指定 ,-Wl,--hash-style=both– 但 gold linker 有 bug, 所以最好用 bfd 的 linkerhttp://sourceware.org/bugzilla/show_bug.cgi?id=13597

Page 14: Android C Library: Bionic 成長計畫

強化版 8-bitprelink map

Page 15: Android C Library: Bionic 成長計畫

Android太貪吃,所以 prelink map拿掉了

No prelink in Android 4.0

Page 16: Android C Library: Bionic 成長計畫

• The speedup that it afforded in the early days of Android is now nullified by the speed of hardware, as well as by the presence of Zygote

• The space savings that come with prelinking are no longer important either.

• Prelinking reduces the effectiveness of Address-Space-Layout Randomization.

• Since it is not part of the gcc suite, the prelinker needs to be maintained separately.

No prelink in Android 4.0 :官方說法

Android Git loghttps://github.com/android/platform_build/commit/b375e71d306f2fd356b9b356b636e568c4581fa1

Page 17: Android C Library: Bionic 成長計畫

• 硬體進步跟 Zygote 機制的導入, prelink 加速效果不顯著

• 只省一丁點空間, 現在記憶體大又便宜• prelink 之後, Address-Space-Layout

Randomization 效果會變弱

• 並非 GNU toolchain 相關專案, Android 要維護很麻煩

No prelink in Android 4.0 :官方說法

白話版本

Page 18: Android C Library: Bionic 成長計畫

Prelink in Android 4.0

• 在較低等級的硬體環境中, prelink 對開機時間仍有影響

• 事實上,在 Android 4.0 已移除的 prelink 機制可撿回來用

Page 19: Android C Library: Bionic 成長計畫

程式啟動流程與 prelink

載入相關動態函式庫

執行檔讀入記憶體

更新符號位址(Relocation)

開始執行 !

在更新符號時,需要大量的符號查詢操作

printf, sin, cos, ...

libc / libm / libdvm...

prelink就是將此階段要查詢解析的符號,預先處理過

Page 20: Android C Library: Bionic 成長計畫

prelink 實驗

libfoo

libc

int bar() { return 100;}

int foo () { printf(“foo”); return bar();}

假設已存有一個建好的且經 prelink處理過後的 libc.so

Page 21: Android C Library: Bionic 成長計畫

prelink 實驗(Relocation)

libfoo

libc

int bar() { return 100;}

int foo () { printf(“foo”); return bar();}

# arm-eabi-objdump libfoo.so -R

libfoo.so: file format elf32-littlearm

DYNAMIC RELOCATION RECORDSOFFSET TYPE VALUE 000010e8 R_ARM_JUMP_SLOT printf000010ec R_ARM_JUMP_SLOT __cxa_finalize00000424 R_ARM_RELATIVE *ABS*0000100c R_ARM_RELATIVE *ABS*

objdump -R可檢視 Relocation Recordlibfoo.so 共有四個 Relocation 要做

Page 22: Android C Library: Bionic 成長計畫

prelink 實驗(Relocation)

libfoo

libc

int bar() { return 100;}

int foo () { printf(“foo”); return bar();}

# arm-eabi-objdump libfoo.so -R

libfoo.so: file format elf32-littlearm

DYNAMIC RELOCATION RECORDSOFFSET TYPE VALUE 000010e8 R_ARM_JUMP_SLOT printf000010ec R_ARM_JUMP_SLOT __cxa_finalize00000424 R_ARM_RELATIVE *ABS*0000100c R_ARM_RELATIVE *ABS*

一個 *ABS* 是 bar 的位址,另一個是系統用的

Page 23: Android C Library: Bionic 成長計畫

prelink 實驗

libfoo

libc

int bar() { return 100;}

int foo () { printf(“foo”); return bar();}

# apriori --locals-only \ --prelinkmap prelink-linux-arm.map \ libfoo.so --output prelinked/libfoo.so

接著對 libfoo.so 進行 prelink

apriori 位於 out/host/linux-x86/bin/prelink map 位於 build/core--locals-only(-l) 指定進行 local prelink

Page 24: Android C Library: Bionic 成長計畫

prelink 實驗

libfoo

libc

int bar() { return 100;}

int foo () { printf(“foo”); return bar();}

# apriori --locals-only \ --prelinkmap prelink-linux-arm.map \ libfoo.so --output prelinked/libfoo.so

build/tools/apriori/prelinkmap.c(183): library 'libfoo.so' not in prelink map

出現錯誤 ,抱怨在 prelink map 找不到 libfoo

Page 25: Android C Library: Bionic 成長計畫

Prelink Map

# core system librarieslibdl.so 0xAFF00000 # [<64K]libc.so 0xAFD00000 # [~2M]libstdc++.so 0xAFC00000 # [<64K]libm.so 0xAFB00000 # [~1M]liblog.so 0xAFA00000 # [<64K]libcutils.so 0xAF900000 # [~1M]libthread_db.so 0xAF800000 # [<64K]libz.so 0xAF700000 # [~1M]libevent.so 0xAF600000 # [???]libssl.so 0xAF400000 # [~2M]libcrypto.so 0xAF000000 # [~4M]libsysutils.so 0xAEF00000 # [~1M]

# bluetoothliba2dp.so 0xAEE00000 # [~1M]audio.so 0xAED00000 # [~1M]input.so 0xAEC00000 # [~1M]…liblept.so 0x9CA00000 # [~5M]

預先分配每個動態函式庫的基底位址 (Base Address)

要 prelink 的函式庫都要加入

Page 26: Android C Library: Bionic 成長計畫

Prelink Map

# core system librarieslibdl.so 0xAFF00000 # [<64K]libc.so 0xAFD00000 # [~2M]libstdc++.so 0xAFC00000 # [<64K]libm.so 0xAFB00000 # [~1M]liblog.so 0xAFA00000 # [<64K]libcutils.so 0xAF900000 # [~1M]libthread_db.so 0xAF800000 # [<64K]libz.so 0xAF700000 # [~1M]libevent.so 0xAF600000 # [???]libssl.so 0xAF400000 # [~2M]libcrypto.so 0xAF000000 # [~4M]libsysutils.so 0xAEF00000 # [~1M]

# bluetoothliba2dp.so 0xAEE00000 # [~1M]audio.so 0xAED00000 # [~1M]input.so 0xAEC00000 # [~1M]…liblept.so 0x9CA00000 # [~5M]libfoo 0x9C900000

預先分配每個動態函式庫的基底位址 (Base Address)

要 prelink 的函式庫都要加入

把 libfoo 加進來

Page 27: Android C Library: Bionic 成長計畫

prelink 實驗(Relocation)

libfoo

libc

int bar() { return 100;}

int foo () { printf(“foo”); return bar();}

# apriori --locals-only \ --prelinkmap prelink-linux-arm.map \ libfoo.so --output prelinked/libfoo.so

加入 prelink map 後,就可順利進行 prelink

# arm-eabi-objdump prelinked/libfoo.so -R

libfoo.so: file format elf32-littlearm

DYNAMIC RELOCATION RECORDSOFFSET TYPE VALUE 000010e8 R_ARM_JUMP_SLOT printf000010ec R_ARM_JUMP_SLOT __cxa_finalize

發現只剩兩個 Relocation!

Page 28: Android C Library: Bionic 成長計畫

prelink 實驗

libfoo

libc

int bar() { return 100;}

int foo () { printf(“foo”); return bar();}

# arm-eabi-objdump prelinked/libfoo.so -R

libfoo.so: file format elf32-littlearm

DYNAMIC RELOCATION RECORDSOFFSET TYPE VALUE 000010e8 R_ARM_JUMP_SLOT printf000010ec R_ARM_JUMP_SLOT __cxa_finalize

發現只剩兩個 Relocation!

其中的祕密在於, libfoo.so 的 base address 在prelink map 中固定 , 而事實上處理 Relocation 僅需base address 加上 Offset即可

Page 29: Android C Library: Bionic 成長計畫

prelink 實驗

libfoo

libc

int bar() { return 100;}

int foo () { printf(“foo”); return bar();}

# apriori --locals-only \ --prelinkmap prelink-linux-arm.map \ libfoo.so --output prelinked/libfoo.so

回顧剛才的參數有個 --locals-only,通常有local ,就有相對的 global

# apriori \ --prelinkmap prelink-linux-arm.map \ libfoo.so --output prelinked/libfoo.so

但直接移除該參數時, apriori 會抱怨參數錯誤

build/tools/apriori/main.c(195): There are command-line-option errors.

Page 30: Android C Library: Bionic 成長計畫

prelink 實驗

libfoo

libc

int bar() { return 100;}

int foo () { printf(“foo”); return bar();}

# apriori \ --prelinkmap prelink-linux-arm.map \ libfoo.so --output prelinked/libfoo.so

build/tools/apriori/main.c(195): There are command-line-option errors.

* 不明原因 *在 apriori的 global prelink的部份程式未完成,但有雛型

進行接下來的實驗前,得先從 0xdroid取用 0xlab的功能增補系列 patch,散落於以下三處:build/external/elfutils/external/elfcopy/

0xdroid git repository:http://gitorious.org/0xdroid

Page 31: Android C Library: Bionic 成長計畫

prelink 實驗(incremental global prelink)

libfoo

libc

int bar() { return 100;}

int foo () { printf(“foo”); return bar();}

# apriori --inc-global-prelink \ --prelinkmap prelink-linux-arm.map \ -L /system/lib \ libfoo.so \ –output prelinked/libfoo.so

參數加上 --inc-global-prelink-L <其他函數庫的路徑 >就會開始進行 Incremental Global Prelink

Page 32: Android C Library: Bionic 成長計畫

prelink 實驗(incremental global prelink)

libfoo

libc

int bar() { return 100;}

int foo () { printf(“foo”); return bar();}

# apriori --inc-global-prelink \ --prelinkmap prelink-linux-arm.map \ -L /system/lib \ libfoo.so –output prelinked/libfoo.so

# arm-eabi-objdump prelinked/libfoo.so -R

libfoo.so: file format elf32-littlearm

DYNAMIC RELOCATION RECORDS (none)

Incremental Global Prelink 處理後,就沒有任何Relocation 需要處理了 !

名字有 incremental 的原因是,該實作事實上會先進行 local prelink再去處理 global prelink 的漸進方式,故命名之,而輸入的函式庫也可為經 local prelink 處理過者

Page 33: Android C Library: Bionic 成長計畫

prelink 實驗(incremental global prelink)

libfoo

libc

int bar() { return 100;}

int foo () { printf(“foo”); return bar();}

# apriori --inc-global-prelink \ --prelinkmap prelink-linux-arm.map \ -L /system/lib \ libfoo.so –output prelinked/libfoo.so

# arm-eabi-objdump prelinked/libfoo.so -R

libfoo.so: file format elf32-littlearm

DYNAMIC RELOCATION RECORDS (none)

在 global prelink 的過程中,會試著搜索外部的符號 , 若找得到且該函式庫也經 prelink 過,則其符號的位址也是已知 , 因此可以 prelink

透過一些觀察可發現,不在 prelink map 的函式庫,其實也可處理掉部份的 Relocation

Page 34: Android C Library: Bionic 成長計畫

prelink 實驗

libfoo

libc

int bar() { return 100;}

int foo () { printf(“foo”); return bar();}

(1)為了實驗目的,將 libfoo從 prelink map 中移除並加上 LOCAL_PRELINK_MODULE := false

# apriori --partial-global-prelink \ -L /system/lib \ libfoo.so --output prelinked/libfoo.so

(2) 接著加上新的參數--partial-global-prelink來進行 partial global prelink

Page 35: Android C Library: Bionic 成長計畫

prelink 實驗

libfoo

libc

int bar() { return 100;}

int foo () { printf(“foo”); return bar();}

# apriori --partial-global-prelink \ -L /system/lib \ libfoo.so --output prelinked/libfoo.so

# arm-eabi-objdump prelinked/libfoo.so -R

libfoo.so: file format elf32-littlearm

DYNAMIC RELOCATION RECORDS00000424 R_ARM_RELATIVE *ABS*0000100c R_ARM_RELATIVE *ABS*

來自 libc 符號的 Relocation 都被 prelink 處理掉

原因是 libc 進行 prelink 後,符號的位址都已固定且已知,因此即使 libfoo沒有分配 base address ,也可處理掉部份的 prelink

此機制命名為 partial global prelink

Page 36: Android C Library: Bionic 成長計畫

prelink家族效能評比

Page 37: Android C Library: Bionic 成長計畫

針對 JNI 量測效能的機械錶

Page 38: Android C Library: Bionic 成長計畫

Aprof : Android Profiler

• 針對 JNI部份客製化

• 類似常見的 gprof工具– Sample based– Instrumentation based

Page 39: Android C Library: Bionic 成長計畫

Aprof : Android Profiler

Page 40: Android C Library: Bionic 成長計畫

Aprof : Android Profiler

• Sample based– 定期查看程式跑到哪

• Instrumentation based– 每次函數被呼叫時會紀錄

Page 41: Android C Library: Bionic 成長計畫

Aprof : Android Profiler % cumulative self self total time time time calls ms/call ms/call name 99.52 2170 2140 2178309 0 0 fib 0.00 2170 0 1 0 217 main 0.32 0 20 0 0 0 write 0.16 0 10 0 0 0 memcpy

Call graph (explanation follows)

-------------------------------------------------------------Image : fooCumulative time : 2170 msSelf time : 2140 ms Function % time cumulative self Count Call by fib 2170 2140 100.00 2170 0 1 main 100.00 2170 2140 2178308 fib main 2170 0 100.00 2170 0 1 __libc_init-------------------------------------------------------------Image : fooCumulative time : 2170 msSelf time : 30 ms write 0 20 memcpy 0 10

Page 42: Android C Library: Bionic 成長計畫

Aprof

Page 43: Android C Library: Bionic 成長計畫

具備 S/L 大法的時間魔法陣

Page 44: Android C Library: Bionic 成長計畫

Checkpoint

Page 45: Android C Library: Bionic 成長計畫

Checkpoint

保存使用狀態 !

Page 46: Android C Library: Bionic 成長計畫

Checkpoint

之後直接從上次保存的狀態回覆

Page 47: Android C Library: Bionic 成長計畫

現有 Checkpoint 機制

• CryoPID– http://cryopid.berlios.de/

• BLCR– https://ftg.lbl.gov/projects/CheckpointRestart/

• DMTCP– http://dmtcp.sourceforge.net/

Page 48: Android C Library: Bionic 成長計畫

DMTCP

• 支援大部分 OS功能– 檔案、網路、 shared memory, SysV IPC...

• 純 user-space checkpoint 實作

• 架構良好易於擴充且開發活耀 !– based on C++

Page 49: Android C Library: Bionic 成長計畫

DMTCP for Android

• 預計可有效減少開機時間• 但 Android 上有許多特殊的機制

– Logger, binder, ashmem, wakelock...

• 目前尚在進行中

Page 50: Android C Library: Bionic 成長計畫

(4) checkpoint

(1) GNU-stylehash in linker

(3) Aprof(2) partial global prelink

Android Native Runetime 成長計畫

Page 51: Android C Library: Bionic 成長計畫

http://0xlab.org