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


74

यह प्रश्न दो चर्चाओं का एक विस्तार है जो हाल ही में " सी ++ बनाम फोरट्रान के लिए एचपीसी " के उत्तरों में आया था । और यह एक सवाल की तुलना में थोड़ी अधिक चुनौती है ...

फोरट्रान के पक्ष में सबसे अधिक सुनी जाने वाली दलील यह है कि कंपाइलर सिर्फ बेहतर हैं। चूँकि अधिकांश C / फोरट्रान संकलक एक ही बैक एंड को साझा करते हैं, दोनों भाषाओं में शब्दार्थ समतुल्य कार्यक्रमों के लिए उत्पन्न कोड समान होना चाहिए। हालांकि, कोई तर्क दे सकता है कि सी / फोरट्रान कंपाइलर को अनुकूलित करने के लिए अधिक / कम आसान है।

इसलिए मैंने एक सरल परीक्षण का प्रयास करने का फैसला किया: मुझे daxpy.f और daxpy.c की एक प्रति मिली और उन्हें gfortran / gcc के साथ संकलित किया।

अब daxpy.c केवल daxpy.f (स्वचालित रूप से उत्पन्न कोड, बदसूरत के रूप में बिल्ली) का एक f2c अनुवाद है, इसलिए मैंने उस कोड को लिया और इसे थोड़ा सा साफ किया (daxpy_c से मिला), जिसका मूल रूप से अंतरतम लूप के रूप में फिर से लिखना था।

for ( i = 0 ; i < n ; i++ )
    dy[i] += da * dx[i];

अंत में, मैंने gcc के वेक्टर सिंटैक्स का उपयोग करके इसे फिर से लिखा (daxpy_cvec दर्ज करें):

#define vector(elcount, type)  __attribute__((vector_size((elcount)*sizeof(type)))) type
vector(2,double) va = { da , da }, *vx, *vy;

vx = (void *)dx; vy = (void *)dy;
for ( i = 0 ; i < (n/2 & ~1) ; i += 2 ) {
    vy[i] += va * vx[i];
    vy[i+1] += va * vx[i+1];
    }
for ( i = n & ~3 ; i < n ; i++ )
    dy[i] += da * dx[i];

ध्यान दें कि मैं लंबाई 2 के वैक्टर का उपयोग करता हूं (यह सब SSE2 अनुमति देता है) और यह कि मैं एक बार में दो वैक्टर की प्रक्रिया करता हूं। ऐसा इसलिए है क्योंकि कई आर्किटेक्चर पर, हमारे पास वेक्टर तत्वों की तुलना में अधिक गुणन इकाइयाँ हो सकती हैं।

सभी कोडों को झंडे के साथ gfortran / gcc संस्करण 4.5 का उपयोग करके संकलित किया गया था "-O3 -Wall -msse2 -march = native -ffast-math -fomit-फ़्रेम-पॉइंटर -मालाइन-डबल-ऑफ़स्ट्रिक्ट-अलियासिंग"। मेरे लैपटॉप पर (Intel Core i5 CPU, M560, 2.67GHz) मुझे निम्न आउटपुट मिला:

pedro@laika:~/work/fvsc$ ./test 1000000 10000
timing 1000000 runs with a vector of length 10000.
daxpy_f took 8156.7 ms.
daxpy_f2c took 10568.1 ms.
daxpy_c took 7912.8 ms.
daxpy_cvec took 5670.8 ms.

तो मूल फोरट्रान कोड 8.1 सेकंड से थोड़ा अधिक लेता है, इसके स्वचालित अनुवाद में 10.5 सेकंड लगते हैं, भोले सी कार्यान्वयन इसे 7.9 में करता है और स्पष्ट रूप से सदिश कोड इसे 5.6 में करता है, थोड़ा कम।

यह फोरट्रान भोले सी कार्यान्वयन की तुलना में थोड़ा धीमा है और वेक्टर सी कार्यान्वयन की तुलना में 50% धीमा है।

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

