क्या वर्णक्रमीय मानदंड शूटआउट (जीसीसी, इंटेल और अन्य संकलक का उपयोग करके) पर फोर्टन की तुलना में सी धीमा है?


13

यहाँ निष्कर्ष:

वास्तव में फोरट्रान संकलक कितने बेहतर हैं?

यह है कि gfortran और gcc सरल कोड के लिए तेज़ हैं। इसलिए मैं कुछ और जटिल कोशिश करना चाहता था। मैंने वर्णक्रमीय मानदंड शूटआउट का उदाहरण लिया। मैं पहली बार 2D मैट्रिक्स A (:, :) का पूर्वसूचक करता हूं, और फिर मान की गणना करता हूं। (मुझे लगता है कि गोलीबारी पर इस समाधान की अनुमति नहीं है।) मैंने फोरट्रान और सी संस्करण को लागू किया है। यहाँ कोड है:

https://github.com/certik/spectral_norm

सबसे तेज़ गफ़रन संस्करण हैं स्पेक्ट्रल_नॉर्म 2.एफ 90 और स्पेक्ट्रल_नॉर्म 6. एफ 90 (एक फोरट्रान के अंतर्निहित मैटमूल और डॉट_प्रोडक्ट का उपयोग करता है, अन्य कोड में इन दो कार्यों को लागू करता है - गति में कोई अंतर नहीं)। सबसे तेज C / C ++ कोड जिसे मैं लिखने में सक्षम था, वह है spectral_norm7.cpp। मेरे लैपटॉप पर git संस्करण 457d9d9 के रूप में समय हैं:

$ time ./spectral_norm6 5500
1.274224153

real    0m2.675s
user    0m2.520s
sys 0m0.132s


$ time ./spectral_norm7 5500
1.274224153

real    0m2.871s
user    0m2.724s
sys 0m0.124s

इसलिए गैफरान का संस्करण थोड़ा तेज है। ऐसा क्यों है? यदि आप एक तेज सी कार्यान्वयन के साथ पुल अनुरोध भेजते हैं (या बस एक कोड पेस्ट करते हैं), तो मैं रिपॉजिटरी को अपडेट करूंगा।

फोरट्रान में मैं एक 2 डी सरणी के आसपास से गुजरता हूं, जबकि सीआई में 1 डी सरणी का उपयोग करते हैं। एक 2 डी सरणी या किसी अन्य तरीके का उपयोग करने के लिए स्वतंत्र महसूस करें जिसे आप फिट देखते हैं।

संकलक के रूप में, आइए gcc बनाम gfortran, icc बनाम ifort, और इसी तरह की तुलना करें। (शूटआउट पृष्ठ के विपरीत, जो ifort बनाम gcc की तुलना करता है।)

अद्यतन : 179 सी 2 के संस्करण का उपयोग करके, जो मेरे सी संस्करण में matmul3 () में सुधार करता है, वे अब उतने ही तेज़ हैं:

$ time ./spectral_norm6 5500
1.274224153

real    0m2.669s
user    0m2.500s
sys 0m0.144s

$ time ./spectral_norm7 5500
1.274224153

real    0m2.665s
user    0m2.472s
sys 0m0.168s

पेड्रो का वेक्टरकृत संस्करण तेजी से नीचे है:

$ time ./spectral_norm8 5500
1.274224153

real    0m2.523s
user    0m2.336s
sys 0m0.156s

अंत में, इंटेल कंपाइलर्स के लिए नीचे दी गई रिपोर्ट के अनुसार, वहाँ कोई बड़ा अंतर नहीं दिखता है और यहां तक ​​कि सबसे सरल फोरट्रान कोड (spectral_norm1) सबसे तेज़ है।


5
मैं अभी एक कंपाइलर के पास कहीं नहीं हूं, लेकिन अपने सरणियों में प्रतिबंधित कीवर्ड जोड़ने पर विचार करें। पॉइंटर्स का एलियासिंग आमतौर पर फ़ॉर्टन और सी फ़ंक्शन कॉल के बीच अंतर होता है। इसके अलावा, फोरट्रान स्तंभ-प्रमुख क्रम में मेमोरी और सी-पंक्ति-प्रमुख में संग्रहीत करता है।
मोइनर

