OpenVX

openvx 

1. 编译

尝试编译openvx_sample,下载相关代码。

下载的sample code直接使用make可以生成libopenvx.so

使用python Build.py --os linux可以编译sample code。

2. OpenVX使用流程

主要包含7个部分:

  1. 创建openvx上下文

    vx_context context = vxCreateContext();
  2. 创建输入、输出图像结点

    vx_image input_rgb_image = vxCreateImage( context, width, height, VX_DF_IMAGE_RGB );

    vx_image output_rgb_image = vxCreateImage( context, width, height, VX_DF_IMAGE_RGB );
  3. 创建graph

    vx_graph graph = vxCreateGraph(context);
  4. 构建graph

    vxScaleImageNode(graph, input_rgb_image, output_rgb_image, VX_INTERPOLATION_AREA)
  5. 验证graph

    vxVerifyGraph( graph );
  6. 真正运行graph

    vxProcessGraph(graph);
  7. 释放资源

    vxReleaseContext(&context);

3. OpenVX中调用OpenCL代码解析

1. vxCreateContext

一个平台对就一个target,一个target包含多个kernel。

./sample/framework/vx_context.c中的变量定义了几种target支持, c_model, opencl, openmp:

vx_char targetModules[][VX_MAX_TARGET_NAME] = {
"openvx-c_model",
#if defined(EXPERIMENTAL_USE_OPENCL)
"openvx-opencl",
#endif
#if defined(EXPERIMENTAL_USE_OPENMP)
"openvx-openmp"
#endif
};

以OpenCL为例,当用户调用函数vxCreateContext(sample/framework/vx_context.c)时,其会调用函数ownLoadTarget (sample/framework/vx_target.c), 去dlopen打开libopenvx-opencl.so, 使用dlsym(mod, name)获取vxTargetInit, vxTargetAddKernel(sample/targets/opencl/vx_interface.c)等opencl的相关函数句柄。

而在vxTargetAddKernel函数中,调用ownInitializeKernel(sample/framework/vx_kernel.c)加载了所有OpenCL实现的kernel函数。

在sample/targets/opencl目录下的c文件定义了一些vx_cl_kernel_description_t box3x3_clkernel变量,包括box3x3_clkernel, gaussian3x3_clkernel, and_kernel等 ,这些kernel

opencl kernel结构:

包含vx_kernel_description_t还有一些其它属性,它把function置为NULL,并提供了一个sourcepath变量用来存放opencl函数。

typedef struct _vx_cl_kernel_description_t {
vx_kernel_description_t description;
char sourcepath[VX_CL_MAX_PATH];
char kernelname[VX_MAX_KERNEL_NAME];
cl_program program[VX_CL_MAX_PLATFORMS];
cl_kernel kernels[VX_CL_MAX_PLATFORMS];
cl_uint num_kernels[VX_CL_MAX_PLATFORMS];
cl_int returns[VX_CL_MAX_PLATFORMS][VX_CL_MAX_DEVICES];
void *reserved; /* for additional data */
} vx_cl_kernel_description_t;

kernel结构:

typedef struct _vx_kernel_description_t {
/*! \brief The vx_kernel_e enum */
vx_enum enumeration;
/*! \brief The name that kernel will be used with \ref vxGetKernelByName. */
vx_char name[VX_MAX_KERNEL_NAME];
/*! \brief The pointer to the function to execute the kernel */
vx_kernel_f function;
/*! \brief The pointer to the array of parameter descriptors */
vx_param_description_t *parameters;
/*! \brief The number of paraemeters in the array. */
vx_uint32 numParams;
/*! \brief The parameters validator */
vx_kernel_validate_f validate;
/*! \brief The input validator (deprecated in openvx 1.1) */
void* input_validate;
/*! \brief The output validator (deprecated in openvx 1.1) */
void* output_validate;
/*! \brief The initialization function */
vx_kernel_initialize_f initialize;
/*! \brief The deinitialization function */
vx_kernel_deinitialize_f deinitialize;
} vx_kernel_description_t;

可以看到目前虽然配置了一些参数,但OpenCL分为主机端代码和device端代码,device端代码在kernel/opencl中,而host端代码在哪呢?如何根据设置的参数去执行Host端代码,从而执行device端代码:

