X86 विधानसभा में परिमाण के क्रम की गणना करने का सबसे तेज़ तरीका


12

कार्य सरल है: असेंबली लिखिए जो पूर्णांक के परिमाण के क्रम को कम से कम घड़ी चक्रों के रूप में उपयोग करता है।

  • परिमाण के क्रम को परिभाषित किया गया है log10, नहीं log2
  • मान्य इनपुट की सीमा है 0करने के लिए , समावेशी। उस सीमा से बाहर के इनपुट के लिए व्यवहार अपरिभाषित है।1012
  • मानों को निकटतम पूर्णांक तक गोल किया जाना चाहिए, इस अपवाद के साथ कि दिए गए इनपुट 0आउटपुट होना चाहिए 0। (आप इसे नकारात्मक इन्फिनिटी का सबसे अच्छा प्रतिनिधित्व मान सकते हैं जो अहस्ताक्षरित पूर्णांक में संभव है)।
  • X86 विधानसभा होना चाहिए।
  • पूर्णांक एक रनटाइम मान होना चाहिए , न कि स्थैतिक / इनलाइन पूर्णांक। इसलिए हम नहीं जानते कि यह संकलन के समय क्या है।
  • मान लें कि आपके पास पूर्णांक पहले से ही एक रजिस्टर में लोड है। (लेकिन स्पष्टता के जवाब में रजिस्टर में मूल्य निर्धारित करना शामिल करें)।
  • किसी भी बाहरी लाइब्रेरी या फ़ंक्शंस को कॉल नहीं कर सकते।
  • इंटेल डॉक्स में उपलब्ध किसी भी निर्देश का उपयोग करने के लिए नि: शुल्क ।
  • नहीं सी।
  • ~ 7 इंटेल कोर आर्किटेक्चर में से कोई भी स्वीकार्य है ( पेज 10 पर सूचीबद्ध )। आदर्श रूप से नेहेल्म (इंटेल कोर i7)।

जीतने वाला उत्तर वह है जो सबसे कम संभव चक्र का उपयोग करता है। यानी, इसमें प्रति सेकंड सबसे अधिक ऑपरेशन हो सकते हैं। अनुमानित घड़ी चक्र सारांश यहाँ हैं: http://www.agner.org/optimize/instruction_tables.pdf । उत्तर चक्र के बाद घड़ी चक्र की गणना हो सकती है।


क्या 'FYL2X' और अन्य FPU निर्देशों की अनुमति है?
डिजिटल ट्रामा

1
परिणाम एक पूर्णांक होना चाहिए? यदि हां, तो इसे कैसे गोल किया जाना चाहिए?
डिजिटल ट्रामा

3
तो इनपुट और आउटपुट दोनों पूर्णांक हैं, हाँ? लेकिन इनपुट 10 ^ 12 के रूप में महान हो सकता है, इसलिए यह 32 बिट इंट के लिए बहुत बड़ा है। तो क्या हम 64 बिट पूर्णांक इनपुट मानते हैं?
पॉल आर

3
क्या जीतने की कसौटी चक्रों की अधिकतम या औसत संख्या के आधार पर है? और अगर यह औसत है, तो इनपुट का वितरण क्या है?
Runer112

2
कौन सा प्रोसेसर लक्षित है? लिंक किए गए दस्तावेज़ में 20 से अधिक विभिन्न प्रक्रियाओं (एएमडी, इंटेल, अन्य) की सूची है और अक्षांशों में काफी भिन्नता है।
डिजिटल ट्रामा

जवाबों:


8

7 चक्र, निरंतर समय

यहाँ इस एसओ प्रश्न के मेरे उत्तर के आधार पर एक समाधान है । यह संख्या को धारण करने के लिए कितने बिट्स की आवश्यकता है, यह गिनने के लिए बीएसआर का उपयोग करता है। यह देखता है कि कितने बिट्स पकड़ सकते हैं सबसे बड़ी संख्या का प्रतिनिधित्व करने के लिए कितने दशमलव अंकों की आवश्यकता है। फिर यह 1 घटाता है यदि वास्तविक संख्या 10 की निकटतम शक्ति से कम है जो कई अंकों के साथ है।

    .intel_syntax noprefix
    .globl  main
main:
    mov rdi, 1000000000000              #;your value here
    bsr rax, rdi
    movzx   eax, BYTE PTR maxdigits[1+rax]
    cmp rdi, QWORD PTR powers[0+eax*8]
    sbb al, 0
    ret
maxdigits:
    .byte   0
    .byte   0
    .byte   0
    .byte   0
    .byte   1
    .byte   1
    .byte   1
    .byte   2
    .byte   2
    .byte   2
    .byte   3
    .byte   3
    .byte   3
    .byte   3
    .byte   4
    .byte   4
    .byte   4
    .byte   5
    .byte   5
    .byte   5
    .byte   6
    .byte   6
    .byte   6
    .byte   6
    .byte   7
    .byte   7
    .byte   7
    .byte   8
    .byte   8
    .byte   8
    .byte   9
    .byte   9
    .byte   9
    .byte   9
    .byte   10
    .byte   10
    .byte   10
    .byte   11
    .byte   11
    .byte   11
    .byte   12