इसके अलावा, क्या कोई इस टेस्ट को icc / ifort के साथ आज़मा सकता है? वेक्टर सिंटैक्स शायद काम नहीं करेगा, लेकिन मैं यह देखने के लिए उत्सुक होगा कि भोला सी संस्करण वहां कैसे व्यवहार करता है। समान xlc / xlf के साथ किसी के लिए भी जाता है।

मैंने यहां स्रोत और एक मेकफाइल अपलोड किया है । सटीक समय पाने के लिए, अपने CPU में Hz की संख्या के लिए test.c में CPU_TPS सेट करें। यदि आप किसी भी संस्करण में कोई सुधार पाते हैं, तो कृपया उन्हें यहाँ पोस्ट करें!

अपडेट करें:

मैंने ऑनलाइन फाइलों में स्टाली का परीक्षण कोड जोड़ा है और इसे C संस्करण के साथ पूरक किया है। मैंने 10'000 की लंबाई वाले वैक्टर पर 1'000'000 लूप करने के लिए कार्यक्रमों को संशोधित किया, जो कि पिछले परीक्षण के अनुरूप था (और क्योंकि मेरी मशीन 1'000'000'000 लंबाई के वैक्टर आवंटित नहीं कर सकती थी, जैसा कि स्टाली के मूल में है। ' कोड)। चूंकि संख्या अब थोड़ी छोटी है, इसलिए मैंने -par-threshold:50संकलक को समानांतर बनाने की अधिक संभावना वाले विकल्प का उपयोग किया । उपयोग किया गया icc / ifort संस्करण 12.1.2 20111128 है और परिणाम निम्नानुसार हैं

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./icctest_c
3.27user 0.00system 0:03.27elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./icctest_f
3.29user 0.00system 0:03.29elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./icctest_c
4.89user 0.00system 0:02.60elapsed 188%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./icctest_f
4.91user 0.00system 0:02.60elapsed 188%CPU

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

अपडेट करें:

हालाँकि मुझे वास्तव में पसंद नहीं है कि सबूत का बोझ यहाँ कहाँ जा रहा है, मैंने सी में स्टाली के मैट्रिक्स गुणन उदाहरण को फिर से कोडित किया है और इसे वेब पर फाइलों में जोड़ा है । यहां एक और दो सीपीयू के लिए ट्रिपल लूप के परिणाम दिए गए हैं:

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./mm_test_f 2500
 triple do time   3.46421700000000     
3.63user 0.06system 0:03.70elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./mm_test_c 2500
triple do time 3.431997791385768
3.58user 0.10system 0:03.69elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./mm_test_f 2500
 triple do time   5.09631900000000     
5.26user 0.06system 0:02.81elapsed 189%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./mm_test_c 2500
triple do time 2.298916975280899
4.78user 0.08system 0:02.62elapsed 184%CPU

ध्यान दें कि cpu_timeफ़ोर्ट्रान में सीपीयू समय और दीवार-घड़ी के समय को मापता है, इसलिए मैंने timeउन्हें 2 सीपीयू के लिए तुलना करने के लिए कॉल लपेट दिया । परिणामों के बीच कोई वास्तविक अंतर नहीं है, सिवाय इसके कि सी संस्करण दो कोर पर थोड़ा बेहतर करता है।

अब matmulकमांड के लिए, निश्चित रूप से केवल फोरट्रान में क्योंकि यह आंतरिक सी में उपलब्ध नहीं है:

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./mm_test_f 2500
 matmul    time   23.6494780000000     
23.80user 0.08system 0:23.91elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./mm_test_f 2500
 matmul    time   26.6176640000000     
26.75user 0.10system 0:13.62elapsed 197%CPU

वाह। यह बिल्कुल भयानक है। किसी को भी पता चल सकता है कि मैं क्या गलत कर रहा हूं, या यह बताएं कि यह आंतरिक क्यों अभी भी किसी भी तरह से एक अच्छी बात है?

मैंने dgemmकॉल को बेंचमार्क में नहीं जोड़ा क्योंकि वे Intel MKL में समान फ़ंक्शन के लिए लाइब्रेरी कॉल हैं।

भविष्य के परीक्षण के लिए, क्या कोई फोरट्रान की तुलना में सी में धीमी गति से ज्ञात एक उदाहरण का सुझाव दे सकता है?

