主要内容

GPU を使用したエンドツーエンド システム シミュレーションの高速化

この例では、MATLAB® Communications Toolbox™ ソフトウェアの System object を使用して、ビット誤り率 (BER) シミュレーションを高速化するために使用できる 4 つの手法の比較を説明します。畳み込み符号化に基づき、小規模なシステムによる MATLAB® Coder™ 製品を使用したコード生成の効果、Parallel Computing Toolbox™ 製品のparforを使用した並列ループ実行、コード生成とparforの组み合わせ,gpuベースの系统对象をを示し。。。。。

この例で取り上げる System object は、Communications Toolbox 製品で利用できます。この例を実行するには、MATLAB Coder のライセンス、Parallel Computing Toolbox のライセンスおよび十分な性能の GPU が必要です。

システム設計とシミュレーション パラメーター

この例では、単純な畳み込み符号化システムを使用してシミュレーションを高速化する方法を示します。システムでは、randiを使用してランダム メッセージ ビットが生成されます。送信機はレート 1/2 畳み込み符号化器を使用してこれらのビットを符号化し、QPSK 変調器スキームを適用してから、シンボルを送信します。シンボルは、信号の破損が発生する AWGN チャネルを通過します。受信機で QPSK 復調が行われ、破損したビットはビタビ アルゴリズムによって復号化されます。最後に、ビット誤り率が計算されます。このシステムで使用する System object は、以下のとおりです。

  • comm.convolutionalencoder -畳み込み畳み込み化

  • comm.PSKModulator - QPSK 変調

  • comm.awgnchannel- awgnチャネル

  • comm.pskdemudulator -qpsk复调(大约llr)

  • comm.viterbidecoder-ビタビビタビ

トランシーバーのコードは以下にあります。

ビット誤り率曲線に沿った各点が、上記の送受信コードの多数の反復による結果を表します。適度な時間で正確な結果を得るために、シミュレーションは S/N 比 (SNR) ごとに 200 個以上のビット誤りと、多くても 5000 までのデータ パケットを収集します。パケットは 2000 メッセージ ビットを表します。SNR の範囲は、1 dB から 5 dB です。

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

初期化

関数 transceiver を 1 回呼び出し、設定時間とオブジェクト作成オーバーヘッドを抽出します。オブジェクトは各関数の永続変数に保存されます。

errs = zeros(长度(SNRDB),1);iTers = zeros(长度(SNRDB),1);berplot =细胞(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. System object のベースライン シミュレーションを実行

  2. MATLAB Coder を使用して、シミュレーション用の MEX 関数を生成

  3. parfor を使用して、ビット誤り率シミュレーションを並列実行

  4. 生成された MEX 関数を parfor と組み合わせ

  5. GPU ベースの System object を使用

fprintf(1,'Bit Error Rate Acceleration Analysis Example\n\n');
位错误率加速分析示例

ベースラインのシミュレーション

さまざまな高速化方法の基準点を確定するために、System object のみを使用してビット誤り率を生成します。このコンポーネントのコードはviterbitransceivercpu.mに含まています。

fprintf(1,'***Baseline - Standard System object simulation***\n');% create random stream for each snrdb simulations = randstream.create('mrg32k3a','numstreams',1,...'CellOutput',true,'NormalTransform','Inversion');RandStream.setGlobalStream(s{1}); ts = tic;forii=1:numel(snrdb) fprintf(1,'Iteration number %d, SNR (dB) = %d\n',ii,snrdb(ii));[errs(ii),iters(ii)] =viterbiTransceiverCPU(snrdb(ii), minErrThreshold, iterCntThreshold);endber = errs./ (msgL* iters); baseTime=toc(ts); berplot{N} = ber; desc{N} =“基线”;reportResultsCommSysGPU(N, baseTime,baseTime,'Baseline');
***Baseline - Standard System object simulation*** Iteration number 1, SNR (dB) = 1 Iteration number 2, SNR (dB) = 2 Iteration number 3, SNR (dB) = 3 Iteration number 4, SNR (dB) = 4 Iteration number 5, SNR (dB) = 5 ---------------------------------------------------------------------------------------------- Versions of the Transceiver | Elapsed Time (sec)| Acceleration Ratio 1. Baseline | 17.0205 | 1.0000 ----------------------------------------------------------------------------------------------

コード生成

MATLAB Coder を使用して、あらかじめコンパイルされた MATLAB コードと一致する最適化された C コードと MEX ファイルを生成できます。関数viterbiTransceiverCPUは MATLAB コード生成サブセットに適合するため、修正せずに MEX 関数にコンパイルできます。

例のこの部分を実行するには、MATLAB Coder ライセンスが必要です。

fprintf(1,'\n***Baseline + codegen***\n');N = N + 1;%增加模拟计数器%创建编码器对象并关闭将导致低的支票% 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 filecodegen('viterbiTransceiverCPU.m','-config','config_obj','-args', {snrdb(1), minErrThreshold, iterCntThreshold} ) fprintf(1,' Done.\n');%运行一次以消除启动开销。viterbiTransceiverCPU_mex(-10,1,1); s = RandStream.getGlobalStream; reset(s);% Use the generated MEX function viterbiTransceiverCPU_mex in the% simulation loop.ts = tic;forii=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);endber = errs./ (msgL* iters); trialtime=toc(ts); berplot{N} = ber; desc{N} ='codgen';ReportresultScommsysgpu(n,审判时间,马萨诸时期,'Baseline + codegen');
***Baseline + codegen*** Generating Code ...Code generation successful. Done. Iteration number 1, SNR (dB) = 1 Iteration number 2, SNR (dB) = 2 Iteration number 3, SNR (dB) = 3 Iteration number 4, SNR (dB) = 4 Iteration number 5, SNR (dB) = 5 ---------------------------------------------------------------------------------------------- Versions of the Transceiver | Elapsed Time (sec)| Acceleration Ratio 1. Baseline | 17.0205 | 1.0000 2. Baseline + codegen | 14.3820 | 1.1835 ----------------------------------------------------------------------------------------------

