Hi,

This series introduce new uAPI(RPMSG_CREATE_EPT_FD_IOCTL) for rpmsg
subsystem.

Current uAPI implementation for rpmsg ctrl & char device manipulation is
abstracted in procedures below:
- fd = open("/dev/rpmsg_ctrlX")
- ioctl(fd, RPMSG_CREATE_EPT_IOCTL, &info); /dev/rpmsgY devnode is
  generated.
- fd_ep = open("/dev/rpmsgY", O_RDWR) 
- operations on fd_ep(write, read, poll ioctl)
- ioctl(fd_ep, RPMSG_DESTROY_EPT_IOCTL)
- close(fd_ep)
- close(fd)

This /dev/rpmsgY abstraction is less favorable for:
- Performance issue: It's time consuming for some operations are
invovled:
  - Device node creation.
    Depends on specific config, especially CONFIG_DEVTMPFS, the overall
    overhead is based on coordination between DEVTMPFS and userspace
    tools such as udev and mdev.

  - Extra kernel-space switch cost.

  - Other major costs brought by heavy-weight logic like device_add().

- /dev/rpmsgY node can be opened only once. It doesn't make much sense
    that a dynamically created device node can be opened only once.

- For some container application such as docker, a client can't access
  host's dev unless specified explicitly. But in case of /dev/rpmsgY, which
  is generated dynamically and whose existence is unknown for clients in
  advance, this uAPI based on device node doesn't fit well.

An anon inode based approach is introduced to address the issues above.
Rather than generating device node and opening it, rpmsg code just make
a anon inode representing eptdev and return the fd to userspace.

# Performance demo

An simple C application is tested to verify performance of new uAPI.

$ cat test.c

#include <linux/rpmsg.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/time.h>

#define N (1 << 20)

int main(int argc, char *argv[])
{
        int ret, fd, ep_fd, loop;
        struct rpmsg_endpoint_info info; 
        struct rpmsg_endpoint_fd_info fd_info; 
        struct timeval start, end;
        int i = 0;
        double t1, t2;

        fd = -1;
        ep_fd = -1;
        loop = N;

        if (argc == 1) {
                loop = N;
        } else if (argc > 1) {
                loop = atoi(argv[1]);
        }

        printf("loop[%d]\n", loop);

        strcpy(info.name, "epx");
        info.src = -1;
        info.dst = -1;

        strcpy(fd_info.name, "epx");
        fd_info.src = -1;
        fd_info.dst = -1;
        fd_info.fd = -1;

        while (fd < 0) {
                fd = open("/dev/rpmsg_ctrl0", O_RDWR);
                if (fd < 0) {
                        printf("open rpmsg_ctrl0 failed, fd[%d]\n", fd);
                }
        }

        gettimeofday(&start, NULL);

        while (loop--) {
                ret = ioctl(fd, RPMSG_CREATE_EPT_IOCTL, &info);
                if (ret < 0) {
                        printf("ioctl[RPMSG_CREATE_EPT_IOCTL] failed, 
ret[%d]\n", ret);
                }

                ep_fd = -1;
                i = 0;

                while (ep_fd < 0) {
                        ep_fd = open("/dev/rpmsg0", O_RDWR);
                        if (ep_fd < 0) {
                                i++;
                                printf("open rpmsg0 failed, epfd[%d]\n", ep_fd);
                        }
                }

                //printf("Number of open failed[%d]\n", i);

                ret = ioctl(ep_fd, RPMSG_DESTROY_EPT_IOCTL, &info);
                if (ret < 0) {
                        printf("old ioctl[RPMSG_DESTROY_EPT_IOCTL] failed, 
ret[%d], errno[%d]\n",
                                ret, errno);
                }

                close(ep_fd);
        }
        
        gettimeofday(&end, NULL);

        printf("time for old way: [%ld] us\n", 1000000 * (end.tv_sec - 
start.tv_sec) + end.tv_usec - start.tv_usec);
        t1 = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - 
start.tv_usec;

        if (argc == 1) {
                loop = N;
        } else if (argc > 1) {
                loop = atoi(argv[1]);
        }

        printf("loop[%d]\n", loop);

        gettimeofday(&start, NULL);

        while (loop--) {
                fd_info.fd = -1;
                ret = ioctl(fd, RPMSG_CREATE_EPT_FD_IOCTL, &fd_info);
                if (ret < 0 || fd_info.fd < 0) {
                        printf("ioctl[RPMSG_CREATE_EPT_FD_IOCTL] failed, 
ret[%d]\n", ret);
                }

                ret = ioctl(fd_info.fd, RPMSG_DESTROY_EPT_IOCTL, &info);
                if (ret < 0) {
                        printf("new ioctl[RPMSG_DESTROY_EPT_IOCTL] failed, 
ret[%d]\n", ret);
                }

                close(fd_info.fd);
        }
        
        gettimeofday(&end, NULL);

        printf("time for new way: [%ld] us\n", 1000000 * (end.tv_sec - 
start.tv_sec) + end.tv_usec - start.tv_usec);
        t2 = 1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - 
start.tv_usec;

        printf("t1(old) / t2(new) = %f\n", t1 / t2);

        close(fd);
}

# Performance benchmark 

- Legacy means benchmark based on old uAPI
- New means benchmark based on new uAPI(the one this series introduce)
- Time are in units of us(10^-6 s)

Test    loops   Total time(legacy)      Total time(new) legacy/new      
1       1000    203227                  2533            80.2    
2       1000    196501                  2384            82.4
3       1000    213619                  2518            84.8
4       1000    215898                  2515            85.8
5       1000    211340                  2417            87.4
6       1000    217008                  2545            85.2
7       1000    213591                  2478            86.1
8       1000    214618                  2351            91.2
9       1000    208021                  2505            83.0
10      1000    217092                  2716            79.9    
11      10000   2040802                 26765           76.2
12      10000   2027708                 26867           75.4
13      10000   1986117                 27151           73.1
14      10000   1992956                 26301           75.7
15      10000   1980262                 25808           76.7
16      10000   1925883                 27926           68.9    
17      10000   1957518                 27100           72.2
18      10000   1980626                 28020           70.6
19      10000   1990349                 27351           72.7
20      10000   1979087                 27563           71.8
21      100000  20266414                256170          79.1
22      100000  19732259                259883          75.9
23      100000  19878399                253710          78.3    
24      100000  19788886                257199          76.9
25      100000  19937663                258865          77.0
26      100000  19602512                256771          76.3
27      100000  19599214                257088          76.2
28      100000  19795920                261488          75.7
29      100000  19719341                263299          74.8
30      100000  19871390                258465          76.8

Dawei Li (3):
  rpmsg: char: Reuse eptdev logic for anon device
  rpmsg: char: Implement eptdev based on anon inode
  rpmsg: ctrl: Introduce RPMSG_CREATE_EPT_FD_IOCTL uAPI

 drivers/rpmsg/rpmsg_char.c | 124 ++++++++++++++++++++++++++++++-------
 drivers/rpmsg/rpmsg_char.h |  19 ++++++
 drivers/rpmsg/rpmsg_ctrl.c |  37 ++++++++---
 include/uapi/linux/rpmsg.h |  19 ++++++
 4 files changed, 167 insertions(+), 32 deletions(-)

---
base-commit: 92a09c47464d040866cf2b4cd052bc60555185fb

Thanks,

        Dawei
-- 
2.25.1


Reply via email to