عندما تعبت من البرمجة في لغة C ، مثل كثيرين ، كنت مهتمًا بـ Go. يتم كتابتها بدقة ، وتجميعها ، وبالتالي مثمرة للغاية. ثم أردت معرفة مدى حيرة المبدعين في Go في تحسين عملهم باستخدام الحلقات والأرقام.
بادئ ذي بدء ، نحن ننظر إلى كيفية القيام C.
نكتب مثل هذا الرمز البسيط:
#include <stdint.h> #include <stdio.h> int main() { uint64_t i; uint64_t j = 0; for ( i = 10000000; i>0; i--) { j ^= i; } printf("%lu\n", j); return 0; }
ترجمة مع O2 ، تفكيك:
564: 31 d2 xor %edx,%edx 566: b8 80 96 98 00 mov $0x989680,%eax 56b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) 570: 48 31 c2 xor %rax,%rdx 573: 48 83 e8 01 sub $0x1,%rax 577: 75 f7 jne 570 <main+0x10>
نحصل على وقت التنفيذ:
حقيقي 0،023 ثانية
المستخدم 0m0،019s
تميز الكلية 0m0،004s
يبدو أنه لا يوجد مكان للتسريع ، لكن لدينا معالج حديث ، لدينا مثل هذه العمليات سجلات سريعة. نجرب الخيارات gcc -mfpmath = sse -msse4.2 والنتيجة هي نفسها.
إضافة -O3 والهتافات:
57a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 580: 83 c0 01 add $0x1,%eax 583: 66 0f ef c8 pxor %xmm0,%xmm1 587: 66 0f d4 c2 paddq %xmm2,%xmm0 58b: 3d 40 4b 4c 00 cmp $0x4c4b40,%eax 590: 75 ee jne 580 <main+0x20>
يمكن ملاحظة أنه يتم استخدام أوامر SSE2 وسجلات SSE ، ونحصل على زيادة ثلاثية في الأداء:
0m0،006s الحقيقي
المستخدم 0m0،006s
تميز الكلية 0m0 ، 000s
أيضا على الذهاب:
package main import "fmt" func main() { i := 0 j := 0 for i = 10000000; i>0; i-- { j ^= i } fmt.Println(j) }
0x000000000048211a <+42>: lea -0x1(%rax),%rdx 0x000000000048211e <+46>: xor %rax,%rcx 0x0000000000482121 <+49>: mov %rdx,%rax 0x0000000000482124 <+52>: test %rax,%rax 0x0000000000482127 <+55>: ja 0x48211a <main.main+42>
توقيت الذهاب:
الذهاب العادية:
حقيقي 0،021 ثانية
مستخدم 0m0،018s
تميز الكلية 0m0،004s
gccgo:
حقيقي 0،058 ثانية
المستخدم 0m0،036 ثانية
تميز الكلية 0m0،014s
الأداء ، كما في حالة C و O2 ، عيّن gccgo نفس النتيجة ، لكنه يعمل لفترة أطول من برنامج التحويل البرمجي Go (1.10.4) العادي. على ما يبدو ، نظرًا لحقيقة أن المترجم العادي يعمل على تحسين إطلاق سلاسل الرسائل بشكل مثالي (في حالتي ، تم إنشاء 5 سلاسل إضافية في 4 مراكز) ، يعمل التطبيق بشكل أسرع.
الخاتمة
ما زلت أتمكن من الحصول على برنامج التحويل البرمجي Go القياسي للعمل مع إرشادات sse للحلقة عن طريق تحريكها الأصلي إلى تعويم sse.
package main
0x0000000000484bbe <+46>: movsd 0x4252a(%rip),%xmm3 # 0x4c70f0 <$f64.3ff0000000000000>
0x0000000000484bc6 <+54>: movups %xmm0,%xmm4
0x0000000000484bc9 <+57>: subsd %xmm3,%xmm0
0x0000000000484bcd <+61>: addsd %xmm4,%xmm1
0x0000000000484bd1 <+65>: xorps %xmm2,%xmm2
0x0000000000484bd4 <+68>: ucomisd %xmm2,%xmm0
0x0000000000484bd8 <+72>: ja 0x484bbe <main.main+46>