अपडेट करें

स्टाली के इस दावे को सत्यापित करने के लिए कि matmulआंतरिक "मैग्निट्यूड का एक क्रम है" छोटे मैट्रिक्स पर स्पष्ट मैट्रिक्स उत्पाद की तुलना में तेज है, मैंने दोनों तरीकों, 10'000 प्रत्येक का उपयोग करके आकार 100x100 के गुणा करने के लिए अपने कोड को संशोधित किया। एक और दो सीपीयू पर परिणाम इस प्रकार हैं:

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=1 time ./mm_test_f 10000 100
 matmul    time   3.61222500000000     
 triple do time   3.54022200000000     
7.15user 0.00system 0:07.16elapsed 99%CPU

pedro@laika:~/work/fvsc$ OMP_NUM_THREADS=2 time ./mm_test_f 10000 100
 matmul    time   4.54428400000000     
 triple do time   4.31626900000000     
8.86user 0.00system 0:04.60elapsed 192%CPU

अपडेट करें

ग्रिसू यह इंगित करने में सही है कि, अनुकूलन के बिना, जीसीसी जटिल संख्याओं पर संचालन को लाइब्रेरी फ़ंक्शन कॉल में परिवर्तित करता है, जबकि कुछ निर्देशों में gfortran इनलाइन करता है।

सी कंपाइलर समान, कॉम्पैक्ट कोड उत्पन्न करेगा यदि विकल्प -fcx-limited-rangeसेट किया जाता है, अर्थात संकलक को मध्यवर्ती मूल्यों में संभावित ओवर / अंडर-फ्लो को अनदेखा करने का निर्देश दिया जाता है। यह विकल्प किसी तरह डिफ़ॉल्ट रूप से gfortran में सेट किया गया है और गलत परिणाम दे सकता है। गफ़रन -fno-cx-limited-rangeमें ज़बरदस्ती करने से कुछ भी नहीं बदला।

तो यह वास्तव में संख्यात्मक गणनाओं के लिए गैफरान का उपयोग करने के खिलाफ एक तर्क है : जटिल मानों पर संचालन भले ही सही परिणाम फ्लोटिंग-पॉइंट सीमा के भीतर हो / पर-प्रवाह। यह वास्तव में एक फोरट्रान मानक है। जीसीसी में, या सामान्य रूप से C99 में, डिफ़ॉल्ट चीजों को सख्ती से करने के लिए है (जब तक कि अन्यथा निर्दिष्ट न हो तो IEEE-754 शिकायत पढ़ें)।

अनुस्मारक: कृपया ध्यान रखें कि मुख्य प्रश्न यह था कि क्या फोरट्रान संकलक सी संकलक की तुलना में बेहतर कोड का उत्पादन करते हैं। यह एक भाषा के दूसरे गुण के सामान्य गुण के रूप में चर्चा के लिए जगह नहीं है। क्या मुझे वास्तव में दिलचस्पी होगी, अगर कोई स्पष्ट रूप से वैश्वीकरण का उपयोग करते हुए सी में एक के रूप में कुशल के रूप में एक daxpy उत्पादन करने के लिए gaxran coaxing का एक तरीका मिल सकता है क्योंकि यह विशेष रूप से SIMI अनुकूलन, या के लिए संकलक पर भरोसा करने की समस्याओं का उदाहरण देता है ऐसी स्थिति में जब एक फोरट्रान संकलक अपने सी प्रतिपक्ष को करता है।


एक समय समस्या यह है कि यदि आपका प्रोसेसर फ़्रीक्वेंसी स्टेपिंग / टर्बो मोड करता है, तो ये परिणाम पूरे नक्शे पर हो सकते हैं।
बिल बर्थ

1
आपका daxpy_c.c वर्तमान में x को कई x के साथ अपडेट कर रहा है और y को बिल्कुल भी नहीं छू रहा है। आप इसे ठीक करने के लिए इसे ठीक करना चाह सकते हैं ...
जैक पोल्सन

1
@JackPoulson: अच्छे कैच, निश्चित और परिणाम अपडेट।
पेड्रो

