Ala*_*ain 5 python core intel-mkl python-3.x intel-python
我最近在具有 2 个处理器的 Linux 服务器上进行了几次测试,每个处理器具有 20 个物理内核(下面给出了一个处理器的完整硬件描述)以及 20 个额外的逻辑内核(因此总共 80 个内核)。进行这项调查的原因是我在一个研究实验室工作,那里的大部分代码都是用 Python 编写的,并且我发现了许多与从计算机到另一台计算机的 Python 性能变化相关的在线帖子。
这是我的设置:
我对 numpy 和 scipy 的各种基本功能进行了比较,特别是:
scipy.sparse.linal.spsolve : 线性系统 (Ax=b) 的解,其中 A 为 68000x68000 稀疏矩阵,xa 为 68000x50 稀疏矩阵, scipy.sparse.linalg.eigsh : 68000x68000 稀疏矩阵的广义特征值问题的解决方案,numpy.dotscipy.linalg.cholesky 和 scipy.linalg.svd基本上,考虑到测试脚本timeit的默认执行及其使用不同数量(x-1)的内核执行,我决定为每个版本的 Python运行测试脚本(每个运行 25 到 100 次以获取相关结果)命令taskset --cpu-list 0-x ...。
以下是我的结果的简要总结:
scipy.sparse.linal.spsolve scipy.sparse.linalg.eigshnumpy.dotscipy.linalg.choleskyscipy.linalg.svd我应该补充一点,黑点和虚线表示默认执行时间,不使用taskset命令。
正如预期的那样,Python Intel 的性能比 Python 3 好。然而,让我感到非常惊讶的是,Python Intel 代码的默认执行速度可能比它在有限(3 到 5)个内核上的执行速度慢(特别是对于 spsolve 和 eigsh )。
这是否正常(我猜在计算时间和内核之间的通信时间之间可以找到平衡点)?有什么方法可以优化多核处理器上 Python 代码的默认执行?
以下是我的服务器核心之一的规格:
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 79
model name : Intel(R) Xeon(R) CPU E5-2698 v4 @ 2.20GHz
stepping : 1
microcode : 0xb00002e
cpu MHz : 1207.958
cache size : 51200 KB
physical id : 0
siblings : 20
core id : 0
cpu cores : 20
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 20
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch epb cat_l3 cdp_l3 invpcid_single intel_ppin intel_pt ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm cqm rdt_a rdseed adx smap xsaveopt cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local dtherm ida arat pln pts spec_ctrl intel_stibp flush_l1d
bogomips : 4389.92
clflush size : 64
cache_alignment : 64
address sizes : 46 bits physical, 48 bits virtual
power management:
Run Code Online (Sandbox Code Playgroud)
另外,这里是我使用的代码:(1)用于spsolve:
#!/usr/bin/env python
import timeit
setup = '''
import numpy
import sys
import timeit
import scipy.io
from scipy.sparse.linalg import spsolve
from scipy import sparse
K=scipy.io.loadmat('K0.mat', struct_as_record=False,squeeze_me=True)
K = K.tocsc()
def problin(K):
MS = numpy.zeros([numpy.shape(K)[0],50])
for i in range(50):
MS[i,i]=1;
MS = sparse.csc_matrix(MS)
#
x = spsolve(-K,MS)
return x
'''
code = '''
x = problin(K)
'''
count = 5
t = timeit.Timer(code,setup = setup)
print("spsolve:", t.timeit(count)/count, "sec")
Run Code Online (Sandbox Code Playgroud)
(2) 对于eigsh:
#!/usr/bin/env python
import timeit
setup = '''
import numpy
import sys
import scipy.io
from scipy.sparse.linalg import eigsh
K=scipy.io.loadmat('K0.mat', struct_as_record=False,squeeze_me=True)
M=scipy.io.loadmat('M0.mat', struct_as_record=False,squeeze_me=True)
K = K['K'].tocsc()
M = M['M'].tocsc()
def vp(K,M): # Function is compiled to machine code when called the first time
w, z = eigsh(K,10,M,sigma=1)
f = numpy.sqrt(w)/2/numpy.pi
return f
'''
code = '''
f = vp(K,M)
'''
count = 5
t = timeit.Timer(code,setup = setup)
print("eigsh:", t.timeit(count)/count, "sec")
Run Code Online (Sandbox Code Playgroud)
(3) 对于 cholesky 和 SVD,我在网上找到了脚本:
#!/usr/bin/env python
import timeit
setup = "import numpy;\
import scipy.linalg as linalg;\
x = numpy.random.random((1000,1000));\
z = numpy.dot(x, x.T)"
count = 25
t = timeit.Timer("linalg.cholesky(z, lower=True)", setup=setup)
print("cholesky:", t.timeit(count)/count, "sec")
t = timeit.Timer("linalg.svd(z)", setup=setup)
print("svd:", t.timeit(count)/count, "sec")
Run Code Online (Sandbox Code Playgroud)
(4) dot:
#!/usr/bin/env python
import numpy
from numpy.distutils.system_info import get_info
import sys
import timeit
print("version: %s" % numpy.__version__)
print("maxint: %i\n" % sys.maxsize)
info = get_info('blas_opt')
print('BLAS info:')
for kk, vv in info.items():
print(' * ' + kk + ' ' + str(vv))
setup = "import numpy; x = numpy.random.random((2000, 2000))"
count = 100
t = timeit.Timer("numpy.dot(x, x.T)", setup=setup)
print("\ndot: %f sec" % (t.timeit(count) / count))
Run Code Online (Sandbox Code Playgroud)