当前,科学计算需求急剧增加,基于CPU-GPU异构系统的异构计算在科学计算领域得到了广泛应用,OpenCL由于其跨平台特性在异构计算领域渐为流行,其调度困难的问题也随之暴露,传统的OpenCL任务调度需要在编码阶段确定调度方案,这种人工调度难度高、适应性差、效率低下、且存在资源竞争问题。MultiCL通过扩展OpenCL标准使得命令队列和设备解耦,实现了自适应调度,并为不同程度的开发人员提供了不同的调度方法,缓解了OpenCL的调度难题。

1 OpenCL基本介绍

OpenCL是第一个面向异构系统通用目的并行编程的开放式、免费标准,适用于跨CPU、GPU和其他处理器的异构混合编程。OpenCL通过创建一个高效的、底层的编程接口,实现了独立于硬件、操作系统和应用程序的并行计算生态系统的基础层。OpenCL用于协调主机和支持OpenCL标准的异构计算设备间的并行计算,并且具有明确的跨平台编程语言。

OpenCL是在异构系统上进行编程的行业标准。OpenCL不仅仅是一种编程语言,更是用于异构系统编程的行业标准框架。相较于CUDA,OpenCL程序可在不同供应商的硬件上移植,具有良好的功能可移植性。但是由于OpenCL作为一个底层通用框架,为程序员开放了大量硬件细节,这样的好处是编程人员提供了大量的程序优化空间,但是也造成了OpenCL程序不具备良好的性能可移植性,即相同程序在移植过程中会造成极大的性能差异。同时对于程序员而言,任务的划分以及调度完全由编程人员指定,编程人员难以感知和预测整体系统的运行状态和负载情况,使得程序难以达到最优效率。

OpenCL架构为了实现跨平台的异构计算,包含以下部分:

  1. OpenCL平台层:OpenCL平台层允许主机程序发现OpenCL设备并调用该设备参与计算,并为特定设备或设备组创建上下文。
  2. OpenCL运行时:OpenCL运行时允许主机程序在上下文创建后对其进行操作,OpenCL运行时为OpenCL程序提供了软件支持。
  3. OpenCL编译器:OpenCL编译器根据内核和设备扩展信息将内核文件编译为可执行文件。编译器支持基于并行扩展的ISO C99(ISO/IEC 9899:1999-Programming languages)语言的子集。OpenCL编译器可根据即时编译和二进制加载两种方式创建可执行文件。

OpenCL架构可分为平台模型、执行模型、存储模型和编程模型。

2 MultiCL

OpenCL标准要求开发人员在程序编码阶段就确定OpenCL程序的调度方案,使OpenCL面临调度难度高、适应性差、资源竞争、效率低下等问题。为了解决上述问题Ashwin M等人在SunCL基础上进一步开发的OpenCL任务级并行调度框架,该框架提供了跨厂商的OpenCL运行时支持。MultiCL实现了上下文级别的全队列调度和针对特定命令队列的本地调度功能,作者以此为基础实现了OpenCL任务的动态调度。

OpenCL内核调度策略取决于编程模型,开发者必须事先明确程序中所包含的内核调度的方案,为了实现OpenCL的自适应任务调度,Ashwin M等人对OpenCL API进行了扩展。表1描述了MultiCL的扩展属性。

表1 MultiCL扩展属性

为了表达全局队列调度机制,MultiCL框架扩展了一个新的上下文属性CL_CONTEXT_SCHEDULER,该扩展属性实现了上下文级别的OpenCL自适应调度,采用CL_CONTEXT_SCHEDULER创建的上下文,该上下文关联的命令队列与OpenCL设备解耦合,即创建OpenCL命令队列是不用指定OpenCL设备,从上下文层面解决了OpenCL内核调度需要在编码阶段完成的问题。OpenCL上下文属性包含两个参数,分别对应了两种全局调度策略:循环调度(ROUND_ROBIN)和自适应调度(AUTO_FIT)。循环调度是在触发调度程序时,将命令队列调度到下一个可用设备上,在实际运行过程中,由于GPU设备支持多内核同时执行,该方案调度时选择计算资源充足的设备进行调度,这种方法会有最小的调度开销,但是并不总是选择最佳的队列-设备映射。自动调度策略是MultiCL框架提出的基于内核预执行的动态调度策略,MultiCL框架将根据动态调度策略选择最佳的队列-设备映射。

