2008-09-30 21 views
7

मैं सी में डबल्स के 2-डी सरणी (एक घने मैट्रिक्स) ++, निरपेक्ष न्यूनतम भूमि के ऊपर तक पहुँचने के साथ प्रतिनिधित्व करने के लिए एक तरह से की जरूरत है।अनुकूलन सी ++ 2-डी सरणियों

मैं विभिन्न लिनक्स/यूनिक्स मशीनों और जीसीसी संस्करणों पर कुछ समय से किया है। वैक्टर का एक एसटीएल वेक्टर, के रूप में घोषित:

vector<vector<double> > matrix(n,vector<double>(n)); 

और matrix[i][j] के माध्यम से पहुँचा घोषित रूप में एक सरणी से उपयोग करने के लिए 5% और 100% धीमी बीच है:

double *matrix = new double[n*n]; 

एक inlined सूचकांक समारोह matrix[index(i,j)] के माध्यम से पहुँचा , जहां index(i,j) i + n * j का मूल्यांकन करता है। एसटीएल के बिना 2-डी सरणी की व्यवस्था करने के अन्य तरीकों - प्रत्येक पंक्ति की शुरुआत में एन पॉइंटर्स की एक सरणी, या स्थिर आकार matrix[n][n] के रूप में स्टैक पर पूरी चीज़ को परिभाषित करना - लगभग उसी गति से चलाना जैसे इंडेक्स फ़ंक्शन विधि ।

हाल के जीसीसी संस्करण (> 4.0) एसटीएल वेक्टर-ऑफ-वैक्टरों को ऑप्टिमाइज़ेशन चालू होने पर गैर-एसटीएल कोड के समान दक्षता में संकलित करने में सक्षम प्रतीत होते हैं, लेकिन यह कुछ हद तक मशीन-निर्भर है।

मैं यदि संभव हो तो एसटीएल उपयोग करना चाहते हैं, लेकिन सबसे तेजी से समाधान का चयन करना होगा। क्या किसी को जीसीसी के साथ एसटीएल अनुकूलित करने में कोई अनुभव है?

उत्तर

8

यदि आप जीसीसी का उपयोग कर रहे हैं तो संकलक आपके मैट्रिक्स एक्सेस का विश्लेषण कर सकता है और कुछ मामलों में स्मृति में ऑर्डर बदल सकता है। जादू संकलक ध्वज के रूप में परिभाषित किया गया है:

-fipa-matrix-reorg 

मैट्रिक्स सपाट और सुर निष्पादित करें। मैट्रिक्स फ़्लैटनिंग को के समतुल्य एन-आयामी मैट्रिक्स, के साथ एम-आयामी मैट्रिक्स को प्रतिस्थापित करने की कोशिश करता है जहां n < मीटर। इससे मैट्रिक्स के तत्वों तक पहुंचने के लिए संकेत का स्तर कम हो जाता है। दूसरा ऑप्टिमाइज़ेशन का मैट्रिक्स ट्रांसपोज़ करना है जो कैश इलाके में सुधार के क्रम में मैट्रिक्स के आयामों को बदलने का प्रयास करता है। दोनों ऑप्टिमाइज़ेशन को fwhole-program ध्वज की आवश्यकता है। ट्रांसपोज़िंग केवल तभी सक्षम होती है जब प्रोफाइलिंग जानकारी उपलब्ध हो।

ध्यान दें कि यह विकल्प -O2 या -O3 द्वारा सक्षम नहीं है। आपको इसे खुद पास करना होगा।

+2

क्या यह वास्तव में std :: vector के साथ काम करता है? मुझे शक है। – lothar

+0

वास्तव में अद्भुत और डरावना दोनों होगा। – peterchen

8

मेरा अनुमान है सबसे तेज, एक मैट्रिक्स के लिए हो सकता है, 1 डी एसटीएल सरणी का उपयोग करें और 2 डी मैट्रिक्स के रूप में उपयोग करने के लिए() ऑपरेटर ओवरराइड करने के लिए।

हालांकि, एसटीएल भी एक प्रकार विशेष रूप से गैर resizeable संख्यात्मक सरणियों के लिए परिभाषित करता है: valarray। इन-प्लेस ऑपरेशंस के लिए आपके पास कई अनुकूलन भी हैं।

