क्या == GLSL में ब्रांचिंग का कारण बनता है?


27

यह जानने की कोशिश कर रहा है कि GLSL में ब्रांचिंग और क्या नहीं होता है।

मैं अपनी छाया में बहुत कुछ कर रहा हूं:

float(a==b)

मैं इसका उपयोग अनुकरण करने के लिए करता हूं यदि कथन, सशर्त शाखाओं के बिना ... लेकिन क्या यह प्रभावी है? मेरे पास अब मेरे कार्यक्रम में कहीं भी बयान नहीं है, और न ही मेरे पास कोई लूप है।

संपादित करें: स्पष्ट करने के लिए, मैं अपने कोड में इस तरह से सामान बनाता हूं:

float isTint = float((renderflags & GK_TINT) > uint(0)); // 1 if true, 0 if false
    float isNotTint = 1-isTint;//swaps with the other value
    float isDarken = float((renderflags & GK_DARKEN) > uint(0));
    float isNotDarken = 1-isDarken;
    float isAverage = float((renderflags & GK_AVERAGE) > uint(0));
    float isNotAverage = 1-isAverage;
    //it is none of those if:
    //* More than one of them is true
    //* All of them are false
    float isNoneofThose = isTint * isDarken * isAverage + isNotTint * isAverage * isDarken + isTint * isNotAverage * isDarken + isTint * isAverage * isNotDarken + isNotTint * isNotAverage * isNotDarken;
    float isNotNoneofThose = 1-isNoneofThose;

    //Calc finalcolor;
    finalcolor = (primary_color + secondary_color) * isTint * isNotNoneofThose + (primary_color - secondary_color) * isDarken * isNotNoneofThose + vec3((primary_color.x + secondary_color.x)/2.0,(primary_color.y + secondary_color.y)/2.0,(primary_color.z + secondary_color.z)/2.0) * isAverage * isNotNoneofThose + primary_color * isNoneofThose;

संपादित करें: मुझे पता है कि मुझे शाखा क्यों नहीं चाहिए। मुझे पता है कि ब्रांचिंग क्या है। मुझे खुशी है कि आप बच्चों को ब्रांचिंग के बारे में सिखा रहे हैं, लेकिन मैं खुद को बूलियन ऑपरेटरों के बारे में जानना चाहता हूं (और बिटवाइज़ ऑप्स लेकिन मुझे पूरा यकीन है कि वे ठीक हैं)

जवाबों:


42

जीएलएसएल में ब्रांचिंग के कारण क्या जीपीयू मॉडल और ओपनजीएल ड्राइवर संस्करण पर निर्भर करता है।

अधिकांश GPU को लगता है कि "दो मूल्यों में से एक का चयन करें" ऑपरेशन का एक रूप है जिसकी कोई शाखा नहीं है:

n = (a==b) ? x : y;

और कभी-कभी जैसी चीजें:

if(a==b) { 
   n = x;
   m = y;
} else {
   n = y;
   m = x;
}

बिना ब्रांचिंग पेनल्टी वाले कुछ चुनिंदा-वैल्यू ऑपरेशन को कम किया जाएगा।

कुछ GPU / ड्राइवर्स में दो मूल्यों के बीच तुलना ऑपरेटर पर थोड़ा जुर्माना (शून्य) है, लेकिन शून्य के मुकाबले तुलनात्मक रूप से तेज़ संचालन।

जहां यह करने के लिए तेज़ हो सकता है:

gl_FragColor.xyz = ((tmp1 - tmp2) != vec3(0.0)) ? E : tmp1;

(tmp1 != tmp2)सीधे तुलना करने के बजाय, लेकिन यह बहुत ही GPU और ड्राइवर पर निर्भर है, जब तक कि आप एक बहुत ही विशिष्ट GPU को लक्षित नहीं कर रहे हैं और कोई अन्य नहीं है जो मैं तुलना ऑपरेशन का उपयोग करने की सलाह देता हूं और ओपनग्ल ड्राइवर को नौकरी का अनुकूलन करने की सलाह देता हूं, क्योंकि किसी अन्य ड्राइवर के पास लंबे फॉर्म के साथ समस्या हो सकती है। और सरल, अधिक पठनीय तरीके के साथ तेज हो।

