710官方网站在上篇《怎么样抉择纠删码编码引擎》中,那里先容易提炼一下降到实处高质量纠删码引擎的要点

小编介绍: 

小编介绍: 

**小编介绍: **
徐祥曦,七牛云工程师,独立开发了多套高品质纠删码/再生码编码引擎。
柳青滴滴骑行总经理,华中科学和技术高校大学生,琢磨方向为基于纠删码的分布式存储系统。

徐祥曦,七牛云工程师,独立开发了多套高性能纠删码/再生码编码引擎。
柳青(JeanLiu),华中财经大学博士,切磋方向为按照纠删码的分布式存储系统。

徐祥曦,七牛云工程师,独立开发了多套高品质纠删码/再生码编码引擎。
柳青(英文名:姬恩Liu),华中科学技术高校硕士,研究方向为依照纠删码的分布式存储系统。

前言:
乘机数据的存储显示出集中化(以分布式存储系统为根基的云存储系统)和移动化(网络活动终端)的自由化,数据可依赖性愈发引起大家的爱护。集群所承载的数据量大大上涨,但存储介质本身的可信赖性提高却很小,那须求大家必须以越来越经济有效的章程来维持数据安全。

前言:

前言:

副本与纠删码都是由此扩张冗余数据的章程来有限支撑数据在发生局地丢失时,原始数据不发出丢失。但相较于副本,纠删码能以低得多的积存空间代价取得相似的可依赖性。比如
3 副本下,存储开支为 3,因为同一的多少被积存了三份,而在
10+3(将原有数据分为 10 份,统计 3 份冗余)的纠删码策略下,存储用度为为
1.3。选取纠删码可以大幅度地缩减存储系统的贮存费用,裁减硬件、运维和管理资产,正是这么伟大的纯收入驱使各大商家纷纭将纠删码应用于自己的仓储系统,比如
谷歌、Facebook、Azure、EMC
等等国际巨头,在国内以Taobao、三星、七牛云等为代表的商家也在协调的储存系统上使用了纠删码。

在上篇《怎么样挑选纠删码编码引擎》中,大家大约领悟了 Reed-SolomonCodes(RS
码)的编/解码进程,以及编码引擎的评判标准。但并没有就实际落成举办拓展,本篇作为《纠删码技术详解》的下篇,大家将重大探索工程落到实处的难题。

在上篇《如何拔取纠删码编码引擎》中,大家简要驾驭了 Reed-SolomonCodes(RS
码)的编/解码进程,以及编码引擎的鉴定标准。但并没有就实际贯彻举行拓展,本篇作为《纠删码技术详解》的下篇,大家将珍爱探索工程完毕的题材。

最优良的纠删码算法是Reade-所罗门码(Reed-Solomon 码,简称 RS 码)。RS
码最早拔取于通讯世界,经过数十年的发展,其在仓储系统中获取广泛应用,比如光盘中利用
RS
码举办容错,幸免光盘上的痕迹导致数据不可读;生活中时常使用的二维码就采纳了RS
码来进步识其他成功率。近年 RS
码在分布式存储系统中的应用被逐步松开,一方面是分布式存储系统存储的积存容量和层面增大的需求;另一方面是由于纠删码编码速度在方今获得快速进步。随着对高质量纠删码引擎在骨子里系统中利用要求,也催生了对纠删码在切实可行系统中落到实处的各个优化手段。并为相关的领导带来了麻烦——究竟怎么的编码引擎才是全速的呢?

那边先不难提炼一下完成高品质纠删码引擎的主题:首先,根据编码理论将矩阵以及有限域的运算工程化,接下去首要通过
SIMD 指令集以及缓存优化办事来进行加速运算。也就是说,大家可以将 RS
的工程已毕划分成多个主导步骤:

此地先简单提炼一下贯彻高品质纠删码引擎的中央:首先,按照编码理论将矩阵以及有限域的运算工程化,接下去紧要通过
SIMD 指令集以及缓存优化办事来举行加快运算。也就是说,大家可以将 RS
的工程落成划分成七个为主步骤:

大家将以这些难题展开对纠删码技术的辨析,协理集团更周密,深远的刺探纠删码在蕴藏系统中的应用并更好地做出技术选型。本种类作品将从纠删码的基本原理初始,随后引出怎么着判定编码引擎优劣这么些题材,接下去将深度剖析代码完成,辅助开发者顺遂完成定制开发。

  1. 将数学理论工程化

  2. 更加的工程优化

  1. 将数学理论工程化

  2. 进一步的工程优化

本连串共计上下两篇篇小说:

那亟需有关研发工程师对以下内容有所控制:

那亟需有关研发工程师对以下内容有所控制:

(上篇)怎么样选取纠删码编码引擎

  1. 有限域的基本概念,包涵有限域的变动与运算

  2. 矩阵的特性以及乘法规则

  3. 处理器连串布局中关于 CPU 指令以及缓存的论争

  1. 有限域的基本概念,包涵有限域的扭转与运算

  2. 矩阵的质量以及乘法规则

  3. 电脑种类布局中关于 CPU 指令以及缓存的辩论

(下篇)落成高品质纠删码引擎

接下去,大家将依照那五个步骤并构成相关基础知识展开完成进程的论述。

接下去,大家将基于那多少个步骤并结合相关基础知识展开完结进度的论述。

正文作为连串首篇,大家将同台切磋纠删码的编码原理与什么选拔编码引擎那四个问题。

一 、理论工程化

以 RS
码为例,纠删码已毕于具体的蕴藏系统可以分成多少个部分:编码、解码和修复进度中的总计都是在有限域上拓展的;编码进程即是统计生成矩阵(范德Mond或柯西矩阵)和具备数据的乘积;解码则是测算解码矩阵(生成矩阵中一些行向量组成的方阵的逆矩阵)和重建数据的乘积。

一 、理论工程化

以 RS
码为例,纠删码已毕于具体的仓储系统可以分成多少个部分:编码、解码和修复进度中的总结都是在有限域上进展的;编码进程即是总计生成矩阵(范德Mond或柯西矩阵)和持有数据的乘积;解码则是测算解码矩阵(生成矩阵中一些行向量组成的方阵的逆矩阵)和重建数据的乘积。

一 、纠删码编码原理

在拓展分析此前,大家先来看一看 RS 码是哪些行事的。

下图显示了 3+2(3 份数据,2 份冗余)下对 2
字节长度的数据开展编码与数码修复进程:

710官方网站 1

为了总结冗余数据,首先大家须求选举出一个相宜的编码矩阵。编码矩阵的上部为一个单位矩阵,这样保险了在编码后原本数据还是可以够直接读取。通过测算编码矩阵和原有数据的乘积,可以到最后的结果。