2
इसके अलावा, मैं पूरी तरह से निश्चित हूं कि अंतर पूरी तरह से फोरलेन संस्करण में मैनुअल अनियंत्रित होने के कारण संकलक को भ्रमित कर रहा है। जब मैं इसे उसी सरल लूप से प्रतिस्थापित करता हूं जिसे आप अपने सी संस्करण में डालते हैं, तो दोनों के बीच प्रदर्शन लगभग समान होता है। परिवर्तन के बिना, फोरट्रान संस्करण इंटेल संकलक के साथ धीमा था।
जैक पॉल्सन

1
@permeakra: वास्तव में, C99 मानक उस restrictकीवर्ड को निर्दिष्ट करता है जो कंपाइलर को ठीक वही बताता है: यह मानने के लिए कि कोई सरणी किसी अन्य डेटा संरचना के साथ ओवरलैप नहीं होती है।
पेड्रो

जवाबों:


37

यूनिट-स्ट्राइड फोरट्रान डैक्सपी के मैनुअल अनियंत्रित होने के कारण आपके समय में अंतर प्रतीत होता है । कमांड का उपयोग करते हुए निम्नलिखित समय एक 2.67 गीगाहर्ट्ज Xeon X5650 पर हैं

./test 1000000 10000

इंटेल 11.1 संकलक

मैनुअलन के साथ फोरट्रान: 8.7 सेकंड
फोरट्रान w / o मैनुअल अनियंत्रित: 5.8 सेकंड
सी w / ओ मैनुअल अनियंत्रित: सेकंड सेकंड

जीएनयू 4.1.2 संकलक

मैनुअल्रॉलिंग के साथ फोरट्रान: 8.3 सेकंड
फोरट्रान डब्ल्यू / ओ मैनुअल अनरोलिंग: 13.5 सेकंड
सी डब्ल्यू / ओ मैनुअल अनरोलिंग:
वेक्टर विशेषताओं के साथ 13.6 सेकंड सी: 5.8 सेकंड

GNU 4.4.5 संकलक

मैनुअलिंग के साथ फोरट्रान: 8.1 सेकंड
फोरट्रान डब्ल्यू / ओ मैनुअल अनरोलिंग: 7.4 सेकंड
सी डब्ल्यू / ओ मैनुअल अनरोलिंग:
वेक्टर सेकंड के साथ 8.5 सेकंड सी: 5.8 सेकंड

निष्कर्ष

  • मैनुअल अनरोलिंग ने इस आर्किटेक्चर पर GNU 4.1.2 फोरट्रान कंपाइलर्स की मदद की, लेकिन नए संस्करण (4.4.5) और इंटेल फोरट्रान कंपाइलर को नुकसान पहुंचाता है।
  • जीएनयू 4.4.5 सी संकलक फोरट्रान के साथ संस्करण 4.2.1 की तुलना में अधिक प्रतिस्पर्धी है।
  • वेक्टर इंट्रिनिक्स जीसीसी के प्रदर्शन को इंटेल संकलक से मेल खाने की अनुमति देते हैं।

Dgemv और dgemm जैसी अधिक जटिल दिनचर्या का परीक्षण करने का समय?


परिणामों के लिए धन्यवाद! Gcc का कौन सा संस्करण आप उपयोग कर रहे थे और क्या आप CPU के बारे में कुछ अधिक विशिष्ट हो सकते हैं?
पेड्रो

2
आपका संकलक आपके CPU से पुराना है ... क्या आप gcc-4.5 के साथ प्रयास कर सकते हैं?
पेड्रो

1
मैंने बस कोशिश की। जीसीसी 4.4.5 के साथ वेक्टरकृत संस्करण इंटेल 11.1 परिणामों से बिल्कुल मेल खाता है।
जैक पॉल्सन

1
मैंने सिर्फ gcc / gfortran संस्करण 4.4.5 स्थापित किया है और मैं अंतर w / o को अनियंत्रित नहीं कर सकता। वास्तव में, दोनों मामलों के लिए उत्पन्न कोडांतरक में, अंतरतम लूप उपयोग किए गए रजिस्टर नामों को छोड़कर समान है, जो विनिमेय हैं। क्या आप अपने परीक्षणों को फिर से सुनिश्चित करने के लिए चला सकते हैं?
पेड्रो