1
-1 इस सवाल का बॉडी कार्यान्वयन के बारे में बात करता है, लेकिन शीर्षक पूछता है कि कौन सी भाषा तेज है? किसी भाषा में गति का गुण कैसे हो सकता है? आपको प्रश्न शीर्षक को संपादित करना चाहिए ताकि यह प्रश्न के शरीर को दर्शाता है।
मिलनसुरिक

@ IRO- बॉट, मैंने इसे ठीक किया। मुझे पता है अगर यह आप के लिए ठीक लग रहा है पता है।
ओन्डिस íertík

1
वास्तव में निष्कर्ष "वास्तव में फोरट्रान संकलक कितना बेहतर है?" उस धागे में काफी सही नहीं हैं। मैंने GCC, PGI, CRAY और Intel कंपाइलरों के साथ एक क्रे पर बेंचमार्क की कोशिश की थी और 3 कंपाइलर के साथ Fortran C (b / w 5-40%) से तेज था। क्रे कम्पाइलर्स ने सबसे तेज़ फोरट्रान / सी कोड का उत्पादन किया लेकिन फोरट्रान कोड 40% तेज था। समय मिलने पर मैं विस्तृत परिणाम पोस्ट करूंगा। क्रे मशीनों का उपयोग करने वाले किसी भी व्यक्ति को बेंचमार्क सत्यापित कर सकते हैं। यह एक अच्छा मंच है क्योंकि 4-5 संकलक उपलब्ध हैं और प्रासंगिक झंडे स्वचालित रूप से ftn / cc आवरण द्वारा लगे हुए हैं।
शाम

एक Opteron प्रणाली पर pgf95 / pgcc (11.10) के साथ भी जाँच की गई: # 1 और # 2 सबसे तेज़ (ifort द्वारा ~ 20% से अधिक) हैं, तो # 6, # 8, # 7 (उस क्रम में)। pgf95 आपके सभी फोरट्रान कोड के लिए ifort से तेज था, और icpc सभी C के लिए pgcpp से तेज था - मुझे यह उल्लेख करना चाहिए कि मेरे सामान के लिए, मैं आमतौर पर ifort को तेजी से खोजता हूं, यहां तक ​​कि समान AMD सिस्टम पर भी।
laxxy

जवाबों:


12

सबसे पहले, इस प्रश्न / चुनौती को पोस्ट करने के लिए धन्यवाद! अस्वीकरण के रूप में, मैं कुछ फोरट्रान अनुभव के साथ एक मूल सी प्रोग्रामर हूं, और सी में घर पर सबसे अधिक महसूस करता हूं, इसलिए, मैं केवल सी संस्करण को बेहतर बनाने पर ध्यान केंद्रित करूंगा। मैं सभी फोरट्रान हैक्स को अपने पास जाने के लिए आमंत्रित करता हूँ!

नए लोगों को यह याद दिलाने के बारे में कि यह किस बारे में है: इस धागे में मूल आधार यह था कि gcc / फोरट्रान और icc / ifort चाहिए, क्योंकि उनके पास क्रमशः एक ही बैक-एंड होते हैं, समान (शब्दार्थ समान) प्रोग्राम के लिए समान कोड का उत्पादन करते हैं, चाहे जो भी हो इसका C या फोरट्रान में होना। परिणाम की गुणवत्ता केवल संबंधित कार्यान्वयन की गुणवत्ता पर निर्भर करती है।

मैंने कोड के साथ थोड़ा सा खेला, और अपने कंप्यूटर पर (थिंकपैड 201x, Intel Core i5 M560, 2.67 GHz), gcc4.6.1 और निम्न कंपाइलर झंडे का उपयोग किया:

GCCFLAGS= -O3 -g -Wall -msse2 -march=native -funroll-loops -ffast-math -fomit-frame-pointer -fstrict-aliasing

मैंने भी आगे बढ़कर C ++ कोड का SIMD- वेक्टरकृत C- भाषा संस्करण लिखा spectral_norm_vec.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

/* Define the generic vector type macro. */  
#define vector(elcount, type)  __attribute__((vector_size((elcount)*sizeof(type)))) type

double Ac(int i, int j)
{
    return 1.0 / ((i+j) * (i+j+1)/2 + i+1);
}

