CN103440229A - 一种基于mic架构处理器的向量化优化方法 - Google Patents
一种基于mic架构处理器的向量化优化方法 Download PDFInfo
- Publication number
- CN103440229A CN103440229A CN2013103496288A CN201310349628A CN103440229A CN 103440229 A CN103440229 A CN 103440229A CN 2013103496288 A CN2013103496288 A CN 2013103496288A CN 201310349628 A CN201310349628 A CN 201310349628A CN 103440229 A CN103440229 A CN 103440229A
- Authority
- CN
- China
- Prior art keywords
- vectorization
- circulation
- compiler
- vector
- simd
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Granted
Links
Images
Landscapes
- Devices For Executing Special Programs (AREA)
Abstract
本发明提供了一种基于MIC架构处理器的向量化优化方法,涉及算法数据依赖关系分析、算法向量化调整优化、向量化编译三个主要步骤,具体内容包括:算法的数据依赖分析、算法的向量化优化调整、编译器自动向量化技术、用户介入的向量化优化方法等。本发明提供的方法适用于MIC架构处理器平台的软件优化,指导软件开发人员以较短的开发周期,较低的开发成本,快速高效地对现有软件,尤其是核心算法进行向量优化改造,实现软件对向量处理器计算资源利用的最大化,最大限度地缩短软件运行时间,显著提高硬件资源利用率,提高软件的计算效率和软件整体性能。
Description
技术领域
本发明涉及计算机高性能计算领域、科学计算领域,具体涉及一种基于MIC架构处理器的向量化优化方法。
背景技术
自从1996年Intel在奔腾处理器上集成了MMX后,越来越多的通用处理器上集成了SIMD(Single Instruction Multiple Data,单指令多数据流)硬件扩展,这种集成了SIMD处理架构的处理器,称为向量处理器。向量处理器的应用也越来越广泛,从最初的多媒体应用扩展到各个应用领域,尤其在高性能计算领域,海量数据、大规模并行处理需求,对处理器的计算能力提出严峻挑战,向量化的并行处理,能有效提高并行处理效率和计算密度,提高硬件资源利用率,进而降低计算成本。
新的MIC架构协处理器具备当前最宽的向量宽度,它构建在至强处理器的并行架构之上,通过集成众多低功耗内核,每一个处理器核具备一个512位的SIMD处理单元和很多新的向量运算指令,MIC架构处理器创造了在一个芯片上的超级计算机,超过每秒一万亿次的计算能力。
随着MIC架构处理器的推广,其强大的SIMD扩展技术将被广泛应用,不仅为高性能计算提供了新的解决问题、提升性能的途径,也带来了一个新的问题——如何快速、高效地实现可靠的向量化并行处理,从而充分释放MIC处理器的计算潜力?这是摆在软件工程师面前的现实挑战。
发明内容
本发明的目的是提供一种基于MIC架构处理器的向量化优化方法。
本发明的目的是按以下方式实现的,内容包括:1)对目标循环进行向量化可行性分析;2)向量化优化;3)编译器自动向量化;4)基于向量化编译指示的向量化;5)算法向量化改造;6)向量化正确性验证;通过重复以上迭代调优过程,以实现循环向量化率最大化,其中:
1)对目标循环进行向量化可行性分析,是对需要向量化的循环进行数据依赖分析,排除循环迭代依赖,所谓循环迭代依赖,是指循环间存在前后依赖,导致循环不具有完全独立性,不能并行处理,从而使该循环不能被向量化;
2)向量化优化,是在数据依赖关系的基础上,采用多种方法手段,使循环被向量化处理;
3)编译器自动向量化,是编译器会自动分析循环间的数据依赖关系,并自主决定是否进行循环向量化;
4)基于向量化编译指示的向量化,是基于数据依赖分析结果,通过在相应循环外添加编译指示语句,指导编译器对该循环进行向量化编译;
5)算法向量化改造,是基于数据依赖分析结果,对算法/循环进行优化改造,包括数据结构调整、循环拆分、循环合并、循环嵌套顺序调整;
6)向量化正确性验证,是验证向量化的正确性,体现在输出结果正确,误差在可以接受的范围内,具体实施步骤、方法细则如下:
1) 循环向量化可行性分析:
编译器自动向量化过程中,可能收到某个循环无法被向量化的编译信息报告,很多时候无法向量化的原因都是循环间存在着变量依赖关系,通过阅读源代码,理解算法,必要时进行测试,确认代码中各循环结构间的数据依赖关系,进行数据依赖关系分析,是为了下一步对循环进行优化调整、并且介入编译器向量化编译行为;
向量化处理的实质,就是将原本串行循环处理的计算任务,转换成若干循环同时处理的方式,因此,各次循环之间不能有前后的数据依赖关系,在实际操作中,编译器通过设置私有变量、添加原子阻塞操作,实现广义的向量化,这取决于向量化处理器硬件的设计及其所支持的指令集的设计,因此,循环可向量化的必要条件是:
a) 循环之间不存在依赖关系,也就是说,所有的循环能同时执行且互不干扰;
b) 必须是内层循环,在一个嵌套的循环中,向量器只能尝试向量化最内层的循环,查看向量器的输出信息能知道循环是否被向量化以及原因,如果影响性能的关键循环没有向量化,需要做一些算法调整,比如调整嵌套循环的顺序;
另外,除了具备以上必要条件外,还要注意以下几点:
(a)向量化处理的数据类型尽量一致,需要向量化处理的语句,其包含的变量尽可能做到长度一致,即数据类型尽可能一致,尽量避免在同一表达式中同时出现单精度和双精度变量;
(b)向量化语句中尽可能避免函数调用:表达式中调用函数,会增加语句的复杂度,干扰编译器实施自动向量化,即使是标准的数学函数,也要尽量避免,如果一定要使用,也要尽可能使函数精度与变量精度一致;
2) 向量化优化,采用以下方法,实现循环的向量化处理;
a) 编译器自动向量化
编译器自动向量化依赖于编译器自身的能力来消除内存引用二义性,Intel C/C++编译器默认向量化编译选项为-vec,即默认情况下向量化是打开的,若关闭向量化,在编译选项中添加-no-vec,编译器在对源代码进行编译时,会输出编译信息/报告,某些编译器有多个编译信息输出级别,其编译信息输出级别可使用-vec-report level控制,通过编译器输出的编译信息报告,以了解编译的详细细节,包括某个循环是否被向量化,向量化失败的原因,这些信息能为向量优化提供依据和指导;
b) 基于向量化编译指示的向量化
向量化编译指示,能更好地指导编译器进行数据依赖分析,从而更好地向量化代码,包括
__declspec(align(n)) 声明能够使编译器克服硬件对齐的限制,restrict修饰词和自动向量化提示解决了由于作用范围、数据依赖和二义性等产生的问题,SIMD编译指示使得最内层的循环被强制向量化,使用向量化编译指令是有风险的,使用的前提条件是程序员必须确保不存在数据依赖;其中SIMD 编译指示有五个可供选择的子句来指导编译器执行何种向量化,恰当地使用这些子句,会让编译器获得足够的信息来产生正确的向量化代码,其中:
(1)vectorlength(num1, num2, …, numN)
指导向量优化单元可以从指定的若干向量长度(VL)num1, num2, … , numN 中选择来向量化循环,对于选定的VL,向量循环的每一次执行的计算工作相当于原来标量循环VL 次执行的计算工作,多个向量长度子句会合并成一个集合;
(2)private(expr1, expr2, …, exprN)
指导向量优化单元使得这些左值(L-value)表达式expr1, exper2, ..., exprN 对于每一次循环都是私有的,多个private 子句会合并成一个集合,左值表达式的初值将被广播到所有的私有子句,除非编译器能够判定初值未在循环体内使用;左值表达式的终值也会被从最后一次执行的循环体复制出来, 除非编译器能够判定终值未在循环后被使用;
(3)linear(var1:step1, var2:step2, …, varN:stepN)
指导编译器每一次标量循环的执行时,var1 的值增加step1, var2 的值增加step2, 依此类推,相应地,每次向量循环的执行,使得这些变量的值分别增加VL*step1,VL*step2, …, VL*stepN,多个linear 子句会被合并成一个集合,如果var 被赋予两个或多个step 值,会产生一个编译错误;
(4)reduction(oper:var1,var2,…,varN)
指导编译器对于变量var1, var2, …, varN 执行向量化规约操作oper,一个SIMD 编译指示有多个归约子句,执行相同或者不同的操作,如果一个变量var 与两个或多个不同的归约操作oper 有关, 会产生一个编译错误;
(5) [no]assert
指导编译器当向量化失败时是否报错,缺省是不报错的,一个SIMD 编译指令不应该存在多个该子句,否则会产生一个编译错误,为了向量化一个包含潜在依赖关系的循环,用户经过数据依赖分析后,确认其不存在循环间数据依赖,可加上#pragma ivdep提示编译器忽略存在的数据依赖关系;
当向量化以上代码段中的循环时,编译器会认为该循环存在循环间依赖,即第j次循环依赖第j+k次循环的结果,这种依赖关系称为交叉迭代依赖,而如果确定k>16,超过MIC VPU的向量处理宽度,循环间就不存在实际意义上的数据依赖,加上#pragma ivdep指示编译器忽略数据的依赖关系并尝试进行向量化,甚至使用#pragma simd强制向量化该循环,如果L<k<16,那么使用#pragma simd vectorlength(L)强制向量化该循环,并且能保证结果的正确性;
3) 算法向量化改造
如果采用以上两种向量化方式,还有部分循环无法实现向量化,在数据依赖分析的基础上,对算法进行深度优化改进,向量化改造方法有:
a) 调整嵌套循环的顺序
b) 自动向量化只能对嵌套中的最内层的循环进行向量化,然而内层循环向量化效果未必最好,通过调整嵌套循环的顺序达到更好的向量化效果,如调整之后的向量化能实现更好的连续访问;
c) 拆分循环
在某些情况下,除了最内层的循环比较耗时外,其它不在最内层循环的代码也比较耗时,而这部分代码是无法自动向量化的,为此,采取拆分循环的方法实现更多的自动向量化,通过对循环的拆分,能使更多的代码自动向量化,获取更好的向量化性能;
d) 手写SIMD指令向量化
第一代Intel MIC产品为KNC(Knights Corner),Knights Corner Instructions是KNC支持的SIMD指令的总称,是类似于SSE、AVX的指令集,通过使用Knights Corner指令,能细粒度地控制向量化运算;
Knights Corner Instructions分类:
(1)Knights Corner指令Knights Corner instruction是指具体的SIMD指令,是汇编指令集中关于SIMD的子集;
(2)内建Knights Corner(Intrinsics of Knights Corner)是对Knights Corner指令的封装,几乎涉及到所有指令,认为这些函数和数据类型是C/C++的内建类型;
Knights Corner类库Knights Corner Class Libraries是为了方便使用Knights Corner指令而做的封装,让程序员尽量简单地使用SIMD指令,介于引语方式和SIMD代码之间;其支持整型和浮点型数据;
4) 向量化正确性验证
编译源代码,然后运行程序,检查程序的输出结果,验证向量化的正确性,向量化可能会带来精度损失,必要时通过编译器的-fp-model选项,调整向量化的精度;
5) 迭代调优
重复以上过程,以实现循环向量化率最大化,从而使MIC处理器VPU的计算性能尽可能发挥出来;
6)性能测试及分析,包括:
(1)测试环境
平台 | Inspur NF5280M3 |
CPU | Intel Xeon CPU E5675 3.07GHz,双路8核 |
Memory | DDR3 1333MHz 128GB |
MIC | KNC,60核,1.0GHz,GDDR5 8GB memory5.5GT/s |
OS | Red Hat Enterprise Linux Server release 6.1,64bit |
编译器 | icc |
测试用例 | 4096*4096矩阵乘法 |
(2)性能测试结果
程序版本 | 版本说明 | 时间(s) |
P_baseline | CPU单线程基准版 | 312.83 |
P_OMP | CPU多线程+自动向量化版 | 170.83 |
P_MIC_base | MIC多线程+自动向量化版 | 174 |
P_baseline_vec | CPU单线程+算法向量化改造+向量化指示版 | 25 |
P_OMP_vec | CPU多线程+算法向量化改造+向量化指示版 | 4.53 |
P_MIC_vec | MIC多线程+算法向量化改造+向量化指示版 | 3.43 |
P_MIC_simd | MIC多线程+算法向量化改造+向量化指示+simd指令版 | 2 |
(3)性能测试结果分析
利用该方法对矩阵乘法应用案例进行向量化改造后,显著地提升了该模块的运行效率,获得了较高的性能加速比。
编译过程中所使用的编译器,是支持MIC架构及其指令集的任意编译器,该编译器生成的目标代码,直接或通过后续编译处理后,能够运行于MIC架构处理器。
本发明的有益效果是:该方法广泛适用于MIC架构处理器并行处理的应用场合,指导软件开发人员以较短的开发周期,较低的开发成本,快速高效地对现有软件进行向量化优化改造,实现软件对系统资源利用最优化,显著提高硬件资源利用率和软件的计算效率,从而大大提升软件整体性能。
附图说明
图1是单精度浮点数据向量化处理示意图;
图2是向量化的层次结构示意图。
具体实施方式
参照说明书附图对本发明的方法作以下详细地说明。
本发明提供了一种基于MIC架构处理器的向量化优化方法。其主要内容是提供一种利用MIC架构协处理器计算设备,最大化提高MIC硬件资源利用率,从而提升MIC处理器平台上软件运行效能的方法。该方法提出,基于MIC架构处理器的向量化优化流程如下:
1) 对目标循环进行向量化可行性分析;
2) 向量化优化
3)编译器自动向量化
4)基于向量化编译指示的向量化
5)算法向量化改造
6)向量化正确性验证。
重复以上过程,迭代调优,以实现循环向量化率最大化。
3、 具体实施方式
本发明的目的在于提供一种基于MIC处理器的向量化优化方法。
为了使本发明的目的、技术方案和优点更加清晰,下面结合附图和实施例,对本发明作以下详细说明。
首先,简要介绍向量化处理原理及MIC处理器的向量处理单元VPU(Vector Process Unit)的架构。MIC处理器核的VPU支持512bit位宽的KCi向量指令,支持16*32bit或8*64bit等多种处理模式,即向量化宽度为8或16。512位相当于16个单精度浮点型数据的长度,单精度浮点数据向量化处理示意图如图1所示:
例如向量加操作C[0~15]=A[0~15]+B[0~15](A、B、C均为float型数据),没有使用向量化时这个操作需要16次加运算,而向量化之后,把A、B、C放到向量寄存器中,进行一次向量加操作即可完成原来的16次加操作,因此,向量化可以大大提高计算速度。
以下说明都基于intel的编译器和C语言进行阐述。
一种基于MIC架构处理器的向量化优化实施步骤、方法细则如下:
6) 循环向量化可行性分析。
编译器自动向量化过程中,可能收到某个循环无法被向量化的编译信息报告。很多时候无法向量化的原因都是循环间存在着变量依赖关系。
通过阅读源代码,理解算法,必要时进行测试,确认代码中各循环结构间的数据依赖关系。进行数据依赖关系分析,是为了下一步对循环进行优化调整、并且介入编译器向量化编译行为。
向量化处理的实质,就是将原本串行循环处理的计算任务,转换成若干循环同时处理的方式,因此,原理上,各次循环之间不能有前后的数据依赖关系。当然,在实际操作中,编译器可以通过设置私有变量、添加原子阻塞操作等方式,实现广义的向量化,这取决于向量化处理器硬件的设计及其所支持的指令集的设计。
因此,循环可向量化的必要条件是:
a) 循环之间不存在依赖关系。
也就是说,所有的循环能同时 执行且互不干扰。例如:
等价于下面的操作:
因此,这个循环是可以被向量化的。
再看一个例子:
无论如何,这个循环是不能被向量化的,因为a[i]在每次迭代中都依赖前一次迭代的结果。我们称这是一个交叉迭代的数据依赖或者“flow dependence”,这样的循环不能被编译器向量化。
b) 必须是内层循环。
在一个嵌套的循环中,向量器只能尝试向量化最内层的循环,查看向量器的输出信息可以知道循环是否被向量化以及原因,如果影响性能的关键循环没有向量化,你可能需要做一些算法调整,比如调整嵌套循环的顺序。
另外,除了具备以上必要条件外,还要注意以下几点:
a) 向量化处理的数据类型尽量一致
需要向量化处理的语句,其包含的变量尽可能做到长度一致,即数据类型尽可能一致。如,尽量避免在同一表达式中同时出现单精度和双精度变量。
7) 向量化语句中尽可能避免函数调用:表达式中调用函数,会增加语句的复杂度,干扰编译器实施自动向量化,即使是标准的数学函数,也要尽量避免,如果一定要使用,也要尽可能使函数精度与变量精度一致,如:
8) 向量化优化
采用以下多种方法,实现循环的向量化处理。
a) 编译器自动向量化
编译器自动向量化依赖于编译器自身的能力来消除内存引用二义性。Intel C/C++编译器,默认向量化编译选项为-vec,即默认情况下向量化是打开的,若关闭向量化可以在编译选项中添加-no-vec。编译器在对源代码进行编译时,会输出编译信息/报告,某些编译器有多个编译信息输出级别,其编译信息输出级别可使用-vec-report level控制,见下表:
-vec-report[level] | 含义 |
0 | 不显示诊断信息。 |
1 | 只显示已向量化的循环(默认值)。 |
2 | 显示已向量化和未向量化的循环。 |
3 | 显示已向量化和未向量化的循环以及数据依赖信息。 |
4 | 只显示未向量化的循环。 |
5 | 显示未向量化的循环以及数据依赖信息。 |
通过编译器输出的编译信息报告,可以了解编译的详细细节,比如某个循环是否被向量化,向量化失败的原因等,这些信息可以为向量优化提供依据和指导。
b) 基于向量化编译指示的向量化
向量化编译指示,可以更好地指导编译器进行数据依赖分析,从而更好地向量化代码。
例如__declspec(align(n)) 声明能够使编译器克服硬件对齐的限制。restrict修饰词和自动向量化提示解决了由于作用范围、数据依赖和二义性等产生的问题。SIMD编译指示使得最内层的循环被强制向量化。使用向量化编译指令是有风险的,使用的前提条件是程序员必须确保不存在数据依赖。
Intel编译器向量化编译指示如下表:
其中SIMD 编译指示有五个可供选择的子句来指导编译器执行何种向量化。恰当地使用这些子句,会让编译器获得足够的信息来产生正确的向量化代码。
(6) vectorlength(num1, num2, …, numN)
指导向量优化单元可以从指定的若干向量长度(VL)num1, num2, … , numN 中选择来向量化循环。对于选定的VL,向量循环的每一次执行的计算工作相当于原来标量循环VL 次执行的计算工作。多个向量长度子句会合并成一个集合。
(7)private(expr1, expr2, …, exprN)
指导向量优化单元使得这些左值(L-value)表达式expr1, exper2, ..., exprN 对于每一次循环都是私有的。多个private 子句会合并成一个集合。左值表达式的初值将被广播到所有的私有子句,除非编译器能够判定初值未在循环体内使用;左值表达式的终值也会被从最后一次执行的循环体复制出来, 除非编译器能够判定终值未在循环后被使用。
(8)linear(var1:step1, var2:step2, …, varN:stepN)
指导编译器每一次标量循环的执行时,var1 的值增加step1, var2 的值增加step2, 依此类推。相应地,每次向量循环的执行,使得这些变量的值分别增加VL*step1,
VL*step2, …, VL*stepN。多个linear 子句会被合并成一个集合。如果var 被赋予两个或多个step 值,会产生一个编译错误。
(9)reduction(oper:var1,var2,…,varN)
指导编译器对于变量var1, var2, …, varN 执行向量化规约操作oper。一个SIMD 编译指示可以有多个归约子句,执行相同或者不同的操作。如果一个变量var 与两个或多个不同的归约操作oper 有关, 会产生一个编译错误。
(10)[no]assert
指导编译器当向量化失败时是否报错,缺省是不报错。一个SIMD 编译指令不应该存在多个该子句,否则会产生一个编译错误。
下面,列举一个典型实例说明基于向量化编译指示的向量化。为了向量化一个包含潜在依赖关系的循环,用户经过数据依赖分析后,确认其不存在循环间数据依赖,可加上#pragma ivdep提示编译器忽略存在的数据依赖关系,示例程序片段如下:
当向量化以上代码段中的循环时,编译器会认为该循环存在循环间依赖,即第j次循环依赖第j+k次循环的结果,这种依赖关系称为交叉迭代依赖。而如果我们确定k>16,超过MIC VPU的向量处理宽度,循环间就不存在实际意义上的数据依赖,加上#pragma ivdep指示编译器忽略数据的依赖关系并尝试进行向量化,甚至可以使用#pragma simd强制向量化该循环。如果L<k<16,那么可以使用#pragma simd vectorlength(L)强制向量化该循环,并且能保证结果的正确性。
9) 算法向量化改造
如果采用以上两种向量化方式,还有部分循环无法实现向量化,可以在数据依赖分析的基础上,对算法进行深度优化改进。主要的向量化改造方法有:
a) 调整嵌套循环的顺序
自动向量化只能对嵌套中的最内层的循环进行向量化,然而内层循环向量化效果未必最好,我们可以通过调整嵌套循环的顺序达到更好的向量化效果,如调整之后的向量化可以实现更好的连续访问,如下面的代码所示,B代码的向量化效果比A的好。
c) 拆分循环
在某些情况下,除了最内层的循环比较耗时外,其它不在最内层循环的代码也比较耗时,而这部分代码是无法自动向量化的,为此,我们可以采取拆分循环的方法实现更多的自动向量化,下面通过一段伪代码说明其使用方法。
假设上面的代码中循环无数据依赖,由于rand函数无法向量化,从而导致整个循环无法向量化,我们可以把一个循环拆成两个循环的方法达到第二个for循环(主要耗时的)实现向量化的目的,代码如下:
假设上面的代码中两层循环均无数据依赖,除了内层循环for(j=0; j<M; j++)比较耗时,对于s的求解也很耗时,然而求解s的部分是无法自动向量化的。我们可以通过拆分外层的循环做到更好地自动向量化效果,修改后的伪代码如下:
d) 手写SIMD指令向量化
向量化的层次如下图所示,越往上的级别,使用的语言越低级,编程越复杂,但控制的灵活性越好,理论上性能也越高。相反的,越往下的级别,编程越容易,但性能可能不是最理想。
第一代Intel MIC产品为KNC(Knights Corner),Knights Corner Instructions是KNC支持的SIMD指令的总称。可以看作是类似于SSE、AVX等的指令集。通过使用Knights Corner指令,可以细粒度地控制向量化运算。
Knights Corner Instructions分类:
(3) Knights Corner指令(Knights Corner instruction)是指具体的SIMD指令,是汇编指令集中关于SIMD的子集。
(4) 内建Knights Corner(Intrinsics of Knights Corner)是对Knights Corner指令的封装(几乎涉及到所有指令),可以认为这些函数和数据类型是C/C++的内建类型。
(5) Knights Corner类库(Knights Corner Class Libraries)是为了方便使用Knights Corner指令而做的封装,可以让程序员尽量简单地使用SIMD指令,介于引语方式和SIMD代码之间。其支持整型和浮点型数据。
下面通过单精度浮点向量加的例子说明三者的区别:
通过上面的例子可以看出使用类库的方式非常简单,能够以最类似于标量的方式(把数组看成变量),进行向量化改造。而直接使用内建Knights Corner则更接近常规的思维方式,将两个数组通过向量化函数进行运算,当然,其代码要比使用类库方式复杂一些,但由于减少了封装和调用,因此性能也会略有提高。而内联汇编则是最难阅读的,由于最贴近底层,因而执行效率也最高,只是编程的成本也是最高的。在实际的SIMD指令编写中,我们一般采用内建Knights Corner的方式。
下面我们通过一个向量加的示例说明SIMD指令的使用方法。
10) 向量化正确性验证。
编译源代码,然后运行程序,检查程序的输出结果,验证向量化的正确性。
向量化可能会带来精度损失,必要时可以通过编译器的-fp-model选项,调整向量化的精度。
11) 迭代调优。
重复以上过程,以实现循环向量化率最大化,从而使MIC处理器VPU的计算性能尽可能发挥出来。
4、性能测试及分析
将该方法应用于一个典型的高性能运算案例——矩阵乘法。
1) 测试环境
平台 | Inspur NF5280M3 |
CPU | Intel Xeon CPU E5675 3.07GHz,双路8核 |
Memory | DDR3 1333MHz 128GB |
MIC | KNC,60核,1.0GHz,GDDR5 8GB memory5.5GT/s |
OS | Red Hat Enterprise Linux Server release 6.1,64bit |
编译器 | icc |
测试用例 | 4096*4096矩阵乘法 |
2) 性能测试结果
程序版本 | 版本说明 | 时间(s) |
P_baseline | CPU单线程基准版 | 312.83 |
P_OMP | CPU多线程+自动向量化版 | 170.83 |
P_MIC_base | MIC多线程+自动向量化版 | 174 |
P_baseline_vec | CPU单线程+算法向量化改造+向量化指示版 | 25 |
P_OMP_vec | CPU多线程+算法向量化改造+向量化指示版 | 4.53 |
P_MIC_vec | MIC多线程+算法向量化改造+向量化指示版 | 3.43 |
P_MIC_simd | MIC多线程+算法向量化改造+向量化指示+simd指令版 | 2 |
3) 性能测试结果分析
利用该方法对矩阵乘法应用案例进行向量化改造后,显著地提升了该模块的运行效率,获得了较高的性能加速比。
5、总结
由本发明的技术方案可见,本发明提供了一种基于MIC架构处理器的向量化优化方法,该方法广泛适用于MIC架构处理器并行处理的应用场合,指导软件开发人员以较短的开发周期,较低的开发成本,快速高效地对现有软件进行向量化优化改造,实现软件对系统资源利用最优化,显著提高硬件资源利用率和软件的计算效率,从而大大提升软件整体性能。
除说明书所述的技术特征外,均为本专业技术人员的已知技术。
Claims (2)
1.一种基于MIC架构处理器的向量化优化方法,其特征在于,内容包括:1)对目标循环进行向量化可行性分析;2)向量化优化;3)编译器自动向量化;4)基于向量化编译指示的向量化;5)算法向量化改造;6)向量化正确性验证;通过重复以上迭代调优过程,以实现循环向量化率最大化,其中:
1)对目标循环进行向量化可行性分析,是对需要向量化的循环进行数据依赖分析,排除循环迭代依赖,所谓循环迭代依赖,是指循环间存在前后依赖,导致循环不具有完全独立性,不能并行处理,从而使该循环不能被向量化;
2)向量化优化,是在数据依赖关系的基础上,采用多种方法手段,使循环被向量化处理;
3)编译器自动向量化,是编译器会自动分析循环间的数据依赖关系,并自主决定是否进行循环向量化;
4)基于向量化编译指示的向量化,是基于数据依赖分析结果,通过在相应循环外添加编译指示语句,指导编译器对该循环进行向量化编译;
5)算法向量化改造,是基于数据依赖分析结果,对算法/循环进行优化改造,包括数据结构调整、循环拆分、循环合并、循环嵌套顺序调整;
6)向量化正确性验证,是验证向量化的正确性,体现在输出结果正确,误差在可以接受的范围内,具体实施步骤、方法细则如下:
1)循环向量化可行性分析:
编译器自动向量化过程中,可能收到某个循环无法被向量化的编译信息报告,很多时候无法向量化的原因都是循环间存在着变量依赖关系,通过阅读源代码,理解算法,必要时进行测试,确认代码中各循环结构间的数据依赖关系,进行数据依赖关系分析,是为了下一步对循环进行优化调整、并且介入编译器向量化编译行为;
向量化处理的实质,就是将原本串行循环处理的计算任务,转换成若干循环同时处理的方式,因此,各次循环之间不能有前后的数据依赖关系,在实际操作中,编译器通过设置私有变量、添加原子阻塞操作,实现广义的向量化,这取决于向量化处理器硬件的设计及其所支持的指令集的设计,因此,循环可向量化的必要条件是:
a)循环之间不存在依赖关系,也就是说,所有的循环能同时执行且互不干扰;
b)必须是内层循环,在一个嵌套的循环中,向量器只能尝试向量化最内层的循环,查看向量器的输出信息能知道循环是否被向量化以及原因,如果影响性能的关键循环没有向量化,需要做一些算法调整,比如调整嵌套循环的顺序;
另外,除了具备以上必要条件外,还要注意以下几点:
(a)向量化处理的数据类型尽量一致,需要向量化处理的语句,其包含的变量尽可能做到长度一致,即数据类型尽可能一致,尽量避免在同一表达式中同时出现单精度和双精度变量;
(b)向量化语句中尽可能避免函数调用:表达式中调用函数,会增加语句的复杂度,干扰编译器实施自动向量化,即使是标准的数学函数,也要尽量避免,如果一定要使用,也要尽可能使函数精度与变量精度一致;
2)向量化优化,采用以下方法,实现循环的向量化处理;
a)编译器自动向量化
编译器自动向量化依赖于编译器自身的能力来消除内存引用二义性,Intel C/C++编译器默认向量化编译选项为-vec,即默认情况下向量化是打开的,若关闭向量化,在编译选项中添加-no-vec,编译器在对源代码进行编译时,会输出编译信息/报告,某些编译器有多个编译信息输出级别,其编译信息输出级别可使用-vec-report level控制,通过编译器输出的编译信息报告,以了解编译的详细细节,包括某个循环是否被向量化,向量化失败的原因,这些信息能为向量优化提供依据和指导;
b)基于向量化编译指示的向量化
向量化编译指示,能更好地指导编译器进行数据依赖分析,从而更好地向量化代码,包括
__declspec(align(n)) 声明能够使编译器克服硬件对齐的限制,restrict修饰词和自动向量化提示解决了由于作用范围、数据依赖和二义性等产生的问题,SIMD编译指示使得最内层的循环被强制向量化,使用向量化编译指令是有风险的,使用的前提条件是程序员必须确保不存在数据依赖;其中SIMD 编译指示有五个可供选择的子句来指导编译器执行何种向量化,恰当地使用这些子句,会让编译器获得足够的信息来产生正确的向量化代码,其中:
(1)vectorlength(num1, num2, …, numN)
指导向量优化单元可以从指定的若干向量长度(VL)num1, num2, … , numN 中选择来向量化循环,对于选定的VL,向量循环的每一次执行的计算工作相当于原来标量循环VL 次执行的计算工作,多个向量长度子句会合并成一个集合;
(2)private(expr1, expr2, …, exprN)
指导向量优化单元使得这些左值(L-value)表达式expr1, exper2, ..., exprN 对于每一次循环都是私有的,多个private 子句会合并成一个集合,左值表达式的初值将被广播到所有的私有子句,除非编译器能够判定初值未在循环体内使用;左值表达式的终值也会被从最后一次执行的循环体复制出来, 除非编译器能够判定终值未在循环后被使用;
(3)linear(var1:step1, var2:step2, …, varN:stepN)
指导编译器每一次标量循环的执行时,var1 的值增加step1, var2 的值增加step2, 依此类推,相应地,每次向量循环的执行,使得这些变量的值分别增加VL*step1,VL*step2, …, VL*stepN,多个linear 子句会被合并成一个集合,如果var 被赋予两个或多个step 值,会产生一个编译错误;
(4)reduction(oper:var1,var2,…,varN)
指导编译器对于变量var1, var2, …, varN 执行向量化规约操作oper,一个SIMD 编译指示有多个归约子句,执行相同或者不同的操作,如果一个变量var 与两个或多个不同的归约操作oper 有关, 会产生一个编译错误;
(5)[no]assert
指导编译器当向量化失败时是否报错,缺省是不报错的,一个SIMD 编译指令不应该存在多个该子句,否则会产生一个编译错误,为了向量化一个包含潜在依赖关系的循环,用户经过数据依赖分析后,确认其不存在循环间数据依赖,可加上#pragma ivdep提示编译器忽略存在的数据依赖关系;
当向量化以上代码段中的循环时,编译器会认为该循环存在循环间依赖,即第j次循环依赖第j+k次循环的结果,这种依赖关系称为交叉迭代依赖,而如果确定k>16,超过MIC VPU的向量处理宽度,循环间就不存在实际意义上的数据依赖,加上#pragma ivdep指示编译器忽略数据的依赖关系并尝试进行向量化,甚至使用#pragma simd强制向量化该循环,如果L<k<16,那么使用#pragma simd vectorlength(L)强制向量化该循环,并且能保证结果的正确性;
3)算法向量化改造
如果采用以上两种向量化方式,还有部分循环无法实现向量化,在数据依赖分析的基础上,对算法进行深度优化改进,向量化改造方法有:
a)调整嵌套循环的顺序;
b)自动向量化只能对嵌套中的最内层的循环进行向量化,然而内层循环向量化效果未必最好,通过调整嵌套循环的顺序达到更好的向量化效果,如调整之后的向量化能实现更好的连续访问;
c)拆分循环
在某些情况下,除了最内层的循环比较耗时外,其它不在最内层循环的代码也比较耗时,而这部分代码是无法自动向量化的,为此,采取拆分循环的方法实现更多的自动向量化,通过对循环的拆分,能使更多的代码自动向量化,获取更好的向量化性能;
d)手写SIMD指令向量化
第一代Intel MIC产品为KNC(Knights Corner),Knights Corner Instructions是KNC支持的SIMD指令的总称,是类似于SSE、AVX的指令集,通过使用Knights Corner指令,能细粒度地控制向量化运算;
Knights Corner Instructions分类:
(1)Knights Corner指令Knights Corner instruction是指具体的SIMD指令,是汇编指令集中关于SIMD的子集;
(2)内建Knights Corner(Intrinsics of Knights Corner)是对Knights Corner指令的封装,几乎涉及到所有指令,认为这些函数和数据类型是C/C++的内建类型;
Knights Corner类库Knights Corner Class Libraries是为了方便使用Knights Corner指令而做的封装,让程序员尽量简单地使用SIMD指令,介于引语方式和SIMD代码之间;其支持整型和浮点型数据;
4)向量化正确性验证
编译源代码,然后运行程序,检查程序的输出结果,验证向量化的正确性,向量化可能会带来精度损失,必要时通过编译器的-fp-model选项,调整向量化的精度;
5)迭代调优
重复以上过程,以实现循环向量化率最大化,从而使MIC处理器VPU的计算性能尽可能发挥出来;
6)性能测试及分析,包括:
(1)测试环境
(2)性能测试结果
(3)性能测试结果分析
利用该方法对矩阵乘法应用案例进行向量化改造后,显著地提升了该MIC模块的运行效率,获得了较高的性能加速比。
2.根据权利要求1所述的方法,其特征在于,编译过程中所使用的编译器,是支持MIC架构及其指令集的任意编译器,该编译器生成的目标代码,直接或通过后续编译处理后,能够运行于MIC架构处理器。
Priority Applications (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN201310349628.8A CN103440229B (zh) | 2013-08-12 | 2013-08-12 | 一种基于mic架构处理器的向量化优化方法 |
Applications Claiming Priority (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN201310349628.8A CN103440229B (zh) | 2013-08-12 | 2013-08-12 | 一种基于mic架构处理器的向量化优化方法 |
Publications (2)
Publication Number | Publication Date |
---|---|
CN103440229A true CN103440229A (zh) | 2013-12-11 |
CN103440229B CN103440229B (zh) | 2017-11-10 |
Family
ID=49693921
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN201310349628.8A Active CN103440229B (zh) | 2013-08-12 | 2013-08-12 | 一种基于mic架构处理器的向量化优化方法 |
Country Status (1)
Country | Link |
---|---|
CN (1) | CN103440229B (zh) |
Cited By (20)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN104112264A (zh) * | 2014-07-15 | 2014-10-22 | 东南大学 | 一种基于局部方差图像增强的优化方法 |
CN104346318A (zh) * | 2014-10-15 | 2015-02-11 | 中国人民解放军国防科学技术大学 | 面向通用多核dsp的矩阵乘加速方法 |
US20150277877A1 (en) * | 2014-03-25 | 2015-10-01 | Nec Laboratories America, Inc. | Compiler optimization for many integrated core processors |
CN105204822A (zh) * | 2015-10-27 | 2015-12-30 | 浪潮(北京)电子信息产业有限公司 | 一种基于mic协处理器的多数据流处理方法 |
CN105242907A (zh) * | 2015-09-10 | 2016-01-13 | 西安交通大学 | Arm二进制代码的neon向量化转换方法 |
WO2016061911A1 (zh) * | 2014-10-20 | 2016-04-28 | 浪潮电子信息产业股份有限公司 | 一种基于mic实现聚类算法的方法及装置 |
CN105808310A (zh) * | 2016-04-01 | 2016-07-27 | 浪潮电子信息产业股份有限公司 | 一种适用于大规模并行软件GTC的核心模块Pushe的高效向量化方法 |
CN106959937A (zh) * | 2017-03-30 | 2017-07-18 | 中国人民解放军国防科学技术大学 | 一种面向gpdsp的反卷积矩阵的向量化实现方法 |
CN107193535A (zh) * | 2017-05-16 | 2017-09-22 | 中国人民解放军信息工程大学 | 基于simd扩展部件的嵌套循环向量并行的实现方法及其装置 |
CN108416056A (zh) * | 2018-03-21 | 2018-08-17 | 哈工大大数据(哈尔滨)智能科技有限公司 | 基于条件包含依赖的相关性学习方法、装置、设备及介质 |
CN110673877A (zh) * | 2019-08-22 | 2020-01-10 | 成都信息工程大学 | 一种基于手动向量化的并行计算方法 |
CN110795106A (zh) * | 2019-10-30 | 2020-02-14 | 中国人民解放军战略支援部队信息工程大学 | 程序向量化过程中动静结合的内存别名分析处理方法及装置 |
CN111428327A (zh) * | 2018-12-24 | 2020-07-17 | 深圳市中兴微电子技术有限公司 | 一种指令硬件架构的构建方法、装置及存储介质 |
CN112947932A (zh) * | 2021-02-24 | 2021-06-11 | 上海商汤智能科技有限公司 | 对编译过程中的向量化进行优化的方法、装置及电子设备 |
CN113704687A (zh) * | 2020-05-21 | 2021-11-26 | 杭州海康威视数字技术股份有限公司 | 一种张量计算运行方法、装置及运算系统 |
CN114489518A (zh) * | 2022-03-28 | 2022-05-13 | 山东大学 | 测序数据质量控制方法及系统 |
CN114637388A (zh) * | 2022-03-18 | 2022-06-17 | 中国科学院计算技术研究所 | 面向数据流处理器的功耗控制方法及装置 |
WO2022126885A1 (en) * | 2020-12-17 | 2022-06-23 | Huawei Technologies Co., Ltd. | Method and apparatus for retaining optimal width vector operations in arbitrary/flexible vector width architecture |
CN115951936A (zh) * | 2023-01-17 | 2023-04-11 | 上海燧原科技有限公司 | 向量化编译程序的芯片适配方法、装置、设备及介质 |
CN117234514A (zh) * | 2023-11-08 | 2023-12-15 | 睿思芯科(深圳)技术有限公司 | 将标量化程序转换为向量化程序的方法、系统及相关设备 |
Citations (4)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US20030076885A1 (en) * | 2001-10-19 | 2003-04-24 | Koninklijke Philips Electronics N.V. | Method and system for skipping decoding of overlaid areas of video |
US20050289529A1 (en) * | 2004-06-24 | 2005-12-29 | Yoav Almog | Method and apparatus to vectorize multiple input instructions |
CN102231118A (zh) * | 2011-07-25 | 2011-11-02 | 中国科学技术大学 | 一种基于龙芯3a向量访存的编译优化方法 |
CN103049245A (zh) * | 2012-10-25 | 2013-04-17 | 浪潮电子信息产业股份有限公司 | 一种基于cpu多核平台的软件性能优化方法 |
-
2013
- 2013-08-12 CN CN201310349628.8A patent/CN103440229B/zh active Active
Patent Citations (4)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US20030076885A1 (en) * | 2001-10-19 | 2003-04-24 | Koninklijke Philips Electronics N.V. | Method and system for skipping decoding of overlaid areas of video |
US20050289529A1 (en) * | 2004-06-24 | 2005-12-29 | Yoav Almog | Method and apparatus to vectorize multiple input instructions |
CN102231118A (zh) * | 2011-07-25 | 2011-11-02 | 中国科学技术大学 | 一种基于龙芯3a向量访存的编译优化方法 |
CN103049245A (zh) * | 2012-10-25 | 2013-04-17 | 浪潮电子信息产业股份有限公司 | 一种基于cpu多核平台的软件性能优化方法 |
Non-Patent Citations (2)
Title |
---|
孟小甫等: "龙芯3A多核处理器系统级性能优化与分析", 《计算机研究与发展》 * |
王寅峰等: "MIC商用并行编程性能优化分析", 《深圳信息职业技术学院学报》 * |
Cited By (31)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
US20150277877A1 (en) * | 2014-03-25 | 2015-10-01 | Nec Laboratories America, Inc. | Compiler optimization for many integrated core processors |
US9471289B2 (en) * | 2014-03-25 | 2016-10-18 | Nec Corporation | Compiler optimization for many integrated core processors |
CN104112264A (zh) * | 2014-07-15 | 2014-10-22 | 东南大学 | 一种基于局部方差图像增强的优化方法 |
CN104346318A (zh) * | 2014-10-15 | 2015-02-11 | 中国人民解放军国防科学技术大学 | 面向通用多核dsp的矩阵乘加速方法 |
CN104346318B (zh) * | 2014-10-15 | 2017-03-15 | 中国人民解放军国防科学技术大学 | 面向通用多核dsp的矩阵乘加速方法 |
WO2016061911A1 (zh) * | 2014-10-20 | 2016-04-28 | 浪潮电子信息产业股份有限公司 | 一种基于mic实现聚类算法的方法及装置 |
CN105242907A (zh) * | 2015-09-10 | 2016-01-13 | 西安交通大学 | Arm二进制代码的neon向量化转换方法 |
CN105242907B (zh) * | 2015-09-10 | 2018-01-19 | 西安交通大学 | Arm二进制代码的neon向量化转换方法 |
CN105204822A (zh) * | 2015-10-27 | 2015-12-30 | 浪潮(北京)电子信息产业有限公司 | 一种基于mic协处理器的多数据流处理方法 |
CN105808310A (zh) * | 2016-04-01 | 2016-07-27 | 浪潮电子信息产业股份有限公司 | 一种适用于大规模并行软件GTC的核心模块Pushe的高效向量化方法 |
CN106959937B (zh) * | 2017-03-30 | 2019-03-29 | 中国人民解放军国防科学技术大学 | 一种面向gpdsp的反卷积矩阵的向量化实现方法 |
CN106959937A (zh) * | 2017-03-30 | 2017-07-18 | 中国人民解放军国防科学技术大学 | 一种面向gpdsp的反卷积矩阵的向量化实现方法 |
CN107193535B (zh) * | 2017-05-16 | 2019-11-08 | 中国人民解放军信息工程大学 | 基于simd扩展部件的嵌套循环向量并行的实现方法及其装置 |
CN107193535A (zh) * | 2017-05-16 | 2017-09-22 | 中国人民解放军信息工程大学 | 基于simd扩展部件的嵌套循环向量并行的实现方法及其装置 |
CN108416056B (zh) * | 2018-03-21 | 2020-12-04 | 哈工大大数据(哈尔滨)智能科技有限公司 | 基于条件包含依赖的相关性学习方法、装置、设备及介质 |
CN108416056A (zh) * | 2018-03-21 | 2018-08-17 | 哈工大大数据(哈尔滨)智能科技有限公司 | 基于条件包含依赖的相关性学习方法、装置、设备及介质 |
CN111428327A (zh) * | 2018-12-24 | 2020-07-17 | 深圳市中兴微电子技术有限公司 | 一种指令硬件架构的构建方法、装置及存储介质 |
CN110673877A (zh) * | 2019-08-22 | 2020-01-10 | 成都信息工程大学 | 一种基于手动向量化的并行计算方法 |
CN110673877B (zh) * | 2019-08-22 | 2020-09-01 | 成都信息工程大学 | 一种基于手动向量化的并行计算方法 |
CN110795106B (zh) * | 2019-10-30 | 2022-10-04 | 中国人民解放军战略支援部队信息工程大学 | 程序向量化过程中动静结合的内存别名分析处理方法及装置 |
CN110795106A (zh) * | 2019-10-30 | 2020-02-14 | 中国人民解放军战略支援部队信息工程大学 | 程序向量化过程中动静结合的内存别名分析处理方法及装置 |
CN113704687A (zh) * | 2020-05-21 | 2021-11-26 | 杭州海康威视数字技术股份有限公司 | 一种张量计算运行方法、装置及运算系统 |
CN113704687B (zh) * | 2020-05-21 | 2024-04-05 | 杭州海康威视数字技术股份有限公司 | 一种张量计算运行方法、装置及运算系统 |
WO2022126885A1 (en) * | 2020-12-17 | 2022-06-23 | Huawei Technologies Co., Ltd. | Method and apparatus for retaining optimal width vector operations in arbitrary/flexible vector width architecture |
US11714619B2 (en) | 2020-12-17 | 2023-08-01 | Huawei Technologies Co., Ltd. | Method and apparatus for retaining optimal width vector operations in arbitrary/flexible vector width architecture |
CN112947932A (zh) * | 2021-02-24 | 2021-06-11 | 上海商汤智能科技有限公司 | 对编译过程中的向量化进行优化的方法、装置及电子设备 |
CN114637388A (zh) * | 2022-03-18 | 2022-06-17 | 中国科学院计算技术研究所 | 面向数据流处理器的功耗控制方法及装置 |
CN114489518A (zh) * | 2022-03-28 | 2022-05-13 | 山东大学 | 测序数据质量控制方法及系统 |
CN115951936A (zh) * | 2023-01-17 | 2023-04-11 | 上海燧原科技有限公司 | 向量化编译程序的芯片适配方法、装置、设备及介质 |
CN117234514A (zh) * | 2023-11-08 | 2023-12-15 | 睿思芯科(深圳)技术有限公司 | 将标量化程序转换为向量化程序的方法、系统及相关设备 |
CN117234514B (zh) * | 2023-11-08 | 2024-02-23 | 睿思芯科(深圳)技术有限公司 | 将标量化程序转换为向量化程序的方法、系统及相关设备 |
Also Published As
Publication number | Publication date |
---|---|
CN103440229B (zh) | 2017-11-10 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
CN103440229A (zh) | 一种基于mic架构处理器的向量化优化方法 | |
Stephens et al. | The ARM scalable vector extension | |
Tang et al. | The pochoir stencil compiler | |
Ansel et al. | Petabricks: A language and compiler for algorithmic choice | |
Rul et al. | An experimental study on performance portability of OpenCL kernels | |
Porpodas et al. | PSLP: Padded SLP automatic vectorization | |
US9009689B2 (en) | Speculative compilation to generate advice messages | |
Deniz et al. | Minime: Pattern-aware multicore benchmark synthesizer | |
Mustafa | A survey of performance tuning techniques and tools for parallel applications | |
Lambert et al. | In-depth optimization with the OpenACC-to-FPGA framework on an Arria 10 FPGA | |
Nobre et al. | Aspect-driven mixed-precision tuning targeting gpus | |
Zhong et al. | Using advanced vector extensions avx-512 for mpi reductions | |
Ashraf et al. | AAP4All: An Adaptive Auto Parallelization of Serial Code for HPC Systems. | |
Christofi et al. | Exploring HPC parallelism with data-driven multithreating | |
Han et al. | Polyhedral-Based Compilation Framework for In-Memory Neural Network Accelerators | |
Custers | Algorithmic species: Classifying program code for parallel computing | |
Akimova et al. | Algorithm of Automatic Parallelization of Generalized Matrix Multiplication | |
Mukunoki et al. | Minimal-precision computing for high-performance, energy-efficient, and reliable computations | |
Cramer et al. | Evaluating the performance of OpenMP offloading on the NEC SX-Aurora TSUBASA vector engine | |
Lupo et al. | Enhancing regional ocean modeling simulation performance with the Xeon Phi architecture | |
Biookaghazadeh et al. | Characterizing Loop Acceleration in Heterogeneous Computing | |
Giacomoni et al. | Toward a toolchain for pipeline parallel programming on CMPs | |
Nobre et al. | Beyond Polyhedral Analysis of OpenStream Programs | |
Gelis et al. | Parallel programming for physicists | |
Zhang | Rendering and Image Processing for Micro Lithography on Xeon Phi Knights Landing Processor |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
C06 | Publication | ||
PB01 | Publication | ||
C10 | Entry into substantive examination | ||
SE01 | Entry into force of request for substantive examination | ||
GR01 | Patent grant | ||
GR01 | Patent grant |