下边介绍解码进度,当 1,2 两块数据丢失,即:

710官方网站 2

当数码块暴发丢失,在编码矩阵中去掉相应行,等式依然维持创造。那为大家接下去復苏原来数据提供了按照。

原本数据的修复进程如下:

710官方网站 3

为了恢复生机数据,首先大家求剩余编码数据的逆矩阵,等式两边乘上这几个逆矩阵依然保持卓殊。与此同时,互逆矩阵的乘积为单位矩阵,因而得以被消掉。那么所求得的逆矩阵与剩余块的数码的乘积就是原本数据了。

数据编码以字节为单位,假诺将被编码数据看做一个「数组」,「数组」中各样元素是一个字节,数据按照字节顺序被编码。编码进程是计量编码矩阵中元素和「数组」的乘积进度。为确保乘积的演算结果依旧照旧在一个字节大小以内(即
0-255),必须利用到有限域[1]。有限域上的算术运算不相同于常常实数的运算规则。大家平日事先准备好乘法表,并在算术运算时对每三回乘法举行查表得到总结结果。早期的编码引擎之所以品质不佳,是因为逐字节查表的习性是相当低的。若是能一遍性对多字节进行查表以及对应的吞吐和运算,引擎的工作作用必将极大进步。

众多 CPU 厂商提供了蕴藏越多位数的寄存器(大于 64
位),那类寄存器和对应帮助的演算使得用户程序可以同时对当先机器位数的数据进行演算,匡助那类寄存器和运算的下令称之为SIMD(Single
Instruction Multiple Data)指令集,比如 AMD 协助的 SSE 指令集最大帮忙128 bits 的数码运算,AVX2 命令集最大协助 512 bits
的数额运算。它们为我们对一个「数组」数据分别实施同一的操作,进步了数据运算的并行性。近来,市面上所有高质量的纠删码引擎均选取了该项技术以抓牢编解码品质。

1.1 有限域运算

有限域是纠删码中运算的基础域,所有的编解码和重建运算都是基某个有限域的。不止是纠删码,一般的编码方法都在有限域上举行,比如大规模的AES加密中也有有限域运算。使用有限域的一个最首要原由是电脑并无法确切执行无限域的运算,比如合理数域和虚数域。

除此以外,在有限域上运算另一个要害的便宜是运算后的结果大小在一定限制内,那是因为有限域的封闭性决定的,那也为顺序设计提供了便民。比如在
RS 中,大家一般使用 GF(2^8),即 0~255
这一有限域,那是因为其尺寸刚好为1字节,便于大家对数码进行仓储和测算。

在规定了有限域的轻重缓急之后,通过有限域上的变通多项式可以找到该域上的生成元\[1\],进而通过生成元的幂次遍历有限域上的因素,利用这一性质大家可以变动对应的指数表。通过指数表大家可以求出对数表,再采用指数表与对数表最毕生成乘法表。关于本原多项式的变化以及有关运算表的计量可以参照我在开源库中的数学工具。[2]

有了乘法表,大家就足以在运算进程中一向查表获得结果,而不用举行复杂的多项式运算了。同时也简单窥见,查表优化将会化为接下去工作的最紧要与困难。

1.1 有限域运算

有限域是纠删码中运算的基础域,所有的编解码和重建运算都是基某个有限域的。不止是纠删码,一般的编码方法都在有限域上举办,比如大规模的AES加密中也有有限域运算。使用有限域的一个紧要原因是总括机并不可能可信执行无限域的演算,比如制造数域和虚数域。

除此以外,在有限域上运算另一个关键的好处是运算后的结果大小在自然范围内,那是因为有限域的封闭性决定的,那也为顺序设计提供了造福。比如在
RS 中,大家日常使用 GF(2^8),即 0~255
这一有限域,那是因为其尺寸刚好为1字节,便于大家对数据开展仓储和统计。

在确定了有限域的轻重之后,通过有限域上的变型多项式能够找到该域上的生成元\[1\],进而通过生成元的幂次遍历有限域上的因素,利用这一属性大家能够转移对应的指数表。通过指数表大家得以求出对数表,再使用指数表与对数表最一生成乘法表。关于本原多项式的变迁以及有关运算表的测算可以参照我在开源库中的数学工具。[2]

有了乘法表,大家就足以在运算进程中直接查表得到结果,而不用进行复杂的多项式运算了。同时也一见倾心发现,查表优化将会变成接下去工作的重点与困难。

二、编码引擎裁判标准

大家将从以下多少个根本目标来对编码引擎进行辨析:

1、 高编/解码速度;

2、参数可配置;

3、编码速度平稳;

4、代码简洁、稳定;

5 、下降修复费用等。

1.2 选取生成矩阵

生成矩阵(GM, generator matrix)
定义了怎么将原始数据块编码为冗余数据块,RS
码的生成矩阵是一个 行 列矩阵,将 块原始数据块编码为 块冗余数据块。要是对应的编码是系统码(比如
RAID),编码后含有了原来数据,则生成矩阵中含有一个 k×k 大大小小的单位矩阵和(nk)×k 的冗余矩阵,
单位矩阵对应的是原来数据块,冗余矩阵对应的是冗余数据块。非系统码没有单位矩阵,整个生成矩阵都是冗余矩阵,由此编码后唯有冗余数据块。平常我们会利用系统码以抓实多少提取时的作用,那么接下去大家必要找到合适的冗余矩阵。

在解码进程中大家要对矩阵求逆,由此所选择的矩阵必须满意子矩阵可逆的性质。近日业界应用最多的三种矩阵是
Vandermonde matrix (范德蒙矩阵)和Cauchy matrix(柯西矩阵)。其中范德蒙矩阵历史最为悠久,但必要注意的是我们并不可以一贯利用范德蒙矩阵

作为生成矩阵,而急需经过高斯消元后才能使用,那是因为在编码参数(k+m)比较大时会存在矩阵不可逆的高危害。

柯西矩阵运算简单,只然而必要总计乘法逆元,我们可以提前统计好乘法逆元表以供生成编码矩阵时利用。创造以柯西矩阵为生成矩阵的编码矩阵的伪代码如下图所示:

*// m 为编码矩阵*

*// rows为行数,cols为列数*

*// *k×k 的单位矩阵

**for **j := 0; j < cols; j++ {

   m[j][j] = byte(1)

}

*//* mxk 的柯西矩阵

**for **i := cols; i < rows; i++ {

   **for **j := 0; j < cols; j++ {

      d := i ^ j

      a := inverseTable[d]    *// 查乘法逆元表*

      m[i][j] = byte(a)

   }

}

1.2 拔取生成矩阵