एक संख्यात्मक प्रकार तर्क के रूप में स्वीकार करते हैं valarray:

valarray<double> a; 

उसके बाद, आप स्लाइस, अप्रत्यक्ष सरणियों, उपयोग कर सकते हैं ... और हां, आप valarray वारिस और अपने खुद के ऑपरेटर को परिभाषित() कर सकते हैं (पूर्णांक मैं, पूर्णांक जे) 2 डी सरणियों के लिए ...

+0

मेरा उपरोक्त वैलारे के लिए है, एक कस्टम मैट्रिक्स प्रकार बनाने के लिए जरूरी नहीं है। खैर, कस्टम मैट्रिक्स प्रकार काम कर सकता है, लेकिन अभी भी वेक्टर के बजाय वालराय पर आधारित होना चाहिए (वालर्रे स्लाइसिंग का समर्थन करता है, जो एक पंक्ति प्राप्त करने के समान ही कॉलम प्राप्त करता है)। –

+0

std :: valarray से सावधानीपूर्वक विरासत; यह विरासत के लिए डिज़ाइन नहीं किया गया है, अधिकांश "एसटीएल" के रूप में। –

+0

जब तक आप उन्हें डेटा नहीं जोड़ते हैं तब तक आप एसटीएल के किसी भी वर्ग का उत्तराधिकारी हो सकते हैं क्योंकि कन्स्ट्रक्टर को नहीं बुलाया जाएगा। यद्यपि कोई पीबी जोड़ने तरीकों नहीं है। – PierreBdR

6

मेरे सिफारिश Boost.UBLAS है, जो तेजी से मैट्रिक्स/वेक्टर वर्गों प्रदान करता है का उपयोग करने के लिए होगा।

+0

मुझे यह स्पष्ट करना चाहिए था कि जब मैं matrices से निपट रहा हूं, तो मैं जो परिचालन कर रहा हूं वह विशिष्ट रैखिक बीजगणित नहीं है। UBLAS रैखिक बीजगणित के लिए बहुत अच्छा लग रहा है, लेकिन शायद मैं इसे केवल 2 डी सरणी भंडारण के रूप में उपयोग कर रहा हूं। –

+0

मैंने 2 डी डेटा (मानचित्र) के रूप में उपयोग के लिए विभिन्न रैखिक बीजगणित पुस्तकालयों की कोशिश की है, लेकिन वे गैर-रैखिक बीजगणित उद्देश्यों के लिए उपयोग करने के लिए सुविधाजनक नहीं हैं और न ही वेक्टरों के वेक्टर से तेज़ हैं। UBLAS (और अन्य) गुणा और अन्य 'ठेठ' मैट्रिक्स उपयोगों के लिए केवल तेज़ है, एक्सेस करने के लिए इतना नहीं। – Roel

7

बहुत संभावना है कि यह एक स्थानीय संदर्भ-संदर्भ मुद्दा है। vector अपने आंतरिक सरणी को आवंटित करने के लिए new का उपयोग करता है, इसलिए प्रत्येक पंक्ति के प्रत्येक शीर्षक के कारण प्रत्येक पंक्ति स्मृति में कम से कम अलग होगी; जब आप उन्हें आवंटित करते हैं तो स्मृति पहले ही खंडित हो जाती है। सरणी की विभिन्न पंक्तियों में कम से कम कैश-लाइन गलती हो सकती है और पृष्ठ की गलती हो सकती है; यदि आप वास्तव में दुर्भाग्यपूर्ण हैं तो दो आसन्न पंक्तियां स्मृति लाइनों पर हो सकती हैं जो एक टीएलबी स्लॉट साझा करती हैं और एक तक पहुंचने से दूसरे को बेदखल कर दिया जाएगा।

इसके विपरीत आपके अन्य समाधान गारंटी देते हैं कि सभी डेटा आसन्न है। यदि आप संरचना को संरेखित करते हैं तो यह आपके प्रदर्शन में सहायता कर सकता है ताकि यह संभवतः कुछ कैश लाइनों को पार कर सके।

vectorआकार बदलने योग्य सरणी के लिए डिज़ाइन किया गया है। यदि आपको सरणी का आकार बदलने की आवश्यकता नहीं है, तो नियमित C++ सरणी का उपयोग करें। एसटीएल ऑपरेशंस आमतौर पर सी ++ सरणी पर काम कर सकते हैं।

