2012-03-15 32 views
9

मुझे अपने परिपत्र बफर कोड की दक्षता में सुधार करने में कुछ मदद चाहिए।सी सर्कुलर बफर दक्षता में सुधार

मैंने स्टैक ओवरफ्लो के चारों ओर एक नज़र डाली और पाया कि (लगभग) सर्कुलर बफर पर सभी विषय ऐसे बफर या सर्कुलर बफर के मूल कार्यान्वयन के उपयोग के बारे में हैं। मुझे वास्तव में इसे सुपर कुशल बनाने के बारे में जानकारी चाहिए।

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

मैं कोड का सबसे महत्वपूर्ण बिट्स यहाँ डाल देता हूँ, पूर्ण बफर कोड के माध्यम से उपलब्ध है http://dl.dropbox.com/u/39710897/circular%20buffer.rar

किसी को भी मुझे कैसे इस बफर की दक्षता में सुधार करने के लिए पर कुछ संकेत के साथ प्रदान कर सकते हैं?

#define BUFF_SIZE 3    // buffer size set at compile time 

typedef struct buffer{ 
    float buff[BUFF_SIZE]; 
    int readIndex; 
    int writeIndex; 
}buffer; 

/********************************\ 
* void write(buffer* buffer, float value) 
* writes value into the buffer 
* @param buffer* buffer 
* pointer to buffer to be used 
* @param float value 
* valueto be written in buffer 
\********************************/ 
void write(buffer* buffer,float value){ 
    buffer->buff[buffer->writeIndex]=value; 
    buffer->writeIndex++; 
    if(buffer->writeIndex==BUFF_SIZE) 
     buffer->writeIndex=0; 
} 

/********************************\ 
* float readn(buffer* buffer, int Xn) 
* reads specified value from buffer 
* @param buffer* buffer 
* pointer to buffer to be read from 
* @param int Xn 
* specifies the value to be read from buffer counting backwards from the most recently written value 
* i.e. the most recently writen value can be read with readn(buffer, 0), the value written before that with readn(buffer, 1) 
\********************************/ 
float readn(buffer* buffer, int Xn){ 
    int tempIndex; 

    tempIndex=buffer->writeIndex-(Xn+1); 
    while(tempIndex<0){ 
     tempIndex+=BUFF_SIZE; 
    } 

    return buffer->buff[tempIndex]; 
} 
+0

'readIndex' का उपयोग नहीं किया जाता है। – valdo

+0

रीडइंडेक्स वास्तव में ऊपर सूचीबद्ध कार्यों में उपयोग नहीं किया जाता है। इसका उपयोग हालांकि() फ़ंक्शन में किया जाता है जो संलग्न रार फ़ाइल में पाया जा सकता है। यहां सूचीबद्ध readn() फ़ंक्शन बफर (यानी दूसरा अंतिम लिखित मान) – Gurba

उत्तर

12

"ओली चार्ल्सवर्थ" के रूप में सुझाव दिया गया है - यदि आपका बफर आकार 2 की शक्ति है तो आप चीजों को सरल बनाने में सक्षम होंगे। मैं पढ़ना/लिखना कार्य निकाय लिखना चाहता हूं, ताकि इरादा अधिक स्पष्ट हो।

#define BUFF_SIZE 4 
#define BUFF_SIZE_MASK (BUFF_SIZE-1) 

typedef struct buffer{ 
    float buff[BUFF_SIZE]; 
    int writeIndex; 
}buffer; 

void write(buffer* buffer,float value){ 
    buffer->buff[(buffer->writeIndex++) & BUFF_SIZE_MASK] = value; 
} 

float readn(buffer* buffer, int Xn){ 
    return buffer->buff[(buffer->writeIndex + (~Xn)) & BUFF_SIZE_MASK]; 
} 

कुछ स्पष्टीकरण। ध्यान दें कि कोई शाखा नहीं है (if) बिल्कुल। हम सरणी अनुक्रमणिका को सरणी सीमाओं तक सीमित नहीं करते हैं, इसके बजाय हम इसे मुखौटा के साथ जोड़ रहे हैं।

readn बजाय पहुँच सूचकांक की गणना में

रूप

writeIndex - (Xn+1)

हम प्रयोग कर रहे:

writeIndex + (~Xn)

यह 2 पूरक arithmetics संभालने काम करता है। यही है, पूर्णांक को नकारात्मक बनाने के लिए, हम अपने सभी बिट्स को नहीं कर रहे हैं, और फिर 1 जोड़ रहे हैं। लेकिन चूंकि आप संख्या से 1 घटा देना चाहते हैं - ऐसा करने की ज़रूरत नहीं है।

+1

जैसे ही आप बिटमैस्क का उपयोग करते हैं, आपको बस 'हस्ताक्षरित' इंडेक्स प्रकारों पर स्विच करना चाहिए। तो आपको इसके बारे में 2-पूरक या सामान के बारे में बहस करने की आवश्यकता नहीं है। –

+0