double dot_product2(int n, double u[], double v[])
{
    double w;
    int i;
    union {
        vector(2,double) v;
        double d[2];
        } *vu = u, *vv = v, acc[2];

    /* Init some stuff. */
    acc[0].d[0] = 0.0; acc[0].d[1] = 0.0;
    acc[1].d[0] = 0.0; acc[1].d[1] = 0.0;

    /* Take in chunks of two by two doubles. */
    for ( i = 0 ; i < (n/2 & ~1) ; i += 2 ) {
        acc[0].v += vu[i].v * vv[i].v;
        acc[1].v += vu[i+1].v * vv[i+1].v;
        }
    w = acc[0].d[0] + acc[0].d[1] + acc[1].d[0] + acc[1].d[1];

    /* Catch leftovers (if any) */
    for ( i = n & ~3 ; i < n ; i++ )
        w += u[i] * v[i];

    return w;

}

void matmul2(int n, double v[], double A[], double u[])
{
    int i, j;
    union {
        vector(2,double) v;
        double d[2];
        } *vu = u, *vA, vi;

    bzero( u , sizeof(double) * n );

    for (i = 0; i < n; i++) {
        vi.d[0] = v[i];
        vi.d[1] = v[i];
        vA = &A[i*n];
        for ( j = 0 ; j < (n/2 & ~1) ; j += 2 ) {
            vu[j].v += vA[j].v * vi.v;
            vu[j+1].v += vA[j+1].v * vi.v;
            }
        for ( j = n & ~3 ; j < n ; j++ )
            u[j] += A[i*n+j] * v[i];
        }

}


void matmul3(int n, double A[], double v[], double u[])
{
    int i;

    for (i = 0; i < n; i++)
        u[i] = dot_product2( n , &A[i*n] , v );

}

void AvA(int n, double A[], double v[], double u[])
{
    double tmp[n] __attribute__ ((aligned (16)));
    matmul3(n, A, v, tmp);
    matmul2(n, tmp, A, u);
}


double spectral_game(int n)
{
    double *A;
    double u[n] __attribute__ ((aligned (16)));
    double v[n] __attribute__ ((aligned (16)));
    int i, j;

    /* Aligned allocation. */
    /* A = (double *)malloc(n*n*sizeof(double)); */
    if ( posix_memalign( (void **)&A , 4*sizeof(double) , sizeof(double) * n * n ) != 0 ) {
        printf( "spectral_game:%i: call to posix_memalign failed.\n" , __LINE__ );
        abort();
        }


    for (i = 0; i < n; i++) {
        for (j = 0; j < n; j++) {
            A[i*n+j] = Ac(i, j);
        }
    }


    for (i = 0; i < n; i++) {
        u[i] = 1.0;
    }
    for (i = 0; i < 10; i++) {
        AvA(n, A, u, v);
        AvA(n, A, v, u);
    }
    free(A);
    return sqrt(dot_product2(n, u, v) / dot_product2(n, v, v));
}

int main(int argc, char *argv[]) {
    int i, N = ((argc >= 2) ? atoi(argv[1]) : 2000);
    for ( i = 0 ; i < 10 ; i++ )
        printf("%.9f\n", spectral_game(N));
    return 0;
}

सभी तीन संस्करणों को एक ही झंडे और एक ही gccसंस्करण के साथ संकलित किया गया था। ध्यान दें कि मैंने अधिक सटीक समय प्राप्त करने के लिए मुख्य फ़ंक्शन कॉल को 0..9 से एक लूप में लपेटा।

$ time ./spectral_norm6 5500
1.274224153
...
real    0m22.682s
user    0m21.113s
sys 0m1.500s

$ time ./spectral_norm7 5500
1.274224153
...
real    0m21.596s
user    0m20.373s
sys 0m1.132s

$ time ./spectral_norm_vec 5500
1.274224153
...
real    0m21.336s
user    0m19.821s
sys 0m1.444s

तो "बेहतर" संकलक झंडे के साथ, सी ++ संस्करण आउट फोरट्रान संस्करण और हाथ से कोडित वेक्टर लूप केवल एक मामूली सुधार प्रदान करता है। सी ++ संस्करण के लिए कोडांतरक पर एक त्वरित नज़र से पता चलता है कि मुख्य छोरों को भी सदिश कर दिया गया है, यद्यपि बहुत आक्रामक तरीके से अनियंत्रित।

