2012-09-01 15 views
8

यह आम लिस्प फ़ंक्शन, जो कि दीवार के वायरफ्रेम किनारों के चार सिरों की गणना करता है, जिसमें बेहद सरल किंडरगार्टन-स्तर अंकगणित और कुछ 'केस' परीक्षण गतिशील रूप से 1 9 6608 बाइट प्रति रेंडर फ्रेम आवंटित करने के लिए जिम्मेदार प्रतीत होते हैं; एसबीसीएल का प्रोफाइलर मुझे बताता है कि यह मेरा सबसे समस्याग्रस्त कार्य है जहां तक ​​विपक्ष जाता है। मैं जो काम कर रहा हूं उसके बारे में एक सामान्य विचार देने के लिए, यह एक छोटा पहला व्यक्ति डंगऑन क्रॉलर गेम है, और एक कालकोठरी बिल्कुल 32x32 कोशिकाएं होती है, और प्रत्येक कक्ष में 4 दीवारें होती हैं। 32 * 32 * 4 * एक्स = 1 9 6608, और इसलिए एक्स 48 हो गया है, जो 4 * 12 (4 दीवारें * 12 फ्लोट प्रति दीवार हो सकता है? शायद नहीं)।इस आम लिस्प समारोह में "रहस्य-consing" को खत्म करना?

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

  1. 'गति' के लिए 'अनुकूलन' के लिए एक 'घोषित' कर रहा:

    (defun calculate-wall-points (x y wall) 
        (declare (integer x y) 
          (keyword wall)) 
        "Return the 4 vertices (12 floats) of a given dungeon cell wall" 
        (let ((xf (coerce x 'float)) 
         (yf (coerce y 'float))) 
        (case wall 
         (:SOUTH 
         (values xf yf 0.0 
           (1+ xf) yf 0.0 
           (1+ xf) yf 1.0 
           xf yf 1.0)) 
         (:WEST 
         (values xf yf 0.0 
           xf yf 1.0 
           xf (1+ yf) 1.0 
           xf (1+ yf) 0.0)) 
         (:NORTH 
         (values xf (1+ yf) 0.0 
           xf (1+ yf) 1.0 
           (1+ xf) (1+ yf) 1.0 
           (1+ xf) (1+ yf) 0.0)) 
         (:EAST 
         (values (1+ xf) (1+ yf) 0.0 
           (1+ xf) (1+ yf) 1.0 
           (1+ xf) yf 1.0 
           (1+ xf) yf 0.0)) 
    
         (otherwise 
         (error "Not a valid heading passed for wall in function calculate-wall-points: ~A" wall))))) 
    

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

  2. तब मैंने सोचा कि 'मूल्य' यह कर रहे हैं। शायद, मैंने सोचा, यह आंतरिक रूप से केवल 'सूची' की तरह कुछ है, जो बिना किसी संदेह के, conses (ब्रह्मांड में 'सूची' फ़ंक्शन का एकमात्र उद्देश्य है)। इसे कम करने की कोशिश करने के लिए मैंने क्या किया? बस प्रयोग के लिए, मैंने फ़ाइल को एक दीवार-वर्टेक्स-बफर ग्लोबल सरणी बनाने के लिए संशोधित किया, आकार के फ्लोट के 12 तत्वों को फिट करने के लिए आकार दिया, और इसे संशोधित करने के लिए इस फ़ंक्शन को संशोधित किया, और कॉलिंग फ़ंक्शन इसके बाद से पढ़ने के लिए इस फ़ंक्शन को कॉल करना (इसलिए यह लगातार किसी भी स्थान को आवंटित करने के बजाय स्मृति में उसी स्थान पर रखे 12 फ्लोट्स का एक सेट सेट करेगा)। आश्चर्य की बात है, इसने इस समारोह को एक विपक्षी-पिग्गी होने से नहीं रोका! तो ... 'मामला' कर रहा था? मुझे यह दिलचस्प लगता है कि, पहले उल्लेख किया गया था कि रहस्य संख्या 48 थी। 48 = 4 * 12, शायद उन 4 केस परीक्षण 12 फ्लोट प्रति 'मूल्य' कॉल के समय। या, यह एक संयोग हो सकता है, जिसमें 48 बाइट्स का अर्थ कुछ और है (चूंकि एक फ्लोट 1 बाइट नहीं है, मुझे संदेह है कि यह कुछ और है)। यह महत्वपूर्ण लगता है, लेकिन मैं अपने सिर को लपेट नहीं सकता कि मेरे अगले दृष्टिकोण क्या हो।

  3. 'मामले' को 'cond' समकक्ष के साथ बदलने की कोशिश की, बस इस बिंदु पर स्ट्रॉ के लिए grasping, कुछ भी नहीं किया।

तो यह कार्य कहां से "रहस्य consing" आ सकता है? आप एक और समस्या के इस मुश्किल gremlin दृष्टिकोण से अधिक अनुभवी लिस्प प्रोग्रामर कैसे अनुभव करेंगे?


(EDIT) @FheheemMitha के लिए, वह कार्य है जो गणना-दीवार-बिंदु फ़ंक्शन का उपयोग करता है; कि परेशानी समारोह बाद में साथ inlined गया था (सुचना (इनलाइन गणना दीवार-अंक)) बस से पहले की गणना दीवार-अंक की परिभाषा:

(defun render-dungeon-room (dungeon-object x y) 
    (declare (optimize (speed 3) (space 0) (debug 0))) 
    (declare (type fixnum x y)) 
    (let ((cell (cell-at dungeon-object x y))) 
    (unless (null cell) 
     (dolist (wall-heading +basic-headings+) 
    (unless (eq wall-heading (opposite-heading *active-player-heading*)) 
     (when (eql (get-wall-type cell wall-heading) :NORMAL) 
     (multiple-value-bind (v1x v1y v1z v2x v2y v2z v3x v3y v3z v4x v4y v4z) 
     (calculate-wall-points x y wall-heading) 
      (declare (type float v1x v1y v1z v2x v2y v2z v3x v3y v3z v4x v4y v4z)) 

     (gl:with-primitive :quads 
    (if (is-edit-mode) 
     (case wall-heading 
      (:NORTH 
      (gl:color 0.4 0.4 0.4)) 
      (:WEST 
      (gl:color 0.4 0.0 0.0)) 
      (:SOUTH 
      (gl:color 0.0 0.0 0.4)) 
      (:EAST 
      (gl:color 0.0 0.4 0.0))) 
     (gl:color 0.1 0.1 0.1)) 
    (gl:vertex (the float v1x) 
      (the float v1y) 
      (the float v1z)) 
    (gl:vertex (the float v2x) 
      (the float v2y) 
      (the float v2z)) 
    (gl:vertex (the float v3x) 
      (the float v3y) 
      (the float v3z)) 
    (gl:vertex (the float v4x) 
      (the float v4y) 
      (the float v4z))) 

     (gl:color 1.0 1.0 1.0) 
     (gl:with-primitive :line-loop 
    (gl:vertex (the float v1x) 
      (the float v1y) 
      (the float v1z)) 
    (gl:vertex (the float v2x) 
      (the float v2y) 
      (the float v2z)) 
    (gl:vertex (the float v3x) 
      (the float v3y) 
      (the float v3z)) 
    (gl:vertex (the float v4x) 
      (the float v4y) 
      (the float v4z))))))))) 

शून्य)

उत्तर

9

स्मृति consed आवंटन के कारण होता है तैरता है। प्रत्येक फ़ंक्शन कॉल फ्लोट करता है, वास्तव में 32 बिट single-floatsConsing मतलब है कि कुछ डेटा ढेर पर आवंटित किया जाता है: विपक्ष कोशिकाओं, संख्या, सरणियों, ...

एक single-float है 32 बिट स्मृति वस्तु। 4 निवाले।

(+ 1.0 2.0) -> 3.0 

उपरोक्त मामले 3.0 में, एक नए नाव है संभवतः नव consed।

(+ (+ 1.0 2.0) 4.0) -> 7.0) 

अब ऊपर की गणना से ऊपर क्या है? आंतरिक + ऑपरेशन एक फ्लोट 3.0 देता है। इसके साथ क्या होता है?

  • इसे प्रोसेसर रजिस्टर में वापस किया जा सकता है और अगले ऑपरेशन के लिए वहां उपयोग किया जा सकता है।
  • इसे स्टैक पर वापस किया जा सकता है और अगले ऑपरेशन के लिए
  • अधिक जटिल ऑपरेशन में इसे ढेर में आवंटित किया जा सकता है और एक ढेर मूल्य के लिए सूचक के रूप में लौटाया जा सकता है। यह मामला हो सकता है यदि सभी लौटाए गए मूल्यों के लिए पर्याप्त रजिस्ट्रार नहीं हैं या स्टैक फ्रेम का आकार सभी लौटाए गए मूल्यों के लिए पर्याप्त नहीं है।

अब बाद में इन फ्लोट्स के साथ क्या होता है? क्या वे किसी भी तरह से संग्रहीत हैं? एक सूची में? एक नई सरणी में? एक नए structure में? एक नई CLOS ऑब्जेक्ट में?

ऊपर यह स्पष्ट करता है कि यह प्रोसेसर आर्किटेक्चर और कंपाइलर रणनीति पर निर्भर करता है। एक x86 में कई रजिस्ट्रार नहीं हैं। 64 बिट संस्करण में और भी है। एक आरआईएससी प्रोसेसर में और भी रजिस्ट्रार हैं। फिर ढेर कितना बड़ा है और ठेठ ढेर फ्रेम कितने बड़े हैं?

कई कार्यों को शामिल करने के लिए अधिक जटिल गणनाओं के लिए एक अनुकूलन कंपाइलर अनुकूलित करने में सक्षम हो सकता है कि कौन से मूल्य रजिस्टरों में रहते हैं और इस प्रकार विपक्ष को कम करते हैं।

ऊपर यह भी स्पष्ट करता है कि आम लिस्प के लिए फ्लोट ऑपरेशंस को गैर-सहमति देने के लिए कोई पूरी तरह से सामान्य नुस्खा नहीं है। Consing को कम करने की क्षमता कुछ सामान्य विचारों पर निर्भर करती है और बहुत सारे कंपाइलर/आर्किटेक्चर विशिष्ट चाल पर निर्भर करती है।

चूंकि आप एसबीसीएल का उपयोग कर रहे हैं, एसबीसीएल मेलिंग सूची पर सलाह मांगना और ओएस, आर्किटेक्चर (इंटेल, आर्म, ...) के बारे में उन्हें बताना और यह 32 बिट या 64 बिट मोड में चल रहा है। एक बेहतर तस्वीर के साथ आने के लिए अधिक संदर्भ कोड भी आवश्यक है कि कैसे कम किया जा सकता है। पढ़ने के लिए

कुछ पृष्ठभूमि जानकारी:

  • Fast Floating-Point Processing in Common Lisp
  • केन एंडरसन (जो दुर्भाग्य से कुछ साल पहले मृत्यु हो गई, एक बहुत ही उपयोगी Lisper) कुछ जानकारी के बारे में Lisp and Performance, Files (संग्रहीत संस्करण) इकट्ठा किया था।
+1

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

+0

@valq: नमस्ते। मुझे फ़ंक्शन विवाद रोकने के लिए आपने जो किया है, उसके विवरण में रूचि है। क्या आप प्रश्न में या एक अलग उत्तर के रूप में, अपने पूर्व और पोस्ट अनुकूलन कोड के उदाहरण पोस्ट कर सकते हैं? धन्यवाद। –

+0

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

1

कंपाइलर क्या कहता है? यदि आप गति के लिए अनुकूलित करते हैं तो इसे अंकगणित कोड को खोलने में सक्षम नहीं होने के बारे में जोर से शिकायत करनी चाहिए।

अगला, कॉरसिंग के साथ क्या हो रहा है? क्या यह खुले कोडित भी है?

अंत में, याद रखें कि आप आमतौर पर विधानसभा-कोड एक समारोह के साथ जुदा()

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