移植 iperf 網絡性能測試工具到 Android-P
.
.
.
.
.
新開發板使用了 Android-P 的方案,WiFi 剛剛調通,為了測試 WiFi 穩定性,需要使用 iperf 工具。但 Android 並沒有提供這個工具,只能自己移植一份了。
首先下載源代碼,下載地址:https://storage.googleapis.com/google-code-archive-source/v2/code.google.com/iperf/source-archive.zip
解壓後刪除 Makefile 等不相關的文件,並建立 Android.mk,內容如下:
1 LOCAL_PATH := $(call my-dir) 2 3# Device executable. 4 # ========================================================= 5 6 include $(CLEAR_VARS) 7 8 LOCAL_MODULE := iperf 9 10 LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) 11 12 LOCAL_C_INCLUDES := $(LOCAL_PATH)/src 13 14 LOCAL_SRC_FILES := $(call all-c-files-under, src)15 16 LOCAL_CFLAGS := -Wno-error -DIPERF_HOST=0 17 18 LOCAL_MODULE_TAGS := debug 19 20 LOCAL_FORCE_STATIC_EXECUTABLE := true 21 22 include $(BUILD_EXECUTABLE) 23 24 25 # Host executable. 26 # ========================================================= 27 28 include $(CLEAR_VARS) 29 30LOCAL_MODULE := iperf_x86 31 32 LOCAL_C_INCLUDES := $(LOCAL_PATH)/src 33 34 LOCAL_SRC_FILES := $(call all-c-files-under, src) 35 36 LOCAL_CFLAGS := -Wno-error -DIPERF_HOST=1 37 38 LOCAL_LDFLAGS := -static 39 40 LOCAL_MODULE_TAGS := debug 41 42 include $(BUILD_HOST_EXECUTABLE) 43 44 45 include $(call first-makefiles-under,$(LOCAL_PATH))
接下來打開 src/flowlabel.h 文件,在 struct in6_flowlabel_req 結構體的定義外面加上條件編譯指令,修改後如下所示:
1 // It‘s defined in bionic/libc/kernel/uapi/linux/in6.h 2 #if IPERF_HOST 3 struct in6_flowlabel_req 4 { 5 struct in6_addr flr_dst; 6 __u32 flr_label; 7 __u8 flr_action; 8 __u8 flr_share; 9 __u16 flr_flags; 10 __u16 flr_expires; 11 __u16 flr_linger; 12 __u32 __flr_pad; 13 /* Options in format of IPV6_PKTOPTIONS */ 14 }; 15 #endif
IPERF_HOST 這個宏是我們在 Android.mk 裏面定義的,因為編譯 arm 版 iperf 時,編譯參數中會指定 boinic 的庫,這個宏會出現重定義的情況。但編譯 x86 版本的 iperf 時,不會鏈接這些庫,所以這個結構體必須由本程序來定義。
接下來打開 src/iperf_api.c 文件,找到 iperf_new_stream(struct iperf_test *, int) 函數,裏面有這樣的變量定義:
char template[] = "/tmp/iperf3.XXXXXX";
由於 Android 沒有 /tmp 目錄,所以運行的時候會報錯,所以我們把這個目錄修改為 /data 目錄,修改後的代碼如下:
1 #if IPERF_HOST 2 char template[] = "/tmp/iperf3.XXXXXX"; 3 #else 4 char template[] = "/data/iperf3.XXXXXX"; 5 #endif
接下來把 src/config.h.in 重命名為 src/config.h:
>$ mv src/config.h.in src/config.h
最後一步,刪掉 src/t_uuid.c、src/t_timer.c 和 src/t_units.c 三個文件,否則會出現 main() 函數沖突的錯誤。
當然,如果在 Android.mk 中通過 LOCAL_SRC_FILES 變量來指定每個要編譯的源文件,再從中排除掉這三個文件也是可以的。不過這樣做寫的內容比較羅嗦,幹脆把它們仨刪掉,直接用 LOCAL_SRC_FILES := $(call all-c-files-under, src) 自動包含 src 目錄下所有的 .c 文件。
>$ rm src/t_uuid.c src/t_timer.c src/t_units.c
mm 編譯後會生成兩個文件,分別是 arm 版和 x86 版的可執行程序。
>$ mm Install: out/host/linux-x86/bin/iperf_x86 Install: out/target/product/msm8909go/system/xbin/iperf
記錄一個遇到的坑:
一開始編譯的時候報這樣一個錯誤:
error: unused parameter ‘argc‘ [-Werror,-Wunused-parameter]
main() 函數的 argc 參數沒有使用,一般來說報個警告就可以了,為什麽直接報成錯誤了呢?
後來仔細研究了生成的編譯命令發現裏面帶了 -Werror 參數,這個參數會將 warning 轉換為 error,強制要求程序編譯期間不能出現警告。
為了解決這個問題,只需在 Android.mk 中指定 -Wno-error 參數即可:
LOCAL_CFLAGS := -Wno-error
iperf 工具的使用很簡單,網上有很多教程,這裏只給出幾個示例。
啟動服務端:
># iperf -s
-s 參數表示以服務端形式啟動。
網上有些文章說如果使用 UDP 協議需要,指定 -u 參數。但經實測後發現,我使用的這個版本,服務端無需指定 -u 就可以支持 TCP 和 UDP 兩種協議。
啟動客戶端:
./iperf_x86 -c 172.16.61.90 -u -t 600 -b 16M
-c 表示啟動客戶端,後面跟服務端的 IP 地址。
-u 表示使用 UDP 協議,不加此參數使用 TCP 協議。
-t 表示持續執行多少秒的測試,默認10秒。
-b 表示發送的數據包大小,TCP 默認使用最大帶寬,UDP 默認1Mbits。
TCP 協議適合用來測試最大帶寬,UDP 協議適合用來測試丟包率、網絡抖動等情況。
移植 iperf 網絡性能測試工具到 Android-P