SORU
5 Aralık 2011, PAZARTESİ


Nasıl bir döngü başına 4 Flop teorik maksimum elde ederim?

Nasıl 4 kayan nokta işlemleri teorik en yüksek performans (çift hassasiyetli) döngüsü başına 86-64 modern bir Intel işlemci üzerinde elde edilebilir?

Anladığım kadarıyla al 3 ay için bir sse add 5 döngü için mul tam en modern Intel işlemciler (bkz: örneğin Agner Fog's 'Instruction Tables' ). Bir boru hattı nedeniyle eğer algoritma en az 3 bağımsız özetler varsa 1 add döngüsü başına bir verimlilik elde edebilirsiniz. Yana doğru yola addpd olarak skaler addsd sürümleri ve sse kayıtları içerebilir 2 double'nın aktarımı olabilir kadar 2 flop başına döngüsü. Ayrıca gibi görünüyor (her ne kadar ben hiç görmedim herhangi bir şekilde doktor bu) addmul'ler olabilir idam paralel veren bir teorik maksimum verimi 4 flop başına döngüsü.

Ancak, basit c/c programı ile performans çoğaltmak mümkün değil ettik. Benim en iyi girişimi hakkında 2.7 flop/devir sonuçlandı. Eğer herkes maksimum performans gösteren basit c/c veya çevirici programı katkıda eğer çok minnettar kalırım.

Benim girişimi:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/time.h>

double stoptime(void) {
   struct timeval t;
   gettimeofday(&t,NULL);
   return (double) t.tv_sec   t.tv_usec/1000000.0;
}

double addmul(double add, double mul, int ops){
   // need to initialise differently otherwise compiler might optimise away
   double sum1=0.1, sum2=-0.1, sum3=0.2, sum4=-0.2, sum5=0.0;
   double mul1=1.0, mul2= 1.1, mul3=1.2, mul4= 1.3, mul5=1.4;
   int loops=ops/10;          // we have 10 floating point ops inside the loop
   double expected = 5.0*add*loops   (sum1 sum2 sum3 sum4 sum5)
                 pow(mul,loops)*(mul1 mul2 mul3 mul4 mul5);

   for(int i=0; i<loops; i  ) {
      mul1*=mul; mul2*=mul; mul3*=mul; mul4*=mul; mul5*=mul;
      sum1 =add; sum2 =add; sum3 =add; sum4 =add; sum5 =add;
   }
   return  sum1 sum2 sum3 sum4 sum5 mul1 mul2 mul3 mul4 mul5 - expected;
}

int main(int argc, char** argv) {
   if(argc!=2) {
      printf("usage: %s <num>\n", argv[0]);
      printf("number of operations: <num> millions\n");
      exit(EXIT_FAILURE);
   }
   int n=atoi(argv[1])*1000000;
   if(n<=0) n=1000;

   double x=M_PI;
   double y=1.0 1e-8;
   double t=stoptime();
   x=addmul(x,y,n);
   t=stoptime()-t;
   printf("addmul:\t %.3f s, %.3f Gflops, res=%f\n",t,(double)n/t/1e9,x);

   return EXIT_SUCCESS;
}

Derlenmiş

g   -O2 -march=native addmul.cpp ; ./a.out 1000

üreten Intel Core üzerinde aşağıdaki çıktıyı ı5-750, 2.66 GHz

addmul:  0.270 s, 3.707 Gflops, res=1.326463

yani döngü başına sadece 1.4 flop. Çevirici kod ile g -S -O2 -march=native -masm=intel addmul.cpp ana döngü gibi görünüyor benim için uygun:

.L4:
inc eax
mulsd   xmm8, xmm3
mulsd   xmm7, xmm3
mulsd   xmm6, xmm3
mulsd   xmm5, xmm3
mulsd   xmm1, xmm3
addsd   xmm13, xmm2
addsd   xmm12, xmm2
addsd   xmm11, xmm2
addsd   xmm10, xmm2
addsd   xmm9, xmm2
cmp eax, ebx
jne .L4

Paketli sürümleri ile skaler sürümleri (addpd mulpd) değişen yürütme zamanı değiştirmeden flop sayısı çift olur ve döngü başına 2.8 flop sadece kısa olsun diye. Döngü başına 4 flop elde eden herhangi bir basit örnek?

Düzenleme:

Mysticial tarafından program güzel, küçük, işte benim sonuçlar (sadece birkaç saniye için olsa çalıştırın):

  • gcc -O2 -march=nocona: 10.66 Gflops (2.1 flop/döngüsü) 5.6 Gflops
  • cl /O2, openmp kaldırıldı: 10.66 Gflops (3.8 flop/döngüsü) 10.1 Gflops

Biraz karmaşık ama benim sonuçlar çok uzak gibi görünür:

  • gcc -O2 ile bağımsız kayan nokta işlemleri sırasını değiştirir alternatif amacı addpd mulpd'In mümkünse. Aynı durum 36* *için.

  • gcc -O2 -march=nocona tanımlı olarak fp işlemler sırası tutmak gibi görünüyor C kaynak.

  • cl /O2 64-bit derleyici SDK for Windows 7 döngü-çözümü otomatik olarak yapar ve denemek ve operasyonları düzenlemek gibi görünüyor 3 addpd'ın 3 mulpd'nun (en azından benim ile diğer gruplar sistem ve basit bir program benim için).

  • Benim Core i5 750 (Nahelem architecture) alternatif gibi add ve mul yok ve mümkün görünüyor buna paralel olarak, her iki operasyonu için. Ancak, eğer 3 gruplanmış eğer aniden gibi çalışır sihirli.

  • Diğer mimariler (muhtemelen Sandy Bridge ve diğerleri) görünür bir sorun olmadan paralel/mul Ekle icra edebilir Kurul, kodu başka.

  • İtiraf etmek zor, ama benim sistem olsa da cl /O2 çok daha iyi bir iş yok benim sistem için düşük seviyede operasyonları optimize ve zirveye yakın elde küçük c yukarıdaki örnekte performans. Arasında ölçtüm 1.85-2.01 flop/döngüsü (saat kullanmış() olmayan kesin olan Windows Sanırım, daha iyi bir çekim - teşekkürler Mackie Messer) kullanmanız gerekir.

  • En iyi ben gcc ile yönetilen el ile döngü sonsuza ayarlamak içindi üç kişilik gruplar halinde ekleme ve çarpılması. İle g -O2 -march=nocona addmul_unroll.cpp En iyi ihtimalle 1.8 flop karşılık gelen 0.207s, 4.825 Gflops/devir alıyorum şimdi oldukça mutluyum.

C kodu for döngü ile değiştirdim

   for(int i=0; i<loops/3; i  ) {
      mul1*=mul; mul2*=mul; mul3*=mul;
      sum1 =add; sum2 =add; sum3 =add;
      mul4*=mul; mul5*=mul; mul1*=mul;
      sum4 =add; sum5 =add; sum1 =add;

      mul2*=mul; mul3*=mul; mul4*=mul;
      sum2 =add; sum3 =add; sum4 =add;
      mul5*=mul; mul1*=mul; mul2*=mul;
      sum5 =add; sum1 =add; sum2 =add;

      mul3*=mul; mul4*=mul; mul5*=mul;
      sum3 =add; sum4 =add; sum5 =add;
   }

ve Meclis gibi görünüyor

.L4:
mulsd   xmm8, xmm3
mulsd   xmm7, xmm3
mulsd   xmm6, xmm3
addsd   xmm13, xmm2
addsd   xmm12, xmm2
addsd   xmm11, xmm2
mulsd   xmm5, xmm3
mulsd   xmm1, xmm3
mulsd   xmm8, xmm3
addsd   xmm10, xmm2
addsd   xmm9, xmm2
addsd   xmm13, xmm2
...

CEVAP
5 Aralık 2011, PAZARTESİ


Önce bu tam olarak görev yaptım. Ama esas güç tüketimi ve CPU sıcaklıkları ölçmek için. Aşağıdaki kod oldukça uzun olan) benim Çekirdek optimum yakın i7 2600K sağlıyor.