4
क्या हम कह सकते हैं कि इस तरह की पुरानी बहस "हम फोरट्रान का उपयोग करते रहते हैं क्योंकि यह अधिक प्रदर्शनकारी है", ताकि हम अंत में इसे डंपर में फेंक सकें?
स्टेफानो बोरीनी

16

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

मेरे लैपटॉप (मैकबुक प्रो, इंटेल कोर i7, 2.66 गीगाहर्ट्ज) पर चल रहा है, आपके हैंड-वेक्टराइज्ड सी वर्जन और नॉन-हैंड वेक्टरफाइड फोरट्रान वर्जन के सापेक्ष प्रदर्शन, आपके द्वारा उपयोग किए गए कंपाइलर पर निर्भर करते हैं:

Compiler     Fortran time     C time
GCC 4.6.1    5408.5 ms        5424.0 ms
GCC 4.5.3    7889.2 ms        5532.3 ms
GCC 4.4.6    7735.2 ms        5468.7 ms

इसलिए, ऐसा लगता है कि जीसीसी 4.6 शाखा में लूप को पहले से बेहतर बनाने में बेहतर था।


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


scicomp में आपका स्वागत है! मैं सहमत हूं कि संकलक संस्करण इस मामले में भाषा के रूप में महत्वपूर्ण हैं। क्या आपके अंतिम वाक्य में 'ऑफ' के बजाय 'का मतलब' था?
एरन अहमदिया

9

जिस तरह से मैं फोरट्रान में AXPY लिखता हूं वह थोड़ा अलग है। यह गणित का सटीक अनुवाद है।

m_blas.f90

 module blas

   interface axpy
     module procedure saxpy,daxpy
   end interface

 contains

   subroutine daxpy(x,y,a)
     implicit none
     real(8) :: x(:),y(:),a
     y=a*x+y
   end subroutine daxpy

   subroutine saxpy(x,y,a)
     implicit none
     real(4) :: x(:),y(:),a
     y=a*x+y
   end subroutine saxpy

 end module blas

अब एक कार्यक्रम में उपरोक्त दिनचर्या कहते हैं।

test.f90

 program main

   use blas
   implicit none

   real(4), allocatable :: x(:),y(:)
   real(4) :: a
   integer :: n

   n=1000000000
   allocate(x(n),y(n))
   x=1.0
   y=2.0
   a=5.0
   call axpy(x,y,a)
   deallocate(x,y)

 end program main

अब इसे संकलित करें और चलाएं ...

login1$ ifort -fast -parallel m_blas.f90 test.f90
ipo: remark #11000: performing multi-file optimizations
ipo: remark #11005: generating object file /tmp/ipo_iforttdqZSA.o

login1$ export OMP_NUM_THREADS=1
login1$ time ./a.out 
real    0 m 4.697 s
user    0 m 1.972 s
sys     0 m 2.548 s

login1$ export OMP_NUM_THREADS=2
login1$ time ./a.out 
real    0 m 2.657 s
user    0 m 2.060 s
sys     0 m 2.744 s

ध्यान दें कि मैं किसी भी लूप या किसी भी स्पष्ट OpenMP निर्देशों का उपयोग नहीं कर रहा हूं । क्या यह सी में संभव होगा (यानी, लूप और ऑटो-समानांतर का कोई उपयोग नहीं)? मैं C का उपयोग नहीं करता इसलिए मुझे नहीं पता।


स्वचालित समांतरिकरण इंटेल संकलक (फोरट्रान और सी दोनों) की एक विशेषता है, और भाषा का नहीं। इसलिए C में समतुल्य भी समानांतर होना चाहिए। जिज्ञासा से बाहर, यह कैसे अधिक मध्यम n = 10000 के लिए प्रदर्शन करता है?
पेड्रो

