From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 6736AA057C; Fri, 27 Mar 2020 12:47:16 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 48D341C1B4; Fri, 27 Mar 2020 12:47:16 +0100 (CET) Received: from mail-wm1-f67.google.com (mail-wm1-f67.google.com [209.85.128.67]) by dpdk.org (Postfix) with ESMTP id 2EB9C1C1A4 for ; Fri, 27 Mar 2020 12:47:14 +0100 (CET) Received: by mail-wm1-f67.google.com with SMTP id b12so11096659wmj.3 for ; Fri, 27 Mar 2020 04:47:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=accelercomm-com.20150623.gappssmtp.com; s=20150623; h=subject:to:references:from:message-id:date:user-agent:mime-version :in-reply-to:content-transfer-encoding:content-language; bh=aO2ICZknEnq4aRV8cHiiR9keu/RTPJ/iWJ4z+08CNE8=; b=t1MEhofyu9pxETlDQabN8U/kX8/sodN9okAKtPLfiWBzIZa4GSgjG2QuE4tr1zV5Qw owsrg1vSGB3p5NidwFONXtmyygCN68YDKKg6nsksUrZwprOt+wnPrBMdcTutC43/VYny ptM2pI5x3YCHzbbskzaW1CxESaFNFMRFpUahkaMVbnV1RcprJDyCzxTWQV9M2YyNpm/C uPcK/NQDmhB/BmwtoKN3TnIoHMtMbR6dJThhSUmEK55oOZXlcMGWvHRqzDsR16qo2ejU CqxRM1d8xMciywb/JF9S6uJFfKo0IxRrh5FxPyKo3DUxd0TYypIPN/e6t3/BShmKbZrM SRww== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-transfer-encoding :content-language; bh=aO2ICZknEnq4aRV8cHiiR9keu/RTPJ/iWJ4z+08CNE8=; b=OSo344IX34EEoJNU5fApIF1oWLXtPNUgYYJB8RqG0ekvtWc3KwOq7SYJOx10z6UQYd Hh+O7HzAtfPr6ym3Cx5FN/vUJX6gvQUocxSg6IMRZGpNmAH58p6VGFckhC+DjB/5/Nsn ++O1yAJyUbWJmatLJHO2qbdNaZJEcoL3qEraNi3cCp2wrFMrip2jR5oRls3KT9RefFbT gbSEV7zIeIfs2DovBQ40ASn5WGKjxUgIPRoyFwCcJkWbM9reYE4V1juRtOX58EXD7EfC 07K4FO1zX9PEmfyk9/1ww+8b521//4hdm52r+zsdZ1k49SU5/kF2WAZhx9P4sjJJ8HQ6 nwkw== X-Gm-Message-State: ANhLgQ3DadX7M02JtEV7/J8Aq1cOOe1LlW6C+1Zh+tgbT3x1ZKckBfn7 xxpww8iLCu5hMzUSo+3IbWXEqN8qitk= X-Google-Smtp-Source: ADFU+vtM3AbzTEsTL61HsVWMpxHnZHNp0p3S7VxxVPdyrs6tiOWHcWW1ttgXFIkh4pzD9Wjvqwetpg== X-Received: by 2002:a1c:1fc9:: with SMTP id f192mr5179457wmf.4.1585309633292; Fri, 27 Mar 2020 04:47:13 -0700 (PDT) Received: from ?IPv6:2a00:23c4:cf2d:a200:6023:b810:2491:c6a9? ([2a00:23c4:cf2d:a200:6023:b810:2491:c6a9]) by smtp.gmail.com with ESMTPSA id u8sm7671731wrn.69.2020.03.27.04.47.12 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 27 Mar 2020 04:47:12 -0700 (PDT) To: dev@dpdk.org References: <1582778348-113547-15-git-send-email-nicolas.chautru@intel.com> <1585193268-74468-1-git-send-email-nicolas.chautru@intel.com> <1585193268-74468-8-git-send-email-nicolas.chautru@intel.com> From: Dave Burley Message-ID: <4680e1e8-957b-8983-7110-af676b692568@accelercomm.com> Date: Fri, 27 Mar 2020 11:47:12 +0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.5.0 MIME-Version: 1.0 In-Reply-To: <1585193268-74468-8-git-send-email-nicolas.chautru@intel.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-Language: en-US Subject: Re: [dpdk-dev] [PATCH v5 07/10] test-bbdev: support for performance tests X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Acked-by: Dave Burley On 26/03/2020 03:27, Nicolas Chautru wrote: > From: Nic Chautru > > Includes support for BLER (Block Error Rate) wireless > performance test with new arguments for SNR and number > of iterations for 5G. This generates LLRs for a given > SNR level then measures the ratio of code blocks being > successfully decoded or not. > > Signed-off-by: Nic Chautru > --- > app/test-bbdev/main.c | 29 +- > app/test-bbdev/main.h | 9 +- > app/test-bbdev/test_bbdev_perf.c | 620 ++++++++++++++++++++++++++++++++++++++- > doc/guides/tools/testbbdev.rst | 16 + > 4 files changed, 662 insertions(+), 12 deletions(-) > > diff --git a/app/test-bbdev/main.c b/app/test-bbdev/main.c > index 8a42115..ff65173 100644 > --- a/app/test-bbdev/main.c > +++ b/app/test-bbdev/main.c > @@ -29,6 +29,8 @@ > unsigned int num_ops; > unsigned int burst_sz; > unsigned int num_lcores; > + double snr; > + unsigned int iter_max; > char test_vector_filename[PATH_MAX]; > bool init_device; > } test_params; > @@ -140,6 +142,18 @@ > return test_params.num_lcores; > } > > +double > +get_snr(void) > +{ > + return test_params.snr; > +} > + > +unsigned int > +get_iter_max(void) > +{ > + return test_params.iter_max; > +} > + > bool > get_init_device(void) > { > @@ -180,12 +194,15 @@ > { "test-cases", 1, 0, 'c' }, > { "test-vector", 1, 0, 'v' }, > { "lcores", 1, 0, 'l' }, > + { "snr", 1, 0, 's' }, > + { "iter_max", 6, 0, 't' }, > { "init-device", 0, 0, 'i'}, > { "help", 0, 0, 'h' }, > { NULL, 0, 0, 0 } > }; > + tp->iter_max = DEFAULT_ITER; > > - while ((opt = getopt_long(argc, argv, "hin:b:c:v:l:", lgopts, > + while ((opt = getopt_long(argc, argv, "hin:b:c:v:l:s:t:", lgopts, > &option_index)) != EOF) > switch (opt) { > case 'n': > @@ -237,6 +254,16 @@ > sizeof(tp->test_vector_filename), > "%s", optarg); > break; > + case 's': > + TEST_ASSERT(strlen(optarg) > 0, > + "SNR is not provided"); > + tp->snr = strtod(optarg, NULL); > + break; > + case 't': > + TEST_ASSERT(strlen(optarg) > 0, > + "Iter_max is not provided"); > + tp->iter_max = strtol(optarg, NULL, 10); > + break; > case 'l': > TEST_ASSERT(strlen(optarg) > 0, > "Num of lcores is not provided"); > diff --git a/app/test-bbdev/main.h b/app/test-bbdev/main.h > index 23b4d58..fb3dec8 100644 > --- a/app/test-bbdev/main.h > +++ b/app/test-bbdev/main.h > @@ -19,6 +19,8 @@ > #define MAX_BURST 512U > #define DEFAULT_BURST 32U > #define DEFAULT_OPS 64U > +#define DEFAULT_ITER 6U > + > > > #define TEST_ASSERT(cond, msg, ...) do { \ > @@ -104,8 +106,7 @@ struct test_command { > .command = RTE_STR(name), \ > .callback = test_func_##name, \ > }; \ > - static void __attribute__((constructor, used)) \ > - test_register_##name(void) \ > + RTE_INIT(test_register_##name) \ > { \ > add_test_command(&test_struct_##name); \ > } > @@ -118,6 +119,10 @@ struct test_command { > > unsigned int get_num_lcores(void); > > +double get_snr(void); > + > +unsigned int get_iter_max(void); > + > bool get_init_device(void); > > #endif > diff --git a/app/test-bbdev/test_bbdev_perf.c b/app/test-bbdev/test_bbdev_perf.c > index 4d7dc4e..bc73a97 100644 > --- a/app/test-bbdev/test_bbdev_perf.c > +++ b/app/test-bbdev/test_bbdev_perf.c > @@ -120,6 +120,8 @@ struct thread_params { > double ops_per_sec; > double mbps; > uint8_t iter_count; > + double iter_average; > + double bler; > rte_atomic16_t nb_dequeued; > rte_atomic16_t processing_status; > rte_atomic16_t burst_sz; > @@ -1207,6 +1209,312 @@ typedef int (test_case_function)(struct active_device *ad, > } > } > > + > +/* Returns a random number drawn from a normal distribution > + * with mean of 0 and variance of 1 > + * Marsaglia algorithm > + */ > +static double > +randn(int n) > +{ > + double S, Z, U1, U2, u, v, fac; > + > + do { > + U1 = (double)rand() / RAND_MAX; > + U2 = (double)rand() / RAND_MAX; > + u = 2. * U1 - 1.; > + v = 2. * U2 - 1.; > + S = u * u + v * v; > + } while (S >= 1 || S == 0); > + fac = sqrt(-2. * log(S) / S); > + Z = (n % 2) ? u * fac : v * fac; > + return Z; > +} > + > +static inline double > +maxstar(double A, double B) > +{ > + if (fabs(A - B) > 5) > + return RTE_MAX(A, B); > + else > + return RTE_MAX(A, B) + log1p(exp(-fabs(A - B))); > +} > + > +/* > + * Generate Qm LLRS for Qm==8 > + * Modulation, AWGN and LLR estimation from max log development > + */ > +static void > +gen_qm8_llr(int8_t *llrs, uint32_t i, double N0, double llr_max) > +{ > + int qm = 8; > + int qam = 256; > + int m, k; > + double I, Q, p0, p1, llr_, b[qm], log_syml_prob[qam]; > + /* 5.1.4 of TS38.211 */ > + const double symbols_I[256] = { > + 5, 5, 7, 7, 5, 5, 7, 7, 3, 3, 1, 1, 3, 3, 1, 1, 5, > + 5, 7, 7, 5, 5, 7, 7, 3, 3, 1, 1, 3, 3, 1, 1, 11, > + 11, 9, 9, 11, 11, 9, 9, 13, 13, 15, 15, 13, 13, > + 15, 15, 11, 11, 9, 9, 11, 11, 9, 9, 13, 13, 15, > + 15, 13, 13, 15, 15, 5, 5, 7, 7, 5, 5, 7, 7, 3, 3, > + 1, 1, 3, 3, 1, 1, 5, 5, 7, 7, 5, 5, 7, 7, 3, 3, 1, > + 1, 3, 3, 1, 1, 11, 11, 9, 9, 11, 11, 9, 9, 13, 13, > + 15, 15, 13, 13, 15, 15, 11, 11, 9, 9, 11, 11, 9, 9, > + 13, 13, 15, 15, 13, 13, 15, 15, -5, -5, -7, -7, -5, > + -5, -7, -7, -3, -3, -1, -1, -3, -3, -1, -1, -5, -5, > + -7, -7, -5, -5, -7, -7, -3, -3, -1, -1, -3, -3, > + -1, -1, -11, -11, -9, -9, -11, -11, -9, -9, -13, > + -13, -15, -15, -13, -13, -15, -15, -11, -11, -9, > + -9, -11, -11, -9, -9, -13, -13, -15, -15, -13, > + -13, -15, -15, -5, -5, -7, -7, -5, -5, -7, -7, -3, > + -3, -1, -1, -3, -3, -1, -1, -5, -5, -7, -7, -5, -5, > + -7, -7, -3, -3, -1, -1, -3, -3, -1, -1, -11, -11, > + -9, -9, -11, -11, -9, -9, -13, -13, -15, -15, -13, > + -13, -15, -15, -11, -11, -9, -9, -11, -11, -9, -9, > + -13, -13, -15, -15, -13, -13, -15, -15}; > + const double symbols_Q[256] = { > + 5, 7, 5, 7, 3, 1, 3, 1, 5, 7, 5, 7, 3, 1, 3, 1, 11, > + 9, 11, 9, 13, 15, 13, 15, 11, 9, 11, 9, 13, 15, 13, > + 15, 5, 7, 5, 7, 3, 1, 3, 1, 5, 7, 5, 7, 3, 1, 3, 1, > + 11, 9, 11, 9, 13, 15, 13, 15, 11, 9, 11, 9, 13, > + 15, 13, 15, -5, -7, -5, -7, -3, -1, -3, -1, -5, > + -7, -5, -7, -3, -1, -3, -1, -11, -9, -11, -9, -13, > + -15, -13, -15, -11, -9, -11, -9, -13, -15, -13, > + -15, -5, -7, -5, -7, -3, -1, -3, -1, -5, -7, -5, > + -7, -3, -1, -3, -1, -11, -9, -11, -9, -13, -15, > + -13, -15, -11, -9, -11, -9, -13, -15, -13, -15, 5, > + 7, 5, 7, 3, 1, 3, 1, 5, 7, 5, 7, 3, 1, 3, 1, 11, > + 9, 11, 9, 13, 15, 13, 15, 11, 9, 11, 9, 13, 15, > + 13, 15, 5, 7, 5, 7, 3, 1, 3, 1, 5, 7, 5, 7, 3, 1, > + 3, 1, 11, 9, 11, 9, 13, 15, 13, 15, 11, 9, 11, 9, > + 13, 15, 13, 15, -5, -7, -5, -7, -3, -1, -3, -1, > + -5, -7, -5, -7, -3, -1, -3, -1, -11, -9, -11, -9, > + -13, -15, -13, -15, -11, -9, -11, -9, -13, -15, > + -13, -15, -5, -7, -5, -7, -3, -1, -3, -1, -5, -7, > + -5, -7, -3, -1, -3, -1, -11, -9, -11, -9, -13, -15, > + -13, -15, -11, -9, -11, -9, -13, -15, -13, -15}; > + /* Average constellation point energy */ > + N0 *= 170.0; > + for (k = 0; k < qm; k++) > + b[k] = llrs[qm * i + k] < 0 ? 1.0 : 0.0; > + /* 5.1.4 of TS38.211 */ > + I = (1 - 2 * b[0]) * (8 - (1 - 2 * b[2]) * > + (4 - (1 - 2 * b[4]) * (2 - (1 - 2 * b[6])))); > + Q = (1 - 2 * b[1]) * (8 - (1 - 2 * b[3]) * > + (4 - (1 - 2 * b[5]) * (2 - (1 - 2 * b[7])))); > + /* AWGN channel */ > + I += sqrt(N0 / 2) * randn(0); > + Q += sqrt(N0 / 2) * randn(1); > + /* > + * Calculate the log of the probability that each of > + * the constellation points was transmitted > + */ > + for (m = 0; m < qam; m++) > + log_syml_prob[m] = -(pow(I - symbols_I[m], 2.0) > + + pow(Q - symbols_Q[m], 2.0)) / N0; > + /* Calculate an LLR for each of the k_64QAM bits in the set */ > + for (k = 0; k < qm; k++) { > + p0 = -999999; > + p1 = -999999; > + /* For each constellation point */ > + for (m = 0; m < qam; m++) { > + if ((m >> (qm - k - 1)) & 1) > + p1 = maxstar(p1, log_syml_prob[m]); > + else > + p0 = maxstar(p0, log_syml_prob[m]); > + } > + /* Calculate the LLR */ > + llr_ = p0 - p1; > + llr_ *= (1 << ldpc_llr_decimals); > + llr_ = round(llr_); > + if (llr_ > llr_max) > + llr_ = llr_max; > + if (llr_ < -llr_max) > + llr_ = -llr_max; > + llrs[qm * i + k] = (int8_t) llr_; > + } > +} > + > + > +/* > + * Generate Qm LLRS for Qm==6 > + * Modulation, AWGN and LLR estimation from max log development > + */ > +static void > +gen_qm6_llr(int8_t *llrs, uint32_t i, double N0, double llr_max) > +{ > + int qm = 6; > + int qam = 64; > + int m, k; > + double I, Q, p0, p1, llr_, b[qm], log_syml_prob[qam]; > + /* 5.1.4 of TS38.211 */ > + const double symbols_I[64] = { > + 3, 3, 1, 1, 3, 3, 1, 1, 5, 5, 7, 7, 5, 5, 7, 7, > + 3, 3, 1, 1, 3, 3, 1, 1, 5, 5, 7, 7, 5, 5, 7, 7, > + -3, -3, -1, -1, -3, -3, -1, -1, -5, -5, -7, -7, > + -5, -5, -7, -7, -3, -3, -1, -1, -3, -3, -1, -1, > + -5, -5, -7, -7, -5, -5, -7, -7}; > + const double symbols_Q[64] = { > + 3, 1, 3, 1, 5, 7, 5, 7, 3, 1, 3, 1, 5, 7, 5, 7, > + -3, -1, -3, -1, -5, -7, -5, -7, -3, -1, -3, -1, > + -5, -7, -5, -7, 3, 1, 3, 1, 5, 7, 5, 7, 3, 1, 3, 1, > + 5, 7, 5, 7, -3, -1, -3, -1, -5, -7, -5, -7, > + -3, -1, -3, -1, -5, -7, -5, -7}; > + /* Average constellation point energy */ > + N0 *= 42.0; > + for (k = 0; k < qm; k++) > + b[k] = llrs[qm * i + k] < 0 ? 1.0 : 0.0; > + /* 5.1.4 of TS38.211 */ > + I = (1 - 2 * b[0])*(4 - (1 - 2 * b[2]) * (2 - (1 - 2 * b[4]))); > + Q = (1 - 2 * b[1])*(4 - (1 - 2 * b[3]) * (2 - (1 - 2 * b[5]))); > + /* AWGN channel */ > + I += sqrt(N0 / 2) * randn(0); > + Q += sqrt(N0 / 2) * randn(1); > + /* > + * Calculate the log of the probability that each of > + * the constellation points was transmitted > + */ > + for (m = 0; m < qam; m++) > + log_syml_prob[m] = -(pow(I - symbols_I[m], 2.0) > + + pow(Q - symbols_Q[m], 2.0)) / N0; > + /* Calculate an LLR for each of the k_64QAM bits in the set */ > + for (k = 0; k < qm; k++) { > + p0 = -999999; > + p1 = -999999; > + /* For each constellation point */ > + for (m = 0; m < qam; m++) { > + if ((m >> (qm - k - 1)) & 1) > + p1 = maxstar(p1, log_syml_prob[m]); > + else > + p0 = maxstar(p0, log_syml_prob[m]); > + } > + /* Calculate the LLR */ > + llr_ = p0 - p1; > + llr_ *= (1 << ldpc_llr_decimals); > + llr_ = round(llr_); > + if (llr_ > llr_max) > + llr_ = llr_max; > + if (llr_ < -llr_max) > + llr_ = -llr_max; > + llrs[qm * i + k] = (int8_t) llr_; > + } > +} > + > +/* > + * Generate Qm LLRS for Qm==4 > + * Modulation, AWGN and LLR estimation from max log development > + */ > +static void > +gen_qm4_llr(int8_t *llrs, uint32_t i, double N0, double llr_max) > +{ > + int qm = 4; > + int qam = 16; > + int m, k; > + double I, Q, p0, p1, llr_, b[qm], log_syml_prob[qam]; > + /* 5.1.4 of TS38.211 */ > + const double symbols_I[16] = {1, 1, 3, 3, 1, 1, 3, 3, > + -1, -1, -3, -3, -1, -1, -3, -3}; > + const double symbols_Q[16] = {1, 3, 1, 3, -1, -3, -1, -3, > + 1, 3, 1, 3, -1, -3, -1, -3}; > + /* Average constellation point energy */ > + N0 *= 10.0; > + for (k = 0; k < qm; k++) > + b[k] = llrs[qm * i + k] < 0 ? 1.0 : 0.0; > + /* 5.1.4 of TS38.211 */ > + I = (1 - 2 * b[0]) * (2 - (1 - 2 * b[2])); > + Q = (1 - 2 * b[1]) * (2 - (1 - 2 * b[3])); > + /* AWGN channel */ > + I += sqrt(N0 / 2) * randn(0); > + Q += sqrt(N0 / 2) * randn(1); > + /* > + * Calculate the log of the probability that each of > + * the constellation points was transmitted > + */ > + for (m = 0; m < qam; m++) > + log_syml_prob[m] = -(pow(I - symbols_I[m], 2.0) > + + pow(Q - symbols_Q[m], 2.0)) / N0; > + /* Calculate an LLR for each of the k_64QAM bits in the set */ > + for (k = 0; k < qm; k++) { > + p0 = -999999; > + p1 = -999999; > + /* For each constellation point */ > + for (m = 0; m < qam; m++) { > + if ((m >> (qm - k - 1)) & 1) > + p1 = maxstar(p1, log_syml_prob[m]); > + else > + p0 = maxstar(p0, log_syml_prob[m]); > + } > + /* Calculate the LLR */ > + llr_ = p0 - p1; > + llr_ *= (1 << ldpc_llr_decimals); > + llr_ = round(llr_); > + if (llr_ > llr_max) > + llr_ = llr_max; > + if (llr_ < -llr_max) > + llr_ = -llr_max; > + llrs[qm * i + k] = (int8_t) llr_; > + } > +} > + > +static void > +gen_qm2_llr(int8_t *llrs, uint32_t j, double N0, double llr_max) > +{ > + double b, b1, n; > + double coeff = 2.0 * sqrt(N0); > + > + /* Ignore in vectors rare quasi null LLRs not to be saturated */ > + if (llrs[j] < 8 && llrs[j] > -8) > + return; > + > + /* Note don't change sign here */ > + n = randn(j % 2); > + b1 = ((llrs[j] > 0 ? 2.0 : -2.0) > + + coeff * n) / N0; > + b = b1 * (1 << ldpc_llr_decimals); > + b = round(b); > + if (b > llr_max) > + b = llr_max; > + if (b < -llr_max) > + b = -llr_max; > + llrs[j] = (int8_t) b; > +} > + > +/* Generate LLR for a given SNR */ > +static void > +generate_llr_input(uint16_t n, struct rte_bbdev_op_data *inputs, > + struct rte_bbdev_dec_op *ref_op) > +{ > + struct rte_mbuf *m; > + uint16_t qm; > + uint32_t i, j, e, range; > + double N0, llr_max; > + > + e = ref_op->ldpc_dec.cb_params.e; > + qm = ref_op->ldpc_dec.q_m; > + llr_max = (1 << (ldpc_llr_size - 1)) - 1; > + range = e / qm; > + N0 = 1.0 / pow(10.0, get_snr() / 10.0); > + > + for (i = 0; i < n; ++i) { > + m = inputs[i].data; > + int8_t *llrs = rte_pktmbuf_mtod_offset(m, int8_t *, 0); > + if (qm == 8) { > + for (j = 0; j < range; ++j) > + gen_qm8_llr(llrs, j, N0, llr_max); > + } else if (qm == 6) { > + for (j = 0; j < range; ++j) > + gen_qm6_llr(llrs, j, N0, llr_max); > + } else if (qm == 4) { > + for (j = 0; j < range; ++j) > + gen_qm4_llr(llrs, j, N0, llr_max); > + } else { > + for (j = 0; j < e; ++j) > + gen_qm2_llr(llrs, j, N0, llr_max); > + } > + } > +} > + > static void > copy_reference_ldpc_dec_op(struct rte_bbdev_dec_op **ops, unsigned int n, > unsigned int start_idx, > @@ -1593,6 +1901,30 @@ typedef int (test_case_function)(struct active_device *ad, > return TEST_SUCCESS; > } > > +/* Check Number of code blocks errors */ > +static int > +validate_ldpc_bler(struct rte_bbdev_dec_op **ops, const uint16_t n) > +{ > + unsigned int i; > + struct op_data_entries *hard_data_orig = > + &test_vector.entries[DATA_HARD_OUTPUT]; > + struct rte_bbdev_op_ldpc_dec *ops_td; > + struct rte_bbdev_op_data *hard_output; > + int errors = 0; > + struct rte_mbuf *m; > + > + for (i = 0; i < n; ++i) { > + ops_td = &ops[i]->ldpc_dec; > + hard_output = &ops_td->hard_output; > + m = hard_output->data; > + if (memcmp(rte_pktmbuf_mtod_offset(m, uint32_t *, 0), > + hard_data_orig->segments[0].addr, > + hard_data_orig->segments[0].length)) > + errors++; > + } > + return errors; > +} > + > static int > validate_ldpc_dec_op(struct rte_bbdev_dec_op **ops, const uint16_t n, > struct rte_bbdev_dec_op *ref_op, const int vector_mask) > @@ -2506,6 +2838,139 @@ typedef int (test_case_function)(struct active_device *ad, > } > > static int > +bler_pmd_lcore_ldpc_dec(void *arg) > +{ > + struct thread_params *tp = arg; > + uint16_t enq, deq; > + uint64_t total_time = 0, start_time; > + const uint16_t queue_id = tp->queue_id; > + const uint16_t burst_sz = tp->op_params->burst_sz; > + const uint16_t num_ops = tp->op_params->num_to_process; > + struct rte_bbdev_dec_op *ops_enq[num_ops]; > + struct rte_bbdev_dec_op *ops_deq[num_ops]; > + struct rte_bbdev_dec_op *ref_op = tp->op_params->ref_dec_op; > + struct test_buffers *bufs = NULL; > + int i, j, ret; > + float parity_bler = 0; > + struct rte_bbdev_info info; > + uint16_t num_to_enq; > + bool extDdr = check_bit(ldpc_cap_flags, > + RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_OUT_ENABLE); > + bool loopback = check_bit(ref_op->ldpc_dec.op_flags, > + RTE_BBDEV_LDPC_INTERNAL_HARQ_MEMORY_LOOPBACK); > + bool hc_out = check_bit(ref_op->ldpc_dec.op_flags, > + RTE_BBDEV_LDPC_HQ_COMBINE_OUT_ENABLE); > + > + TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST), > + "BURST_SIZE should be <= %u", MAX_BURST); > + > + rte_bbdev_info_get(tp->dev_id, &info); > + > + TEST_ASSERT_SUCCESS((num_ops > info.drv.queue_size_lim), > + "NUM_OPS cannot exceed %u for this device", > + info.drv.queue_size_lim); > + > + bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id]; > + > + while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT) > + rte_pause(); > + > + ret = rte_bbdev_dec_op_alloc_bulk(tp->op_params->mp, ops_enq, num_ops); > + TEST_ASSERT_SUCCESS(ret, "Allocation failed for %d ops", num_ops); > + > + /* For BLER tests we need to enable early termination */ > + if (!check_bit(ref_op->ldpc_dec.op_flags, > + RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE)) > + ref_op->ldpc_dec.op_flags += > + RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE; > + ref_op->ldpc_dec.iter_max = get_iter_max(); > + ref_op->ldpc_dec.iter_count = ref_op->ldpc_dec.iter_max; > + > + if (test_vector.op_type != RTE_BBDEV_OP_NONE) > + copy_reference_ldpc_dec_op(ops_enq, num_ops, 0, bufs->inputs, > + bufs->hard_outputs, bufs->soft_outputs, > + bufs->harq_inputs, bufs->harq_outputs, ref_op); > + generate_llr_input(num_ops, bufs->inputs, ref_op); > + > + /* Set counter to validate the ordering */ > + for (j = 0; j < num_ops; ++j) > + ops_enq[j]->opaque_data = (void *)(uintptr_t)j; > + > + for (i = 0; i < 1; ++i) { /* Could add more iterations */ > + for (j = 0; j < num_ops; ++j) { > + if (!loopback) > + mbuf_reset( > + ops_enq[j]->ldpc_dec.hard_output.data); > + if (hc_out || loopback) > + mbuf_reset( > + ops_enq[j]->ldpc_dec.harq_combined_output.data); > + } > + if (extDdr) { > + bool preload = i == (TEST_REPETITIONS - 1); > + preload_harq_ddr(tp->dev_id, queue_id, ops_enq, > + num_ops, preload); > + } > + start_time = rte_rdtsc_precise(); > + > + for (enq = 0, deq = 0; enq < num_ops;) { > + num_to_enq = burst_sz; > + > + if (unlikely(num_ops - enq < num_to_enq)) > + num_to_enq = num_ops - enq; > + > + enq += rte_bbdev_enqueue_ldpc_dec_ops(tp->dev_id, > + queue_id, &ops_enq[enq], num_to_enq); > + > + deq += rte_bbdev_dequeue_ldpc_dec_ops(tp->dev_id, > + queue_id, &ops_deq[deq], enq - deq); > + } > + > + /* dequeue the remaining */ > + while (deq < enq) { > + deq += rte_bbdev_dequeue_ldpc_dec_ops(tp->dev_id, > + queue_id, &ops_deq[deq], enq - deq); > + } > + > + total_time += rte_rdtsc_precise() - start_time; > + } > + > + tp->iter_count = 0; > + tp->iter_average = 0; > + /* get the max of iter_count for all dequeued ops */ > + for (i = 0; i < num_ops; ++i) { > + tp->iter_count = RTE_MAX(ops_enq[i]->ldpc_dec.iter_count, > + tp->iter_count); > + tp->iter_average += (double) ops_enq[i]->ldpc_dec.iter_count; > + if (ops_enq[i]->status & (1 << RTE_BBDEV_SYNDROME_ERROR)) > + parity_bler += 1.0; > + } > + > + parity_bler /= num_ops; /* This one is based on SYND */ > + tp->iter_average /= num_ops; > + tp->bler = (double) validate_ldpc_bler(ops_deq, num_ops) / num_ops; > + > + if (test_vector.op_type != RTE_BBDEV_OP_NONE > + && tp->bler == 0 > + && parity_bler == 0 > + && !hc_out) { > + ret = validate_ldpc_dec_op(ops_deq, num_ops, ref_op, > + tp->op_params->vector_mask); > + TEST_ASSERT_SUCCESS(ret, "Validation failed!"); > + } > + > + rte_bbdev_dec_op_free_bulk(ops_enq, num_ops); > + > + double tb_len_bits = calc_ldpc_dec_TB_size(ref_op); > + tp->ops_per_sec = ((double)num_ops * 1) / > + ((double)total_time / (double)rte_get_tsc_hz()); > + tp->mbps = (((double)(num_ops * 1 * tb_len_bits)) / > + 1000000.0) / ((double)total_time / > + (double)rte_get_tsc_hz()); > + > + return TEST_SUCCESS; > +} > + > +static int > throughput_pmd_lcore_ldpc_dec(void *arg) > { > struct thread_params *tp = arg; > @@ -2550,7 +3015,7 @@ typedef int (test_case_function)(struct active_device *ad, > RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE)) > ref_op->ldpc_dec.op_flags -= > RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE; > - ref_op->ldpc_dec.iter_max = 6; > + ref_op->ldpc_dec.iter_max = get_iter_max(); > ref_op->ldpc_dec.iter_count = ref_op->ldpc_dec.iter_max; > > if (test_vector.op_type != RTE_BBDEV_OP_NONE) > @@ -2831,27 +3296,147 @@ typedef int (test_case_function)(struct active_device *ad, > used_cores, total_mops, total_mbps); > } > > +/* Aggregate the performance results over the number of cores used */ > static void > print_dec_throughput(struct thread_params *t_params, unsigned int used_cores) > { > - unsigned int iter = 0; > + unsigned int core_idx = 0; > double total_mops = 0, total_mbps = 0; > uint8_t iter_count = 0; > > - for (iter = 0; iter < used_cores; iter++) { > + for (core_idx = 0; core_idx < used_cores; core_idx++) { > printf( > "Throughput for core (%u): %.8lg Ops/s, %.8lg Mbps @ max %u iterations\n", > - t_params[iter].lcore_id, t_params[iter].ops_per_sec, > - t_params[iter].mbps, t_params[iter].iter_count); > - total_mops += t_params[iter].ops_per_sec; > - total_mbps += t_params[iter].mbps; > - iter_count = RTE_MAX(iter_count, t_params[iter].iter_count); > + t_params[core_idx].lcore_id, > + t_params[core_idx].ops_per_sec, > + t_params[core_idx].mbps, > + t_params[core_idx].iter_count); > + total_mops += t_params[core_idx].ops_per_sec; > + total_mbps += t_params[core_idx].mbps; > + iter_count = RTE_MAX(iter_count, > + t_params[core_idx].iter_count); > } > printf( > "\nTotal throughput for %u cores: %.8lg MOPS, %.8lg Mbps @ max %u iterations\n", > used_cores, total_mops, total_mbps, iter_count); > } > > +/* Aggregate the performance results over the number of cores used */ > +static void > +print_dec_bler(struct thread_params *t_params, unsigned int used_cores) > +{ > + unsigned int core_idx = 0; > + double total_mbps = 0, total_bler = 0, total_iter = 0; > + double snr = get_snr(); > + > + for (core_idx = 0; core_idx < used_cores; core_idx++) { > + printf("Core%u BLER %.1f %% - Iters %.1f - Tp %.1f Mbps %s\n", > + t_params[core_idx].lcore_id, > + t_params[core_idx].bler * 100, > + t_params[core_idx].iter_average, > + t_params[core_idx].mbps, > + get_vector_filename()); > + total_mbps += t_params[core_idx].mbps; > + total_bler += t_params[core_idx].bler; > + total_iter += t_params[core_idx].iter_average; > + } > + total_bler /= used_cores; > + total_iter /= used_cores; > + > + printf("SNR %.2f BLER %.1f %% - Iterations %.1f %d - Tp %.1f Mbps %s\n", > + snr, total_bler * 100, total_iter, get_iter_max(), > + total_mbps, get_vector_filename()); > +} > + > +/* > + * Test function that determines BLER wireless performance > + */ > +static int > +bler_test(struct active_device *ad, > + struct test_op_params *op_params) > +{ > + int ret; > + unsigned int lcore_id, used_cores = 0; > + struct thread_params *t_params; > + struct rte_bbdev_info info; > + lcore_function_t *bler_function; > + uint16_t num_lcores; > + const char *op_type_str; > + > + rte_bbdev_info_get(ad->dev_id, &info); > + > + op_type_str = rte_bbdev_op_type_str(test_vector.op_type); > + TEST_ASSERT_NOT_NULL(op_type_str, "Invalid op type: %u", > + test_vector.op_type); > + > + printf("+ ------------------------------------------------------- +\n"); > + printf("== test: bler\ndev: %s, nb_queues: %u, burst size: %u, num ops: %u, num_lcores: %u, op type: %s, itr mode: %s, GHz: %lg\n", > + info.dev_name, ad->nb_queues, op_params->burst_sz, > + op_params->num_to_process, op_params->num_lcores, > + op_type_str, > + intr_enabled ? "Interrupt mode" : "PMD mode", > + (double)rte_get_tsc_hz() / 1000000000.0); > + > + /* Set number of lcores */ > + num_lcores = (ad->nb_queues < (op_params->num_lcores)) > + ? ad->nb_queues > + : op_params->num_lcores; > + > + /* Allocate memory for thread parameters structure */ > + t_params = rte_zmalloc(NULL, num_lcores * sizeof(struct thread_params), > + RTE_CACHE_LINE_SIZE); > + TEST_ASSERT_NOT_NULL(t_params, "Failed to alloc %zuB for t_params", > + RTE_ALIGN(sizeof(struct thread_params) * num_lcores, > + RTE_CACHE_LINE_SIZE)); > + > + if (test_vector.op_type == RTE_BBDEV_OP_LDPC_DEC) > + bler_function = bler_pmd_lcore_ldpc_dec; > + else > + return TEST_SKIPPED; > + > + rte_atomic16_set(&op_params->sync, SYNC_WAIT); > + > + /* Master core is set at first entry */ > + t_params[0].dev_id = ad->dev_id; > + t_params[0].lcore_id = rte_lcore_id(); > + t_params[0].op_params = op_params; > + t_params[0].queue_id = ad->queue_ids[used_cores++]; > + t_params[0].iter_count = 0; > + > + RTE_LCORE_FOREACH_SLAVE(lcore_id) { > + if (used_cores >= num_lcores) > + break; > + > + t_params[used_cores].dev_id = ad->dev_id; > + t_params[used_cores].lcore_id = lcore_id; > + t_params[used_cores].op_params = op_params; > + t_params[used_cores].queue_id = ad->queue_ids[used_cores]; > + t_params[used_cores].iter_count = 0; > + > + rte_eal_remote_launch(bler_function, > + &t_params[used_cores++], lcore_id); > + } > + > + rte_atomic16_set(&op_params->sync, SYNC_START); > + ret = bler_function(&t_params[0]); > + > + /* Master core is always used */ > + for (used_cores = 1; used_cores < num_lcores; used_cores++) > + ret |= rte_eal_wait_lcore(t_params[used_cores].lcore_id); > + > + print_dec_bler(t_params, num_lcores); > + > + /* Return if test failed */ > + if (ret) { > + rte_free(t_params); > + return ret; > + } > + > + /* Function to print something here*/ > + rte_free(t_params); > + return ret; > +} > + > /* > * Test function that determines how long an enqueue + dequeue of a burst > * takes on available lcores. > @@ -3119,7 +3704,7 @@ typedef int (test_case_function)(struct active_device *ad, > RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE)) > ref_op->ldpc_dec.op_flags -= > RTE_BBDEV_LDPC_ITERATION_STOP_ENABLE; > - ref_op->ldpc_dec.iter_max = 6; > + ref_op->ldpc_dec.iter_max = get_iter_max(); > ref_op->ldpc_dec.iter_count = ref_op->ldpc_dec.iter_max; > > if (test_vector.op_type != RTE_BBDEV_OP_NONE) > @@ -3977,6 +4562,12 @@ typedef int (test_case_function)(struct active_device *ad, > } > > static int > +bler_tc(void) > +{ > + return run_test_case(bler_test); > +} > + > +static int > throughput_tc(void) > { > return run_test_case(throughput_test); > @@ -4006,6 +4597,16 @@ typedef int (test_case_function)(struct active_device *ad, > return run_test_case(throughput_test); > } > > +static struct unit_test_suite bbdev_bler_testsuite = { > + .suite_name = "BBdev BLER Tests", > + .setup = testsuite_setup, > + .teardown = testsuite_teardown, > + .unit_test_cases = { > + TEST_CASE_ST(ut_setup, ut_teardown, bler_tc), > + TEST_CASES_END() /**< NULL terminate unit test array */ > + } > +}; > + > static struct unit_test_suite bbdev_throughput_testsuite = { > .suite_name = "BBdev Throughput Tests", > .setup = testsuite_setup, > @@ -4057,6 +4658,7 @@ typedef int (test_case_function)(struct active_device *ad, > } > }; > > +REGISTER_TEST_COMMAND(bler, bbdev_bler_testsuite); > REGISTER_TEST_COMMAND(throughput, bbdev_throughput_testsuite); > REGISTER_TEST_COMMAND(validation, bbdev_validation_testsuite); > REGISTER_TEST_COMMAND(latency, bbdev_latency_testsuite); > diff --git a/doc/guides/tools/testbbdev.rst b/doc/guides/tools/testbbdev.rst > index 7e95696..9f2f786 100644 > --- a/doc/guides/tools/testbbdev.rst > +++ b/doc/guides/tools/testbbdev.rst > @@ -47,6 +47,8 @@ The tool application has a number of command line options: > [-c TEST_CASE [TEST_CASE ...]] > [-v TEST_VECTOR [TEST_VECTOR...]] [-n NUM_OPS] > [-b BURST_SIZE [BURST_SIZE ...]] [-l NUM_LCORES] > + [-t MAX_ITERS [MAX_ITERS ...]] > + [-s SNR [SNR ...]] > > command-line Options > ~~~~~~~~~~~~~~~~~~~~ > @@ -106,6 +108,14 @@ The following are the command-line options: > Specifies operations enqueue/dequeue burst size. If not specified burst_size is > set to 32. Maximum is 512. > > +``-t MAX_ITERS [MAX_ITERS ...], --iter_max MAX_ITERS [MAX_ITERS ...]`` > + Specifies LDPC decoder operations maximum number of iterations for throughput > + and bler tests. If not specified iter_max is set to 6. > + > +``-s SNR [SNR ...], --snr SNR [SNR ...]`` > + Specifies for LDPC decoder operations the SNR in dB used when generating LLRs > + for bler tests. If not specified snr is set to 0 dB. > + > Test Cases > ~~~~~~~~~~ > > @@ -149,6 +159,12 @@ There are 6 main test cases that can be executed using testbbdev tool: > - Results are printed in million operations per second and million bits > per second > > +* BLER measurement [-c bler] > + - Performs full operation of enqueue and dequeue > + - Measures the achieved throughput on a subset or all available CPU cores > + - Computed BLER (Block Error Rate, ratio of blocks not decoded at a given > + SNR) in % based on the total number of operations. > + > * Interrupt-mode Throughput [-c interrupt] > - Similar to Throughput test case, but using interrupts. No polling. >