Я создал аннотированный след с перфом.По какой-то причине инструкции с наибольшим процентом имеют тип ldp:
5.56 │ ldp s9, s8, [x28,#80]
37.65 │ ldp s2, s3, [x19,#24]
37.65 │ ldp s2, s3, [x19,#24]
Это ошибка?Или это намекает на плохое кэширование L1 / L2, поскольку скорость ldp зависит от кэша?
Редактировать:
Вот выдержка из аннотированного вывода perf.Отрывок из умножения матрицы glm, который использует моя функция:
│ _ZN3glmmlIdLNS_9precisionE0EEENS_7tmat4x4IT_XT0_EE8row_typeERKNS4_8col_typeERKS4_(): ▒
│ ) ▒
│ { ▒ ▒
│ ▒
│ return typename tmat4x4<T, P>::row_type( ◆
│ m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2] + m[0][3] * v[3], ▒
28.86 │ 40: ldp d3, d0, [x0] ▒
│ add x4, x4, #0x20 ▒
│ ldp d18, d10, [x1] ▒
│ m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2] + m[1][3] * v[3], ▒
0.34 │ ldp d21, d24, [x1,#32] ▒
│ m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2] + m[2][3] * v[3], ▒
0.34 │ ldp d20, d23, [x1,#64] ▒
│ m[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3]); ▒
0.34 │ ldp d19, d22, [x1,#96] ▒
│ m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2] + m[1][3] * v[3], ▒
│ fmul d24, d0, d24 ▒
│ m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2] + m[0][3] * v[3], ▒
10.07 │ ldp d2, d1, [x0,#16] ▒
│ m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2] + m[2][3] * v[3], ▒
│ fmul d23, d0, d23 ▒
│ m[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3]); ▒
0.34 │ ldp d8, d6, [x1,#16] ▒
│ fmul d22, d0, d22 ▒
0.34 │ ldp d17, d7, [x1,#48] ▒
│ m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2] + m[0][3] * v[3], ▒
│ fmul d0, d0, d10 ▒
│ m[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3]); ▒
│ ldp d16, d5, [x1,#80] ▒
│ m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2] + m[1][3] * v[3], ▒
│ fmadd d21, d3, d21, d24 ▒
│ m[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3]); ▒
0.34 │ ldp d9, d4, [x1,#112] ▒
│ m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2] + m[2][3] * v[3], ▒
│ fmadd d20, d3, d20, d23 ▒
│ m[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3]); ▒
│ fmadd d19, d3, d19, d22 ▒
│ m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2] + m[0][3] * v[3], ▒
│ fmadd d0, d18, d3, d0 ▒
│ m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2] + m[1][3] * v[3], ▒
0.67 │ fmadd d17, d2, d17, d21 ▒
│ m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2] + m[2][3] * v[3], ▒
│ fmadd d16, d2, d16, d20 ▒
│ m[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3]); ▒
│ fmadd d7, d1, d7, d17 ▒
│ fmadd d5, d1, d5, d16 ▒
1.01 │ fmadd d9, d2, d9, d19 ▒
│ m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2] + m[0][3] * v[3], ▒
│ fmadd d2, d8, d2, d0 ▒
│ m[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3]); ▒
│ fmadd d4, d1, d4, d9 ▒
│ fmadd d1, d6, d1, d2 ▒
0.67 │ add x0, x0, #0x20
С уважением
Редактировать: я добавил исходный код текущей версии метода, который создает ~ 2500 пропусков кэша на входе 10000элементы.Может быть, у кого-то есть еще идеи:
inline void
transformVector ( glm::mat4 const & matrix,
std::vector < glm::vec4 > const & input,
std::vector < glm::vec4 > & output )
{
float32x4x4_t iMatrix = *(float32x4x4_t *)&matrix;
float32x4_t rslt;
std::vector < glm::vec4 >::const_iterator inVertexStart = input.begin();
std::vector < glm::vec4 >::const_iterator inVertexEnd = input.end();
std::vector < glm::vec4 >::iterator outVertexStart = output.begin();
for ( ; inVertexStart != inVertexEnd; inVertexStart++, outVertexStart++ )
{
const float32x4_t input_local = *( float32x4_t const * )&(*inVertexStart);
rslt = vmulq_f32( iMatrix.val[0], input_local);
rslt = vmlaq_f32(rslt, iMatrix.val[1], input_local);
rslt = vmlaq_f32(rslt, iMatrix.val[2], input_local);
rslt = vmlaq_f32(rslt, iMatrix.val[3], input_local);
vst1q_f32( (float32_t*)&( *outVertexStart ), rslt);
}
}
ASM:
0x0000000000400fb0 <+0>: ldr x3, [x1,#8]
0x0000000000400fb4 <+4>: ldr x1, [x1]
0x0000000000400fb8 <+8>: ldr q5, [x0]
0x0000000000400fbc <+12>: cmp x1, x3
0x0000000000400fc0 <+16>: ldr q4, [x0,#16]
0x0000000000400fc4 <+20>: ldr q3, [x0,#32]
0x0000000000400fc8 <+24>: ldr q2, [x0,#48]
0x0000000000400fcc <+28>: ldr x2, [x2]
0x0000000000400fd0 <+32>: b.eq 0x400ff4 <transformVector(glm::tmat4x4<float, (glm::precision)0> const&, std::vector<glm::tvec4<float, (glm::precision)0>, std::allocator<glm::tvec4<float, (glm::precision)0> > > const&, std::vector<glm::tvec4<float, (glm::precision)0>, std::allocator<glm::tvec4<float, (glm::precision)0> > >&)+68>
0x0000000000400fd4 <+36>: ldr q1, [x1],#16
0x0000000000400fd8 <+40>: fmul v0.4s, v1.4s, v4.4s
0x0000000000400fdc <+44>: cmp x3, x1
0x0000000000400fe0 <+48>: fmla v0.4s, v1.4s, v5.4s
0x0000000000400fe4 <+52>: fmla v0.4s, v3.4s, v1.4s
0x0000000000400fe8 <+56>: fmla v0.4s, v1.4s, v2.4s
0x0000000000400fec <+60>: str q0, [x2],#16
0x0000000000400ff0 <+64>: b.ne 0x400fd4 <transformVector(glm::tmat4x4<float, (glm::precision)0> const&, std::vector<glm::tvec4<float, (glm::precision)0>, std::allocator<glm::tvec4<float, (glm::precision)0> > > const&, std::vector<glm::tvec4<float, (glm::precision)0>, std::allocator<glm::tvec4<float, (glm::precision)0> > >&)+36>
0x0000000000400ff4 <+68>: ret