生成矩阵(GM, generator matrix)
定义了怎么样将原本数据块编码为冗余数据块,RS
码的生成矩阵是一个 n 行 k 列矩阵,将 k 块原始数据块编码为 n 块冗余数据块。假诺对应的编码是系统码(比如
RAID),编码后含有了原来数据,则生成矩阵中包涵一个 k×k 大小的单位矩阵和(nk)×k 的冗余矩阵,
单位矩阵对应的是原有数据块,冗余矩阵对应的是冗余数据块。非系统码没有单位矩阵,整个生成矩阵都是冗余矩阵,因而编码后只有冗余数据块。平常我们会使用系统码以增强多少提取时的功用,那么接下去我们须要找到合适的冗余矩阵。

在解码进度中大家要对矩阵求逆,由此所选择的矩阵必须满意子矩阵可逆的质量。近年来业界应用最多的二种矩阵是
Vandermonde matrix (范德蒙矩阵)和Cauchy
matrix(柯西矩阵)。其中范德蒙矩阵历史最好悠久,但需求注意的是大家并无法一向运用范德蒙矩阵

用作生成矩阵,而急需经过高斯消元后才能采纳,这是因为在编码参数(k+m)相比较大时会存在矩阵不可逆的高危机。

柯西矩阵运算不难,只不过需求计算乘法逆元,大家得以提前计算好乘法逆元表以供生成编码矩阵时选择。创造以柯西矩阵为生成矩阵的编码矩阵的伪代码如下图所示:

*// m 为编码矩阵*

*// rows为行数,cols为列数*

*// *k×k 的单位矩阵

**for **j := 0; j < cols; j++ {

   m[j][j] = byte(1)

}

*//* mxk 的柯西矩阵

**for **i := cols; i < rows; i++ {

   **for **j := 0; j < cols; j++ {

      d := i ^ j

      a := inverseTable[d]    *// 查乘法逆元表*

      m[i][j] = byte(a)

   }

}

2.1 高编/解码速度

上文提到,依赖于SIMD 技术 RS
码编码性能有了大幅面的增高。其中,我们得以应用各样发令集扩大以供加速,引擎应该能活动根据CPU 的性状而选取最优的一声令下集增添举行加速。

速度是最宗旨的渴求。不过在那里我很难交付一个万万的数字来衡量速度,因为其受参数,运行平台的熏陶极大。在下文中涉及的三款引擎均有赏心悦目的质量表现,可以以它们为基准来衡量引擎的编码速度。除此之外,我们仍是可以将逐字节查表(下称基本格局)的编码速度与利用
SIMD
技术加快的编码速度做相比较,两者之间应该有丰硕直观的异样。以自身的个体电脑为例(i5-4278U
2.6GHz),在 10+4 的方针下(每个数据块大小为
128KB),基本方法的快慢为(原始数据总量/编码耗时)318.1 MB/s,而透过
AVX2 发令集加快后达到了 5558.6 MB/s[2],在 SSSE3 指令集的增速下也有
2978.87 MB/s 。

除此以外,解码速度应该高于或等于编码速度(视丢失的数额块数量而定),下图截自在本人本机上运行的修复原始数据块的品质测试结果:

710官方网站 4

 1.3 矩阵求逆运算

有限域上的求逆方法和大家上学的线性代数中求逆方法一致,常见的是高斯消元法,算法复杂度是
O(n^3)。进度如下:

  1. 在待求逆的矩阵左边拼接一个单位矩阵
  2. 进行高斯消元运算
  3. 取得到的矩阵左侧非单位矩阵的局地作为求逆的结果,若是不可逆则报错。

我们在其实的测试环境中发现,矩阵求逆的支出仍然相比较大的(大致6000 ns/op)。考虑到在实质上系统中,单盘数据重建往往须要多少个小时或者更长(磁盘I/O
占据绝半数以上小时),求逆统计时间能够忽略不计。

 1.3 矩阵求逆运算

有限域上的求逆方法和我们学习的线性代数中求逆方法同样,常见的是高斯消元法,算法复杂度是
O(n^3)。进程如下:

  1. 在待求逆的矩阵左边拼接一个单位矩阵

  2. 进展高斯消元运算

  3. 获得到的矩阵左侧非单位矩阵的一部分作为求逆的结果,即使不可逆则报错。

我们在实际上的测试环境中窥见,矩阵求逆的付出如故比较大的(大致 6000
ns/op)。考虑到在骨子里系统中,单盘数据重建往往须求多少个钟头或者更长(磁盘I/O
占据绝半数以上年华),求逆总计时间足以忽略不计。

2.2 参数可配备

一款合理的纠删码引擎必须能不辱职分编码策略在辩论范围内可自由切换,那指的是如果要将编码策略举办转变时,仅需从接口传入差距参数而不须要变更引擎本身。这大大下落了三番四遍的付出和护卫所必要的精力。一个可配置参数的编码引擎可以依据数量的冷热程度和数据首要程度选取差别的编码周密,比如可信性须求高的数码可以采用越多冗余。

二、进一步的工程优化

二、进一步的工程优化

2.3 编码速度平稳

速度的稳定性指的是对此不一样尺寸的数量块会有相近的习性表现。由于系统缓存的影响,当被编码数据的大小和缓存大小万分时,编码应该负有最快的快慢。当编码数据的大大小小大于缓存大时辰,内存带宽成为编码速度的瓶颈,文件大小和编码时间表现近似线性关系。那样,数据编码时间是可预料的,用户的劳务质量也是可保险的。在实际上中,我们对此大文件进行定长分块,依次编码,分块大小和缓存大小保持自然关联:以
10+4 编码方法为例,相比数据块尺寸分别为取 L3 Cache Size 的 1/12 以及 12
倍。如 L3 Cache Size 的大大小小为 12MB,则每一块的数据尺寸分别取
1MB,144MB。假诺大数目块下编码速度远远小于小数据块,则印证该引擎 CPU
cache
的优化办事做得不丰硕。对于上述参数来说,大数据块的速度应该不低于小数据块的
70% 。同样以自家的个体电脑为例(L3 Cache 大小为 3MB):

710官方网站 5

2.1 利用 SIMD 加快有限域运算

从上一篇小说可知,有限域上的乘法是由此查表获得的,每个字节和生成矩阵中元素的乘法结果通过查表得到,图1
给出了按字节对本来数据举办编码的进度(生成多项式为x^8 + x^4 + x^3

  • x^2 + 1)。
    对于任意 1 字节来说,在 GF(2^8)
    内有256种可能的值,所以没有元素对应的乘法表大小为 256
    字节。每回查表可以开展一个字节数据的乘法运算,效能很低。

710官方网站 6

 

图 1,
按字节对原本数据开展编码

