Этот пример использует Parallel Computing Toolbox, чтобы ускорить простую, симуляцию частоты ошибок по битам (BER) QPSK. Система состоит из модулятора QPSK, демодулятора QPSK, канала AWGN и небольшого счетчика коэффициента ошибок. В этом примере используются четыре параллельных процессора.
Установите параметры симуляции.
EbNoVec = 5:8; % Eb/No values in dB totalErrors = 200; % Number of bit errors needed for each Eb/No value totalBits = 1e7; % Total number of bits transmitted for each Eb/No value
Выделите память массивам, используемым, чтобы хранить данные, сгенерированные функцией, helper_qpsk_sim_with_awgn
.
[numErrors, numBits] = deal(zeros(length(EbNoVec),1));
Запустите симуляцию и определите время выполнения. Только один процессор будет использоваться, чтобы определить базовую производительность. Соответственно, заметьте, что нормальный цикл for используется.
tic for idx = 1:length(EbNoVec) errorStats = helper_qpsk_sim_with_awgn(EbNoVec, idx, ... totalErrors, totalBits); numErrors(idx) = errorStats(idx,2); numBits(idx) = errorStats(idx,3); end simBaselineTime = toc;
Вычислите BER.
ber1 = numErrors ./ numBits;
Повторно выполните симуляцию для случая, в котором Parallel Computing Toolbox доступен. Создайте пул рабочих.
pool = gcp;
Starting parallel pool (parpool) using the 'local' profile ... Connected to the parallel pool (number of workers: 6).
Определите количество доступных рабочих от NumWorkers
свойство pool
. Симуляция запускает область значений значений по каждому рабочему вместо того, чтобы присвоить одну точку каждому рабочему, когда бывший метод обеспечивает самое большое повышение производительности.
numWorkers = pool.NumWorkers;
Определите длину EbNoVec
для использования во вложенном parfor
цикл. Для соответствующей переменной классификации область значений цикла for вкладывается в parfor
должен быть задан постоянными числами или переменными.
lenEbNoVec = length(EbNoVec);
Выделите память массивам, используемым, чтобы хранить данные, сгенерированные функцией, helper_qpsk_sim_with_awgn
.
[numErrors, numBits] = deal(zeros(length(EbNoVec),numWorkers));
Запустите симуляцию и определите время выполнения.
tic parfor n = 1:numWorkers for idx = 1:lenEbNoVec errorStats = helper_qpsk_sim_with_awgn(EbNoVec, idx, ... totalErrors/numWorkers, totalBits/numWorkers); numErrors(idx,n) = errorStats(idx,2); numBits(idx,n) = errorStats(idx,3); end end simParallelTime = toc;
Вычислите BER. В этом случае результаты нескольких процессоров должны быть объединены, чтобы сгенерировать совокупный BER.
ber2 = sum(numErrors,2) ./ sum(numBits,2);
Сравните значения BER, чтобы проверить, что те же результаты получены независимые от количества рабочих.
semilogy(EbNoVec',ber1,'-*',EbNoVec',ber2,'-^') legend('Single Processor','Multiple Processors','location','best') xlabel('Eb/No (dB)') ylabel('BER') grid
Вы видите, что кривые BER являются по существу тем же самым с любым отклонением, являющимся из-за отличающихся seed случайных чисел.
Сравните времена выполнения для каждого метода.
fprintf(['\nSimulation time = %4.1f sec for one worker\n', ... 'Simulation time = %4.1f sec for multiple workers\n'], ... simBaselineTime, simParallelTime)
Simulation time = 67.2 sec for one worker Simulation time = 17.9 sec for multiple workers
В этом случае, где четыре ядра процессора использовались, фактор улучшения скорости был приблизительно четырьмя.