2016-01-27 12 views
28

अद्यतनप्रदर्शन मल्टी कोर मशीन

पर एकल का आव्यूह गुणन बनाम डबल परिशुद्धता सरणियों की गिरावट दुर्भाग्य से, मेरी निरीक्षण की वजह से, मैं एक पुराने numpy के खिलाफ जुड़ा हुआ MKL के संस्करण (11.1) था। एमकेएल का नया संस्करण (11.3.1) सी में समान प्रदर्शन देता है और जब पाइथन से बुलाया जाता है।

चीजों को अस्पष्ट करने वाला क्या था, भले ही संकलित साझा पुस्तकालयों को स्पष्ट रूप से नए एमकेएल के साथ जोड़ना और एलडी_ * चर के माध्यम से इंगित करना, और फिर पाइथन आयात आयात करने में, किसी भी तरह से पाइथन कॉल पुराने एमकेएल पुस्तकालयों को बना रहा था। केवल python lib फ़ोल्डर में बदलकर सभी libmkl _ *। इसलिए नए एमकेएल के साथ मैं पायथन और सी कॉल में प्रदर्शन मैच करने में सक्षम था।

पृष्ठभूमि/पुस्तकालय जानकारी।

मैट्रिक्स गुणा एसजीईएमएम (सिंगल-प्रेसिजन) और डीजीएमएम (डबल-प्रेसिजन) इंटेल की एमकेएल लाइब्रेरी कॉल के माध्यम से numpy.dot फ़ंक्शन के माध्यम से किया गया था। लाइब्रेरी फ़ंक्शंस की वास्तविक कॉल को सत्यापित किया जा सकता है उदा। oprof।

यहां 2x18 कोर CPU E5-2699 v3 का उपयोग करना, इसलिए कुल 36 भौतिक कोर का उपयोग करना। KMP_AFFINITY = स्कैटर। लिनक्स पर चल रहा है।

टी एल; डॉ

1) क्यों numpy.dot, हालांकि यह एक ही MKL पुस्तकालय कार्यों बुला रहा है, दो बार है धीमी पर सबसे अच्छा सी संकलित कोड की तुलना में?

2) numpy.dot के माध्यम से आप कोर की बढ़ती संख्या के साथ प्रदर्शन में कमी क्यों करते हैं, जबकि सी कोड में समान प्रभाव नहीं देखा जाता है (उसी लाइब्रेरी फ़ंक्शंस को कॉल करना)।

समस्या

मैंने देखा है कि सिंगल/डबल परिशुद्धता के कर आव्यूह गुणन एक संकलित सी साझा लाइब्रेरी से सीधे cblas_sgemm/dgemm बुला के रूप में numpy.dot में तैरता है, साथ ही काफ़ी बदतर देना आंतरिक शुद्ध सी कोड से समान एमकेएल cblas_sgemm/dgemm फ़ंक्शंस को कॉल करने की तुलना में प्रदर्शन।

import numpy as np 
import mkl 
n = 10000 
A = np.random.randn(n,n).astype('float32') 
B = np.random.randn(n,n).astype('float32') 
C = np.zeros((n,n)).astype('float32') 

mkl.set_num_threads(3); %time np.dot(A, B, out=C) 
11.5 seconds 
mkl.set_num_threads(6); %time np.dot(A, B, out=C) 
6 seconds 
mkl.set_num_threads(12); %time np.dot(A, B, out=C) 
3 seconds 
mkl.set_num_threads(18); %time np.dot(A, B, out=C) 
2.4 seconds 
mkl.set_num_threads(24); %time np.dot(A, B, out=C) 
3.6 seconds 
mkl.set_num_threads(30); %time np.dot(A, B, out=C) 
5 seconds 
mkl.set_num_threads(36); %time np.dot(A, B, out=C) 
5.5 seconds 

वास्तव में ऊपर के रूप में ही कर रहा है, लेकिन डबल परिशुद्धता एक साथ, बी और सी, आपको मिलता है: 3 कोर: 20, 6 कोर: 10s, 12 कोर: 5s, 18 कोर: 4.3s, 24 कोर: 3 एस, 30 कोर: 2.8 एस, 36 कोर: 2.8 एस।

एकल परिशुद्धता फ़्लोटिंग बिंदुओं के लिए गति की टॉपिंग अप कैश मिस से जुड़ी प्रतीत होती है। 28 कोर रन के लिए, यहां परफ का आउटपुट है। एकल परिशुद्धता के लिए:

perf stat -e task-clock,cycles,instructions,cache-references,cache-misses ./ptestf.py 
631,301,854 cache-misses # 31.478 % of all cache refs 