3
यह पूरी बात थी। ऑटोपार फोरट्रान में इस तथ्य के कारण आसान है कि फोरट्रान (सी के विपरीत) मैटल्ट, ट्रांसपोज़ आदि जैसे पूरे सरणी संचालन का समर्थन करता है, इसलिए फोरट्रान संकलक के लिए कोड अनुकूलन आसान है। GFortran (जो आपने उपयोग किया है) में फोरट्रान कंपाइलर को ऑप्टिमाइज़ करने के लिए डेवलपर संसाधन नहीं हैं क्योंकि उनका फोकस वर्तमान में अनुकूलन के बजाय फोरट्रान 2003 मानक को लागू करना है।
22

Uhmm ... इंटेल C / C ++ कंपाइलर iccभी स्वचालित समांतरिकरण करता है। मैंने icctest.cअन्य स्रोतों में एक फ़ाइल जोड़ी है । क्या आप इसे उसी विकल्पों के साथ संकलित कर सकते हैं जैसा आपने ऊपर इस्तेमाल किया था, इसे चलाएं, और समय की रिपोर्ट करें? मुझे सब कुछ बाहर करने के लिए gcc से बचने के लिए अपने कोड में एक प्रिंटफ-स्टेटमेंट जोड़ना था। यह सिर्फ एक त्वरित हैक है और मुझे आशा है कि यह बग-मुक्त है!
पेड्रो

मैंने नवीनतम icc / ifort संकलक डाउनलोड किया है और परीक्षण स्वयं किए हैं। प्रश्न को इन नए परिणामों में शामिल करने के लिए अद्यतन किया गया है, अर्थात, इंटेल के ऑटोवेस्ट्रलाइजेशन दोनों फोरट्रान और सी में काम करता है
पेड्रो

1
धन्यवाद। हां मैंने देखा कि शायद थोड़ा अंतर है क्योंकि लूप सरल हैं और ऑपरेशन लेवल 1 BLAS हैं। लेकिन जैसा कि मैंने पहले कहा था कि फोरट्रान की संपूर्ण सरणी संचालन और PURE / ELEMENTAL जैसे कीवर्ड का उपयोग करने की क्षमता के कारण कंपाइलर अनुकूलन के लिए अधिक जगह है। संकलक इस जानकारी का उपयोग कैसे करते हैं और यह वास्तव में क्या करता है यह अलग बात है। अगर आप bpaste.net/show/23035
stali

6

मुझे लगता है, यह केवल दिलचस्प नहीं है कि एक कंपाइलर आधुनिक हार्डवेयर के लिए कोड का अनुकूलन कैसे करता है। विशेष रूप से जीएनयू सी और जीएनयू फोरट्रान के बीच कोड पीढ़ी बहुत अलग हो सकती है।

तो आइए उनके बीच के अंतर को दिखाने के लिए एक और उदाहरण पर विचार करें।

जटिल संख्याओं का उपयोग करते हुए, GNU C संकलक एक जटिल संख्या पर लगभग बहुत ही बुनियादी अंकगणितीय ऑपरेशन के लिए एक बड़ा ओवरहेड बनाता है। फोरट्रान कंपाइलर बेहतर कोड देता है। आइए फ़ोर्ट्रान में निम्नलिखित छोटे उदाहरण देखें:

COMPLEX*16 A,B,C
C=A*B

(gfortran -g -o complex.fo -c complex.f95; objdump -d -S complex.fo):

C=A*B
  52:   dd 45 e0                fldl   -0x20(%ebp)
  55:   dd 45 e8                fldl   -0x18(%ebp)
  58:   dd 45 d0                fldl   -0x30(%ebp)
  5b:   dd 45 d8                fldl   -0x28(%ebp)
  5e:   d9 c3                   fld    %st(3)
  60:   d8 ca                   fmul   %st(2),%st
  62:   d9 c3                   fld    %st(3)
  64:   d8 ca                   fmul   %st(2),%st
  66:   d9 ca                   fxch   %st(2)
  68:   de cd                   fmulp  %st,%st(5)
  6a:   d9 ca                   fxch   %st(2)
  6c:   de cb                   fmulp  %st,%st(3)
  6e:   de e9                   fsubrp %st,%st(1)
  70:   d9 c9                   fxch   %st(1)
  72:   de c2                   faddp  %st,%st(2)
  74:   dd 5d c0                fstpl  -0x40(%ebp)
  77:   dd 5d c8                fstpl  -0x38(%ebp)