现阶段主流的支撑 SIMD 相关指令的寄存器有 128bit(XMM 指令)、256bit (YMM
指令)那两种容量,那代表对于64位的机械来说,分别提供了2到4倍的拍卖能力,大家得以考虑选用 SIMD
指令并行地为更加多多少举行乘法运算。

但各种元素的乘法表的深浅为 256 Byte
,那大大高于了寄存器容纳能力。为了达成利用并行查表的目标,大家运用分治的想想将多少个字节的乘法运算举行拆分。

字节 y 与字节 a 的乘法运算进度可代表为,其中 y(a) 表示从 y
的乘法表中查询与 x 相乘结果的操作:

y(a) = y * a

 

大家将字节 a 拆分成高4位(al) 与低 4 位 (ar) 多个部分,即(其中 ⊕

为异或运算):

a = (al << 4) ⊕ ar

 

这么字节 a 就意味着为 0-15 与 (0-15 << 4)
异或运算的结果了。于是原先的 y 与 a 的乘法运算可代表为:

y(a) = y(al << 4) ⊕ y(ar)

 

鉴于 ar 与 al 的范围均为 0-15(0-1111),字节 y
与它们相乘的结果也就唯有16个可能的值了 。这样原本256 字节的字节 y
的乘法表就可以被 2 张 16 字节的乘法表替换了。

上边以依据本原多项式 x^8 + x^4 + x^3 + x^2 + 1 转变的 GF(2^8)
为例,分别通过查询普通乘法表与利用拆分乘法表来演示 16 * 100
的一个钱打二十四个结进程。

16 的完整乘法表为:

table = [0 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240
 29 13 61 45 93 77 125 109 157 141 189 173 221 205 253 237 58 42 26 10 122 
106 90 74 186 170 154 138 250 234 218 202 39 55 7 23 103 119 71 87 167 183
 135 151 231 247 199 215 116 100 84 68 52 36 20 4 244 228 212 196 180 164 
148 132 105 121 73 89 41 57 9 25 233 249 201 217 169 185 137 153 78 94 110 
126 14 30 46 62 206 222 238 254 142 158 174 190 83 67 115 99 19 3 51 35 211
 195 243 227 147 131 179 163 232 248 200 216 168 184 136 152 104 120 72 88 
40 56 8 24 245 229 213 197 181 165 149 133 117 101 85 69 53 37 21 5 210 194 
242 226 146 130 178 162 82 66 114 98 18 2 50 34 207 223 239 255 143 159 175 
191 79 95 111 127 15 31 47 63 156 140 188 172 220 204 252 236 28 12 60 44 
92 76 124 108 129 145 161 177 193 209 225 241 1 17 33 49 65 81 97 113 166 
182 134 150 230 246 198 214 38 54 6 22 102 118 70 86 187 171 155 139 251 
235 219 203 59 43 27 11 123 107 91 75]

 

计算 16 * 100 可以直接查表得到:

table[100] = 14

 

16 的低4位乘法表,也就是16 与 0-15 的乘法结果:

lowtable = [0 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240]

 

16 的高4位乘法表,为16 与 0-15 << 4 的乘法结果:

hightable = [0 29 58 39 116 105 78 83 232 245 210 207 156 129 166 187]

 

将 100 (01100100)拆分,则:

100 = 0110 << 4 ⊕ 0100

 

在没有表中查询 0100(4),得:

lowtable[4] = 64

 

在高位表中查询0110 (6),得:

hightable[6] = 78

 

将多少个查询结果异或:

result = 64 ^ 78 = 1000000 ^ 1001110 = 1110 = 14

 

从上面的自查自纠中,大家不难窥见采纳SIMD的新算法升高查表速度主要呈现在七个方面:

  1. 削减了乘法表大小;

  2. 加强查表并行度(从1个字节到16甚至32个字节)

应用 SIMD
指令在大大下降了乘法表的层面的同时多了四次查表操作以及异或运算。由于新的乘法表每一部分只有16 字节,咱们可以顺遂的将其放置于 XMM 寄存器中,从而拔取 SIMD
指令集提供的通令来开展数量向量运算,将原本的逐字节查表立异为相互的对 16
字节进行查表,同时异或操作也是 16
字节并行的。除此之外,由于乘法表的一体化规模的回落,在编码进度中的缓存污染也被大大减轻了,关于缓存的难题大家会在接下去的小节中举行更密切的解析。

上述的统计进程以单个字节作为例子,下边大家一同来分析应用 SIMD
技术对多少个字节举办演算的进程。基本步骤如下:
拆分保存原有数据的 XMM 寄存器中的数据向量,分别存储于不一样的 XMM 寄存器中

根据拆分后的多寡向量对乘法表举行重排,即获得查表结果。大家得以将乘法表驾驭为按顺序排放的数组,数首席营业官度为
16,查表的历程可以了解为将拆分后的数目(数据范围为 0-15
)作为目录对乘法表数组开展重新排序。那样大家就足以经过排序指令落成查表操作了将重排后的结果开展异或,拿到终极的演算结果

以下是伪代码:

*// 将原始数据的右移4bit*

d2 = raw_data >> 4

*// 将右移后的数据的每字节与15(即1111)做AND操作,得到数据高位*

high_data = d2 AND 1111

*// 原始数据的每字节与15(即1111)做AND操作,得到数据低位*

low_data = raw_data AND 1111

*// 以数据作为索引对乘法表进行了重排*

for i, b = range low_data { low_ret[i]=low_table[b]}

for i, b = range high_data {high_ret[i]=high_table[b]}

*// 异或两部分结果得到最终数据*

ret = low_ret XOR high_ret

 

内需专注的是,要运用 SIMD 加快有限域运算,对 CPU 的最低必要是永葆 SSSE3
扩张指令集。其余为了尽量升高成效,大家理应先行对数码举行内存对齐操作,在
SSSE3 下我们须求将数据对齐到 16
Bytes,否则大家不得不使用非对齐指令展开数量的读取和写入。在那一点上相比特殊的是
Go 语言, 一方面 Go 辅助直接调用汇编函数这为运用 SIMD
指令集提供了语言上的扶助;但其余一头 Golang
又隐蔽了内存申请的底细,那使得指定内存对齐操作不可控,即使大家也可以因而cgo 或者汇编来兑现,但那增添额外的负责。所幸,对于 CPU 来说一个 Cache
line
的大小为64byte,那在大势所趋程度上可以扶持大家缩短非对齐读写带来的惩治。其余,根据Golang
的内存对齐算法,对于较大的数据块,Golang 是会自行对齐到 32 byte
的,因而对齐或非对齐指令的进行功效是如出一辙的。

2.1 利用 SIMD 加快有限域运算

