C مقابل الذهاب الحلقات والرياضيات البسيطة

عندما تعبت من البرمجة في لغة 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 // +build amd64 import "fmt" func main() { var i float64 = 0 var j float64 = 0 for i = 10000000; i>0; i-- { j += i } fmt.Println(j) } 


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>

Source: https://habr.com/ru/post/ar432986/


All Articles