Измерение и повышение эффективности графического процессора

Начало работы с бенчмаркингом графический процессор

Вы можете использовать различные тесты бенчмарка в MATLAB® для измерения эффективности вашего графического процессора:

  • Использование gpuBench в MATLAB Central File Exchange для выполнения различных тестов, включая как память, так и вычисление интенсивных задач как с одинарной, так и с двойной точностью. Сравните эффективность отображения с вычислительной картой. Для получения дополнительной информации смотрите https://www.mathworks.com/matlabcentral/fileexchange/34080-gpubench.

  • Используйте paralleldemo_gpu_bench скрипт в Measuring GPU Performance для получения информации о скорости шины PCI, производительности чтения/записи памяти графический процессор и пиковых вычислениях для вычислений матрицы двойной точности.

Улучшите эффективность с помощью вычислений одинарной точности

Вы можете улучшить эффективность вашего графического процессора, выполнив вычисления с одинарной точностью вместо двойной точности. В расчетах центральный процессор, с другой стороны, вы не получаете этого улучшения при переключении с двойной на одинарную точность. Причина в том, что большинство графического процессора карт предназначены для графических отображений, требующих высокой одинарной точности эффективности.

Типичные примеры вычислений, подходящих для одноточных расчетов на графическом процессоре, включают обработку изображений и машинное обучение, см., например, https://www.mathworks.com/content/dam/mathworks/tag-team/Objects/d/Deep_Learning_in_Cloud_Whitepaper.pdf. Однако другие типы вычислений, такие как задачи линейной алгебры, обычно требуют двойной точности обработки.

Вы можете получить повышение эффективности до 50 раз для одиночных вычислений по сравнению с двойной точностью, в зависимости от карты GPU и общего количества ядер. Вычислительные карты высшего класса обычно показывают меньшее улучшение. Определить повышение эффективности конкретного графического процессора можно используя gpuBench, см. https://www.mathworks.com/matlabcentral/fileexchange/34080-gpubench.

Полный обзор эффективности NVIDIA® Графические процессоры, см. https://en.wikipedia.org/wiki/List_of_Nvidia_graphics_processing_units. Можно вычислить коэффициент улучшения эффективности между одинарной точностью и двойной точностью следующим образом:

  • Найдите графический процессор на странице wiki выше.

  • Получите указанные значения эффективности с одинарной и двойной точностью из таблицы. Если значения GFLOPS двойной точности нет, предположим, что отношение для двойной точности 24‐32x медленнее.

  • Разделите указанное значение GFLOPS одинарной точности на значение GFLOPS двойной точности.

Примечание

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

Основной рабочий процесс повышения эффективности

Цель графических процессоров в MATLAB - ускорить работу ваших приложений. В этой теме рассматриваются основные концепции и практики, которые могут помочь вам достичь лучшей эффективности на графическом процессоре, такие как строение оборудования GPU и лучшие практики в вашем коде. В нем обсуждается компромисс между сложностью реализации и эффективностью и описываются критерии, которые можно использовать для выбора между использованием функций gpuArray, arrayfunФайлы MEX, или ядра CUDA. Наконец, в нем описывается, как точно измерить эффективность на графическом процессоре.

При преобразовании кода MATLAB для запуска на графическом процессоре лучше всего начать с кода MATLAB, который уже хорошо работает. В то время как GPU и CPU имеют различную эффективность, общие рекомендации по написанию хорошего кода MATLAB также помогают вам написать хороший код MATLAB для графический процессор. Первый шаг - почти всегда профилировать код центрального процессора. Строки кода, на которые профилировщик показов больше всего времени на центральный процессор, вероятно, будут таковые, на которых вы должны сконцентрироваться, когда вы кодируете графический процессор.

Легче всего начать преобразование кода с помощью встроенных функций MATLAB, которые поддержка данные gpuArray. Эти функции берут входы gpuArray, выполняют вычисления на графическом процессоре и возвращают выходы gpuArray. Список функций MATLAB, поддерживающих данные gpuArray, находится в Run MATLAB Functions на графическом процессоре. В целом эти функции поддерживают те же аргументы и типы данных, что и стандартные функции MATLAB, которые вычисляются на центральном процессоре.

