سؤال

هل هناك بدائل أسرع لـ memcpy() في C++؟

هل كانت مفيدة؟

المحلول

ومن غير المحتمل. سوف مترجم / مكتبة القياسية من المرجح أن يكون التنفيذ الفعال للغاية ومصممة من memcpy. وmemcpy هي في الأساس أدنى المعهد هناك لنسخ جزء واحد من الذاكرة إلى آخر.

إذا كنت تريد المزيد من speedups، والعثور على طريقة للا تحتاج إلى أي نسخ الذاكرة.

نصائح أخرى

أولا، كلمة نصيحة.افترض أن الأشخاص الذين كتبوا مكتبتك القياسية ليسوا أغبياء.إذا كانت هناك طريقة أسرع لتنفيذ memcpy عام، لكانوا قد فعلوا ذلك.

ثانيا، نعم، هناك بدائل أفضل.

  • في لغة C++، استخدم std::copy وظيفة.إنه يفعل نفس الشيء، لكنه 1) أكثر أمانًا، و2) يحتمل أن يكون أسرع في بعض الحالات.إنه قالب، مما يعني أنه يمكن تخصيصه لأنواع محددة، مما يجعله أسرع من memcpy العام في لغة C.
  • أو يمكنك استخدام معرفتك المتفوقة لك حالة محددة.كان على منفذي memcpy كتابته لذا كان أداؤه جيدًا كل قضية.إذا كانت لديك معلومات محددة حول الموقف الذي تحتاج إليها، فقد تتمكن من كتابة نسخة أسرع.على سبيل المثال، ما مقدار الذاكرة التي تحتاجها للنسخ؟كيف يتم مواءمتها؟قد يسمح لك ذلك بكتابة memcpy أكثر كفاءة لـ هذا حالة محددة.لكنها لن تكون جيدة في معظم الحالات الأخرى (إذا كانت ستعمل على الإطلاق)

نشر خبير التحسين Agner Fog وظائف الذاكرة المحسنة: http://agner.org/optimize/#asmlib.بالرغم من ذلك فهو تحت GPL.

منذ بعض الوقت، قال أجنر إن هذه الوظائف يجب أن تحل محل الوظائف المدمجة في دول مجلس التعاون الخليجي لأنها أسرع كثيرًا.لا أعرف إذا كان قد تم ذلك منذ ذلك الحين.

هذه الإجابة لسؤال مشابه جدًا (حول memset()) ينطبق هنا أيضًا.

تقول بشكل أساسي أن المترجمين يقومون بإنشاء بعض التعليمات البرمجية المثالية جدًا memcpy()/memset() - وأكواد مختلفة حسب طبيعة الكائنات (الحجم، المحاذاة، إلخ).

وتذكر فقط memcpy() القرون في C++.

في أجل العثور على أو إرسال نسخة روتين الذاكرة السريعة، ينبغي لنا أن نفهم كيف المعالجات العمل.

ومعالجات بنتيوم برو منذ إنتل قيام "إعدام خارج النظام". ويمكن أن تنفيذ العديد من التعليمات بالتوازي إذا الإرشادات لا تملك التبعيات. ولكن هذه ليست سوى حالة عندما تعمل على التعليمات مع سجلات فقط. إذا كانت تعمل مع الذاكرة، وتستخدم وحدة CPU إضافية، تسمى "وحدة تحميل" (لقراءة البيانات من الذاكرة) و "وحدات تخزين" (كتابة البيانات إلى الذاكرة). معظم وحدات المعالجة المركزية واثنين من وحدات تحميل وحدة تخزين واحدة، أي أنها يمكن تنفيذ تعليمات في المتوازيين الذي يقرأ من الذاكرة والتعليمات واحد يكتب في الذاكرة (مرة أخرى، وإذا كانت لا تؤثر على بعضها البعض). حجم هذه الوحدات عادة ما يكون نفس الحد الأقصى لحجم السجل - إذا كانت وحدة المعالجة المركزية لديها سجلات XMM (SSE) - انها 16 بايت، إذا كان لديه سجلات YMM (AVX) - هو 32 بايت، وهلم جرا. يتم تحويل كافة التعليمات التي قراءة أو كتابة الذاكرة لعمليات الصغرى (مكتب خدمات المشاريع المتناهية الصغر) التي تذهب إلى مجموعة مشتركة من مكتب خدمات المشاريع المتناهية الصغر والانتظار هناك لوحدات تحميل ومخزن لتكون قادرة على خدمتهم. حمولة أو مخزن وحدة واحدة يمكن أن تؤدي إلا المرجع الصغيرة في وقت واحد، بغض النظر عن حجم البيانات التي تحتاجها لتحميل أو متجر، سواء كان ذلك 1 بايت أو 32 بايت.