同时为了实现本地调度策略,对OpenCL API命令调度队列属性进行了扩展,添加了SCHED_AUTO__或SCHED_OFF,分别确定特定的队列是选择自动调度模式还是手动调度模式。MultiCL框架给用户提供了选项,用户可以选用SCHED_OFF标志手动指定调度方案,用户也可以在创建命令队列时添加SCHED_AUTO__标志来实现自动调度,其中包括静态调度(SCHED_AUTO_STATIC)和动态调度(SCHED_AUTO_DYNAMIC)。针对命令队列属性的修改旨在作为调度的微调参数,针对不同程度的OpenCL开发人员,制定了不同程度的调度策略。对于具有丰富经验的开发人员,可以直接忽略MultiCL框架提供的命令队列参数,选择手动调度所有队列,便于开发人员根据异构系统底层特点实现任务划分和内核优化,对于中等级别的开发人员,对底层架构有一定了解,可根据OpenCL内核的负载类型(例如:SCHED_IO_BOUND, SCHED_COMPUTE_BOUND等)选择命令队列属性作为系统的调度提示,便于MultiCL框架根据OpenCL内核类型提示构建微型内核和进行调度,对于初级开发人员,则可以采用MultiCL框架提供的自适应动态调度,由MultiCL运行时决定内核调度方案,该方式会带来一定的运行时开销。

MultiCL扩展的clSetCommandQueueSchedProperty命令用于标记调度程序区域,并可以在需要时设置更多调度程序标志,例如使用以下属性:SCHED_COMPUTE_BOUND,SCHED_MEM_BOUND,SCHED_IO_BOUND或SCHED_ITERATIVE指定队列中的预期计算类型,与clCreateCommandQueue的扩展参数相对应,该函数便于调度方案优化。OpenCL内核启动命令的参数包括命令队列,内核对象和内核的启动配置。MultiCL为了自动调度的方便,实现了新的OpenCL API命令clSetKernelWorkGroupInfo,用于设定内核配置参数,MultiCL框架在OpenCL内核调度命令加入命令队列前就可以获取内核的工作组和工作组中工作项信息,便于MultiCL框架进行内核调度。

MultiCL运行时设计如图1所示。

使用SCHED_OFF标志创建的用户命令队列将静态映射到所选设备(由开发人员在编码阶段指定映射方案),而使用SCHED_AUTO标志创建的命令队列将由MultiCL自动调度。MultiCL框架将OpenCL内核启动命令加入队列后,如果该命令队列是SCHED_OFF标志创建的命令队列,则采用静态调度方案,MultiCL运行时保留了SunCL运行时静态调度方案的部分,给开发人员保留了静态硬编码调度的功能。如果该命令队列是以SCHED_AUTO标志创建的,则交由自适应调度器映射到设备池中某一设备。上述调度过程包含了设备静态分析(在clGetPlatformIds读取设备信息阶段进行),内核静态分析(clBuildProgram,clCreateProgramWithSource构建程序阶段进行),内核动态分析(clEnqueue*命令阶段)和设备映射。MultiCL动态调度模块通过独立线程与OpenCL程序执行并发执行,利用OpenCL初始化阶段开销隐藏MultiCL运行时内核分析和设备分析带来的开销。

图1 MultiCL运行时结构图

MultiCL动态调度包含三个主要的运行时模块:设备分析器、内核分析器和任务调度器。

  1. 设备分析器,用于收集和分析设备的性能(内存,计算能力和I/O);
  2. 内核分析器,分析和预测内核在不同设备上的执行时间;
  3. 任务调度器,将SCHED_AUTO标记的命令队列中的任务调度到设备上。上述三个运行时模块在MultiCL对OpenCL标准扩展的基础上实现了OpenCL任务的动态调度。设备分析器和内核分析器分别对OpenCL设备和内核进行分析,判断OpenCL设备与内核的契合程度,为任务调度器提供数据基础。