Если все функции, которые вы хотите использовать, поддерживаются на графическом процессоре, выполняемый код на графическом процессоре может быть таким же простым, как и вызов gpuArray для передачи входных данных в графический процессор и вызывающих gather получение выхода данных из графического процессора по завершении. Во многих случаях вам может потребоваться векторизация кода, замена закольцованных скалярных операций на матрицу MATLAB и векторные операции. Хотя векторизация, как правило, является хорошей практикой на центральном процессоре, она обычно критически важна для достижения высокой эффективности на графическом процессоре. Для получения дополнительной информации см. раздел «Векторизация для повышения эффективности графического процессора».

Расширенные инструменты для повышения эффективности

Не исключено, что даже после преобразования входов в gpuArrays и векторизации вашего кода в вашем алгоритме есть операции, которые либо не встроенные функции, либо которые недостаточно быстры, чтобы соответствовать требованиям вашего приложения. В таких ситуациях у вас есть три основные опции: использовать arrayfun для предварительной компиляции элементарных частей вашего приложения используйте функции библиотеки графического процессора или написать пользовательское ядро CUDA.

Если у вас есть чисто элементарная функция, можно улучшить ее эффективность, вызвав ее с arrayfun. The arrayfun функция на графическом процессоре превращает поэлементную функцию MATLAB в пользовательское ядро CUDA, таким образом уменьшая накладные расходы на выполнение операции. Часто существует подмножество вашего приложения, которое можно использовать с arrayfun даже если целое приложение не может быть. Пример повышения эффективности поэлементных функций MATLAB ® на графическом процессоре с использованием ARRAYFUN показывает основные концепции этого подхода; и пример Использование GPU ARRAYFUN для моделирования Монте-Карло показывает, как это можно сделать в симуляциях для финансового приложения.

MATLAB предоставляет обширную библиотеку функций, поддерживающих графический процессор, в Parallel Computing Toolbox™, Image Processing Toolbox™, Signal Processing Toolbox™ и других продуктах. Однако существует множество библиотек дополнительных функций, не имеющих прямых встроенных аналогов в поддержке графического процессора MATLAB. Примеры включают библиотеку NVIDIA Performance Primitives и библиотеку CURAND, которые включены в набор инструментальных средств CUDA, поставляемый с MATLAB. Если необходимо вызвать функцию в одной из этих библиотек, это можно сделать с помощью интерфейса GPU MEX. Этот интерфейс позволяет вам извлечь указатели на данные устройства из MATLAB gpuArrays, чтобы вы могли передать эти указатели на функции GPU. Можно преобразовать возвращенные значения в gpuArrays для возврата в MATLAB. Для получения дополнительной информации смотрите Запуск MEX-функций, содержащих код CUDA.

Наконец, у вас есть опция написания пользовательского ядра CUDA для нужной операции. Такие ядра могут быть непосредственно интегрированы в MATLAB с помощью объекта CUDAKernel.

Пример, иллюстрирующий три подхода к вычислениям графический процессор: набор Мандельброта, показывает, как реализовать простое вычисление с использованием трех подходов, упомянутых в этом разделе. Этот пример начинается с кода MATLAB, который легко конвертируется для запуска на графическом процессоре, переписывает код для использования arrayfun для поэлементных операций и, наконец, показывает, как интегрировать пользовательское ядро CUDA для той же операции.

Также можно записать ядро CUDA в составе файла MEX и вызвать его с помощью CUDA Runtime API внутри файла MEX. Любой из этих подходов может позволить вам работать с низкоуровневыми функциями GPU, такими как общая память и память текстур, которые не доступны непосредственно в коде MATLAB. Для получения дополнительной информации см. пример «Доступ к расширенным функциям CUDA с помощью MEX».

Лучшие практики для повышения эффективности

Аппаратное строение