"शाखाएँ" हमेशा एक बुरी चीज नहीं होती हैं। उदाहरण के लिए OpenPandora में उपयोग किए जाने वाले SGX530 GPU पर, यह स्केल 2x shader (30ms):

    lowp vec3 E = texture2D(s_texture0, v_texCoord[0]).xyz;
    lowp vec3 D = texture2D(s_texture0, v_texCoord[1]).xyz;
    lowp vec3 F = texture2D(s_texture0, v_texCoord[2]).xyz;
    lowp vec3 H = texture2D(s_texture0, v_texCoord[3]).xyz;
    lowp vec3 B = texture2D(s_texture0, v_texCoord[4]).xyz;
    if ((D - F) * (H - B) == vec3(0.0)) {
            gl_FragColor.xyz = E;
    } else {
            lowp vec2 p = fract(pos);
            lowp vec3 tmp1 = p.x < 0.5 ? D : F;
            lowp vec3 tmp2 = p.y < 0.5 ? H : B;
            gl_FragColor.xyz = ((tmp1 - tmp2) != vec3(0.0)) ? E : tmp1;
    }

इस समकक्ष shader (80ms) की तुलना में नाटकीय रूप से तेज़ी से समाप्त हुआ:

    lowp vec3 E = texture2D(s_texture0, v_texCoord[0]).xyz;
    lowp vec3 D = texture2D(s_texture0, v_texCoord[1]).xyz;
    lowp vec3 F = texture2D(s_texture0, v_texCoord[2]).xyz;
    lowp vec3 H = texture2D(s_texture0, v_texCoord[3]).xyz;
    lowp vec3 B = texture2D(s_texture0, v_texCoord[4]).xyz;
    lowp vec2 p = fract(pos);

    lowp vec3 tmp1 = p.x < 0.5 ? D : F;
    lowp vec3 tmp2 = p.y < 0.5 ? H : B;
    lowp vec3 tmp3 = D == F || H == B ? E : tmp1;
    gl_FragColor.xyz = tmp1 == tmp2 ? tmp3 : E;

आप पहले से कभी नहीं जानते हैं कि एक विशिष्ट GLSL संकलक या एक विशिष्ट GPU कैसे काम करेगा जब तक आप इसे बेंचमार्क नहीं करते।


बिंदु में जोड़ने के लिए (यहां तक ​​कि मेरे पास वास्तविक समय संख्या और shader कोड नहीं है जो आपको इस भाग के लिए प्रस्तुत करने के लिए) मैं वर्तमान में अपने नियमित परीक्षण हार्डवेयर के रूप में उपयोग करता हूं:

  • इंटेल एचडी ग्राफिक्स 3000
  • इंटेल एचडी 405 ग्राफिक्स
  • एनवीडिया जीटीएक्स 560 एम
  • एनवीडिया जीटीएक्स 960
  • AMD Radeon R7 260X
  • एनवीडिया जीटीएक्स 1050

परीक्षण करने के लिए विभिन्न, सामान्य, GPU मॉडल की एक विस्तृत श्रृंखला के रूप में।

विंडोज, लिनक्स मालिकाना और लिनक्स ओपन सोर्स ओपनजीएल और ओपनसीएल ड्राइवरों के साथ प्रत्येक का परीक्षण।

और हर बार जब मैं GLSL शेडर (ऊपर SGX530 उदाहरण के रूप में) या एक विशेष GPU / चालक कॉम्बो के लिए OpenCL संचालन का प्रयास करता हूं, तो मैं दूसरे GPU / ड्राइवर्स में से एक से अधिक पर प्रदर्शन को समान रूप से नुकसान पहुंचाता हूं।

