exponenta event banner

Ускорение моделирования системы от конца к концу с помощью графических процессоров

В этом примере показано сравнение четырех методов, которые можно использовать для ускорения моделирования частоты битовых ошибок (BER) с использованием системных объектов в программном обеспечении MATLAB ® Communications Toolbox™. Небольшая система, основанная на сверточном кодировании, иллюстрирует эффект генерации кода с использованием продукта MATLAB ® Coder™, параллельное выполнение цикла с использованиемparfor в продукте Parallel Computing Toolbox™ сочетание генерации кода и parforи системные объекты на основе графического процессора.

Системные объекты этого примера доступны в продукте Communications Toolbox. Для выполнения этого примера необходимо иметь лицензию MATLAB Coder, лицензию Parallel Computing Toolbox и достаточный графический процессор.

Параметры проектирования и моделирования системы

В этом примере используется простая система сверточного кодирования для иллюстрации стратегий ускорения моделирования. Система генерирует биты случайных сообщений с помощью randi. Передатчик кодирует эти биты с использованием сверточного кодера скорости 1/2, применяет схему модуляции QPSK и затем передает символы. Символы проходят через канал AWGN, где происходит повреждение сигнала. Демодуляция QPSK происходит в приемнике, и поврежденные биты декодируются с использованием алгоритма Витерби. Наконец, вычисляется частота битовых ошибок. В этой системе используются следующие системные объекты:

  • коммуникация. ConvolutionalEncoder - сверточное кодирование

  • comm.PSKModulator - модуляция QPSK

  • comm.AWGNChannel - канал AWGN

  • comm.PSKDemodulator - демодуляция QPSK (приблизительно LLR)

  • comm.ViterbiDecoder - декодирование Витерби

Код приемопередатчиков можно найти в:

Каждая точка вдоль кривой частоты битовых ошибок представляет результат многих итераций кода приемопередатчика, описанного выше. Для получения точных результатов за разумное время моделирование соберет по меньшей мере 200 битовых ошибок на значение отношения сигнал/шум (SNR) и не более 5000 пакетов данных. Пакет представляет 2000 битов сообщения. SNR находится в диапазоне от 1 дБ до 5 дБ.

iterCntThreshold = 5000;
minErrThreshold = 200;
msgL = 2000;
snrdb = 1:5;

Инициализация

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

errs  = zeros(length(snrdb),1);
iters = zeros(length(snrdb),1);

berplot = cell(1,5);
numframes = 500;    %GPU version runs 500 frames in parallel.

viterbiTransceiverCPU(-10,1,1);
viterbiTransceiverGPU(-10,1,1,numframes);

N=1; %N tracks which simulation variant is run

Технологический процесс

Поток операций для этого примера:

  1. Выполнение моделирования базовой линии системных объектов

  2. Использование кодера MATLAB для создания функции MEX для моделирования

  3. Используйте parfor для параллельного выполнения моделирования частоты битовых ошибок

  4. Объединение созданной функции MEX с parfor

  5. Использование системных объектов на основе GPU

fprintf(1,'Bit Error Rate Acceleration Analysis Example\n\n');

Моделирование базовой линии

Чтобы установить опорную точку для различных стратегий ускорения, кривая частоты битовых ошибок генерируется только с использованием системных объектов. Код приемопередатчика находится в viterbiTransceiverCPU.m.

fprintf(1,'***Baseline - Standard System object simulation***\n');

% create random stream for each snrdb simulation
s = RandStream.create('mrg32k3a','NumStreams',1,...
    'CellOutput',true,'NormalTransform', 'Inversion');
RandStream.setGlobalStream(s{1});

ts = tic;
for ii=1:numel(snrdb)
    fprintf(1,'Iteration number %d, SNR (dB) = %d\n',ii, snrdb(ii));
    [errs(ii),iters(ii)] =viterbiTransceiverCPU(snrdb(ii), minErrThreshold, iterCntThreshold);
end
ber = errs./ (msgL* iters);
baseTime=toc(ts);
berplot{N} = ber;
desc{N} = 'baseline';
reportResultsCommSysGPU(N, baseTime,baseTime, 'Baseline');

Создание кода

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

Для выполнения этой части примера необходимо иметь лицензию MATLAB Coder.

fprintf(1,'\n***Baseline + codegen***\n');
N=N+1; %Increase simulation counter

% Create the coder object and turn off checks which will cause low
% performance.
fprintf(1,'Generating Code ...');
config_obj = coder.config('MEX');
config_obj.EnableDebugging = false;
config_obj.IntegrityChecks = false;
config_obj.ResponsivenessChecks = false;
config_obj.EchoExpressions = false;

% Generate a MEX file
codegen('viterbiTransceiverCPU.m', '-config', 'config_obj', '-args', {snrdb(1), minErrThreshold, iterCntThreshold} )
fprintf(1,'  Done.\n');

%Run once to eliminate startup overhead.
viterbiTransceiverCPU_mex(-10,1,1);

s = RandStream.getGlobalStream;
reset(s);

% Use the generated MEX function viterbiTransceiverCPU_mex in the
% simulation loop.
ts = tic;
for ii=1:numel(snrdb)
    fprintf(1,'Iteration number %d, SNR (dB) = %d\n',ii, snrdb(ii));
    [errs(ii),iters(ii)] = viterbiTransceiverCPU_mex(snrdb(ii), minErrThreshold, iterCntThreshold);
end
ber = errs./ (msgL* iters);
trialtime=toc(ts);
berplot{N} = ber;
desc{N} = 'codegen';
reportResultsCommSysGPU(N, trialtime,baseTime, 'Baseline + codegen');

Parfor - выполнение параллельного цикла