В целом вы можете достичь лучшей эффективности, когда ваш графический процессор посвящен вычислениям. Использовать один и тот же графический процессор как для расчетов, так и для графики обычно нецелесообразно, из-за объема памяти, занятого для проблем разумного размера и постоянного использования устройства системой для графики. По возможности получите отдельное устройство для графики. Сведения о настройке устройства для вычислений или графики зависят от версии операционной системы и драйвера.

В Windows® системы, устройство графического процессора может находиться в одном из двух режимов: режиме Windows Отображения Драйвера Модели (WDDM) или Tesla Compute Кластера (TCC). Для оптимальной эффективности любые устройства, используемые для вычислений, должны находиться в режиме TCC. Для получения дополнительной информации см. документацию NVIDIA.

Высокопроизводительные вычислительные устройства NVIDIA, линия Tesla, поддерживают коды коррекции ошибок (ECC) при чтении и записи памяти графический процессор. Цель ECC состоит в том, чтобы исправить случайные битовые ошибки, которые происходят нормально при чтении или записи динамической памяти. Одним из методов повышения эффективности является отключение ECC для увеличения достижимой полосы пропускания памяти. В то время как оборудование может быть сконфигурировано таким образом, MathWorks не рекомендует эту практику. Потенциальная потеря точности из-за молчаливых ошибок может быть более вредной, чем преимущество эффективности.

Методы кодирования MATLAB

В этой теме описываются общие методы, которые помогают вам достичь лучшей эффективности на графическом процессоре. Некоторые из этих советов применяются и при записи кода MATLAB для центрального процессора.

Данные в массивах MATLAB хранятся в основном порядке. Поэтому выгодно работать вдоль первой или столбцовой размерности вашего массива. Если одна размерность ваших данных значительно длиннее других, вы можете достичь лучшей эффективности, если сделаете эту первую размерность. Точно так же, если вы часто работаете с определенной размерностью, обычно лучше всего иметь его в качестве первой размерности. В некоторых случаях, если последовательные операции нацелены на различные размерности массива, может быть выгодно транспонировать или переместить массив между этими операциями.

Графические процессоры достигают высокой эффективности путем параллельного вычисления многих результатов. Таким образом, матричные и более высокомерные операции над массивами обычно выполняют намного лучше, чем операции с векторами или скалярами. Можно достичь лучшей эффективности путем перезаписи циклов, чтобы использовать более размерные операции. Процесс пересмотра основанного на цикле скалярно-ориентированного кода для использования матрицы MATLAB и векторных операций называется векторизацией. Для получения дополнительной информации см. «Использование векторизации».

По умолчанию все операции в MATLAB выполняются в арифметике с двойной точностью и плавающей точностью. Однако большинство операций поддерживает различные типы данных, включая целое число и одну точность с плавающей точностью. Современные графические процессоры и центральные процессоры обычно имеют намного более высокую пропускную способность при выполнении операций с одной точностью, а данные с одной точностью с плавающей точкой занимают меньше памяти. Если требования точности вашего приложения позволяют использовать с одной точностью с плавающей точностью, это может значительно улучшить производительность вашего кода MATLAB.

Графический процессор находится в конце механизма передачи данных, известного как шина PCI. В то время как эта шина является эффективной, высокополосный способ передачи данных из памяти хоста ПК на различные карты расширения, он все еще намного медленнее, чем общая полоса пропускания глобальной памяти графического процессора или центрального процессора (для получения дополнительной информации см. пример «Измерение эффективности графический процессор»). В сложение, передачи с графического процессора устройства на память хоста MATLAB заставляют MATLAB ждать завершения всех ожидающих операций на устройстве перед выполнением любых других операторов. Это может существенно повлиять на эффективность вашего приложения. В целом следует ограничить количество раз, когда вы передаете данные между рабочим пространством MATLAB и графическим процессором. Если вы можете перенести данные в графический процессор один раз в начале вашего приложения, выполните все вычисления, которые вы можете на графическом процессоре, и затем перенести результаты обратно в MATLAB в конце, что, как правило, приводит к лучшей эффективности. Точно так же, когда это возможно, он помогает создавать массивы непосредственно на графическом процессоре, используя либо 'gpuArray' или 'like' опция для таких функций, как zeros (например, Z = zeros(___,'gpuArray') или Z = zeros(N,'like',g) для существующих g gpuArray).

