Qualcomm Hexagon DSP入门篇之开始连接:fastRPC技术

Qualcomm Hexagon DSP入门篇之开始连接:fastRPC技术

      FastRPC主要用途:

      在开始Hexagon DSP开发时,我们需要熟悉为此平台打造的FastRPC技术,为方便用户快速进行客户端的开发以及DSP的调试,FastRPC为用户提供了一种先进的远程调用方式,从而使得用户可以在本地客户端上实现远程的调用,在本篇中,我将着重介绍FastRPC的架构并在安卓系统上实现,以及演示如何使用ION内存分配来为FastRPC创建连续的缓存区域。

      FastRPC在设计之初便致力于实现在aDSP与APPS(基于应用处理器)之间远程的调用,为实现其功能,程序需要如下的硬件实现:

      1.aDSP与应用共享内存(不包括L2/L1缓存)

      2.aDSP中能支持有限的物理映射

      同时,为了支持高性能的计算,应用的内存必须被直接映射到aDSP中,原因在于aDSP中没有支持足够物理地址以及ION。

      通过将缓存分成in以及rout区,驱动程序能够实现aDSP与应用之间的cache同步,使RPC的延迟降低了将近50%,此外”inrout”与”in and rout”模式并没有太大区别,因此inrout并没有被采纳。

      考虑到如下原因,在aDSP中,FastRPC协议采用同步的设计:

      1.用户并不需要繁琐的创建一个线程来添加异步行为

      2.对于内核来说,添加异步调用将会导致额外的复杂度,导致内核对aDSP与应用之间的管理更加麻烦。

      3.对于aDSP来说,由于性能主要是由cache的异步操作决定的,所以,内存的速度并不会因此受到影响,

      从官方给出的图片我们可以看出该技术调用的方式:


      可以看出,FastRPC由六个主要部分组成:

      Client:用户模式下启动的远程调用程序

      Stub:与Client连接,用于自动生成交互代码并编排参数

      ADSPRPC 驱动:ADSPRPC核心驱动,用于接收远程调用,安排队列并等待客户端的响应

      ADSPRPC 框架:ADSPRPC框架将指令出列并为其调度处理

      Skel:为未编排的参数自动生成代码

      Object:实现调用的方法

       安卓环境下的FastRPC实现

       在为安卓系统搭建FastRPC连接时需要如下的组件:

      应用处理器端:

      在aDSP端则需要如下的库:

      通过如下步骤来设置FastRPC驱动程序(注意,当使用FastRPC调用远程文件系统时,FastRPC可以自动生成,所以不需要多余的启动步骤)

1.   检测adsprpc.ko驱动程序是否正在运行:

adb shell ls /dev/adsprpc-smd

2.   如果文件不存在那么输入如下命令

adb root
adb wait-for-device
adb shell insmod /system/lib/modules/adsprpc.ko

3.   如果模块不存在并且/dev/adsprpc-smd在设备中无法支持FastRPC,则重新检测adsprpc.ko的存在

adb shell ls /dev/adsprpc-smd

4.   通过如上的步骤,FastRPC就被配置成功了


建议选择性的检查adsprpcd是否在运行

logcat -s adsprpc


该守护进程可能位于/system/bin或/system/vendor/bin中,如果该程序正在运行且没有报错信息,则说明FastRPC已经成功使能并且可以进行操作了

反之,若守护进程没有运行,则启动守护进程并检查

locat -s adsprpc


  之所以会出现这种情况,是因为在某些老版本中,守护进程还未初始化时所有的进程调用都会被屏蔽

使用ION分配器

  aDSP的硬件架构对于非连续内存的访问非常低效,这种对内存的访问差不多等同于”malloc”指令。不过安卓系统为其提供了称为ION的连续内存分配器,对于更加深入的文献可参考http://lwn.net/Articles/480055.

   不同版本的安卓可以为用户提供不同版本的ION实现,下文中将会演示两种版本下为ION的API

  ICS与JB

   ICS与JB的实现对于ion_alloc中的ioctl有不同的结构,举例如下:

ICS

struct ion_allocation_data {
     size_t len;
     size_t align;
     unsigned int flags;
     struct ion_handle *handle;
};

  同时为了确定堆栈的id,调用者需要设置标志位

alloc.flags = (0x1 << HEAP_ID);
JB

struct ion_allocation_data {
     size_t len;
     size_t align;
   unsigned int heap_mask;
     unsigned int flags;
     struct ion_handle *handle;
};

  为了确定堆栈的id,调用者需要设置heap_mask

alloc.heap_mask = (0x1 << HEAP_ID);


在aDSP上创建persistent线程

  在开发是,另外一个需要考虑的问题便是导入到aDSP中的模块需要被所有的处理过程共享,因此,如果一个对于高级操作系统来说,时刻保持特定的上下文从而跟踪需要时刻调用的数据是非常重要的。

  因此我们可以通过HAP_pls.h来创建这样一个线程

struct thread {
   qurt_thread_t tid;
   qurt_sem_t sem;
   boolean running;
   void* stack;
}
static int thread_start(void* data) {
   struct thread* th = (struct thread*)data;
   while(th->running) {
      qurt_sem_down(&th->sem);
   }
   return 0;
}
static void thread_dtor(void* data) {
   struct thread* th = (struct thread*)data;
   if(th->tid) {
      int err;
      th->running = 0;
      qurt_sem_up(&th->sem);
      qurt_thread_join(th->tid, &err);
   }
   if(th->stack) {
      free(th->stack);
      qurt_sem_destroy(&th->sem);
   }
}
static int thread_ctor (void* ctx, void* data) {
   //this constructor may be called twice, but only one instance will survive
   qurt_thread_attr_t attr;
   struct thread* th = (struct thread*)data;
   int size = 1024*8;
   if(0 == (th->stack = malloc(size))) {
      goto error;
   }
   qurt_sem_init_val(&th->sem, 0);
   qurt_thread_attr_set_stack_size (&attr, size);
   qurt_thread_attr_set_stack_addr (&attr, (unsigned long long *)th->stack);
   qurt_thread_attr_set_name (&attr, "my thread");
   th->running = 1;
   if(0 != qurt_thread_create(&th->tid, &attr, (void*)thread_start, th)) {
      goto error;
   }
   return 0;
error:
   thread_dtor(th);
   return -1;
}
//the first time this function is called the thread will be constructed
//all subsequent calls will return the same thread instance or non-zero failure
//this function should only be called from a FastRPC provided thread.
static int thread_instance(struct thread* th)  {
   return HAP_pls_add_lookup((uint32)thread_ctor,  //type, some unique address
                              0,                   //key, for different type instances
                              sizeof(struct thread),  //size of our struture
                              thread_ctor,            //structure ctor
                              0,                      //aditional user context for ctor
                              thread_dtor,            //desturctor
                              &th);                   //result
}
至此,我们就介绍了使用FastRPC过程中的一些基本步骤以及快速上手代码,如果您还有更多的疑惑,可以查看官方提供的文献,作为一种可以实现远程实时开发的技术,FastRPC为我们提供了难以想象的方便,当开发安卓系统的时候,相信各位能有更好的体验。

你可能感兴趣的:(架构设计,嵌入式,开发者,HexagonDSP)