Используя parforMATLAB выполняет код приемопередатчика для всех значений SNR параллельно. Для этого необходимо открыть параллельный пул и добавить parfor цикл.

Для выполнения этой части примера необходимо иметь лицензию Parallel Computing Toolbox.

fprintf(1,'\n***Baseline + parfor***\n');
fprintf(1,'Accessing multiple CPU cores ...\n');
if isempty(gcp('nocreate'))
    pool = parpool;
    poolWasOpen = false;
else
    pool = gcp;
    poolWasOpen = true;
end
nW=pool.NumWorkers;
N=N+1; %Increase simulation counter

snrN = numel(snrdb);

mT = minErrThreshold / nW;
iT = iterCntThreshold / nW;

errN =  zeros(nW, snrN);
itrN =  zeros(nW, snrN);

% replicate snrdb
snrdb_rep=repmat(snrdb,nW,1);

% create an independent stream for each worker
s = RandStream.create('mrg32k3a','NumStreams',nW,...
    'CellOutput',true,'NormalTransform', 'Inversion');

% pre-run
parfor jj=1:nW
    RandStream.setGlobalStream(s{jj});
    viterbiTransceiverCPU(-10, 1, 1);
end

fprintf(1,'Start parfor job ... ');
ts = tic;
parfor jj=1:nW
    for ii=1:snrN
        [err, itr] = viterbiTransceiverCPU(snrdb_rep(jj,ii), mT, iT);
        errN(jj,ii) = err;
        itrN(jj,ii) = itr;
    end
end
ber = sum(errN)./ (msgL*sum(itrN));
trialtime=toc(ts);
fprintf(1,'Done.\n');
berplot{N} = ber;
desc{N} = 'parfor';
reportResultsCommSysGPU(N, trialtime,baseTime, 'Baseline + parfor');

Parfor и создание кода

Можно объединить последние два метода дополнительного ускорения. Скомпилированная функция MEX может выполняться внутри parfor цикл.

Для выполнения этой части примера необходимо иметь лицензию MATLAB Coder и лицензию Parallel Computing Toolbox.

fprintf(1,'\n***Baseline + codegen + parfor***\n');
N=N+1; %Increase simulation counter

% pre-run
parfor jj=1:nW
    RandStream.setGlobalStream(s{jj});
    viterbiTransceiverCPU_mex(1, 1, 1); % use the same mex file
end

fprintf(1,'Start parfor job ... ');
ts = tic;
parfor jj=1:nW
    for ii=1:snrN
        [err, itr] = viterbiTransceiverCPU_mex(snrdb_rep(jj,ii), mT, iT);
        errN(jj,ii) = err;
        itrN(jj,ii) = itr;
    end
end
ber = sum(errN)./ (msgL*sum(itrN));
trialtime=toc(ts);
fprintf(1,'Done.\n');
berplot{N} = ber;
desc{N} = 'codegen + parfor';
reportResultsCommSysGPU(N, trialtime,baseTime, 'Baseline + codegen + parfor');

GPU

Системные объекты, которые viterbiTransceiverCPU использование функций доступно для выполнения на GPU. Версии на основе GPU:

  • comm.gpu. ConvolutionalEncoder - сверточное кодирование

  • comm.gpu.PSKModulator - модуляция QPSK

  • comm.gpu.AWGNChannel - канал AWGN

  • comm.gpu.PSKDemodulator - демодуляция QPSK (приблизительно LLR)

  • comm.gpu.ViterbiDecoder - декодирование Витерби

Графический процессор наиболее эффективен при одновременной обработке больших объемов данных. Системные объекты на основе GPU могут обрабатывать несколько кадров за один вызов пошагового метода. numframes переменная представляет количество кадров, обработанных за один вызов. Это аналогично parfor за исключением того, что параллелизм основан на каждом объекте, а не на viterbiTransceiverCPU основа вызова.

Для выполнения этой части примера необходимо иметь лицензию Parallel Computing Toolbox и графический процессор с поддержкой CUDA ® 1.3.

fprintf(1,'\n***GPU***\n');
N=N+1; %Increase simulation counter

try
    dev = parallel.gpu.GPUDevice.current;
    fprintf(...
        'GPU detected (%s, %d multiprocessors, Compute Capability %s)\n',...
        dev.Name, dev.MultiprocessorCount, dev.ComputeCapability);

    sg = parallel.gpu.RandStream.create('mrg32k3a','NumStreams',1,'NormalTransform','Inversion');
    parallel.gpu.RandStream.setGlobalStream(sg);

    ts = tic;
    for ii=1:numel(snrdb)
        fprintf(1,'Iteration number %d, SNR (dB) = %d\n',ii, snrdb(ii));
        [errs(ii),iters(ii)] =viterbiTransceiverGPU(snrdb(ii), minErrThreshold, iterCntThreshold, numframes);
    end
    ber = errs./ (msgL* iters);
    trialtime=toc(ts);
    berplot{N} = ber;
    desc{N} = 'GPU';
    reportResultsCommSysGPU(N, trialtime,baseTime, 'Baseline + GPU');

    fprintf(1,'  Done.\n');

catch %#ok<CTCH>

    % Report that the appropriate GPU was not found.
    fprintf(1, ['Could not find an appropriate GPU or could not ', ...
        'execute GPU code.\n']);

end

Анализ

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

lines = {'kx-.', 'ro-', 'cs--', 'm^:', 'g*-'};
for ii=1:numel(desc)
    semilogy(snrdb, berplot{ii}, lines{ii});
    hold on;
end
hold off;
title('Bit Error Rate for Various Acceleration Strategies');
xlabel('Signal to Noise Ratio (dB)');
ylabel('BER');
legend(desc{:});

Очистка

Оставьте параллельный пул в исходном состоянии.

if ~poolWasOpen
    delete(gcp);
end