Измерение эффективности на графическом процессоре

Лучший способ измерения эффективности на графическом процессоре - это использование gputimeit. Эта функция принимает за вход указатель на функцию без входных параметров и возвращает измеренное время выполнения этой функции. Он заботится о таких факторах бенчмаркинга, как повторение размеченной по времени операции, чтобы получить лучшее разрешение, выполнение функции перед измерением, чтобы избежать накладных расходов на инициализацию и вычитание накладных расходов функции синхронизации. Кроме того, gputimeit обеспечивает выполнение всех операций на графическом процессоре перед установлением окончательного времени.

Например, рассмотрите измерение времени, необходимого для вычисления lu факторизация случайной матрицы A размера N-by- N. Вы можете сделать это, определив функцию, которая делает lu факторизация и передача указателя на функцию в gputimeit:

A = rand(N,'gpuArray');
fh = @() lu(A);
gputimeit(fh,2); % 2nd arg indicates number of outputs

Можно также измерить эффективность с tic и toc. Однако, чтобы получить точное время на графическом процессоре, необходимо дождаться завершения операций перед вызовом toc. Есть два способа сделать это. Вы можете позвонить gather на конечном графическом процессоре перед вызовом tocЭто заставляет все расчеты завершаться до выполнения измерения времени. Кроме того, вы можете использовать wait функция со gpuDevice объект как его вход. Например, если вы хотели измерить время, необходимое для вычисления lu факторизация матричных A использование tic, toc, и wait, вы можете сделать это следующим образом:

gd = gpuDevice();
tic();
[l,u] = lu(A);
wait(gd);
tLU = toc();

Можно также использовать профилировщик MATLAB, чтобы показать, как время расчета распределяется в коде GPU. Обратите внимание, что для выполнения измерений синхронизации профилировщик запускает каждую строку кода независимо, поэтому он не может рассчитать перекрытие (асинхронное) выполнение, которое может произойти во время нормальной операции. Для синхронизации всех алгоритмов, вы должны использовать tic и toc, или gputimeit, как описано выше. Кроме того, профиль может не привести к правильным результатам для пользовательских MEX-функций, если они выполняются асинхронно.

Векторизация для повышения эффективности графический процессор

В этом примере показано, как улучшить эффективность путем запуска функции на графическом процессоре вместо центрального процессора и векторизации вычислений.

Рассмотрим функцию, которая выполняет быструю свертку столбцов матрицы. Быстрая свертка, которая является общей операцией в приложениях обработки сигналов, преобразует каждый столбец данных из временного интервала в частотный диапазон, умножает его на преобразование вектора фильтра, преобразуется назад во временной интервал и сохраняет результат в выходной матрице.

function y = fastConvolution(data,filter)
[m,n] = size(data);
% Zero-pad filter to the column length of data, and transform
filter_f = fft(filter,m);

% Create an array of zeros of the same size and class as data
y = zeros(m,n,'like',data);

% Transform each column of data
for ix = 1:n
    af = fft(data(:,ix));
    y(:,ix) = ifft(af .* filter_f);
end
end

Выполните эту функцию в центральном процессоре на данных определенного размера и измерьте время выполнения с помощью MATLAB timeit функция. The timeit функция заботится об общих факторах бенчмаркинга, таких как учет запуска и накладных расходов.

a = complex(randn(4096,100),randn(4096,100));  % Data input
b = randn(16,1);                               % Filter input
c = fastConvolution(a,b);                      % Calculate output
ctime = timeit(@()fastConvolution(a,b));       % Measure CPU time
disp(['Execution time on CPU = ',num2str(ctime)]);

На примере машины этот код отображает выход:

Execution time on CPU = 0.019335