powers:
    .quad   0
    .quad   10
    .quad   100
    .quad   1000
    .quad   10000
    .quad   100000
    .quad   1000000
    .quad   10000000
    .quad   100000000
    .quad   1000000000
    .quad   10000000000
    .quad   100000000000
    .quad   1000000000000

Ubuntu के लिए GCC 4.6.3 पर संकलन और निकास कोड में मान लौटाता है।

मैं किसी भी आधुनिक प्रोसेसर के लिए उस चक्र तालिका की व्याख्या करने के लिए आश्वस्त नहीं हूं, लेकिन @ डिजिटलट्रूमा की विधि का उपयोग करते हुए, नेहलिम प्रोसेसर पर, मुझे 7 मिलते हैं ?

ins        uOps Latency
---        -    - 
BSR r,r  : 1    3
MOVZX r,m: 1    -
CMP m,r/i: 1    1 
SBB r,r/i: 2    2

ओह - DigitalTrauma को देखने के बाद मैंने अपना लिखना शुरू किया। इसी तरह के विचार। उनकी गिनती पद्धति का उपयोग करते हुए मुझे लगता है कि बीएसआर,
एमओवी

हाँ, मुझे लगता है कि तुम्हारा मेरा धड़कता है। बस यह दिखाने के लिए चला जाता है कि ए) मैं असेंबली प्रोग्रामर नहीं हूं और बी) असेंबली हमारे लिए सबसे अच्छी तरह से अकेला रह गया है;;
डिजिटल ट्रॉमा

The integer must be a runtime value, not a static/inline integer. So we don't know what it is at compile time.
बिल्ली

1
दाईं ओर, और अगली पंक्ति कहती है: "मान लें कि आपके पास पूर्णांक पहले से ही एक रजिस्टर में लोड है। (लेकिन स्पष्टता के लिए उत्तर में रजिस्टर में मान सेट करना शामिल है)।" जो मैंने किया है।
एशेल्ली

Movzx eax को mov al से बदलें। ईएक्सएक्स के शीर्ष 24 बिट्स पहले से ही शून्य होंगे, इसलिए zx बेमानी है (और यह महंगा है)।
पीटर फेर्री

6

सबसे अच्छा मामला 8 चक्र, सबसे खराब मामला 12 चक्र

चूंकि यह प्रश्न में स्पष्ट नहीं है, इसलिए मैं इसे आइवी ब्रिज की विलंबता से दूर कर रहा हूं।

यहाँ दृष्टिकोण bsrएक गरीब आदमी के log2 () के रूप में (बिट स्कैन रिवर्स) अनुदेश का उपयोग करना है । परिणाम को एक जम्प टेबल में एक इंडेक्स के रूप में उपयोग किया जाता है जिसमें बिट्स 0 से 42 के लिए प्रविष्टियां होती हैं। मैं मान रहा हूं कि 64 बिट डेटा पर उस ऑपरेशन को दिए जाने की आवश्यकता है, फिर bsrनिर्देश का उपयोग ठीक है।

सबसे अच्छा मामला इनपुट में, जुमटेबल प्रविष्टि bsrपरिणाम को सीधे परिमाण में मैप कर सकती है । उदाहरण के लिए सीमा 32-63 में इनपुट के लिए, bsrपरिणाम 5 होगा, जिसे 1. के परिमाण में मैप किया जाता है। इस मामले में, अनुदेश मार्ग है:

Instruction    Latency

bsrq                 3
jmp                  2
movl                 1
jmp                  2

total                8

सबसे खराब स्थिति इनपुट में, bsrपरिणाम दो संभावित परिमाणों के लिए मैप होगा, इसलिए जम्पटेबल प्रविष्टि यह cmpजांचने के लिए एक अतिरिक्त करती है कि इनपुट> 10 एन है या नहीं । उदाहरण के लिए ६४-१२, रेंज में इनपुट के लिए, bsrपरिणाम ६ होगा। इसी जम्पटेबल प्रविष्टि तब जांचता है कि इनपुट> १०० है और तदनुसार उत्पादन परिमाण सेट करता है।

सबसे खराब स्थिति पथ के अलावा, हमारे पास उपयोग करने के लिए 64 बिट तत्काल मूल्य को लोड करने के लिए एक अतिरिक्त चल अनुदेश है cmp, इसलिए सबसे खराब स्थिति निर्देश है:

Instruction    Latency

bsrq                 3
jmp                  2
movabsq              1
cmpq                 1
ja                   2
movl                 1
jmp                  2

total               12

यहाँ कोड है:

    /* Input is loaded in %rdi */
    bsrq    %rdi, %rax
    jmp *jumptable(,%rax,8)
.m0:
    movl    $0, %ecx
    jmp .end
.m0_1:
    cmpq    $9, %rdi
    ja  .m1
    movl    $0, %ecx
    jmp .end
.m1:
    movl    $1, %ecx
    jmp .end
.m1_2:
    cmpq    $99, %rdi
    ja  .m2
    movl    $1, %ecx
    jmp .end
