سؤال

لدي حلقة مكتوب في C + + التي يتم تنفيذ كل عنصر من كبير عدد صحيح الصفيف.داخل حلقة, أنا القناع بعض أجزاء من عدد صحيح و من ثم إيجاد قيم الحد الأدنى والحد الأقصى.سمعت أنه إذا كنت تستخدم تعليمات SSE هذه العمليات فإنه سيتم تشغيل أسرع بكثير مقارنة العادي حلقة مكتوبة باستخدام المعامل و إذا كان آخر الشروط.سؤالي هو هل يجب أن أذهب لهذه SSE التعليمات ؟ أيضا, ماذا يحدث إذا كان قانون بلدي يعمل على معالج ؟ وسوف لا تزال تعمل أو هذه التعليمات المعالج تحديدا ؟

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

المحلول

  1. تعليمات SSE هي المعالج محددة. يمكنك البحث عن المعالج الذي يدعم أي إصدار SSE على Wikipedia.
  2. إذا كان رمز SSE سيكون أسرع أو لا يعتمد على العديد من العوامل: الأول هو بالطبع ما إذا كانت المشكلة مرتبطة بالذاكرة أو وحدة المعالجة المركزية. إذا كانت حافلة الذاكرة هي Bootleneck SSE لن يساعد كثيرا. حاول تبسيط الحسابات الصحيحة الخاصة بك، إذا كان هذا يجعل التعليمات البرمجية أسرع، فمن المحتمل أن تكون ملزمة وحدة المعالجة المركزية، ولديك فرصة جيدة لتسريعها.
  3. كن على دراية بأن كتابة رمز SIMD أصعب بكثير من كتابة التعليمات البرمجية C ++، وأن التعليمات البرمجية الناتجة أكثر صعوبة في التغيير. احتفظ دائما برمز C ++ حتى الآن، ستحتاج إليها كتعليق وتحقق من صحة رمز المجمع الخاص بك.
  4. فكر في استخدام مكتبة مثل IPP، والتي تنفذ عمليات SIMD ذات المستوى المنخفض الشائع المحسن لمختلف المعالجات.

نصائح أخرى

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

مشاكل:

1 إذا كان مسار التعليمات البرمجية يعتمد على البيانات التي تتم معالجتها، يصبح SIMD أصعب بكثير. علي سبيل المثال:

a = array [index];
a &= mask;
a >>= shift;
if (a < somevalue)
{
  a += 2;
  array [index] = a;
}
++index;

ليس من السهل أن تفعل مثل SIMD:

a1 = array [index] a2 = array [index+1] a3 = array [index+2] a4 = array [index+3]
a1 &= mask         a2 &= mask           a3 &= mask           a4 &= mask
a1 >>= shift       a2 >>= shift         a3 >>= shift         a4 >>= shift
if (a1<somevalue)  if (a2<somevalue)    if (a3<somevalue)    if (a4<somevalue)
  // help! can't conditionally perform this on each column, all columns must do the same thing
index += 4

2 إذا لم تكن البيانات تلغى ثم تحميل البيانات في تعليمات SIMD مرهقة

3 الرمز هو المعالج خاص. SSE هي فقط على IA32 (Intel / AMD) وليس كل دعم CPUS IA32 SSE.

تحتاج إلى تحليل الخوارزمية والبيانات لمعرفة ما إذا كان يمكن أن تكون SSE'd وهذا يتطلب معرفة كيفية عمل SSE. هناك الكثير من الوثائق حول موقع Intel.

هذا النوع من المشكلات هو مثال مثالي حيث يعد Profiler مستوى منخفض المستوى ضروريا. (شيء مثل VTune) يمكن أن يوفر لك فكرة أكثر استنارة عن المكان الذي تكمن فيه النقاط الساخنة.

أعتقد، من ما تصفه هو أن النقاط الساخنة سيكون من المحتمل أن يكون فشل التنبؤ الفرعي الناتج عن حسابات دقيقة / ماكس باستخدام إذا / غير ذلك. لذلك، يجب أن تسمح لك استخدام SIMD Internissics باستخدام التعليمات دقيقة / ماكس، ومع ذلك، قد يكون من المستحق أن يحاول فقط استخدام Min / Max Collecomulation بدلا من ذلك. قد يحقق هذا معظم المكاسب بألم أقل.

