ios - मेमोरी लेखन प्रदर्शन-जीपीयू सीपीयू साझा मेमोरी




swift memory-management (2)

प्रकार के आकार को कम करें

मूल रूप से, मैं 16-बिट आकार वाले इंटीग्रेट्स को फ़्लोट्स (32-बिट) के रूप में पूर्व-रूपांतरित कर रहा था क्योंकि आखिरकार उनका उपयोग किया जाएगा। यह एक ऐसा मामला है जहां प्रदर्शन आपको डेटा को आकार में कटौती करने के लिए मूल्यों को 16-बिट्स के रूप में स्टोर करने के लिए मजबूर करना शुरू कर देता है।

स्विफ्ट पर उद्देश्य सी

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

परीक्षण की कठिनाई

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

मैं memkite द्वारा प्रदान किए गए साझा GPU / CPU दस्तावेज़ के अनुसार MTLBuffer का उपयोग कर इनपुट और आउटपुट MTLBuffer दोनों आवंटित कर रहा हूं।

इसके अलावा: posix_memalign साथ posix_memalign तुलना में नवीनतम API का उपयोग करना आसान है

let metalBuffer = self.metalDevice.newBufferWithLength(byteCount, options: .StorageModeShared)

मेरा कर्नेल फ़ंक्शन लगभग 16 मिलियन जटिल मूल्य structs पर काम करता है और स्मृति के लिए जटिल मूल्य structs के बराबर संख्या लिखता है।

मैंने कुछ प्रयोग किए हैं और मेरा धातु कर्नेल 'जटिल गणित खंड' 0.003 सेकंड (हाँ!) में निष्पादित करता है, लेकिन बफर को परिणाम लिखना> 0.05 (नहीं!) सेकंड लेता है। मेरे प्रयोग में मैंने गणित के भाग पर टिप्पणी की और केवल शून्य को स्मृति को असाइन किया और इसे 0.05 सेकंड लगते हैं, असाइनमेंट पर टिप्पणी करते हुए और गणित को वापस 0.003 सेकेंड जोड़ते हैं।

क्या इस मामले में साझा स्मृति धीमी है, या क्या कोई अन्य युक्ति या चाल है जिसे मैं कोशिश कर सकता हूं?

अतिरिक्त विवरण

टेस्ट प्लेटफार्म

  • आईफोन 6 एस - प्रति फ्रेम ~ 0.039 सेकंड
  • आईपैड एयर 2 - प्रति फ्रेम ~ 0.130 सेकंड

स्ट्रीमिंग डेटा

शेडर के प्रत्येक अपडेट को संरचना में float प्रकारों की एक जोड़ी के रूप में लगभग 50000 जटिल संख्याएं मिलती हैं।

struct ComplexNumber {
    float real;
    float imaginary;
};

कर्नेल हस्ताक्षर

kernel void processChannelData(const device Parameters *parameters [[ buffer(0) ]],
                               const device ComplexNumber *inputSampleData [[ buffer(1) ]],
                               const device ComplexNumber *partAs [[ buffer(2) ]],
                               const device float *partBs [[ buffer(3) ]],
                               const device int *lookups [[ buffer(4) ]],
                               device float *outputImageData [[ buffer(5) ]],
                               uint threadIdentifier [[ thread_position_in_grid ]]);

सभी बफर में - वर्तमान में - inputSampleData को छोड़कर अपरिवर्तनीय डेटा जो 50000 नमूने प्राप्त करता है, मैं चालू रहूंगा। अन्य बफर में लगभग 16 मिलियन मान (128 चैनल x 130000 पिक्सेल) होते हैं। मैं प्रत्येक 'पिक्सेल' पर कुछ संचालन करता हूं और चैनलों में जटिल परिणाम outputImageData और आखिरकार जटिल संख्या का पूर्ण मूल्य outputImageData और परिणामी float outputImageData को असाइन करता outputImageData

प्रेषण

commandEncoder.setComputePipelineState(pipelineState)

commandEncoder.setBuffer(parametersMetalBuffer, offset: 0, atIndex: 0)
commandEncoder.setBuffer(inputSampleDataMetalBuffer, offset: 0, atIndex: 1)
commandEncoder.setBuffer(partAsMetalBuffer, offset: 0, atIndex: 2)
commandEncoder.setBuffer(partBsMetalBuffer, offset: 0, atIndex: 3)
commandEncoder.setBuffer(lookupsMetalBuffer, offset: 0, atIndex: 4)
commandEncoder.setBuffer(outputImageDataMetalBuffer, offset: 0, atIndex: 5)

let threadExecutionWidth = pipelineState.threadExecutionWidth
let threadsPerThreadgroup = MTLSize(width: threadExecutionWidth, height: 1, depth: 1)
let threadGroups = MTLSize(width: self.numberOfPixels / threadsPerThreadgroup.width, height: 1, depth:1)

commandEncoder.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadsPerThreadgroup)
commandEncoder.endEncoding()
metalCommandBuffer.commit()
metalCommandBuffer.waitUntilCompleted()

गिटहब उदाहरण

मैंने Slow नामक एक उदाहरण लिखा है और इसे गिटहब पर रखा है। लगता है कि बाधा इनपुट बफर में मूल्यों का लेखन है। तो, मुझे लगता है कि सवाल बाधा से बचने के लिए कैसे बन जाता है?

मेमोरी कॉपी

मैंने विभिन्न बाइट प्रतिलिपि तरीकों के प्रदर्शन की तुलना करने के लिए एक त्वरित परीक्षण लिखा।

वर्तमान स्थिति

मैंने निष्पादन समय को 0.02ish सेकेंड में घटा दिया है जो बहुत कुछ नहीं लगता है, लेकिन यह फ्रेम प्रति सेकेंड की संख्या में एक बड़ा अंतर बनाता है। वर्तमान में सबसे बड़ा सुधार cblas_scopy() स्विच करने का परिणाम है।


आप अपने डेटा को एन्कोडिंग के माध्यम से MetalHuffman कोड और जीपीयू पर डिकोडिंग के माध्यम से एक बड़ी गति प्राप्त कर सकते हैं, MetalHuffman देखें। यह हालांकि आपके डेटा पर निर्भर करता है।





metal