2012-05-21 6 views
15

मैं अपनी परियोजनाओं में से एक में एक कस्टम ढेर कार्यान्वयन का उपयोग करता हूं। यह दो प्रमुख हिस्से होते हैं:हीप एकल-थ्रेडेड उपयोग के लिए अनुकूलित (लेकिन इस तक सीमित नहीं है)

  1. फिक्स्ड आकार-ब्लॉक ढेर। अर्थात। एक ढेर जो केवल एक विशिष्ट आकार के ब्लॉक आवंटित करता है। यह बड़े मेमोरी ब्लॉक (या तो वर्चुअल मेमोरी पेज या किसी अन्य ढेर से) आवंटित करता है, और फिर उन्हें परमाणु आवंटन इकाइयों में विभाजित करता है।

    यह आवंटन/तेजी से मुक्त करता है (ओ (1) में) और बाहरी ढेर द्वारा लगाई गई चीजों को ध्यान में रखते हुए कोई मेमोरी उपयोग ओवरहेड नहीं होता है।

  2. वैश्विक सामान्य उद्देश्य ढेर। इसमें उपरोक्त (निश्चित आकार) ढेर की बाल्टी होती है। अनुरोधित आवंटन आकार डब्लूआरटी उचित बाल्टी चुनता है, और इसके माध्यम से आवंटन करता है।

    चूंकि पूरा आवेदन (भारी) बहु थ्रेडेड है - वैश्विक ढेर ताले इसके संचालन के दौरान उपयुक्त बाल्टी।

    नोट: पारंपरिक ढेर के विपरीत, इस ढेर को न केवल आवंटन के लिए आवंटन आकार की आवश्यकता होती है, बल्कि मुक्त करने के लिए भी आवंटन आकार की आवश्यकता होती है। यह खोजों या अतिरिक्त मेमोरी ओवरहेड के बिना उपयुक्त बाल्टी की पहचान करने की अनुमति देता है (जैसे आवंटित ब्लॉक से पहले ब्लॉक आकार को सहेजना)। हालांकि कुछ हद तक कम सुविधाजनक, यह मेरे मामले में ठीक है। इसके अलावा, चूंकि "बाल्टी कॉन्फ़िगरेशन" संकलन-समय पर ज्ञात है (सी ++ टेम्पलेट वूडू के माध्यम से कार्यान्वित) - उचित बाल्टी संकलन समय पर निर्धारित की जाती है।

अब तक सबकुछ अच्छा दिखता है (और काम करता है)।

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

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

इससे मुझे आश्चर्य होता है: क्या एकल-थ्रेडेड उपयोग के लिए ढेर को अनुकूलित करने के लिए कोई ज्ञात तकनीक है?

संपादित करें: गूगल के tcmalloc बाहर की जाँच के सुझाव देने के लिए @Voo को

विशेष धन्यवाद।

ऐसा लगता है कि मैंने कम-से-कम (कम से कम छोटी वस्तुओं के लिए) किया था। लेकिन इसके अलावा वे प्रति-थ्रेड कैशिंग को बनाए रखते हुए, मेरे पास सटीक समस्या का समाधान करते हैं।

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

ओटीओएच कैशिंग के साथ विचार बहुत आसान और अधिक कुशल लगता है। मैं इसे काम करने की कोशिश करूंगा।

बहुत बहुत धन्यवाद।

पी.एस .:

दरअसल गूगल के tcmalloc महान है। मेरा मानना ​​है कि यह मेरे द्वारा किए गए कार्यों (कम से कम निश्चित आकार के भाग) के समान ही लागू किया गया है।

लेकिन, पैडेंटिक होने के लिए, एक बात है जहां मेरा ढेर बेहतर है। दस्तावेज़ों के मुताबिक, टीसीएमएलओसी एक ओवरहेड लगभग 1% (असम्बद्ध रूप से) लगाता है, जबकि मेरा ओवरहेड 0.0061% है। यह सटीक होने के लिए 4/64K है।

:)

+0

यह मेरा परीक्षण करने के लिए मैं साल पहले किया है याद रखता है। आमतौर पर इस्तेमाल किया जाने वाला "खराब" मानक तंत्र एक अच्छा "कस्टम" कार्यान्वयन के 100 गुना से अधिक समय लेता है। –

+1

मुझे यह देखना अच्छा लगेगा कि मानक स्मृति आवंटक से तेज़ होने पर आपने क्या किया है। चूंकि अधिकांश मानक कार्यान्वयन पहले से ही करते हैं जो आपके दावों (और बहुत कुछ) करने का दावा करते हैं। मुझे ओ (1) उत्सुकता का दावा है, खासकर जब आप कोई ओवरहेड का दावा नहीं करते हैं (मुझे यकीन है कि जब आप इसके पेटेंट के माध्यम से जाते हैं तो आप एक सुंदर पैसा कमाएंगे)। –