तो स्पष्ट रूप से उच्च-स्तरीय गणितीय जटिलता को कम करने के अलावा (जैसे: एकल पारस्परिक के लिए 5 समान विभाजनों को बदलें और इसके बजाय 5 गुणन) और बनावट लुकअप / बैंडविड्थ को कम करें, यह सबसे अधिक संभावना है कि आपके समय की बर्बादी होगी।

हर GPU दूसरों से बहुत अलग है।

यदि आप विशेष रूप से (ए) गेमिंग कंसोल (एस) पर एक विशिष्ट जीपीयू के साथ काम कर रहे हैं तो यह एक अलग कहानी होगी।

अन्य (छोटे गेम देवों के लिए लेकिन अभी भी उल्लेखनीय) के लिए कम महत्वपूर्ण पहलू यह है कि कंप्यूटर GPU ड्राइवर एक दिन चुपचाप आपके शेड्स ( यदि आपका गेम काफी लोकप्रिय हो जाता है ) को री-लिखित लोगों के साथ उस विशेष GPU के लिए अनुकूलित कर सकते हैं। ऐसा करना आपके लिए सब काम करता है।

वे लोकप्रिय खेलों के लिए ऐसा करेंगे जो अक्सर बेंचमार्क के रूप में उपयोग किए जाते हैं।

या यदि आप अपने खिलाड़ियों को शेड्स तक पहुंच देते हैं, तो वे आसानी से उन्हें खुद संपादित कर सकते हैं, उनमें से कुछ अपने स्वयं के लाभ के लिए कुछ अतिरिक्त एफपीएस निचोड़ सकते हैं।

उदाहरण के लिए, पंखे से बने शेडर और टेक्सचर पैक ओब्लाइव के लिए नाटकीय रूप से फ्रेम दर को बढ़ाने के लिए अन्यथा मुश्किल से बजाने वाले हार्डवेयर हैं।

और अंत में, एक बार जब आपका शेडर पर्याप्त रूप से जटिल हो जाता है, तो आपका गेम लगभग पूरा हो जाता है, और आप विभिन्न हार्डवेयर पर परीक्षण करना शुरू कर देते हैं, आप काफी व्यस्त होंगे बस अपने शेडर्स को विभिन्न प्रकार के GPU पर काम करने के लिए ठीक कर देंगे क्योंकि यह विभिन्न बगों के कारण होता है जो आप अभ्यस्त नहीं होंगे। उन्हें उस डिग्री के लिए अनुकूलित करने का समय है।


"या यदि आप अपने खिलाड़ियों को शेड्स तक पहुंच देते हैं, तो वे उन्हें आसानी से खुद को संपादित कर सकते हैं ..." जब से आपने यह उल्लेख किया है, तो वॉलकॉक शेडर्स और इस तरह आपका दृष्टिकोण क्या हो सकता है? सम्मान प्रणाली, सत्यापित, रिपोर्ट ...? मुझे लॉबियों के विचार समान शादियों / संपत्तियों तक सीमित हैं, जो कुछ भी वे हो सकते हैं, क्योंकि अधिकतम / मिनट / स्केलेबल यथार्थवाद, कारनामों पर रुख करते हैं, और इसलिए समीक्षा, सहयोग, आदि को प्रोत्साहित करने के लिए खिलाड़ियों और संयोजनों को एक साथ लाना चाहिए। यह याद रखने के लिए कि गैरी के मॉड ने काम किया, लेकिन मैं अच्छी तरह से लूप से बाहर हूं।
जॉन पी

1
@ जॉन सुरक्षा जो कुछ भी मानती है कि ग्राहक समझौता नहीं करता है वैसे भी काम नहीं करता है। यदि आप नहीं चाहते हैं कि लोग अपने शेड्स को संपादित करें तो उन्हें उजागर करने का कोई मतलब नहीं है, लेकिन यह वास्तव में सुरक्षा के साथ बहुत मदद नहीं करता है। चारदीवारी जैसी चीजों का पता लगाने के लिए आपकी रणनीति को ग्राहक को पहले बाधा के रूप में चीजों के साथ खिलवाड़ करना चाहिए, और यकीनन इस उत्तर के रूप में लाइट मोडिंग की अनुमति देने के लिए एक बड़ा लाभ हो सकता है अगर यह खिलाड़ी के लिए एक पता लगाने योग्य अनुचित लाभ का कारण नहीं बनता है। ।
घन