وهكذا، فإن أسرع نسخ الذاكرة يكون التحرك من وإلى السجلات مع الحد الأقصى لحجم. لمعالجات تمكين AVX، أن أسرع طريقة لنسخ الذاكرة يكون لتكرار التسلسل التالي،-بسطه حلقة:

vmovdqa     ymm0,ymmword ptr [rcx]
vmovdqa     ymm1,ymmword ptr [rcx+20h]
vmovdqa     ymmword ptr [rdx],ymm0
vmovdqa     ymmword ptr [rdx+20h],ymm1

كود جوجل نشرت في وقت سابق hplbsh ليست جيدة جدا، لأنها تستخدم كل 8 XMM يسجل لاحتواء البيانات قبل أن تبدأ في الكتابة مرة أخرى، في حين لا حاجة لذلك - لأن لدينا سوى اثنين من وحدات تحميل ومخزن واحد وحدة. لذلك سجلات اثنين فقط تعطي أفضل النتائج. باستخدام أن العديد من السجلات في أي وسيلة يحسن الأداء.

وروتين نسخ الذاكرة ويمكن أيضا استخدام بعض التقنيات "المتقدمة" مثل "الجلب المسبق" لإرشاد المعالج لتحميل الذاكرة إلى ذاكرة التخزين المؤقت في وقت مبكر و"يكتب غير الزمنية" (إذا كنت تنسخ قطع ذاكرة كبيرة جدا و لا تحتاج البيانات من المخزن المؤقت للإخراج لتكون على الفور اقرأ)، مقابل الانحياز يكتب الصغيرة المحايدة، وما إلى ذلك.

والمعالجات الحديثة، الذي صدر منذ عام 2013، إذا كان لديهم قليلا ERMS في CPUID، ويسمى ب "تعزيز movsb مندوب"، وذلك لنسخ الذاكرة الكبيرة، و"movsb مندوب" يمكن أن تستخدم - سوف النسخة يكون جدا بسرعة، حتى أسرع من سجلات YMM، وأنها ستعمل مع مخبأ بشكل صحيح. ومع ذلك، وتكاليف بدء التشغيل من هذه التعليمات هي عالية جدا - حوالي 35 دورة، لذلك يدفع ما يصل فقط على كتل الذاكرة كبيرة

.

وآمل أنه ينبغي أن يكون الآن الأسهل بالنسبة لك لاختيار أو كتابة أفضل نسخة ذاكرة روتين اللازمة لحالتك.

ويمكنك حتى حفاظ على memcpy القياسية / memmove، ولكن الحصول على largememcpy الخاصة بنفسك () لاحتياجاتك.

واعتمادا على ما كنت تحاول القيام به ... لو كان ما يكفي من memcpy كبيرة، وكنت فقط أن الكتابة إلى النسخة قليلة، وmmap مع MMAP_PRIVATE إنشاء تعيين النسخ عند الكتابة يمكن أن يكون تصور أسرع .

واعتمادا على النظام الأساسي الخاص بك قد يكون هناك حالات الاستخدام محددة، مثل إذا كنت تعرف يتم محاذاة المصدر والوجهة إلى خط التخزين المؤقت وحجم مضاعف صحيح لحجم خط التخزين المؤقت. بشكل عام سوف تنتج معظم المجمعين كود الأمثل إلى حد ما لmemcpy بالرغم من ذلك.

ولست متأكدا من أن استخدام memcpy الافتراضي هو دائما الخيار الأفضل. معظم تطبيقات memcpy لقد ألقيت نظرة تميل في محاولة لمحاذاة البيانات في البداية، ومن ثم القيام بنسخ الانحياز. إذا يتم محاذاة البيانات بالفعل، أو هي صغيرة جدا، ثم وهذا هو إضاعة الوقت.

وأحيانا يكون من المفيد أن يكون نسخة كلمة المتخصصة، نسخة كلمة نصف، نسخة بايت memcpy، وطالما أنه لا يكون لها تأثير سلبي جدا على مخابئ.

وأيضا، قد تريد السيطرة الدقيقة على خوارزمية تخصيص الفعلية. في صناعة الألعاب من الشائع للغاية بالنسبة للأشخاص لكتابة الخاصة الروتينية تخصيص الذاكرة، وبغض النظر عن مقدار الجهد أنفق من قبل المطورين toolchain في المقام الأول تطويره. الألعاب رأيت دائما تميل إلى استخدام دوغ ليا وMalloc .

وبصفة عامة على الرغم من تريد ان تكون إضاعة الوقت في محاولة لتحسين memcpy كما سوف يكون هناك شك الكثير من بت أسهل من التعليمات البرمجية في التطبيق الخاص بك لتسريع.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top