.m2:
    movl    $2, %ecx
    jmp .end
.m2_3:
    cmpq    $999, %rdi
    ja  .m3
    movl    $2, %ecx
    jmp .end
.m3:
    movl    $3, %ecx
    jmp .end
.m3_4:
    cmpq    $9999, %rdi
    ja  .m4
    movl    $3, %ecx
    jmp .end
.m4:
    movl    $4, %ecx
    jmp .end
.m4_5:
    cmpq    $99999, %rdi
    ja  .m5
    movl    $4, %ecx
    jmp .end
.m5:
    movl    $5, %ecx
    jmp .end
.m5_6:
    cmpq    $999999, %rdi
    ja  .m6
    movl    $5, %ecx
    jmp .end
.m6:
    movl    $6, %ecx
    jmp .end
.m6_7:
    cmpq    $9999999, %rdi
    ja  .m7
    movl    $6, %ecx
    jmp .end
.m7:
    movl    $7, %ecx
    jmp .end
.m7_8:
    cmpq    $99999999, %rdi
    ja  .m8
    movl    $7, %ecx
    jmp .end
.m8:
    movl    $8, %ecx
    jmp .end
.m8_9:
    cmpq    $999999999, %rdi
    ja  .m9
    movl    $8, %ecx
    jmp .end
.m9:
    movl    $9, %ecx
    jmp .end
.m9_10:
    movabsq $9999999999, %rax
    cmpq    %rax, %rdi
    ja  .m10
    movl    $9, %ecx
    jmp .end
.m10:
    movl    $10, %ecx
    jmp .end
.m10_11:
    movabsq $99999999999, %rax
    cmpq    %rax, %rdi
    ja  .m11
    movl    $10, %ecx
    jmp .end
.m11:
    movl    $11, %ecx
    jmp .end
.m11_12:
    movabsq $999999999999, %rax
    cmpq    %rax, %rdi
    ja  .m12
    movl    $11, %ecx
    jmp .end
.m12:
    movl    $12, %ecx
    jmp .end

jumptable:
    .quad   .m0
    .quad   .m0
    .quad   .m0
    .quad   .m0_1
    .quad   .m1
    .quad   .m1
    .quad   .m1_2
    .quad   .m2
    .quad   .m2
    .quad   .m2_3
    .quad   .m3
    .quad   .m3
    .quad   .m3
    .quad   .m3_4
    .quad   .m4
    .quad   .m4
    .quad   .m4_5
    .quad   .m5
    .quad   .m5
    .quad   .m5_6
    .quad   .m6
    .quad   .m6
    .quad   .m6
    .quad   .m6_7
    .quad   .m7
    .quad   .m7
    .quad   .m7_8
    .quad   .m8
    .quad   .m8
    .quad   .m8_9
    .quad   .m9
    .quad   .m9
    .quad   .m9
    .quad   .m9_10
    .quad   .m10
    .quad   .m10
    .quad   .m10_11
    .quad   .m11
    .quad   .m11
    .quad   .m11_12
    .quad   .m12
    .quad   .m12
    .quad   .m12

.end:
/* output is given in %ecx */

यह ज्यादातर प्रूफ-ऑफ-कॉन्सेप्ट C कोड मैंने लिखा था के लिए gcc असेंबलर आउटपुट से उत्पन्न हुआ था । नोट सी कोड जंप टेबल को लागू करने के लिए एक कम्प्यूटेशनल गोटो का उपयोग करता है। यह __builtin_clzll()gcc बिलिन का भी उपयोग करता है , जो bsrनिर्देश (प्लस xor) के लिए संकलित करता है ।


मैंने इस पर पहुंचने से पहले कई समाधानों पर विचार किया:

  • FYL2Xप्राकृतिक लॉग की गणना करने के लिए, फिर FMULआवश्यक स्थिरांक द्वारा। अगर यह एक [टैग: निर्देश: गोल्फ] प्रतियोगिता होती तो यह निश्चित रूप से जीतता। लेकिन FYL2Xआइवी ब्रिज के लिए 90-106 की विलंबता है।

  • हार्ड-कोडेड बाइनरी सर्च। यह वास्तव में प्रतिस्पर्धी हो सकता है - मैं इसे लागू करने के लिए किसी और को छोड़ दूँगा :)।

  • परिणामों की पूर्ण लुकिंग तालिका। मुझे यकीन है कि सैद्धांतिक रूप से सबसे तेज़ है, लेकिन 1TB लुकअप टेबल की आवश्यकता होगी - अभी तक व्यावहारिक नहीं - शायद कुछ वर्षों में अगर मूर का कानून जारी रहेगा।


यदि आवश्यक हो तो मैं सभी अनुमत इनपुट के लिए एक औसत विलंबता की गणना कर सकता हूं।
डिजिटल ट्रॉमा

jmpऔर jccविलंबता नहीं है, केवल थ्रूपुट लागत। शाखा-भविष्यवाणी + सट्टा निष्पादन का मतलब है कि नियंत्रण निर्भरता डेटा निर्भरता श्रृंखला का हिस्सा नहीं है।
पीटर कॉर्डेस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.