ठीक है, आप समस्या को परिभाषित कर रहे हैं जहां यह प्रतीत होता है कि सुधार के लिए बहुत जगह नहीं है। मेरे अनुभव में यह काफी दुर्लभ है। मैंने नवंबर 1993 में डॉ। डॉब्स लेख में इसे स्पष्ट करने की कोशिश की, जिसमें पारंपरिक रूप से अच्छी तरह से डिज़ाइन किए गए गैर-तुच्छ कार्यक्रम से शुरू हुआ, जिसमें कोई स्पष्ट अपशिष्ट नहीं था और इसे अनुकूलन की एक श्रृंखला के माध्यम से ले जाया गया जब तक कि इसकी दीवार-घड़ी का समय 48 सेकंड से कम नहीं हुआ। 1.1 सेकंड के लिए, और स्रोत कोड का आकार 4. के एक कारक से कम हो गया था। मेरा नैदानिक उपकरण यह था । परिवर्तनों का क्रम यह था:
पहली समस्या पाई गई सूची समूहों का उपयोग (जिसे अब "पुनरावृत्त" और "कंटेनर कक्षाएं" कहा जाता है) आधे से अधिक समय के लिए लेखांकन। जिन्हें काफी सरल कोड से बदल दिया गया था, जिससे समय 20 सेकंड तक नीचे आ गया।
अब सबसे बड़ा टाइम-टेकर अधिक सूची-निर्माण है। प्रतिशत के रूप में, यह पहले इतना बड़ा नहीं था, लेकिन अब यह इसलिए है क्योंकि बड़ी समस्या को हटा दिया गया था। मुझे इसे गति देने का एक तरीका मिल गया है, और समय 17 सेकंड तक गिर जाता है।
अब स्पष्ट अपराधियों को ढूंढना कठिन है, लेकिन कुछ छोटे हैं जिनके बारे में मैं कुछ कर सकता हूं, और समय 13 सेकंड तक चला जाता है।
अब मैं एक दीवार से टकराया लगता हूं। नमूने मुझे बता रहे हैं कि यह क्या कर रहा है, लेकिन मुझे ऐसा कुछ भी नहीं मिल रहा है जिसे मैं सुधार सकता हूं। तब मैं कार्यक्रम के मूल डिजाइन पर, इसके लेन-देन से संचालित संरचना पर प्रतिबिंबित करता हूं, और पूछता हूं कि क्या सभी सूची-खोज जो यह कर रही है, वास्तव में समस्या की आवश्यकताओं से अनिवार्य है।
फिर मैंने एक री-डिज़ाइन पर मारा, जहां प्रोग्राम कोड वास्तव में स्रोत के एक छोटे से सेट से (प्रीप्रोसेसर मैक्रोज़ के माध्यम से) उत्पन्न होता है, और जिसमें प्रोग्राम लगातार उन चीजों का पता नहीं लगा रहा है जो प्रोग्रामर को पता है कि काफी अनुमानित है। दूसरे शब्दों में, इसे करने के लिए चीजों के अनुक्रम की "व्याख्या" न करें, इसे "संकलित" करें।
- उस रीडिज़ाइन को किया जाता है, जो स्रोत कोड को 4 के कारक से सिकोड़ता है, और समय 10 सेकंड तक कम हो जाता है।
अब, क्योंकि यह इतनी जल्दी हो रहा है, यह नमूना करना कठिन है, इसलिए मैं इसे करने के लिए 10 गुना अधिक काम देता हूं, लेकिन निम्नलिखित समय मूल कार्यभार पर आधारित हैं।
अधिक निदान से पता चलता है कि यह कतार-प्रबंधन में समय बिता रहा है। इन-लाइनिंग में 7 सेकंड का समय कम हो जाता है।
अब एक बड़ा समय लेने वाला नैदानिक मुद्रण है जो मैं कर रहा था। फ्लश कि - 4 सेकंड।
अब सबसे बड़े टाइम-टेकर्स मॉलॉक और फ्री में कॉल करते हैं । ऑब्जेक्ट को रीसायकल - 2.6 सेकंड।
नमूना जारी रखते हुए, मुझे अभी भी ऐसे ऑपरेशन मिलते हैं जो कड़ाई से आवश्यक नहीं हैं - 1.1 सेकंड।
कुल गति कारक: 43.6
अब कोई भी दो कार्यक्रम एक जैसे नहीं हैं, लेकिन गैर-खिलौना सॉफ्टवेयर में मैंने हमेशा इस तरह की प्रगति देखी है। पहले आपको आसान सामान मिलता है, और फिर अधिक कठिन होता है, जब तक कि आप कम रिटर्न वाले बिंदु तक नहीं पहुंचते। तब आपके द्वारा हासिल की गई अंतर्दृष्टि अच्छी तरह से एक नया स्वरूप प्रदान कर सकती है, स्पीडअप के एक नए दौर की शुरुआत, जब तक आप फिर से कम रिटर्न नहीं मारते। अब इस बिंदु है जिस पर यह है कि क्या आश्चर्य का कोई मतलब हो सकता है ++i
या i++
या for(;;)
या while(1)
कर रहे हैं तेजी से: प्रकार के प्रश्नों के मैं स्टैक ओवरफ़्लो पर तो अक्सर देखते हैं।
PS यह आश्चर्य हो सकता है कि मैंने एक प्रोफाइलर का उपयोग क्यों नहीं किया। इसका उत्तर यह है कि इनमें से लगभग हर एक "समस्या" एक फ़ंक्शन कॉल साइट थी, जो नमूनों को इंगित करती है। प्रोफाइलर, आज भी, बस मुश्किल से इस विचार के आसपास आ रहे हैं कि बयान और कॉल निर्देश पूरे कार्यों की तुलना में पता लगाने, और ठीक करने में आसान हैं।
मैंने वास्तव में ऐसा करने के लिए एक प्रोफाइलर का निर्माण किया, लेकिन कोड क्या कर रहा है, इसके साथ एक वास्तविक डाउन-एंड-डर्टी अंतरंगता के लिए, अपनी उंगलियों को सही तरीके से प्राप्त करने के लिए कोई विकल्प नहीं है। यह कोई समस्या नहीं है कि नमूनों की संख्या छोटी है, क्योंकि इनमें से कोई भी समस्या इतनी कम नहीं है कि वे आसानी से छूट जाएं।
जोड़ा: jerryjvl ने कुछ उदाहरणों का अनुरोध किया। यहाँ पहली समस्या है। इसमें कोड की अलग-अलग पंक्तियों की एक छोटी संख्या होती है, साथ में आधा समय लगता है:
/* IF ALL TASKS DONE, SEND ITC_ACKOP, AND DELETE OP */
if (ptop->current_task >= ILST_LENGTH(ptop->tasklist){
. . .
/* FOR EACH OPERATION REQUEST */
for ( ptop = ILST_FIRST(oplist); ptop != NULL; ptop = ILST_NEXT(oplist, ptop)){
. . .
/* GET CURRENT TASK */
ptask = ILST_NTH(ptop->tasklist, ptop->current_task)
ये सूची क्लस्टर ILST (एक सूची वर्ग के समान) का उपयोग कर रहे थे। उन्हें सामान्य तरीके से लागू किया जाता है, जिसमें "सूचना छिपाना" का अर्थ है कि वर्ग के उपयोगकर्ताओं को परवाह नहीं थी कि उन्हें कैसे लागू किया गया है। जब इन पंक्तियों को लिखा गया था (लगभग 800 पंक्तियों की कोड में से) विचार इस विचार को नहीं दिया गया था कि ये एक "अड़चन" हो सकता है (मुझे उस शब्द से नफरत है)। वे बस चीजों को करने का अनुशंसित तरीका हैं। यह कहना आसान है कि इन बातों से बचना चाहिए था, लेकिन मेरे अनुभव में प्रदर्शन की सभी समस्याएं ऐसी हैं। सामान्य तौर पर, प्रदर्शन समस्याओं को बनाने से बचने की कोशिश करना अच्छा है। यह उन लोगों को खोजने और ठीक करने के लिए बेहतर है जो बनाए गए हैं, भले ही उन्हें "टाला जाना चाहिए" (दृष्टि में)।
यहाँ दो अलग लाइनों में दूसरी समस्या है:
/* ADD TASK TO TASK LIST */
ILST_APPEND(ptop->tasklist, ptask)
. . .
/* ADD TRANSACTION TO TRANSACTION QUEUE */
ILST_APPEND(trnque, ptrn)
ये आइटम को उनके सिरों पर जोड़कर सूची बना रहे हैं। (फिक्स को सरणियों में आइटम एकत्र करना था, और एक ही बार में सभी सूचियों का निर्माण करना था।) दिलचस्प बात यह है कि ये कथन केवल लागत (यानी कॉल स्टैक पर) मूल समय के 3/48 थे, इसलिए वे अंदर नहीं थे वास्तव में शुरुआत में एक बड़ी समस्या । हालांकि, पहली समस्या को दूर करने के बाद, उन्होंने उस समय का 3/20 खर्च किया और इसलिए अब एक "बड़ी मछली" थी। सामान्य तौर पर, यह है कि यह कैसे जाता है।
मैं जोड़ सकता हूं कि यह परियोजना एक वास्तविक परियोजना से डिस्टिल्ड थी जिस पर मैंने मदद की थी। उस परियोजना में, प्रदर्शन की समस्याएं कहीं अधिक नाटकीय थीं (जैसे कि स्पीडअप थीं), जैसे कि किसी कार्य को पूरा करने के लिए आंतरिक लूप के भीतर डेटाबेस-एक्सेस रूटीन को कॉल करना।
संदर्भ जोड़ा: स्रोत कोड, दोनों मूल और पुन: डिज़ाइन, www.ddj.com में , 1993 के लिए, फ़ाइल 9311.zip में, फ़ाइल slug.asc और slug.zip में पाया जा सकता है ।
EDIT 2011/11/26: विजुअल C ++ में स्रोत कोड युक्त एक SourceForge प्रोजेक्ट है और इसे कैसे ट्यून किया गया था, इसका ब्लो-बाय-ब्लो विवरण है। यह केवल ऊपर वर्णित परिदृश्य के पहले आधे हिस्से से गुजरता है, और यह ठीक उसी क्रम का पालन नहीं करता है, लेकिन फिर भी मैग्नेट स्पीडअप का 2-3 ऑर्डर मिलता है।