<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:"Apple Color Emoji";
        panose-1:0 0 0 0 0 0 0 0 0 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
span.EmailStyle19
        {mso-style-type:personal-reply;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:72.0pt 72.0pt 72.0pt 72.0pt;}
div.WordSection1
        {page:WordSection1;}
--></style>
</head>
<body lang="en-IT" link="#0563C1" vlink="#954F72" style="word-wrap:break-word">
<div class="WordSection1">
<div>
<p class="MsoNormal">> > Could you, please, set "Author" correctly - "Elena Agostini <eagostini@nvidia.com>"?<o:p></o:p></p>
<p class="MsoNormal">> > Otherwise, we see in the git log:<o:p></o:p></p>
<p class="MsoNormal">> ><o:p></o:p></p>
<p class="MsoNormal">> > "Author: eagostini <eagostini@nvidia.com>"<o:p></o:p></p>
<p class="MsoNormal">> ><o:p></o:p></p>
<p class="MsoNormal">> > Compare with:<o:p></o:p></p>
<p class="MsoNormal">> > "Author: Bing Zhao <bingz@nvidia.com>"<o:p></o:p></p>
<p class="MsoNormal">> > "Author: Viacheslav Ovsiienko <viacheslavo@nvidia.com>"<o:p></o:p></p>
<p class="MsoNormal">> ><o:p></o:p></p>
<p class="MsoNormal">> > Also, please, see the codestyle issues, too many code lines far beyond 100 chars.<o:p></o:p></p>
<p class="MsoNormal">> > Lines like this:<o:p></o:p></p>
<p class="MsoNormal">> > +             if (mbuf_mem_types[idx] == MBUF_MEM_GPU && strcmp(cur_fwd_eng->fwd_mode_name, "io") != 0) {<o:p></o:p></p>
<p class="MsoNormal">> > can be easily be splitted.<o:p></o:p></p>
<p class="MsoNormal">> ><o:p></o:p></p>
<p class="MsoNormal">> > >>app/testpmd: add GPU memory option in iofwd<o:p></o:p></p>
<p class="MsoNormal">> > As I see from the patch - it adds the new mbuf pool type (residing on GPU memory).<o:p></o:p></p>
<p class="MsoNormal">> > May be, we should reword the title?<o:p></o:p></p>
<p class="MsoNormal">> > " app/testpmd: add GPU memory option for mbuf pools"<o:p></o:p></p>
<p class="MsoNormal">> ><o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > > This patch introduces GPU memory in testpmd through the gpudev library.<o:p></o:p></p>
<p class="MsoNormal">> > > Testpmd can be used for network benchmarks when using GPU memory<o:p></o:p></p>
<p class="MsoNormal">> > > instead of regular CPU memory to send and receive packets.<o:p></o:p></p>
<p class="MsoNormal">> > > This option is currently limited to iofwd engine.<o:p></o:p></p>
<p class="MsoNormal">> > Why? Because iofwd the only mode not touching the mbuf data?<o:p></o:p></p>
<p class="MsoNormal">> > Is it critical for functionality? Is GPU mbuf pool memory accessible from CPU side?<o:p></o:p></p>
<p class="MsoNormal">> > I would explain the reasons (for supporting iofwd mode only) in commit message.<o:p></o:p></p>
<p class="MsoNormal">> ><o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > > Signed-off-by: Elena Agostini <eagostini@nvidia.com><o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > > Depends-on: series-19465 ("GPU library")<o:p></o:p></p>
<p class="MsoNormal">> > > Depends-on: series-20422 ("common/mlx5: fix external memory pool<o:p></o:p></p>
<p class="MsoNormal">> > > registration")<o:p></o:p></p>
<p class="MsoNormal">> > > ---<o:p></o:p></p>
<p class="MsoNormal">> > >  app/test-pmd/cmdline.c                |  14 +++<o:p></o:p></p>
<p class="MsoNormal">> > >  app/test-pmd/meson.build              |   2 +-<o:p></o:p></p>
<p class="MsoNormal">> > >  app/test-pmd/parameters.c             |  13 ++-<o:p></o:p></p>
<p class="MsoNormal">> > >  app/test-pmd/testpmd.c                | 133 +++++++++++++++++++++++---<o:p></o:p></p>
<p class="MsoNormal">> > >  app/test-pmd/testpmd.h                |  16 +++-<o:p></o:p></p>
<p class="MsoNormal">> > >  doc/guides/testpmd_app_ug/run_app.rst |   3 +<o:p></o:p></p>
<p class="MsoNormal">> > >  6 files changed, 164 insertions(+), 17 deletions(-)<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > > diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index<o:p></o:p></p>
<p class="MsoNormal">> > > 4f51b259fe..36193bc566 100644<o:p></o:p></p>
<p class="MsoNormal">> > > --- a/app/test-pmd/cmdline.c<o:p></o:p></p>
<p class="MsoNormal">> > > +++ b/app/test-pmd/cmdline.c<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -3614,6 +3614,7 @@ parse_item_list(const char *str, const char<o:p></o:p></p>
<p class="MsoNormal">> ><o:p></o:p></p>
<p class="MsoNormal">> > The "parse_item_list()" is used to parse the list looking like "number0, number1, ...., numberN"<o:p></o:p></p>
<p class="MsoNormal">> > and invoked for "core","port", "txtimes", etc. Not sure all of these params need to handle "g"<o:p></o:p></p>
<p class="MsoNormal">> > suffix. We should allow "g" processing only for "mbuf-size". We have "item_name" argument<o:p></o:p></p>
<p class="MsoNormal">> > to check whether we are invoked on "mbuf-size".<o:p></o:p></p>
<p class="MsoNormal">> ><o:p></o:p></p>
<p class="MsoNormal">> > > *item_name, unsigned int max_items,<o:p></o:p></p>
<p class="MsoNormal">> > >     unsigned int j;<o:p></o:p></p>
<p class="MsoNormal">> > >     int value_ok;<o:p></o:p></p>
<p class="MsoNormal">> > >     char c;<o:p></o:p></p>
<p class="MsoNormal">> > > +   int gpu_mbuf = 0;<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > >     /*<o:p></o:p></p>
<p class="MsoNormal">> > >      * First parse all items in the list and store their value.<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -3628,6 +3629,14 @@ parse_item_list(const char *str, const char<o:p></o:p></p>
<p class="MsoNormal">> > > *item_name, unsigned int max_items,<o:p></o:p></p>
<p class="MsoNormal">> > >                     value_ok = 1;<o:p></o:p></p>
<p class="MsoNormal">> > >                     continue;<o:p></o:p></p>
<p class="MsoNormal">> > >             }<o:p></o:p></p>
<p class="MsoNormal">> > > +           if (c == 'g') {<o:p></o:p></p>
<p class="MsoNormal">> > We should check whether "g" is the single char suffix (last char).<o:p></o:p></p>
<p class="MsoNormal">> > Otherwise, "20g48" and "g20gggg48" would be also valid values.<o:p></o:p></p>
<p class="MsoNormal">> ><o:p></o:p></p>
<p class="MsoNormal">> > > +                   /*<o:p></o:p></p>
<p class="MsoNormal">> > > +                    * When this flag is set, mbufs for this segment<o:p></o:p></p>
<p class="MsoNormal">> > > +                    * will be created on GPU memory.<o:p></o:p></p>
<p class="MsoNormal">> > > +                    */<o:p></o:p></p>
<p class="MsoNormal">> > > +                   gpu_mbuf = 1;<o:p></o:p></p>
<p class="MsoNormal">> > > +                   continue;<o:p></o:p></p>
<p class="MsoNormal">> > > +           }<o:p></o:p></p>
<p class="MsoNormal">> > >             if (c != ',') {<o:p></o:p></p>
<p class="MsoNormal">> > >                     fprintf(stderr, "character %c is not a decimal digit\n",<o:p></o:p></p>
<p class="MsoNormal">> > > c);<o:p></o:p></p>
<p class="MsoNormal">> > >                     return 0;<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -3640,6 +3649,8 @@ parse_item_list(const char *str, const char<o:p></o:p></p>
<p class="MsoNormal">> > > *item_name, unsigned int max_items,<o:p></o:p></p>
<p class="MsoNormal">> > >                     parsed_items[nb_item] = value;<o:p></o:p></p>
<p class="MsoNormal">> > >                     value_ok = 0;<o:p></o:p></p>
<p class="MsoNormal">> > >                     value = 0;<o:p></o:p></p>
<p class="MsoNormal">> > > +                   mbuf_mem_types[nb_item] = gpu_mbuf ?<o:p></o:p></p>
<p class="MsoNormal">> > > MBUF_MEM_GPU : MBUF_MEM_CPU;<o:p></o:p></p>
<p class="MsoNormal">> > > +                   gpu_mbuf = 0;<o:p></o:p></p>
<p class="MsoNormal">> > >             }<o:p></o:p></p>
<p class="MsoNormal">> > >             nb_item++;<o:p></o:p></p>
<p class="MsoNormal">> > >     }<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -3648,6 +3659,9 @@ parse_item_list(const char *str, const char<o:p></o:p></p>
<p class="MsoNormal">> > > *item_name, unsigned int max_items,<o:p></o:p></p>
<p class="MsoNormal">> > >                     item_name, nb_item + 1, max_items);<o:p></o:p></p>
<p class="MsoNormal">> > >             return 0;<o:p></o:p></p>
<p class="MsoNormal">> > >     }<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   mbuf_mem_types[nb_item] = gpu_mbuf ? MBUF_MEM_GPU :<o:p></o:p></p>
<p class="MsoNormal">> > > MBUF_MEM_CPU;<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >     parsed_items[nb_item++] = value;<o:p></o:p></p>
<p class="MsoNormal">> > >     if (! check_unique_values)<o:p></o:p></p>
<p class="MsoNormal">> > >             return nb_item;<o:p></o:p></p>
<p class="MsoNormal">> > > diff --git a/app/test-pmd/meson.build b/app/test-pmd/meson.build index<o:p></o:p></p>
<p class="MsoNormal">> > > d5df52c470..5c8ca68c9d 100644<o:p></o:p></p>
<p class="MsoNormal">> > > --- a/app/test-pmd/meson.build<o:p></o:p></p>
<p class="MsoNormal">> > > +++ b/app/test-pmd/meson.build<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -32,7 +32,7 @@ if dpdk_conf.has('RTE_HAS_JANSSON')<o:p></o:p></p>
<p class="MsoNormal">> > >      ext_deps += jansson_dep<o:p></o:p></p>
<p class="MsoNormal">> > >  endif<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > > -deps += ['ethdev', 'gro', 'gso', 'cmdline', 'metrics', 'bus_pci']<o:p></o:p></p>
<p class="MsoNormal">> > > +deps += ['ethdev', 'gro', 'gso', 'cmdline', 'metrics', 'bus_pci',<o:p></o:p></p>
<p class="MsoNormal">> > > +'gpudev']<o:p></o:p></p>
<p class="MsoNormal">> > >  if dpdk_conf.has('RTE_CRYPTO_SCHEDULER')<o:p></o:p></p>
<p class="MsoNormal">> > >      deps += 'crypto_scheduler'<o:p></o:p></p>
<p class="MsoNormal">> > >  endif<o:p></o:p></p>
<p class="MsoNormal">> > > diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c index<o:p></o:p></p>
<p class="MsoNormal">> > > 0974b0a38f..d41f7f220b 100644<o:p></o:p></p>
<p class="MsoNormal">> > > --- a/app/test-pmd/parameters.c<o:p></o:p></p>
<p class="MsoNormal">> > > +++ b/app/test-pmd/parameters.c<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -87,7 +87,10 @@ usage(char* progname)<o:p></o:p></p>
<p class="MsoNormal">> > >            "in NUMA mode.\n");<o:p></o:p></p>
<p class="MsoNormal">> > >     printf("  --mbuf-size=N,[N1[,..Nn]: set the data size of mbuf to "<o:p></o:p></p>
<p class="MsoNormal">> > >            "N bytes. If multiple numbers are specified the extra pools "<o:p></o:p></p>
<p class="MsoNormal">> > > -          "will be created to receive with packet split features\n");<o:p></o:p></p>
<p class="MsoNormal">> > > +          "will be created to receive with packet split features\n"<o:p></o:p></p>
<p class="MsoNormal">> > > +              "Use 'g' suffix for GPU memory.\n"<o:p></o:p></p>
<p class="MsoNormal">> > > +              "If no or an unrecognized suffix is provided, CPU is<o:p></o:p></p>
<p class="MsoNormal">> > > assumed\n");<o:p></o:p></p>
<p class="MsoNormal">> > Unrecognized suffix? I would emit an error and abort the launch.<o:p></o:p></p>
<p class="MsoNormal">> ><o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >     printf("  --total-num-mbufs=N: set the number of mbufs to be<o:p></o:p></p>
<p class="MsoNormal">> > > allocated "<o:p></o:p></p>
<p class="MsoNormal">> > >            "in mbuf pools.\n");<o:p></o:p></p>
<p class="MsoNormal">> > >     printf("  --max-pkt-len=N: set the maximum size of packet to N<o:p></o:p></p>
<p class="MsoNormal">> > > bytes.\n"); @@ -595,6 +598,7 @@ launch_args_parse(int argc, char** argv)<o:p></o:p></p>
<p class="MsoNormal">> > >     struct rte_eth_dev_info dev_info;<o:p></o:p></p>
<p class="MsoNormal">> > >     uint16_t rec_nb_pkts;<o:p></o:p></p>
<p class="MsoNormal">> > >     int ret;<o:p></o:p></p>
<p class="MsoNormal">> > > +   uint32_t idx = 0;<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > >     static struct option lgopts[] = {<o:p></o:p></p>
<p class="MsoNormal">> > >             { "help",                       0, 0, 0 },<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -1538,4 +1542,11 @@ launch_args_parse(int argc, char** argv)<o:p></o:p></p>
<p class="MsoNormal">> > >                               "ignored\n");<o:p></o:p></p>
<p class="MsoNormal">> > >             mempool_flags = 0;<o:p></o:p></p>
<p class="MsoNormal">> > >     }<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   for (idx = 0; idx < mbuf_data_size_n; idx++) {<o:p></o:p></p>
<p class="MsoNormal">> > > +           if (mbuf_mem_types[idx] == MBUF_MEM_GPU &&<o:p></o:p></p>
<p class="MsoNormal">> > > strcmp(cur_fwd_eng->fwd_mode_name, "io") != 0) {<o:p></o:p></p>
<p class="MsoNormal">> > > +                   fprintf(stderr, "GPU memory mbufs can be used with<o:p></o:p></p>
<p class="MsoNormal">> > > iofwd engine only\n");<o:p></o:p></p>
<p class="MsoNormal">> > > +                   rte_exit(EXIT_FAILURE, "Command line is<o:p></o:p></p>
<p class="MsoNormal">> > > incorrect\n");<o:p></o:p></p>
<p class="MsoNormal">> > > +           }<o:p></o:p></p>
<p class="MsoNormal">> > > +   }<o:p></o:p></p>
<p class="MsoNormal">> > Please, note, the forwarding mode can be changed from interactive prompt with "set fwd <mode>" command.<o:p></o:p></p>
<p class="MsoNormal">> > If iofwd mode is crucial for GPU functionality - we should prevent switching to other modes if GPU pools are engaged.<o:p></o:p></p>
<p class="MsoNormal">> ><o:p></o:p></p>
<p class="MsoNormal">> ><o:p></o:p></p>
<p class="MsoNormal">> > >  }<o:p></o:p></p>
<p class="MsoNormal">> > > diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index<o:p></o:p></p>
<p class="MsoNormal">> > > a66dfb297c..1af235c4d8 100644<o:p></o:p></p>
<p class="MsoNormal">> > > --- a/app/test-pmd/testpmd.c<o:p></o:p></p>
<p class="MsoNormal">> > > +++ b/app/test-pmd/testpmd.c<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -205,6 +205,12 @@ uint32_t mbuf_data_size_n = 1; /* Number of<o:p></o:p></p>
<p class="MsoNormal">> > > specified mbuf sizes. */  uint16_t mbuf_data_size[MAX_SEGS_BUFFER_SPLIT]<o:p></o:p></p>
<p class="MsoNormal">> > > = {<o:p></o:p></p>
<p class="MsoNormal">> > >     DEFAULT_MBUF_DATA_SIZE<o:p></o:p></p>
<p class="MsoNormal">> > >  }; /**< Mbuf data space size. */<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +/* Mbuf memory types. */<o:p></o:p></p>
<p class="MsoNormal">> > > +enum mbuf_mem_type mbuf_mem_types[MAX_SEGS_BUFFER_SPLIT];<o:p></o:p></p>
<p class="MsoNormal">> > > +/* Pointers to external memory allocated for mempools. */ uintptr_t<o:p></o:p></p>
<p class="MsoNormal">> > > +mempools_ext_ptr[MAX_SEGS_BUFFER_SPLIT];<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >  uint32_t param_total_num_mbufs = 0;  /**< number of mbufs in all pools - if<o:p></o:p></p>
<p class="MsoNormal">> > >                                        * specified on command-line. */  uint16_t<o:p></o:p></p>
<p class="MsoNormal">> > > stats_period; /**< Period to show statistics (disabled by default) */ @@ -<o:p></o:p></p>
<p class="MsoNormal">> > > 543,6 +549,12 @@ int proc_id;<o:p></o:p></p>
<p class="MsoNormal">> > >   */<o:p></o:p></p>
<p class="MsoNormal">> > >  unsigned int num_procs = 1;<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > > +/*<o:p></o:p></p>
<p class="MsoNormal">> > > + * In case of GPU memory external mbufs use, for simplicity,<o:p></o:p></p>
<p class="MsoNormal">> > > + * the first GPU device in the list.<o:p></o:p></p>
<p class="MsoNormal">> > > + */<o:p></o:p></p>
<p class="MsoNormal">> > > +int gpu_id = 0;<o:p></o:p></p>
<p class="MsoNormal">> > It is assigned with zero and never changes. Support the first GPU only?<o:p></o:p></p>
<p class="MsoNormal">> > This limitation should be mentioned in documentation.<o:p></o:p></p>
<p class="MsoNormal">> ><o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >  static void<o:p></o:p></p>
<p class="MsoNormal">> > >  eth_rx_metadata_negotiate_mp(uint16_t port_id)  { @@ -1103,6 +1115,79<o:p></o:p></p>
<p class="MsoNormal">> > > @@ setup_extbuf(uint32_t nb_mbufs, uint16_t mbuf_sz, unsigned int<o:p></o:p></p>
<p class="MsoNormal">> > > socket_id,<o:p></o:p></p>
<p class="MsoNormal">> > >     return ext_num;<o:p></o:p></p>
<p class="MsoNormal">> > >  }<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > > +static struct rte_mempool *<o:p></o:p></p>
<p class="MsoNormal">> > > +gpu_mbuf_pool_create(uint16_t mbuf_seg_size, unsigned int nb_mbuf,<o:p></o:p></p>
<p class="MsoNormal">> > > +                   unsigned int socket_id, uint16_t port_id,<o:p></o:p></p>
<p class="MsoNormal">> > > +                   int gpu_id, uintptr_t * mp_addr)<o:p></o:p></p>
<p class="MsoNormal">> > > +{<o:p></o:p></p>
<p class="MsoNormal">> > > +   int ret = 0;<o:p></o:p></p>
<p class="MsoNormal">> > > +   char pool_name[RTE_MEMPOOL_NAMESIZE];<o:p></o:p></p>
<p class="MsoNormal">> > > +   struct rte_eth_dev_info dev_info;<o:p></o:p></p>
<p class="MsoNormal">> > > +   struct rte_mempool *rte_mp = NULL;<o:p></o:p></p>
<p class="MsoNormal">> > > +   struct rte_pktmbuf_extmem gpu_mem;<o:p></o:p></p>
<p class="MsoNormal">> > > +   struct rte_gpu_info ginfo;<o:p></o:p></p>
<p class="MsoNormal">> > > +   uint8_t gpu_page_shift = 16;<o:p></o:p></p>
<p class="MsoNormal">> > > +   uint32_t gpu_page_size = (1UL << gpu_page_shift);<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   ret = eth_dev_info_get_print_err(port_id, &dev_info);<o:p></o:p></p>
<p class="MsoNormal">> > > +   if (ret != 0)<o:p></o:p></p>
<p class="MsoNormal">> > > +           rte_exit(EXIT_FAILURE,<o:p></o:p></p>
<p class="MsoNormal">> > > +                   "Failed to get device info for port %d\n",<o:p></o:p></p>
<p class="MsoNormal">> > > +                   port_id);<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   mbuf_poolname_build(socket_id, pool_name, sizeof(pool_name),<o:p></o:p></p>
<p class="MsoNormal">> > > port_id, MBUF_MEM_GPU);<o:p></o:p></p>
<p class="MsoNormal">> > > +   if (!is_proc_primary()) {<o:p></o:p></p>
<p class="MsoNormal">> > > +           rte_mp = rte_mempool_lookup(pool_name);<o:p></o:p></p>
<p class="MsoNormal">> > > +           if (rte_mp == NULL)<o:p></o:p></p>
<p class="MsoNormal">> > > +                   rte_exit(EXIT_FAILURE,<o:p></o:p></p>
<p class="MsoNormal">> > > +                           "Get mbuf pool for socket %u failed: %s\n",<o:p></o:p></p>
<p class="MsoNormal">> > > +                           socket_id, rte_strerror(rte_errno));<o:p></o:p></p>
<p class="MsoNormal">> > > +           return rte_mp;<o:p></o:p></p>
<p class="MsoNormal">> > > +   }<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   if (rte_gpu_info_get(gpu_id, &ginfo))<o:p></o:p></p>
<p class="MsoNormal">> > > +           rte_exit(EXIT_FAILURE, "Can't retrieve info about GPU %d -<o:p></o:p></p>
<p class="MsoNormal">> > > bye\n",<o:p></o:p></p>
<p class="MsoNormal">> > > +gpu_id);<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   TESTPMD_LOG(INFO,<o:p></o:p></p>
<p class="MsoNormal">> > > +           "create a new mbuf pool <%s>: n=%u, size=%u, socket=%u<o:p></o:p></p>
<p class="MsoNormal">> > > GPU device=%s\n",<o:p></o:p></p>
<p class="MsoNormal">> > > +           pool_name, nb_mbuf, mbuf_seg_size, socket_id, ginfo.name);<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   /* Create an external memory mempool using memory allocated on<o:p></o:p></p>
<p class="MsoNormal">> > > the<o:p></o:p></p>
<p class="MsoNormal">> > > +GPU. */<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   gpu_mem.elt_size = RTE_MBUF_DEFAULT_BUF_SIZE;<o:p></o:p></p>
<p class="MsoNormal">> > > +   gpu_mem.buf_len = RTE_ALIGN_CEIL(nb_mbuf * gpu_mem.elt_size,<o:p></o:p></p>
<p class="MsoNormal">> > > gpu_page_size);<o:p></o:p></p>
<p class="MsoNormal">> > > +   gpu_mem.buf_iova = RTE_BAD_IOVA;<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   gpu_mem.buf_ptr = rte_gpu_mem_alloc(gpu_id, gpu_mem.buf_len);<o:p></o:p></p>
<p class="MsoNormal">> > > +   if (gpu_mem.buf_ptr == NULL)<o:p></o:p></p>
<p class="MsoNormal">> > > +           rte_exit(EXIT_FAILURE, "Could not allocate GPU device<o:p></o:p></p>
<p class="MsoNormal">> > > memory\n");<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   ret = rte_extmem_register(gpu_mem.buf_ptr, gpu_mem.buf_len,<o:p></o:p></p>
<p class="MsoNormal">> > > NULL, gpu_mem.buf_iova, gpu_page_size);<o:p></o:p></p>
<p class="MsoNormal">> > > +   if (ret)<o:p></o:p></p>
<p class="MsoNormal">> > > +           rte_exit(EXIT_FAILURE, "Unable to register addr 0x%p, ret<o:p></o:p></p>
<p class="MsoNormal">> > > %d\n",<o:p></o:p></p>
<p class="MsoNormal">> > > +gpu_mem.buf_ptr, ret);<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   uint16_t pid = 0;<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   RTE_ETH_FOREACH_DEV(pid)<o:p></o:p></p>
<p class="MsoNormal">> > > +   {<o:p></o:p></p>
<p class="MsoNormal">> > > +           ret = rte_dev_dma_map(dev_info.device, gpu_mem.buf_ptr,<o:p></o:p></p>
<p class="MsoNormal">> > > +                                     gpu_mem.buf_iova,<o:p></o:p></p>
<p class="MsoNormal">> > > gpu_mem.buf_len);<o:p></o:p></p>
<p class="MsoNormal">> > > +           if (ret) {<o:p></o:p></p>
<p class="MsoNormal">> > > +                   rte_exit(EXIT_FAILURE, "Unable to DMA map addr<o:p></o:p></p>
<p class="MsoNormal">> > > 0x%p for device %s\n",<o:p></o:p></p>
<p class="MsoNormal">> > > +                                    gpu_mem.buf_ptr, dev_info.device-<o:p></o:p></p>
<p class="MsoNormal">> > > >name);<o:p></o:p></p>
<p class="MsoNormal">> > > +           }<o:p></o:p></p>
<p class="MsoNormal">> > > +   }<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   rte_mp = rte_pktmbuf_pool_create_extbuf(pool_name, nb_mbuf,<o:p></o:p></p>
<p class="MsoNormal">> > > mb_mempool_cache, 0, mbuf_seg_size, socket_id, &gpu_mem, 1);<o:p></o:p></p>
<p class="MsoNormal">> > > +   if (rte_mp == NULL) {<o:p></o:p></p>
<p class="MsoNormal">> > > +           rte_exit(EXIT_FAILURE, "Creation of GPU mempool <%s><o:p></o:p></p>
<p class="MsoNormal">> > > failed\n", pool_name);<o:p></o:p></p>
<p class="MsoNormal">> > > +   }<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   *mp_addr = (uintptr_t) gpu_mem.buf_ptr;<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +   return rte_mp;<o:p></o:p></p>
<p class="MsoNormal">> > > +}<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >  /*<o:p></o:p></p>
<p class="MsoNormal">> > >   * Configuration initialisation done once at init time.<o:p></o:p></p>
<p class="MsoNormal">> > >   */<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -1117,7 +1202,7 @@ mbuf_pool_create(uint16_t mbuf_seg_size,<o:p></o:p></p>
<p class="MsoNormal">> > > unsigned nb_mbuf,<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > >     mb_size = sizeof(struct rte_mbuf) + mbuf_seg_size;  #endif<o:p></o:p></p>
<p class="MsoNormal">> > > -   mbuf_poolname_build(socket_id, pool_name, sizeof(pool_name),<o:p></o:p></p>
<p class="MsoNormal">> > > size_idx);<o:p></o:p></p>
<p class="MsoNormal">> > > +   mbuf_poolname_build(socket_id, pool_name, sizeof(pool_name),<o:p></o:p></p>
<p class="MsoNormal">> > > size_idx,<o:p></o:p></p>
<p class="MsoNormal">> > > +MBUF_MEM_CPU);<o:p></o:p></p>
<p class="MsoNormal">> > >     if (!is_proc_primary()) {<o:p></o:p></p>
<p class="MsoNormal">> > >             rte_mp = rte_mempool_lookup(pool_name);<o:p></o:p></p>
<p class="MsoNormal">> > >             if (rte_mp == NULL)<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -1700,19 +1785,42 @@ init_config(void)<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > >             for (i = 0; i < num_sockets; i++)<o:p></o:p></p>
<p class="MsoNormal">> > >                     for (j = 0; j < mbuf_data_size_n; j++)<o:p></o:p></p>
<p class="MsoNormal">> > > -                           mempools[i * MAX_SEGS_BUFFER_SPLIT + j]<o:p></o:p></p>
<p class="MsoNormal">> > > =<o:p></o:p></p>
<p class="MsoNormal">> > > -                                   mbuf_pool_create(mbuf_data_size[j],<o:p></o:p></p>
<p class="MsoNormal">> > > -                                                     nb_mbuf_per_pool,<o:p></o:p></p>
<p class="MsoNormal">> > > -                                                     socket_ids[i], j);<o:p></o:p></p>
<p class="MsoNormal">> > > +                   {<o:p></o:p></p>
<p class="MsoNormal">> > > +                           if (mbuf_mem_types[j] == MBUF_MEM_GPU)<o:p></o:p></p>
<p class="MsoNormal">> > > {<o:p></o:p></p>
<p class="MsoNormal">> > > +                                   if (rte_gpu_count_avail() == 0)<o:p></o:p></p>
<p class="MsoNormal">> > > +                                           rte_exit(EXIT_FAILURE, "No<o:p></o:p></p>
<p class="MsoNormal">> > > GPU device available.\n");<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > > +                                   mempools[i *<o:p></o:p></p>
<p class="MsoNormal">> > > MAX_SEGS_BUFFER_SPLIT + j] =<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >     gpu_mbuf_pool_create(mbuf_data_size[j],<o:p></o:p></p>
<p class="MsoNormal">> > What about GPU/CPU adherence ? Do we create one GPU pool per CPU socket?<o:p></o:p></p>
<p class="MsoNormal">> > Disregarding  hardware topology at all?<o:p></o:p></p>
<p class="MsoNormal">> > We can mitigate the issue by "--socket-mem/--socket-num" parameter though.<o:p></o:p></p>
<p class="MsoNormal">> ><o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >              nb_mbuf_per_pool,<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >              socket_ids[i], j, gpu_id,<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >              &(mempools_ext_ptr[j]));<o:p></o:p></p>
<p class="MsoNormal">> > > +                           } else {<o:p></o:p></p>
<p class="MsoNormal">> > > +                                   mempools[i *<o:p></o:p></p>
<p class="MsoNormal">> > > MAX_SEGS_BUFFER_SPLIT + j] =<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >     mbuf_pool_create(mbuf_data_size[j],<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >     nb_mbuf_per_pool,<o:p></o:p></p>
<p class="MsoNormal">> > > +                                                           socket_ids[i],<o:p></o:p></p>
<p class="MsoNormal">> > > j);<o:p></o:p></p>
<p class="MsoNormal">> > > +                           }<o:p></o:p></p>
<p class="MsoNormal">> > > +                   }<o:p></o:p></p>
<p class="MsoNormal">> > >     } else {<o:p></o:p></p>
<p class="MsoNormal">> > >             uint8_t i;<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > >             for (i = 0; i < mbuf_data_size_n; i++)<o:p></o:p></p>
<p class="MsoNormal">> > > -                   mempools[i] = mbuf_pool_create<o:p></o:p></p>
<p class="MsoNormal">> > > -                                   (mbuf_data_size[i],<o:p></o:p></p>
<p class="MsoNormal">> > > -                                    nb_mbuf_per_pool,<o:p></o:p></p>
<p class="MsoNormal">> > > -                                    socket_num == UMA_NO_CONFIG ?<o:p></o:p></p>
<p class="MsoNormal">> > > -                                    0 : socket_num, i);<o:p></o:p></p>
<p class="MsoNormal">> > > +           {<o:p></o:p></p>
<p class="MsoNormal">> > > +                   if (mbuf_mem_types[i] == MBUF_MEM_GPU) {<o:p></o:p></p>
<p class="MsoNormal">> > > +                           mempools[i] =<o:p></o:p></p>
<p class="MsoNormal">> > > gpu_mbuf_pool_create(mbuf_data_size[i],<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >                        nb_mbuf_per_pool,<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >                        socket_num == UMA_NO_CONFIG ? 0 : socket_num,<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >                        i, gpu_id,<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >                        &(mempools_ext_ptr[i]));<o:p></o:p></p>
<p class="MsoNormal">> > > +                   } else {<o:p></o:p></p>
<p class="MsoNormal">> > > +                           mempools[i] =<o:p></o:p></p>
<p class="MsoNormal">> > > mbuf_pool_create(mbuf_data_size[i],<o:p></o:p></p>
<p class="MsoNormal">> > > +                                                   nb_mbuf_per_pool,<o:p></o:p></p>
<p class="MsoNormal">> > > +                                                   socket_num ==<o:p></o:p></p>
<p class="MsoNormal">> > > UMA_NO_CONFIG ?<o:p></o:p></p>
<p class="MsoNormal">> > > +                                                   0 : socket_num, i);<o:p></o:p></p>
<p class="MsoNormal">> > > +                   }<o:p></o:p></p>
<p class="MsoNormal">> > > +           }<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >     }<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > >     init_port_config();<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -3415,8 +3523,11 @@ pmd_test_exit(void)<o:p></o:p></p>
<p class="MsoNormal">> > >             }<o:p></o:p></p>
<p class="MsoNormal">> > >     }<o:p></o:p></p>
<p class="MsoNormal">> > >     for (i = 0 ; i < RTE_DIM(mempools) ; i++) {<o:p></o:p></p>
<p class="MsoNormal">> > > -           if (mempools[i])<o:p></o:p></p>
<p class="MsoNormal">> > > +           if (mempools[i]) {<o:p></o:p></p>
<p class="MsoNormal">> > >                     mempool_free_mp(mempools[i]);<o:p></o:p></p>
<p class="MsoNormal">> > > +                   if (mbuf_mem_types[i] == MBUF_MEM_GPU)<o:p></o:p></p>
<p class="MsoNormal">> > > +                           rte_gpu_mem_free(gpu_id, (void<o:p></o:p></p>
<p class="MsoNormal">> > > *)mempools_ext_ptr[i]);<o:p></o:p></p>
<p class="MsoNormal">> > > +           }<o:p></o:p></p>
<p class="MsoNormal">> > >     }<o:p></o:p></p>
<p class="MsoNormal">> > >     free(xstats_display);<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > > diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index<o:p></o:p></p>
<p class="MsoNormal">> > > 669ce1e87d..9919044372 100644<o:p></o:p></p>
<p class="MsoNormal">> > > --- a/app/test-pmd/testpmd.h<o:p></o:p></p>
<p class="MsoNormal">> > > +++ b/app/test-pmd/testpmd.h<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -12,6 +12,7 @@<o:p></o:p></p>
<p class="MsoNormal">> > >  #include <rte_gro.h><o:p></o:p></p>
<p class="MsoNormal">> > >  #include <rte_gso.h><o:p></o:p></p>
<p class="MsoNormal">> > >  #include <rte_os_shim.h><o:p></o:p></p>
<p class="MsoNormal">> > > +#include <rte_gpudev.h><o:p></o:p></p>
<p class="MsoNormal">> > >  #include <cmdline.h><o:p></o:p></p>
<p class="MsoNormal">> > >  #include <sys/queue.h><o:p></o:p></p>
<p class="MsoNormal">> > >  #ifdef RTE_HAS_JANSSON<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -474,6 +475,11 @@ extern uint8_t dcb_config;  extern uint32_t<o:p></o:p></p>
<p class="MsoNormal">> > > mbuf_data_size_n;  extern uint16_t<o:p></o:p></p>
<p class="MsoNormal">> > > mbuf_data_size[MAX_SEGS_BUFFER_SPLIT];<o:p></o:p></p>
<p class="MsoNormal">> > >  /**< Mbuf data space size. */<o:p></o:p></p>
<p class="MsoNormal">> > > +enum mbuf_mem_type {<o:p></o:p></p>
<p class="MsoNormal">> > > +   MBUF_MEM_CPU,<o:p></o:p></p>
<p class="MsoNormal">> > > +   MBUF_MEM_GPU<o:p></o:p></p>
<p class="MsoNormal">> > > +};<o:p></o:p></p>
<p class="MsoNormal">> > > +extern enum mbuf_mem_type<o:p></o:p></p>
<p class="MsoNormal">> > > mbuf_mem_types[MAX_SEGS_BUFFER_SPLIT];<o:p></o:p></p>
<p class="MsoNormal">> > >  extern uint32_t param_total_num_mbufs;<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > >  extern uint16_t stats_period;<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -717,14 +723,16 @@ current_fwd_lcore(void)<o:p></o:p></p>
<p class="MsoNormal">> > >  /* Mbuf Pools */<o:p></o:p></p>
<p class="MsoNormal">> > >  static inline void<o:p></o:p></p>
<p class="MsoNormal">> > >  mbuf_poolname_build(unsigned int sock_id, char *mp_name,<o:p></o:p></p>
<p class="MsoNormal">> > > -               int name_size, uint16_t idx)<o:p></o:p></p>
<p class="MsoNormal">> > > +               int name_size, uint16_t idx, enum mbuf_mem_type<o:p></o:p></p>
<p class="MsoNormal">> > > mem_type)<o:p></o:p></p>
<p class="MsoNormal">> > >  {<o:p></o:p></p>
<p class="MsoNormal">> > > +   const char *suffix = mem_type == MBUF_MEM_GPU ? "_gpu" : "";<o:p></o:p></p>
<p class="MsoNormal">> > > +<o:p></o:p></p>
<p class="MsoNormal">> > >     if (!idx)<o:p></o:p></p>
<p class="MsoNormal">> > >             snprintf(mp_name, name_size,<o:p></o:p></p>
<p class="MsoNormal">> > > -                    MBUF_POOL_NAME_PFX "_%u", sock_id);<o:p></o:p></p>
<p class="MsoNormal">> > > +                    MBUF_POOL_NAME_PFX "_%u%s", sock_id, suffix);<o:p></o:p></p>
<p class="MsoNormal">> > >     else<o:p></o:p></p>
<p class="MsoNormal">> > >             snprintf(mp_name, name_size,<o:p></o:p></p>
<p class="MsoNormal">> > > -                    MBUF_POOL_NAME_PFX "_%hu_%hu",<o:p></o:p></p>
<p class="MsoNormal">> > > (uint16_t)sock_id, idx);<o:p></o:p></p>
<p class="MsoNormal">> > > +                    MBUF_POOL_NAME_PFX "_%hu_%hu%s",<o:p></o:p></p>
<p class="MsoNormal">> > > (uint16_t)sock_id, idx, suffix);<o:p></o:p></p>
<p class="MsoNormal">> > >  }<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > >  static inline struct rte_mempool *<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -732,7 +740,7 @@ mbuf_pool_find(unsigned int sock_id, uint16_t idx)  {<o:p></o:p></p>
<p class="MsoNormal">> > >     char pool_name[RTE_MEMPOOL_NAMESIZE];<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > > -   mbuf_poolname_build(sock_id, pool_name, sizeof(pool_name), idx);<o:p></o:p></p>
<p class="MsoNormal">> > > +   mbuf_poolname_build(sock_id, pool_name, sizeof(pool_name), idx,<o:p></o:p></p>
<p class="MsoNormal">> > > +mbuf_mem_types[idx]);<o:p></o:p></p>
<p class="MsoNormal">> > >     return rte_mempool_lookup((const char *)pool_name);  }<o:p></o:p></p>
<p class="MsoNormal">> > ><o:p></o:p></p>
<p class="MsoNormal">> > > diff --git a/doc/guides/testpmd_app_ug/run_app.rst<o:p></o:p></p>
<p class="MsoNormal">> > > b/doc/guides/testpmd_app_ug/run_app.rst<o:p></o:p></p>
<p class="MsoNormal">> > > index 30edef07ea..ede7b79abb 100644<o:p></o:p></p>
<p class="MsoNormal">> > > --- a/doc/guides/testpmd_app_ug/run_app.rst<o:p></o:p></p>
<p class="MsoNormal">> > > +++ b/doc/guides/testpmd_app_ug/run_app.rst<o:p></o:p></p>
<p class="MsoNormal">> > > @@ -119,6 +119,9 @@ The command line options are:<o:p></o:p></p>
<p class="MsoNormal">> > >      The default value is 2048. If multiple mbuf-size values are specified the<o:p></o:p></p>
<p class="MsoNormal">> > >      extra memory pools will be created for allocating mbufs to receive packets<o:p></o:p></p>
<p class="MsoNormal">> > >      with buffer splitting features.<o:p></o:p></p>
<p class="MsoNormal">> > > +    Providing mbuf size with a 'g' suffix (e.g. ``--mbuf-size=2048g``),<o:p></o:p></p>
<p class="MsoNormal">> > > +    will cause the mempool to be created on a GPU memory area allocated.<o:p></o:p></p>
<p class="MsoNormal">> > > +    This option is currently limited to iofwd engine with the first GPU.<o:p></o:p></p>
<p class="MsoNormal">> > Mmm, if we have multiple GPUs - we have no way to specify on which one we should allocate the pool.<o:p></o:p></p>
<p class="MsoNormal">> > Syntax is not complete<span style="font-family:"Apple Color Emoji"">☹</span>. Possible we should specify GPU port id after the suffix ? Like 2048g2 ?<o:p></o:p></p>
<p class="MsoNormal">> > If port index is omitted we should consider we have the only GPU and check this.<o:p></o:p></p>
<p class="MsoNormal">> <o:p></o:p></p>
<p class="MsoNormal">> Do we need to overload --mbuf-size parameter here?<o:p></o:p></p>
<p class="MsoNormal">> Why not add 'gpu' option to --mp-alloc parameter?<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">--mbuf-size is preferred to --mp-alloc because with --mbuf-size you can enable buffer split<span lang="EN-US"> feature<o:p></o:p></span></p>
<p class="MsoNormal">allocating multiple mempools <span lang="EN-US">with</span> different mbufs sizes on different type of memories.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<p class="MsoNormal">An example would be --mbuf-size=2048g,1024 which will create two mempools to split packets,<o:p></o:p></p>
<p class="MsoNormal">one in GPU memory and another in CPU memory<o:p></o:p></p>
</div>
</div>
</body>
</html>