从上一篇小说可见,有限域上的乘法是透过查表获得的,每个字节和生成矩阵中元素的乘法结果通过查表获得,图1
给出了按字节对原有数据开展编码的长河(生成多项式为x^8 + x^4 + x^3 + x^2

  • 1)。
    对此任意 1 字节来说,在 GF(2^8)
    内有256种可能的值,所以并未元素对应的乘法表大小为 256
    字节。每回查表可以进行一个字节数据的乘法运算,成效很低。

710官方网站 7

 

图 1, 按字节对本来数据举行编码

近期主流的援救 SIMD 相关指令的寄存器有 128bit(XMM 指令)、256bit (YMM
指令)那三种容量,那表示对于64位的机器来说,分别提供了2到4倍的处理能力,大家可以设想使用
SIMD 指令并行地为越多数据开展乘法运算。

但每个元素的乘法表的大小为 256 Byte
,这大大超乎了寄存器容纳能力。为了完成利用并行查表的目的,大家采纳分治的盘算将多少个字节的乘法运算举办拆分。

字节 y 与字节 a 的乘法运算进程可代表为,其中 y(a) 表示从 y
的乘法表中查询与 x 相乘结果的操作:

y(a) = y * a

 

大家将字节 a 拆分成高4位(al) 与低 4 位 (ar) 四个部分,即(其中 ⊕

为异或运算):

a = (al << 4) ⊕ ar

 

如此字节 a 就代表为 0-15 与 (0-15 << 4)
异或运算的结果了。于是原先的 y 与 a 的乘法运算可代表为:

y(a) = y(al << 4) ⊕ y(ar)

 

由于 ar 与 al 的限定均为 0-15(0-1111),字节 y
与它们相乘的结果也就只有16个可能的值了 。那样原本256 字节的字节 y
的乘法表就足以被 2 张 16 字节的乘法表替换了。

上边以按照本原多项式 x^8 + x^4 + x^3 + x^2 + 1 转移的 GF(2^8)
为例,分别通过询问普通乘法表与应用拆分乘法表来演示 16 * 100
的盘算进度。

16 的全部乘法表为:

table = [0 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240
 29 13 61 45 93 77 125 109 157 141 189 173 221 205 253 237 58 42 26 10 122 
106 90 74 186 170 154 138 250 234 218 202 39 55 7 23 103 119 71 87 167 183
 135 151 231 247 199 215 116 100 84 68 52 36 20 4 244 228 212 196 180 164 
148 132 105 121 73 89 41 57 9 25 233 249 201 217 169 185 137 153 78 94 110 
126 14 30 46 62 206 222 238 254 142 158 174 190 83 67 115 99 19 3 51 35 211
 195 243 227 147 131 179 163 232 248 200 216 168 184 136 152 104 120 72 88 
40 56 8 24 245 229 213 197 181 165 149 133 117 101 85 69 53 37 21 5 210 194 
242 226 146 130 178 162 82 66 114 98 18 2 50 34 207 223 239 255 143 159 175 
191 79 95 111 127 15 31 47 63 156 140 188 172 220 204 252 236 28 12 60 44 
92 76 124 108 129 145 161 177 193 209 225 241 1 17 33 49 65 81 97 113 166 
182 134 150 230 246 198 214 38 54 6 22 102 118 70 86 187 171 155 139 251 
235 219 203 59 43 27 11 123 107 91 75]

 

计算 16 * 100 可以直接查表得到:

table[100] = 14

 

16 的低4位乘法表,也就是16 与 0-15 的乘法结果:

lowtable = [0 16 32 48 64 80 96 112 128 144 160 176 192 208 224 240]

 

16 的高4位乘法表,为16 与 0-15 << 4 的乘法结果:

hightable = [0 29 58 39 116 105 78 83 232 245 210 207 156 129 166 187]

 

将 100 (01100100)拆分,则:

100 = 0110 << 4 ⊕ 0100

 

在低位表中查询 0100(4),得:

lowtable[4] = 64

 

在高位表中查询0110 (6),得:

hightable[6] = 78

 

将多少个查询结果异或:

result = 64 ^ 78 = 1000000 ^ 1001110 = 1110 = 14

 

从上面的相比中,我们简单发现选择SIMD的新算法提升查表速度主要突显在四个方面:

  1. 减弱了乘法表大小;

  2. 增强查表并行度(从1个字节到16竟然32个字节)

行使 SIMD
指令在大大下降了乘法表的范畴的还要多了几遍查表操作以及异或运算。由于新的乘法表每一片段只有16 字节,大家得以万事大吉的将其放置于 XMM 寄存器中,从而选择 SIMD
指令集提供的一声令下来进展数据向量运算,将原本的逐字节查表立异为互相的对 16
字节进行查表,同时异或操作也是 16
字节并行的。除此之外,由于乘法表的完好规模的下降,在编码进程中的缓存污染也被大大减轻了,关于缓存的题目大家会在接下去的小节中开展更密切的解析。

以上的揣度进度以单个字节作为例子,下边大家一并来分析利用 SIMD
技术对八个字节举办演算的长河。基本步骤如下:
拆分保存原有数据的 XMM 寄存器中的数据向量,分别存储于不一致的 XMM 寄存器中

据悉拆分后的数量向量对乘法表进行重排,即取得查表结果。大家可以将乘法表领悟为按梯次排放的数组,数老板度为
16,查表的进度可以领略为将拆分后的多少(数据范围为 0-15
)作为目录对乘法表数组举行再一次排序。那样大家就足以经过排序指令完毕查表操作了将重排后的结果举行异或,获得最后的演算结果

以下是伪代码:

*// 将原始数据的右移4bit*

d2 = raw_data >> 4

*// 将右移后的数据的每字节与15(即1111)做AND操作,得到数据高位*

high_data = d2 AND 1111

*// 原始数据的每字节与15(即1111)做AND操作,得到数据低位*

low_data = raw_data AND 1111

*// 以数据作为索引对乘法表进行了重排*

for i, b = range low_data { low_ret[i]=low_table[b]}

for i, b = range high_data {high_ret[i]=high_table[b]}

*// 异或两部分结果得到最终数据*

ret = low_ret XOR high_ret

 

亟待专注的是,要采用 SIMD 加速有限域运算,对 CPU 的最低必要是支撑 SSSE3
扩充指令集。其它为了尽量提升功能,大家应领先行对数码举办内存对齐操作,在
SSSE3 下我们要求将数据对齐到 16
Bytes,否则大家只能选拔非对齐指令展开数据的读取和写入。在那点上比较新鲜的是
Go 语言, 一方面 Go 协助直接调用汇编函数那为利用 SIMD
指令集提供了语言上的援救;但此外一面 Golang
又隐蔽了内存申请的底细,那使得指定内存对齐操作不可控,固然大家也足以由此cgo 或者汇编来已毕,但那增加额外的担当。所幸,对于 CPU 来说一个 Cache
line
的尺寸为64byte,这在自然水准上可以辅助我们减弱非对齐读写带来的惩罚。其余,依照Golang
的内存对齐算法,对于较大的数据块,Golang 是会活动对齐到 32 byte
的,由此对齐或非对齐指令的执行功效是同等的。

