سؤال

أقوم بعمل مكتبة ناقلات/مصفوفة. (GCC ، ARM NEON ، iPhone)

typedef struct{ float v[4]; } Vector;
typedef struct{ Vector v[4]; } Matrix;

لقد مررت ببنيت البيانات كمؤشر لتجنب تدهور الأداء من نسخ البيانات عند استدعاء وظيفة. لذلك قمت بتصميم وظيفة مثل هذه في البداية:

void makeTranslation(const Vector* factor, Matrix* restrict result);

ولكن ، إذا كانت الوظيفة مضمنة ، فهل هناك أي سبب لتمرير القيم كمؤشر للأداء؟ هل يتم نسخ تلك المتغيرات أيضًا؟ ماذا عن التسجيل والخزائن؟ حاولت إعادة تصميم الوظيفة مثل هذا:

inline Matrix makeTranslation(const Vector factor) __attribute__ ((always_inline));

كيف تفكر في استدعاء تكاليف كل حالة؟

  • أضفت "const" إلى التوقيع الثاني لتعكس الاقتراحات.
هل كانت مفيدة؟

المحلول

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

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

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

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

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