可以看到在vxTargetInit函数中,调用ownInitializeKernel初始化kernel时,判断了kfunc是否为NULL,(kfunc == NULL ? vxclCallOpenCLKernel : kfunc)如果为NULL则使用vxclCallOpenCLKernel函数。

我们再看vxclCallOpenCLKernel函数,我们发现这个函数里有clSetKernelArg,clEnqueueNDRangeKernel等OpenCL的API函数,这个便是host-side的OpenCL代码。

2. vxScaleImageNode

在sample/framework/vx_node_api.c中定义了所有提供的可用的OpenVX结点,包括vxScaleImageNode结点,通过如下方法创建Node:

vx_kernel kernel   = vxGetKernelByEnum( context, VX_KERNEL_SCALE_IMAGE );

如果函数有两种实现,那么按照优先级使用: opencl > openmp > c_model。(不对,感觉优先使用的是c_model的函数;实际是先找到opencl kernel,但找到之后并没有停止查找,找到后面的c_model就会覆盖掉前面的opencl kernel。不知道这儿是写错了,还是就是要优先使用c_model,代码见sample/framework/vx_kernel.c中的vxGetKernelByEnum函数)

node的参数如何传递给kernel: 在vxCreateNodeByStructure中调用vxSetParameterByIndex将Node的参数传递kernel。

3. vxVerifyGraph

vx_graph.c会调用每一个结点的validator函数,包括inputValidator,outputValidator,确保构建的Graph可以跑通。

4. vxProcessGraph

vxProcessGraph函数调用vxExecuteGraph函数,在其中调用action = target->funcs.process(target, &node, 0, 1);,其中的funcs.process就是各个target的vxTargetProcess函数。

在vxTargetProcess中会调用nodes[n]->kernel->function,即我们事先定义的host-side端代码,传递结点,参数,以及参数个数:

status = nodes[n]->kernel->function((vx_node)nodes[n],
(vx_reference *)nodes[n]->parameters,
nodes[n]->kernel->signature.num_parameters);

而我们的function,则主要负责内存管理,以及调用device端代码。

几种参数类型:

memory:

CL_MEM_OBJECT_BUFFER

CL_MEM_OBJECT_IMAGE2D

scalar:

VX_TYPE_SCALAR

threashold:

VX_TYPE_THRESHOLD

4. OpenVX中使用OpenCL的编译问题

使用Makefile编译出来的so默认是没有opencl。

使用Build.py出来的so可以有opencl,但结点报错:

Target[1] is not valid!

Target[2] is not valid!

LOG: [ status = -17 ] Node: org.khronos.openvx.color_convert: parameter[1] is not a valid type 1280!

在target.mak中对SYSDEFS添加EXPERIMENTAL_USE_OPENCL,可以编译Opencl,但在运行时build opencl 代码时报错,可以将错误信息打印出来,发现找不到头文件。

查看代码,发现在sample/targets/opencl/vx_interface.c中需要如下两个参数,VX_CL_INCLUDE_DIR是VX头文件位置,VX_CL_SOURCE_DIR是CL源码位置,在环境中可以配置这两个参数:

char *vx_incs = getenv("VX_CL_INCLUDE_DIR");

char *cl_dirs = getenv("VX_CL_SOURCE_DIR");

/usr/include/features.h:367:12: fatal error: 'sys/cdefs.h' file not found

在cl编译命令里(sample/targets/opencl/vx_interface.c)添加-I /usr/include/x86_64-linux-gnu/:

