Pull to refresh

Начальное ускорение математики

Reading time12 min
Views4.5K

Всем привет. В графических приложениях есть своего рода сердце — этой графики. Это математика, от того как исполнена математика, зависит общий отклик приложения, есть некоторые подходы, при помощи которых не сразу, но можно войти в начальное понимание, как и что ускорять.

В этой статье хочу показать как я почти в 10 раз ускорил графику при помощи математики.

Особенности

Воспользуюсь FreeBSD 14.2-Release, clang15.

если воспользоваться коммандой

find / | grep "immintrin.h"

одним из найденных файлов будет

/usr/local/llvm15/lib/clang/15.0.7/include/immintrin.h

из этого файла мне понадобится

#include <xmmintrin.h> //ключевой файл 
#include <wmmintrin.h> //
#include <smmintrin.h> //
#include <nmmintrin.h> // 
#include <immintrin.h> //общий файл в файле /usr/local/llvm15/lib/clang/15.0.7/include/module.modulemap указаны минимальные ориентиры что где распологается и для каких версий ускорений

буду так же пользоваться калькулятором для отстройки*, так же понадобятся 3 матрицы, над которыми будут производиться тесты, 3 вектора, так же будет производиться простейший замер времени над матрицами 2 раза — 1 прогон исходный вариант без ускорения, и второй вариант с ускорением по принципу — 1,10,100,1000,10000,100000,1000000

Скрытый текст
#pragma GCC optimize("Ofast,unroll-loops,-ffast-math")
#pragma GCC target("sse")
#include <xmmintrin.h>
#include <wmmintrin.h>
#include <smmintrin.h>
#include <nmmintrin.h>
#include <immintrin.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <string.h>
typedef float f32;

struct vec4_t
{
    f32 x;
    f32 y;
    f32 z;
    f32 w;
};
typedef struct vec4_t vec4;

struct mat4_t
{
    f32 v[16];
};
typedef struct mat4_t mat4;

//see also 2 upd in the end
void mulm4VVV(const float *result, const float *a, const float *b)
{
    __m128 row0 = _mm_loadu_ps(&b[0]);
    __m128 row1 = _mm_loadu_ps(&b[4]);
    __m128 row2 = _mm_loadu_ps(&b[8]);
    __m128 row3 = _mm_loadu_ps(&b[12]);

    __m128 newRow0 = _mm_mul_ps(row0,                   _mm_set1_ps(a[0]));
    newRow0 = _mm_add_ps(newRow0, _mm_mul_ps(row1, _mm_set1_ps(a[1])));
    newRow0 = _mm_add_ps(newRow0, _mm_mul_ps(row2, _mm_set1_ps(a[2])));
    newRow0 = _mm_add_ps(newRow0, _mm_mul_ps(row3, _mm_set1_ps(a[3])));

    __m128 newRow1 = _mm_mul_ps(row0,                   _mm_set1_ps(a[4]));
    newRow1 = _mm_add_ps(newRow1, _mm_mul_ps(row1, _mm_set1_ps(a[5])));
    newRow1 = _mm_add_ps(newRow1, _mm_mul_ps(row2, _mm_set1_ps(a[6])));
    newRow1 = _mm_add_ps(newRow1, _mm_mul_ps(row3, _mm_set1_ps(a[7])));

    __m128 newRow2 = _mm_mul_ps(row0,                   _mm_set1_ps(a[8]));
    newRow2 = _mm_add_ps(newRow2, _mm_mul_ps(row1, _mm_set1_ps(a[9])));
    newRow2 = _mm_add_ps(newRow2, _mm_mul_ps(row2, _mm_set1_ps(a[10])));
    newRow2 = _mm_add_ps(newRow2, _mm_mul_ps(row3, _mm_set1_ps(a[11])));

    __m128 newRow3 = _mm_mul_ps(row0,                  _mm_set1_ps(a[12]));
    newRow3 = _mm_add_ps(newRow3, _mm_mul_ps(row1, _mm_set1_ps(a[13])));
    newRow3 = _mm_add_ps(newRow3, _mm_mul_ps(row2, _mm_set1_ps(a[14])));
    newRow3 = _mm_add_ps(newRow3, _mm_mul_ps(row3, _mm_set1_ps(a[15])));

    _mm_storeu_ps(&result[0], newRow0);
    _mm_storeu_ps(&result[4], newRow1);
    _mm_storeu_ps(&result[8], newRow2);
    _mm_storeu_ps(&result[12], newRow3);
}