2.4 代码简洁、稳定

为了利用 SIMD 加快我们不得不引入汇编代码或者封装后的 CPU
指令,因而代码方式并不普遍。为了增强可读性可将有些逻辑抽离到高档语言,不过会损失部分属性,那其中的得失须要根据集团的研发实力举行衡量。

接下去的可维护性也不行关键。首先是接口稳定,不会趁机新技巧的引入而招致代码大规模重构;其余代码必须透过有成立的测试模块以便在继承的立异中将验新算法。

比如原先的 SIMD 加速是基于 SSE 指令集增添来做的,随后 速龙 又推出 AVX
指令集进一步升高了品质,引擎应该能即时跟上硬件发展的步子。在比方说,再生码(可以了解为能减小修复开支的纠删码)是以后提高的可行性,但大家不可能因为算法的升迁而肆意更改引擎的接口。

二 写缓存友好代码

缓存优化通过两下边进行,其一是裁减缓存污染;其二是增高缓存命中率。在品尝成功这两点从前,大家先来分析缓存的着力工作规律。

CPU 缓存的默许工作方式是 Write-Back,
即每两遍读写内存数据都急需先写入缓存。上文提到的 Cache line
即为缓存工作的着力单位,其大小为稳定的 64 byte ,也就说就是从内存中读取
1字节的数据,CPU 也会将其余的63
字节带入缓存。那样设计的原由首如若为了增长缓存的时光局域性,因为所要执行的数码大小平日远远领先这些数字,提前将数据读取至缓存有利于接下去的多少在缓存中被打中。

二 写缓存友好代码

缓存优化通过两地方开展,其一是裁减缓存污染;其二是增加缓存命中率。在品味已毕那两点以前,大家先来分析缓存的骨干工作原理。

CPU 缓存的默许工作方式是 Write-Back,
即每便读写内存数据都亟待先写入缓存。上文提到的 Cache line
即为缓存工作的骨干单位,其尺寸为稳定的 64 byte ,也就说就是从内存中读取
1字节的数额,CPU 也会将其余的63
字节带入缓存。那样设计的来由根本是为着增强缓存的年月局域性,因为所要执行的数据大小平常远远当先这一个数字,提前将数据读取至缓存有利于接下去的数目在缓存中被击中。

2.5 下跌修复费用

纠删码的一大逆风局便是修补代价数倍于副本方案。k+m 策略的 RS
码在修补任何一个数目块时,都急需k
份的其他数据从磁盘上读取和在网络上传输。比如 10+4
的方案下,丢失一个多少块将必须读取 10
个块来修复,那些修复进程占用大批量磁盘 I/O
和网络流量,并使得系统暴光在一种降级的不稳定景况。因而,实际系统中应当尽量防止使用过大的
k 值。

再生码[2]
便是为了化解数据修复开销而被提议的,它可以极大缩短节点失效时所急需的吞吐的数据量。不过其复杂度大,一方面下降了编码速度,此外一头牺牲了传统
RS 码的有些地道性质,在工程完成上的难度也当先传统纠删码。

2.1 矩阵运算分块

矩阵运算的循环迭代中都用到了行与列,因而原始数据矩阵与编码矩阵的造访总有一方是非接二连三的,通过不难的巡回调换并不可能改正运算的空中局域性。因而大家通过分块的法门来加强时间局域性来压缩缓存缺失。

分块算法不是对一个数组的整行或整列举办操作,而是对其子矩阵展开操作,目标是在缓存中的数据被沟通此前,最大限度的选用它。

分块的尺寸不宜过大,太大的分块无法被装进缓存;其它也不能够过小,太小的分块导致外部逻辑的调用次数大大上涨,暴发了不须求的函数调用开支,而且也不可以丰盛利用缓存空间。

2.1 矩阵运算分块

矩阵运算的循环迭代中都用到了行与列,因而原始数据矩阵与编码矩阵的拜会总有一方是非一连的,通过容易的巡回互换并无法创新运算的半空中局域性。由此大家通过分块的措施来增强时间局域性来压缩缓存缺失。

分块算法不是对一个数组的整行或整列举行操作,而是对其子矩阵展开操作,目标是在缓存中的数据被互换以前,最大限度的采取它。

分块的尺寸不宜过大,太大的分块不可能被装进缓存;其它也无法过小,太小的分块导致外部逻辑的调用次数大大上升,暴发了不须要的函数调用开销,而且也不可以丰裕利用缓存空间。

三、闻明引擎相比较

当前被使用最广泛并使用了 SIMD 加快的发动机有如下两款:

  1. Intel 出品的 ISA-L[4]

  2. J.S.Plank 教师领导的 Jerasure[4]

  3. klauspost 的个人项目(in Golang)[6]

那五款引擎的实施成效都不行高,在完成上略有出入,以下是具体分析:

2.2 裁减缓存污染

不费吹灰之力察觉的是,编码矩阵中的周到并不会完全覆盖全部 GF(2^8),例如 10+4
的编码方案中,编码矩阵上校验矩阵大小为
4×10,编码全面至多(可能会有重新)有10×4=40
个。因而大家得以预先举行一个乘法表开端化的长河,比如生成一个新的二维数组来储存编码周到的乘法表。裁减表的限量可以在读取表的进度中对缓存的污染。

其它在定义方法集时需求专注的是防止结构体中的元素浪费。防止将不须求的参数扔进结构体中,如若每一个格局仅使用其中若干个因素,则其他因素白白侵夺了缓存空间。

2.2 减弱缓存污染

轻易窥见的是,编码矩阵中的周密并不会全盘覆盖整个 GF(2^8),例如 10+4
的编码方案中,编码矩阵元帅验矩阵大小为
4×10,编码周详至多(可能会有再度)有10×4=40
个。因而大家得以优先举行一个乘法表初叶化的经过,比如生成一个新的二维数组来存储编码周详的乘法表。减少表的界定可以在读取表的长河中对缓存的传染。

除此以外在定义方法集时要求小心的是防止结构体中的元素浪费。防止将不需要的参数扔进结构体中,即使每一个艺术仅使用其中多少个元素,则其余因素白白侵吞了缓存空间。

3.1 ISA-L