Parfor - パラレル ループ実行

matlabはparforを使用して、すべての SNR 値に対して送受信コードを並列実行します。これには、並列プールを開き、parforループを追加する必要があります。

例のこの部分を実行するには、Parallel Computing Toolbox のライセンスが必要です。

fprintf(1,'\n***Baseline + parfor***\n');fprintf(1,'Accessing multiple CPU cores ...\n');ifisempty(gcp('nocreate')) pool = parpool; poolWasOpen = false;elsepool = GCP;pool -Wasopen = true;end西北= pool.NumWorkers;N = N + 1;%增加模拟计数器snrN =元素个数(snrdb);太= minErrThreshold / nW; iT = iterCntThreshold / nW; errN = zeros(nW, snrN); itrN = zeros(nW, snrN);%复制SNRDBsnrdb_rep=repmat(snrdb,nW,1);%为每个工人创建一个独立的流s = randstream.create('mrg32k3a','numstreams',NW,...'CellOutput',true,'NormalTransform','Inversion');% pre-runparforJJ = 1:NWRandStream.setGlobalStream(s{jj}); viterbiTransceiverCPU(-10, 1, 1);endfprintf(1,'Start parfor job ... ');ts = tic;parforJJ = 1:NWforii=1:snrN [err, itr] = viterbiTransceiverCPU(snrdb_rep(jj,ii), mT, iT); errN(jj,ii) = err; itrN(jj,ii) = itr;endendber = sum(errN)./ (msgL*sum(itrN)); trialtime=toc(ts); fprintf(1,'Done.\n');berplot{N} = ber; desc{N} ='parfor';ReportresultScommsysgpu(n,审判时间,马萨诸时期,'Baseline + parfor');
***基线 + parfor ***访问多个CPU内核...使用“本地”配置文件开始并行池(PARPOOL)...连接到并行池(工人数:8)。开始工作...完成。--------------------------------------------------------------------------------------------------------------------------------------------------------------------- |经过的时间(SEC)|加速度比率1.基线|17.0205 |1.0000 2.基线 +代码|14.3820 |1.1835 3.基线 + PARFOR | 2.6984 | 6.3075 ----------------------------------------------------------------------------------------------

Parfor とコード生成

最後の 2 つの方法を組み合わせることで、さらに高速化することができます。コンパイルされた MEX 関数は、parforループ内部で実行できます。

例のこの部分を実行するには、MATLAB Coder のライセンスと Parallel Computing Toolbox のライセンスが必要です。

