首页 > 编程语言 >OpenCL 编程步骤 3. 获取Context 上下文

OpenCL 编程步骤 3. 获取Context 上下文

时间:2024-12-20 11:32:01浏览次数:3  
标签:CL 上下文 Context cl OpenCL context NULL 设备

转载 https://deepinout.com/opencl/opencl-basic-tutorials/opencl-create-context.html

上下文为关联的设备、内存对象、命令队列、程序对象、内核对象提供一个容器。上下文是OpenCL应用的核心。正是上下文驱动着应用程序与特定设备以及特定设备之间的通信。

对于上下文中关联的所有计算设备必须全都来自于同一平台,对于来自不同平台的OpenCL设备,需要为各个平台独立地创建上下文。对于同一平台的设备,上下文中可以关联多个设备。主机应用也可以使用多个上下文来管理多个设备,甚至同一个平台多个设备都可以关联到不同的上下文,如下图所示。

在上图中,平台1有多个CPU和GPU设备。同一平台的设备可以关联到同一上下文中,所以上下文1、上下文2中关联CPU和GPU设备是可行的。

对于平台中的设备,上下文不是非要关联所有的设备,所以在上下文4中只是关联了部分设备。而不同平台的设备不能关联到同一上下文中,所以关联平台1中的GPU3和平台2中的CPU1的上下文3是不合法的。

个人理解:

  • 平台对上下文,一对多
  • 同一平台的设备对上下文,多对一

OpenCL 创建上下文

OpenCL上下文对象用cl_context类型表示,可以使用如下两个函数其中之一来创建上下文:

cl_context clCreateContext(const cl_context_properties *properties,
                           cl_uint num_devices ,
                           const cl_device_id *devices ,
                           void (CL_CALLBACK *pfn_notify )(const char *, const void *, size_t, void *),
                           void *user_data ,
                           cl_int *errcode_ret )

cl_context clCreateContextFromType(const cl_context_properties *properties,
                                   cl_device_type device_type ,
                                   void (CL_CALLBACK *pfn_notify )(const char *, const void *, size_t, void *),
                                   void *user_data,
                                   cl_int *errcode_ret)

两个函数用法很类似,主要的区别在于:

  • clCreateContext显示地指定设备(devices)来创建上下文;
  • clCreateContextFromType根据给定的设备类型(device_type)来创建上下文。对设备类型详见下表。

参数properties指定上下文属性名称及属性相应的值的列表,且最后一个元素为0,见下表。当实现自定义选择平台时,参数properties可以设置为NULL。

参数pfn_notify和user_data用来共同定义一个回调函数,可以调用这个回调报告上下文生命周期中出现错误的有关信息,要把user_data作为最后一个参数传至回调函数。user_data为void类型指针,也就是可以指向任何数据,当错误发生时user_data能够提供信息。参数pfn_notf iy和user_data也都可以设置为NULL。参数errcode_ret为函数的返回状态,成功执行值为CL_SUCCESS,否则值为对应的错误代码。

下面的代码清单展示了给定一个平台,查询平台中GPU设备,并创建上下文:

cl_device_id *device;
cl_platform_id platform;
cl_int err;
cl_uint NumDevice;

//选择第一个平台
err = clGetPlatformIDs(1, &platform, NULL);
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 0, NULL, &NumDevice);
device = (cl_device_id *)malloc(sizeof(cl_device_id) *NumDevice);

//选择GPU设备
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, NumDevice, device, NULL);

//创建上下文
cl_context_properties properites[] = {CL_CONTEXT_PLATFORM, (cl_context_properties)platform, 0};

//指定设备创建上下文
//cl_context
context=clCreateContext(properites,NumDevice,device,NULL,NULL,&err);

//指定设备类型创建上下文
cl_context context = clCreateContextFromType(properites, CL_DEVICE_TYPE_GPU, NULL, NULL, &err);

例子中,clCreateContext函数把平台中查询到的所有GPU设备都关联到创建的上下文中。clCreateContextFromType则是选择第一平台中的GPU设备。从功能来说,两个函数实现的功能是一样的。

clGetContextInfo

给定上下文,可以使用如下函数查询上下文各个属性信息:

cl_int clGetContextInfo(cl_context      context ,
                        cl_context_info param_name ,
                        size_t          param_value_size ,
                        void            *param_value ,
                        size_t          *param_value_size_ret )

参数param_name为查询属性名称,取值见下表,参数param_value返回上下文查询属性信息。