纠删码作为 ISA-L
库所提供的职能之一,其特性应该是眼下业界最佳。须求留意的是 AMD选用的习性测试方法与学界常用的方法略有出路,其将数据块与冗余块的尺寸之和除以耗时用作速度,而貌似的办法是不带有冗余块的。其余,ISA-L
未对 vandermonde
矩阵做越发处理,而是直接拼接单位矩阵作为其编码矩阵,由此在某些参数下会冒出编码矩阵线性相关的难点。好在
ISA-L 提供了cauchy 矩阵作为第二方案。

ISA-L 之所以速度快,一方面是出于 速龙谙熟汇编优化之道,其次是因为它将总体矩阵运算搬迁到汇编中举行。但那导致了汇编代码的霸道膨胀,令人毛骨悚然。

其它 ISA-L 匡助的下令集扩张丰富,下至 SSE,上到 AVX512,平台适应性最强。

三、 指令级并行与数据级并行的一语破的优化

本节重大介绍怎么样行使 AVX/AVX2
指令集以及指令级并行优化来进一步升高质量表现。除此之外,我们还能对汇编代码举办微调以获取微小的升官。比如,尽量避免使用
R8-R15 那 8
个寄存器,因为指令解码会比其他通用寄存器多一个字节。但过多汇编优化细节是和
CPU 架构设计相关的,书本上甚至 AMD提供的手册也并不能够提供最标准的点拨(因为有滞后性),而且这一个操作带来的出力并不显明,在那边就不做要紧表明了。

三、 指令级并行与数据级并行的中肯优化

本节重中之重介绍怎么样利用 AVX/AVX2
指令集以及指令级并行优化来进一步提升品质表现。除此之外,我们还足以对汇编代码举行微调以获得微小的晋级。比如,尽量幸免使用
R8-R15 那 8
个寄存器,因为指令解码会比其余通用寄存器多一个字节。但不少汇编优化细节是和
CPU 架构设计相关的,书本上甚至 英特尔提供的手册也并无法提供最可看重的率领(因为有滞后性),而且那么些操作带来的效应并不明了,在此处就不做主要表达了。

3.2 Jerasure2.0

差异于 ISA-L 直接动用汇编代码,Jerasure2.0 使用 C
语言封装后的一声令下,那样代码越发的和谐。此外 Jerasure2.0 不仅仅帮忙GF(2^8) 有限域的统计,其还足以开展 GF(2^4) – GF(2^128)
之间的有限域。并且除了 RS 码,还提供了 Cauchy Reed-Solomon code (CRS
码)等其余编码方法的支撑。它在工业使用之外,其学问价值也分外高。近年来其是行使最为普遍的编码库之一。近日Jerasure2.0 并不扶助 AVX 加快,固然如此,然则在仅使用 SSE
的情状下,Jerasure2.0 仍然提供了非凡高的性质表现。然则关键小编之一 JamesS. Plank 助教转了商讨方向,其余一位作者 Greenan
大学生已经进入工业界。由此后续的掩护将是个比较大的标题。

3.1 利用 AVX2

在上文中我们早已驾驭哪些将乘法表拆分成 128bits 的轻重以适应 XMM
寄存器,那么对于 AVX 指令集来说,要充足发挥其效劳,必要将乘法表复制到
256 bit 的 YMM 寄存器。为了形成这一点,大家可以动用 XMM 寄存器为 YMM
寄存器的低位这一特点,仅使用一条指令来形成表的复制(英特尔 风格):
vinserti128 ymm0, ymm0, xmm0, 1

那条指令功能是将 xmm0 寄存器中的数据拷贝到 ymm0 中,而剩余 128 位数据经过
ymm0 获得,其中立时数 1 标志 xmm0 拷贝的目标地是 ymm0
的上位。那条指令提供了八个 source operand(源操作数)以及一个
destination operand(目的操作数),大家在那边运用 ymm0
寄存器同时作为源操作数
和目的操作数
来兑现了表的复制操作。接下来大家便可以使用与 SSSE3
下一样的艺术来展开单指令 32 byte 的编码运算进程了。

由于使用了 SSE 与 AVX 那三种扩张指令集,我们须要防止 AVX-SSE Transition
Penalties[3]。之所以会有那种特性惩罚紧即使由于 SSE 指令对 YMM
寄存器的要职一窍不通,SSE 指令与 AVX 指令的混用会导致机器不断的执行 YMM
寄存器的高位保存与回复,那大大影响了质量表现。尽管对指令不熟练,难以幸免指令混用,那么可以在
RET 前应用 VZEROUPPER 指令来清空 YMM 寄存器的上位。

3.1 利用 AVX2

在上文中大家曾经清楚什么样将乘法表拆分成 128bits 的轻重缓急以适应 XMM
寄存器,那么对于 AVX 指令集来说,要丰硕发挥其意义,须要将乘法表复制到
256 bit 的 YMM 寄存器。为了完结那或多或少,我们得以应用 XMM 寄存器为 YMM
寄存器的没有这一特性,仅使用一条指令来已毕表的复制(AMD 风格):
vinserti128 ymm0, ymm0, xmm0, 1

那条指令功能是将 xmm0 寄存器中的数据拷贝到 ymm0 中,而剩余 128 位数据通过
ymm0 得到,其中立时数 1 标明 xmm0 拷贝的目标地是 ymm0
的要职。这条指令提供了五个 source operand(源操作数)以及一个
destination operand(目的操作数),大家在此处运用 ymm0
寄存器同时作为源操作数
和对象操作数
来已毕了表的复制操作。接下来大家便足以运用与 SSSE3
下同样的艺术来开展单指令 32 byte 的编码运算进程了。

由于使用了 SSE 与 AVX 那三种伸张指令集,大家必要避免 AVX-SSE Transition
Penalties[3]。之所以会有那种性质惩罚重即使由于 SSE 指令对 YMM
寄存器的上位一无所知,SSE 指令与 AVX 指令的混用会导致机器不断的实施 YMM
寄存器的要职保存与回复,那大大影响了品质表现。借使对指令不熟知,难防止止指令混用,那么可以在
RET 前应用 VZEROUPPER 指令来清空 YMM 寄存器的高位。

3.3 klauspost 的 ReedSolomon

klauspost 利用 Golang 的汇编接济,友好地行使了 SIMD 技术,此款引擎的
SIMD
加速部分是时下本人看齐的贯彻中不过简单的,矩阵运算的一些逻辑被移到了外围高级语言中,加上
Golang 自带的汇编帮衬,使得汇编代码阅读起来更佳的团结。不过 Go
并从未并轨所有指令,部分指令不得不选取 YASM
等汇编编译器将指令编译成字节种类写入汇编文件中。一方面促成了命令的通通不行读,别的一头那有些代码的语法风格是
AMD 而非 Golang 汇编的 AT&T
风格,平添了迷惑。那款引擎比较显明的弱点有两点:1.对于较大的数据块,编码速度会有远大的下滑;2.修复速度显明慢于编码速度。