fprintf(1,'\ n ***基线 + codegen + parfor *** \ n');N = N + 1;%增加模拟计数器% pre-runparforJJ = 1:NWRandStream.setGlobalStream(s{jj}); viterbiTransceiverCPU_mex(1, 1, 1);% use the same mex fileendfprintf(1,'Start parfor job ... ');ts = tic;parforJJ = 1:NWforii=1:snrN [err, itr] = viterbiTransceiverCPU_mex(snrdb_rep(jj,ii), mT, iT); errN(jj,ii) = err; itrN(jj,ii) = itr;endendber = sum(errN)./ (msgL*sum(itrN)); trialtime=toc(ts); fprintf(1,'Done.\n');berplot{N} = ber; desc{N} ='codegen + parfor';ReportresultScommsysgpu(n,审判时间,马萨诸时期,“基线 +代码 + parfor”);
***Baseline + codegen + parfor*** Start parfor job ... Done. ---------------------------------------------------------------------------------------------- Versions of the Transceiver | Elapsed Time (sec)| Acceleration Ratio 1. Baseline | 17.0205 | 1.0000 2. Baseline + codegen | 14.3820 | 1.1835 3. Baseline + parfor | 2.6984 | 6.3075 4. Baseline + codegen + parfor | 2.7059 | 6.2902 ----------------------------------------------------------------------------------------------

GPU

関数viterbiTransceiverCPUが使用する System object は GPU での実行時に利用できます。GPU ベース バージョン:

  • comm.gpu.ConvolutionalEncoder - 畳み込み符号化

  • comm.gpu.PSKModulator - QPSK 変調

  • comm.gpu.AWGNChannel - AWGN チャネル

  • comm.gpu.pskdemudulator -qpsk复调(llr)

  • comm.gpu.ViterbiDecoder - ビタビ復号化

大量データ一括には,,,,がが最も效果ですですですです。。。。ベースベースベースベースベースベースベースベースののののののののののののののののののののののののはははははははnumframesは呼び出しごとに処理されるフレーム数を表します。並列処理がviterbiTransceiverCPUの呼び出し単位ではなく、オブジェクト単位であるという点を除き、これはparforに類似しています。

例のこの部分を実行するには、Parallel Computing Toolbox のライセンスと CUDA® 1.3 対応 GPU が必要です。

fprintf(1,'\n***GPU***\n');N = N + 1;%增加模拟计数器尝试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;forii=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);endber = errs./ (msgL* iters); trialtime=toc(ts); berplot{N} = ber; desc{N} ='GPU';ReportresultScommsysgpu(n,审判时间,马萨诸时期,“基线 + GPU”);fprintf(1,' Done.\n');catch%#ok% Report that the appropriate GPU was not found.fprintf(1,[“找不到合适的GPU或找不到”,...'执行GPU代码。\ n']);end
***GPU*** GPU detected (Tesla V100-PCIE-32GB, 80 multiprocessors, Compute Capability 7.0) Iteration number 1, SNR (dB) = 1 Iteration number 2, SNR (dB) = 2 Iteration number 3, SNR (dB) = 3 Iteration number 4, SNR (dB) = 4 Iteration number 5, SNR (dB) = 5 ---------------------------------------------------------------------------------------------- Versions of the Transceiver | Elapsed Time (sec)| Acceleration Ratio 1. Baseline | 17.0205 | 1.0000 2. Baseline + codegen | 14.3820 | 1.1835 3. Baseline + parfor | 2.6984 | 6.3075 4. Baseline + codegen + parfor | 2.7059 | 6.2902 5. Baseline + GPU | 0.1895 | 89.8137 ---------------------------------------------------------------------------------------------- Done.

解析

これらの試行結果を比較すると、すべてのシミュレーション高速化方法の中で GPU が圧倒的に速いことが明らかです。このパフォーマンス向上を実現するには、シミュレーション コードをごくわずかに変更するだけです。それにもかかわらず、以下のプロットが示すように、ビット誤り率性能は失われません。曲線における微小な差異は、異なる乱数生成アルゴリズムや、曲線上の同じ点における異なるデータの品質を平均化したことの影響です。

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

クリーンアップ

並列プールを元の状態にします。

if〜Pool -Wasopen Delete(GCP);end
Parallel pool using the 'local' profile is shutting down.