void DotProduct4VVV(float *a,float *b,float *c)
{
    __m128 a0 = _mm_loadu_ps(&a[0]);
    __m128 b0 = _mm_loadu_ps(&b[0]);

    _mm_storeu_ps(&c[0], _mm_dp_ps(a0,b0,0xFF));
}

mat4 Mulm4(const mat4 a, const mat4 b)
{
    mat4 result;

    result.v[0] = a.v[0] * b.v[0] + a.v[4] * b.v[1] + a.v[8] * b.v[2] + a.v[12] * b.v[3];
    result.v[1] = a.v[1] * b.v[0] + a.v[5] * b.v[1] + a.v[9] * b.v[2] + a.v[13] * b.v[3];
    result.v[2] = a.v[2] * b.v[0] + a.v[6] * b.v[1] + a.v[10] * b.v[2] + a.v[14] * b.v[3];
    result.v[3] = a.v[3] * b.v[0] + a.v[7] * b.v[1] + a.v[11] * b.v[2] + a.v[15] * b.v[3];

    result.v[4] = a.v[0] * b.v[4] + a.v[4] * b.v[5] + a.v[8] * b.v[6] + a.v[12] * b.v[7];
    result.v[5] = a.v[1] * b.v[4] + a.v[5] * b.v[5] + a.v[9] * b.v[6] + a.v[13] * b.v[7];
    result.v[6] = a.v[2] * b.v[4] + a.v[6] * b.v[5] + a.v[10] * b.v[6] + a.v[14] * b.v[7];
    result.v[7] = a.v[3] * b.v[4] + a.v[7] * b.v[5] + a.v[11] * b.v[6] + a.v[15] * b.v[7];

    result.v[8] = a.v[0] * b.v[8] + a.v[4] * b.v[9] + a.v[8] * b.v[10] + a.v[12] * b.v[11];
    result.v[9] = a.v[1] * b.v[8] + a.v[5] * b.v[9] + a.v[9] * b.v[10] + a.v[13] * b.v[11];
    result.v[10] = a.v[2] * b.v[8] + a.v[6] * b.v[9] + a.v[10] * b.v[10] + a.v[14] * b.v[11];
    result.v[11] = a.v[3] * b.v[8] + a.v[7] * b.v[9] + a.v[11] * b.v[10] + a.v[15] * b.v[11];

    result.v[12] = a.v[0] * b.v[12] + a.v[4] * b.v[13] + a.v[8] * b.v[14] + a.v[12] * b.v[15];
    result.v[13] = a.v[1] * b.v[12] + a.v[5] * b.v[13] + a.v[9] * b.v[14] + a.v[13] * b.v[15];
    result.v[14] = a.v[2] * b.v[12] + a.v[6] * b.v[13] + a.v[10] * b.v[14] + a.v[14] * b.v[15];
    result.v[15] = a.v[3] * b.v[12] + a.v[7] * b.v[13] + a.v[11] * b.v[14] + a.v[15] * b.v[15];

    return result;
}

float Dotv4(const vec4 a, const vec4 b)
{
    return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}

void stopW(clock_t start)
{
  clock_t end = clock();
  float seconds = (float)(end - start) / CLOCKS_PER_SEC;

  printf("Elapsed: %.12f seconds\n", seconds);
}

int getN()
{
  return rand()%100;
}

