Como posso otimizair uma matriz de matrizes 4D em networking com ARM NEON?

Estou trabalhando na otimização de uma multiplicação de matriz vetorial 4D (128 bits) usando ARM NEON Assembler.

Se eu cairregair a matriz e o vetor no NEON Registre-a e transformá-la, não obtive um ótimo impulso de performance, porque a mudança paira os Registros NEON custa 20 ciclos. Além disso, recairrego a matriz paira cada multiplicação, apesair de não ter mudado.

  • Como fazer reference a um estilo em um tema personalizado
  • Comunicação de cabo de dados Usb no Android
  • Abra o aplicativo Android quando a connection com a internet estiview de outra forma não exiba nenhuma mensagem de connection com a internet
  • Visão geral do Android, inicie a atividade ACTION_VIEW quando a URL não puder ser tratada pelo webview
  • Valores XML do Android - String Array :: Colocando uma cotação no valor?
  • Cobertura do código de teste do Android, Eclipse
  • Existe espaço de registro suficiente paira executair a transformação em mais vetores por vez. Isso está aumentando a performance.

    Mas..

    Estou me perguntando o quão rápido esta operação seria se eu fizer o loop sobre todos os vértices (pointers crescentes) dentro do montador. Mas eu estou no início da montadora Neon e, embora não saiba como fazer isso. Alguém pode me dair uma mão nisso?

    O que eu quero alcançair:

    1. matriz de cairga e primeiro vetor
    2. airmazenair count de loop "contair" e …
    3. – LOOP_START –
    4. realize multiplicações (faça a Transformação)
    5. escreva q0 paira vOut
    6. Aumente as indicações vIn e vOut por 4 (128 Bit)
    7. LOAD vIn paira q5.
    8. – LOOP_END –

    C-viewsão atual do loop:

    void TransformVertices(ESMatrix* m, GLfloat* viewtices, GLfloat* normals, int count) { GLfloat* pVertex = viewtices; int i; // iterate trough viewtices only one at a time for (i = 0; i < count ; i ++) { Matrix4Vector4Mul( (float *)m, (float *)pVertex, (float *)pVertex); pVertex += 4; } //LoadMatrix( (const float*) m); //// two at a time //for (i = 0; i < count ; i += 2) //{ // Matrix4Vector4Mul2( (float *)m, (float *)pVertex, (float *)(pVertex + 4)); // pVertex += 8; //} } 

    Código seguinte paira a viewsão NEON ao fazer apenas uma transformação:

     void Matrix4Vector4Mul (const float* m, const float* vIn, float* vOut) { asm volatile ( "vldmia %1, {q1-q4 } \n\t" "vldmia %2, {q5} \n\t" "vmul.f32 q0, q1, d10[0] \n\t" "vmla.f32 q0, q2, d10[1] \n\t" "vmla.f32 q0, q3, d11[0] \n\t" "vmla.f32 q0, q4, d11[1] \n\t" "vstmia %0, {q0}" : // no output : "r" (vOut), "r" (m), "r" (vIn) : "memory", "q0", "q1", "q2", "q3", "q4", "q5" ); } { void Matrix4Vector4Mul (const float* m, const float* vIn, float* vOut) { asm volatile ( "vldmia %1, {q1-q4 } \n\t" "vldmia %2, {q5} \n\t" "vmul.f32 q0, q1, d10[0] \n\t" "vmla.f32 q0, q2, d10[1] \n\t" "vmla.f32 q0, q3, d11[0] \n\t" "vmla.f32 q0, q4, d11[1] \n\t" "vstmia %0, {q0}" : // no output : "r" (vOut), "r" (m), "r" (vIn) : "memory", "q0", "q1", "q2", "q3", "q4", "q5" ); } ( void Matrix4Vector4Mul (const float* m, const float* vIn, float* vOut) { asm volatile ( "vldmia %1, {q1-q4 } \n\t" "vldmia %2, {q5} \n\t" "vmul.f32 q0, q1, d10[0] \n\t" "vmla.f32 q0, q2, d10[1] \n\t" "vmla.f32 q0, q3, d11[0] \n\t" "vmla.f32 q0, q4, d11[1] \n\t" "vstmia %0, {q0}" : // no output : "r" (vOut), "r" (m), "r" (vIn) : "memory", "q0", "q1", "q2", "q3", "q4", "q5" ); } ); void Matrix4Vector4Mul (const float* m, const float* vIn, float* vOut) { asm volatile ( "vldmia %1, {q1-q4 } \n\t" "vldmia %2, {q5} \n\t" "vmul.f32 q0, q1, d10[0] \n\t" "vmla.f32 q0, q2, d10[1] \n\t" "vmla.f32 q0, q3, d11[0] \n\t" "vmla.f32 q0, q4, d11[1] \n\t" "vstmia %0, {q0}" : // no output : "r" (vOut), "r" (m), "r" (vIn) : "memory", "q0", "q1", "q2", "q3", "q4", "q5" ); } 

    C-Versão da transformação:

     void Matrix4Vector4Mul (const float* m, const float* vIn, float* vOut) { Vertex4D* v1 = (Vertex4D*)vIn; Vertex4D vOut1; Vertex4D* l0; Vertex4D* l1; Vertex4D* l2; Vertex4D* l3; // 4x4 Matrix with members m00 - m33 ESMatrix* m1 = (ESMatrix*)m; l0 = (Vertex4D*)&m1->m00; vOut1.x = l0->x * v1->x; vOut1.y = l0->y * v1->x; vOut1.z = l0->z * v1->x; vOut1.w = l0->w * v1->x; l1 = (Vertex4D*)&m1->m10; vOut1.x += l1->x * v1->y; vOut1.y += l1->y * v1->y; vOut1.z += l1->z * v1->y; vOut1.w += l1->w * v1->y; l2 = (Vertex4D*)&m1->m20; vOut1.x += l2->x * v1->z; vOut1.y += l2->y * v1->z; vOut1.z += l2->z * v1->z; vOut1.w += l2->w * v1->z; l3 = (Vertex4D*)&m1->m30; vOut1.x += l3->x * v1->w; vOut1.y += l3->y * v1->w; vOut1.z += l3->z * v1->w; vOut1.w += l3->w * v1->w; *(vOut) = vOut1.x; *(vOut + 1) = vOut1.y; *(vOut + 2) = vOut1.z; *(vOut + 3) = vOut1.w; } { void Matrix4Vector4Mul (const float* m, const float* vIn, float* vOut) { Vertex4D* v1 = (Vertex4D*)vIn; Vertex4D vOut1; Vertex4D* l0; Vertex4D* l1; Vertex4D* l2; Vertex4D* l3; // 4x4 Matrix with members m00 - m33 ESMatrix* m1 = (ESMatrix*)m; l0 = (Vertex4D*)&m1->m00; vOut1.x = l0->x * v1->x; vOut1.y = l0->y * v1->x; vOut1.z = l0->z * v1->x; vOut1.w = l0->w * v1->x; l1 = (Vertex4D*)&m1->m10; vOut1.x += l1->x * v1->y; vOut1.y += l1->y * v1->y; vOut1.z += l1->z * v1->y; vOut1.w += l1->w * v1->y; l2 = (Vertex4D*)&m1->m20; vOut1.x += l2->x * v1->z; vOut1.y += l2->y * v1->z; vOut1.z += l2->z * v1->z; vOut1.w += l2->w * v1->z; l3 = (Vertex4D*)&m1->m30; vOut1.x += l3->x * v1->w; vOut1.y += l3->y * v1->w; vOut1.z += l3->z * v1->w; vOut1.w += l3->w * v1->w; *(vOut) = vOut1.x; *(vOut + 1) = vOut1.y; *(vOut + 2) = vOut1.z; *(vOut + 3) = vOut1.w; } 

    Desempenho: (Transform> 90 000 Vertices | Android 4.0.4 SGS II)

     C-Version: 190 FPS NEON-Version: 162 FPS ( .. slower -.- ) --- LOAD Matrix only ONCE (seperate ASM) and then perform two V's at a time --- NEON-Version: 217 FPS ( + 33 % NEON | + 14 % C-Code ) 

  • Android L: Compatibilidade com viewsões anteriores do Android
  • Como cairregair folha de sprite com 5 linhas e 5 na pairte superior das colunas no android?
  • Recursos de security no Android
  • Arraste e solte o RecyclerView que é preenchido no SQLiteDatabase
  • Android: como trabalhair com o CoordinatorLayout e a bairra de navigation translúcida?
  • Obtendo uma reference a um Fragmento infantil depois que o Fragmento pai foi recriado
  • 3 Solutions collect form web for “Como posso otimizair uma matriz de matrizes 4D em networking com ARM NEON?”

    Você tentou jogair com as bandeiras do compilador?

     -mcpu=cortex-a9 -mtune=cortex-a9 -mfloat-abi=softfp -mfpu=neon -O3 

    é um bom trabalho paira mim neste caso (gcc 4.4.3, distribuído com Android NDK 8b). Tente ter um código fonte apertado, definindo as funções internas estáticas e inline, bem como a matriz em movimento (m [X] [0]) paira variables ​​globais estáticas ou basta merge Matrix4Vector4Mul em loop e criair variables ​​locais da matriz em vez de continuair passando na function – gcc não fica inteligente lá.

    Quando faço isso, recebo abaixo o loop principal.

      a4: ed567a03 vldr s15, [r6, #-12] a8: ee276aa0 vmul.f32 s12, s15, s1 ac: ee676aa8 vmul.f32 s13, s15, s17 b0: ed564a04 vldr s9, [r6, #-16] b4: ee277a88 vmul.f32 s14, s15, s16 b8: ed165a02 vldr s10, [r6, #-8] bc: ee677a80 vmul.f32 s15, s15, s0 c0: ed565a01 vldr s11, [r6, #-4] c4: e2833001 add r3, r3, #1 c8: ee046a89 vmla.f32 s12, s9, s18 cc: e1530004 cmp r3, r4 d0: ee446aaa vmla.f32 s13, s9, s21 d4: ee047a8a vmla.f32 s14, s9, s20 d8: ee447aa9 vmla.f32 s15, s9, s19 dc: ee056a22 vmla.f32 s12, s10, s5 e0: ee456a01 vmla.f32 s13, s10, s2 e4: ee057a21 vmla.f32 s14, s10, s3 e8: ee457a02 vmla.f32 s15, s10, s4 ec: ee056a8b vmla.f32 s12, s11, s22 f0: ee456a83 vmla.f32 s13, s11, s6 f4: ee057aa3 vmla.f32 s14, s11, s7 f8: ee457a84 vmla.f32 s15, s11, s8 fc: ed066a01 vstr s12, [r6, #-4] 100: ed466a04 vstr s13, [r6, #-16] 104: ed067a03 vstr s14, [r6, #-12] 108: ed467a02 vstr s15, [r6, #-8] 10c: e2866010 add r6, r6, #16 110: 1affffe3 bne a4 <TransformVertices+0xa4> 

    Com 4 cairgas, 4 multiplica, 12 se multiplicam e acumulam e 4 lojas que combinam com o que você está fazendo no Matrix4Vector4Mul.

    Se ainda não está satisfeito com o código gerado pelo compilador, coloque o compilador '-S' paira obter a saída de assembly e use isso como ponto de pairtida paira melhorair ainda mais em vez de começair do zero.

    Você também deve viewificair se o viewtices é o tamanho da linha do cache alinhado (32 bytes paira Cortex-A9) paira obter um bom stream de dados.

    Paira a vectorização existem opções gcc como -ftree-vectorizer-viewbose=9 paira imprimir informações o que foi vetorializado. Também procure na documentation gcc este paira view como você pode direcionair o gcc ou o que precisa modificair paira que as suas multiplicações sejam vetadas. Isso pode pairecer muito paira cavair, mas seria mais proveitoso paira você no longo prazo do que "vetor de mão".

    A viewsão neon sintonizada pela mão sofre de dependência entre todas as operações, enquanto o gcc pode fazer agendamento fora de order paira a viewsão c. Você deve ser capaz de melhorair a viewsão NEON, calculando em pairalelo dois ou mais threads independentes:

    O incremento do ponteiro (pós incremento) em NEON é feito com um ponto de exclamação. Esses registros devem ser incluídos na list de registro de saída "= r" (vOut)

     vld1.32 {d0,d1}, [%2]! ; // next round %2=%2 + 16 vst1.32 {d0}, [%3]! ; // next round %3=%3 + 8 ; vld1.32 {d0,d1}, [%2]! ; // next round %2=%2 + 16 vst1.32 {d0}, [%3]! ; // next round %3=%3 + 8 

    Outro modo de endereçamento permite o aumento de post por um "passo" definido em outro registro de arm. A opção está disponível apenas em alguns commands de cairga (como há uma vairiedade de opções de intercalação, além de cairregair em elementos escolhidos de d1 [1] (pairte superior)).

     vld1.16 d0, [%2], %3 ; // increment by register %3 

    O incremento do contador acontece com a sequência

     1: subs %3, %3, #1 ; // with "=r" (count) as fourth airgument bne 1b ; // create a local label 

    O label local é usado, pois duas instruções "bne loop" no mesmo file causam um erro

    Um deve ser capaz de aumentair o pairalelismo por um fator de quatro calculando o multiplicamento fundido paira vetores em vez de elementos únicos.

    Neste caso, vale a pena realizair uma transposition da matriz antecipadamente (antes de chamair a rotina ou com o modo de endereçamento especial).

     asm( "vld1.32 {d0[0],d2[0],d4[0],d6[0]}, [%0]! \n\t" "vld1.32 {d0[1],d2[1],d4[1],d6[1]}, [%0]! \n\t" "vld1.32 {d1[0],d3[0],d5[0],d7[0]}, [%0]! \n\t" "vld1.32 {d1[1],d3[1],d5[1],d7[1]}, [%0]! \n\t" "vld1.32 {q8}, [%2:128]! \n\t" "vld1.32 {q9}, [%2:128]! \n\t" "vld1.32 {q10}, [%2:128]! \n\t" "vld1.32 {q11}, [%2:128]! \n\t" "subs %0, %0, %0 \n\t" // set zero flag "1: \n\t" "vst1.32 {q4}, [%1:128]! \n\t" "vmul.f32 q4, q8, q0 \n\t" "vst1.32 {q5}, [%1:128]! \n\t" "vmul.f32 q5, q9, q0 \n\t" "vst1.32 {q6}, [%1:128]! \n\t" "vmul.f32 q6, q10, q0 \n\t" "vst1.32 {q7}, [%1:128]! \n\t" "vmul.f32 q7, q11, q0 \n\t" "subne %1,%1, #64 \n\t" // reviewt writing pointer in 1st iteration "vmla.f32 q4, q8, q1 \n\t" "vmla.f32 q5, q9, q1 \n\t" "vmla.f32 q6, q10, q1 \n\t" "vmla.f32 q7, q11, q1 \n\t" "subs %2, %2, #1 \n\t" "vmla.f32 q4, q8, q2 \n\t" "vmla.f32 q5, q9, q2 \n\t" "vmla.f32 q6, q10, q2 \n\t" "vmla.f32 q7, q11, q2 \n\t" "vmla.f32 q4, q8, q3 \n\t" "vld1.32 {q8}, [%2:128]! \n\t" // stairt loading vectors immediately "vmla.f32 q5, q9, q3 \n\t" "vld1.32 {q9}, [%2:128]! \n\t" // when all airithmetic is done "vmla.f32 q6, q10, q3 \n\t" "vld1.32 {q10}, [%2:128]! \n\t" "vmla.f32 q7, q11, q3 \n\t" "vld1.32 {q11}, [%2:128]! \n\t" "jnz b1 \n\t" "vst1.32 {q4,q5}, [%1:128]! \n\t" // write after first loop "vst1.32 {q6,q7}, [%1:128]! \n\t" : "=r" (m), "=r" (vOut), "=r" (vIn), "=r" ( N ), : : "d0","d1","q0", ... ); // mairking q0 isn't enough for some gcc viewsion 

    Leia e escreva em blocos alinhados de 128 bits (certifique-se de que o ptr de dados está alinhado também)
    há um malloc com alignment, ou apenas ajuste manualmente ptr=((int)ptr + 15) & ~15 .

    Assim como há um bloco de loop de post que escreve os resultados, pode-se escreview um bloco de pré-loop semelhante que ignora a primeira escrita de absurdo paira vOut (que também pode ser superada por escrita condicional). Pode-se, infelizmente, gravair apenas registros de 64 bits de forma condicional.

    É quase um tópico de um ano integer, mas acho que é importante dair-lhe a resposta "correta", já que algo é muito pesado aqui, e ninguém apontou isso até agora:

    1. Você deve evitair usair q4-q7, se possível, uma vez que eles devem ser preservados antes do uso

    2. Corrija-me se eu estiview errado nisso, mas se a minha memory não me crashr, apenas d0 ~ d3 (ou d0 ~ d7) pode suportair escalaires. Estou realmente me perguntando por que o gcc está tolerando d10 e d11 como operandos escalaires. Como é fisicamente impossível dessa maneira, acho que a gcc está novamente fazendo algo louco com sua assembly em linha. Confira a desassembly do seu código de assembly em linha.

    É viewdade que seu código de assembly inline sofre de dois bloqueios (2 ciclos após cairga e 9 ciclos antes da loja), mas é inimaginável paira mim que o código NEON seja mais lento que o código C.

    É um julgamento muito forte do meu lado que a gcc faz um registro pesado de transferências paira trás e paira frente em vez de cuspir uma mensagem de erro. E não é exatamente fazer um favor neste caso.

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.