Теперь выполните эту функцию на графическом процессоре. Вы можете сделать это легко, изменив входные данные на gpuArrays, а не на обычные массивы MATLAB. The 'like' синтаксис, используемый при создании выхода внутри функции, гарантирует, что y будет gpuArray, если data является gpuArray.

ga = gpuArray(a);                              % Move array to GPU
gb = gpuArray(b);                              % Move filter to GPU
gc = fastConvolution(ga,gb);                   % Calculate on GPU
gtime = gputimeit(@()fastConvolution(ga,gb));  % Measure GPU time
gerr = max(max(abs(gather(gc)-c)));            % Calculate error
disp(['Execution time on GPU = ',num2str(gtime)]);
disp(['Maximum absolute error = ',num2str(gerr)]);

На той же машине этот код отображает выход:

Execution time on CPU = 0.019335
Execution time on GPU = 0.027235
Maximum absolute error = 1.1374e-14

К сожалению, графический процессор медленнее, чем центральный процессор для этой проблемы. Причина в том, что for-цикл выполняет операции БПФ, умножения и обратного БПФ для отдельных столбцов длины 4096. Лучший способ увеличить эффективность - векторизация кода, чтобы один вызов функции MATLAB выполнял больше вычислений. Операции FFT и IFFT легко векторизировать: fft(A) вычисляет БПФ каждого столбца матрицы A. Можно выполнить умножение фильтра с каждым столбцом в матрице сразу с помощью бинарной функции скалярного расширения MATLAB bsxfun. Векторизованная функция выглядит следующим образом:

function y = fastConvolution_v2(data,filter)
m = size(data,1);
% Zero-pad filter to the length of data, and transform
filter_f = fft(filter,m);

% Transform each column of the input
af = fft(data);

% Multiply each column by filter and compute inverse transform
y = ifft(bsxfun(@times,af,filter_f));
end

Выполните тот же эксперимент с помощью векторизованной функции:

a = complex(randn(4096,100),randn(4096,100));   % Data input
b = randn(16,1);                                % Filter input
c = fastConvolution_v2(a,b);                    % Calculate output
ctime = timeit(@()fastConvolution_v2(a,b));     % Measure CPU time
disp(['Execution time on CPU = ',num2str(ctime)]);

ga = gpuArray(a);                               % Move data to GPU
gb = gpuArray(b);                               % Move filter to GPU
gc = fastConvolution_v2(ga, gb);                % Calculate on GPU
gtime = gputimeit(@()fastConvolution_v2(ga,gb));% Measure GPU time
gerr = max(max(abs(gather(gc)-c)));             % Calculate error
disp(['Execution time on GPU = ',num2str(gtime)]);
disp(['Maximum absolute error = ',num2str(gerr)]);
Execution time on CPU = 0.010393
Execution time on GPU = 0.0020537
Maximum absolute error = 1.1374e-14

В заключение векторизация кода помогает и центральному процессору, и графическому процессору версиям запускаться быстрее. Однако векторизация помогает графическому процессору гораздо больше, чем центральный процессор. Улучшенная версия центральный процессор почти в два раза быстрее оригинала; улучшенная версия графический процессор в 13 раз быстрее оригинала. Графический процессор пошел от 40% медленнее, чем центральный процессор в исходной версии, до примерно в пять раз быстрее в пересмотренной версии.

Поиск и устранение проблем с графическими процессорами

Если у вас в машине только один графический процессор, то вполне вероятно, что ваша видеокарта также выступает в качестве вашей карты отображения. В этом случае ваш графический процессор, вероятно, подвержен тайм-ауту, установленному операционной системой (ОС). Вы можете изучить это для вашего графический процессор следующим образом:

gpuDevice
ans =
...
KernelExecutionTimeout: 1
Если KernelExecutionTimeout = 1, тогда ваш графический процессор подвержен тайм-ауту, установленному ОС, гарантируя, что ОС всегда способна печатать обновления на экране. Если вычисление графического процессора занимает слишком много времени, то операция погибает. В этом случае для успешного возобновления вычислений графического процессора необходимо перезапустить MATLAB.

См. также

Похожие темы