मैं आपको बहुत धन्यवाद देता हूं, इसने मेरा कोड लगभग 6.5 गुना तेज कर दिया है! मैं इसे एक नाटकीय सुधार – Gurba

+0

कहूंगा क्योंकि मैं केवल 1 उत्तर स्वीकार कर सकता हूं, उदाहरण के कारण मैं ओली चार्ल्सवर्थ एक समान उत्तर के साथ आया हूं। – Gurba

9

आप अपने बफर आकार कर सकते हैं एक शक्ति-की-2, फिर शून्य के खिलाफ जांच बिना शर्त बिट मास्किंग साथ बदला जा सकता। अधिकांश प्रोसेसर पर, यह तेज़ होना चाहिए।

+1

सहमत से एक विशिष्ट मान पढ़ने के लिए कार्य करता है। इसके अलावा इंडेक्स ओवर/अंडर-फ्लो की जांच करने की आवश्यकता नहीं होगी। बस किसी भी जांच के बिना इसे बढ़ाएं और घटाएं, वास्तविक तत्व पहुंच – valdo

+0

के लिए इसे और मास्क करें, मैं इसकी जांच करूँगा, इसे 2 की शक्ति बनाना काफी आसान है (बस BUFF_SIZE को 4 सेट करें)। मुझे बिट-मास्किंग के लिए थोड़ा सा खोदना होगा हालांकि – Gurba

+0

@ गुर्बा मुझे लगता है कि अंतिम एप्लिकेशन में बहुत बड़ा बफर आकार होगा? अन्यथा मैं पहली जगह रिंग बफर एडीटी के उपयोग पर जोरदार सवाल उठाऊंगा। – Lundin

3

यह सुरुचिपूर्ण प्रतीत नहीं होता है लेकिन कुशल है। पॉइंटर के माध्यम से संरचना तत्वों तक पहुंचने से बहुत सारे निर्देश मिल रहे हैं। क्यों नहीं संरचना को पूरी तरह से हटाएं और buffer और writeIndex को वैश्विक चर के रूप में बनाएं? इससे आपके readn और write फ़ंक्शंस के आकार में काफी कमी आएगी।

मैं जीसीसी में करने की कोशिश की और यहाँ के साथ और संरचना

संरचना

_write: 
    pushl %ebp 
    movl %esp, %ebp 
    movl 8(%ebp), %ecx 
    movl 8(%ebp), %eax 
    movl 16(%eax), %edx 
    movl 12(%ebp), %eax 
    movl %eax, (%ecx,%edx,4) 
    movl 8(%ebp), %eax 
    incl 16(%eax) 
    movl 8(%ebp), %eax 
    cmpl $3, 16(%eax) 
    jne L1 
    movl 8(%ebp), %eax 
    movl $0, 16(%eax) 
L1: 
    popl %ebp 
    ret 

के साथ संरचना के बिना बिना उत्पादन होता है।यानी शुरुआत के वैश्विक

_write: 
    pushl %ebp 
    movl %esp, %ebp 
    movl _writeIndex, %edx 
    movl 8(%ebp), %eax 
    movl %eax, _buff(,%edx,4) 
    incl _writeIndex 
    cmpl $3, _writeIndex 
    jne L1 
    movl $0, _writeIndex 
L1: 
    popl %ebp 
    ret 
+0

ओवरफ़्लो सक्षम होगा ऑप्टिमाइज़ेशन सक्षम होने के साथ ऐसा कोई बड़ा अंतर नहीं होना चाहिए। एक बार 'buff' और 'writeIndex' के पते को हल कर सकता है, बाकी सभी एक जैसा होना चाहिए। ऑप्टिमाइज़ेशन के बिना ओटीओएच 'buff -> ...' जैसी कोई पहुंच लंबी – valdo

+1

होगी यदि ओपी को एक से अधिक बफर इंस्टेंस की आवश्यकता होती है तो यह काम नहीं करेगा। –

+0

@ वाल्डो हम्म .. लेकिन संकलक कुछ और कर रहा है। मैंने '-O2' के साथ प्रयास किया और परिणामी कोड उपर्युक्त लोगों की तुलना में बहुत बड़ा प्रतीत होता है: O –

3

रखते हुए ट्रैक और संकेत के साथ परिपत्र बफर के अंत के रूप में buffer और writeIndex बनाना, के बाद से पता करने के मामले में क्रम में गणना की जाएगी, थोड़ा सरणी अनुक्रमण की तुलना में तेजी की संभावना है उत्तरार्द्ध। इसके बजाय readIndex को प्रतिस्थापित करने और इंडेक्स को float* के साथ लिखने का प्रयास करें। कोड तो होगा

*buffer->writeIndex = value; 
buffer->writeIndex++; 
if(buffer->writeIndex == buffer + BUFF_SIZE) 
    buffer->writeIndex=buffer->buff; 

buffer + BUFF_SIZE अभी भी एक निरंतर अभिव्यक्ति हो जाएगा और संकलक, संकलन समय पर तय पता करने के लिए कि अनुवाद कर देगा।