सरणी को सही दिशा में चलने के लिए सुनिश्चित करें, यानी नीचे (लगातार स्मृति पते) की बजाय। इससे कैश दोष कम हो जाएंगे।

+0

मैंने वेक्टर समाधान में ब्लॉक हेडर के बारे में नहीं सोचा था। मुझे गलत तरीके से चलने से संभावित मंदी के बारे में पता था हालांकि: मेरे स्पीड टेस्ट से पता चलता है कि गलत तरीके से चलना सही तरीके से चार गुना धीमा हो सकता है! –

1

उचित होने के लिए मैट्रिक्स पर उपयोग किए जा रहे एल्गोरिदम पर निर्भर करता है।

डबल नाम [एन * एम] प्रारूप बहुत तेज़ है जब आप पंक्तियों से डेटा तक पहुंच रहे हैं क्योंकि गुणा और अतिरिक्त के अलावा लगभग कोई ओवरहेड नहीं है और क्योंकि आपकी पंक्तियों को डेटा पैक किया जाता है जो कैश में सुसंगत होगा।

यदि आपके एल्गोरिदम कॉलम आदेश डेटा का उपयोग करते हैं तो अन्य लेआउट में बेहतर कैश समेकन हो सकता है। यदि मैट्रिक्स के क्वाड्रंट्स में आपका एल्गोरिदम एक्सेस डेटा भी अन्य लेआउट बेहतर हो सकता है।

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

1

आप आसानी से वेक्टर < डबल> (एन * एम) कर सकते हैं;

1

आप http://eigen.tuxfamily.org/ पर Eigen सी ++ टेम्पलेट लायब्रेरी को देखने के लिए चाहते हो सकता है। यह वेक्टर/मैट्रिक्स गणनाओं को अनुकूलित करने के लिए AltiVec या sse2 कोड उत्पन्न करता है।

0

एक अन्य संबंधित पुस्तकालय ब्लिट्ज ++ है: http://www.oonumerics.org/blitz/docs/blitz.html

ब्लिट्ज ++ सरणी हेरफेर अनुकूलन करने के लिए बनाया गया है।

0

मैंने अपनी खुद की 2 आयामी सरणी कक्षाओं को घोषित करके कच्चे चित्रों के लिए कुछ समय पहले ऐसा किया है।

एक सामान्य 2 डी सरणी में, आप जैसे तत्वों का उपयोग:

सरणी [2] [3]। अब उस प्रभाव को प्राप्त करने के लिए, आपके पास ओवरलोडेड [] सरणी एक्सेसर के साथ एक क्लास सरणी होगी। लेकिन, यह अनिवार्य रूप से एक और सरणी लौटाएगा, जिससे आपको दूसरा आयाम देगा।

इस दृष्टिकोण के साथ समस्या यह है कि इसमें एक डबल फ़ंक्शन कॉल ओवरहेड है।

जिस तरह से मैंने किया था() शैली अधिभार का उपयोग करना था।

तो सरणी के बजाय [2] [3], बदलें, मैंने यह स्टाइल सरणी (2,3) किया है।

वह() फ़ंक्शन बहुत छोटा था और मैंने सुनिश्चित किया कि यह रेखांकित किया गया था। http://www.learncpp.com/cpp-tutorial/99-overloading-the-parenthesis-operator/

अगर आप की जरूरत है प्रकार टेम्पलेट कर सकते हैं:

कि की सामान्य अवधारणा के लिए यह लिंक देखें।
मेरा अंतर यह था कि मेरी सरणी गतिशील थी। मेरे पास घोषित करने वाली चार मेमोरी का एक ब्लॉक था। और मैंने एक कॉलम कैश लगाया, इसलिए मुझे पता था कि बाइट्स के मेरे अनुक्रम में अगली पंक्ति कब शुरू हुई थी। एक्सेस को पड़ोसी मूल्यों तक पहुंचने के लिए अनुकूलित किया गया था, क्योंकि मैं इसे छवि प्रसंस्करण के लिए उपयोग कर रहा था।

कोड के बिना समझा जाना मुश्किल है लेकिन अनिवार्य रूप से परिणाम सी जितना तेज था, और समझने और उपयोग करने में बहुत आसान था।

संबंधित मुद्दे