Burada el ile büyük miktardır not için önemli şey döngü çözümü çarpar bu dönüşümlü olarak ve ekler...

Benim GitHub bulunabilir tüm proje: https://github.com/Mysticial/Flops

Uyarı:

Eğer bu derleme çalışma, CPU sıcaklıkları dikkat etmeye karar verirseniz!!!
Aşırı ısınmasına yok emin olun. Ve emin ol CPU azaltma sonuçları etkilemez!

Ayrıca, bu kodu çalıştırmanın sonucu ne olursa olsun ben sorumluluk almam.

Notlar:

  • Bu kod x 64 için optimize edilmiştir. 86 bu derleme için yeterli kayıtları yok.
  • Bu kod, Visual Studio 2010/2012 ve GCC 4.6 üzerinde çalışmak için test edilmiştir.
    ICC 11 (Intel Derleyici 11) şaşırtıcı derecede iyi sorun derleme vardır.
  • Bu ön KG'DEN işlemciler için. Intel Haswell ve AMD Bulldozer işlemciler üzerinde tepe FLOP (ve daha sonra) elde etmek için, (Çarpma Erimiş) talimatları ihtiyaç duyulacak KG'DEN. Bu kriter kapsamı dışındadır.

#include <emmintrin.h>
#include <omp.h>
#include <iostream>
using namespace std;