void wIntr()
{
  mat4 a=(mat4){
    2,9,40,5,
    8,6,5,6,
    8,9,7,4,
    7,5,3,10
  };
  
  mat4 b=(mat4){
    50,30,88,70,
    85,100,0,10,
    89,65,50,60,
    99,45,14,80
  };

  mat4 c;
  mulm4VVV(c.v,a.v,b.v);
  
  printf(
	 "%f %f %f %f \n%f %f %f %f \n%f %f %f %f \n%f %f %f %f \n",
	 c.v[0],  c.v[1],  c.v[2],  c.v[3],
	 c.v[4],  c.v[5],  c.v[6],  c.v[7],
	 c.v[8],  c.v[9],  c.v[10], c.v[11],
	 c.v[12], c.v[13], c.v[14], c.v[15]
	 );
  for(int i=0;i<1;i++)
    {
      c=Mulm4(a,b);

    }
  for(int i=0;i<10;i++)
    {
      mat4 a=(mat4){
	getN(),getN(),getN(),getN(),
	getN(),getN(),getN(),getN(),
	getN(),getN(),getN(),getN(),
	getN(),getN(),getN(),getN()
      };
  
      mat4 b=(mat4){
	getN(),getN(),getN(),getN(),
	getN(),getN(),getN(),getN(),
	getN(),getN(),getN(),getN(),
	getN(),getN(),getN(),getN()
      };
  
      c=Mulm4(a,b);
    }
  for(int i=0;i<100;i++)
    {
      c=Mulm4(a,b);
    }
  for(int i=0;i<1000;i++)
    {
      c=Mulm4(a,b);
    }
  for(int i=0;i<10000;i++)
    {
      c=Mulm4(a,b);
    }
  for(int i=0;i<100000;i++)
    {
      c=Mulm4(a,b);
    }
  for(int i=0;i<1000000;i++)
    {
      c=Mulm4(a,b);
    }
}


void Intr()
{
  mat4 a=(mat4){
    2,9,40,5,
    8,6,5,6,
    8,9,7,4,
    7,5,3,10
  };
  
  mat4 b=(mat4){
    50,30,88,70,
    85,100,0,10,
    89,65,50,60,
    99,45,14,80
  };

  mat4 c;
  mulm4VVV(&c.v[0],a.v,b.v);

  printf(
	 "%f %f %f %f \n%f %f %f %f \n%f %f %f %f \n%f %f %f %f \n",
	 c.v[0],  c.v[1],  c.v[2],  c.v[3],
	 c.v[4],  c.v[5],  c.v[6],  c.v[7],
	 c.v[8],  c.v[9],  c.v[10], c.v[11],
	 c.v[12], c.v[13], c.v[14], c.v[15]
	 );
  for(int i=0;i<1;i++)
    {
      mulm4VVV(c.v,a.v,b.v);
    }
  for(int i=0;i<10;i++)
    {
      mulm4VVV(c.v,a.v,b.v);
    }
  for(int i=0;i<100;i++)
    {
      mulm4VVV(c.v,a.v,b.v);
    }
  for(int i=0;i<1000;i++)
    {
      mulm4VVV(c.v,a.v,b.v);
    }
  for(int i=0;i<10000;i++)
    {
      mulm4VVV(c.v,a.v,b.v);
    }
  for(int i=0;i<100000;i++)
    {
      mulm4VVV(c.v,a.v,b.v);
    }
  for(int i=0;i<1000000;i++)
    {
      mulm4VVV(c.v,a.v,b.v);
    }
}


int main()
{
  struct timespec Ta,Tb;
  
  float GlobalTime=0;
  float localTime=0;
  
  clock_gettime(CLOCK_MONOTONIC,&Ta);
  wIntr();
  clock_gettime(CLOCK_MONOTONIC,&Tb);
  localTime=(double) (Tb.tv_nsec - Ta.tv_nsec) / 1000000 +
            (double) (Tb.tv_sec - Ta.tv_sec);
  
  printf("%f\n",localTime);
  
  clock_gettime(CLOCK_MONOTONIC,&Ta);
  Intr();
  clock_gettime(CLOCK_MONOTONIC,&Tb);
  localTime=(double) (Tb.tv_nsec - Ta.tv_nsec) / 1000000 +
            (double) (Tb.tv_sec - Ta.tv_sec);
  
  printf("%f\n",localTime);

  vec4 ACC={9,2,7,0};
  vec4 BCC={4,8,10,0};
  vec4 CCC;

  DotProduct4VVV((float*)&ACC,(float*)&BCC,(float*)&CCC);
  printf("%f \n",CCC.x);
  return 0;
}
пример части перемножения матриц
пример части перемножения матриц

исправленная вверсия проверки upd

Скрытый текст
#pragma GCC optimize("Ofast,unroll-loops,-ffast-math")
#pragma GCC target("sse")
#include <xmmintrin.h>
#include <wmmintrin.h>
#include <smmintrin.h>
#include <nmmintrin.h>
#include <immintrin.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <string.h>
typedef float f32;