और डबल परिशुद्धता:

93,087,703 cache-misses # 5.164 % of all cache refs 

सी साझा लाइब्रेरी,

/opt/intel/bin/icc -o comp_sgemm_mkl.so -openmp -mkl sgem_lib.c -lm -lirc -O3 -fPIC -shared -std=c99 -vec-report1 -xhost -I/opt/intel/composer/mkl/include 

#include <stdio.h> 
#include <stdlib.h> 
#include "mkl.h" 

void comp_sgemm_mkl(int m, int n, int k, float *A, float *B, float *C); 

void comp_sgemm_mkl(int m, int n, int k, float *A, float *B, float *C) 
{ 
    int i, j; 
    float alpha, beta; 
    alpha = 1.0; beta = 0.0; 

    cblas_sgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, 
       m, n, k, alpha, A, k, B, n, beta, C, n); 
} 

अजगर आवरण समारोह के साथ संकलित, ऊपर संकलित पुस्तकालय बुला:

def comp_sgemm_mkl(A, B, out=None): 
    lib = CDLL(omplib) 
    lib.cblas_sgemm_mkl.argtypes = [c_int, c_int, c_int, 
           np.ctypeslib.ndpointer(dtype=np.float32, ndim=2), 
           np.ctypeslib.ndpointer(dtype=np.float32, ndim=2), 
           np.ctypeslib.ndpointer(dtype=np.float32, ndim=2)] 
    lib.comp_sgemm_mkl.restype = c_void_p 
    m = A.shape[0] 
    n = B.shape[0] 
    k = B.shape[1] 
    if np.isfortran(A): 
     raise ValueError('Fortran array') 
    if m != n: 
     raise ValueError('Wrong matrix dimensions') 
    if out is None: 
     out = np.empty((m,k), np.float32) 
    lib.comp_sgemm_mkl(m, n, k, A, B, out) 

हालांकि, सी-संकलित बाइनरी कॉलिंग एमकेएल के cblas_sgemm/cblas_dgemm से स्पष्ट कॉल, सी में मॉलोक के माध्यम से आवंटित सरणी के साथ, पायथन कोड की तुलना में लगभग 2x बेहतर प्रदर्शन देता है, यानी numpy.dot कॉल। इसके अलावा, कोर की बढ़ती संख्या के साथ प्रदर्शन गिरावट का प्रभाव नहीं देखा जाता है। सर्वश्रेष्ठ प्रदर्शन एकल-परिशुद्धता मैट्रिक्स गुणा के लिए 900 एमएस था और mkl_set_num_cores के माध्यम से सभी 36 भौतिक कोरों का उपयोग करते समय और numactl --interleave = सभी के साथ सी कोड चलाने के दौरान हासिल किया गया था।

शायद इस स्थिति को प्रोफाइलिंग/निरीक्षण/समझने के लिए कोई फैंसी टूल या सलाह? किसी भी पढ़ने की सामग्री भी बहुत सराहना की है।

अद्यतन @Hristo Iliev सलाह के बाद, चल numactl --interleave = सभी ./ipython (शोर के अंदर) के समय परिवर्तन नहीं किया है, लेकिन शुद्ध सी बाइनरी runtimes बेहतर बनाता है।

+1

आप शायद युगल के साथ scalability सीमा तक पहुंच गए नहीं कर रहे हैं यह एक सटीक की तुलना में 2 गुणा अधिक काम है के रूप में। यदि आप मैट्रिक्स आकार को कम कर देंगे तो आप एक ही व्यवहार को डबल परिशुद्धता के साथ देख सकते हैं। – Elalfer

+0

अधिक कोर के अतिरिक्त प्रदर्शन को देखने योग्य होने के लिए मुझे डबल परिशुद्धता के लिए मैट्रिक्स आकार को एन = 1000 में कम करना पड़ा। उच्च आकार के साथ, यह बस ऊपर है। इसके अलावा, यह केवल 2x अधिक काम नहीं है (वेक्टरेशन के कारण), लेकिन 2x अधिक मेमोरी स्थानांतरित की जा सकती है। –

+0

पायथन दुभाषिया को 'numactl --interleave = nodes python' के रूप में चलाने का प्रयास करें और फिर बेंचमार्क फिर से करें। –

उत्तर

7

मुझे संदेह है कि यह दुर्भाग्यपूर्ण थ्रेड शेड्यूलिंग के कारण है। मैं आपके जैसा प्रभाव पुन: उत्पन्न करने में सक्षम था। पायथन ~ 2.2 एस पर चल रहा था, जबकि सी संस्करण 1.4-2.2 से भारी बदलाव दिखा रहा था।