typedef unsigned long long uint64;

double test_dp_mac_SSE(double x,double y,uint64 iterations){
    register __m128d r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,rA,rB,rC,rD,rE,rF;

    //  Generate starting data.
    r0 = _mm_set1_pd(x);
    r1 = _mm_set1_pd(y);

    r8 = _mm_set1_pd(-0.0);

    r2 = _mm_xor_pd(r0,r8);
    r3 = _mm_or_pd(r0,r8);
    r4 = _mm_andnot_pd(r8,r0);
    r5 = _mm_mul_pd(r1,_mm_set1_pd(0.37796447300922722721));
    r6 = _mm_mul_pd(r1,_mm_set1_pd(0.24253562503633297352));
    r7 = _mm_mul_pd(r1,_mm_set1_pd(4.1231056256176605498));
    r8 = _mm_add_pd(r0,_mm_set1_pd(0.37796447300922722721));
    r9 = _mm_add_pd(r1,_mm_set1_pd(0.24253562503633297352));
    rA = _mm_sub_pd(r0,_mm_set1_pd(4.1231056256176605498));
    rB = _mm_sub_pd(r1,_mm_set1_pd(4.1231056256176605498));

    rC = _mm_set1_pd(1.4142135623730950488);
    rD = _mm_set1_pd(1.7320508075688772935);
    rE = _mm_set1_pd(0.57735026918962576451);
    rF = _mm_set1_pd(0.70710678118654752440);

    uint64 iMASK = 0x800fffffffffffffull;
    __m128d MASK = _mm_set1_pd(*(double*)&iMASK);
    __m128d vONE = _mm_set1_pd(1.0);

    uint64 c = 0;
    while (c < iterations){
        size_t i = 0;
        while (i < 1000){
            //  Here's the meat - the part that really matters.

            r0 = _mm_mul_pd(r0,rC);
            r1 = _mm_add_pd(r1,rD);
            r2 = _mm_mul_pd(r2,rE);
            r3 = _mm_sub_pd(r3,rF);
            r4 = _mm_mul_pd(r4,rC);
            r5 = _mm_add_pd(r5,rD);
            r6 = _mm_mul_pd(r6,rE);
            r7 = _mm_sub_pd(r7,rF);
            r8 = _mm_mul_pd(r8,rC);
            r9 = _mm_add_pd(r9,rD);
            rA = _mm_mul_pd(rA,rE);
            rB = _mm_sub_pd(rB,rF);

            r0 = _mm_add_pd(r0,rF);
            r1 = _mm_mul_pd(r1,rE);
            r2 = _mm_sub_pd(r2,rD);
            r3 = _mm_mul_pd(r3,rC);
            r4 = _mm_add_pd(r4,rF);
            r5 = _mm_mul_pd(r5,rE);
            r6 = _mm_sub_pd(r6,rD);
            r7 = _mm_mul_pd(r7,rC);
            r8 = _mm_add_pd(r8,rF);
            r9 = _mm_mul_pd(r9,rE);
            rA = _mm_sub_pd(rA,rD);
            rB = _mm_mul_pd(rB,rC);

            r0 = _mm_mul_pd(r0,rC);
            r1 = _mm_add_pd(r1,rD);
            r2 = _mm_mul_pd(r2,rE);
            r3 = _mm_sub_pd(r3,rF);
            r4 = _mm_mul_pd(r4,rC);
            r5 = _mm_add_pd(r5,rD);
            r6 = _mm_mul_pd(r6,rE);
            r7 = _mm_sub_pd(r7,rF);
            r8 = _mm_mul_pd(r8,rC);
            r9 = _mm_add_pd(r9,rD);
            rA = _mm_mul_pd(rA,rE);
            rB = _mm_sub_pd(rB,rF);

            r0 = _mm_add_pd(r0,rF);
            r1 = _mm_mul_pd(r1,rE);
            r2 = _mm_sub_pd(r2,rD);
            r3 = _mm_mul_pd(r3,rC);
            r4 = _mm_add_pd(r4,rF);
            r5 = _mm_mul_pd(r5,rE);
            r6 = _mm_sub_pd(r6,rD);
            r7 = _mm_mul_pd(r7,rC);
            r8 = _mm_add_pd(r8,rF);
            r9 = _mm_mul_pd(r9,rE);
            rA = _mm_sub_pd(rA,rD);
            rB = _mm_mul_pd(rB,rC);

            i  ;
        }

        //  Need to renormalize to prevent denormal/overflow.
        r0 = _mm_and_pd(r0,MASK);
        r1 = _mm_and_pd(r1,MASK);
        r2 = _mm_and_pd(r2,MASK);
        r3 = _mm_and_pd(r3,MASK);
        r4 = _mm_and_pd(r4,MASK);
        r5 = _mm_and_pd(r5,MASK);
        r6 = _mm_and_pd(r6,MASK);
        r7 = _mm_and_pd(r7,MASK);
        r8 = _mm_and_pd(r8,MASK);
        r9 = _mm_and_pd(r9,MASK);
        rA = _mm_and_pd(rA,MASK);
        rB = _mm_and_pd(rB,MASK);
        r0 = _mm_or_pd(r0,vONE);
        r1 = _mm_or_pd(r1,vONE);
        r2 = _mm_or_pd(r2,vONE);
        r3 = _mm_or_pd(r3,vONE);
        r4 = _mm_or_pd(r4,vONE);
        r5 = _mm_or_pd(r5,vONE);
        r6 = _mm_or_pd(r6,vONE);
        r7 = _mm_or_pd(r7,vONE);
        r8 = _mm_or_pd(r8,vONE);
        r9 = _mm_or_pd(r9,vONE);
        rA = _mm_or_pd(rA,vONE);
        rB = _mm_or_pd(rB,vONE);

        c  ;
    }

    r0 = _mm_add_pd(r0,r1);
    r2 = _mm_add_pd(r2,r3);
    r4 = _mm_add_pd(r4,r5);
    r6 = _mm_add_pd(r6,r7);
    r8 = _mm_add_pd(r8,r9);
    rA = _mm_add_pd(rA,rB);

    r0 = _mm_add_pd(r0,r2);
    r4 = _mm_add_pd(r4,r6);
    r8 = _mm_add_pd(r8,rA);

    r0 = _mm_add_pd(r0,r4);
    r0 = _mm_add_pd(r0,r8);


    //  Prevent Dead Code Elimination
    double out = 0;
    __m128d temp = r0;
    out  = ((double*)&temp)[0];
    out  = ((double*)&temp)[1];

    return out;
}

void test_dp_mac_SSE(int tds,uint64 iterations){

    double *sum = (double*)malloc(tds * sizeof(double));
    double start = omp_get_wtime();

#pragma omp parallel num_threads(tds)
    {
        double ret = test_dp_mac_SSE(1.1,2.1,iterations);
        sum[omp_get_thread_num()] = ret;
    }

    double secs = omp_get_wtime() - start;
    uint64 ops = 48 * 1000 * iterations * tds * 2;
    cout << "Seconds = " << secs << endl;
    cout << "FP Ops  = " << ops << endl;
    cout << "FLOPs   = " << ops / secs << endl;

    double out = 0;
    int c = 0;
    while (c < tds){
        out  = sum[c  ];
    }

    cout << "sum = " << out << endl;
    cout << endl;

    free(sum);
}

int main(){
    //  (threads, iterations)
    test_dp_mac_SSE(8,10000000);

    system("pause");
}

Çıkış (1 iplik, 10000000 tekrarlamalar) - Visual Studio ile Derlenmiş 2010 SP1 x 64 Sürümü:

Seconds = 55.5104
FP Ops  = 960000000000
FLOPs   = 1.7294e 010
sum = 2.22652

Makine bir Çekirdek 2600K @ 4.4 GHz i7. Teorik SSE tepe = 4.4 GHz * 4 flopİle 17,6 GFlops. Bu kod sağlar17.3 GFlops- fena değil.