8
@ जॉन यदि आप चाहते हैं कि खिलाड़ी भी दीवारों के माध्यम से न देखें, तो सर्वर को दीवार के पीछे क्या है, इसके बारे में कोई जानकारी न दें।
पॉलिग्नोम

1
बस यही है - मैं उन खिलाड़ियों के बीच दीवार-हैकिंग के खिलाफ नहीं हूं जो इसे किसी भी कारण से पसंद करते हैं। एक खिलाड़ी के रूप में, हालांकि, मैंने कई एएए खिताबों को त्याग दिया है क्योंकि - अन्य कारणों के बीच - उन्होंने पैसे / एक्सपी / आदि के दौरान सौंदर्य संबंधी तरीकों का उदाहरण दिया। हैकर्स असंतुष्ट हो गए (जिन्होंने भुगतान करने के लिए निराश लोगों के वास्तविक धन को बंद कर दिया), अपनी रिपोर्ट और अपील प्रणाली को समझने और स्वचालित करने के लिए, और कुछ खेलों को जीवित रखने के लिए देखभाल करने वाले सर्वरों की संख्या से जीवित और मर गए। मैं उम्मीद कर रहा था कि देव और खिलाड़ी दोनों के रूप में अधिक विकेन्द्रीकृत दृष्टिकोण हो सकता है।
जॉन पी

अगर मैं कहीं भी इनलाइन नहीं करता हूं। मैं बस फ्लोट (बूलियन स्टेटमेंट) * (कुछ) करता
हूं

7

@ स्टेपहेन होकेनहुल का उत्तर आपको बहुत कुछ देता है जो आपको जानना आवश्यक है, इसका पूरी तरह से हार्डवेयर पर निर्भर होना।

लेकिन मैं आपको कुछ उदाहरण देता हूं कि यह हार्डवेयर पर निर्भर कैसे हो सकता है, और ब्रांचिंग यहां तक ​​कि एक मुद्दा भी क्यों है, जब GPU ब्रांचिंग करता है तो दृश्यों के पीछे क्या करता है।

मेरा ध्यान मुख्य रूप से एनवीडिया के साथ है, मुझे निम्न स्तर के CUDA प्रोग्रामिंग के साथ कुछ अनुभव है, और मैं देखता हूं कि SPX-V की तरह PTX ( IR CUDA कर्नेल के लिए क्या है , लेकिन सिर्फ Nvidia के लिए) उत्पन्न होता है और कुछ बदलाव करने के मानदंड देखें।

GPU आर्किटेक्चर में ब्रांचिंग इतना बड़ा सौदा क्यों है?

पहले स्थान पर शाखा करना बुरा क्यों है? जीपीयू पहली जगह में शाखा से बचने की कोशिश क्यों करता है? क्योंकि जीपीयू आमतौर पर एक योजना का उपयोग करते हैं जहां थ्रेड्स एक ही अनुदेश सूचक को साझा करते हैं । GPU एक SIMD वास्तुकला का पालन करते हैंआम तौर पर, और जबकि इसकी ग्रैन्युलैरिटी बदल सकती है (अर्थात एनवीडिया के लिए 32 थ्रेड्स, एएमडी और अन्य के लिए 64), कुछ स्तरों पर थ्रेड्स का एक समूह एक ही इंस्ट्रक्शन पॉइंटर को साझा करता है। इसका मतलब यह है कि उन थ्रेड्स को समान समस्या पर एक साथ काम करने के लिए कोड की एक ही लाइन को देखने की आवश्यकता है। आप पूछ सकते हैं कि वे कोड की समान लाइनों का उपयोग करने और विभिन्न चीजों को करने में कैसे सक्षम हैं? वे रजिस्टरों में विभिन्न मूल्यों का उपयोग करते हैं, लेकिन उन रजिस्टरों को अभी भी पूरे समूह में कोड की समान लाइनों में उपयोग किया जाता है। जब ऐसा होता है तो क्या होता है? (IE एक शाखा?) अगर कार्यक्रम वास्तव में इसके आसपास कोई रास्ता नहीं है, तो यह समूह को विभाजित करता है (एनवीडिया इस तरह के 32 थ्रेड्स के बंडलों को एक ताना कहा जाता है , एएमडी और समानांतर कंप्यूटिंग अकादमी के लिए, इसे तरंग के रूप में जाना जाता है।) दो या दो से अधिक विभिन्न समूहों में।