下面的代码清单展示了使用clContextInfo()查询上下文关联的设备数目及上下文的引用计数方法:

cl_platform_id platform;
cl_int err;
cl_uint NumDevice;

err = clGetPlatformIDs(1, &platform, NULL);
cl_context_properties properites[] = {CL_CONTEXT_PLATFORM, (cl_context_properties)platform, 0};
cl_context context = clCreateContextFromType(properites, CL_DEVICE_TYPE_ALL, NULL, NULL, &err);

NumDevice = 0;
size_t DeviceSize;
err = clGetContextInfo(context, CL_CONTEXT_NUM_DEVICES, sizeof(cl_uint), &NumDevice, NULL);

printf("Number of Device in context:%d\n", NumDevice);

上述代码片段中,在调用函数clContextInfo时,对其参数param_name指定的是CL_CONTEXT_NUM_DEVICES,从字面上理解非常直观,即我们要查询当前上下所包含的计算设备个数。除了可指定CL_CONTEXT_NUM_DEVICES这个属性以外,还能指定CL_CONTEXT_REFERENCE_COUNT这一属性,表示查询当前上下文的引用计数值。在之前我们没有讲解任何关于OpenCL中引用计数的概念,那这个引用计数到底是什么?它又有何作用呢?

在使用clCreateContext或clCreateContextFromType创建上下文时,并不像我们之前创建平台和设备时返回错误代码,而是直接返回cl_context对象,此时该上下文对象的引用计数为1。

其实,OpenCL对很多对象采用了类似于Apple的Cocoa Framework中的内存管理机制(毕竟OpenCL的初稿出自Apple)。在这种机制下,主张谁分配了某个对象,那么谁就负责释放该对象。如果这个对象不是由你来分配的,那么你也不用去释放它。我们通过OpenCL接口就能看出哪些对象是被分配的,哪些不是。例如,clGetPlatformIDs函数所获得的platform_id对象就不需要通过某个接口进行释放,因为它是通过Get获得的。

类似的是, clGetDeviceIDs也同样如此。这里的clCreateContext我们看到用的是Create这个前缀,当我们看到这个前缀时就要想到一定有一个与之相对应的Retain接口和Release接口。Retain接口用于显式地做引用计数加1操作;而Release则是显式地做引用计数减1操作,而只有当引用计数为0时,Release操作才会释放对应的空间。而引入这个引用计数机制对于第三方库或者跨模块的开发非常有利。例如,我们在模块A创建了一个上下文,然后在做完某个计算后把它提交给模块B继续计算。

当然,出于性能要求,模块B借用了这个上下文对象之后可能会自己另建一个命令队列然后执行,因此与模块A的后续操作完全可以是异步的。这就会引发一个问题,当模块A执行完之后,把该上下文对象释放掉,而模块B此时还在使用这个上下文对象。因此,如果没有引用计数,而是直接把此上下文对象释放掉,那么模块B在使用此对象时就可能会引发异常。而有了引用计数机制,我们可以遵循这个机制来做——在模块A中创建上下文对象,那么在A用完之后通过Release接口将它释放。如果要把此对象交给模块B做后续操作,那么要由模块B对此对象做一次Retain操作,然后模块B操作完成之后也要调用一次Release操作来释放此上下文对象。这样一来,上下文对象就能安全而又完整地被模块A与模块B共同使用了。

上下文对象的Retain和Release接口

对于上下文对象的Retain和Release接口如下:

cl_int clRetainContext(cl_context context )
cl_int clReleaseContext(cl_context context )

clRetainContext增加引用计数(引用计数+1),clReleaseContext减少引用计数(引用计数-1)。如果外部函数访问预先创建的上下文,确保在处理前调用clRetainContext,处理完成后调用clReleaseContext。如果在创建上下文的函数中,在函数完成前调用clReleaseContext来减少引用计数,使其值为0,释放上下文空间。

下面的代码展示了这两个函数的使用方式:

…
cl_context_properties properites[] = {CL_CONTEXT_PLATFORM, (cl_context_properties)platform, 0};
cl_context context = clCreateContextFromType(properites, CL_DEVICE_TYPE_ALL, NULL, NULL, NULL);

cl_uint ReferenCount;
clGetContextInfo(context, CL_CONTEXT_REFERENCE_COUNT, sizeof(cl_uint), &ReferenCount, NULL);
printf("Initial Reference Count: %d\n ", ReferenCount);

