c++ मैं लिनक्स में सी++ कोड कैसे चला सकता हूं?




unix profiling (8)

मेरे पास एक सी ++ एप्लिकेशन है, जो लिनक्स पर चल रहा है, जिसे मैं अनुकूलित करने की प्रक्रिया में हूं। मैं कैसे इंगित कर सकता हूं कि मेरे कोड के कौन से क्षेत्र धीरे-धीरे चल रहे हैं?


नए कर्नेल (जैसे नवीनतम उबंटू कर्नेल) नए 'परफ' टूल ( apt-get install linux-tools ) AKA perf_events

ये क्लासिक नमूना प्रोफाइलर्स ( man-page ) के साथ-साथ भयानक timechart !

महत्वपूर्ण बात यह है कि ये उपकरण सिस्टम प्रोफाइलिंग हो सकते हैं और न केवल प्रोफाइलिंग प्रक्रिया कर सकते हैं - वे धागे, प्रक्रियाओं और कर्नेल के बीच बातचीत दिखा सकते हैं और प्रक्रियाओं के बीच शेड्यूलिंग और I / O निर्भरताओं को समझने देते हैं।


ये दो विधियां हैं जिनका उपयोग मैं अपने कोड को तेज़ करने के लिए करता हूं:

सीपीयू बाध्य अनुप्रयोगों के लिए:

  1. अपने कोड के संदिग्ध भागों की पहचान करने के लिए DEBUG मोड में एक प्रोफाइलर का उपयोग करें
  2. फिर रिलीज मोड पर स्विच करें और जब तक आप प्रदर्शन में बदलाव नहीं देखते हैं, तब तक अपने कोड के संदिग्ध खंडों को दबाएं (इसे कुछ भी नहीं दबाएं)।

I / O बाध्य अनुप्रयोगों के लिए:

  1. अपने कोड के संदिग्ध भागों की पहचान करने के लिए रिलीज मोड में एक प्रोफाइलर का उपयोग करें।

एनबी

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

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

I / O-bound के लिए, प्रोफाइलर अभी भी रिलीज मोड में I / O संचालन की पहचान कर सकता है क्योंकि I / O संचालन या तो साझा लाइब्रेरी (अधिकांश समय) या सबसे खराब स्थिति से बाहरी रूप से जुड़े होते हैं, परिणामस्वरूप एक sys- कॉल इंटरप्ट वेक्टर (जो प्रोफाइलर द्वारा आसानी से पहचाना जा सकता है)।


यह नाज़गोब के ग्रप्रोफ उत्तर का जवाब है ।

मैं पिछले कुछ दिनों में जीप्रोफ का उपयोग कर रहा हूं और पहले से ही तीन महत्वपूर्ण सीमाएं पाई हैं, जिनमें से एक मैंने कहीं और दस्तावेज नहीं देखा है (अभी तक):

  1. यह बहु-थ्रेडेड कोड पर ठीक से काम नहीं करता है, जब तक कि आप workaround उपयोग न करें

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

  3. यह here कहता here कि "... संख्याओं के आंकड़े गिनने से प्राप्त होते हैं, नमूना नहीं। वे पूरी तरह से सटीक हैं ..."। फिर भी मुझे अपने कॉल ग्राफ को 5345859132 + 784984078 को मेरे सबसे बुलाए गए फ़ंक्शन पर कॉल आंकड़े के रूप में मिलते हैं, जहां पहली संख्या प्रत्यक्ष कॉल होने वाली है, और दूसरी रिकर्सिव कॉल (जो सभी स्वयं से हैं)। चूंकि यह निहित है, मेरे पास एक बग था, मैंने कोड में लंबे (64-बिट) काउंटर लगाए और एक ही रन फिर से किया। मेरी मायने रखती है: 5345859132 प्रत्यक्ष, और 78094395406 स्वयं-रिकर्सिव कॉल। वहां बहुत सारे अंक हैं, इसलिए मैं बताता हूं कि रिकर्सिव कॉल जो मैं मापता हूं, वह 78 बीएन है, जीआरओफ़ से 784 मीटर बनाम: 100 अलग-अलग कारक। दोनों रन सिंगल थ्रेडेड और अनप्टीमिज्ड कोड थे, एक संकलित-जी और अन्य -जीपी।