snprintf(cl_args, sizeof(cl_args), "-D VX_CL_KERNEL -I %s -I /usr/include/x86_64-linux-gnu/ -I %s %s %s", vx_incs, cl_dirs...

Linux gnu/stubs-32.h: No such file or directory

这是缺少32位的嵌入式C库。在嵌入式开发环境配置时,也常遇到这个问题。sudo apt-get install libc6-dev-i386

fatal error: 'stddef.h' file not found

定位stddef.h, 在cl编译命令里cl_args里添加-I /usr/include/linux/

vx_khr_opencl.h和vx_api.h里有些类型进行了重定义:

不要在vx_khr_opencl.h里include vx_api.h。

histogram.cl仍然报错,将histogram的kernel去掉,就可以成功编译。

5. 使用OpenCL vx_not

使用c_model的VX_KERNEL_NOT可以正常运行,使用opencl的就会报如下错误:

clSetKernelArg: OpenCL error CL_INVALID_ARG_INDEX at vxclCallOpenCLKernel in /home/guru_ge/openvx/openvx_sample/sample/targets/opencl/vx_interface.c:639

clSetKernelArg: OpenCL error CL_INVALID_ARG_INDEX at vxclCallOpenCLKernel in /home/guru_ge/openvx/openvx_sample/sample/targets/opencl/vx_interface.c:639

clEnqueueNDRangeKernel: OpenCL error CL_INVALID_KERNEL_ARGS at vxclCallOpenCLKernel in /home/guru_ge/openvx/openvx_sample/sample/targets/opencl/vx_interface.c:724

尝试自己写host side的code。

写完发现并在Load时就不通过,检查原因,打开log信息,发现在自己实现的代码中有个CL_ERROR_MSG找不到,直接注释该行代码,程序可以正常运行。但是得到的结果还是不对,全是黑色,好像是没有将处理后的结果拷贝回来,导致结果全是0。

这是因为cl中提供两种形式的表达,一个是image2d_t,一个是简单的buffer,在vx_interface.c中编译cl时,加上了CL_USE_LUMINANCE,使用的是image2d_t;而在编译整个OpenVX时,没有加上CL_USE_LUMINANCE,导致外面使用的是简单的buffer,而一个image2d_t的参数如果使用buffer需要传递5个参数,所以导致最后设置参数时两边不一致出错。修改concerto/target.mak在31行SYSDEFS里加上CL_USE_LUMINANCE就可以了。

虽然不报错了,但是出来的结果居然是一条直线,而不是取反后的效果,很奇怪:


一条直线

难道是传给opencl的图像就不对?尝试手动拷贝图像数据。

尝试学习opencl c 语法,修改代码查看结果,发现openvx在实现opencl的时候not kernel时存在一些不规范的地方,可能这些问题在其它平台可以运行,但到现在这个平台上就不行了。

原来的kernel实现:

__kernel void vx_not(read_only image2d_t a, write_only image2d_t b) {
int2 coord = (get_global_id(0), get_global_id(1));
write_imageui(b, coord, ~read_imageui(a, nearest_clamp, coord));
}

首先我尝试打印其像素坐标时,发现得到的x, y坐标总是相同的,这很奇怪,这也解释了为什么结果只有一条直线,因为它只写了x, y坐标相同的那些像素点的值。查看 API发现get_global_id返回的是size_t,所以要用(int)去显示转换一下,再打印时,发现坐标在不停的变换,变成正常的了。

再运行,得到的图居然是一幅全白的图,说明像素值还有问题。尝试打印原像素值,与取反后的像素值,发现相加不是255,说明这里的取反操作也有问题。read_imageui返回的类型是uint4向量,我们取反时,得到的结果并不对,这里使用255直接相减,最后代码如下所示:

__kernel void vx_not(read_only image2d_t a, write_only image2d_t b) {
int2 coord = (int2)(get_global_id(0), get_global_id(1));
write_imageui(b, coord, 255-read_imageui(a, nearest_clamp, coord));
}

得到的效果正确了,如下:


right_result

6. 实现OpenCL vx_scale

实现opencl scale报错:

parameter[1] is an invalid dimension 640x240

传递的参数是(inputImg, outputImg, type),parameter[1]应该是输出图像,大小确实应该是640x240。

使用c_model中的outputvalidator就不报这个错了,说明不能直接return VX_SUCCESS,可能validator中还需要做些其它的事情。

在validator中会记录一些信息,以供后面verify时与实际传入参数比对,所以不能直接返回SUCCESS:

    ptr->type = VX_TYPE_IMAGE;
ptr->dim.image.format = VX_DF_IMAGE_U8;
ptr->dim.image.width = width;
ptr->dim.image.height = height;

然而现在又报如下错误:

clEnqueueNDRangeKernel: OpenCL error CL_INVALID_EVENT at vxclCallOpenCLKernel in /home/guru_ge/openvx/openvx_sample/sample/targets/opencl/vx_interface.c:725

clEnqueueReadImage: OpenCL error CL_INVALID_EVENT at vxclCallOpenCLKernel in /home/guru_ge/openvx/openvx_sample/sample/targets/opencl/vx_interface.c:793

为什么event会invalid呢?尝试自己写host-side代码,不使用默认的。

自己的代码报如下错误:

VX_ZONE_ERROR:[vxcl_platform_notifier:59] CL_OUT_OF_RESOURCES error executing CL_COMMAND_READ_IMAGE on GeForce GTX 1080 Ti (Device 0)

spec里解释CL_OUT_OF_RESOURCES: if there is a failure to allocate resources required by the OpenCL implementation on the device.

这估计是使用c_model的validator导致没有初始化cl_mem,尝试使用cl validator。

在check scale node parameter时报如下错误:

LOG: [ status = -10 ] Node[3] org.khronos.openvx.image_scaling: parameter[2] failed input/bi validation!

这估计是Input validator里只允许Image类型,没有判断scalar类型。

所以validator要对每个参数逐一判断,对于input参数,直接返回SUCCESS就可以了;而对output参数,还需要写一些信息。

结果还是全黑的,在kernel中打印坐标发现也不对,查看代码发现输入的维度是输入图片的大小,这儿应该是输出图像的大小才对。

再运行还是黑色,发现在取坐标转换时,没有将float转为int,导致有问题(所以类型要确保完全一致,不会替你做转换)。修改后,可以正常运行。

__kernel void image_scaling(read_only image2d_t in,
write_only image2d_t out)
{
//从glob_id中获取目标像素坐标
int2 coordinate = (int2)(get_global_id(0), get_global_id(1));
//计算归一化浮点坐标
float2 normalizedCoordinate = convert_float2(coordinate) * (float2)(2, 2);
//根据归一化坐标从原图中读取像素数据
uint4 colour = read_imageui(in, sampler, convert_int2(normalizedCoordinate));
//将像素数据写入目标图像
write_imageui(out, coordinate, colour);
}

实际比较,vx_not, vx_scale使用opencl, c_model实现时间对比:

opencl:

average time: 44099.857143 us

c_model:

average time: 68343.380952 us

7. vx debug print信息

程序中通过获取VX_ZONE_MASK环境变量的值来设置Log级别,可以通过如下将所有级别信息都打开:

export VX_ZONE_MASK=fffff

一共有如下几个级别,每个级别占int的一个bit位:

enum vx_debug_zone_e {
VX_ZONE_ERROR = 0, /*!< Used for most errors */
VX_ZONE_WARNING = 1, /*!< Used to warning developers of possible issues */
VX_ZONE_API = 2, /*!< Used to trace API calls and return values */
VX_ZONE_INFO = 3, /*!< Used to show run-time processing debug */ VX_ZONE_PERF = 4, /*!< Used to show performance information */
VX_ZONE_CONTEXT = 5,
VX_ZONE_OSAL = 6,
VX_ZONE_REFERENCE = 7, VX_ZONE_ARRAY = 8,
VX_ZONE_IMAGE = 9,
VX_ZONE_SCALAR = 10,
VX_ZONE_KERNEL = 11, VX_ZONE_GRAPH = 12,
VX_ZONE_NODE = 13,
VX_ZONE_PARAMETER = 14,
VX_ZONE_DELAY = 15, VX_ZONE_TARGET = 16,
VX_ZONE_LOG = 17, VX_ZONE_MAX = 32
};

Ref

AMD openvx实现:

https://github.com/GPUOpen-ProfessionalCompute-Libraries/amdovx-core

https://github.com/GPUOpen-ProfessionalCompute-Libraries/amdovx-modules

OpenVX的更多相关文章

  1. Visionworks OpenVX

    [TOC] Visionworks OpenVX OpenVX heterogeneous computation framework Spec OpenVX 1.2源碼解析 - 目錄結構 除了官方的 ...

  2. 人工智能AI芯片与Maker创意接轨(下)

    继「人工智能AI芯片与Maker创意接轨」的(上)篇中,认识了人工智能.深度学习,以及深度学习技术的应用,以及(中)篇对市面上AI芯片的类型及解决方案现况做了完整剖析后,系列文到了最后一篇,将带领各位 ...

  3. 人工智能AI芯片与Maker创意接轨 (中)

    在人工智能AI芯片与Maker创意接轨(上)这篇文章中,介绍人工智能与深度学习,以及深度学习技术的应用,了解内部真实的作业原理,让我们能够跟上这波AI新浪潮.系列文来到了中篇,将详细介绍目前市面上的各 ...

  4. 【ARM-Linux开发】【CUDA开发】【深度学习与神经网络】Jetson Tx2安装相关之三

    JetPack(Jetson SDK)是一个按需的一体化软件包,捆绑了NVIDIA®Jetson嵌入式平台的开发人员软件.JetPack 3.0包括对Jetson TX2 , Jetson TX1和J ...

  5. Jetson TX2

    NVIDIA Jetson TX2作为一个嵌入式平台的深度学习端,具备不错的GPU性能,可以发现TX2的GPU的计算能力是6.2.这意味着TX2对半精度运算有着良好的支持,因此,完全可以在桌面端训练好 ...

  6. Jetson TX2介绍

    Jetson TX2是NIVDIA瞄准人工智能在Jetson TK1和TX1推出后的升级 TX2的GPU和CPU都进行了升级,内存增加到了8GB.存储增加到了32GB,支持Wifi和蓝牙,编解码支持H ...

  7. OpenNESS,开源的边缘网络服务平台

    目录 文章目录 目录 参考文章 OpenNESS 的电梯间演讲 OpenNESS 与 ETSI MEC Edge Controller Software 的功能清单 Edge Platform Sof ...

  8. 基于GPU的图像处理平台

    基于GPU的图像处理平台 1.  (309)英伟达推Jetson TX1 GPU模块力推人工智能 1.1 产品概述 Jetson TX1 GPU模块,主要针对近年来蓬勃发展的人工智能市场,包括无人机. ...

  9. NVIDIA Jetson™ TX1 Module

    NVIDIA® Jetson TX1 是一台模块式计算机,代表了视觉计算领域近20年的研发成就,其尺寸仅有信用卡大小.Jetson TX1 基于NVIDIA Maxwell™ 架构,配有256个 NV ...

随机推荐

  1. C语言指针与指向指针的指针

    #include <stdio.h> #include <string.h> int main() { char a[]="hello world"; ch ...

  2. 洛谷 1486 郁闷的出纳员【Treap】

    [题意概述] 要求维护一个序列支持以下操作: 1,插入元素x: 2,把序列的所有元素加上x: 3,把序列的所有元素减去x,同时低于一个给定的下限的元素马上被删除: 4,询问序列中第k大的元素. [题解 ...

  3. 【Codeforces 429B】Working out

    [链接] 我是链接,点我呀:) [题意] 两个人,一个人在左上角,一个人在左下角. 左上角要到右下角去 左下角要到右上角去 只能走到相邻的格子(不能往回走,即一个往右下,一个往右上走) 要求这两个人必 ...

  4. AIM Tech Round (Div. 2)——ABCD

    http://codeforces.com/contest/624 A.python是用来写div2的AB题的... a, b, x, y = map(float, raw_input().split ...

  5. java中的redis工具类

    1.redis基础类 package com.qlchat.component.redis.template; import javax.annotation.PostConstruct; impor ...

  6. POJ 1376 Robot

    Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 7866   Accepted: 2586 Description The R ...

  7. ZooKeeper是什么(转)

    ZooKeeper是什么? ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提 ...

  8. [Meteor] Meteor安装被墙问题

    我的系统安装地址是这个https://static-meteor.netdna-ssl.com/packages-bootstrap/1.3.2.4/meteor-bootstrap-os.osx.x ...

  9. Android 65K问题之Multidex原理分析及NoClassDefFoundError的解决方法

    Android 65K问题相信困惑了不少人,尽管AS的出来能够通过分dex高速解决65K问题,可是同一时候也easy由于某些代码没有打包到MainDex里引起NoClassDefFoundError. ...

  10. jsencrypt代码分析

    jsencrypt代码分析——openssl的rsa加密解密在js的实现   在js上做rsa,感觉jsencrypt这个是封装的比较好的,但用起来还是遇到了些坑,所以踩进代码里填填坑- 项目在这里  ...