struct vec4_t
{
    f32 x;
    f32 y;
    f32 z;
    f32 w;
};
typedef struct vec4_t vec4;

struct mat4_t
{
    f32 v[16];
};
typedef struct mat4_t mat4;

void mulm4VVV(const float *result, const float *a, const float *b)//
{
    __m128 row0 = _mm_loadu_ps(&b[0]);//a for transform section (result,a,b)
    __m128 row1 = _mm_loadu_ps(&b[4]);
    __m128 row2 = _mm_loadu_ps(&b[8]);
    __m128 row3 = _mm_loadu_ps(&b[12]);

    __m128 newRow0 = _mm_mul_ps(row0,                   _mm_set1_ps(a[0]));//b for transform section (result,a,b)
    newRow0 = _mm_add_ps(newRow0, _mm_mul_ps(row1, _mm_set1_ps(a[1])));
    newRow0 = _mm_add_ps(newRow0, _mm_mul_ps(row2, _mm_set1_ps(a[2])));
    newRow0 = _mm_add_ps(newRow0, _mm_mul_ps(row3, _mm_set1_ps(a[3])));

    __m128 newRow1 = _mm_mul_ps(row0,                   _mm_set1_ps(a[4]));
    newRow1 = _mm_add_ps(newRow1, _mm_mul_ps(row1, _mm_set1_ps(a[5])));
    newRow1 = _mm_add_ps(newRow1, _mm_mul_ps(row2, _mm_set1_ps(a[6])));
    newRow1 = _mm_add_ps(newRow1, _mm_mul_ps(row3, _mm_set1_ps(a[7])));

    __m128 newRow2 = _mm_mul_ps(row0,                   _mm_set1_ps(a[8]));
    newRow2 = _mm_add_ps(newRow2, _mm_mul_ps(row1, _mm_set1_ps(a[9])));
    newRow2 = _mm_add_ps(newRow2, _mm_mul_ps(row2, _mm_set1_ps(a[10])));
    newRow2 = _mm_add_ps(newRow2, _mm_mul_ps(row3, _mm_set1_ps(a[11])));

    __m128 newRow3 = _mm_mul_ps(row0,                  _mm_set1_ps(a[12]));
    newRow3 = _mm_add_ps(newRow3, _mm_mul_ps(row1, _mm_set1_ps(a[13])));
    newRow3 = _mm_add_ps(newRow3, _mm_mul_ps(row2, _mm_set1_ps(a[14])));
    newRow3 = _mm_add_ps(newRow3, _mm_mul_ps(row3, _mm_set1_ps(a[15])));

    _mm_storeu_ps(&result[0], newRow0);
    _mm_storeu_ps(&result[4], newRow1);
    _mm_storeu_ps(&result[8], newRow2);
    _mm_storeu_ps(&result[12], newRow3);
}

void DotProduct4VVV(float *a,float *b,float *c)
{
    __m128 a0 = _mm_loadu_ps(&a[0]);
    __m128 b0 = _mm_loadu_ps(&b[0]);

    _mm_storeu_ps(&c[0], _mm_dp_ps(a0,b0,0xFF));
}

