2008-10-02 38 views
8

32-बिट CPU पर, एक पूर्णांक 4 बाइट्स है और एक छोटा पूर्णांक 2 बाइट है। यदि मैं एक सी/सी ++ एप्लिकेशन लिख रहा हूं जो कई संख्यात्मक मानों का उपयोग करता है जो हमेशा एक छोटे पूर्णांक की प्रदान की गई सीमा के भीतर फिट होंगे, तो यह 4 बाइट पूर्णांक या 2 बाइट पूर्णांक का उपयोग करने के लिए अधिक कुशल है?32-बिट CPUs पर, एक 'पूर्णांक' प्रकार 'छोटा' प्रकार से अधिक कुशल है?

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

+0

डुप्लिकेट प्रश्न। [.NET इंटीजर बनाम Int16?] (Http://stackoverflow.com/questions/129023/net-integer-vs-int16#137625) देखें (यह .NET लेबल है, लेकिन यह हार्डवेयर आर्किटेक्चर के बारे में वही लागू होता है।) –

+4

@ जोनएडम्स: यह बिल्कुल किसी भी तरह से कोई डुप्लिकेट नहीं है, क्योंकि .NET स्वयं का एक ढांचा है और जो कुछ भी सच है, .NET के लिए कुछ भी सही नहीं हो सकता है लेकिन .NET। कुछ सीपीयू पर 32 बिट ऑप्स .NET में तेजी से हो सकते हैं (चूंकि .NET को इसके लिए अनुकूलित किया गया है), फिर भी जब सादा सी कोड लिखते हैं, तो 64 बिट ओप उस सीपीयू पर 32 बिट ऑप्स से अधिक तेज़ हो सकते हैं (क्योंकि सी कंपाइलर मई 32 बिट के मुकाबले 64 बिट के लिए कोड को बेहतर अनुकूलित करने में सक्षम हो)। – Mecki

उत्तर

12

हां, आपको 32 बिट सीपीयू पर निश्चित रूप से 32 बिट पूर्णांक का उपयोग करना चाहिए, अन्यथा यह अप्रयुक्त बिट्स से मास्किंग समाप्त कर सकता है (यानी, यह हमेशा 32 बिट्स में गणित करेगा, फिर उत्तर को 16 बिट्स में परिवर्तित करें)

यह आपके लिए दो बार 16 बिट ऑपरेशंस नहीं करेगा, लेकिन यदि आप स्वयं कोड लिखते हैं और आपको यकीन है कि यह अतिप्रवाह नहीं होगा, तो आप इसे स्वयं कर सकते हैं।

संपादित करें: मुझे यह जोड़ना चाहिए कि यह "कुशल" की परिभाषा पर कुछ हद तक निर्भर करता है। हालांकि यह 32-बिट संचालन को और तेज़ी से करने में सक्षम होगा, आप निश्चित रूप से दो गुना अधिक स्मृति का उपयोग करेंगे।

यदि इन्हें किसी भी आंतरिक लूप में मध्यवर्ती गणनाओं के लिए उपयोग किया जा रहा है, तो 32-बिट का उपयोग करें। यदि, हालांकि, आप इसे डिस्क से पढ़ रहे हैं, या यहां तक ​​कि यदि आपको केवल कैश मिस के लिए भुगतान करना है, तो भी यह 16-बिट पूर्णांक का उपयोग करने के लिए बेहतर काम कर सकता है। सभी अनुकूलन के साथ, जानने के लिए केवल एक ही रास्ता है: प्रोफ़ाइल

+1

यह ध्यान दिया जाना चाहिए कि सी 99 में stdint.h int_fastN_t और uint_fastN_t प्रकार है, जहां एन 8/16/32/64 है (हालांकि सभी हमेशा उपलब्ध नहीं होते हैं)। बूस्ट सी ++ के बराबर है, और g ++ में stdint.h शामिल भी है। जो कम से कम आवश्यक आकार के साथ सबसे तेज़ प्रकार माना जाता है। –

12

यदि आपके पास संख्याओं की एक बड़ी श्रृंखला है, तो काम करने वाले छोटे आकार के साथ जाएं। 32 बिट इट्स की तुलना में 16 बिट शॉर्ट्स की सरणी के साथ काम करने के लिए यह अधिक कुशल होगा क्योंकि आपको दो बार कैश घनत्व मिलता है। 32 बिट रजिस्टरों में 16 बिट मानों के साथ काम करने के लिए सीपीयू को किसी भी साइन एक्सटेंशन की लागत कैश मिस की लागत की तुलना में मामूली रूप से नगण्य है।

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

3

यह निर्भर करता है। यदि आप सीपीयू बाध्य हैं, तो 32 बिट सीपीयू पर 32 बिट ऑपरेशंस 16 बिट से तेज होंगे। यदि आप स्मृतिबद्ध हैं (विशेष रूप से यदि आपके पास बहुत अधिक L2 कैश मिस हैं), तो उस छोटे डेटा का उपयोग करें जिसमें आप निचोड़ सकते हैं।

आप यह पता लगा सकते हैं कि आप एक प्रोफाइलर का उपयोग कर रहे हैं जो सीपीयू और एल 2 दोनों को माप देगा Intel's VTune। आप एक ही लोड के साथ अपने ऐप को 2 बार चलाएंगे, और यह आपके ऐप में हॉटस्पॉट के एक दृश्य में 2 रनों को मर्ज करेगा, और आप कोड की प्रत्येक पंक्ति के लिए देख सकते हैं कि उस लाइन पर कितने चक्र खर्च किए गए थे। यदि कोड की एक महंगी रेखा पर, आप 0 कैश मिस देखते हैं, तो आप सीपीयू बाध्य हैं। यदि आप बहुत सारी यादें देखते हैं, तो आप स्मृति बंधे हैं।

1

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

इस प्रकार, यदि आपका डेटासेट बड़ा है, तो आप शायद 16 बिट पूर्णांक का उपयोग कर बेहतर हैं। यदि आपकी सूची सॉर्ट की गई है, तो आप एक कोडिंग योजना तैयार कर सकते हैं जिसमें अंतर या रन-लम्बाई एन्कोडिंग शामिल है, जो स्मृति बैंडविड्थ को और भी कम कर देगा।

7

यदि आप "कई" पूर्णांक मानों का उपयोग कर रहे हैं, तो आपकी प्रसंस्करण में बाधा बैंडविड्थ को स्मृति के लिए उत्तरदायी है। 16 बिट पूर्णांक डेटा कैश में अधिक कसकर पैक करते हैं, और इसलिए एक प्रदर्शन जीत होगी।

यदि आप बहुत बड़ी मात्रा में डेटा क्रंचिंग कर रहे हैं, तो आपको Ulrich Drepper द्वारा What Every Programmer Should Know About Memory पढ़ना चाहिए। डेटा कैश की दक्षता को अधिकतम करने के बारे में अध्याय 6 पर ध्यान केंद्रित करें।

0

जब आप 32 बिट कहते हैं, तो मुझे लगता है कि आपका मतलब x86 है। 16 बिट अंकगणितीय काफी धीमी है: ऑपरेंड-आकार उपसर्ग डीकोडिंग वास्तव में धीमा कर देता है। इसलिए अपने अस्थायी चर को छोटा int या int16_t न बनाएं।

हालांकि, x86 32 या 64 बिट रजिस्टरों में कुशलतापूर्वक 16 और 8 बिट पूर्णांक लोड कर सकता है। (movzx/movsx: शून्य और साइन एक्सटेंशन)। तो सरणी और संरचना क्षेत्रों के लिए लघु int का उपयोग करने के लिए स्वतंत्र महसूस करें, लेकिन सुनिश्चित करें कि आप अपने अस्थायी चर के लिए int या long का उपयोग करें।

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

यह बकवास है। भार/स्टोर निर्देश एल 1 कैश के साथ बातचीत करते हैं, और सीमित कारक ओप की संख्या है; चौड़ाई अप्रासंगिक है। जैसे कोर 2 पर: चौड़ाई के बावजूद 1 लोड और प्रति चक्र 1 स्टोर। एल 1 कैश में एल 2 कैश के लिए 128 या 256 बिट पथ है।

यदि लोड आपकी बाधा है, तो लोड होने के बाद आप एक चौड़ा भार जिसे शिफ्ट या मास्क के साथ विभाजित करते हैं, मदद कर सकते हैं। या समांतर में लोड होने के बाद अनपॅक किए बिना समानांतर में डेटा को संसाधित करने के लिए सिमड का उपयोग करें।

3

सलाह को न सुनें, इसे आजमाएं।

यह शायद आपके द्वारा उपयोग किए जा रहे हार्डवेयर/कंपाइलर पर भारी निर्भर होने जा रहा है। एक त्वरित परीक्षण इस सवाल का संक्षिप्त काम करना चाहिए। यहां प्रश्न लिखने के लिए परीक्षण लिखने के लिए शायद कम समय है।

+0

वाक्यांश "चालाक काम" – dddJewelsbbb

3

एक 32 बिट सीपीयू एक सीपीयू है जो आमतौर पर 32 बिट मानों पर आंतरिक रूप से संचालित होता है, लेकिन इसका मतलब यह नहीं है कि यह 8/16 बिट मान पर एक ही ऑपरेशन करते समय धीमा है। उदाहरण के लिए x86, 8086 तक पिछड़ा संगत, एक रजिस्टर के अंशों पर काम कर सकता है। इसका मतलब है कि यदि रजिस्टर 32 बिट चौड़ा है, तो यह केवल पहले 16 या उस रजिस्टर के पहले 8 बिट पर ही काम कर सकता है और बिल्कुल धीमा नहीं होगा। इस अवधारणा को x86_64 द्वारा भी अपनाया गया है, जहां पंजीयक 64 बिट हैं, फिर भी वे केवल पहले 32, 16, या 8 बिट पर ही काम कर सकते हैं।

इसके अलावा x86 CPU हमेशा स्मृति से पूरी कैश लाइन लोड करते हैं, अगर पहले से ही कैश में नहीं है, और कैश लाइन 4 बाइट से भी बड़ी है (32 बिट CPUs के बजाय 8 या 16 बाइट्स के लिए) और इस प्रकार स्मृति से 2 बाइट लोड हो रहा है स्मृति से 4 बाइट लोड करने के समान ही तेज़ है। यदि स्मृति से कई मानों को संसाधित करते हैं, तो 16 बिट मान वास्तव में 32 बिट मानों से अधिक तेज़ हो सकते हैं, क्योंकि कम स्मृति स्थानान्तरण होते हैं। यदि एक कैश लाइन 8 बाइट है, तो प्रति कैश लाइन के चार 16 बिट मान हैं, फिर भी केवल दो 32 बिट मान हैं, इस प्रकार 16 बिट इन्ट्स का उपयोग करते समय आपके पास 32 बिट इन्ट्स का उपयोग करके प्रत्येक चार मानों तक एक मेमोरी एक्सेस होती है, आपके पास प्रत्येक दो मान होते हैं , जिसके परिणामस्वरूप एक बड़ी int सरणी को संसाधित करने के लिए दो बार स्थानान्तरण होता है।

अन्य सीपीयू, उदाहरण के लिए पीपीसी की तरह, एक रजिस्टर के केवल एक अंश को संसाधित नहीं कर सकते हैं, वे हमेशा पूर्ण रजिस्टर को संसाधित करते हैं। फिर भी इन CPUs में विशेष लोड ऑपरेशंस होते हैं जो उन्हें अनुमति देते हैं, उदा। स्मृति से 16 बिट मान लोड करें, इसे 32 बिट तक बढ़ाएं और इसे एक रजिस्टर में लिखें।बाद में उनके पास एक विशेष स्टोर ऑपरेशन है जो रजिस्टर से मूल्य लेता है और केवल अंतिम 16 बिट को स्मृति में संग्रहीत करता है; दोनों ऑपरेशन को केवल एक सीपीयू चक्र की आवश्यकता होती है, जैसे 32 बिट लोड/स्टोर की आवश्यकता होती है, इसलिए कोई गति अंतर नहीं होता है। और चूंकि पीपीसी केवल रजिस्टरों पर अंकगणितीय परिचालन कर सकता है (x86 के विपरीत, जो सीधे मेमोरी पर भी काम कर सकता है), यह लोड/स्टोर प्रक्रिया तब भी होती है जब आप 32 बिट इंट्स या 16 बिट इंट्स का उपयोग करते हैं।

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

तो यदि आप यहां एक सामान्य नियम की अपेक्षा करते हैं, तो मुझे आपको निराश करना होगा। न तो कोई यह सुनिश्चित करने के लिए कह सकता है कि 16 बिट ऑपरेशंस 32 बिट ऑपरेशंस के लिए समान रूप से तेज़ हैं, और न ही कोई यह सुनिश्चित कर सकता है कि 32 बिट ऑपरेशंस हमेशा तेज होंगे। यह भी निर्भर करता है कि आपका कोड वास्तव में उन संख्याओं के साथ क्या कर रहा है और यह कैसा चल रहा है। मैंने बेंचमार्क देखा है जहां 16 बिट ऑपरेशंस के साथ 32 बिट ऑपरेशंस कुछ 32 बिट सीपीयू पर एक ही कोड की तुलना में तेज़ थे, हालांकि मैंने पहले से ही विपरीत होने को देखा है। यहां तक ​​कि एक कंपाइलर से दूसरे में स्विच करना या आपके कंपाइलर संस्करण को अपग्रेड करना पहले से ही सब कुछ बदल सकता है। मैं केवल निम्नलिखित कह सकता हूं: जो भी दावा करता है कि शॉर्ट्स के साथ काम करना इंट्स के साथ काम करने से काफी धीमा है, कृपया उस दावे के लिए एक नमूना स्रोत कोड प्रदान करें और सीपीयू और कंपाइलर का नाम परीक्षण के लिए इस्तेमाल किया जाए, क्योंकि मैंने कभी ऐसा कुछ अनुभव नहीं किया है पिछले 10 वर्षों के बारे में। ऐसी कुछ स्थितियां हो सकती हैं, जहां स्याही के साथ काम करना शायद 1-5% तेज हो, फिर भी 10% से कम कुछ भी "महत्वपूर्ण" नहीं है और सवाल यह है कि, कुछ मामलों में स्मृति को दो बार बर्बाद करना उचित है क्योंकि यह आपको खरीद सकता है 2% प्रदर्शन? मुझे ऐसा नहीं लगता।

+1

x86 प्रोसेसर का चालाक उपयोग "आंशिक रजिस्टर स्टॉल" का सामना करता है, यदि आप कहते हैं, 'ax' पर लिखें और फिर' eax' से पढ़ने का प्रयास करें। अगर आप 16- और 32-बिट परिचालन मिश्रण कर रहे हैं तो इसके बारे में कुछ पता होना चाहिए। – cHao

+0

इसके अलावा, x86 के पास एक लंबे रजिस्टर ('movsx',' movzx') में एक छोटा सा मूल्य पढ़ने के लिए समान निर्देश हैं। तो आप पूरी तरह से 32-बिट चला सकते हैं, स्टालों से बच सकते हैं, और अभी भी 16-बिट मानों के साथ काम कर सकते हैं। – cHao

+1

@cHao: ठीक है, मेमोरी स्टालों को छोड़कर, जो आपको 16 बिट के लिए 32 बिट के लिए अक्सर दोगुना कर देगा। इनट्स और कंपाइलर पर बहुत सारी गणना करने पर, वे सभी रजिस्टरों में रख सकते हैं, 32 बिट वास्तव में x86/x86_64 और पीपीसी (केवल कुछ प्रतिशत) पर थोड़ा तेज है। फिर भी जब सरणी में संग्रहीत कई (लाखों) स्याही पर बहुत सारी गणनाएं होती हैं, int16 int32 के बराबर तेज़ होता है, कभी-कभी थोड़ा तेज़ भी होता है। पिछले सप्ताह के अंत में इंटेल कोर 2 डुओ और मोटोरोला पीपीसी जी 4 पर इसे बेंचमार्क किया, क्योंकि मैं खुद को जानना चाहता था। दिलचस्प: int8 का उपयोग होने पर सभी CPUs पर सभी परीक्षण सबसे तेज़ थे। – Mecki