3.2 指令级并行 (ILP) 优化

先后分支指令的开支并不仅仅为命令执行所须要的周期,因为它们或者影响前端流水线和内部缓存的情节。大家能够通过如下技术来收缩分支指令对质量的影响,并且抓牢分支预测单元的准确性:

  1. 少的使用分支指令

  2. 当贯穿 (fall-through) 更或者被实践时,使用向前条件跳转

  3. 当贯穿代码不太可能被实践时,使用向后条件跳转

上前跳转平日用在检讨函数参数的代码块中,要是大家幸免了流传长度为 0
的数码切片,那样能够在汇编中去掉相关的支行判断。在自我的代码中仅有一条向后条件跳转指令,用在循环代码块的底部。要求注意的是,以上
2 、 3
点中的优化措施是为着契合静态分支预测算法的须求,可是在市场上根据硬件动态预测方法等电脑占主导地位,因而那两点优化可能并不会起到增强分支预测准确度的功用,更加多的是优质的编程习惯的标题。

对此 CPU
的执行引擎来说,其往往包罗多个实施单元实例,那是实践引擎并发执行三个微操做的基本原理。其余CPU
内核的调度器下会挂有八个端口,那意味着每个周期调度器可以给执行引擎分发三个微操作。因而大家可以应用循环展开来狠抓指令级并行的可能。

循环展开就是将循环体复制多次,同时调动循环的终止代码。由于它裁减了分支判断的次数,由此得以未来自差异迭代的命令放在一起调度。

自然,若是循环展开知识不难地展开指令复制,最终动用的都是同一组寄存器,可能会妨碍对循环的有效性调度。因而大家应当合理分配寄存器的应用。其它,假诺循环规模较大,会招致指令缓存的缺失率上涨。AMD的优化手册中指出,循环体不应该超越 500 条指令。[4]

3.2 指令级并行 (ILP) 优化

次第分支指令的开销并不只为命令执行所需求的周期,因为它们可能影响前端流水线和其中缓存的内容。大家可以通过如下技术来压缩分支指令对品质的震慑,并且增加分支预测单元的准确性:

  1. 少的使用分支指令

  2. 当贯穿 (fall-through) 更可能被实施时,使用向前条件跳转

  3. 当贯穿代码不太可能被执行时,使用向后条件跳转

上前跳转平常用在检查函数参数的代码块中,假诺大家避免了流传长度为 0
的多少切片,那样可以在汇编中去掉相关的支行判断。在自家的代码中仅有一条向后条件跳转指令,用在循环代码块的底层。须要留意的是,以上
2 、 3
点中的优化措施是为着契合静态分支预测算法的渴求,但是在商海上根据硬件动态预测方法等电脑占主导地位,由此那两点优化可能并不会起到抓好分支预测准确度的功用,越多的是脍炙人口的编程习惯的题材。

对于 CPU
的施行引擎来说,其往往带有多少个实施单元实例,那是执行引擎并发执行多少个微操做的基本原理。别的CPU
内核的调度器下会挂有多少个端口,那代表每个周期调度器能够给执行引擎分发四个微操作。因而大家得以应用循环展开来增强指令级并行的可能。

循环展开就是将循环体复制很多次,同时调整循环的为止代码。由于它减少了分支判断的次数,因而得以未来自分裂迭代的指令放在一起调度。

当然,即便循环展开知识简单地开展指令复制,最终动用的都是同一组寄存器,可能会妨碍对循环的管事调度。由此我们应有制造分配寄存器的使用。别的,假若循环规模较大,会招致指令缓存的缺失率上升。速龙的优化手册中提议,循环体不该超过 500 条指令。[4]

四、自己已毕一款引擎

或许是出于对开源库后续维护问题的忧虑,也有可能是存活方案并不能满足公司对某些特定必要和偏好,很多小卖部选取了自研引擎。那么哪些写出高速的代码呢?在上头的简要介绍中,受限于篇幅我跳过了过多细节。比如
SIMD 技术是怎么着为纠删码服务的,以及如何行使 CPU Cache
做优化等居多首要难点。咱们会在一连的稿子中逐步举行其达成,欢迎我们继续关心。


附录:

  1. 许以超 马松雅. 代数编码与密码[M]. 香港:高等教育出版社, 2015.

  2. 徐祥曦
    Reed-Solomon

  3. Alexandros G Dimakis, P Godfrey, Yunnan Wu, Martin J Wainwright, and
    Kannan Ramchan-dran. Network coding for distributed storage systems.
    Information Theory, IEEE Transactions on, 56(9):4539–4551, 2010.

  4. Intel
    ISA-L

  5. Jerasure

  6. klauspost
    Reed-Solomon

四、 小结

上述内容相比完好的还原了纠删码引擎的完结进程,涉及到了较多的数学和硬件层面的学问,对于大部分工程师来说可能相对陌生,大家期待通过本连串作品的介绍可以为我们的工程举行提供多少扶助。但受限于篇幅,很多情节不能够周密展开。比如,部分数学工具的反驳与认证并不曾赢得详细的诠释,还亟需读者通过其余标准材料的来进展更深远的读书。

附录:
Galois Fields and Cyclic Codes
http://user.xmission.com/~rimrock/Documents/Galois%20Fields%20and%20Cyclic%20Codes.pdf

有限域相关计算 https://github.com/templexxx/reedsolomon/tree/master/mathtools

Avoiding AVX-SSE Transition Penalties
https://software.intel.com/en-us/articles/avoiding-avx-sse-transition-penalties

Intel 64 and IA-32 Architectures Optimization Reference Manual :3.4.2.6
Optimization for Decoded ICache

 

四、 小结

上述内容相比完好的还原了纠删码引擎的贯彻进程,涉及到了较多的数学和硬件层面的文化,对于多数工程师来说也许相对陌生,我们期待通过本连串小说的牵线可以为大家的工程实施提供多少援救。但受限于篇幅,很多情节不能周全拓展。比如,部分数学工具的争鸣与认证并不曾赢得详细的分解,还索要读者通过此外标准材料的来展开更透彻的求学。

附录:
Galois Fields and Cyclic Codes
http://user.xmission.com/~rimrock/Documents/Galois%20Fields%20and%20Cyclic%20Codes.pdf

有限域相关总计 https://github.com/templexxx/reedsolomon/tree/master/mathtools

Avoiding AVX-SSE Transition Penalties
https://software.intel.com/en-us/articles/avoiding-avx-sse-transition-penalties

Intel 64 and IA-32 Architectures Optimization Reference Manual :3.4.2.6
Optimization for Decoded ICache

相关文章