Вопрос:

Использование mkl_set_num_threads с numpy

python numpy intel-mkl

4024 просмотра

4 ответа

33366 Репутация автора

Я пытаюсь установить количество потоков для вычисления NumPy с помощью mkl_set_num_threadsэтого

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

но я продолжаю получать ошибку сегментации:

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

Получение количества потоков не проблема:

print mkl_rt.mkl_get_max_threads()

Как я могу заставить мой код работать? Или есть другой способ установить количество потоков во время выполнения?

Автор: Daniel Источник Размещён: 02.02.2015 05:17

Ответы (4)


14 плюса

33366 Репутация автора

Решение

Офион повел меня правильно. Несмотря на документацию, необходимо передать параметр mkl_set_num_threadпо ссылке.

Теперь я определил функции для получения и установки потоков

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

и они работают как положено.

Редактировать: в соответствии с Rufflewind, имена C-функций пишутся заглавными буквами, которые ожидают параметры по значению:

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
Автор: Daniel Размещён: 03.02.2015 07:01

5 плюса

6717 Репутация автора

Короче говоря, используйте MKL_Set_Num_Threadsего и его друзей из CamelCased при вызове MKL из Python. То же самое относится к C, если вы этого не сделаете #include <mkl.h>.


Документация MKL, кажется, предполагает, что правильная сигнатура типа в C:

void mkl_set_num_threads(int nt);

Хорошо, давайте попробуем минимальную программу:

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

Скомпилируйте его с помощью GCC и boom , Segmentation faultснова. Так что, похоже, проблема не ограничивается Python.

Запуск его через отладчик (GDB) показывает:

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

Подождите секунду, mkl_set_num_threads_?? Это Fortran версия о mkl_set_num_threads! Как мы в итоге назвали версию на Фортране? (Имейте в виду, что соглашение о вызовах Фортрана требует, чтобы аргументы передавались как указатели, а не по значению.)

Оказывается, документация была законченным фасадом. Если вы на самом деле осмотрите заголовочные файлы для последних версий MKL, вы найдете это симпатичное маленькое определение:

void    MKL_Set_Num_Threads(int nth);
#define mkl_set_num_threads         MKL_Set_Num_Threads

… И теперь все имеет смысл! Корректная функция do call (для кода C) есть MKL_Set_Num_Threads, а не mkl_set_num_threads. Изучение таблицы символов показывает, что на самом деле определены четыре различных варианта :

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_
…

Почему Intel включила четыре различных варианта одной функции, несмотря на то, что в документации были только варианты C и Fortran? Я не знаю наверняка, но я подозреваю, что это для совместимости с различными компиляторами Фортрана. Видите ли, соглашение о вызовах Фортрана не стандартизировано. Различные компиляторы будут по-разному манипулировать именами функций:

  • некоторые используют верхний регистр,
  • некоторые используют нижний регистр с завершающим подчеркиванием, и
  • некоторые используют строчные буквы без каких-либо украшений.

Могут быть и другие способы, о которых я не знаю. Этот прием позволяет использовать библиотеку MKL с большинством компиляторов Фортрана без каких-либо изменений, недостатком является то, что функции C необходимо "искажать", чтобы освободить место для 3 вариантов соглашения о вызовах Фортрана.

Автор: Rufflewind Размещён: 03.02.2015 07:42

0 плюса

163 Репутация автора

Для людей, которые ищут полное решение, вы можете использовать контекстный менеджер:

import ctypes


class MKLThreads(object):
    _mkl_rt = None

    @classmethod
    def _mkl(cls):
        if cls._mkl_rt is None:
            try:
                cls._mkl_rt = ctypes.CDLL('libmkl_rt.so')
            except OSError:
                cls._mkl_rt = ctypes.CDLL('mkl_rt.dll')
        return cls._mkl_rt

    @classmethod
    def get_max_threads(cls):
        return cls._mkl().mkl_get_max_threads()

    @classmethod
    def set_num_threads(cls, n):
        assert type(n) == int
        cls._mkl().mkl_set_num_threads(ctypes.byref(ctypes.c_int(n)))

    def __init__(self, num_threads):
        self._n = num_threads
        self._saved_n = self.get_max_threads()

    def __enter__(self):
        self.set_num_threads(self._n)
        return self

    def __exit__(self, type, value, traceback):
        self.set_num_threads(self._saved_n)

Тогда используйте это как:

with MKLThreads(2):
    # do some stuff on two cores
    pass

Или просто манипулируя конфигурацией, вызывая следующие функции:

# Example
MKLThreads.set_num_threads(3)
print(MKLThreads.get_max_threads())

Код также доступен в этой сути .

Автор: Alex Maystrenko Размещён: 24.01.2019 04:25

0 плюса

3259 Репутация автора

Для тех, кто ищет кроссплатформенное и пакетное решение, обратите внимание, что мы недавно выпустили threadpoolctlмодуль для ограничения количества потоков, используемых в пулах потоков уровня C, называемых python ( OpenBLAS, OpenMPи MKL). Смотрите этот ответ для получения дополнительной информации.

Автор: Thomas Moreau Размещён: 04.06.2019 11:46
Вопросы из категории :
32x32