यदि आपके पास कोड की केवल दो अलग-अलग लाइनें हैं, तो आप काम कर रहे थ्रेड्स को दो समूहों के बीच विभाजित कर रहे हैं (यहाँ से मैं उन्हें वॉर्प्स कहूँगा)। आइए एनवीडिया आर्किटेक्चर को मानें, जहां ताना का आकार 32 है, यदि इन थ्रेड्स में से आधे डायवर्ज करते हैं, तो आपके पास 32 सक्रिय थ्रेड्स के कब्जे में 2 वॉर होंगे, जो पुट एंड के माध्यम से कम्प्यूटेशनल से चीजों को आधा कुशल बनाता है। कई आर्किटेक्चर पर GPU एक ही निर्देश पोस्ट शाखा तक पहुंचने के बाद थ्रेड्स को एक ही ताना में परिवर्तित करके इसे मापने का प्रयास करेगा , या संकलक स्पष्ट रूप से एक सिंक्रनाइज़ेशन बिंदु डाल देगा जो GPU को थ्रेड्स को वापस करने, या प्रयास करने के लिए कहता है।

उदाहरण के लिए:

if(a)
    x += z * w;
    q >>= p;
else if(c)
    y -= 3;
r += t;

थ्रेड में डायवर्ज (डिसिमिलर इंस्ट्रक्शन पाथ) को मोड़ने की एक मजबूत क्षमता होती है, इसलिए ऐसे मामले में आप अभिसरण हो सकते हैं r += t;जहां निर्देश बिंदु फिर से वही होंगे। विचलन भी दो से अधिक शाखाओं के साथ हो सकता है, जिसके परिणामस्वरूप कम ताना उपयोग भी होता है, चार शाखाओं का मतलब है कि 32 धागे 4 वार में विभाजित हो जाते हैं, 25% थ्रूपुट उपयोग। कन्वर्जेंस हालांकि इनमें से कुछ मुद्दों को छिपा सकता है, क्योंकि 25% पूरे कार्यक्रम के माध्यम से थ्रूपुट नहीं रहते हैं।

कम परिष्कृत GPU पर, अन्य समस्याएँ हो सकती हैं। डायवर्ट करने के बजाय वे केवल सभी शाखाओं की गणना करते हैं और फिर अंत में आउटपुट का चयन करते हैं। यह विचलन के समान हो सकता है (दोनों में 1 / n थ्रूपुट उपयोग है), लेकिन डुप्लिकेट दृष्टिकोण के साथ कुछ प्रमुख मुद्दे हैं।

एक शक्ति का उपयोग है, जब आप एक शाखा होती है तो आप बहुत अधिक बिजली का उपयोग कर रहे हैं, यह मोबाइल जीपीयू के लिए बुरा होगा। दूसरा यह है कि विचलन केवल एनवीडिया गपस पर होता है जब एक ही ताना के धागे अलग-अलग रास्ते लेते हैं और इस तरह एक अलग निर्देश सूचक होता है (जिसे पास्कल के रूप में साझा किया जाता है)। तो आप अभी भी शाखा कर सकते हैं और एनवीडिया जीपीयू पर थ्रूपुट के मुद्दे नहीं हैं यदि वे 32 के गुणक में होते हैं या केवल दर्जनों में से एक ही ताना होता है। अगर एक शाखा होने की संभावना है, तो यह अधिक संभावना है कि कम धागे विचलन करेंगे और आपके पास वैसे भी एक शाखा नहीं होगी।