यह जीएनयू Gprof (डेबियन के लिए जीएनयू Gprof ) 2.18.0.20080103 64-बिट डेबियन लेनी के तहत चल रहा था, अगर यह किसी की मदद करता है।


यदि आपका लक्ष्य प्रोफाइलर का उपयोग करना है, तो सुझाए गए लोगों में से एक का उपयोग करें।

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

बस इसे कई बार रोक दें, और हर बार कॉल स्टैक को देखें। यदि कुछ कोड है जो समय के कुछ प्रतिशत, 20% या 50% या जो कुछ भी बर्बाद कर रहा है, तो यह संभावना है कि आप प्रत्येक नमूने पर इस अधिनियम में इसे पकड़ लेंगे। तो यह लगभग नमूने का प्रतिशत है जिस पर आप इसे देखेंगे। कोई शिक्षित अनुमान नहीं है। यदि आपके पास अनुमान है कि समस्या क्या है, तो यह साबित या अस्वीकार कर देगा।

आपके पास विभिन्न आकारों की कई प्रदर्शन समस्याएं हो सकती हैं। यदि आप उनमें से किसी एक को साफ़ करते हैं, तो शेष लोग एक बड़ा प्रतिशत लेंगे, और बाद के पासों पर स्पॉट करना आसान होगा। यह आवर्धन प्रभाव , जब कई समस्याओं पर मिश्रित होता है , तो वास्तव में बड़े पैमाने पर गतिशील कारकों का कारण बन सकता है।

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

  1. वे निर्देश स्तर पर सारांशित नहीं करते हैं, और
  2. वे रिकर्सन की उपस्थिति में भ्रमित सारांश देते हैं।

वे यह भी कहेंगे कि यह केवल खिलौनों के कार्यक्रमों पर काम करता है, जब वास्तव में यह किसी भी कार्यक्रम पर काम करता है, और ऐसा लगता है कि बड़े कार्यक्रमों पर बेहतर काम होता है, क्योंकि उन्हें खोजने में और अधिक समस्याएं होती हैं। वे कहेंगे कि कभी-कभी ऐसी चीजें होती हैं जो समस्या नहीं होती हैं, लेकिन यह केवल तभी सच है जब आप एक बार कुछ देखते हैं। यदि आपको एक से अधिक नमूने पर कोई समस्या दिखाई देती है, तो यह वास्तविक है।

पीएस यह बहु-थ्रेड कार्यक्रमों पर भी किया जा सकता है यदि थ्रेड पूल के कॉल-स्टैक नमूने इकट्ठा करने का कोई तरीका है, जैसा कि जावा में है।

पीपीएस एक मोटा सामान्यता के रूप में, आपके सॉफ़्टवेयर में आपके पास अमूर्तता की अधिक परतें हैं, अधिक संभावना है कि आपको यह पता चल जाएगा कि यह प्रदर्शन समस्याओं का कारण है (और गति प्राप्त करने का अवसर)।

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

एक और आपत्ति जो मैं अक्सर सुनता हूं वह है: " यह किसी जगह को यादृच्छिक रूप से रोक देगा, और यह वास्तविक समस्या को याद करेगा "। यह वास्तविक समस्या क्या है इसकी पूर्व अवधारणा होने से आता है। प्रदर्शन समस्याओं की एक प्रमुख संपत्ति यह है कि वे उम्मीदों को खारिज करते हैं। नमूनाकरण आपको बताता है कि कुछ समस्या है, और आपकी पहली प्रतिक्रिया अविश्वास है। यह स्वाभाविक है, लेकिन आप यह सुनिश्चित कर सकते हैं कि क्या यह एक समस्या पाता है, यह वास्तविक है, और इसके विपरीत।

जोड़ा गया: मुझे बेयसियन स्पष्टीकरण दें कि यह कैसे काम करता है। मान लीजिए कि कुछ निर्देश I (कॉल या अन्यथा) है जो कि कॉल पर है, उस समय कुछ अंश f (और इस प्रकार बहुत अधिक खर्च करता है)। सादगी के लिए, मान लीजिए कि हम नहीं जानते कि f क्या है, लेकिन मान लीजिए कि यह 0.1, 0.2, 0.3, ... 0.9, 1.0 है, और इनमें से प्रत्येक संभावना की पूर्व संभावना 0.1 है, इसलिए ये सभी लागत समान रूप से समान हैं संभावना पूर्व-प्राथमिकता।