जो 39 बाइट्स मशीन कोड हैं। जब हम C में समान मानते हैं

 double complex a,b,c; 
 c=a*b; 

और आउटपुट पर एक नज़र डालें (ऊपर की तरह उसी तरह से), हमें मिलता है:

  41:   8d 45 b8                lea    -0x48(%ebp),%eax
  44:   dd 5c 24 1c             fstpl  0x1c(%esp)
  48:   dd 5c 24 14             fstpl  0x14(%esp)
  4c:   dd 5c 24 0c             fstpl  0xc(%esp)
  50:   dd 5c 24 04             fstpl  0x4(%esp)
  54:   89 04 24                mov    %eax,(%esp)
  57:   e8 fc ff ff ff          call   58 <main+0x58>
  5c:   83 ec 04                sub    $0x4,%esp
  5f:   dd 45 b8                fldl   -0x48(%ebp)
  62:   dd 5d c8                fstpl  -0x38(%ebp)
  65:   dd 45 c0                fldl   -0x40(%ebp)
  68:   dd 5d d0                fstpl  -0x30(%ebp)

जो 39 बाइट्स मशीन कोड भी हैं, लेकिन फ़ंक्शन चरण 57 संदर्भित करता है, काम का उचित हिस्सा करता है और वांछित संचालन करता है। इसलिए हमारे पास मल्टी ऑपरेशन चलाने के लिए 27 बाइट मशीन कोड हैं। समारोह पीछे muldc3 द्वारा प्रदान किया गया है libgcc_s.soऔर मशीन कोड में 1375 बाइट के पदचिह्न हैं। यह कोड को नाटकीय रूप से धीमा कर देता है और एक प्रोफाइलर का उपयोग करते समय एक दिलचस्प आउटपुट देता है।

जब हम बीएलएएस के उदाहरणों को लागू zaxpyकरते हैं और एक ही परीक्षण करते हैं, तो फोरट्रान कंपाइलर को सी कंपाइलर से बेहतर परिणाम देना चाहिए।

(मैंने इस प्रयोग के लिए GCC 4.4.3 का उपयोग किया, लेकिन मैंने इस व्यवहार को एक अन्य GCC रिलीज़ के लिए देखा)

इसलिए मेरी राय में हम केवल समानांतरकरण और वैश्वीकरण के बारे में ही नहीं सोचते हैं जब हम सोचते हैं कि कौन सा बेहतर संकलक है हमें यह भी देखना होगा कि बुनियादी चीजों को कोडांतरक कोड में कैसे अनुवाद किया जाता है। यदि यह अनुवाद खराब कोड देता है तो अनुकूलन केवल इनपुट के रूप में इस चीजों का उपयोग कर सकता है।


1
मैंने आपके कोड की तर्ज पर एक उदाहरण पकाया है, complex.cऔर इसे ऑनलाइन कोड में जोड़ा है। मुझे यह सुनिश्चित करने के लिए सभी इनपुट / आउटपुट जोड़ना पड़ा कि कुछ भी अनुकूलित नहीं है। __muldc3अगर मैं उपयोग नहीं करता तो मुझे केवल एक कॉल मिलता है -ffast-math। साथ -O2 -ffast-mathमैं inlined कोडांतरक के 9 लाइनों मिलता है। क्या आप इसकी पुष्टि कर सकते हैं?
पेड्रो

मैंने जनरेट किए गए असेंबलर में अंतर के लिए एक अधिक विशिष्ट कारण पाया है और इसे ऊपर मेरे प्रश्न में जोड़ा है।
पेड्रो

का उपयोग करते हुए -O2 संकलक का नेतृत्व करता है कि रनटाइम पर हर संभव गणना करने के लिए, यही कारण है कि ऐसे निर्माण कभी-कभी खो जाते हैं। जब आप आउटपुट पर भरोसा करना चाहते हैं, तो -स्टास्ट-गणित विकल्प का उपयोग वैज्ञानिक कंप्यूटिंग में नहीं किया जाना चाहिए।
एमके उर्फ ​​ग्रिसू

