Android HIDL學習(4) ---- 高性能比較(HIDL, FMQ, MMAP)

寫在前面

公司一些方案,在Andoird P上架構必須要修改成HIDL,不然會遇到一系列的Selinux的問題,所以決定還是按照標準的Android HIDL的架構重新寫了方案(因為比較機密,所以不透露具體方案代碼)。但是我們的這個模塊對性能的要求非常高,不然咱們的設備怎么能打敗競爭對手呢,怎么屹立在世界500強呢,對吧。_
因為我們做的工業(yè)設備,對實時性要求比較高,但是HIDL的設計畢竟是需要進程間通信來調用到比較low level的接口的,肯定會有一些性能損失,但是好在還有一些別的機制來挽回損失,本文就來探討一下這個問題,以及對不同的方式做一下性能的比對。

幾種不同的方式對比

我們的需求是,應用層需要調用一些接口到kernel中的驅動,有一個HAL層封裝了對驅動的操作,應用層去調用HAL層接口,其實就跟標準的AOSP的模塊類似。那么問題就來了,以前是直接調用HAL接口,然后通過open/read/write/ioctl來跟驅動通信就好了,比較關心性能損耗就是系統(tǒng)調用到kernel中的時間損耗,其他都還好。但是一旦改成HIDL接口的寫法,應用層就變成了HIDL的client端,調用到HAL的server端是用過binder/hwbinder進程間通信完成的,會有一些性能的損耗,我們就來測一下這個損耗是多少,因為我們的應用場景對這個時間比較關心,所以需要做這些分析,而且應用層會頻繁的調用HAL接口。
如果比較難理解的話,我們來舉個例子:
這個例子是在Android Camera開發(fā)過程中可能遇到的,在camera預覽過程中,上層app需要實時的獲取camera采集的圖像數(shù)據(jù),這個數(shù)據(jù)量是很大的,而且這個過程也是很復雜的,因為在預覽過程中還需要調整ISP進行不同效果參數(shù)的調整,在這個過程中對camera模塊進行控制很頻繁(通過I2C把數(shù)據(jù)寫到camera模組中)。我們假設要寫進去的數(shù)據(jù)在應用層,需要通過HAL層接口調用到驅動中進行真正的I2C通信。


Android HIDL學習(4) ---- 高性能比較.jpg

左邊黃色的,是使用以前的HAL層架構,直接app進程直接function call調用hall層的函數(shù),通過ioctl的system call把數(shù)據(jù)傳送到kernel層。
右邊藍色的,是使用HIDL來實現(xiàn)app調用底層I2C操作,分為兩部分,app作為HIDL的client端通過binder進程間通信來調用server端的接口。
對我們而言,比較關心的就是proxy client端進程間調用到server端的時間延遲,畢竟是進程間通信,肯定沒有直接調用來的快。而且兩個不同進程,就涉及到數(shù)據(jù)的拷貝,當i2c需要寫入的數(shù)據(jù)很大而且調用次數(shù)很多的時候這個拷貝和傳輸?shù)难舆t就會顯得比較突出了。
我們這里就使用幾種不同的調用方式來看時間延遲和效率問題:

  • 直接調用
  • HIDL接口傳輸
  • Oneway HIDL interface
    參考代碼:

https://github.com/JayZhang0708/HIDL-4

最終調用干活的方法
#define LOG_TAG     "Sample#Lib"
#include <log/log.h>
#include <string.h>
#include "sample.h"

int writeMessage(uint8_t *data, int32_t size)
{
    int i;
    uint8_t tmp = 0;
    for(i = 0; i < size; i++) {
        tmp += data[i];
        tmp &= 0xff;
    }

    return tmp;
}

很簡單,其實就是遍歷傳過來的數(shù)組。

直接調用
void test_function_call(void)
{
    android::StopWatch stopWatch("test_function_call");
    writeMessage(buffer, BUFFER_SIZE);
}
HIDL接口傳遞
void test_hidl_interface(void)
{
    SampleMessage message;
    message.size = BUFFER_SIZE;
    message.data.resize(BUFFER_SIZE);
    ::memcpy(&message.data[0], buffer, BUFFER_SIZE);
    android::StopWatch stopWatch("test_hidl_interface");
    benchmark->writeMessage(message);
}
Oneyway HIDL接口
void test_oneway_hidl_interface(void)
{
    SampleMessage message;
    message.size = BUFFER_SIZE;
    message.data.resize(BUFFER_SIZE);
    ::memcpy(&message.data[0], buffer, BUFFER_SIZE);
    android::StopWatch stopWatch("test_oneway_hidl_interface");
    benchmark->writeMessageOneway(message);
}
結果

04-30 04:14:09.425 29520 29520 D StopWatch: StopWatch test_function_call (us): 1
04-30 04:14:09.426 29520 29520 D StopWatch: StopWatch test_hidl_interface (us): 325
04-30 04:14:09.426 29520 29520 D StopWatch: StopWatch test_oneway_hidl_interface (us): 98
代碼詳細就不介紹了,之前的幾篇文章都有些。
結果顯而易見,直接調用是很快的,基本沒有啥lentency,使用HIDL接口傳輸數(shù)據(jù)會比較費時間,我們這里傳輸了1000個byte所以比較明顯。
然后就是第三個,使用了oneway

package vendor.sample.benchmark@1.0;

interface IBenchmark {
    writeMessage(SampleMessage message);
    oneway writeMessageOneway(SampleMessage message);
};

一般來說binder進程間通信時同步的,也就是當client調用接口到server的時候,需要server處理結束,然后返回給client。
當我們把接口設置成oneway,就可以把接口的調用變成異步的,當client調用接口的時候,系統(tǒng)會重新起一個線程來處理client的函數(shù),調用接口的線程會直接返回。
所以當我們有一些接口不需要得到返回值而且不需要block當前線程的時候需要把接口定義為oneway來提升調用的效率,當然了,如果你壓根就不考慮性能的話,那就無所謂啦。

談談內存共享

其實在用到比較大數(shù)據(jù)傳輸?shù)臅r候,最好的選擇是使用內存共享來實現(xiàn)不同進程間的通信,因為使用內存共享涉及到的代碼比較多,這里就不具體講了,詳細的話后面有機會再單獨寫一篇,在Android中如何使用內存共享實現(xiàn)不同進程間通信。
比較常見的例子就是Camera的HIDL實現(xiàn)了,把framebuffer在kernel和應用層不同進程間進行共享,實現(xiàn)buffer填充的時候零拷貝動作。最常用的就是使用Android的ION框架來實現(xiàn)。

最后是FMQ

FMQ的出現(xiàn)就是為了解決HIDL接口通信性能差的,我們后面單獨來講解Android的FMQ,其實在瀏覽AOSP原生的代碼中使用FMQ的場景不多,在我自己的使用過程中,我一般用作事件的通知,但是原來的寫法就是使用HIDL 的callback機制來實現(xiàn),我嘗試改為FMQ來實現(xiàn),實測下來效果不是很明顯,但是會減小系統(tǒng)開銷,不需要頻繁的進程間通信了。
具體可以參考下面鏈接:
https://source.android.com/devices/architecture/hidl/fmq

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,401評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,011評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,263評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,543評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,323評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,874評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,968評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,095評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 48,605評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,551評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,720評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,242評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,961評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,358評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,612評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,330評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,690評論 2 370

推薦閱讀更多精彩內容