2015-02-02 20 views
13

Ich versuche, die Anzahl der Threads für numpy Berechnungen mit mkl_set_num_threads wie dieseMit mkl_set_num_threads mit numpy

import numpy 
import ctypes 
mkl_rt = ctypes.CDLL('libmkl_rt.so') 
mkl_rt.mkl_set_num_threads(4) 

zu setzen aber ich erhalte einen Segmentation Fault bekommen:

Program received signal SIGSEGV, Segmentation fault. 
0x00002aaab34d7561 in mkl_set_num_threads__() from /../libmkl_intel_lp64.so 

gibt es die Anzahl der Gewinde ist kein Problem:

print mkl_rt.mkl_get_max_threads() 

Wie kann ich meinen Code arbeiten lassen? Oder gibt es eine andere Möglichkeit, die Anzahl der Threads zur Laufzeit festzulegen?

+0

Als ich die Enthought Python Distribution hatte, konnte ich 'mkl' als Modul importieren. Ich frage mich, was hinter den Kulissen passiert ist. –

Antwort

9

Ophion führte mich auf dem richtigen Weg. Trotz der Dokumentation muss man den Parameter mkl_set_num_thread per Referenz übertragen.

Jetzt habe ich auf Funktionen definiert, für das Abrufen und Einstellen der Fäden

import numpy 
import ctypes 
mkl_rt = ctypes.CDLL('libmkl_rt.so') 
mkl_get_max_threads = mkl_rt.mkl_get_max_threads 
def mkl_set_num_threads(cores): 
    mkl_rt.mkl_set_num_threads(ctypes.byref(ctypes.c_int(cores))) 

mkl_set_num_threads(4) 
print mkl_get_max_threads() # says 4 

und sie funktionieren wie erwartet.

Edit: nach Rufflewind, die Namen der C-Funktionen sind in Großbuchstaben geschrieben, die Parameter, die von Wert erwarten:

import ctypes 

mkl_rt = ctypes.CDLL('libmkl_rt.so') 
mkl_set_num_threads = mkl_rt.MKL_Set_Num_Threads 
mkl_get_max_threads = mkl_rt.MKL_Get_Max_Threads 
5

Lange Rede kurzer Sinn, verwenden MKL_Set_Num_Threads und seine camelcase Freunde, wenn MKL Aufruf aus Python. Das gleiche gilt für C, wenn Sie nicht #include <mkl.h>.


Die MKL documentation scheint darauf hinzudeuten, dass die richtige Art Signatur in C:

void mkl_set_num_threads(int nt); 

Okay, lassen Sie uns ein Minimalprogramm versuchen dann:

void mkl_set_num_threads(int); 
int main(void) { 
    mkl_set_num_threads(1); 
    return 0; 
} 

es Kompilieren mit GCC und Boom, Segmentation fault wieder. Es scheint also, dass das Problem nicht auf Python beschränkt ist.

es läuft durch einen Debugger (GDB) offenbart:

Program received signal SIGSEGV, Segmentation fault. 
0x0000… in mkl_set_num_threads_() 
    from /…/mkl/lib/intel64/libmkl_intel_lp64.so 

Warte eine Sekunde, mkl_set_num_threads_ ?? Das ist die Fortran-Version von mkl_set_num_threads! Wie haben wir am Ende die Fortran-Version genannt? (Beachten Sie, dass die Aufrufkonvention von Fortran erfordert, dass die Argumente als Zeiger und nicht als Wert übergeben werden.)

Es stellt sich heraus, dass die Dokumentation eine vollständige Fassade war. Wenn Sie tatsächlich die Header-Dateien für die aktuellen Versionen von MKL untersuchen, werden Sie diese nette kleine Definition finden:

void MKL_Set_Num_Threads(int nth); 
#define mkl_set_num_threads   MKL_Set_Num_Threads 

... und jetzt ist alles macht Sinn! Die korrekte Funktion do call (für C-Code) ist MKL_Set_Num_Threads, nicht mkl_set_num_threads.die Symboltabelle Inspizieren zeigt, dass es tatsächlich vier verschiedene Varianten definiert sind:

nm -D /…/mkl/lib/intel64/libmkl_rt.so | grep -i mkl_set_num_threads 
00000000000e3060 T MKL_SET_NUM_THREADS 
… 
00000000000e30b0 T MKL_Set_Num_Threads 
… 
00000000000e3060 T mkl_set_num_threads 
00000000000e3060 T mkl_set_num_threads_ 
… 

Warum hat Intel legte in vier verschiedenen Varianten einer Funktion trotz nur C und Fortran sind Varianten in der Dokumentation? Ich weiß es nicht genau, aber ich vermute, dass es für die Kompatibilität mit verschiedenen Fortran-Compilern ist. Sie sehen, Fortran Aufruf Konvention ist nicht standardisiert. Verschiedene Compiler mangle the names der Funktionen unterschiedlich:

  • einige verwenden Großbuchstaben,
  • einige verwenden Kleinbuchstaben mit einem hinteren Unterstrich und
  • einige verwenden Kleinbuchstaben ohne Dekoration alles an.

Es kann sogar andere Wege geben, die mir nicht bekannt sind. Dieser Trick erlaubt es, die MKL-Bibliothek mit meisten Fortran-Compilern ohne jegliche Modifikation zu verwenden, der Nachteil ist, dass C-Funktionen "gemangelt" werden müssen, um Platz für die 3 Varianten der Fortran-Aufrufkonvention zu schaffen.