मुझे इस बात का भी आभास हो गया है कि gfortranयहां पर मौजूद असेम्बलर और बड़े आश्चर्य की बात है: कोई वैश्वीकरण नहीं। मैं इस तथ्य को विशेषता देता हूं कि यह समस्या सीमित बैंडविड्थ तक सीमित है, कम से कम मेरी वास्तुकला पर। मैट्रिक्स के प्रत्येक गुणन के लिए, 230MB डेटा का पता लगाया जाता है, जो कैश के सभी स्तरों पर बहुत अधिक दलदल करता है। यदि आप एक छोटे इनपुट मान का उपयोग करते हैं, उदाहरण के लिए 100, प्रदर्शन अंतर काफी बढ़ जाता है।

साइड-नोट के रूप में, वेक्टराइजेशन, संरेखण और संकलक झंडे के बारे में ध्यान देने के बजाय, सबसे स्पष्ट अनुकूलन एकल-सटीक अंकगणित में पहले कुछ पुनरावृत्तियों की गणना करना होगा, जब तक कि हमारे पास परिणाम के ~ 8 अंक न हों। एकल-सटीक निर्देश न केवल तेज़ हैं, बल्कि स्मृति की मात्रा जो चारों ओर ले जानी है, भी आधी है।


आपके समय के लिए बहुत - बहुत धन्यवाद! मुझे उम्मीद थी कि आप जवाब देंगे। :) तो सबसे पहले मैंने आपके झंडे का उपयोग करने के लिए मेकफिल को अपडेट किया। फिर मैंने आपका C कोड spectral_norm8.c और अपडेटेड README के ​​रूप में डाल दिया। मैंने अपनी मशीन पर समय ( github.com/certik/spectral_norm/wiki/Timings ) को अपडेट किया और जैसा कि आप देख सकते हैं, संकलक झंडे ने मेरी मशीन पर सी संस्करण को तेजी से नहीं बनाया (यानी gfortran अभी भी जीतता है, लेकिन आपका SIMD-वेक्टरकृत संस्करण बीट गुर्राटन।
ओन्डिस íertík

@ OndřejČertík: बस जिज्ञासा से बाहर, क्या के संस्करण gcc/ gfortranप्रयोग कर रहे हैं? पिछले थ्रेड्स में, विभिन्न संस्करणों ने काफी अलग परिणाम दिए।
पेड्रो

मैं 4.6.1-9ubuntu3 का उपयोग करता हूं। क्या आपके पास इंटेल कंपाइलर्स तक पहुंच है? गफ़रन के साथ मेरा अनुभव यह है कि कभी-कभी यह (अभी तक) इष्टतम कोड का उत्पादन नहीं करता है। IFort आमतौर पर करता है।
ओन्डिस íertík

1
@ Ond theejČertík: अब परिणाम अधिक समझ में आता है! मैंने इस बात की अनदेखी की थी कि matmul2फोरट्रान संस्करण matmul3मेरे सी संस्करण में शब्दार्थ के बराबर है । दो संस्करणों वास्तव में अब एक ही हैं और इस तरह gcc/ gfortran चाहिए दोनों के लिए एक ही परिणाम है, जैसे कोई भी सामने के अंत / भाषा इस मामले में अन्य की तुलना में बेहतर है। gccबस इसका फायदा है कि हम जिन वेक्टर निर्देशों का फायदा उठा सकते हैं, उन्हें चुनना चाहिए।
पेड्रो

1
@ cjordan1: मैंने vector_sizeकोड प्लेटफ़ॉर्म को स्वतंत्र बनाने के लिए विशेषता का उपयोग करने का चयन किया है , अर्थात इस सिंटैक्स gccका उपयोग करते हुए, आईबीएम पावर आर्किटेक्चर पर AltiVec का उपयोग करते हुए अन्य प्लेटफार्मों के लिए वेक्टर कोड उत्पन्न करने में सक्षम होना चाहिए।
पेड्रो

7

user389 का उत्तर हटा दिया गया है लेकिन मुझे बताएं कि मैं उसके शिविर में दृढ़ता से हूं: मैं यह देखने में विफल हूं कि हम विभिन्न भाषाओं में माइक्रो-बेंचमार्क की तुलना करके क्या सीखते हैं। यह मेरे लिए किसी आश्चर्य की बात नहीं है कि C और फोरट्रान को इस बेंचमार्क पर समान प्रदर्शन मिलता है, यह देखते हुए कि यह कितना छोटा है। लेकिन बेंचमार्क भी उबाऊ है क्योंकि यह दोनों भाषाओं में एक दर्जन लाइनों में आसानी से लिखा जा सकता है। एक सॉफ्टवेयर के नजरिए से, यह प्रतिनिधि मामला नहीं है: हमें ऐसे सॉफ्टवेयर की परवाह करनी चाहिए, जिसमें 10,000 या 100,000 लाइन के कोड हों और इसके लिए कंपाइलर कैसे करें। बेशक, उस पैमाने पर, एक को जल्दी से अन्य चीजों का पता चल जाएगा: उस भाषा ए को 10,000 लाइनों की आवश्यकता होती है जबकि भाषा बी को 50,000 की आवश्यकता होती है। या आप क्या करना चाहते हैं, इसके आधार पर दूसरे तरीके से। और अचानक यह '

दूसरे शब्दों में, यह मेरे लिए ज्यादा मायने नहीं रखता है कि शायद मेरा आवेदन 50% तेज हो सकता है यदि मैंने इसे फोरट्रान 77 में विकसित किया है, अगर इसके बजाय मुझे इसे ठीक से चलाने के लिए केवल 1 महीने का समय लगेगा, जबकि मुझे 3 महीने का समय लगेगा। F77 में। यहाँ प्रश्न के साथ समस्या यह है कि यह एक पहलू (व्यक्तिगत गुठली) पर केंद्रित है जो मेरे विचार में व्यवहार में प्रासंगिक नहीं है।


माना। बहुत अलग-अलग, बहुत मामूली संपादन (-3 वर्ण, +9 वर्ण) से अलग यह किस मूल्य के लिए है, मैं उनके उत्तर की मुख्य भावना से सहमत था। जहाँ तक मुझे पता है, C ++ / C / फोरट्रान कंपाइलर डिबेट तभी मायने रखता है जब किसी ने प्रदर्शन बढ़ाने के लिए हर दूसरे संभावित एवेन्यू को समाप्त कर दिया हो, यही वजह है कि 99.9% लोगों के लिए, ये तुलनाएं मायने नहीं रखती हैं। मुझे चर्चा विशेष रूप से ज्ञानवर्धक नहीं लगती है, लेकिन मुझे साइट पर कम से कम एक व्यक्ति के बारे में पता है, जो प्रदर्शन कारणों से सी और सी ++ पर फोरट्रान को चुनने का प्रयास कर सकता है, यही कारण है कि मैं यह नहीं कह सकता कि यह पूरी तरह से बेकार है।
ज्योफ ऑक्सबेरी

4
मैं अपने मुख्य बिंदु से सहमत हैं, लेकिन मैं अभी भी लगता है कि इस चर्चा के लिए उपयोगी है के रूप में वहाँ हैं वहाँ लोग हैं, जो अभी भी किसी भी तरह का मानना है की एक संख्या वहाँ कुछ जादू एक भाषा "तेजी" अन्य की तुलना में अधिक आसान बनाता है, समान संकलक के उपयोग के बावजूद बैकेंड। इस मिथक को दूर करने के लिए मैं मुख्य रूप से इन बहसों में योगदान देता हूं। जैसा कि कार्यप्रणाली के लिए, कोई "प्रतिनिधि मामला" नहीं है, और मेरी राय में, मैट्रिक्स-वेक्टर बहु ​​के रूप में कुछ सरल लेना एक अच्छी बात है, क्योंकि यह संकलक को यह दिखाने के लिए पर्याप्त स्थान देता है कि वे क्या कर सकते हैं या नहीं।
पेड्रो

@GeoffOxberry: निश्चित रूप से, आप हमेशा ऐसे लोगों को पाएंगे जो कम या ज्यादा अच्छी तरह से व्यक्त और उचित कारणों के लिए एक भाषा का उपयोग करते हैं। मेरा प्रश्न, हालांकि, यह होगा कि फोरट्रान कितनी तेजी से होगा यदि कोई डेटा संरचनाओं का उपयोग करता है जो कहते हैं, एक असंरचित, अनुकूली परिमित तत्व जाल हैं। इस तथ्य के अलावा कि यह फोरट्रान में लागू करने के लिए अजीब होगा (जो कोई भी C ++ में इसे लागू करता है, वह एसटीएल का भारी उपयोग करता है), क्या फोरट्रान वास्तव में इस तरह के कोड के लिए तेज होगा जिसमें कोई तंग लूप नहीं है, कई अप्रत्यक्ष, बहुत सारे आइएफएस?
वोल्फगैंग बैंगर्थ

@WolfgangBangerth: जैसे मैंने अपनी पहली टिप्पणी में कहा था, मैं आपसे और उपयोगकर्ता389 (जोनाथन डर्सी) के साथ सहमत हूं, इसलिए मुझसे यह पूछना कि प्रश्न निरर्थक है। उस ने कहा, मैं किसी को भी आमंत्रित करूंगा जो यह मानता है कि भाषा का विकल्प (सी ++ / सी / फोरट्रान के बीच) आपके प्रश्न का उत्तर देने के लिए उनके आवेदन में प्रदर्शन के लिए महत्वपूर्ण है। अफसोस की बात है कि मुझे संदेह है कि इस तरह की बहस कंपाइलर संस्करणों के लिए हो सकती है।
ज्योफ ऑक्सबेरी

@GeoffOxberry: हाँ, और मेरा स्पष्ट रूप से मतलब नहीं था कि आपको उस प्रश्न का उत्तर देने की आवश्यकता थी।
वोल्फगैंग बैंगर्थ

5

यह पता चला है कि मैं अपने सिस्टम के गॉथरन कंपाइलर के साथ संकलित फोर्ट्रान कोड की तुलना में तेजी से पायथन कोड (बीएलएएस संचालन करने के लिए संख्यात्मक उपयोग करके) लिख सकता हूं।

$ gfortran -o sn6a sn6a.f90 -O3 -march=native
    
    $ ./sn6a 5500
1.274224153
1.274224153
1.274224153
   1.9640001      sec per iteration

$ python ./foo1.py
1.27422415279
1.27422415279
1.27422415279
1.20618661245 sec per iteration

foo1.py:

import numpy
import scipy.linalg
import timeit

def specNormDot(A,n):
    u = numpy.ones(n)
    v = numpy.zeros(n)

    for i in xrange(10):
        v  = numpy.dot(numpy.dot(A,u),A)
        u  = numpy.dot(numpy.dot(A,v),A)

    print numpy.sqrt(numpy.vdot(u,v)/numpy.vdot(v,v))

    return

n = 5500

ii, jj = numpy.meshgrid(numpy.arange(1,n+1), numpy.arange(1,n+1))
A  = (1./((ii+jj-2.)*(ii+jj-1.)/2. + ii))

t = timeit.Timer("specNormDot(A,n)", "from __main__ import specNormDot,A,n")
ntries = 3

print t.timeit(ntries)/ntries, "sec per iteration"

और sn6a.f90, एक बहुत ही हल्के ढंग से संशोधित स्पेक्ट्रल_नॉर्म 6.f90:

program spectral_norm6
! This uses spectral_norm3 as a starting point, but does not use the
! Fortrans
! builtin matmul and dotproduct (to make sure it does not call some
! optimized
! BLAS behind the scene).
implicit none

integer, parameter :: dp = kind(0d0)
real(dp), allocatable :: A(:, :), u(:), v(:)
integer :: i, j, n
character(len=6) :: argv
integer :: calc, iter
integer, parameter :: niters=3

call get_command_argument(1, argv)
read(argv, *) n

allocate(u(n), v(n), A(n, n))
do j = 1, n
    do i = 1, n
        A(i, j) = Ac(i, j)
    end do
end do

call tick(calc)

do iter=1,niters
    u = 1
    do i = 1, 10
        v = AvA(A, u)
        u = AvA(A, v)
    end do

    write(*, "(f0.9)") sqrt(dot_product2(u, v) / dot_product2(v, v))
enddo

print *, tock(calc)/niters, ' sec per iteration'

contains

pure real(dp) function Ac(i, j) result(r)
integer, intent(in) :: i, j
r = 1._dp / ((i+j-2) * (i+j-1)/2 + i)
end function

pure function matmul2(v, A) result(u)
! Calculates u = matmul(v, A), but much faster (in gfortran)
real(dp), intent(in) :: v(:), A(:, :)
real(dp) :: u(size(v))
integer :: i
do i = 1, size(v)
    u(i) = dot_product2(A(:, i), v)
end do
end function

pure real(dp) function dot_product2(u, v) result(w)
! Calculates w = dot_product(u, v)
real(dp), intent(in) :: u(:), v(:)
integer :: i
w = 0
do i = 1, size(u)
    w = w + u(i)*v(i)
end do
end function

pure function matmul3(A, v) result(u)
! Calculates u = matmul(v, A), but much faster (in gfortran)
real(dp), intent(in) :: v(:), A(:, :)
real(dp) :: u(size(v))
integer :: i, j
u = 0
do j = 1, size(v)
    do i = 1, size(v)
        u(i) = u(i) + A(i, j)*v(j)
    end do
end do
end function

pure function AvA(A, v) result(u)
! Calculates u = matmul2(matmul3(A, v), A)
! In gfortran, this function is sligthly faster than calling
! matmul2(matmul3(A, v), A) directly.
real(dp), intent(in) :: v(:), A(:, :)
real(dp) :: u(size(v))
u = matmul2(matmul3(A, v), A)
end function

subroutine tick(t)
    integer, intent(OUT) :: t

    call system_clock(t)
end subroutine tick

! returns time in seconds from now to time described by t 
real function tock(t)
    integer, intent(in) :: t
    integer :: now, clock_rate

    call system_clock(now,clock_rate)

    tock = real(now - t)/real(clock_rate)
end function tock
end program

1
गाल में जीभ, मुझे लगता है?
रॉबर्ट हार्वे

-1 सवाल का जवाब नहीं देने के लिए, लेकिन मुझे लगता है कि आप पहले से ही जानते हैं।
पेड्रो

दिलचस्प है, आपने किस संस्करण का उपयोग किया, और आपने पेड्रो के झंडे के साथ भंडार में उपलब्ध सी कोड का परीक्षण किया?
एरन अहमदिया

1
वास्तव में, मुझे लगता है कि यह अब स्पष्ट है, यह मानते हुए कि आप व्यंग्यात्मक नहीं थे।
रॉबर्ट हार्वे

1
इस पोस्ट के बाद से, और अन्य किसी भी प्रश्न या पोस्ट को, एरन द्वारा इस तरह से संपादित नहीं किया जा रहा है, ताकि वह अपनी राय से बेहतर मिलान कर सके, हालांकि मेरी पूरी बात यह है कि सभी पदों को ठीक उसी तरह से लेबल किया जाना चाहिए, "ये परिणाम निरर्थक हैं" caveats, मैं इसे हटा रहा हूँ।

3

इंटेल संकलक के साथ यह जाँच की। 11.1 (-Ex, implying -O3) के साथ, और 12.0 (-O2) के साथ सबसे तेज़ 1,2,6,7, और 8 हैं (यानी "सबसे सरल" फोरट्रान और सी कोड, और हाथ-सदिश C) - ये ~ 1.5 के दशक में एक दूसरे से अप्रभेद्य हैं। टेस्ट 3 और 5 (एक फ़ंक्शन के रूप में सरणी के साथ) धीमे हैं; # 4 मैं संकलन नहीं कर सका।

काफी, अगर 12.0 और -O3 के साथ संकलित करें, -O2 के बजाय, पहले 2 ("सरलतम") फोरट्रान कोड A LOT (1.5 -> 10.2 सेकंड) को धीमा कर देते हैं - यह पहली बार नहीं है जब मुझे कुछ पसंद आया है। यह, लेकिन यह सबसे नाटकीय उदाहरण हो सकता है। यदि यह अभी भी वर्तमान रिलीज में मामला है, तो मुझे लगता है कि यह इंटेल को रिपोर्ट करने के लिए एक अच्छा विचार होगा, क्योंकि इस सरल मामले में उनकी अनुकूलन के साथ स्पष्ट रूप से कुछ गलत हो रहा है।

अन्यथा मैं जोनाथन से सहमत हूं कि यह एक विशेष रूप से जानकारीपूर्ण अभ्यास नहीं है :)


इसे जाँचने के लिए धन्यवाद! यह मेरे अनुभव की पुष्टि करता है, कि गैफरान अभी पूरी तरह से परिपक्व नहीं है, क्योंकि किसी कारण से मटमूल ऑपरेशन धीमा है। इसलिए मेरे लिए निष्कर्ष केवल मैटमूल का उपयोग करना और फोरट्रान कोड को सरल रखना है।
ओन्देजे íertík

दूसरी ओर, मुझे लगता है कि gfortran के पास स्वचालित रूप से सभी matmul () कॉल को BLAS कॉल (शायद dot_product (), निश्चित नहीं) में परिवर्तित करने के लिए एक कमांड लाइन विकल्प है। हालांकि यह कोशिश कभी नहीं की।
laxxy
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.