设备分析器是在OpenCL clGetPlatformIds命令调用期间执行的设备概要分析器。设备分析器从设备概要文件中检索OpenCL设备的概要信息。如果文件中不存在该设备的概要信息,则MultiCL运行时将运行数据带宽和指令吞吐量基准测试,并将测得的指标作为静态信息存入设备概要文件中。基准测试源于SHOC基准测试NVIDIA SDK,这些基准测试是MultiCL运行时的一部分。仅当系统配置发生更改时(例如,在系统中添加新设备或从中删除设备)时,才需要再次运行基准测试。

内核分析器通过性能建模或性能预测技术来估计内核执行时间。MultiCL为了减少内核分析器所带来的时间开销,采用每个设备运行一次微型内核,并将相应的执行时间存储为内核配置文件的一部分。该微型内核由微型仿真技术创建,并将其调度到系统中的每一个参与计算的设备上运行,该内核划分单个工作组工作项,并记录该微型内核在每个设备上的相对性能。这种方式会给当前程序带来潜在的运行时开销,但是MultiCL采用的微型内核在运行时优化后,实验验证其运行时开销很小,有时可以忽略不计。同时该方式也能较为准确的反映内核在不同设备上的运行差异。微型内核创建发生在OpenCL clCreateProgramWithSource和clBuildProgram命令期间。MultiCL运行时拦截clCreateProgramWithSource调用,并为每个内核创建一个迷你内核对象,通过拦截clBuildProgram调用,将带有新微型内核的程序构建为单独的二进制文件。尽管此方法使OpenCL的构建时间增加了一倍,但作者认为这是初始设置成本,不会改变程序的实际运行时间。

任务调度器将获取每一个OpenCL命令队列,并将关联的命令队列添加到就绪队列池中进行调度。MultiCL仅通过概要设备信息文件和内核配置文件得到任务映射方案。MultiCL运行时读取每个队列的聚合内核配置文件,任务调度器采用使命令队列内核执行时间最短的策略来确定理想的队列-设备映射,最大限度地减少并发执行时间。动态调度方法保证了理想的内核-设备映射,同时OpenCL平台下的设备数量不多,因此调度产生的开销可以忽略不计。调度程序将命令队列映射到设备后,该队列将从队列池中删除。

3 总结

OpenCL首次提出了面向异构系统通用目的并行编程的开放式标准,适用于跨CPU、GPU和其他处理器的异构混合编程。而MultiCL通过对OpenCL标准的扩展,以在上下文全级别和命令队列本地级别进行静态和动态调度。MultiCL是一个运行时系统,通过设备分析器,内核分析器和任务调度器完成了OpenCL的动态调度,同时保留了OpenCL本身由开发人员指定的静态调度方法,MultiCL运行时优化使开发人员能够专注于应用程序级别的数据和任务分解,而不是设备级别的体系结构详细信息和设备调度,极大减轻了OpenCL开发难度,为以后的任务调度研究提供了良好的软件支持。但是,MultiCL也引入了预执行开销,降低了程序执行效率,同时其预执行评估方案难以反映内核实际运行状态,尚待进一步优化。

作者:京东物流 靳紫薇

来源:京东云开发者社区 自猿其说Tech 转载请注明来源