شيء من هذا القبيل:

inline int 
minimum(int a, int b)
{
  int mask = (a - b) >> 31;
  return ((a & mask) | (b & ~mask));
}

إذا كنت تستخدم تعليمات SSE، فمن الواضح أنك تقتصر على المعالجات التي تدعم هذه. هذا يعني X86، التي يرجع تاريخها إلى بنتيوم 2 أو نحو ذلك (لا أتذكر بالضبط عندما تم تقديمها، لكنها منذ زمن طويل)

SSE2، الذي، بقدر ما أستطيع أن أذكر، هو الذي يقدم العمليات العددية، أكثر حداثة إلى حد ما (بنتيوم 3؟ على الرغم من أن معالجات AMD Athlon الأولى لم تدعمها)

في أي حال، لديك خياران لاستخدام هذه التعليمات. إما أن تكتب كتلة الكود بأكملها في التجميع (ربما فكرة سيئة. هذا يجعل من المستحيل فعليا على التحويل البرمجي لتحسين الكود الخاص بك، ومن الصعب جدا أن يكتب الإنسان مجمع فعال).

بدلا من ذلك، استخدم جوهري المتوفر مع برنامج التحويل البرمجي الخاص بك (إذا كانت الذاكرة تخدمها، وعادة ما تكون محددة في xmmintrin.h)

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

قد يكون من المغري استخدام مكتبة تلتف جميع ألعاب SSE منخفضة المستوى، ولكن قد تدمر أيضا أي فائدة أداء محتملة.

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

إذا كنت تنوي استخدام Microsoft Visual C ++، فيجب عليك قراءة هذا:

http://www.codeproject.com/kb/recipes/sseintro.aspx.

لقد نفذنا بعض رمز معالجة الصور، على غرار ما تصفه ولكن على صفيف بايت، في SSE. تعتبر السرعة مقارنة مع رمز C كبير، اعتمادا على الخوارزمية الدقيقة أكثر من عامل 4، حتى فيما يتعلق بمجموعة التحويل البرمجي Intel. ومع ذلك، كما ذكرت بالفعل لديك العيوب التالية:

  • قابلية التنقل. سيتم تشغيل الرمز كل وحدة المعالجة المركزية التي يشبهها Intel، لذلك أيضا AMD، ولكن ليس على وحدات المعالجة المركزية الأخرى. هذه ليست مشكلة بالنسبة لنا لأننا نتحكم في الأجهزة المستهدفة. يمكن أن يكون التحويل البرمجيات التبديلية وحتى نظام تشغيل 64 بت أيضا مشكلة.

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

  • قابلية الصيانة. معظم مبرمجين C أو C ++ ليس لديهم معرفة بالتجمع / SSE.

سيتم تقديم نصيحتي لكي تذهب للحصول عليها إلا إذا كنت بحاجة فعلا إلى تحسين الأداء، ولا يمكنك العثور على وظيفة لمشكلتك في مكتبة مثل Intel IPP، وإذا كنت تستطيع العيش مع مشكلات قابلية إمكانية النقل.

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

كانت تعليمات SSE في الأصل على رقائق Intel، ولكن مؤخرا (منذ Athlon؟) يدعمها AMD أيضا، لذلك إذا قمت بإجراء رمز مقابل مجموعة تعليمات SSE، فيجب أن تكون محمولة إلى معظم X86 Procs.

ومع ذلك، قد لا يكون الأمر يستحق وقتك لتعلم ترميز SSE إلا إذا كنت على دراية بالفعل بالمجمع على X86 - قد يكون خيار أسهل للتحقق من مستندات برنامج التحويل البرمجي ومعرفة ما إذا كانت هناك خيارات للسماح للمترجم إلى رمز SSE Authentogenerate لك. بعض التحويل البرمجيات تفعل حلقات جيدة جدا في هذه الطريقة. (ربما لا فوجئك أن نسمع أن محاملي إنتل يقومون بعمل جيد في هذا :)

اكتب التعليمات البرمجية التي تساعد المحول البرمجي على فهم ما تفعله. سوف يفهم دول مجلس التعاون الخليجي وتحسين رمز SSE مثل هذا:

typedef union Vector4f
{
        // Easy constructor, defaulted to black/0 vector
    Vector4f(float a = 0, float b = 0, float c = 0, float d = 1.0f):
        X(a), Y(b), Z(c), W(d) { }

        // Cast operator, for []
    inline operator float* ()
    { 
        return (float*)this;
    }

        // Const ast operator, for const []
    inline operator const float* () const
    { 
        return (const float*)this;
    }

    // ---------------------------------------- //

    inline Vector4f operator += (const Vector4f &v)
    {
        for(int i=0; i<4; ++i)
            (*this)[i] += v[i];

        return *this;
    }

    inline Vector4f operator += (float t)
    {
        for(int i=0; i<4; ++i)
            (*this)[i] += t;

        return *this;
    }

        // Vertex / Vector 
        // Lower case xyzw components
    struct {
        float x, y, z;
        float w;
    };

        // Upper case XYZW components
    struct {
        float X, Y, Z;
        float W;
    };
};

فقط لا تنسى أن يكون لديك -MSSE -MSS2 على معلمات البناء الخاصة بك!

على الرغم من أنه صحيح أن SSE محددا لبعض المعالجات (قد تكون SSE آمنة نسبيا، إلا أن SSE2 أقل بكثير في تجربتي)، يمكنك اكتشاف وحدة المعالجة المركزية في وقت التشغيل، وتحميل التعليمات البرمجية بشكل حيوي حسب وحدة المعالجة المركزية المستهدفة.

يمكن أن يسرع Simd Internissics (مثل SSE2) هذا النوع من الأشياء حتى خبرات الاستخدام بشكل صحيح. فهي حساسة للغاية للمحاذاة وقطافة خط الأنابيب؛ الاستخدام الإهمال يمكن أن يجعل الأداء أسوأ مما كان عليه من دونهم. ستحصل على تسريع أسهل وأكثر فورية من مجرد استخدام جلب من جلب ذاكرة التخزين المؤقت للتأكد من أن جميع دولتك في L1 في الوقت المناسب لك للعمل عليها.

ما لم تكن دئتك تحتاج إلى إنتاجية أفضل من 100،000،000 أعداد صحيحة في الثانية، فربما لا يستحق SIMD عناءك.

فقط لإضافة لفترة وجيزة إلى ما قيل من قبل إصدارات SSE المختلفة التي تتوفر على وحدة المعالجة المركزية المختلفة: يمكن التحقق من ذلك من خلال النظر في إشارات الميزات المعنية التي تم إرجاعها بواسطة تعليمات CPUID (انظر وثائق Intel للحصول على التفاصيل).

القي نظرة على مجمع مضمنة ل c / c ++، هنا هو المادة DDJ. وبعد ما لم تكن هناك 100٪، سيتم تشغيل برنامجك على منصة متوافقة، يجب عليك اتباع التوصيات العديدة التي قدمتها هنا.

وأنا أتفق مع الملصقات السابقة. يمكن أن تكون الفوائد كبيرة جدا ولكنها قد تتطلب الكثير من العمل. وثائق Intel حول هذه التعليمات أكثر من 4K صفحات. قد ترغب في التحقق من easysse (مكتبة مغلفات C ++ على أمثلة داخلية + مجانية) من Ocali Inc.

أفترض انتمائي مع هذا Easyysse واضح.

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

فإنه من المحتمل أن يكون أفضل بكثير بالنسبة لك لكتابة صغيرة جدا الحلقات والحفاظ على البيانات الخاصة بك جدا تنظيم محكم و الاعتماد فقط على المترجم أفعل هذا من أجلكسواء Intel ج مترجم و دول مجلس التعاون الخليجي (منذ 4.1) يمكن لصناعة السيارات vectorize التعليمات البرمجية الخاصة بك ، وربما القيام بعمل أفضل مما كنت.(فقط إضافة ftree-vectorize إلى CXXFLAGS.)

تحرير:شيء آخر أود أن أشير إليه هو أن العديد من المجمعين الدعم الجمعية إينترينسيكس, الذي سيكون على الأرجح ، والمنظمة البحرية الدولية ، يكون أسهل في الاستخدام من asm() أو __asm{} الجملة.

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