初探GF-Complete(伽罗瓦运算库)

来源:互联网 发布:淘宝 海外 上传身份证 编辑:程序博客网 时间:2024/05/17 04:00
GF-Complete 是一个开源、综合性的伽罗瓦运算库,相应的文章发表在FAST13 中(见参考文献【1】)。作者是大名鼎鼎的Jim Plank 教授,作为开源纠错码库Jerasure 的开发者,在这个伽罗瓦运算库中创新地采用了SSE 指令集来加速纠错码运算的瓶颈---伽罗瓦运算中的乘法运算,并采用了其他运算方法,综合得到GF-Complete。该库可在Plank 主页中下载得到,下面就GF-Complete 库做简要分析,详细可参考文档【2】。




 
一、文件的组成


GF-Complete 有以下文件:


1. gf_complete.h 是应用程序使用的的头文件,所有的其他源程序将生成各自的 .o 文件,所有的 .o 文件将被打包为gf_complete.a ,供应用程序使用。gf_complete.h 包含了通用的数据类型gf_t (GF(2w) 中所有值得类型)和其他运算接口;


2. gf_general.h 中包含了不同大小w 的伽罗瓦域基础运算,尽力消除不同w 大小带来不同数据类型运算的痛苦。文件gf_wgen.c / gf_w4.c / gf_w16.c / gf_w32.c / gf_w64.c / gf_w128.c 分别对应着w<32 / w=4,8,16,32,64,128 的基础运算(加法,乘法,除法,乘2等);


3. gf_rand.h 和gf_rand.c 是一个随机数生成器;


4. gf_int.h 定义了gf_w** 需要使用的一些初始化函数和其他类型;


 


下面几个文件并不是该库所必须的,主要用于测试和例子:


6. gf_mult.c / gf_div.c  / gf_add.c 分别是域上的单个乘法/除法/加法工具;


7. whats_my_sse.c 是用于查看该机器支持哪些指令集,直接通过gcc 可编译;


2. gf_method.h 和 gf_method.c 是用来帮助用户知道自己可以使用的方法(不同处理器支持的指令集不同);


8. gf_time.c / gf_uint.c / gf_ploy.c 分别用于测试速度,单元测试和域中寻找本原多项式;


9. gf_example_1/2/3/4 分别对应着伽罗瓦域上的单个乘法和除法、一块区域乘以一个常量、w=64 的常用运算,w=128 的常用运算测试;


 
二、gf_time


gf_time 是其中一个最重要的测试速度的工具,命令格式如下:


UNIX>gf_time w tests seed buffer-size iterations method


其中w 是位长,大于零小于等于32,或者为64 和128;seed 是用于随机数的种子;buffer-size 为每次运算的区域的大小,iterations 为循环次数(用于测速);最重要的两个参数是tests 和 method,tests 指测试的选项,有以下几种:
‘M’ 单个乘法计算
‘D’ 单个除法计算
 ‘I’    单个元素转置
‘G’  一个随机常量乘以一块区域
‘0’ 零乘以一块区域(等同于bzero())
‘1’ 一乘以一块区域(等同于memcpy() 和 XOR)
‘2’ 二乘以一块区域,这比一般的乘二运算要快(通过移位实现)
‘S’ 所有三种单个测试‘M’,‘D’,‘I’
‘R’ 所有四个区域测试‘G’,‘0’,‘1’,‘2’
‘A’ 所有七个测试


method 是伽罗瓦域上计算采用的技术(取决于机器支持的指令集,现有的伽罗瓦域运算方法和位长w ),通过gf_method 可以查询到对应机器支持的方法,gf_method 有三部分组成:乘法方法,区域乘法方法和除法方法。


乘法对应有以下方法:
 ‘TABLE’          乘法表
 ‘LOG’              对数表
‘LOG_ZERO’ 类似于对数表
 ‘SHIFT’           通过不可约多项式进行移位乘法,速度很慢,参考【3】
 ‘BYTWO_p’    通过循环乘二并选择性异或被乘数得到乘法结果,可以利用到Anvin 乘二的优化
 ‘BYTWO_b’    同上
 ‘SPLIT’            乘法裂表(比如LR表,或者利用SIMD 的表,详见【1】)分别有wa 和wb 两个参数
 ‘GROUP’         使用左右组合表的方法(参考文献【4】)
 ‘COMPOSITE’在一个组合域上进行运算,GF((2l)k) 在参考文献【3】、【4】有介绍


区域乘法有以下方法:
 ‘-’              使用默认方法
 ‘LAZY’      区域乘法前生成查询表
 ‘SSE’        如果有SSE4 指令集,则使用
‘NOSSE’ 不使用SSE4 指令集
‘SINGLE’ 每次查询一个元素运算的表
‘DOUBLE’每次查询两个元素运算的表
 ‘QUAD’     每次查询四个元素运算的表,‘SINGLE’是一般的查询表,之所以有另外两个表,是为了加速较小w 的运算,达到内存使用和计算的均衡