OpenCL任务调度基础介绍的更多相关文章

  1. Web3D编程入门总结——WebGL与Three.js基础介绍

    /*在这里对这段时间学习的3D编程知识做个总结,以备再次出发.计划分成“webgl与three.js基础介绍”.“面向对象的基础3D场景框架编写”.“模型导入与简单3D游戏编写”三个部分,其他零散知识 ...

  2. C++ 迭代器 基础介绍

    C++ 迭代器 基础介绍 迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围.迭代器就如同一个指针.事实上,C++的指针也是一种迭代器.但是,迭代器不仅仅是指针,因此你不能认为他们一定 ...

  3. Node.js学习笔记(一)基础介绍

    什么是Node.js 官网介绍: Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js us ...

  4. Node.js 基础介绍

    什么是Node.js 官网介绍: Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js us ...

  5. 1、git基础介绍及远程/本地仓库、分支

    1. Git基础介绍 基于Git进行开发时,首先需要将远程仓库代码clone到本地,即为本地仓库.后续大部分时间都是基于本地仓库上的分支进行编码,最后将本地仓库的代码合入远程仓库. 1.1. 远程仓库 ...

  6. git基础介绍

    git基础介绍 这是git操作的基础篇,是以前的写的操作文档,就没有进行手打,直接把图片贴进来了,你们担待哈,有不正确的地方可以指正出来,我将在第一时间去修改,多谢哈! 一.文件状态:git系统的文件 ...

  7. OSPF基础介绍

    OSPF基础介绍 一.RIP的缺陷 1.以跳数评估的路由并非最优路径 2.最大跳数16导致网络尺度小 3.收敛速度慢 4.更新发送全部路由表浪费网络资源 二.OSPF基本原理 1.什么是OSPF a& ...

  8. iOS系统及客户端软件测试的基础介绍

    iOS系统及客户端软件测试的基础介绍 iOS现在的最新版本iOS5是10月12号推出,当前版本是4.3.5 先是硬件部分,采用iOS系统的是iPad,iPhone,iTouch这三种设备,其中iPho ...

  9. 高通camera结构(摄像头基础介绍)

    摄像头基础介绍 一.摄像头结构和工作原理. 拍摄景物通过镜头,将生成的光学图像投射到传感器上,然后光学图像被转换成电信号,电信号再经过模数转换变为数字信号,数字信号经过DSP加工处理,再被送到电脑中进 ...

  10. Erlang基础 -- 介绍 -- Wordcount示例演示

    在前两个blog中,已经说了Erlang的历史.应用场景.特点,这次主要演示一个Wordcount的示例,就是给定一个文本文件,统计这个文本文件中的单词以及该单词出现的次数. 今天和群友们讨论了一个问 ...

随机推荐

  1. DevOps|研发效能治理:进化史、规模化与治理复杂性

    麻广广@码猿外 研发效能这个词近几年火遍全网,各大企业都加入了研发效能治理的行列,开始梳理企业内部各个团队的研发流程,以期望找到企业降本增效的方向. 抛开政治因素,研发效能治理我们到底是在谈什么呢?从 ...

  2. Unity的IPostprocessBuildWithReport:深入解析与实用案例

    Unity IPostprocessBuildWithReport Unity IPostprocessBuildWithReport是Unity引擎中的一个非常有用的功能,它可以让开发者在构建项目后 ...

  3. Redis从入门到放弃(10):分布式锁

    在分布式系统中,实现对共享资源的安全访问是一个关键问题.Redis作为一种高性能的内存数据库,提供了多种方式来实现分布式锁,以解决多个节点之间对共享资源的并发访问问题. 本文将介绍五种Redis分布式 ...

  4. 何时使用MongoDB而不是MySql

    什么是 MySQL 和 MongoDB MySQL 和 MongoDB 是两个可用于存储和管理数据的数据库管理系统.MySQL 是一个关系数据库系统,以结构化表格格式存储数据.相比之下,MongoDB ...

  5. redis开启多线程

    在Redis 6.0中,非常受关注的第一个新特性就是多线程. 在Redis 6.0中,多线程默认是禁用的,只使用主线程.如果需要使用多线程功能,需要在 redis.conf文件中进行配置(重启服务). ...

  6. [FlareOn3]Challenge1

    打开直接f5,发现只有一个可疑函数 进入 base64??? base64解密

  7. Spark入门系列视频教程

     视频目录: Spark入门| 01 Spark概念架构 Spark入门| 02 Spark集群搭建 Spark入门| 03 Spark Shell算子操作 Spark入门| 04 Spark单词计数 ...

  8. Solution -「NOI 2021」轻重边

    Description Link. 给出一棵树,初始边权为 \(0\),支持毛毛虫虫体赋 \(1\),虫足赋 \(0\),以及查询路径边权和操作,\(n,m\leqslant 10^5\). Solu ...

  9. linux安装clickhouse

    linux安装clickhouse 1. 系统要求 ClickHouse可以在任何具有x86_64,AArch64或PowerPC64LE CPU架构的Linux,FreeBSD或Mac OS X上运 ...

  10. 解决SpringBoot3.X中starter配置自动注入失效问题

    在自定义 starter 项目时,如果组件无法被 @ComponentScan 扫描并且想自动注册到 IOC 中,在springboot2.7之前 我们会采用 spring,factories 方式, ...