您好!
我正在尝试使用 spmatrix 乘法例程将矩阵乘以2k x 2k 的顺序。
两个矩阵都位于 DDR 中、L1和 L2都已完全缓存。
单核性能非常慢、无法满足我的实时要求。
我想使用 openmp 将代码并行至多核。
我知道单核性能下降是由于未对齐读取、这是矩阵乘法的固有问题。
是否有方法可以实现更好的性能。 我将查看的性能接近为 DSPLib 矩阵乘法例程提供的基准标记。
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
您好!
我正在尝试使用 spmatrix 乘法例程将矩阵乘以2k x 2k 的顺序。
两个矩阵都位于 DDR 中、L1和 L2都已完全缓存。
单核性能非常慢、无法满足我的实时要求。
我想使用 openmp 将代码并行至多核。
我知道单核性能下降是由于未对齐读取、这是矩阵乘法的固有问题。
是否有方法可以实现更好的性能。 我将查看的性能接近为 DSPLib 矩阵乘法例程提供的基准标记。
您好、Prathek
这是一个非常有趣的问题。 很明显、16M 字节的数据不能放入 L2中、DDR 存在非连续数据的问题、因此我建议如下:
1.使用 EDMA 将数据加载到 L2中。 使用 B 索引从 DDR 连续读取、并在 L2中使用 STRIDE 进行写入。
2.将矩阵分为多个部分,每个部分都应安装在 L1D 内。 L1D 为32KB 或8K sp 值、因此将矩阵分解为64 x 64 (或类似分区)的一部分。 将数据读写到 L2、并使用 EDMA 将数据从 L2移入 DDR 并移回
我建议首先尝试对 L2存储器中的128 x 128矩阵执行此操作、如果这对您有效、请转到 EDMA 方案
过去、我开发了用于对大型矩阵进行 Cholesky 分解 的代码(我测试了128x128)、在我的情况下、数据位于 L2中、但分区是为了适应 L1D 高速缓存并存储中间结果而完成的。 我使用大小至少为10x10的进程的函数、我展示了如何使用此帖子中包含调试代码的源代码完成该操作。 实际代码显然没有所有消耗如此多周期的 printf、并且不需要某些操作(这些操作仅用于调试目的)。 此外、我附加了一个带有已测量基准的文档(同样、对于 Cholesky)。 请注意、大小必须至少为10 (我有用于较小矩阵的类似函数)
请注意、这是我的个人职能部门、而不是 TI、因此不存在明确或隐含的保证、即它能够正常工作、提供正确的结果或提供任何支持
void kincholeskyLarger_10 (int N、float * in、float * out、float * OneOverDiag)
{
float x0、x1、 xx0、xx1 ;
int k,l,m ;
float *p1,*p2;
float y0、y1;
float *p_in 、*p_in1、 *p_out1、 *p_out;
内扩散 ;
双 A01 、B01、C01、D01、E01、 F01、 G01、h01;
float a0 ;
////// 在步骤6中、我将尝试对指针进行条纹线
//// 输入指针可以是 restrict
//// 输出指针不能为、因为它在写入后被重新读取
//// 我们可以分离
如果 (N < 10)
{
printf(" N 必须至少为10\n") ;
返回 ;
}
//////////// 处理第一行/列
P_IN = IN ;
P_OUT = OUT ;
printf ("p_in %x p_out %x \n"、p_in、p_out) ;
A01 = _amemd8 (IN);//
A0 =_lof (A01) ; //用于调试
IN = IN + 2 ;
y0 =_rsqrsp (a0) ; //第一个 NR 猜测、
Y1 = y0 *(3- a0 * y0 * y0)* 0.5 ; // 第一次迭代,16位准确度
x0 = Y1 *(3- a0 * Y1 *)* 0.5 ; // 第二次迭代
printf (" a0和 x0 %f %f \n"、a0、x0) ;
b01 =_ftod (x0、x0) ;
*OUT+=a0 * x0 ;
*OUT+=0.0 ;
printf("第一 个输出 %f\n", a0 * x0 );
*OneOverDiag ++= x0 ;
_nassert( N >=10 ); /* 最小的矩阵为10x10 */
扩散= 4;
/// 下一个块计算第一列中的所有数字
对于(k=1;k< N;k++)
{
A01 = _amemd8 (in);
printf(" A01 %f %f\n"),_lof (A01),_hif (A01)) ;
C01 =_dmpysp (A01、B01) ;
_amemd8 (out) = C01 ;
IN = IN +扩散;
OUT = OUT +扩散;
扩散=扩散+ 2 ;
printf ("p_in %x p_out %x \n"、in、out) ;
printf ("out %f %f \n"、_lof (C01)、_hif (C01));
}
//////////////// 第二行/列的处理
///将指针移回和移出
IN = p_in + 4 ;//第二行对角线处的点
OUT = p_OUT + 2;
A01 =_amemd8 (out);
OUT = OUT + 2 ;
b01 =_dmpysp (A01、A01);
XX0 = _HIF (B01)+_lof (B01);
printf("xx0 %f p_in %x \n",xx0,p_in ) ;
xx1 = (浮点)*in; // 仅读取实值
x0=(xx1-xx0) ;
printf (“xx1 %f x0 %f \n”、xx1、x0) ;
y0 =_rsqrsp (x0) ; //第一个 NR 猜测、
Y1 = y0 *(3.0 - x0 * y0 * y0)* 0.5 ; // 第一次迭代,16位准确度
X1 = Y1 *(3.0 - x0 * Y1 *)* 0.5 ; // 第二次迭代
D01 =_ftod (x1、x1) ;
*OneOverDiag ++= x1 ;
*OUT++=x0 * x1 ;
printf("out %f \n"x0*x1) ;
*OUT+=0.0 ; // 保存对角线
// 此时,输出指向第三行的第一个元素(位置6)和
// 以行2对角线的实部为单位(位置4)
///////////////////////////////////
/// 下一个块计算第二列中的所有数字
//A01 具有第二行第一个元素的值
扩散= 4 ;
IN = IN + 4 ;
对于(l = 2;l < N;l++)
{
printf (“In %x diffP %d”,In,diffP) ;
h01 = _amemd8 (out); //读取输出输入
OUT = OUT + 2 ; // 指向行的第二个元素
printf("h01 %f %f\n",_lof (h01),_hif (h01));
E01 =_complex_conjugate_mpysp (h01、A01) ;
printf (" E01 %f %f \n",_lof (E01),_HIF (E01));
F01 =_amemd8 (in) ; // 读取输入
G01 =_dsubsp (F01、E01) ;
printf (" F01 %f %f \n",_lof (F01),_HIF (F01));
printf (" G01 %f %f \n",_lof (G01),_hif (G01));
C01 =_dmpysp (G01、D01) ;
printf (" C01 %f %f \n",_lof (C01),_HIF (C01));
_amemd8 (out) = C01 ;
printf (“difP =%d \n”,扩散 P) ;
OUT = OUT +扩散;
扩散=扩散+2 ;
IN = IN +扩散;
}
////// 第 k 行的通用循环开始
//// 从第2行开始,指针 P1从 out+6开始,它将开始
///递增 6、8、10等
//// 因此、扩散 P1为6、P1 = OUT+ 6、并且在每个环路 P1 = P1 +扩散 P1之后
/// 和扩散 P1 =扩散 P1 + 2
//// p_in 点在 in + 10、然后是18、28、40
//// 因此 p_in 比 p1递增2
in =p_in ;
out = p_out;
P1 =输出+ 6 ;
P_IN = IN + 10 ;
扩散= 6 ;
printf (" in %x out %x \n"、in、out) ;
对于(k= 2、000、<N; k++)
{
P_IN = IN + k *(k+3) ;
//// 步骤1 -计算总和
printf(" P1 %x、p_in %x \n"、 p1、p_in ) ;
P_OUT1 = P1 ;
xx1 = 0.0 ;
对于(L=0;<k; l++)
{
A01 = _amemd8 (p_out1);
printf("A01 %f %f\n",_lof (A01),_hif (A01));
b01 =_dmpysp (A01、A01);
XX0 = _HIF (B01)+_lof (B01);
P_OUT1 = p_OUT1 + 2 ;
xx1 = xx1 + xx0 ;
printf ("sumD %f \n"、xx1) ;
}
//p_out1 指向行 k 中的最后一个元素(对角线)
/// P1 在第一个优先级点
//p_in 指向输入中的对角线
// h01 =_amemd8 (p_in) ;
XX0 =*p_in ;
x0=(xx0-xx1) ;
printf (“xx1 %f xx0 %f x0 %f \n”、xx1、xx0、x0) ;
y0 =_rsqrsp (x0) ; //第一个 NR 猜测、
Y1 = y0 *(3.0 - x0 * y0 * y0)* 0.5 ; // 第一次迭代,16位准确度
X1 = Y1 *(3.0 - x0 * Y1 *)* 0.5 ; // 第二次迭代
// x1是1/sqrt
D01 =_ftod (x1、x1) ;
*OneOverDiag ++= x1 ;
printf ("x1 =%f \n"、x1) ;
/// 现在我们有1/sqrt、我们可以从开始对第 k 行的所有释放进行筛选
/// 对角线
//p_out1 指向对角线(输出)-对于第2行、它是10;对于第3行、它是18
/// 对于第2行、它以6、8等递增
/// 对于第3行、它以8、10等递增
/// P1 指向行 k 的第一个元素
/// 请注意、瓶颈可能不是倍增器 、而是寄存器或负载、
/// 、因此我们可以将寻址改回多路复用器
// m = k *(k+1) ;
// n = k *(k+3) ; //对角线位置
// P1 =&out[m] ;
*p_out1++=x0 * x1;
*p_out1++ =0.0 ;
printf (“对角线输出%f \n",x0 * x1);
/// 下一步是构建所有低于对角线的值
//// 这些元素
//// 对角线位于位置 k*(k+3)
//// 下一个位于位置 k*(k+3)+ 2 *(k + 1)
//// 下一个位于地址 k*(k+3)+ 2*(k+ 3)+ 2 *(k+1)
/// 和一般情况。 在第 k+u 行中,新元素的地址为 k*(k+3)+和(2*r),其中 r 为 k+1 到 u
// 现在到值的地址。 列 k 和行 l 中的值 (k < l)
/// 具有以下公式 (输入矩阵、L 和 U 为输出)
// a (k+m、k)=和(u 从 o 到 k-1) L (k、u)* L (k+m、u)共轭+ D1 * L (k+m、k)
/// 因此
/// L (k+m、k)=(A (k+m、k)-和)* x1
如果 (k+1 == N) 返回;
// 计算低于对角线的所有值(对于 L)
b01 =_ftod (0.0、0.0) ;
对于(l = k+1;l < N;l++)
{
P1 = Out + k*(k+1) ; // 保留寻址不变
P2 =输出+ l *(l+1) ;
p_in1 = in + k*2 +(l+1)* l ;
P_OUT1 =输出+ k*2 +(l+1)* l ;
对于(m=0;<k;m++)
{
printf("P1 %x P2 %x \n"、P1、P2 ) ;
h01 = _amemd8 (P1); //读取输出输入
A01 = _amemd8 (P2);
P1 = P1 + 2 ;
P2 = P2 + 2 ;
printf ("h01和 a 01 %f %f %f %f %f \n"、_lof (h01)、_hif (h01)、_lof (A01)、_hif (A01))));
E01 =_complex_conjugate_mpysp (h01、A01) ; // 或其他方法
b01 =_daddsp (E01、B01) ;//累加图像和实数
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
printf (" B01 %f %f \n",_lof (B01),_hif (B01));
F01 =_amemd8 (p_in1) ; // 读取输入
G01 =_dsubsp (F01、B01) ;
printf (" F01 %f %f \n",_lof (F01),_HIF (F01));
printf (" G01 %f %f \n",_lof (G01),_hif (G01));
C01 =_dmpysp (G01、D01) ;
printf (" C01 %f %f \n",_lof (C01),_HIF (C01));
_amemd8 (p_out1) = C01 ;
P1 = P1 + 2 ;
////////// 输出的地址是 什么??????
}
}
返回 ;
}