<div dir="ltr"><div dir="ltr"><div class="gmail_default" style=""><font face="monospace">Stephen, thank you for the reply. It occurred to me right after I sent</font></div><div class="gmail_default" style=""><font face="monospace">the email, </font><span style="font-family:monospace">the salient call was rte_eal_remote_launch which you confirmed.</span></div><div class="gmail_default" style=""><font face="monospace"><br>For the benefit of everybody else let me provide a full explanation.</font></div><div class="gmail_default" style=""><font face="monospace"><br></font></div><div class="gmail_default" style=""><font face="monospace">The scenario is a test program,</font></div><div class="gmail_default" style=""><font face="monospace"><br></font></div><div class="gmail_default" style=""><font face="monospace">* Creates 1 RX queue then reads and pretty prints contents in a loop<br style="">* Creates 1 TX queue then sends packets to a hardcoded IP address in a loop<br style=""><br></font></div><div class="gmail_default" style=""><font face="monospace">The intent is to run the RX loop on one core, and the TX loop on another core. </font></div><div class="gmail_default" style=""><font face="monospace"><br></font></div><div class="gmail_default" style=""><font face="monospace">Now, DPDK users may have run across the '--lcores' argument to DPDK programs. </font></div><div class="gmail_default" style=""><font face="monospace">See here for reference documentation: </font></div><div class="gmail_default" style=""><font face="monospace"><br></font></div><div class="gmail_default" style=""><font face="monospace"><a href="https://doc.dpdk.org/guides-2.0/prog_guide/env_abstraction_layer.html" target="_blank">https://doc.dpdk.org/guides-2.0/prog_guide/env_abstraction_layer.html</a><br></font></div><div class="gmail_default" style=""><font face="monospace"><a href="https://doc.dpdk.org/guides/linux_gsg/linux_eal_parameters.html">https://doc.dpdk.org/guides/linux_gsg/linux_eal_parameters.html</a><br></font></div><div class="gmail_default" style=""><font face="monospace"><br></font></div><div class="gmail_default" style=""><font face="monospace">All DPDK command line arguments are processed by the DPDK application</font></div><div class="gmail_default" style=""><font face="monospace">with "rte_eal_init" first thing in the application e.g. early in 'main()'.</font></div><div class="gmail_default" style=""><font face="monospace"><br></font></div><div class="gmail_default" style=""><font face="monospace">Now in this context, the --lcores argument is a hint or direction to DPDK that the program</font></div><div class="gmail_default" style=""><font face="monospace">will create one or more lcores. In DPDK an "lcore" is a thread of control pinned to a</font></div><div class="gmail_default" style=""><font face="monospace">CPU HW core. So, for example,  the fragment "--lcores=(1)@2,(2)@4" in the command</font></div><div class="gmail_default" style=""><font face="monospace">would tell DPDK that the program will create and run two application lcores namely </font></div><div class="gmail_default" style=""><font face="monospace">lcore '1' on CPU </font><span style="font-family:monospace">HW core 2, and lcore '2' on CPU HW core 4.</span></div><div class="gmail_default" style=""><font face="monospace"><br></font></div><div class="gmail_default" style=""><font face="monospace">Then, when all the memzone, mempool, queue, and NIC initialization is done, the program</font></div><div class="gmail_default" style=""><font face="monospace">can parlay the lcores argument above to actually launch the application threads pinned</font></div><div class="gmail_default" style=""><font face="monospace">to the correct as instructed like this,</font></div><div class="gmail_default" style=""><font face="monospace"><br>  int lcore_hello(__rte_unused void *arg)<br>  {<br>    unsigned lcore_id;<br>    lcore_id = rte_lcore_id();<br>    printf("hello from core %u\n", lcore_id);<br>    return 0;<br> }<br></font></div><div class="gmail_default" style=""><font face="monospace"> int main(int argc, char **argv) {</font></div><div class="gmail_default" style=""><font face="monospace">    ret = rte_eal_init(argc, argv);<br>    if (ret < 0)<br>        rte_panic("Cannot init EAL\n");</font></div><div class="gmail_default" style=""><font face="monospace"><br></font></div><div class="gmail_default" style=""><font face="monospace">    // memzone, mempool, queue, and NIC setup not shown</font></div><div class="gmail_default" style=""><font face="monospace"><br></font></div><div class="gmail_default" style=""><font face="monospace">    // If program run with --lcores=(1)@2,(2)@4 this loop will</font></div><div class="gmail_default" style=""><font face="monospace">    // create and run two threads lcore 1 pinned to CPU 2 and lcore 2</font></div><div class="gmail_default" style=""><font face="monospace">    // pinned to CPU 4. the output will look like:</font></div><div class="gmail_default" style=""><font face="monospace">    //     hello from core 1</font></div><div class="gmail_default" style=""><font face="monospace">    //     hello from core 2</font></div><div class="gmail_default" style=""><font face="monospace">    RTE_LCORE_FOREACH_WORKER(lcore_id) {<br>        rte_eal_remote_launch(lcore_hello, NULL, lcore_id);<br>    }<br></font></div><div class="gmail_default" style=""><font face="monospace">    .</font></div><div class="gmail_default" style=""><font face="monospace">    .</font></div><div class="gmail_default" style=""><font face="monospace">    .</font></div><div class="gmail_default" style=""><font face="monospace"><br></font></div><div class="gmail_default" style=""><font face="monospace">See this program for a standalone example including shutdown:</font></div><div class="gmail_default" style=""><font face="monospace"><a href="https://doc.dpdk.org/api/examples_2helloworld_2main_8c-example.html#a5">https://doc.dpdk.org/api/examples_2helloworld_2main_8c-example.html#a5</a></font></div><div class="gmail_default" style="">Note the referenced program sneaks in a call to <span style="font-family:monospace">lcore_hello on the main thread</span></div><div class="gmail_default" style=""><span style="font-family:monospace">by calling '</span>lcore_hello(NULL)'. And that call will print '<span style="font-family:monospace">hello from core 0'. But</span></div><div class="gmail_default" style=""><span style="font-family:monospace">do not think that output was a side effect of </span><span style="font-family:monospace">RTE_LCORE_FOREACH_WORKER.</span></div><div class="gmail_default" style=""><font face="monospace">See next for details.</font></div><div class="gmail_default" style=""><br></div><div class="gmail_default" style=""><font face="monospace">The other detail worth mentioning is the special case of lcore 0. lcore 0</font></div><div class="gmail_default" style=""><font face="monospace">is a synonym for the main thread e.g. the thread the DPDK program runs on</font></div><div class="gmail_default" style=""><font face="monospace">starting in main. The </font><span style="font-family:monospace">RTE_LCORE_FOREACH_WORKER will NOT include lcore 0</span></div><div class="gmail_default" style=""><span style="font-family:monospace">even if you reference it in the command line. The salient point is the loop</span></div><div class="gmail_default" style=""><font face="monospace">launches WORKER threads, and worker threads are for lcores > 0.</font></div><div class="gmail_default" style=""><font face="monospace"><br></font></div><div class="gmail_default" style=""><font face="monospace">Now if you provide, say, "</font><span style="font-family:monospace">--lcores=(1)@2,(2)@4,(0)@6" the above program</span></div><div class="gmail_default" style=""><span style="font-family:monospace">will still launch the same two worker threads pinned to the same CPUs</span></div><div class="gmail_default" style=""><span style="font-family:monospace">just as before. The only difference is that the main thread will be pinned</span></div><div class="gmail_default" style=""><span style="font-family:monospace">to CPU core 6. You can get the same effect by running:<br>   </span></div><div class="gmail_default" style=""><span style="font-family:monospace">   # task and main thread start on CPU 6, and "</span><span style="font-family:monospace">--lcores=(1)@2,(2)@4"</span></div><div class="gmail_default" style=""><span style="font-family:monospace">   # will start two worker threads on CPUS 2, 4 as described above<br>   taskset -c6 <task>  ... </span><font face="monospace">"</font><span style="font-family:monospace">--lcores=(1)@2,(2)@4" ...</span></div><div class="gmail_default" style=""><br></div><div class="gmail_default" style=""><font face="monospace">> When I run this program I include the command line arguments<br style="">> "--lcores=(0)@1,(1)@2" which is passed to 'rte_eal_init'.<br></font></div><div class="gmail_default" style=""><font face="monospace"><br></font></div></div><font face="monospace"><br></font><div class="gmail_quote"><div dir="ltr" class="gmail_attr"><font face="monospace">On Sat, Mar 30, 2024 at 12:52 PM Stephen Hemminger <<a href="mailto:stephen@networkplumber.org" target="_blank">stephen@networkplumber.org</a>> wrote:<br></font></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><font face="monospace">On Sat, 30 Mar 2024 12:06:15 -0400<br>
fwefew 4t4tg <<a href="mailto:7532yahoo@gmail.com" target="_blank">7532yahoo@gmail.com</a>> wrote:<br>
<br>
> I've made a DPDK test program that does the following on the same machine<br>
> and for the same NIC. This is a test; it does nothing practical:<br>
> <br>
> * Creates 1 RX queue then reads and pretty prints contents in a loop<br>
> * Creates 1 TX queue then sends packets to a hardcoded IP address in a loop<br>
> <br>
> When I run this program I include the command line arguments<br>
> "--lcores=(0)@1,(1)@2" which is passed to 'rte_eal_init'.<br>
> <br>
> This means there's a lcore identified '0' run on CPU HW core 1, and lcore<br>
> '1' run on CPU HW core 2.<br>
> <br>
> As I understand it, the intent of the lcores argument is that this test<br>
> program will eventually run the RX loop as lcore 0, and the TX loop as<br>
> lcore 1 (or vice-versa).<br>
> <br>
> On the other hand after all the required DPDK setup is done --- memzones,<br>
> mempools, queues, NIC devices initialized and started --- here's what DPDK<br>
> has not done:<br>
> <br>
> * It hasn't started an application thread for lcore 0 or lcore 1<br>
> * DPDK doesn't know the function entry point for either loop so no loops<br>
> are running.<br>
> <br>
> Which is totally fine ... DPDK isn't magic. If the application programmer<br>
> wants a RX and TX application thread pinned to some CPU, it should create<br>
> the threads, set the CPU affinity, and run the loop in the NUMA aligned<br>
> way. This is trivial to do. That is, with the required DPDK setup done, all<br>
> that's left is to do this trivial work ... and the test program is up and<br>
> running: problem solved.<br>
> <br>
> The --lcores doesn't and cannot do this application work. So what is the<br>
> practical result of it? What does it do?<br>
<br>
Did your application every start the other threads with DPDK?<br>
It is not recommended for applications to manage their own threads.<br>
Possible but hard to get right.<br>
<br>
A typical application looks like:<br>
<br>
<br>
main() {<br>
    // do some initialization<br>
    rte_eal_init()<br>
<br>
    // do more initialization that has to be done in main thread<br>
<br>
    rte_eal_mp_remote_launch(worker_func, arg, CALL_MAIN);<br>
<br>
    // main thread worker_func has exited, wait for others<br>
    rte_eal_mp_wait_lcore()<br>
<br>
    // back to single main thread<br>
    rte_eal_cleanup()<br>
}<br></font>
<br>
</blockquote></div></div>