This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM3352 cpu usage for spidev_test

Dear Sir,

I tested the spidev_test in the kernel/Documentation/spi/spidev_test.c and use top to check the CPU loading.

just adding a while loop to continue the SPI transfer.

CPU is fixed at 1Ghz, testing at both EZSDK7, and 8.

1. When SPI clock is set 500Khz as default, the CPU usage is 14.6%.

    

2. When SPI clock is higher like 24Mhz,  the CPU usage can be reduced obviously.

    

It looks like the time is took by spi1 driver doing the I/O.

Is this result normal that I get a really high CPU loading when using a 500Khz SPI transfering? (My client need it to work at a lower frequencies.)

I saw the DMA channel defined in the am33xx.dtsi.

Isn't the DMA enabled and I can get a lower CPU usage for this I/O read/write?

Thank you.

  • Hi,

    WTMEC_FoneC said:
    just adding a while loop to continue the SPI transfer.

    This is what really loads the MPU, as it's continuously running through the loop, checking the exit condition.

  • Dear Biser,

    Actually, the delay loop is in spidev_test.c and function usleep() as I know should not occupy the cpu like this.
    So the process is spidev_test, but the time cost in the above is in spi1.
    Besides, it will be reduced after I increase the SPI Clock.
    Would you please help me clarify this?

    Thank you.
  • Dear Biser,

    the application is a display panel with SPI interface.
    The reason for this while loop is to simulate the SPI transfer data behavior.
    The major issue is the LOW clock SPI message transfer caused more CPU usage.
    I checked the driver has spin_lock_irq when doing spi_sync.
    Please help clarify if it is the root cause and if it's normal high CPU loading with LOW SPI clockrate.

    Thank you.
  • I have asked the software team to comment on this use case.
  • Hi Biser:

    WT Fone is our Disty, may you help to update this?
    Thanks.

    BR Rio
  • This has already been sent to the software team. Feedback will be posted here when available.
  • Hi,

    Sorry for the late response. I had to test this on my side.

    Biser, is correct in his statement, that the while loop is loading the cpu.  In my understanding it is fine to see this behavior, when you test spi like this (with a  loop in spidev_test.c)

    I'll try to explain. I work with a 500KHz speed of the spi transfer. 

    1. Here are the tests (I wasn't optimizing my programs, so cpu loads are far worst than what you report, but behaviour should be similar on your side) I ran on my BBB, running kernel 4.1:

    1.1) loop the spi transfer directly in spidev_test.c, as bellow:

    if (input_tx) {

                 size = strlen(input_tx+1);

                 tx = malloc(size);

                 rx = malloc(size);

                 size = unescape((char *)tx, input_tx, size);

                 while (1) {

                        transfer(fd, tx, rx, size);

                        free(rx);

                        free(tx);

                  }

                 } else {

                        while (1)

                              transfer(fd, default_tx, default_rx, sizeof(default_tx));

    }

    1.2) execute  a shell script that calls the spidev_test.c, compiled as spi:

    #!/bin/sh                                                                                                                            

    while true                                                                                                                          

    do                                                                                                                                  

    ./spi                                                                                                                              

    done

    As a result CPU load is ~70%, because of the while (1) loop. Result was similar (even worse) when I comment the transfer() call in 1.1).

    On the other hand: 

    2.1) I use the spidev_test.c, without a while loop in it: 

    if (input_tx) {

                 size = strlen(input_tx+1);

                 tx = malloc(size);

                 rx = malloc(size);

                 size = unescape((char *)tx, input_tx, size);

                        transfer(fd, tx, rx, size);

                        free(rx);

                        free(tx);

                 } else {

                              transfer(fd, default_tx, default_rx, sizeof(default_tx));

    }

    2.2). And simulate the spi transfer with a loop in the shell script, like: 

    #!/bin/sh
    while true
    do
    ./spi
    done 

    CPU load is 14%. Here is the explanation: 

    In user space a C program is executed at several hundred KHz speed. So, when you call the spidev_test.c WITH a while loop in it the loop increments with a speed approximately equal to the spi tranfer executed by the transfer() call, so CPU waits for the transfer (since they are equally fast) which loads the processor. 

    On the other hand a shell script is executed far more slower (several KHz speed), so when the shell script steps in the transfer() it takes longer time to go to the next call in the spidev_test.c & the spi transfer is executed by then => cpu does not wait. 

    The behavior is similar in your case: 
    When working with 400KHz spi transfer speed, the spidev_test.c is executed equally fast as the spi transfer => cpu waits & is loaded. 

    When working with 24MHz spi transfer speed, the spidev_test.c takes longer to step through the calls, allowing the transfer() to execute while the pc steps over the program. 

    Hope this helps. 

    Best Regards, 
    Yordan

  • Dear All,

    Thank you for kindly help.
  • Hi Yordan,

    Thank you very much for your detailed explanation~

    The problem we faced and the test you've done, actually has a little different.

    In your test, calling the transfer() in a while loop without any delay.

    In our test, we put a 5ms delay after calling transfer().

    The transfer function sends 38-byte data with a 5MHz speed.

    The time for transmission would take about 0.07ms. (1/5MHz * 8-bit * 38-byte), so we think, to put a 5ms delay should be enough.

    But we still can see the CPU loading on spi1 is still quite high, 9.4%.

    The purpose of the test is to simulate controlling a low speed OLED panel. A short delay between two commands is necessary.

    Can you give us some advice to lower the CPU loading? 

    Regards,

    Max

  • Hi Max,

    I did the same test on my side (BBB, running SDK2.0 kernel 4.1).

    Modified the transfer() call as:

    static void transfer(int fd)

    {

    int ret;

           static const useconds_t _5ms = 5000;

           uint8_t tx[] = {

                    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

                   0x40, 0x00, 0x00, 0x00, 0x00, 0x95,

                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

                   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,

                   0xF0, 0x0D,

           };

           uint8_t rx[ARRAY_SIZE(tx)] = {0, };        

    I tested two options:

    1) delay in the while(1) loop:

     if (input_tx) {

    size = strlen(input_tx+1);

    tx = malloc(size);

    rx = malloc(size);

    size = unescape((char *)tx, input_tx, size);

                  while (1) {

      //transfer(fd, tx, rx, size);

                      transfer(fd);

      free(rx);

      free(tx);

                      //usleep(_5ms);

                  }

    } else {

                   while (1) {

      //transfer(fd, default_tx, default_rx, sizeof(default_tx));

                      transfer(fd);

                      //usleep(_5ms);

                   }

    }

    2). Delay in the transfer() function: 

    int ret;
    static const useconds_t _5ms = 5000;

    uint8_t tx[] = {
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 

    ........................

    ........................

    ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
    if (ret < 1)
       pabort("can't send spi message");
    usleep(_5ms);

    In both cases I see 1% cpu load for ./spi -s 5000000 & 2% cpu load for [spi1] : 

    Best Regards, 
    Yordan

  • On kernel 3.14 (SDK8.0) I see the following cpu load:

    Mem: 117100K used, 391996K free, 0K shrd, 692324K buff, 692368K cached

    CPU:   0% usr   5% sys   0% nic  94% idle   0% io   0% irq   0% sirq

    Load average: 0.27 0.52 0.30 1/59 2078

     PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND

     630     2     root          SW       0        0%      3%   [spi1]

    2073  2069 root           S      1172     0%       1% ./SPIDEV

    Best Regards,

    Yordan

  • Hi Yordan,

    Thanks~
    My linux kernel is 3.14.57 with RT patch, that is different with yours.
    I'm going to update SDK and linux kernel.
    Update you soon.

    Is this the right SDK?
    software-dl.ti.com/.../index_FDS.html

    Regards,
    Max
  • Hi Max,

    Yes, this is the right SDK.

    Best Regards,
    Yordan