एक अन्य छोटा मुद्दा यह है कि जब आप GPUs की तुलना CPUs से करते हैं, तो उनके पास प्रायः प्रीडिक्शन मैकेनिज्म और अन्य मजबूत ब्रांच मैकेनिज्म नहीं होते हैं, क्योंकि वे हार्डवेयर कितना मैकेनिज्म लेते हैं, आप अक्सर इसकी वजह से आधुनिक GPU पर नो-ओप फिल देख सकते हैं ।

व्यावहारिक GPU वास्तुकला अंतर उदाहरण

अब स्टेफ़नी का उदाहरण लेते हैं और देखते हैं कि दो सैद्धांतिक वास्तुशिल्प पर शाखा-कम समाधान के लिए विधानसभा क्या दिखती है।

n = (a==b) ? x : y;

जैसे स्टीफन ने कहा, जब डिवाइस कंपाइलर एक शाखा का सामना करता है, तो वह "चुन" तत्व के लिए एक निर्देश का उपयोग करने का निर्णय ले सकता है जो कि शाखा जुर्माना नहीं होगा। इसका मतलब है कि कुछ उपकरणों पर इसे कुछ इस तरह संकलित किया जाएगा

cmpeq rega, regb
// implicit setting of comparison bit used in next part
choose regn, regx, regy

एक निर्देश के साथ दूसरों पर, यह करने के लिए संकलित किया जा सकता है

n = ((a==b))* x + (!(a==b))* y

जो दिख सकता है:

cmpeq rega regb
// implicit setting of comparison bit used in next part
mul regn regcmp regx
xor regcmp regcmp 1
mul regresult regcmp regy
mul regn regn regresult

जो शाखा-कम और समतुल्य है, लेकिन अधिक निर्देश लेता है। क्योंकि स्टीफेंस का उदाहरण संभवतः उनके संबंधित सिस्टम पर संकलित किया जाएगा, यह स्वयं को ब्रंच करने के लिए गणित को मैन्युअल रूप से समझने की कोशिश करने के लिए बहुत अधिक समझ में नहीं आता है, क्योंकि पहले आर्किटेक्चर के कंपाइलर इसके बजाय दूसरे फॉर्म को संकलित करने का निर्णय ले सकते हैं तेज रूप।


5

मैंने @Stephane Hockenhull के जवाब में कही गई हर बात पर सहमति जताई। अंतिम बिंदु पर विस्तार करने के लिए:

आप पहले से कभी नहीं जानते हैं कि एक विशिष्ट GLSL संकलक या एक विशिष्ट GPU कैसे काम करेगा जब तक आप इसे बेंचमार्क नहीं करते।

बिल्कुल सच। इसके अलावा, मुझे लगता है कि इस तरह का सवाल काफी बार आता है। लेकिन व्यवहार में मैंने शायद ही कभी एक टुकड़े टुकड़े को एक प्रदर्शन के मुद्दे का स्रोत देखा है। यह बहुत अधिक सामान्य है कि अन्य कारक ऐसे मुद्दे पैदा कर रहे हैं जैसे कि GPU से बहुत अधिक राज्य की रीडिंग, बहुत सारे बफ़र्स की अदला-बदली, एक ही ड्रॉ कॉल में बहुत अधिक काम करना आदि।

दूसरे शब्दों में, इससे पहले कि आप किसी शेडर को माइक्रो-ऑप्टिमाइज़ करने के बारे में चिंता करें, अपने पूरे ऐप को प्रोफ़ाइल करें और सुनिश्चित करें कि शेड्स वही हैं जो आपकी मंदी का कारण बन रहा है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.