+1

संपूर्ण बाल्टी विचार मूल रूप से Google का tcmalloc है (हालांकि यह एक सामान्य आवंटक है क्योंकि इसे गतिशील रूप से तय करना है कि किस बाल्टी का उपयोग करना है)। tcmalloc आपकी समस्या से बचने के लिए थ्रेड स्थानीय भंडारण का उपयोग करता है और केवल सामान्य ढेर से ही आवंटित करता है और इसलिए ताले से बचाता है। – Voo

उत्तर

10

एक विचार प्रति-धागा एक स्मृति allocator बनाए रखना है। ग्लोबल मेमोरी पूल से प्रत्येक आवंटक को मेमोरी के काफी चंकी ब्लॉक प्री-असाइन करें। आसन्न स्मृति पते से चंकी ब्लॉक को आवंटित करने के लिए अपने एल्गोरिदम को डिज़ाइन करें (बाद में उस पर अधिक)।

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

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

इस योजना का एक लाभ यह है कि यह false sharing को खत्म करने के लिए प्रवृत्त होगा, क्योंकि किसी दिए गए धागे के लिए स्मृति को सम्मिलित पता रिक्त स्थान में आवंटित किया जाएगा।

एक तरफ ध्यान दें, अगर आपने इसे पहले से नहीं पढ़ा है, तो मैं अपने मेमोरी प्रबंधन को लागू करने वाले किसी भी व्यक्ति के लिए IBM's Inside Memory Management आलेख सुझाता हूं।

अद्यतन

लक्ष्य बहुत तेजी से स्मृति आवंटन एक मल्टी-थ्रेडेड वातावरण के लिए अनुकूलित (के रूप में यह अपने आप को कैसे करना सीखने के खिलाफ) है, तो वैकल्पिक स्मृति allocators पर एक नजर है। यदि लक्ष्य सीख रहा है, तो शायद उनके स्रोत कोड देखें।

+0

अलावा Hoarde से वहाँ भी है [tcmalloc] (http://goog-perftools.sourceforge.net/doc/tcmalloc.html) जो मूल रूप से ऑप्स (थ्रेड स्थानीय ढेर) और कम स्पष्ट सुधार स्पष्ट साथ प्रस्तावित योजना है। जब मैंने इसका परीक्षण किया, तो यह होर्ड से तेज था लेकिन मुझे लगता है कि उपयोग के मामलों पर निर्भर करता है। – Voo

+0

@Voo: सटीक होने के लिए, यह थ्रेड-लोकल * हीप * नहीं है, लेकिन थ्रेड-लोकल * कैश *, जो एक पूरी तरह से अलग जानवर है। कृपया मेरा अद्यतन प्रश्न पढ़ें। अनुलेख मैं चाहता हूं कि आप मेरी ढेर को बेंचमार्क करें, यह देखने के लिए कि इसकी तुलना कैसे की जाती है। – valdo

+0

आपके सुझावों के लिए धन्यवाद। मुझे झूठी साझाकरण के मौके को कम करने के लिए प्रति-थ्रेड संगत मेमोरी ब्लॉक आवंटित करने के बारे में बिंदु पसंद आया। हालांकि आईएमएचओ असली "मीठा स्थान" प्रति-थ्रेड ** कैशिंग ** है, प्रति-थ्रेड * आवंटक * नहीं है। यह बेहद सरल है और बहु-थ्रेडेड प्रदर्शन के लिए महत्वपूर्ण जुर्माना के बिना एकल-थ्रेडेड उपयोग के लिए संभवतया सर्वश्रेष्ठ संभव प्रदर्शन प्रदान करता है। हां, झूठी साझाकरण की संभावना अधिक है, लेकिन यह सामान्य परिदृश्यों में मामूली आईएमएचओ होगा। – valdo

0

यह एक अच्छा विचार जेफ Bonwicks स्लैब संभाजक और vmem पर क्लासिक कागजात पढ़ने के लिए हो सकता है। मूल स्लैब आवंटक कुछ हद तक लगता है जो आप कर रहे हैं। हालांकि बहुत बहुमुखी अनुकूल नहीं है, यह आपको कुछ विचार दे सकता है।

The Slab Allocator: An Object-Caching Kernel Memory Allocator

फिर वह VMEM साथ अवधारणा है, जो निश्चित रूप से, क्योंकि यह एक बहु cpu वातावरण में बहुत अच्छा व्यवहार किया था आप कुछ विचार दे देंगे बढ़ाया।

Magazines and Vmem: Extending the Slab Allocator to Many CPUs and Arbitrary Resources

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