はじめに
https://qiita.com/cielavenir/items/93d2b5b057bfe1383670 の関連。
A.soとB.soがあって、Aはlibmkl_rt、Bはlibblasに静的リンクしているとする。このとき、本来であれば、A.soおよびB.soを動的リンクするなら1、Aはlibmkl_rt、 BはlibblasをBLAS実装に使うはず。
ところが、実際には、AがMKLのBLAS関数を呼んだ後にBをロードすると、BもMKLをBLAS実装に使うようになってしまう。もし(そうそうないことだが)BがMKL以外のBLAS実装の挙動に依存する2なら、これは問題となりうる。が、今回は回避策はなさそうに思える…。
デモ
scipy/spatial/qhull.soのバイナリパッケージはlibopenblasにリンクしているが、LD_DEBUG="libs symbols" 環境で以下を実行すると、(libopenblasでなく)MKLのdgetrf/dgetrs/dgeconがロードされることが観測される。import scipy
ではscipy/spatial/qhull.soのロードに至らないことに注意。
#!/usr/bin/python
import numpy
import scipy # this does not guarantee scipy.spatial safety.
print(numpy.dot([[1,2]],[[3],[4]]))
points = numpy.random.rand(30, 2) # 30 random points in 2-D
import ctypes
n=ctypes.c_int(3)
alpha=ctypes.c_double(3)
beta=ctypes.c_double(-2)
A=(ctypes.c_double*9)(1,2,9,8,10,-5,3,8,-1)
B=(ctypes.c_double*9)(9,3,-8,8,11,6,3,2.3,1)
C=(ctypes.c_double*9)(3,8,6,3,4,1,1.2,8,-2)
# this CDLL loads so using RTLD_LOCAL
ctypes.CDLL("libmkl_rt.so").cblas_dgemm(102,111,111,n,n,n,alpha,A,n,B,n,beta,C,n)
print(list(C))
print '=== check dgetrf/dgetrs/dgecon below ==='
from scipy.spatial import ConvexHull
hull = ConvexHull(points)
おわりに
思うところがあって、先のデモでも複数個のモジュールを使うパターンを追加したところ、再現できた(あちらは(constructor attributeを使っているので)関数を呼ばずともロードしただけで再現する)。挙動を観測するに、libmkl_rtはあのdlopenし直すやつをやっているだけではないだろうか…?
新しいglibcの対策(および別解)
angel様いわく、.aを使った上で-pie -rdynamicを指定することで回避可能とのこと。
が、このようにして生成したライブラリはglibc 2.30以降では標準ではロードできない。mkexeloadableをバイナリに対して用いることでロード可能になる。
ところで、このプログラムで操作しているのはELFタグ6ffffffbであるが、これを検索するとLLVMで-Bsymbolicをサポートしようとするパッチが見つかる。つまり、-Wl,-Bsymbolic
を指定すれば良い。ただし、これも.aを使う必要がある。さらに、-sharedを使う以上は.aが-fPICでコンパイルされている必要がある。
以上のことは https://github.com/cielavenir/angel_pietest には反映している。
さて、Debian busterは、/usr/lib/x86_64-linux/gnu/blas/libblas.aが-fPICでコンパイルされているが、bullseyeはそうでない。3.8.0-5以降のパッケージは-fPICでなくなった旨の更新履歴がある。lapackのソースパッケージをコンパイルし、lapack-3.9.0/pic32/libcblas_pic.a lapack-3.9.0/pic32/librefblas_pic.a lapack-3.9.0/pic32/libcblas_pic.a
3にリンクすればよいが、実用的ではない。
…普通にmkexeloadable使ったほうが良さそうです^^;;;でもこれのおかげで6ffffffbというキーワードがわかったので感謝。