eglibc效能分析與優化

eglibc是 Debian/Ubuntu 提供C語言程式動態連結時使用的函式庫,系統中使用C語言所撰寫的程式,本篇文章將討論如何分析 eglibc 的執行狀況與瓶頸,選出有優化潛力的函式,並如何去優化這些函式,最後再展示我們優化後的數據成果。

分析數據

這裡是用 libc-bench 跑 -pg 之後的結果。
使用的是 eglibc 的 profiling 版本,為 libc6-prof_2.17-0ubuntu5_armhf.deb
實驗所使用的程式碼與編譯方式在 eglibc/libc-bench/gprof_src 底下

原始數據在 gprof_src/analysis.txt 和 gprof_src/output.png
從實驗數據來看,依序應該 tune 這些 function

eglibc-gprof

name Self seconds % time cumulative seconds calls self calls total s/calls lang
read 0.35 6.68 0.35 21708 0.00 0.00 system call
_IO_vfscanf_internal 0.33 6.30 0.68 1635489 0.00 0.00
putc 0.31 5.92 0.99 5000000 0.00 0.00
clone 0.31 5.92 1.30 7499 0.00 0.00 asm
gconv_transform_utf8_internal 0.27 5.15 1.57 3175867 0.00 0.00
gnu_mcount_nc 0.26 4.96 1.83 0 0.00 0.00
mbrtowc 0.24 4.58 2.07 3175817 0.00 0.00
getc 0.23 4.39 2.30 5000000 0.00 0.00
strstr 0.20 3.82 2.50 68414 0.00 0.00
b_stdio_putcgetc 0.20 3.82 2.70 1 0.20 0.78
b_stdio_putcgetc_unlocked 0.19 3.63 2.89 1 0.19 0.29
memchr 0.14 2.67 3.03 2269541 0.00 0.00 asm
libc_do_syscall 0.13 2.48 3.16 0 0.00 0.00 asm
munmap 0.12 2.29 3.28 2286 0.00 0.00 system call
re_search_internal 0.12 2.29 3.40 2 0.06 0.08
pthread_mutex_lock 0.11 2.10 3.51 1381473 0.00 0.00
index 0.11 2.10 3.62 91302 0.00 0.00 builtin
_int_malloc 0.10 1.91 3.72 230096 0.00 0.00
_IO_old_init 0.09 1.72 3.81 1635521 0.00 0.00
pthread_create 0.08 1.53 3.89 7502 0.00 0.00
mprotect 0.08 1.53 3.97 4753 0.00 0.00 system call
Laligned 0.08 1.53 4.05 0 0.00 0.00
rawmemchr 0.07 1.34 4.12 1635499 0.00 0.00
_IO_str_init_static_internal 0.07 1.34 4.19 1635491 0.00 0.00
isoc99_vsscanf 0.07 1.34 4.26 1635489 0.00 0.00
write 0.07 1.34 4.33 2496 0.00 0.00 system call
_dl_mcount_wrapper_check 0.06 1.15 4.39 3175867 0.00 0.00
memcpy 0.06 1.15 4.45 758019 0.00 0.00
b_utf8_onebyone 0.06 1.15 4.51 1 0.06 0.63
_IO_sputbackc 0.05 0.95 4.56 3022065 0.00 0.00
_IO_setb 0.05 0.95 4.61 1635552 0.00 0.00

實驗數據

可靠度測試

實驗環境

  • Odroid-U2

名詞定義

  • Baseline

    baseline 是用 dpkg-buildpackage 編出來的 libc6-dev_2.17-0ubuntu5_armhf.deb,裡面才有我們所需要的 libc6.a
    dpkg -i ./libc6-dev_2.17-0ubuntu5_armhf.deb 安裝 package

  • Native

    native 是利用 apt-get update 取得最新的 libc6-dev

  • musl

    musl 係利用 musl-1.0.3 (​http://www.musl-libc.org/releases/musl-1.0.3.tar.gz) 所取得

數據與分析

Baseline vs. Native

improve_base_native

最大的差距是 b_malloc_bubble 有 8.51%,第二大是 b_stdio_putcgetc_unlocked 有 3.58%,第三大是 b_pthread_create_serial1 有 2.45%
平均差距為 0.56%,只有千分之五強。

Baseline vs. musl

插圖

最大的差距是 b_pthread_uselesslock 有 4.86%,第二大是 b_malloc_big2 有 2.34%,第三大是 b_malloc_big1 有 2.24%
平均差距為 1.04%。

優化方法

修改eglibc部分演算法

實驗環境

比較使用native的libc和改過strstr的eglibc來跑libc-bench的結果。因為只改strstr的結果,故僅挑出string相關的benchmark來做比較。之前實驗取樣 500 次的結果相當穩定,平均標準差百分比都在1%以下,故本實驗只取樣 10 次。

名詞定義

  • Native

    native 是利用 apt-get update 取得最新的 libc6-dev

  • 工人智慧

    人工修改eglibc部分演算法後的版本

可靠度分析

Native

在誤差方面相當小,實驗的可靠度高

  • 最大的差距是 b_string_memset 有 4.34%
  • 第二大是 b_string_strchr 有 0.69%
  • 第三大是 b_string_strstr(“abcdefghijklmnopqrstuvwxyz”) 有 0.51%
  • 平均差距為 0.89%。

工人智慧

在誤差方面相當小,實驗的可靠度高

  • 最大的差距是 b_string_strstr(“abcdefghijklmnopqrstuvwxyz”) 有 1.41%
  • 第二大是 b_string_strstr(“aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac”) 有 1.16%
  • 第三大是 b_string_strstr(“aaaaaaaaaaaaaaaaaaaaaaaaac”) 有 0.67%
  • 平均差距為 0.55%。

優化改善比較

放圖

可以看到優化後,有關strstr的都變好,在b_string_strstr(“aaaaaaaaaaaaaacccccccccccc”)的例子中甚至有2倍多的改善, b_string_strstr(“abcdefghijklmnopqrstuvwxyz”)和b_string_strstr(“azbycxdwevfugthsirjqkplomn”)的例子也有1倍多的改善。

觀察到的另一點是,把musl的strstr實做直接搬進eglibc當中所得到的結果,都比本來直接換musl-gcc可以得到更好的改善。

在最長字串的部分,本來直接用musl和直接用baseline的狀況時,musl的表現是比較差的,但是可能是因為eglibc編譯選項有調教過的關係,也有9%的改善。

Linker Optimization Option

  • 開啟下列三個 option,看是否可以增強效能
    • –sort-common
    • –sort-sections=alignment
    • –reduce-memory-overheads

實驗結果

  • –sort-common 無效,因為 glibc 沒有 common symbols
  • –sort-aligment 無效,segment 與 section 順序都沒有改變,alignment 還是亂跳
  • –reduce-memory-overheads 有點用,可以觀察到的結果如下
    • header 變小
    • debug 和 string table 變小

Code Size

對造組 實驗組 縮小 Improvement
9017580 9017052 528 bytes 0.005855 %

單位是 byte,在 code size 上有改善,但是改善幅度幾乎看不見

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *