2015-07-29 20 views
8

Kendime, paralel bir programın performansını (flopta) ölçmenin en iyi yolunun ne olacağını sordum. Papi_flops hakkında okudum. Bu seri bir program için iyi çalışıyor gibi görünüyor. Ama paralel bir programın genel performansını nasıl ölçebileceğimi bilmiyorum.Paralel programların genel performansı nasıl ölçülür (papi ile)

Bir blas/lapack işlevinin performansını ölçmek istiyorum. Ama aynı zamanda başka bir fonksiyonu ölçmek istiyorum, özellikle operasyon sayısının bilinmediği fonksiyonlar. (Gemm durumunda ops bilinir (ops (gemm) = 2 * n^3), bu yüzden işlem sayısını ve yürütme süresinin bir fonksiyonu olarak performansı hesaplayabilirdim.) Kütüphane (Intel kullanıyorum MKL) konuları otomatik olarak oluşturur. Bu yüzden, her bir iş parçacığının performansını tek tek ölçemiyorum ve sonra azaltın. Bu işlev GEMM terazi,

1 threads: 200 in 0.001459 sec, 5570.258789 MFLOPS 
2 threads: 200 in 0.000785 sec, 5254.993652 MFLOPS 
4 threads: 200 in 0.000423 sec, 4919.640137 MFLOPS 
8 threads: 200 in 0.000264 sec, 3894.036865 MFLOPS 

Biz yürütme kez görebilir:

#include <stdlib.h>                
#include <stdio.h>                
#include <string.h>                
#include "mkl.h" 
#include "omp.h" 
#include "papi.h"  

int main(int argc, char *argv[])             
{                     
    int i, j, l, k, n, m, idx, iter; 
    int mat, mat_min, mat_max; 
    int threads; 
    double *A, *B, *C; 
    double alpha =1.0, beta=0.0; 

    float rtime1, rtime2, ptime1, ptime2, mflops; 
    long long flpops; 

    #pragma omp parallel 
    { 
    #pragma omp master 
    threads = omp_get_num_threads(); 
    } 

    if(argc < 4){                 
    printf("pass me 3 arguments!\n");            
    return(-1);                 
    }                    
    else                   
    {                    
    mat_min = atoi(argv[1]); 
    mat_max = atoi(argv[2]); 
    iter = atoi(argv[3]);               
    }      

    m = mat_max; n = mat_max; k = mat_max; 

    printf (" Initializing data for matrix multiplication C=A*B for matrix \n" 
      " A(%ix%i) and matrix B(%ix%i)\n\n", m, k, k, n); 

    A = (double *) malloc(m*k * sizeof(double)); 
    B = (double *) malloc(k*n * sizeof(double)); 
    C = (double *) malloc(m*n * sizeof(double)); 

    printf (" Intializing matrix data \n\n"); 
    for (i = 0; i < (m*k); i++) 
    A[i] = (double)(i+1); 
    for (i = 0; i < (k*n); i++) 
    B[i] = (double)(-i-1); 
    memset(C,0,m*n*sizeof(double)); 

    // actual meassurment 
    for(mat=mat_min;mat<=mat_max;mat+=5) 
    { 
    m = mat; n = mat; k = mat; 

    for(idx=-1; idx<iter; idx++){ 
     PAPI_flops(&rtime1, &ptime1, &flpops, &mflops); 
     cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, 
        m, n, k, alpha, A, k, B, n, beta, C, n); 
     PAPI_flops(&rtime2, &ptime2, &flpops, &mflops); 
    } 

    printf("%d threads: %d in %f sec, %f MFLOPS\n",threads,mat,rtime2-rtime1,mflops);fflush(stdout); 
    } 

    printf("Done\n");fflush(stdout); 

    free(A); 
    free(B); 
    free(C); 

    return 0; 
} 

Bu (matris boyutu 200), bir çıkışı olan:

Bu

benim örnektir. Ancak, ölçtüğüm floplar sadece 0 numaralı dişin performansıdır.

Sorum şu: Genel performansı nasıl ölçebilirim? Herhangi bir girdi için minnettarım.

+0

Umm .. Her iş parçacığı için floş ölçün ve sonra bunları birlikte ekleyin? – Voo

+0

