hidl 性能设计

1-使用binder 架构存在的问题
如果设计的系统是对时间要求比较苛刻,那么采用HIDL 就要考虑性能
从framework 与hal 在同一个进程,演进到framework 与hal 在不同进程,那么肯定存在性能的损耗。

图片.png

  • 左边黄色的,是使用以前的HAL层架构,直接app进程直接function call调用hall层的函数,通过ioctl的system call把数据传送到kernel层。
  • 右边蓝色的,是使用HIDL来实现app调用底层I2C操作,分为两部分,app作为HIDL的client端通过binder进程间通信来调用server端的接口。
  • proxy client端进程间调用到server端的时间延迟,毕竟是进程间通信,肯定没有直接调用来的快。而且两个不同进程,就涉及到数据的拷贝,当i2c需要写入的数据很大而且调用次数很多的时候这个拷贝和传输的延迟就会显得比较突出了。
图片.png
  • [1]直接调用 passthrough
  • [2]binder HIDL接口传输 就是上图中的3
  • [3]Oneway HIDL interface, 这个可以理解不阻塞形式,也是对应上图中3其中的一种形式

对[1][2][3]进行测试性能
类服务器端的底层写函数:

#define LOG_TAG     "Sample#Lib"
#include 
#include 
#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;
}

直接调用:

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);
}

StopWatch: StopWatch test_function_call (us): 1
StopWatch: StopWatch test_hidl_interface (us): 325
StopWatch: StopWatch test_oneway_hidl_interface (us): 98
可以看出passthrough 是性能最好的,google 采用了binder ,舍弃了性能最优,获得了与vendor 的隔离。

2-对binder HIDL 进行改进-共享内存
共享内存
研究hidl ,必须要研究共享内存的方式, 因为这个太重要,camera HIDL 涉及到的就是采用了这种方式
不同的进程进行大量数据传输的时候,共享内存,零拷贝,这样是最经济的
Memory:

HIDL memory 类型会映射到 libhidlbase 中的 hidl_memory 类,该类表示未映射的共享内存。这是要在 HIDL 中共享内存而必须在进程之间传递的对象。要使用共享内存,需满足以下条件:

  • 获取 IAllocator 的实例(当前只有“ashmem”实例可用)并使用该实例分配共享内存。
  • IAllocator::allocate() 返回 hidl_memory 对象,该对象可通过 HIDL RPC 传递,并能使用 libhidlmemory 的 mapMemory 函数映射到某个进程。
  • mapMemory 返回对可用于访问内存的 sp 对象的引用(IMemory 和 IAllocator 在 [email protected] 中定义)。
    IAllocator 分配内存:
#include 
#include 
#include 
using ::android::hidl::allocator::V1_0::IAllocator;
using ::android::hidl::memory::V1_0::IMemory;
using ::android::hardware::hidl_memory;
....
  sp ashmemAllocator = IAllocator::getService("ashmem");
  ashmemAllocator->allocate(2048, [&](bool success, const hidl_memory& mem) {
        if (!success) { /* error */ }
        // now you can use the hidl_memory object 'mem' or pass it around
  }));

对内存的实际更改必须通过 IMemory 对象完成(在创建 mem 的一端或在通过 HIDL RPC 接收更改的一端完成):

// Same includes as above
sp memory = mapMemory(mem);
void* data = memory->getPointer();
memory->update();
// update memory however you wish after calling update and before calling commit
data[0] = 42;
memory->commit();
// …
memory->update(); // the same memory can be updated multiple times
// …
memory->commit();

上面对memory 使用有了基本的了解,下面进行详细的介绍
HIDL memory 梳理:
HIDL 内存块是一个建立在HIDL @1.0::IAllocator, 和 HIDL @1.0::IMapper的抽象层。
它是为具有多个内存块共享单个内存堆的HIDL Severis而设计的。


图片.png

使用实例
声明HAL
IFoo HAL:

import [email protected]::MemoryBlock;
interface IFoo {
    getSome() generates(MemoryBlock block);
    giveBack(MemoryBlock block);
};

Android.bp:

hidl_interface {
    ...
    srcs: [
        "IFoo.hal",
    ],
    interfaces: [
        "[email protected]",
        ...
};

再HAL service 端的实现:
1.获取 hidl_memory

#include 
using ::android::hidl::allocator::V1_0::IAllocator;
using ::android::hardware::hidl_memory;
...
  sp allocator = IAllocator::getService("ashmem");
  allocator->allocate(2048, [&](bool success, const hidl_memory& mem)
  {
        if (!success) { /* error */ }
        // you can now use the hidl_memory object 'mem' or pass it
  }));

2.创建一个HidlMemoryDealer来获取hidl_memory:

#include 
using ::android::hardware::HidlMemoryDealer
/* The mem argument is acquired in the Step1, returned by the ashmemAllocator->allocate */
sp memory_dealer = HidlMemoryDealer::getInstance(mem);

3.使用MemoryBlock申请内存

struct MemoryBlock {
IMemoryToken token;
uint64_t size;
uint64_t offset;
};
//==========================================
#include 
using ::android::hidl::memory::block::V1_0::MemoryBlock;
Return Foo::getSome(getSome_cb _hidl_cb) {
    MemoryBlock block = memory_dealer->allocate(1024);
    if(HidlMemoryDealer::isOk(block)){
        _hidl_cb(block);
    ...

4 解除分配:

Return Foo::giveBack(const MemoryBlock& block) {
    memory_dealer->deallocate(block.offset);

5.使用数据

#include 
#include 
using ::android::hidl::memory::V1_0::IMemory;
sp memory = mapMemory(block);
uint8_t* data =
static_cast(static_cast(memory->getPointer()));

6.配置 Android.bp

shared_libs: [
        "[email protected]",
        "[email protected]"
        "[email protected]",
        "libhidlbase",
        "libhidlmemory",

3-对binder HIDL 进行改进-FMQ
FMQ 快速队列, FMQ 在实际的使用中并不多,主要的理念就是FMQ 在进程间传递,不经过kernel binder 节点,节省了开支,后面继续研究

REF:
https://www.jianshu.com/p/550040f8f7cb

你可能感兴趣的:(hidl 性能设计)