Çıkış (8 konuları, 10000000 tekrarlamalar) - Visual Studio ile Derlenmiş 2010 SP1 x 64 Sürümü:

Seconds = 117.202
FP Ops  = 7680000000000
FLOPs   = 6.55279e 010
sum = 17.8122

Teorik SSE tepe çekirdek 4.4 * = 4 GHz flop * 470.4 GFlops.Gerçek65.5 GFlops.


Hadi bir adım ileri atın. AVX...

#include <immintrin.h>
#include <omp.h>
#include <iostream>
using namespace std;

typedef unsigned long long uint64;

double test_dp_mac_AVX(double x,double y,uint64 iterations){
    register __m256d r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,rA,rB,rC,rD,rE,rF;

    //  Generate starting data.
    r0 = _mm256_set1_pd(x);
    r1 = _mm256_set1_pd(y);

    r8 = _mm256_set1_pd(-0.0);

    r2 = _mm256_xor_pd(r0,r8);
    r3 = _mm256_or_pd(r0,r8);
    r4 = _mm256_andnot_pd(r8,r0);
    r5 = _mm256_mul_pd(r1,_mm256_set1_pd(0.37796447300922722721));
    r6 = _mm256_mul_pd(r1,_mm256_set1_pd(0.24253562503633297352));
    r7 = _mm256_mul_pd(r1,_mm256_set1_pd(4.1231056256176605498));
    r8 = _mm256_add_pd(r0,_mm256_set1_pd(0.37796447300922722721));
    r9 = _mm256_add_pd(r1,_mm256_set1_pd(0.24253562503633297352));
    rA = _mm256_sub_pd(r0,_mm256_set1_pd(4.1231056256176605498));
    rB = _mm256_sub_pd(r1,_mm256_set1_pd(4.1231056256176605498));

    rC = _mm256_set1_pd(1.4142135623730950488);
    rD = _mm256_set1_pd(1.7320508075688772935);
    rE = _mm256_set1_pd(0.57735026918962576451);
    rF = _mm256_set1_pd(0.70710678118654752440);

    uint64 iMASK = 0x800fffffffffffffull;
    __m256d MASK = _mm256_set1_pd(*(double*)&iMASK);
    __m256d vONE = _mm256_set1_pd(1.0);

    uint64 c = 0;
    while (c < iterations){
        size_t i = 0;
        while (i < 1000){
            //  Here's the meat - the part that really matters.

            r0 = _mm256_mul_pd(r0,rC);
            r1 = _mm256_add_pd(r1,rD);
            r2 = _mm256_mul_pd(r2,rE);
            r3 = _mm256_sub_pd(r3,rF);
            r4 = _mm256_mul_pd(r4,rC);
            r5 = _mm256_add_pd(r5,rD);
            r6 = _mm256_mul_pd(r6,rE);
            r7 = _mm256_sub_pd(r7,rF);
            r8 = _mm256_mul_pd(r8,rC);
            r9 = _mm256_add_pd(r9,rD);
            rA = _mm256_mul_pd(rA,rE);
            rB = _mm256_sub_pd(rB,rF);

            r0 = _mm256_add_pd(r0,rF);
            r1 = _mm256_mul_pd(r1,rE);
            r2 = _mm256_sub_pd(r2,rD);
            r3 = _mm256_mul_pd(r3,rC);
            r4 = _mm256_add_pd(r4,rF);
            r5 = _mm256_mul_pd(r5,rE);
            r6 = _mm256_sub_pd(r6,rD);
            r7 = _mm256_mul_pd(r7,rC);
            r8 = _mm256_add_pd(r8,rF);
            r9 = _mm256_mul_pd(r9,rE);
            rA = _mm256_sub_pd(rA,rD);
            rB = _mm256_mul_pd(rB,rC);

            r0 = _mm256_mul_pd(r0,rC);
            r1 = _mm256_add_pd(r1,rD);
            r2 = _mm256_mul_pd(r2,rE);
            r3 = _mm256_sub_pd(r3,rF);
            r4 = _mm256_mul_pd(r4,rC);
            r5 = _mm256_add_pd(r5,rD);
            r6 = _mm256_mul_pd(r6,rE);
            r7 = _mm256_sub_pd(r7,rF);
            r8 = _mm256_mul_pd(r8,rC);
            r9 = _mm256_add_pd(r9,rD);
            rA = _mm256_mul_pd(rA,rE);
            rB = _mm256_sub_pd(rB,rF);

            r0 = _mm256_add_pd(r0,rF);
            r1 = _mm256_mul_pd(r1,rE);
            r2 = _mm256_sub_pd(r2,rD);
            r3 = _mm256_mul_pd(r3,rC);
            r4 = _mm256_add_pd(r4,rF);
            r5 = _mm256_mul_pd(r5,rE);
            r6 = _mm256_sub_pd(r6,rD);
            r7 = _mm256_mul_pd(r7,rC);
            r8 = _mm256_add_pd(r8,rF);
            r9 = _mm256_mul_pd(r9,rE);
            rA = _mm256_sub_pd(rA,rD);
            rB = _mm256_mul_pd(rB,rC);

            i  ;
        }

        //  Need to renormalize to prevent denormal/overflow.
        r0 = _mm256_and_pd(r0,MASK);
        r1 = _mm256_and_pd(r1,MASK);
        r2 = _mm256_and_pd(r2,MASK);
        r3 = _mm256_and_pd(r3,MASK);
        r4 = _mm256_and_pd(r4,MASK);
        r5 = _mm256_and_pd(r5,MASK);
        r6 = _mm256_and_pd(r6,MASK);
        r7 = _mm256_and_pd(r7,MASK);
        r8 = _mm256_and_pd(r8,MASK);
        r9 = _mm256_and_pd(r9,MASK);
        rA = _mm256_and_pd(rA,MASK);
        rB = _mm256_and_pd(rB,MASK);
        r0 = _mm256_or_pd(r0,vONE);
        r1 = _mm256_or_pd(r1,vONE);
        r2 = _mm256_or_pd(r2,vONE);
        r3 = _mm256_or_pd(r3,vONE);
        r4 = _mm256_or_pd(r4,vONE);
        r5 = _mm256_or_pd(r5,vONE);
        r6 = _mm256_or_pd(r6,vONE);
        r7 = _mm256_or_pd(r7,vONE);
        r8 = _mm256_or_pd(r8,vONE);
        r9 = _mm256_or_pd(r9,vONE);
        rA = _mm256_or_pd(rA,vONE);
        rB = _mm256_or_pd(rB,vONE);

        c  ;
    }

    r0 = _mm256_add_pd(r0,r1);
    r2 = _mm256_add_pd(r2,r3);
    r4 = _mm256_add_pd(r4,r5);
    r6 = _mm256_add_pd(r6,r7);
    r8 = _mm256_add_pd(r8,r9);
    rA = _mm256_add_pd(rA,rB);

    r0 = _mm256_add_pd(r0,r2);
    r4 = _mm256_add_pd(r4,r6);
    r8 = _mm256_add_pd(r8,rA);

    r0 = _mm256_add_pd(r0,r4);
    r0 = _mm256_add_pd(r0,r8);

    //  Prevent Dead Code Elimination
    double out = 0;
    __m256d temp = r0;
    out  = ((double*)&temp)[0];
    out  = ((double*)&temp)[1];
    out  = ((double*)&temp)[2];
    out  = ((double*)&temp)[3];

    return out;
}