clRetainContext(context);
clGetContextInfo(context, CL_CONTEXT_REFERENCE_COUNT, sizeof(cl_uint), &ReferenCount, NULL);
printf("Reference Count: %d\n ", ReferenCount);

clReleaseContext(context);
clGetContextInfo(context, CL_CONTEXT_REFERENCE_COUNT, sizeof(cl_uint), &ReferenCount, NULL);
printf("Reference Count: %d\n ", ReferenCount);

如上代码,输出为:

Initial Reference Count:1
Reference Count:2
Reference Count:1

标签:CL,上下文,Context,cl,OpenCL,context,NULL,设备
From: https://www.cnblogs.com/turbinee/p/18618951

相关文章

  • OpenCL 编程步骤 2. 获取设备
    clGetDeviceIDs查询支持OpenCL设备列表:cl_intclGetDeviceIDs(cl_platform_idplatform,cl_device_typedevice_type,cl_uintnum_entries,cl_device_id*devices,......
  • OpenCL 编程步骤 1. 获取平台
    参考OpenCL平台clGetPlatformIDs使用如下函数查询来获得系统平台列表:cl_intclGetPlatformIDs(cl_uintnum_entries,cl_platform_id*platforms,cl_uint*num_platforms)在OpenCL程序中,上述函数可以调用两次:......
  • 深入理解华为鸿蒙的 Context
    深入理解华为鸿蒙的Context一、引言在华为鸿蒙操作系统里,Context是极为关键的概念。它如同应用运行的信息中心,为应用提供环境信息、资源访问途径以及与系统交互的接口,对构建优质鸿蒙应用至关重要。二、Context的基本概念与作用(一)定义与核心功能Context代表应用运行的上下......
  • RequestContextHolder 与 HttpServletRequest 的联系
    1.什么是RequestContextHolder?RequestContextHolder是Spring框架提供的一个工具类,用于在当前线程中存储和获取与请求相关的上下文信息。它是基于ThreadLocal实现的,能够保证每个线程独立存储和访问请求信息。与HttpServletRequest的关系:HttpServletRequest:是标准......
  • context.Session,写入数据,多久数据会清掉
     遇到一个数据偶尔为空的情况,数据是从sesion里取的,怀疑是session数据清空导致的。在不同的上下文中,context.Session数据的清空时间可能会有所不同。以下是几种可能的情况:ASP.NETCore中的Session:在ASP.NETCore应用程序中,Session的过期时间可以通过配置来设置。默认情......
  • 报错:jsmpeg.min.js:1 The AudioContext was not allowed to start. It must be resume
    文章目录问题分析1.添加用户点击监听事件2.使用userGesture事件3.手动触发用户交互4.使用await和async问题在使用jsmpeg接入视频流时控制台报警告,且页面没出现视频分析这个报错是因为浏览器的安全策略限制,AudioContext需要在用户与页面进行交互(如点击、......
  • 在LESS中如何定义变量上下文中的范围?
    在LESS中,变量的作用范围是其被声明的位置和该位置之后的所有区域,直到被另一个同名的变量声明覆盖。LESS没有提供类似于其他编程语言中的块级作用域或函数作用域的概念。然而,你可以通过一些技巧来模拟变量的“局部”作用域。在混合(Mixin)中定义变量:在LESS中,你可以在混合中定义变量......
  • 探索Spring之利剑:ApplicationContext接口
    嘿,开发者们!你是否曾在构建Spring应用时,感到困惑于那些复杂的配置和神秘的容器?今天,我们将揭开Spring中一个核心接口——ApplicationContext​的神秘面纱。这不仅是一篇技术文章,更是一次深入Spring心脏的探险之旅。系好安全带,我们即将启程!......
  • RequestContextHolder
    RequestContextHolder 是Spring框架中的一个工具类,它允许在没有显式传递请求对象的情况下,访问当前HTTP请求的上下文信息。它在一些需要访问当前请求但又不方便直接传递 HttpServletRequest 对象的场景中非常有用。基本概念RequestContextHolder 主要通过 ThreadLoca......
  • Net Core Cookie 、Net Framework cookie IHttpContextAccessor HttpContextAccessor
    NetEntityFrameworkCookieNetCoreCookieOptionsoption=newCookieOptions();option.Expires=DateTime.Now.AddMilliseconds(10);Response.Cookies.Append(key,value,option);IHttpContextAccessorHttpContextAccessorCORECOOKIE进行封装nam......