mat4 Mulm4(const mat4 a, const mat4 b)
{
    mat4 result;

    result.v[0] = a.v[0] * b.v[0] + a.v[4] * b.v[1] + a.v[8] * b.v[2] + a.v[12] * b.v[3];
    result.v[1] = a.v[1] * b.v[0] + a.v[5] * b.v[1] + a.v[9] * b.v[2] + a.v[13] * b.v[3];
    result.v[2] = a.v[2] * b.v[0] + a.v[6] * b.v[1] + a.v[10] * b.v[2] + a.v[14] * b.v[3];
    result.v[3] = a.v[3] * b.v[0] + a.v[7] * b.v[1] + a.v[11] * b.v[2] + a.v[15] * b.v[3];

    result.v[4] = a.v[0] * b.v[4] + a.v[4] * b.v[5] + a.v[8] * b.v[6] + a.v[12] * b.v[7];
    result.v[5] = a.v[1] * b.v[4] + a.v[5] * b.v[5] + a.v[9] * b.v[6] + a.v[13] * b.v[7];
    result.v[6] = a.v[2] * b.v[4] + a.v[6] * b.v[5] + a.v[10] * b.v[6] + a.v[14] * b.v[7];
    result.v[7] = a.v[3] * b.v[4] + a.v[7] * b.v[5] + a.v[11] * b.v[6] + a.v[15] * b.v[7];

    result.v[8] = a.v[0] * b.v[8] + a.v[4] * b.v[9] + a.v[8] * b.v[10] + a.v[12] * b.v[11];
    result.v[9] = a.v[1] * b.v[8] + a.v[5] * b.v[9] + a.v[9] * b.v[10] + a.v[13] * b.v[11];
    result.v[10] = a.v[2] * b.v[8] + a.v[6] * b.v[9] + a.v[10] * b.v[10] + a.v[14] * b.v[11];
    result.v[11] = a.v[3] * b.v[8] + a.v[7] * b.v[9] + a.v[11] * b.v[10] + a.v[15] * b.v[11];

    result.v[12] = a.v[0] * b.v[12] + a.v[4] * b.v[13] + a.v[8] * b.v[14] + a.v[12] * b.v[15];
    result.v[13] = a.v[1] * b.v[12] + a.v[5] * b.v[13] + a.v[9] * b.v[14] + a.v[13] * b.v[15];
    result.v[14] = a.v[2] * b.v[12] + a.v[6] * b.v[13] + a.v[10] * b.v[14] + a.v[14] * b.v[15];
    result.v[15] = a.v[3] * b.v[12] + a.v[7] * b.v[13] + a.v[11] * b.v[14] + a.v[15] * b.v[15];

    return result;
}

float Dotv4(const vec4 a, const vec4 b)
{
    return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}

void stopW(clock_t start)
{
  clock_t end = clock();
  float seconds = (float)(end - start) / CLOCKS_PER_SEC;

  printf("Elapsed: %.12f seconds\n", seconds);
}

int getN()
{
  return rand()%100;
}

void wIntr()
{
  mat4 a=(mat4){
    2,9,40,5,
    8,6,5,6,
    8,9,7,4,
    7,5,3,10
  };
  
  mat4 b=(mat4){
    50,30,88,70,
    85,100,0,10,
    89,65,50,60,
    99,45,14,80
  };

  mat4 c;
  c=Mulm4(a,b);//(b,a)
  
  printf(
	 "%f %f %f %f \n%f %f %f %f \n%f %f %f %f \n%f %f %f %f \n",
	 c.v[0],  c.v[1],  c.v[2],  c.v[3],
	 c.v[4],  c.v[5],  c.v[6],  c.v[7],
	 c.v[8],  c.v[9],  c.v[10], c.v[11],
	 c.v[12], c.v[13], c.v[14], c.v[15]
	 );
  /* for(int i=0;i<1;i++) */
  /*   { */
  /*     c=Mulm4(a,b); */

  /*   } */
  /* for(int i=0;i<10;i++) */
  /*   { */
  /*     /\* mat4 a=(mat4){ *\/ */
  /*     /\* 	getN(),getN(),getN(),getN(), *\/ */
  /*     /\* 	getN(),getN(),getN(),getN(), *\/ */
  /*     /\* 	getN(),getN(),getN(),getN(), *\/ */
  /*     /\* 	getN(),getN(),getN(),getN() *\/ */
  /*     /\* }; *\/ */
  
  /*     /\* mat4 b=(mat4){ *\/ */
  /*     /\* 	getN(),getN(),getN(),getN(), *\/ */
  /*     /\* 	getN(),getN(),getN(),getN(), *\/ */
  /*     /\* 	getN(),getN(),getN(),getN(), *\/ */
  /*     /\* 	getN(),getN(),getN(),getN() *\/ */
  /*     /\* }; *\/ */
  
  /*     c=Mulm4(a,b); */
  /*   } */
  /* for(int i=0;i<100;i++) */
  /*   { */
  /*     c=Mulm4(a,b); */
  /*   } */
  /* for(int i=0;i<1000;i++) */
  /*   { */
  /*     c=Mulm4(a,b); */
  /*   } */
  /* for(int i=0;i<10000;i++) */
  /*   { */
  /*     c=Mulm4(a,b); */
  /*   } */
  /* for(int i=0;i<100000;i++) */
  /*   { */
  /*     c=Mulm4(a,b); */
  /*   } */
  /* for(int i=0;i<1000000;i++) */
  /*   { */
  /*     c=Mulm4(a,b); */
  /*   } */
}