‘STDMAP’使用标准字位对其,内存块分割为连续的字
‘ALTMAP’非标准字位对其,每个字分割在不同的内存块中
‘CAUCHY’将内存分为w 块且仅进行Cauchy Reed-Solomon 中的异或运算【5】


除法有以下方法选择:
 ‘-’               使用默认方法
‘EUCLID’ 使用欧几里得算法,方法慢,但允许使用乘法进行除法计算
‘MATRIX’  将每个元素转化为w×w 大小的bit-matrix(像在Cauchy Reed-Solomon 中),然后转置该矩阵得到逆元素
三、字长和选项


w = 4:


“BYTWO_b SSE -”是默认的区域运算的一半速度,几乎和乘二一样快,但单个运算慢;


“BYTWO_b NOSSE -”是不使用SSE4 指令最快的区域运算方法;


“TABLE QUAD -”是不使用SSE 指令,基于查询表最快的方法;


w = 8:


默认下速度最快


w = 16:


“SPLIT 16 4 SSE,ALTMAP -”这是w = 16时最快的区域乘法,关于这部分算法可以参考【2】


“BYTWO_b SSE -” 这对于区域乘二是最快的选项,但其他乘法就慢了


w = 32:


“SPLIT 32 4 SSE,ALTMAP -” 和w = 16一样,这个比默认方法要快


“SPLIT 8 8 - -” 单个乘法最好的选择,但要预分配1.75MB 内存


“BYTWO_b SSE -” 乘二非常快


“SPLIT 32 8 - -” 不使用SSE4 指令集最快的区域乘法,不使用1.75MB 内存


“COMPOSITE 2 1 SPLIT 16 4 SSE,ALTMAP - ALTMAP -” 对于较大的w,组合(composite)操作是最好的方法,但对于单个乘法计算不友好


w = 64:


“SPLIT 64 4 SSE,ALTMAP -” 这是最快的区域运算,采用128个不同的查找表,单个运算慢,建议使用默认方法


“COMPOSITE 2 1 SPLIT 32 4 SSE,ALTMAP - ALTMAP -”  区域运算也很快


“BYTWO_b SSE -” 这一直是区域乘二的最快方法


w = 128:


“SPLIT 128 4 - -” 方法尚不完善,这是暂时最快的方法


“BYTWO_b - - ”最快的区域乘二


 
三、源码分析


先看几个 .h头文件(gf_complete.h 包含于gf_general.h 和gf_int.h 中)定义了一些数据结构:


gf_general_t  (gf_general.h)代表伽罗瓦域中元素类型,减少w 不同带来不同数据类型运算的痛苦;
 1: typedef union { 


 2: uint32_t w32; 


 3: uint64_t w64; 


 4: uint64_t w128[2]; 


 5: } gf_general_t; 




 


gf_internal_t  (gf_int.h)代表伽罗瓦运算,包含了运算指定的类型和参数;
 1: typedef struct { 


 2: int mult_type; 


 3: int region_type; 


 4: int divide_type; 


 5: int w; 


 6: uint64_t prim_poly; 


 7: int free_me; 


 8: int arg1; 


 9: int arg2; 


 10: gf_t *base_gf; 


 11: void *private; 


 12: } gf_internal_t; 




 


gf_region_data  (gf_int.h)代表一块要进行区域乘法计算的内存块;
 1: typedef struct { 


 2: gf_t *gf; 


 3: void *src; 


 4: void *dest; 


 5: int bytes; 


 6: uint64_t val; 


 7: int xor; 


 8: int align; 


 9: void *s_start; 


 10: void *d_start; 


 11: void *s_top; 


 12: void *d_top; 


 13: } gf_region_data; 




 


gf_val_32_t , gf_val_64_t , gf_val_128_t 分别作为w = 32、64、128时伽罗瓦域中的元素类型,是uint32_t,uint64_t 和uint64_t * 的别名。


gf_func_a_b 是两个元素乘法或除法的函数指针,对于不同w 有三种函数指针;


gf_func_a     是一个元素求逆的函数指针


gf_func_region 是一个元素乘以一个区域的函数指针


gf_t  是一个伽罗瓦域运算的结构体,某个gf_t的实例(且允许我这么说)代表了一个伽罗瓦域的运算方法
 1: typedef struct gf { 


 2: gf_func_a_b multiply; 


 3: gf_func_a_b divide; 


 4: gf_func_a inverse; 


 5: gf_region multiply_region; 


 6: gf_extract extract_word; 


 7: void *scratch; 


 8: } gf_t; 




这些结构通过gf_free 释放空间


 但一个应用程序调用这些方法时,需要指定参数进行初始化,比如生成查找表等,这些可以通过gf_init_easy() 和gf_init_hard(),前者是后者的一个默认参数的选择,如果手动选择参数调用后者即可。也可以通过提供的create_gf_from_argv(&gf, w, argc, argv, 6) 通过手动输入参数进行初始化。