तो मान लें कि हम केवल 2 स्टैक नमूने लेते हैं, और हम दोनों नमूने, नामित अवलोकन o=2/2 2/2 पर निर्देश I देखते हैं। यह हमें आवृत्ति f के नए अनुमान देता है, इसके अनुसार:

Prior                                    
P(f=x) x  P(o=2/2|f=x) P(o=2/2&&f=x)  P(o=2/2&&f >= x)  P(f >= x)

0.1    1     1             0.1          0.1            0.25974026
0.1    0.9   0.81          0.081        0.181          0.47012987
0.1    0.8   0.64          0.064        0.245          0.636363636
0.1    0.7   0.49          0.049        0.294          0.763636364
0.1    0.6   0.36          0.036        0.33           0.857142857
0.1    0.5   0.25          0.025        0.355          0.922077922
0.1    0.4   0.16          0.016        0.371          0.963636364
0.1    0.3   0.09          0.009        0.38           0.987012987
0.1    0.2   0.04          0.004        0.384          0.997402597
0.1    0.1   0.01          0.001        0.385          1

                  P(o=2/2) 0.385                

अंतिम कॉलम कहता है कि, उदाहरण के लिए, संभावना 60% की पूर्व धारणा से f > = 0.5 92% है।

मान लीजिए कि पूर्व धारणाएं अलग हैं। मान लीजिए कि हम मानते हैं कि पी (एफ = 0.1) .991 (लगभग निश्चित) है, और अन्य सभी संभावनाएं लगभग असंभव हैं (0.001)। दूसरे शब्दों में, हमारी पूर्व निश्चितता यह है कि I सस्ता I । फिर हमें मिलता है:

Prior                                    
P(f=x) x  P(o=2/2|f=x) P(o=2/2&& f=x)  P(o=2/2&&f >= x)  P(f >= x)

0.001  1    1              0.001        0.001          0.072727273
0.001  0.9  0.81           0.00081      0.00181        0.131636364
0.001  0.8  0.64           0.00064      0.00245        0.178181818
0.001  0.7  0.49           0.00049      0.00294        0.213818182
0.001  0.6  0.36           0.00036      0.0033         0.24
0.001  0.5  0.25           0.00025      0.00355        0.258181818
0.001  0.4  0.16           0.00016      0.00371        0.269818182
0.001  0.3  0.09           0.00009      0.0038         0.276363636
0.001  0.2  0.04           0.00004      0.00384        0.279272727
0.991  0.1  0.01           0.00991      0.01375        1

                  P(o=2/2) 0.01375                

अब यह कहता है कि पी (एफ> = 0.5) 0.6% की पूर्व धारणा से 26% है। तो बेयस हमें संभावित लागत के हमारे अनुमान को अपडेट करने की अनुमति देता है। यदि डेटा की मात्रा कम है, तो यह हमें सटीक रूप से नहीं बताती कि लागत क्या है, केवल इतना है कि यह ठीक करने के लायक होने के लिए पर्याप्त है।

फिर भी इसे देखने का एक और तरीका उत्तराधिकार का नियम कहा जाता है। यदि आप 2 बार सिक्का फिसलते हैं, और यह दोनों बार सिर आता है, तो यह आपको सिक्के के संभावित भार के बारे में क्या बताता है? उत्तर देने का सम्मानित तरीका यह कहना है कि यह बीटा वितरण है, औसत मूल्य (हिट + 1 की संख्या) / (प्रयासों की संख्या + 2) = (2 + 1) / (2 + 2) = 75%।

(कुंजी यह है कि हम एक बार से अधिक बार देखते हैं। अगर हम इसे केवल एक बार देखते हैं, तो यह हमें f > 0. को छोड़कर बहुत कुछ नहीं बताता है।)

इसलिए, नमूने की एक बहुत छोटी संख्या हमें निर्देशों की लागत के बारे में बहुत कुछ बता सकती है जो इसे देखती है। (और यह उन्हें एक आवृत्ति के साथ, औसतन, उनकी लागत के आनुपातिक रूप से देखेगा। यदि n नमूने लिया जाता है, और f लागत है, तो I nf+/-sqrt(nf(1-f)) नमूने पर दिखाई दूंगा। उदाहरण , n=10 , f=0.3 , यह 3+/-1.4 नमूने है।)