void Intr()
{
  mat4 a=(mat4){
    2,9,40,5,
    8,6,5,6,
    8,9,7,4,
    7,5,3,10
  };
  
  mat4 b=(mat4){
    50,30,88,70,
    85,100,0,10,
    89,65,50,60,
    99,45,14,80
  };

  mat4 c;
  mulm4VVV(&c.v[0],a.v,b.v);

  printf(
	 "%f %f %f %f \n%f %f %f %f \n%f %f %f %f \n%f %f %f %f \n",
	 c.v[0],  c.v[1],  c.v[2],  c.v[3],
	 c.v[4],  c.v[5],  c.v[6],  c.v[7],
	 c.v[8],  c.v[9],  c.v[10], c.v[11],
	 c.v[12], c.v[13], c.v[14], c.v[15]
	 );
  /* for(int i=0;i<1;i++) */
  /*   { */
  /*     mulm4VVV(c.v,a.v,b.v); */
  /*   } */
  /* for(int i=0;i<10;i++) */
  /*   { */
  /*     /\* mat4 a=(mat4){ *\/ */
  /*     /\* 	getN(),getN(),getN(),getN(), *\/ */
  /*     /\* 	getN(),getN(),getN(),getN(), *\/ */
  /*     /\* 	getN(),getN(),getN(),getN(), *\/ */
  /*     /\* 	getN(),getN(),getN(),getN() *\/ */
  /*     /\* }; *\/ */
  
  /*     /\* mat4 b=(mat4){ *\/ */
  /*     /\* 	getN(),getN(),getN(),getN(), *\/ */
  /*     /\* 	getN(),getN(),getN(),getN(), *\/ */
  /*     /\* 	getN(),getN(),getN(),getN(), *\/ */
  /*     /\* 	getN(),getN(),getN(),getN() *\/ */
  /*     /\* }; *\/ */
  /*     mulm4VVV(c.v,a.v,b.v); */
  /*   } */
  /* for(int i=0;i<100;i++) */
  /*   { */
  /*     mulm4VVV(c.v,a.v,b.v); */
  /*   } */
  /* for(int i=0;i<1000;i++) */
  /*   { */
  /*     mulm4VVV(c.v,a.v,b.v); */
  /*   } */
  /* for(int i=0;i<10000;i++) */
  /*   { */
  /*     mulm4VVV(c.v,a.v,b.v); */
  /*   } */
  /* for(int i=0;i<100000;i++) */
  /*   { */
  /*     mulm4VVV(c.v,a.v,b.v); */
  /*   } */
  /* for(int i=0;i<1000000;i++) */
  /*   { */
  /*     mulm4VVV(c.v,a.v,b.v); */
  /*   } */
}


int main()
{
  struct timespec Ta,Tb;
  
  float GlobalTime=0;
  float localTime=0;
  
  clock_gettime(CLOCK_MONOTONIC,&Ta);
  wIntr();
  clock_gettime(CLOCK_MONOTONIC,&Tb);
  localTime=
             (double) (Tb.tv_nsec - Ta.tv_nsec) / 1000000 +
         (double) (Tb.tv_sec - Ta.tv_sec);
  printf("%f\n",localTime);
  
  clock_gettime(CLOCK_MONOTONIC,&Ta);
  Intr();
  clock_gettime(CLOCK_MONOTONIC,&Tb);
  localTime=
             (double) (Tb.tv_nsec - Ta.tv_nsec) / 1000000 +
         (double) (Tb.tv_sec - Ta.tv_sec);
  printf("%f\n",localTime);

  vec4 ACC={9,2,7,0};
  vec4 BCC={4,8,10,0};
  vec4 CCC;

  DotProduct4VVV((float*)&ACC,(float*)&BCC,(float*)&CCC);
  printf("%f \n",CCC.x);
  return 0;
}

Более точную информацию с описанием функций можно найти в выше приведенных файлах.