void test_dp_mac_AVX(int tds,uint64 iterations){

    double *sum = (double*)malloc(tds * sizeof(double));
    double start = omp_get_wtime();

#pragma omp parallel num_threads(tds)
    {
        double ret = test_dp_mac_AVX(1.1,2.1,iterations);
        sum[omp_get_thread_num()] = ret;
    }

    double secs = omp_get_wtime() - start;
    uint64 ops = 48 * 1000 * iterations * tds * 4;
    cout << "Seconds = " << secs << endl;
    cout << "FP Ops  = " << ops << endl;
    cout << "FLOPs   = " << ops / secs << endl;

    double out = 0;
    int c = 0;
    while (c < tds){
        out  = sum[c  ];
    }

    cout << "sum = " << out << endl;
    cout << endl;

    free(sum);
}

int main(){
    //  (threads, iterations)
    test_dp_mac_AVX(8,10000000);

    system("pause");
}

Çıkış (1 iplik, 10000000 tekrarlamalar) - Visual Studio ile Derlenmiş 2010 SP1 x 64 Sürümü:

Seconds = 57.4679
FP Ops  = 1920000000000
FLOPs   = 3.34099e 010
sum = 4.45305

Teorik AVX tepe = GHz * 4.4 flop 835.2 GFlops. Gerçek33.4 GFlops.

