2015-07-29 6 views
8

मैंने अपने आप से पूछा कि समांतर कार्यक्रम के प्रदर्शन (फ्लॉप में) को मापने का सबसे अच्छा तरीका क्या होगा। मैंने papi_flops के बारे में पढ़ा। ऐसा लगता है कि एक धारावाहिक कार्यक्रम के लिए ठीक काम करता है। लेकिन मुझे नहीं पता कि मैं समानांतर कार्यक्रम के समग्र प्रदर्शन को कैसे माप सकता हूं।समांतर कार्यक्रमों (पापी के साथ)

मैं नीचे दिए गए उदाहरण में अपने उदाहरण में ब्लैस/लैपैक फ़ंक्शन के प्रदर्शन को मापना चाहता हूं। लेकिन मैं अन्य कार्यों को भी मापना चाहता हूं, विशेष रूप से कार्य जहां ऑपरेशन की संख्या ज्ञात नहीं है। (जीएमएम के मामले में ओप्स ज्ञात हैं (ओप (जीएमएम) = 2 * एन^3), इसलिए मैं संचालन की संख्या और निष्पादन समय के कार्य के रूप में प्रदर्शन की गणना कर सकता हूं।) लाइब्रेरी (मैं इंटेल का उपयोग कर रहा हूं एमकेएल) धागे स्वचालित रूप से spawn। तो मैं व्यक्तिगत रूप से प्रत्येक धागे के प्रदर्शन को माप नहीं सकता और फिर इसे कम कर सकता हूं।

#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; 
} 

यह (मैट्रिक्स आकार 200 के लिए) एक उत्पादन है:

यह मेरा उदाहरण है

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 

हम निष्पादन समय के लिए देख सकते हैं, कि समारोह GEMM तराजू। लेकिन फ्लॉप जो मैं माप रहा हूं केवल थ्रेड 0 का प्रदर्शन है।

मेरा प्रश्न है: मैं समग्र प्रदर्शन को कैसे माप सकता हूं? मैं किसी भी इनपुट के लिए आभारी हूँ।

+0

उम्म .. प्रत्येक धागे के लिए फ्लॉप मापें और फिर उन्हें एक साथ जोड़ें? – Voo

+0

मैं यह कैसे कर सकता हूं? ब्लैस लाइब्रेरी धागे बनाते हैं। तो, समांतर क्षेत्र फ़ंक्शन कॉल dgemm के अंदर है। मेरे पास व्यक्तिगत धागे तक पहुंच नहीं है। बेशक मैं ब्लैस लाइब्रेरी को फिर से कंपाइल कर सकता हूं और फिर समांतर क्षेत्र के अंदर प्रत्येक थ्रेड के लिए प्रदर्शन को मापता हूं (एमकेएल के मामले में संभव नहीं है, ठीक है, मैं ओपनब्लैस पर स्विच कर सकता हूं)। लेकिन यही वह है जिसे मैं टालना चाहता हूं। – Sebastian

+0

क्या आप फ्लॉप की संख्या दिखा सकते हैं? शायद mflops सभी धागे में औसत है? –

उत्तर

4

सबसे पहले, मैं सिर्फ उत्सुक हूं - आपको फ्लॉप की आवश्यकता क्यों है? क्या आपको बस परवाह नहीं है कि कितना समय लिया जाता है? या शायद अन्य बीएलएएस पुस्तकालयों की तुलना में लिया गया समय?

पीएपीआई धागा अपने आप पर बहुत मदद नहीं है।

मैं क्या करूँगा फ़ंक्शन कॉल के आसपास मापता है और देखें कि यह कितने थ्रेडों के साथ बदलता है। इसे भौतिक कोर की तुलना में अधिक धागे नहीं पैदा करना चाहिए (एचटी यहां अच्छा नहीं है)। फिर, यदि मैट्रिक्स काफी बड़ा है, और मशीन लोड नहीं होती है, तो समय को केवल धागे की संख्या से विभाजित करना चाहिए। उदा।, 4 कोर से 10 सेकंड 2.5 सेकंड बनना चाहिए।