при помощи mmloadu_ps = происходит инициализация регистра

при помощи mmstoreu_ps = происходит запись результата в переменную

при помощи mmset1_ps = установка значением

при помощи mmadd_ps = сложение

при помощи mmmul_ps = перемножение

при помощи mmdp_ps = происходит dotProduct

регистры 128 битные [4xfloat]

как видим прирост почти в 10 раз

clang main.c -Ofast -ffast-math -msse4.1 -msse4.2 -lm -ldl

матрицы как пример, замеры по калькулятору
матрицы как пример, замеры по калькулятору
исправленная версия проверки upd
исправленная версия проверки upd
пример upd
пример upd
Скрытый текст
void SetCCC(
  Transform1 *transform,
  vec3 p, // position
  float rotateDegree, 
  vec3 rotateX, //angles
  vec3 rotateY, 
  vec3 rotateZ, 
  vec3 scale) //
{
    ...
                      //in this time      b                    a
    mulm4VVV(transform->model.v,transform->Translate.v,transform->model.v);//(b,a)
    mulm4VVV(transform->model.v,transform->Rotate.v,transform->model.v);
    mulm4VVV(transform->model.v,transform->Scale.v,transform->model.v);

}



//void atTheTest2()//0,1,2,3
//{
// 
//  vec4 a1=(vec4){2,9,40,5};vec4 b1=(vec4){50 ,85,89,99};
//  
//  vec4 a2=(vec4){8,6,5,6};vec4 b2=(vec4){30,100,65,45};
//  
//  vec4 a3=(vec4){8,9,7,4};vec4 b3=(vec4){88,0,50,14};
//  
//  vec4 a4=(vec4){7,5,3,10};vec4 b4=(vec4){70,10,60,80};
//                                 
//  //Mulv4 умножение векторов add сложение
//  vec4 c1;                          //x,y,z,w
//  c1=Mulv4(         a1,(vec4){b1.z,b1.z,b1.z,b1.z}); //a row
//
//  c1=Addv4(c1,Mulv4(a2,(vec4){b2.z,b2.z,b2.z,b2.z}));
//
//  c1=Addv4(c1,Mulv4(a3,(vec4){b3.z,b3.z,b3.z,b3.z}));
//
//  c1=Addv4(c1,Mulv4(a4,(vec4){b4.z,b4.z,b4.z,b4.z}));
  /* printf("%f %f %f %f\n",Dotv4(a1,b1),Dotv4(a2,b1),Dotv4(a3,b1),Dotv4(a4,b1)); */ == /* result.v[0] = a.v[0] * b.v[0] + a.v[4] * b.v[1] + a.v[8] * b.v[2] + a.v[12] * b.v[3]; */
//  /* printf("%f %f %f %f\n",Dotv4(a1,b2),Dotv4(a2,b2),Dotv4(a3,b2),Dotv4(a4,b2)); */
//  /* printf("%f %f %f %f\n",Dotv4(a1,b3),Dotv4(a2,b3),Dotv4(a3,b3),Dotv4(a4,b3)); */
//  /* printf("%f %f %f %f\n",Dotv4(a1,b4),Dotv4(a2,b4),Dotv4(a3,b4),Dotv4(a4,b3)); */
//  /* result.v[0] = a.v[0] * b.v[0] + a.v[4] * b.v[1] + a.v[8] * b.v[2] + a.v[12] * b.v[3]; *///a collumn
//  /* result.v[1] = a.v[1] * b.v[0] + a.v[5] * b.v[1] + a.v[9] * b.v[2] + a.v[13] * b.v[3]; */
//  /* result.v[2] = a.v[2] * b.v[0] + a.v[6] * b.v[1] + a.v[10] * b.v[2] + a.v[14] * b.v[3]; */
//  /* result.v[3] = a.v[3] * b.v[0] + a.v[7] * b.v[1] + a.v[11] * b.v[2] + a.v[15] * b.v[3]; */
//  printf("%f %f %f %f\n",c1.x,c1.y,c1.z,c1.w);
//}

upd

upd2

Скрытый текст
#pragma GCC optimize("Ofast,unroll-loops,-ffast-math")
#pragma GCC target("sse")
#include <xmmintrin.h>
#include <wmmintrin.h>
#include <smmintrin.h>
#include <nmmintrin.h>
#include <immintrin.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#pragma pack(1)
typedef float f32;