1
ठीक है, उस तर्क से (नहीं -ffast-math) आपको अपने जटिल-मूल्यवान संगणनाओं के लिए फोरट्रान का उपयोग नहीं करना चाहिए। जैसा कि मैंने अपने प्रश्न के अद्यतन में वर्णन किया है, -ffast-mathया, अधिक सामान्यतः, -fcx-limited-rangeउसी गैर-आईईईई का उपयोग करने के लिए मजबूर करता है, जैसे कि फोरट्रान में मानक सीमाएं सीमित हैं । इसलिए यदि आप जटिल मूल्यों और सही Infs और NaN की पूरी श्रृंखला चाहते हैं, तो आपको Fortran का उपयोग नहीं करना चाहिए ...
Pedro

2
@Proro: यदि आप चाहते हैं कि जीसीसी GFortran wrt की तरह व्यवहार करे। जटिल गुणा और भाग, आपको -fcx-फोरट्रान-नियमों का उपयोग करना चाहिए।
जनाब

4

मित्रों,

मुझे यह चर्चा बहुत दिलचस्प लगी, लेकिन मैं यह देखकर हैरान रह गया कि मटमुल उदाहरण में लूप को फिर से ऑर्डर करने से तस्वीर बदल गई। मेरे पास मेरी वर्तमान मशीन पर एक इंटेल संकलक उपलब्ध नहीं है, इसलिए मैं gfortran का उपयोग कर रहा हूं, लेकिन mm_test.f90 में लूप का फिर से लिखना।

call cpu_time(start)  
do r=1,runs  
  mat_c=0.0d0  
     do j=1,n  
        do k=1,n  
  do i=1,n  
           mat_c(i,j)=mat_c(i,j)+mat_a(i,k)*mat_b(k,j)  
        end do  
     end do  
  end do  
end do  
call cpu_time(finish)  

मेरी मशीन के लिए पूरे परिणाम बदल दिए हैं।

पिछले संस्करण के समय परिणाम थे:

#time ./mm_test_f 10000 100
 matmul    time   6.3620000000000001     
 triple do time   21.420999999999999     

जबकि ट्रिपल छोरों के साथ फिर से ऊपर के रूप में व्यवस्थित:

#time ./mm_test_f 10000 100
 matmul    time   6.3929999999999998     
 triple do time   3.9190000000000005    

यह इंटेल (R) कोर (TM) i7-2600K CPU / 3.99GHz पर gcc / gfortran 4.7.2 20121109 है

कंपाइलर झंडे का इस्तेमाल उन मेकफाइल से किया गया था जो मुझे यहां मिले ...


3
यह आश्चर्य की बात नहीं है, क्योंकि मेमोरी में मैट्रिक्स स्टोरेज एक आदेश का समर्थन करता है, अर्थात, यदि पंक्तियों को संचित रूप से संग्रहीत किया जाता है, तो पंक्तियों के अंतर पर लूप करना बेहतर होता है, तब से आप बार-बार लोड करने (स्लाइस) की तुलना में प्रत्येक पंक्ति को तेज स्थानीय मेमोरी में लोड कर सकते हैं ) यह एक तत्व तक पहुँचने के लिए। देखें stackoverflow.com/questions/7395556
क्रिश्चियन क्लैसन

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

-2

यह ऐसी भाषाएं नहीं हैं जो कोड को तेज़ी से चलाती हैं, हालांकि वे मदद करती हैं। यह संकलक, सीपीयू और ऑपरेटिंग सिस्टम है जो कोड को तेजी से चलाता है। भाषाओं की तुलना करना सिर्फ एक मिथ्या नाम है, बेकार और अर्थहीन। इसका कोई मतलब नहीं है क्योंकि आप दो चर की तुलना कर रहे हैं: भाषा और संकलक। यदि एक कोड तेजी से चलता है, तो आप नहीं जानते कि यह भाषा कितनी है या यह कितना संकलक है। मुझे समझ में नहीं आता है कि कंप्यूटर विज्ञान समुदाय अभी यह क्यों नहीं समझता है :-(

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.