आवेदन: KMP_AFFINITY=scatter,granularity=thread यह सुनिश्चित करता है कि 28 थ्रेड हमेशा एक ही प्रोसेसर थ्रेड पर चल रहे हैं।

दोनों रनटाइम्स को अधिक स्थिर ~ 1.24 एस के लिए सी और ~ 1.26 एस पाइथन के लिए कम करता है।

यह 28 कोर दोहरी सॉकेट ज़ीऑन ई 5-2680 वी 3 सिस्टम पर है।

दिलचस्प बात यह है कि, 24 समान दोहरी सॉकेट हैसवेल प्रणाली पर, पाइथन और सी दोनों थ्रेड एफ़िनिटी/पिनिंग के बिना लगभग समान प्रदर्शन करते हैं।

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

आपको यह भी विचार करने की आवश्यकता है कि इंटेल ओपनएमपी रनटाइम एक अतिरिक्त प्रबंधन थ्रेड उत्पन्न करता है जो शेड्यूलर को भ्रमित कर सकता है। पिनिंग के लिए और विकल्प हैं, उदाहरण के लिए KMP_AFFINITY=compact - लेकिन किसी कारण से जो पूरी तरह से मेरे सिस्टम पर गड़बड़ हो गया है। आप चरम पर ,verbose जोड़ सकते हैं यह देखने के लिए कि रनटाइम आपके धागे को कैसे पिन कर रहा है।

likwid-pin एक उपयोगी विकल्प है जो अधिक सुविधाजनक नियंत्रण प्रदान करता है।

सामान्य एकल परिशुद्धता में कम से कम डबल परिशुद्धता के रूप में तेज़ होना चाहिए।डबल परिशुद्धता धीमी हो सकती है क्योंकि:

  • आपको डबल परिशुद्धता के लिए अधिक मेमोरी/कैश बैंडविड्थ की आवश्यकता है।
  • आप ALUs एकल परिशुद्धता के लिए उच्च througput है कि निर्माण कर सकते हैं, लेकिन है कि आमतौर पर सीपीयू बल्कि GPUs के लिए लागू नहीं होता।

मुझे लगता है कि एक बार जब आप प्रदर्शन विसंगति से छुटकारा पा लेते हैं, तो यह आपकी संख्याओं में दिखाई देगा।

जब आप MKL/* GEMM के लिए थ्रेड की संख्या पैमाने पर विचार

  • मेमोरी/साझा कैश बैंडविड्थ एक टोंटी हो सकता है, scalability
  • टर्बो मोड सीमित प्रभावी रूप से कोर आवृत्ति जब कम हो जाएगा उपयोग बढ़ रहा है। यह मामूली आवृत्ति पर चलने पर भी लागू होता है: हैसवेल-ईपी प्रोसेसर पर, एवीएक्स निर्देश कम "एवीएक्स आधार आवृत्ति" लगाएंगे - लेकिन प्रोसेसर को उस से अधिक होने की अनुमति है जब कम कोर का उपयोग किया जाता है/थर्मल हेडरूम उपलब्ध होता है और सामान्य रूप से भी थोड़े समय के लिए और अधिक। यदि आप पूरी तरह से तटस्थ परिणाम चाहते हैं, तो आपको AVX बेस आवृत्ति का उपयोग करना होगा, जो आपके लिए 1.9 गीगाहर्ट्ज है। यह here दस्तावेज है, और one picture में समझाया गया है।

मुझे नहीं लगता कि यह निर्धारित करने का एक आसान तरीका है कि आपका आवेदन खराब शेड्यूलिंग से कैसे प्रभावित होता है। आप इसे perf trace -e sched:sched_switch के साथ बेनकाब कर सकते हैं और इसे देखने के लिए some software है, लेकिन यह एक उच्च सीखने की वक्र के साथ आएगा। और फिर फिर - समानांतर प्रदर्शन विश्लेषण के लिए आपको वैसे भी धागे पिन करना चाहिए।

+0

मैंने समस्या के कारण से अपना प्रश्न अपडेट कर लिया है। आपके उत्तरों में अमूल्य जानकारी है। बीटीडब्ल्यू, केएमपी_एएफएफआईएनटी = कॉम्पैक्ट एक ही कोर पर दो धागे आवंटित करता है, और 4 धागे के साथ, केवल 2 कोर का उपयोग किया जाएगा, इत्यादि। –

संबंधित मुद्दे