अद्यतनप्रदर्शन मल्टी कोर मशीन
पर एकल का आव्यूह गुणन बनाम डबल परिशुद्धता सरणियों की गिरावट दुर्भाग्य से, मेरी निरीक्षण की वजह से, मैं एक पुराने 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 बेहतर बनाता है।
आप शायद युगल के साथ scalability सीमा तक पहुंच गए नहीं कर रहे हैं यह एक सटीक की तुलना में 2 गुणा अधिक काम है के रूप में। यदि आप मैट्रिक्स आकार को कम कर देंगे तो आप एक ही व्यवहार को डबल परिशुद्धता के साथ देख सकते हैं। – Elalfer
अधिक कोर के अतिरिक्त प्रदर्शन को देखने योग्य होने के लिए मुझे डबल परिशुद्धता के लिए मैट्रिक्स आकार को एन = 1000 में कम करना पड़ा। उच्च आकार के साथ, यह बस ऊपर है। इसके अलावा, यह केवल 2x अधिक काम नहीं है (वेक्टरेशन के कारण), लेकिन 2x अधिक मेमोरी स्थानांतरित की जा सकती है। –
पायथन दुभाषिया को 'numactl --interleave = nodes python' के रूप में चलाने का प्रयास करें और फिर बेंचमार्क फिर से करें। –