Bunu nasıl yapabilirim? Blas kütüphanesi konuları oluşturur. Yani, paralel bölge işlev çağrısı dgemm içinde. Bireysel konulara erişimim yok. Elbette blas kütüphanesini yeniden derleyebilirim ve daha sonra paralel bölgenin içinde her iplik için performansı ölçün (MKL durumunda mümkün değil, tamam OpenBlas'a geçebilirdim). Ama bundan kaçınmak istediğim şey bu. – Sebastian

+0

Flop sayısını gösterir misiniz? Belki mflops tüm iş parçacıklarının ortalamasıdır? –

cevap

4

İlk olarak, merak ediyorum - neden FLOPS'a ihtiyacınız var? Ne kadar zaman aldığın umurunda değil misin? ya da belki diğer BLAS kütüphaneleri ile karşılaştırılan zaman?

PAPI, kendi başına çok fazla yardıma dayanan bir iş parçacığıdır.

Yapacağım şey, işlev çağrısı etrafında ölçmek ve ortaya çıktığı iş parçacığı sayısıyla saatin nasıl değiştiğini görmek. Fiziksel çekirdeklerden daha fazla iplik üretmemelidir (HT burada iyi değildir). Daha sonra, matris yeterince büyükse ve makine yüklü değilse, zaman sadece iplik sayısına bölünmelidir. Ör., 4 çekirdeğin 10 saniyesinin 2.5 saniye olması gerekir. Bunun dışında, gerçekten ölçmek için yapabileceğiniz 2 şey vardır:
1. Şimdi kullandığınız her şeyi kullanın, ancak başlangıç ​​/ bitiş ölçüm kodunuzu BLAS kodu etrafında enjekte edin. Bunu yapmanın bir yolu (linux), pthread_start'ı tanımlayan ve orijinalleri çağıran ancak bazı ekstra ölçümler yapan kendi işlevlerinizi kullanan bir lib ön yüklemesidir. Süreç zaten çalıştığında işlev işaretçisini geçersiz kılmanın başka bir yolu (= trambolin). Linux'ta GOT/PLT'de ve pencerelerde daha karmaşık - bir kütüphane arayın.
2. Baktığınız anda yürütülen talimatların sayısını bildirmek için oprofile veya başka bir profilleyiciyi kullanın. Ya da daha iyisi, yürütülen kayan nokta talimatlarının sayısını bildirmek. Bununla ilgili küçük bir sorun, SSE talimatlarının bir kerede 2 veya daha fazla çift kat artırması veya eklemesidir, dolayısıyla bunu hesaba katmanız gerekir. Her zaman mümkün olan maksimum işlenenleri kullandıklarını düşünebilirsiniz.

+0

Her şeyden önce: Cevabınız için teşekkür ederiz! Neden performans ve yürütme süresini ölçmek istiyorum? Aslında LAPACK'ın yoğun eigensolverini analiz etmekle ilgileniyorum. Yoğun eigensolverler üç fonksiyonu çağırır: 1) tridiagonal forma indirgeme, 2) tridiagonal eigensolver, 3) geri transformasyon. Yoğun eigensolver darboğazlarını tanımlamak için zaman ve performans ölçmek gerekir. Yalnızca yürütme sürem varsa, ör. Azaltmada çoğu zaman harcadığımı görebiliyordum. Ama kaynakları verimli kullanıp kullanmadığımı bilmiyorum. Bu yüzden bu darboğaz olup olmadığından emin olamıyorum. – Sebastian

+0

Bu sorun için iki Varyant önerdiniz. Birinci olanı beğendim. Pthread_create (ve ayrıca pthread_join) üzerine yazmak, PAPI ile çalışmanın tek nedeni gibi görünüyor. Çalışma zamanında işaretçinin üzerine yazmak benim durumum için anlam ifade ediyor (kodumda çok fazla doğruluk kontrolü var, bu kısmı da ölçmek istemiyorum). – Sebastian

+0

Kuramı anlayabiliyorum, ancak bunu nasıl uygulayacağımı bilmiyorum. Pthread_create işlev işaretçisinin üzerine yazmak zorunda kalacaktım. Bu işlevin içinde orijinal pthread_create işleviyle iş parçacığı oluşturmam gerekiyor ve bundan sonra ölçümü başlatmam gerekiyor. Üzerine yazılan işaretçi ve özgün işaretçi ile sorunu nasıl çözeceğinizden emin değilim. Benim fikrim makrolar. En iyi yol bu mu? Genel olarak: Bir örneğiniz var mı yoksa bu konuda daha fazla bilgi edinmek için tavsiye edilen bir okuma tavsiyeniz var mı? Teşekkürler! – Sebastian

İlgili konular