Çıkış (8 konuları, 10000000 tekrarlamalar) - Visual Studio ile Derlenmiş 2010 SP1 x 64 Sürümü:

Seconds = 111.119
FP Ops  = 15360000000000
FLOPs   = 1.3823e 011
sum = 35.6244

Teorik AVX tepe * 4 çekirdek 4.4 * = GHz 8 flop140.8 GFlops.Gerçek138.2 GFlops.


Bazı açıklamalar için:

Performans kritik haliyle 48 yönergeleri iç döngü içinde. 12 talimatlar her 4 blok içine kırık olduğunu fark edeceksiniz. Bu talimatları 12 blok, her biri birbirinden tamamen bağımsız ve yürütmek için ortalama 6 devir almak.

Talimatları ve döngüleri 6 sayı kullanımı arasında 12 var. Çarpma gecikme 5 döngü, sadece gecikme tezgahları önlemek için yeterli değil.

Normalleşme adımı/underflowing üzerinde veri tutmak için gereklidir. Bu-hiçbir şey yapmadan yavaş yavaş kod/veri büyüklüğünü artırmak veya azaltmak için bu gereklidir.

Aslında olası tüm sıfır kullanım ve normalleşme adımı kurtulmak eğer bundan daha iyisini. Kriter güç tüketimi ve sıcaklık ölçmek için yazdım çünkü, ancak,Flop"", sıfır yerine . veri gerçek olduğundan emin olmak zorundaydım - yürütme birimleri çok iyi özel durum işleme daha az güç kullanımı ve daha az ısı üretmek için sıfır olabilir.


Diğer Sonuçlar:

  • Intel @ Core i7 920 3.5 GHz
  • Windows 7 64 bit
  • Visual Studio 2010 SP1 x 64 Sürümü

Konular: 1

Seconds = 72.1116
FP Ops  = 960000000000
FLOPs   = 1.33127e 010
sum = 2.22652

Teorik SSE en yüksek: 4 flop * 3.5 = GHz14.0 GFlops. Gerçek13.3 GFlops.

Konular: 8

Seconds = 149.576
FP Ops  = 7680000000000
FLOPs   = 5.13452e 010
sum = 17.8122

Teorik SSE en yüksek: 4 * çekirdek * 3.5 = GHz . 4 flop ^strong>56.0 GFlops. Gerçek51.3 GFlops.

İşlemci benim temps 76C çok parçacıklı kaçarken vuruldu! Eğer bu, emin olmak için çalışıyorsa sonuçları CPU azaltma etkilenmez.


  • 2 x Intel X5482 Harpertown @ 3.2 GHz getirdiğini belirtti
  • Ubuntu Linux 10 64
  • 4.5.2 x 64 - (- - msse3 -O2 fopenmp) GCC

Konular: 1

Seconds = 78.3357
FP Ops  = 960000000000
FLOPs   = 1.22549e 10
sum = 2.22652

Teorik SSE en yüksek: 4 flop * 3.2 = GHz12.8 GFlops. Gerçek12.3 GFlops.

Konular: 8

Seconds = 78.4733
FP Ops  = 7680000000000
FLOPs   = 9.78676e 10
sum = 17.8122

Teorik SSE en yüksek: 8 * çekirdek * 3.2 = GHz . 4 flop ^strong>102.4 GFlops. Gerçek97.9 GFlops.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • HowtoDrawAndPaint

    HowtoDrawAnd

    24 EKİM 2010
  • Jeremy Stark

    Jeremy Stark

    23 Mayıs 2010
  • MuscleProdigyTV

    MuscleProdig

    8 Ocak 2011