यह प्रश्न दो चर्चाओं का एक विस्तार है जो हाल ही में " सी ++ बनाम फोरट्रान के लिए एचपीसी " के उत्तरों में आया था । और यह एक सवाल की तुलना में थोड़ी अधिक चुनौती है ...
फोरट्रान के पक्ष में सबसे अधिक सुनी जाने वाली दलील यह है कि कंपाइलर सिर्फ बेहतर हैं। चूँकि अधिकांश 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 अनुकूलन, या के लिए संकलक पर भरोसा करने की समस्याओं का उदाहरण देता है ऐसी स्थिति में जब एक फोरट्रान संकलक अपने सी प्रतिपक्ष को करता है।