मापने और यादृच्छिक ढेर नमूनाकरण के बीच अंतर के लिए एक सहज अनुभव देने के लिए जोड़ा गया:
अब प्रोफाइलर हैं जो दीवार घड़ी के समय भी ढेर का नमूना देते हैं, लेकिन क्या आता है माप (या गर्म पथ, या गर्म स्थान, जिसमें से एक "बाधा" आसानी से छिप सकती है)। वे आपको क्या नहीं दिखाते (और वे आसानी से कर सकते हैं) वास्तविक नमूने स्वयं हैं। और यदि आपका लक्ष्य बाधा को ढूंढना है, तो आपको जिनकी संख्या देखने की आवश्यकता है, वह औसतन 2 है, जो उस समय के अंश से विभाजित होता है। तो अगर इसमें 30% समय लगता है, तो औसतन 2 / .3 = 6.7 नमूने इसे दिखाएंगे, और 20 नमूने दिखाए जाने का मौका 99.2% होगा।

माप की जांच और स्टैक नमूने की जांच के बीच अंतर का एक ऑफ-द-कफ चित्रण यहां दिया गया है। बाधा इस तरह एक बड़ा ब्लॉब हो सकता है, या कई छोटे, यह कोई फर्क नहीं पड़ता।

मापन क्षैतिज है; यह आपको बताता है कि समय के विशिष्ट दिनचर्या का कितना अंश लेता है। नमूना लंबवत है। यदि उस पल में पूरा कार्यक्रम क्या कर रहा है, इससे बचने का कोई तरीका है, और यदि आप इसे दूसरे नमूने पर देखते हैं , तो आपको बाधा मिली है। यही कारण है कि अंतर - समय के लिए पूरे कारण को देखते हुए, इतना नहीं।


मैं अपने प्रोफाइलिंग टूल सूट के लिए आधार के रूप में Valgrind और Callgrind का उपयोग करूंगा। जानना महत्वपूर्ण है कि वालग्रिंड मूल रूप से वर्चुअल मशीन है:

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

Callgrind उस पर एक प्रोफाइलर निर्माण है। मुख्य लाभ यह है कि आपको विश्वसनीय परिणाम प्राप्त करने के लिए घंटों तक अपना आवेदन चलाने की ज़रूरत नहीं है। रॉक-ठोस, भरोसेमंद नतीजे पाने के लिए भी एक दूसरा रन पर्याप्त है, क्योंकि कॉलग्रींड एक गैर-प्रोबिंग प्रोफाइलर है।

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


सिंगल-थ्रेडेड प्रोग्राम्स के लिए आप इगप्रोफ , द इग्नोमिनस प्रोफाइलर का उपयोग कर सकते हैं: https://igprof.org/

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


मुझे लगता है कि आप जीसीसी का उपयोग कर रहे हैं। मानक समाधान gprof साथ प्रोफाइल करना होगा।

प्रोफाइलिंग से पहले संकलन में -pg जोड़ना सुनिश्चित करें:

cc -o myprog myprog.c utils.c -g -pg

मैंने अभी तक यह कोशिश नहीं की है लेकिन मैंने google-perftools बारे में अच्छी बातें सुनी हैं। यह निश्चित रूप से एक कोशिश के लायक है।

here संबंधित प्रश्न here

कुछ अन्य buzzwords अगर gprof आपके लिए नौकरी नहीं करता है: Valgrind , Intel VTune , Sun DTrace


Valgrind, callgrind और kcachegrind का प्रयोग करें:

valgrind --tool=callgrind ./(Your binary)

callgrind.out.x उत्पन्न करता है। Kcachegrind का उपयोग कर इसे पढ़ें।

Gprof (add -pg) का प्रयोग करें:

cc -o myprog myprog.c utils.c -g -pg 

(बहु-धागे, फ़ंक्शन पॉइंटर्स के लिए इतना अच्छा नहीं है)

Google-perftools का प्रयोग करें:

समय नमूनाकरण का उपयोग करता है, पता चलता है I / O और CPU बाधाओं का खुलासा किया जाता है।

इंटेल वीट्यून सबसे अच्छा है (शैक्षणिक उद्देश्यों के लिए मुफ्त)।

अन्य: एएमडी कोडेनालिस्ट, ओप्रोफाइल, 'परफ' टूल्स (एपीटी-लिनक्स-टूल्स इंस्टॉल करें)





profiling