• 设备驱动的异步加载 —— 示例分析(1)


    作者

    彭东林
    pengdonglin137@163.com
     

    平台

    Linux-4.10.17
    Qemu2.8 + vexpress-a9
     

    概述

        在系统开机probe驱动的时候,有些设备驱动加载可能需要比较长的时间,尤其是像i2c这样的设备,总线速率较低,如果在probe时读写大量的寄存器的话,会使系统的开机速度变长。针对这个问题,Linux内核提供了驱动异步的加载机制,当然在使用时也有一些限制,比如挂载同一条总线下的设备驱动加载只能串行等等,此外,如果设备的驱动之间存在依赖关系,那么也要慎用。
        下面是Linux内核里引入驱动异步加载的几个patch:
     
            765230b5f084863183aa8adb3405ab3f32c0b16e
            f2411da746985e60d4d087f3a43e271c61785927
            d173a137c5bd95ee29d02705e5fa8890ef149718
     
    引用提交记录中对设备驱动异步加载的解释:
        Some devices take a long time when initializing, and not all drivers are
        suited to initialize their devices when they are open. For example,
        input drivers need to interrogate their devices in order to publish
        device's capabilities before userspace will open them. When such drivers
        are compiled into kernel they may stall entire kernel initialization.
        
        This change allows drivers request for their probe functions to be
        called asynchronously during driver and device registration (manual
        binding is still synchronous). Because async_schedule is used to perform
        asynchronous calls module loading will still wait for the probing to
        complete.
        
        Note that the end goal is to make the probing asynchronous by default,
        so annotating drivers with PROBE_PREFER_ASYNCHRONOUS is a temporary
        measure that allows us to speed up boot process while we validating and
        fixing the rest of the drivers and preparing userspace.
    下面用两个示例说明一下,一个是基于platform的,另一个是基于i2c的。
    涉及到代码可以到下面的链接下载:https://github.com/pengdonglin137/async_drv_load_demo
     

    正文

    一、I2C从设备驱动的异步加载

            这里只关心调用驱动probe的顺序,不关心具体驱动的功能。在设备树里添加4个I2C控制器节点,在第1组I2C控制器下挂两个从设备,目的是观察同一条I2C总线下的从设备驱动的加载顺序,其他三个I2C控制器下面各挂一个从设备,目的是观察不同I2C总线下的从设备驱动的异步加载顺序。为了方便,在驱动probe函数中添加了msleep函数。
            由于在下面的例子中,设备树的解析时间较早,也就是在注册驱动时,对应的device早已经存在了,所以主要分析注册驱动后,驱动找设备的情形。
    • 设备树

    I2C控制器1,下面挂了两个从设备:
        async_demo1_i2c: i2c@20000 {
            compatible = "arm,versatile-i2c";
            reg = <0x20000 0x1000>;
            #address-cells = <1>;
            #size-cells = <0>;
    
            async_demo1@39 {
                compatible = "async_demo1_i2c";
                reg = <0x39>;
                status = "okay";
            };
    
            async_demo1@3a {
                compatible = "async_demo5_i2c";
                reg = <0x3a>;
                status = "okay";
            };
        };
    其他三个I2C控制器,每个下面各挂一个从设备:
        async_demo2_i2c: i2c@30000 {
            compatible = "arm,versatile-i2c";
            reg = <0x30000 0x1000>;
    
            #address-cells = <1>;
            #size-cells = <0>;
    
            async_demo2@39 {
                compatible = "async_demo2_i2c";
                reg = <0x39>;
                status = "okay";
            };
    
        };
    
        async_demo3_i2c: i2c@40000 {
            compatible = "arm,versatile-i2c";
            reg = <0x40000 0x1000>;
    
            #address-cells = <1>;
            #size-cells = <0>;
    
            async_demo3@39 {
                compatible = "async_demo3_i2c";
                reg = <0x39>;
                status = "okay";
            };
    
        };
    
        async_demo4_i2c: i2c@50000 {
            compatible = "arm,versatile-i2c";
            reg = <0x50000 0x1000>;
    
            #address-cells = <1>;
            #size-cells = <0>;
    
            async_demo4@39 {
                compatible = "async_demo4_i2c";
                reg = <0x39>;
                status = "okay";
            };
    
        };

    上面是三个I2C控制器,具体每个I2C控制的reg属性是随意指定的,只要跟其他设备不冲突就行,因为这里只关心驱动的probe。

     
    • 设备驱动

    设备1对应的驱动probe中睡眠4s,并probe_type为PROBE_PREFER_ASYNCHRONOUS:
     1 static int async_demo1_probe(struct i2c_client *i2c,
     2              const struct i2c_device_id *id)
     3 {
     4     printk("%s enter
    ", __func__);
     5     msleep(4000);
     6     printk("%s exit
    ", __func__);
     7     return 0;
     8 }
     9 
    10 static struct i2c_driver async_demo1_i2c_driver = {
    11     .probe            = async_demo1_probe,
    12     .remove         = async_demo1_remove,
    13     .id_table       = async_demo1_i2c_id,
    14     .driver         = {
    15         .name           = "async_demo1_i2c",
    16         .of_match_table = async_demo1_i2c_dt_ids,
    17 #ifdef USE_ASYNC
    18         .probe_type = PROBE_PREFER_ASYNCHRONOUS,
    19 #else
    20         .probe_type = PROBE_FORCE_SYNCHRONOUS,
    21 #endif
    22     },
    23 };
    其他几个设备2、3、4、5的驱动中将probe_type也设置为PROBE_PREFER_ASYNCHRONOUS,在probe函数中分别延迟3s、2s、1s和100ms。
    为了对比,用宏USE_ASYNC来控制是否驱动是否支持异步加载,如果没有定义,那么probe_type就是PROBE_FORCE_SYNCHRONOUS,表示使用同步加载。否则设置为PROBE_PREFER_ASYNCHRONOUS,即使用异步加载。
     
    • 验证

    先看看同步加载驱动的耗时:
     1 [root@vexpress mnt]# insmod async_demo_i2c.ko 
     2 [ 5099.103927] [ 1|  871|         insmod] async_demo_i2c_init enter.
     3 [ 5099.104108] [ 1|  871|         insmod] before async_demo1_i2c
     4 [ 5099.104312] [ 1|  871|         insmod] __driver_attach enter, dev: 2-0039
     5 [ 5099.104466] [ 1|  871|         insmod] bus: 'i2c': driver_probe_device: matched device 2-0039 with driver async_demo1_i2c
     6 [ 5099.104798] [ 1|  871|         insmod] async_demo1_probe enter
     7 [ 5102.861699] [ 1|  871|         insmod] async_demo1_probe exit
     8 [ 5102.862238] [ 1|  871|         insmod] bus_add_driver exit.
     9 [ 5102.862465] [ 1|  871|         insmod] before async_demo2_i2c
    10 [ 5102.862663] [ 1|  871|         insmod] __driver_attach enter, dev: 3-0039
    11 [ 5102.862794] [ 1|  871|         insmod] bus: 'i2c': driver_probe_device: matched device 3-0039 with driver async_demo2_i2c
    12 [ 5102.863064] [ 1|  871|         insmod] async_demo2_probe enter
    13 [ 5105.706465] [ 1|  871|         insmod] async_demo2_probe exit
    14 [ 5105.707067] [ 1|  871|         insmod] bus_add_driver exit.
    15 [ 5105.707317] [ 1|  871|         insmod] before async_demo3_i2c
    16 [ 5105.707516] [ 1|  871|         insmod] __driver_attach enter, dev: 4-0039
    17 [ 5105.707652] [ 1|  871|         insmod] bus: 'i2c': driver_probe_device: matched device 4-0039 with driver async_demo3_i2c
    18 [ 5105.707939] [ 1|  871|         insmod] async_demo3_probe enter
    19 [ 5107.652718] [ 1|  871|         insmod] async_demo3_probe exit
    20 [ 5107.653142] [ 1|  871|         insmod] bus_add_driver exit.
    21 [ 5107.653398] [ 1|  871|         insmod] before async_demo4_i2c
    22 [ 5107.653653] [ 1|  871|         insmod] __driver_attach enter, dev: 5-0039
    23 [ 5107.653852] [ 1|  871|         insmod] bus: 'i2c': driver_probe_device: matched device 5-0039 with driver async_demo4_i2c
    24 [ 5107.654243] [ 1|  871|         insmod] async_demo4_probe enter
    25 [ 5108.625550] [ 1|  871|         insmod] async_demo4_probe exit
    26 [ 5108.626019] [ 1|  871|         insmod] bus_add_driver exit.
    27 [ 5108.626219] [ 1|  871|         insmod] before async_demo5_i2c
    28 [ 5108.626460] [ 1|  871|         insmod] __driver_attach enter, dev: 2-003a
    29 [ 5108.626604] [ 1|  871|         insmod] bus: 'i2c': driver_probe_device: matched device 2-003a with driver async_demo5_i2c
    30 [ 5108.626896] [ 1|  871|         insmod] async_demo5_probe enter
    31 [ 5108.738170] [ 1|  871|         insmod] async_demo5_probe exit
    32 [ 5108.738635] [ 1|  871|         insmod] bus_add_driver exit.
    可以看到,从开始加载到最后加载完毕,耗时9.6s左右,也就是每个驱动probe耗时的累加。上面的驱动的probe被调用的顺序跟驱动的注册顺序相同,先注册的先被调用,串行进行,而且自始至总都在insmod这一个进程的上下文中。
     
    再看看异步加载的情况:
     1 [root@vexpress mnt]# insmod async_demo_i2c.ko 
     2 [ 5487.522979] [ 2|  886|         insmod] async_demo_i2c_init enter.
     3 [ 5487.523168] [ 2|  886|         insmod] before async_demo1_i2c
     4 [ 5487.523379] [ 2|  886|         insmod] bus: 'i2c': probing driver async_demo1_i2c asynchronously
     5 [ 5487.523817] [ 2|  886|         insmod] bus_add_driver exit.
     6 [ 5487.524034] [ 2|  886|         insmod] before async_demo2_i2c
     7 [ 5487.524227] [ 2|  886|         insmod] bus: 'i2c': probing driver async_demo2_i2c asynchronously
     8 [ 5487.524545] [ 2|  886|         insmod] bus_add_driver exit.
     9 [ 5487.524759] [ 2|  886|         insmod] before async_demo3_i2c
    10 [ 5487.524949] [ 2|  886|         insmod] bus: 'i2c': probing driver async_demo3_i2c asynchronously
    11 [ 5487.525248] [ 2|  886|         insmod] bus_add_driver exit.
    12 [ 5487.525448] [ 2|  886|         insmod] before async_demo4_i2c
    13 [ 5487.525642] [ 2|  886|         insmod] bus: 'i2c': probing driver async_demo4_i2c asynchronously
    14 [ 5487.525951] [ 2|  886|         insmod] bus_add_driver exit.
    15 [ 5487.526177] [ 2|  886|         insmod] before async_demo5_i2c
    16 [ 5487.526421] [ 2|  886|         insmod] bus: 'i2c': probing driver async_demo5_i2c asynchronously
    17 [ 5487.526728] [ 2|  886|         insmod] bus_add_driver exit.
    18 [ 5487.527397] [ 0|  858|   kworker/u8:3] driver_attach_async enter.
    19 [ 5487.527627] [ 0|  858|   kworker/u8:3] __driver_attach enter, dev: 2-0039
    20 [ 5487.527822] [ 0|  858|   kworker/u8:3] bus: 'i2c': driver_probe_device: matched device 2-0039 with driver async_demo1_i2c
    21 [ 5487.528246] [ 0|  858|   kworker/u8:3] async_demo1_probe enter
    22 [ 5487.531002] [ 0|  735|   kworker/u8:4] driver_attach_async enter.
    23 [ 5487.531236] [ 0|  735|   kworker/u8:4] __driver_attach enter, dev: 3-0039
    24 [ 5487.531431] [ 0|  735|   kworker/u8:4] bus: 'i2c': driver_probe_device: matched device 3-0039 with driver async_demo2_i2c
    25 [ 5487.532741] [ 3|  888|   kworker/u8:0] driver_attach_async enter.
    26 [ 5487.532968] [ 3|  888|   kworker/u8:0] __driver_attach enter, dev: 4-0039
    27 [ 5487.533162] [ 3|  888|   kworker/u8:0] bus: 'i2c': driver_probe_device: matched device 4-0039 with driver async_demo3_i2c
    28 [ 5487.533647] [ 3|  888|   kworker/u8:0] async_demo3_probe enter
    29 [ 5487.534076] [ 3|  890|   kworker/u8:1] driver_attach_async enter.
    30 [ 5487.534291] [ 3|  890|   kworker/u8:1] __driver_attach enter, dev: 5-0039
    31 [ 5487.534505] [ 3|  890|   kworker/u8:1] bus: 'i2c': driver_probe_device: matched device 5-0039 with driver async_demo4_i2c
    32 [ 5487.534865] [ 3|  890|   kworker/u8:1] async_demo4_probe enter
    33 [ 5487.535282] [ 3|  892|   kworker/u8:2] driver_attach_async enter.
    34 [ 5487.535488] [ 3|  892|   kworker/u8:2] __driver_attach enter, dev: 2-003a
    35 [ 5487.539944] [ 0|  735|   kworker/u8:4] async_demo2_probe enter
    36 [ 5488.514837] [ 3|  890|   kworker/u8:1] async_demo4_probe exit
    37 [ 5488.515209] [ 3|  890|   kworker/u8:1] bus: 'i2c': driver async_demo4_i2c async attach completed: 0
    38 [ 5489.488056] [ 3|  888|   kworker/u8:0] async_demo3_probe exit
    39 [ 5489.488394] [ 3|  888|   kworker/u8:0] bus: 'i2c': driver async_demo3_i2c async attach completed: 0
    40 [ 5490.384618] [ 0|  735|   kworker/u8:4] async_demo2_probe exit
    41 [ 5490.384894] [ 0|  735|   kworker/u8:4] bus: 'i2c': driver async_demo2_i2c async attach completed: 0
    42 [ 5491.282840] [ 0|  858|   kworker/u8:3] async_demo1_probe exit
    43 [ 5491.283172] [ 0|  858|   kworker/u8:3] bus: 'i2c': driver async_demo1_i2c async attach completed: 0
    44 [ 5491.283724] [ 3|  892|   kworker/u8:2] bus: 'i2c': driver_probe_device: matched device 2-003a with driver async_demo5_i2c
    45 [ 5491.284663] [ 3|  892|   kworker/u8:2] async_demo5_probe enter
    46 [ 5491.396770] [ 3|  892|   kworker/u8:2] async_demo5_probe exit
    47 [ 5491.397074] [ 3|  892|   kworker/u8:2] bus: 'i2c': driver async_demo5_i2c async attach completed: 0
    可以看到,驱动加载耗时3.9s左右,其实也就是耗时probe耗时最长的那个驱动的时间,看到异步加载的强大了吧。此外,由于demo5和demo1挂载在一个I2C控制器下,即便驱动里支持异步,但是从结果来看还是是串行的。上面第二个中括号中数字的含义 [处理器编号 | 进程PID | 进程名称]
      在异步加载情形下,驱动注册时,先在insmod进程的上下文,然后发现可以支持异步,就会启动一个后台内核线程来负责接下来的加载任务,上面先后出现了5个内核线程。上面的kworker/u8:n都是内核线程,属于内核工作队列的知识,关于内核工作队列可以阅读笨叔叔的《奔跑吧Linux内核》的5.3节,顺便学习一个笨叔叔在书中传授的关于Linux内核里CMWQ的一个知识点:
     
            CMWQ机制会动态地调整一个线程池中工作线程的执行情况,不会因为某个work回调函数执行了阻塞操作而影响整个线程池中其他work的执行。
     
    上面的例子也充分说明了这一点。
     

    二、platform设备驱动的异步加载

      对于platform总线上的设备来说有些特殊,即便驱动里将probe_type设置为了PROBE_PREFER_ASYNCHRONOUS,但是如果先注册device,再注册driver的话还是串行进行,原因是driver在attach到device时,会先device_lock(dev->parent),然后再去probe。对于platform总线上的device,其dev->parent都指向platform_bus,所以虽然从log上看,确实是由内核线程负责加载驱动的,但是由于锁的原因,表现出来的还是串行,这一点我觉得应该可以优化。如果是先注册driver,后注册device的话,是可以异步的,原因是没有调用device_lock(dev->parent)。
     

    1、device找driver的情形

    跟前面类似,有四个platform_driver,第1个platform_driver的probe里睡4s,第2、3和4个分别睡3s、2s和1s。在驱动模块init时,先注册platform_driver,再注册platform_device。下面是部分示例驱动:
     1 static struct platform_driver async_demo4_v2_driver = {
     2     .probe        = async_demo4_v2_probe,
     3     .remove        = async_demo4_v2_remove,
     4     .driver        = {
     5         .name    = "async_demo4_v2",
     6         .of_match_table = of_match_ptr(async_demo4_v2_dt_ids),
     7 #ifdef USE_ASYNC
     8         .probe_type = PROBE_PREFER_ASYNCHRONOUS,
     9 #else
    10         .probe_type = PROBE_FORCE_SYNCHRONOUS,
    11 #endif
    12     },
    13 };
    14 
    15 static struct platform_device *pdev[4];
    16 
    17 static __init int async_demo_init(void)
    18 {
    19     printk("%s enter.
    ", __func__);
    20 
    21     printk("Register Platform Driver
    ");
    22     platform_driver_register(&async_demo1_v2_driver);
    23     platform_driver_register(&async_demo2_v2_driver);
    24     platform_driver_register(&async_demo3_v2_driver);
    25     platform_driver_register(&async_demo4_v2_driver);
    26 
    27     printk("
    
     Register Platform Device
    ");
    28     pdev[0] = platform_device_register_simple("async_demo1_v2", 0, NULL, 0);
    29     pdev[1] = platform_device_register_simple("async_demo2_v2", 0, NULL, 0);
    30     pdev[2] = platform_device_register_simple("async_demo3_v2", 0, NULL, 0);
    31     pdev[3] = platform_device_register_simple("async_demo4_v2", 0, NULL, 0);
    32 
    33     return 0;
    34 }
     
    先看同步加载的耗时:
     1 [root@vexpress mnt]# insmod async_demo_v2.ko 
     2 [   49.125194] [ 2|  830|         insmod] async_demo_init enter.
     3 [   49.125382] [ 2|  830|         insmod] Register Platform Driver
     4 [   49.125834] [ 2|  830|         insmod] bus_add_driver exit.
     5 [   49.126256] [ 2|  830|         insmod] bus_add_driver exit.
     6 [   49.126665] [ 2|  830|         insmod] bus_add_driver exit.
     7 [   49.127065] [ 2|  830|         insmod] bus_add_driver exit.
     8 [   49.127218] [ 2|  830|         insmod] 
     9 [   49.127218] [ 2|  830|         insmod] 
    10 [   49.127218] [ 2|  830|         insmod]  Register Platform Device
    11 [   49.127760] [ 2|  830|         insmod] bus: 'platform': driver_probe_device: matched device async_demo1_v2.0 with driver async_demo1_v2
    12 [   49.128085] [ 2|  830|         insmod] async_demo1_v2_probe: parent platform
    13 [   49.128232] [ 2|  830|         insmod] async_demo1_v2_probe enter.
    14 [   52.900810] [ 2|  830|         insmod] async_demo1_v2_probe exit.
    15 [   52.901450] [ 2|  830|         insmod] bus: 'platform': driver_probe_device: matched device async_demo2_v2.0 with driver async_demo2_v2
    16 [   52.901819] [ 2|  830|         insmod] async_demo2_v2_probe: parent platform
    17 [   52.902015] [ 2|  830|         insmod] async_demo2_v2_probe enter.
    18 [   55.750675] [ 2|  830|         insmod] async_demo2_v2_probe exit.
    19 [   55.751344] [ 2|  830|         insmod] bus: 'platform': driver_probe_device: matched device async_demo3_v2.0 with driver async_demo3_v2
    20 [   55.751631] [ 2|  830|         insmod] async_demo3_v2_probe enter.
    21 [   57.700598] [ 2|  830|         insmod] async_demo3_v2_probe exit.
    22 [   57.701227] [ 2|  830|         insmod] bus: 'platform': driver_probe_device: matched device async_demo4_v2.0 with driver async_demo4_v2
    23 [   57.701509] [ 2|  830|         insmod] async_demo4_v2_probe enter.
    24 [   58.675576] [ 2|  830|         insmod] async_demo4_v2_probe exit.
    耗时9.5s左右
     
    看看异步的耗时:
     1 [root@vexpress mnt]# insmod async_demo_v2.ko 
     2 [  360.852433] [ 1|  878|         insmod] async_demo_init enter.
     3 [  360.852618] [ 1|  878|         insmod] Register Platform Driver
     4 [  360.852808] [ 1|  878|         insmod] bus: 'platform': probing driver async_demo1_v2 asynchronously
     5 [  360.853108] [ 1|  878|         insmod] bus_add_driver exit.
     6 [  360.853327] [ 1|  878|         insmod] bus: 'platform': probing driver async_demo2_v2 asynchronously
     7 [  360.853608] [ 1|  878|         insmod] bus_add_driver exit.
     8 [  360.853831] [ 1|  878|         insmod] bus: 'platform': probing driver async_demo3_v2 asynchronously
     9 [  360.854090] [ 1|  878|         insmod] bus_add_driver exit.
    10 [  360.854287] [ 1|  878|         insmod] bus: 'platform': probing driver async_demo4_v2 asynchronously
    11 [  360.854568] [ 1|  878|         insmod] bus_add_driver exit.
    12 [  360.854727] [ 1|  878|         insmod] 
    13 [  360.854727] [ 1|  878|         insmod] 
    14 [  360.854727] [ 1|  878|         insmod]  Register Platform Device
    15 [  360.855376] [ 1|  878|         insmod] platform async_demo1_v2.0: scheduling asynchronous probe
    16 [  360.855835] [ 1|  878|         insmod] platform async_demo2_v2.0: scheduling asynchronous probe
    17 [  360.856274] [ 1|  878|         insmod] platform async_demo3_v2.0: scheduling asynchronous probe
    18 [  360.857174] [ 0|  852|   kworker/u8:0] driver_attach_async enter.
    19 [  360.857537] [ 0|  852|   kworker/u8:0] __driver_attach enter, dev: async_demo1_v2.0
    20 [  360.857712] [ 0|  852|   kworker/u8:0] bus: 'platform': driver_probe_device: matched device async_demo1_v2.0 with driver async_demo1_v2
    21 [  360.858984] [ 0|  852|   kworker/u8:0] async_demo1_v2_probe: parent platform
    22 [  360.859267] [ 0|  852|   kworker/u8:0] async_demo1_v2_probe enter.
    23 [  360.859571] [ 0|  854|   kworker/u8:1] driver_attach_async enter.
    24 [  360.859876] [ 0|  854|   kworker/u8:1] __driver_attach enter, dev: async_demo2_v2.0
    25 [  360.860130] [ 0|   50|   kworker/u8:2] driver_attach_async enter.
    26 [  360.860412] [ 0|   50|   kworker/u8:2] __driver_attach enter, dev: async_demo3_v2.0
    27 [  360.866237] [ 1|  878|         insmod] platform async_demo4_v2.0: scheduling asynchronous probe
    28 [  360.866985] [ 2|  856|   kworker/u8:3] driver_attach_async enter.
    29 [  360.867361] [ 2|  856|   kworker/u8:3] __driver_attach enter, dev: async_demo4_v2.0
    30 [  360.868341] [ 3|  858|   kworker/u8:5] __device_attach_async_helper enter.
    31 [  360.869812] [ 1|  292|   kworker/u8:4] __device_attach_async_helper enter.
    32 [  360.870003] [ 1|  292|   kworker/u8:4] bus: 'platform': driver_probe_device: matched device async_demo2_v2.0 with driver async_demo2_v2
    33 [  360.870296] [ 1|  292|   kworker/u8:4] async_demo2_v2_probe: parent platform
    34 [  360.870423] [ 1|  292|   kworker/u8:4] async_demo2_v2_probe enter.
    35 [  360.870882] [ 1|  863|   kworker/u8:7] __device_attach_async_helper enter.
    36 [  360.871057] [ 1|  863|   kworker/u8:7] bus: 'platform': driver_probe_device: matched device async_demo3_v2.0 with driver async_demo3_v2
    37 [  360.871365] [ 1|  863|   kworker/u8:7] async_demo3_v2_probe enter.
    38 [  360.897155] [ 3|  861|   kworker/u8:6] __device_attach_async_helper enter.
    39 [  360.897380] [ 3|  861|   kworker/u8:6] bus: 'platform': driver_probe_device: matched device async_demo4_v2.0 with driver async_demo4_v2
    40 [  360.897688] [ 3|  861|   kworker/u8:6] async_demo4_v2_probe enter.
    41 [  361.890088] [ 3|  861|   kworker/u8:6] async_demo4_v2_probe exit.
    42 [  361.890527] [ 3|  861|   kworker/u8:6] async_demo4_v2 async_demo4_v2.0: async probe completed
    43 [  362.789551] [ 1|  863|   kworker/u8:7] async_demo3_v2_probe exit.
    44 [  362.789885] [ 1|  863|   kworker/u8:7] async_demo3_v2 async_demo3_v2.0: async probe completed
    45 [  363.764507] [ 1|  292|   kworker/u8:4] async_demo2_v2_probe exit.
    46 [  363.764866] [ 1|  292|   kworker/u8:4] async_demo2_v2 async_demo2_v2.0: async probe completed
    47 [  364.662938] [ 0|  852|   kworker/u8:0] async_demo1_v2_probe exit.
    48 [  364.663276] [ 0|  852|   kworker/u8:0] bus: 'platform': driver async_demo1_v2 async attach completed: 0
    49 [  364.663581] [ 0|  854|   kworker/u8:1] bus: 'platform': driver async_demo2_v2 async attach completed: 0
    50 [  364.663845] [ 0|   50|   kworker/u8:2] bus: 'platform': driver async_demo3_v2 async attach completed: 0
    51 [  364.664372] [ 3|  858|   kworker/u8:5] async_demo1_v2 async_demo1_v2.0: async probe completed
    52 [  364.664692] [ 2|  856|   kworker/u8:3] bus: 'platform': driver async_demo4_v2 async attach completed: 0
    耗时3.8s左右。
     

    2、driver找device的情形 

    对于这种情况,只能改一下驱动,修改driver/base/dd.c:
     1 @@ -749,13 +752,17 @@ static int __driver_attach(struct device *dev, void *data)
     2          return ret;
     3      } /* ret > 0 means positive match */
     4  
     5 -    if (dev->parent)    /* Needed for USB */
     6 +    printk("%s enter, dev: %s
    ", __func__, dev_name(dev));
     7 +
     8 +    if (dev->parent && (dev->parent != &platform_bus))    /* Needed for USB */
     9          device_lock(dev->parent);
    10 +
    11      device_lock(dev);
    12      if (!dev->driver)
    13          driver_probe_device(drv, dev);
    14      device_unlock(dev);
    15 -    if (dev->parent)
    16 +
    17 +    if (dev->parent && (dev->parent != &platform_bus))    /* Needed for USB */
    18          device_unlock(dev->parent);
    19  
    20      return 0;
    也就是,当发现parent是platform_bus时,不调用device_lock。
     
    下面看一下同步的耗时:
     1 [root@vexpress mnt]# insmod async_demo.ko 
     2 [   21.384197] [ 1|  809|         insmod] async_demo: loading out-of-tree module taints kernel.
     3 [   21.389316] [ 1|  809|         insmod] async_demo_init enter.
     4 [   21.389462] [ 1|  809|         insmod] before async_demo1
     5 [   21.389829] [ 1|  809|         insmod] __driver_attach enter, dev: async_demo1
     6 [   21.389978] [ 1|  809|         insmod] bus: 'platform': driver_probe_device: matched device async_demo1 with driver async_demo1
     7 [   21.390302] [ 1|  809|         insmod] async_demo1_probe: parent platform
     8 [   21.390479] [ 1|  809|         insmod] async_demo1_probe enter.
     9 [   25.161960] [ 1|  809|         insmod] async_demo1_probe exit.
    10 [   25.162396] [ 1|  809|         insmod] bus_add_driver exit.
    11 [   25.162583] [ 1|  809|         insmod] before async_demo2
    12 [   25.162941] [ 1|  809|         insmod] __driver_attach enter, dev: async_demo2
    13 [   25.163091] [ 1|  809|         insmod] bus: 'platform': driver_probe_device: matched device async_demo2 with driver async_demo2
    14 [   25.163374] [ 1|  809|         insmod] async_demo2_probe: parent platform
    15 [   25.163517] [ 1|  809|         insmod] async_demo2_probe enter.
    16 [   28.017117] [ 1|  809|         insmod] async_demo2_probe exit.
    17 [   28.017622] [ 1|  809|         insmod] bus_add_driver exit.
    18 [   28.017863] [ 1|  809|         insmod] before async_demo3
    19 [   28.018244] [ 1|  809|         insmod] __driver_attach enter, dev: async_demo3
    20 [   28.018419] [ 1|  809|         insmod] bus: 'platform': driver_probe_device: matched device async_demo3 with driver async_demo3
    21 [   28.018736] [ 1|  809|         insmod] async_demo3_probe enter.
    22 [   29.970867] [ 1|  809|         insmod] async_demo3_probe exit.
    23 [   29.971283] [ 1|  809|         insmod] bus_add_driver exit.
    24 [   29.971509] [ 1|  809|         insmod] before async_demo4
    25 [   29.971893] [ 1|  809|         insmod] __driver_attach enter, dev: async_demo4
    26 [   29.972048] [ 1|  809|         insmod] bus: 'platform': driver_probe_device: matched device async_demo4 with driver async_demo4
    27 [   29.972341] [ 1|  809|         insmod] async_demo4_probe enter.
    28 [   30.947713] [ 1|  809|         insmod] async_demo4_probe exit.
    29 [   30.948153] [ 1|  809|         insmod] bus_add_driver exit.
    耗时9.6s左右
     
    下面是异步耗时:
     1 [  129.732599] [ 1|  822|         insmod] async_demo_init enter.
     2 [  129.732765] [ 1|  822|         insmod] before async_demo1
     3 [  129.732945] [ 1|  822|         insmod] bus: 'platform': probing driver async_demo1 asynchronously
     4 [  129.733311] [ 1|  822|         insmod] bus_add_driver exit.
     5 [  129.733461] [ 1|  822|         insmod] before async_demo2
     6 [  129.733611] [ 1|  822|         insmod] bus: 'platform': probing driver async_demo2 asynchronously
     7 [  129.733858] [ 1|  822|         insmod] bus_add_driver exit.
     8 [  129.734004] [ 1|  822|         insmod] before async_demo3
     9 [  129.734155] [ 1|  822|         insmod] bus: 'platform': probing driver async_demo3 asynchronously
    10 [  129.734385] [ 1|  822|         insmod] bus_add_driver exit.
    11 [  129.734524] [ 1|  822|         insmod] before async_demo4
    12 [  129.734676] [ 1|  822|         insmod] bus: 'platform': probing driver async_demo4 asynchronously
    13 [  129.734909] [ 1|  822|         insmod] bus_add_driver exit.
    14 [  129.735450] [ 3|  403|   kworker/u8:4] driver_attach_async enter.
    15 [  129.735772] [ 3|  403|   kworker/u8:4] __driver_attach enter, dev: async_demo1
    16 [  129.736095] [ 3|  403|   kworker/u8:4] bus: 'platform': driver_probe_device: matched device async_demo1 with driver async_demo1
    17 [  129.736430] [ 3|  403|   kworker/u8:4] async_demo1_probe: parent platform
    18 [  129.736570] [ 3|  403|   kworker/u8:4] async_demo1_probe enter.
    19 [  129.736818] [ 3|  262|   kworker/u8:3] driver_attach_async enter.
    20 [  129.737088] [ 3|  262|   kworker/u8:3] __driver_attach enter, dev: async_demo2
    21 [  129.737231] [ 3|  262|   kworker/u8:3] bus: 'platform': driver_probe_device: matched device async_demo2 with driver async_demo2
    22 [  129.737496] [ 3|  262|   kworker/u8:3] async_demo2_probe: parent platform
    23 [  129.737633] [ 3|  262|   kworker/u8:3] async_demo2_probe enter.
    24 [  129.745080] [ 2|   35|   kworker/u8:2] driver_attach_async enter.
    25 [  129.752320] [ 3|   28|   kworker/u8:1] driver_attach_async enter.
    26 [  129.764287] [ 2|   35|   kworker/u8:2] __driver_attach enter, dev: async_demo3
    27 [  129.764487] [ 2|   35|   kworker/u8:2] bus: 'platform': driver_probe_device: matched device async_demo3 with driver async_demo3
    28 [  129.764807] [ 2|   35|   kworker/u8:2] async_demo3_probe enter.
    29 [  129.765317] [ 3|   28|   kworker/u8:1] __driver_attach enter, dev: async_demo4
    30 [  129.765465] [ 3|   28|   kworker/u8:1] bus: 'platform': driver_probe_device: matched device async_demo4 with driver async_demo4
    31 [  129.765760] [ 3|   28|   kworker/u8:1] async_demo4_probe enter.
    32 [  130.733864] [ 3|   28|   kworker/u8:1] async_demo4_probe exit.
    33 [  130.734143] [ 3|   28|   kworker/u8:1] bus: 'platform': driver async_demo4 async attach completed: 0
    34 [  131.710647] [ 2|   35|   kworker/u8:2] async_demo3_probe exit.
    35 [  131.710940] [ 2|   35|   kworker/u8:2] bus: 'platform': driver async_demo3 async attach completed: 0
    36 [  132.612441] [ 3|  262|   kworker/u8:3] async_demo2_probe exit.
    37 [  132.612759] [ 3|  262|   kworker/u8:3] bus: 'platform': driver async_demo2 async attach completed: 0
    38 [  133.514075] [ 3|  403|   kworker/u8:4] async_demo1_probe exit.
    39 [  133.514386] [ 3|  403|   kworker/u8:4] bus: 'platform': driver async_demo1 async attach completed: 0

    耗时3.8s左右。

     
     
    未完待续……
  • 相关阅读:
    JSP中的选择判断 C 标签 一般与 foreach循环一块使用
    python基础学习笔记(四)
    python基础学习笔记(五)
    python基础学习笔记(六)
    python基础学习笔记(三)
    python基础学习笔记(一)
    selenium使用Xpath定位之完整篇
    Selenium Python FirefoxWebDriver处理打开保存对话框
    Selenium操作示例——鼠标悬停显示二级菜单,再点击二级菜单或下拉列表
    Selenium+Python:下载文件(Firefox 和 Chrome)
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/8215275.html
Copyright © 2020-2023  润新知