Измерьте и улучшайте производительность графического процессора

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

Можно использовать различные оценочные испытания в MATLAB®, чтобы измерить уровень графического процессора:

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

  • Используйте paralleldemo_gpu_bench скрипт в Измерении Уровня графического процессора, чтобы получить информацию о вашей скорости шины PCI, чтении-записи памяти графического процессора и пиковой эффективности вычисления для матричных вычислений двойной точности.

Улучшайте производительность Используя вычисления одинарной точности

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

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

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

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

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

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

  • Разделите установленное значение гигафлопс одинарной точности на значение гигафлопс двойной точности.

Примечание

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

Основной рабочий процесс для того, чтобы улучшать производительность

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

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

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

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

Усовершенствованные инструменты для того, чтобы улучшать производительность

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

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

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

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

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

Альтернативно, можно записать ядро CUDA как часть файла MEX и вызвать ее с помощью API Во время выполнения CUDA в файле MEX. Любой из этих подходов может позволить вам работать с низкоуровневыми функциями графического процессора, такими как общая память и текстурировать память, которые не непосредственно доступны в коде MATLAB. Для получения дополнительной информации смотрите, что пример Получает доступ к Усовершенствованным Функциям CUDA Используя MEX.

Лучшые практики для того, чтобы улучшать производительность

Аппаратная конфигурация

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Можно также использовать профилировщика MATLAB, чтобы показать, как время вычисления распределяется в коде графического процессора. Обратите внимание на то, что, чтобы выполнить измерения синхронизации, профилировщик запускает каждую строку кода независимо, таким образом, она не может составлять наложение (асинхронного) выполнения того, которое может произойти во время нормального функционирования. Для синхронизации целых алгоритмов необходимо использовать 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 функция. 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. '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- цикл выполняет БПФ, умножение и обратные операции FFT на отдельных столбцах длины 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% медленнее, чем центральный процессор в исходной версии, приблизительно к в пять раз быстрее в исправленной версии.

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

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

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

Смотрите также

Похожие темы