struct vec4_t
{
    f32 x;
    f32 y;
    f32 z;
    f32 w;
};
typedef struct vec4_t vec4;

struct mat4_t
{
    f32 v[16];
};
typedef struct mat4_t mat4;

vec4 Mulv4(vec4 a, vec4 b)
{
    return (vec4){a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w};
}
vec4 Addv4(const vec4 a, const vec4 b)
{
    return (vec4){a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w};
}

vec4 Processing(vec4 c1,vec4 a,vec4 b,int shift)
{
    return Addv4(c1,Mulv4(a,b));
}

vec4 TakeIting(vec4 c1,const float *a,const float *b,int shiftA,int ShapeShifter)
{
  return Processing(c1,(vec4){*(a+shiftA),*(a+shiftA+1),*(a+shiftA+2),*(a+shiftA+3)},(vec4){*(b+ShapeShifter),*(b+ShapeShifter),*(b+ShapeShifter),*(b+ShapeShifter)},ShapeShifter);
}

float* Seting(float *a,int shift,vec4 b)
{
  *(a+shift)=b.x;
  *(a+shift+1)=b.y;
  *(a+shift+2)=b.z;
  *(a+shift+3)=b.w;
  return a;
}

vec4 GetingSum(vec4 c1,const float *a,const float *b,int ShapeShifter)
{
    c1=TakeIting(c1,a,b,0<<2,ShapeShifter+0);
    c1=TakeIting(c1,a,b,1<<2,ShapeShifter+1);
    c1=TakeIting(c1,a,b,2<<2,ShapeShifter+2);
    c1=TakeIting(c1,a,b,3<<2,ShapeShifter+3);
    return c1;
}

vec4 Proc2(vec4 c1,float *result,const float *a,const float *b,int shiftA,int ShapeShifter)
{
    c1=GetingSum((vec4){0,0,0,0},a,b,ShapeShifter);
    Seting(result,shiftA,c1);
    return c1;
}

void atTheTestMatMul(float *result,const float *a,const float *b)
{
    vec4 c1;
    c1=Proc2(c1,result,a,b,0<<2,0<<2);
    c1=Proc2(c1,result,a,b,1<<2,1<<2);
    c1=Proc2(c1,result,a,b,2<<2,2<<2);
    c1=Proc2(c1,result,a,b,3<<2,3<<2);
}

int main()
{
    mat4 a=(mat4){
    2,9,40,5,
    8,6,5,6,
    8,9,7,4,
    7,5,3,10
  };
  
  mat4 b=(mat4){
    50,30,88,70,
    85,100,0,10,
    89,65,50,60,
    99,45,14,80
  };
  struct timespec Ta,Tb;
  
  float GlobalTime=0;
  float localTime=0;
    mat4 c;

  clock_gettime(CLOCK_MONOTONIC,&Ta);
  atTheTestMatMul(&c.v[0],&a.v[0],&b.v[0]);
  clock_gettime(CLOCK_MONOTONIC,&Tb);
  localTime=(float)(Tb.tv_nsec - Ta.tv_nsec) / 1000000 +(float)(Tb.tv_sec - Ta.tv_sec);
  printf("%f\n",localTime);
  
//printf(
// "%f %f %f %f \n%f %f %f %f \n%f %f %f %f \n%f %f %f %f \n",
	 //c.v[0],  c.v[1],  c.v[2],  c.v[3],
	 //c.v[4],  c.v[5],  c.v[6],  c.v[7],
	 //c.v[8],  c.v[9],  c.v[10], c.v[11],
	 //c.v[12], c.v[13], c.v[14], c.v[15]
	 //);
  return 0;
}

Ресурсы

*https://www.mathsisfun.com/algebra/vectors-dot-product.html

https://www.mathsisfun.com/algebra/matrix-calculator.html

**https://en.wikipedia.org/wiki/Single_instruction,_multiple_data

http://www.club155.ru/x86cmdsimd/MOVUPS

https://en.wikipedia.org/wiki/Matrix_multiplication

Tags:
Hubs:
Total votes 20: ↑5 and ↓15-8
Comments74

Articles