इसके अलावा, 2 चीजें हैं जो आप वास्तव में इसे मापने के लिए कर सकते हैं:
1. जो भी आप अभी उपयोग करते हैं उसका उपयोग करें लेकिन बीएलएएस कोड के आस-पास अपना प्रारंभ/अंत माप कोड डालें। ऐसा करने का एक तरीका (लिनक्स में) एक lib को प्री-लोड करना है जो pthread_start को परिभाषित करता है और अपने स्वयं के फ़ंक्शंस का उपयोग करता है जो मूल को कॉल करते हैं लेकिन कुछ अतिरिक्त माप करते हैं। जब प्रक्रिया पहले से चल रही है (= trampoline) फ़ंक्शन पॉइंटर को ओवरराइड करने का एक और तरीका। लिनक्स में यह जीओटी/पीएलटी में है और खिड़कियों में यह अधिक जटिल है - लाइब्रेरी की तलाश करें।
2. आप जिस समय देखभाल करते हैं उसमें निष्पादित निर्देशों की संख्या की रिपोर्ट करने के लिए oprofile, या कुछ अन्य प्रोफाइलर का उपयोग करें। या फिर बेहतर, निष्पादित फ्लोटिंग पॉइंट निर्देशों की संख्या की रिपोर्ट करने के लिए। इसके साथ एक छोटी सी समस्या यह है कि एसएसई निर्देश एक समय में 2 या अधिक युगल गुणा कर रहे हैं या जोड़ना चाहते हैं ताकि आपको इसके लिए जिम्मेदार होना पड़े। मुझे लगता है कि आप मान सकते हैं कि वे हमेशा अधिकतम संभव संचालन का उपयोग करते हैं।

+0

सबसे पहले: आपके उत्तर के लिए धन्यवाद! मैं प्रदर्शन और निष्पादन समय को मापना क्यों चाहता हूं? मैं वास्तव में लैपैक के घने ईगेंसोलवर का विश्लेषण करने में रूचि रखता हूं। घने eigensolvers तीन समारोह कहते हैं: 1) tridiagonal रूप में कमी, 2) tridiagonal eigensolver, 3) backtransformation। घने eigensolver की बाधाओं की पहचान करने के लिए समय और प्रदर्शन को मापना आवश्यक है। अगर मेरे पास केवल निष्पादन का समय है, तो उदा। मैं देख सकता था कि मैं कटौती में अधिकतर समय बिताता हूं। लेकिन मुझे नहीं पता कि मैं संसाधनों का कुशलता से उपयोग करता हूं या नहीं। तो मुझे यकीन नहीं है कि यह बाधा है। – Sebastian

+0

आपने इस समस्या के लिए दो प्रकार सुझाए हैं। मैं पहले वाले को पसंद करता हूं। Pthread_create (और pthread_join) को ओवरराइट करना केवल पीएपीआई के साथ काम करने का एकमात्र प्रतीत होता है। रनटाइम पर सूचक को ओवरराइट करना मेरे मामले के लिए समझ में आता है (मेरे पास मेरे कोड में बहुत सारी शुद्धता जांच है, मैं इस भाग को भी मापना नहीं चाहता)। – Sebastian

+0

मैं सिद्धांत को समझ सकता हूं, लेकिन मुझे यकीन नहीं है कि मैं इसे कैसे कार्यान्वित कर सकता हूं। मुझे फ़ंक्शन पॉइंटर को pthread_create पर ओवरराइट करना होगा। इस फ़ंक्शन के अंदर मुझे मूल pthread_create फ़ंक्शन के साथ धागा बनाना है और इसके बाद मुझे मापना शुरू करना है। मुझे सच में यकीन नहीं है कि ओवरराइट किए गए पॉइंटर और मूल सूचक के साथ समस्या का समाधान कैसे करें। इसके लिए मेरा विचार मैक्रोज़ हैं। क्या यह सबसे अच्छा तरीका है? सामान्य में: क्या आपके पास कोई उदाहरण है या क्या आपके पास इसके बारे में अधिक जानने के लिए अनुशंसित पढ़ने की सलाह है? धन्यवाद! – Sebastian