linux -- 启动分析及耗时分析

来源:互联网 发布:剑三萝莉女神捏脸数据 编辑:程序博客网 时间:2024/06/06 14:04
入口:start_kernel(kernel/init/main.c) {        char *command_line;        char *after_dashes;    lockdep_init() /* ? 初始化lockdep hash 表 or 系统哈希表chainhash_table ? */    set_task_stack_end_magic()    smp_setup_processor_id(kernel/arch/arm/kernel/setup.c) /*当只有一个CPU的时候这个函数就什么都不做,但是如果有多个CPU的时候那么它就 返回在启动的时候的那个CPU的号  */        [    0.000000] Booting Linux on physical CPU 0x500    debug_objects_early_init() //初始化debug kernel相关    boot_init_stack_canary() //初始化栈canary值,canary值防止栈溢出攻击, stack_canary是带防止栈溢出攻击保护的堆栈。    cgroup_init_early(kernel/kernel/cgroup.c) //Cgroup初始化,将一组任务在一个或多个子系统中与一组参数关联.Cgroup是近代linux kernel出现的.它为进程和其后续的子进程提供了一种性能控制机制        --> cgroup_init_subsys            [    0.000000] Initializing cgroup subsys cpuset            [    0.000000] Initializing cgroup subsys cpu            [    0.000000] Initializing cgroup subsys cpuacct    local_irq_disable()  /*关闭当前CPU的中断*/    boot_cpu_init() //对于CPU核的系统来说,设置第一个CPU核为活跃CPU核。对于单CPU核系统来说,设置CPU核为活跃CPU核    pr_notice("%s", linux_banner);        [    0.000000] Linux version 4.4.41 (feizhitao@feizhitao-All-Series) (gcc version 4.8.4 (Ubuntu/Linaro 4.8.4-2ubuntu1~14.04.1) ) #5 SMP Thu May 11 13:54:33 CST 2017        /*每种体系结构都有自己的setup_arch()函数,是体系结构相关的,具体编译哪个 体系结构的setup_arch()函数,由源码树顶层目录下的Makefile中的ARCH变量决定           例如: ARM体系结构的。          SUBARCH :=arm            ARCH  ?= $(SUBARCH)          该函数在所在的路劲为 /arm/kernel/setup.c,其中那个command_line就是有bootloader传过来的!这个函数是个重量级的函数,大家不可忽视!该函数完成体系结构相关的初始化,          内核移植的过程一般也就到此函数为止了,其余的就只是一些相关的外设驱动。*/    setup_arch(kernel/arch/arm/kernel/setup.c)        --> setup_processor()            [    0.000000] CPU: ARMv7 Processor [410fc0d1] revision 1 (ARMv7), cr=10c5387d            --> cacheid_init()                [    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache        --> setup_machine_fdt(kernel/arch/arm/kernel/devtree.c)            --> of_flat_dt_match_machine(kernel/drivers/of/fdt.c)                [    0.000000] Machine model: rockchip,rk3288-evb-act8846        --> paging_init(kernel/arch/arm/mm/mmu.c)            -->build_mem_type_table()                [    0.000000] Memory policy: Data cache writealloc            --> bootmem_init(kernel/arch/arm/mm/init.c)-->zone_sizes_init()-->free_area_init_node                -->free_area_init_node(kernel/mm/page_alloc.c) /* ? free_area_init_nodes() x, ? free_area_init() x*/                    --> calculate_node_totalpages()                        [    0.000000] On node 0 totalpages: 524288                    [    0.000000] free_area_init_node: node 0, pgdat c1095340, node_mem_map eeffa000                    --> free_area_init_core()                        [    0.000000]   Normal zone: 1536 pages used for memmap                        [    0.000000]   Normal zone: 0 pages reserved                        [    0.000000]   Normal zone: 196608 pages, LIFO batch:31                        [    0.000000]   HighMem zone: 327680 pages, LIFO batch:31    static inline void  mm_init_cpumask(kernel/include/linux/mm_types.h) /* cpu屏蔽位清零 */    setup_command_line() /*将命令行参数保存到字符数组static_command_line*/    setup_nr_cpu_ids()    setup_per_cpu_areas(kernel/mm/percpu.c) /* 每个CPU分配pre-cpu结构内存并复制.data.percpu段的数据 */         --> pcpu_embed_first_chunk()            --> pr_info("PERCPU: Embedded %zu pages/cpu @%p s%zu r%zu d%zu u%zu\n",            --> pcpu_setup_first_chunk()                --> pcpu_dump_alloc_info()                     [    0.000000] pcpu-alloc: s24448 r8192 d20608 u53248 alloc=13*4096                    [    0.000000] pcpu-alloc: [0] 0 [0] 1 [0] 2 [0] 3     smp_prepare_boot_cpu();  /* arch-specific boot-cpu hooks */    /*? numa_zonelist_order_handler(kernel/mm/page_alloc.c) */        /*-->*/     build_all_zonelists(kernel/mm/page_alloc.c) /* 建立系统内存页区(zone)链表 */            [    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 522752    page_alloc_init(kernel/mm/page_alloc.c)        --> hotcpu_notifier(?) /* no print*/    pr_notice("Kernel command line: %s\n", boot_command_line);        [    0.000000] Kernel command line: earlyprintk console=tty1 console=ttyS2,115200n8 rw root=/dev/mmcblk2p7 rootfstype=ext4 init=/sbin/init    parse_early_param(); /* 解析启动命令行参数 */    after_dashes = parse_args("Booting kernel",  static_command_line, __start___param, __stop___param - __start___param, -1, -1, NULL, &unknown_bootoption);    jump_label_init();    /*    * These use large bootmem allocations and must precede    * kmem_cache_init()    *//* 设置 log输出缓冲buf */    setup_log_buf(0);/* 初始化和分配pid散列表 */    pidhash_init(kernel/kernel/pid.c);        [    0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes)/* 创建虚拟文件系统(vfs)需要各种数据结构的缓存 */    vfs_caches_init_early(kernel/fs/dcache.c)         --> dcache_init_early()             [    0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)        --> inode_init_early()            [    0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)/* 内核异常表排序 */    sort_main_extable();/* 异常捕获设置初始化,跟体系结构相关,arm架构的实现是空函数 */    trap_init();/* 内核内存分配器初始化,初始化slab机制分配器和vmalloc机制 */    mm_init() --> mem_init(kernel/arch/arm/mm/init.c) --> mem_init_print_info(kernel/mm/page_alloc.c)        [    0.000000] Memory: 2062916K/2097152K available (10240K kernel code, 628K rwdata, 2608K rodata, 1024K init, 548K bss, 34236K reserved, 0K cma-reserved, 1310720K highmem)        [    0.000000] Virtual kernel memory layout:                   vector  : 0xffff0000 - 0xffff1000   (   4 kB)                   fixmap  : 0xffc00000 - 0xfff00000   (3072 kB)                   vmalloc : 0xf0800000 - 0xff800000   ( 240 MB)                   lowmem  : 0xc0000000 - 0xf0000000   ( 768 MB)                   pkmap   : 0xbfe00000 - 0xc0000000   (   2 MB)                   modules : 0xbf000000 - 0xbfe00000   (  14 MB)                     .text : 0xc0008000 - 0xc0b00000   (11232 kB)                     .init : 0xc0f00000 - 0xc1000000   (1024 kB)                     .data : 0xc1000000 - 0xc109d2a0   ( 629 kB)                      .bss : 0xc109f000 - 0xc11282ac   ( 549 kB)        /*         * Set up the scheduler prior starting any interrupts (such as the         * timer interrupt). Full topology setup happens at smp_init()         * time - but meanwhile we still have a functioning scheduler.         *//* 调度器数据结构初始化*/        sched_init();        /*         * Disable preemption - early bootup scheduling is extremely         * fragile until we cpu_idle() for the first time.         *//* 关抢断和中断,启动期间不允许调度和中断 */        preempt_disable();        if (WARN(!irqs_disabled(),                 "Interrupts were enabled *very* early, fixing it\n"))                local_irq_disable();/* 为 idr(一种将一个整数ID号和一个指针关联在一起的机制) 机制创建cache */        idr_init_cache();/* rcu(read-copy-update, 内核锁机制一类)机制初始化 */        rcu_init();        /* trace_printk() and trace points may be used after this */        trace_init();/* 上下文tracking机制 ? 该机制被 CONFIG_CONTEXT_TRACKING_FORCE 包住了 */        context_tracking_init();/* 为内核基数树算法分配内存,运用于内存页查找 */        radix_tree_init();        /* init some links before init_ISA_irqs() *//* 初始化体系结构相关irq,创建irq描述符,插入到基数属链表 irq_desc_tree 中管理*/        early_irq_init();        init_IRQ();/* 时钟相关初始化*/        tick_init();        rcu_init_nohz();        init_timers();        hrtimers_init();        softirq_init();        timekeeping_init();        time_init();/* 进程调度时钟初始化 */        sched_clock_postinit();/* cpu 性能相关monitor */        perf_event_init();/* gdb等debug工具设置相关 */        profile_init();/* smp下跨cpu的函数传递初始化 */        call_function_init();        WARN(!irqs_disabled(), "Interrupts were enabled early\n");        early_boot_irqs_disabled = false;/* 使能中断 */        local_irq_enable();/* slab 分配器后期初始化 */        kmem_cache_init_late();        /*         * HACK ALERT! This is early. We're enabling the console before         * we've done PCI setups etc, and console_init() must be aware of         * this. But we do want output early, in case something goes wrong.         *//* 终端控制台输出初始化 */        console_init(); register_console/* 检查异常记录信息,如果存在异常,走内核panic流程 */        if (panic_later)                panic("Too many boot %s vars at `%s'", panic_later,                      panic_param);/* printk 输出相关信息 */        lockdep_info();        /*         * Need to run this when irqs are enabled, because it wants         * to self-test [hard/soft]-irqs on/off lock inversion bugs         * too:         *//* 打印测试信息 */        locking_selftest();#ifdef CONFIG_BLK_DEV_INITRD        if (initrd_start && !initrd_below_start_ok &&            page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {                pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",                    page_to_pfn(virt_to_page((void *)initrd_start)),                    min_low_pfn);                initrd_start = 0;        }#endif        page_ext_init();/* debug 相关*/        debug_objects_mem_init();/* 内存leak监视 */        kmemleak_init();        setup_per_cpu_pageset();        numa_policy_init();        if (late_time_init)                late_time_init();        sched_clock_init();        calibrate_delay();/* 进程pid 映射表初始化 */        pidmap_init();        anon_vma_init();        acpi_early_init();#ifdef CONFIG_X86        if (efi_enabled(EFI_RUNTIME_SERVICES))                efi_enter_virtual_mode();#endif#ifdef CONFIG_X86_ESPFIX64        /* Should be run before the first non-init thread is created */        init_espfix_bsp();#endif/* 创建内核进程分配的cache */        thread_info_cache_init();         cred_init();/* fork 机制初始化 */        fork_init(); /* 创建进程需要的slab缓存 */        proc_caches_init();         buffer_init();/* 内核安全架构初始化 */        key_init();         security_init();/* kgdb 在线调试相关支持*/        dbg_late_init(); /* vfs所需要的slab缓存 */        vfs_caches_init();/* 为 sigqueue_cachep 创建slab缓存 */        signals_init();         /* rootfs populating might need page-writeback *//* 内存页写回机制初始化 */        page_writeback_init(); /* proc 文件系统 */        proc_root_init();         nsfs_init();        cpuset_init();        cgroup_init();        taskstats_init_early();        delayacct_init();        check_bugs();        acpi_subsystem_init();        sfi_init_late();        if (efi_enabled(EFI_RUNTIME_SERVICES)) {                efi_late_init();                efi_free_boot_services();        }/* trace 初始化 */        ftrace_init();        /* Do the rest non-__init'ed, we're now alive */        rest_init();}static noinline void __init_refok rest_init(void)                                                     {        int pid;        rcu_scheduler_starting();        smpboot_thread_init();                                                                                /*                                                                                                     * We need to spawn init first so that it obtains pid 1, however                                       * the init task will end up wanting to create kthreads, which, if                                     * we schedule it before we create kthreadd, will OOPS.                                                */        kernel_thread(kernel_init, NULL, CLONE_FS);                                                           numa_default_policy();                                                                                pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);                                          rcu_read_lock();                                                                                      kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);                                               rcu_read_unlock();        complete(&kthreadd_done);                                                                             /*         * The boot idle thread must execute schedule()                                                        * at least once to get things moving:                                                                 */        init_idle_bootup_task(current);                                                                       schedule_preempt_disabled();        /* Call into cpu_idle with preempt disabled */                                                        cpu_startup_entry(CPUHP_ONLINE);                                                              }小结:1、首先0号进程fork出1号init进程,执行设备驱动初始化和拉起第一个用户空间程序init;2、接着0号进程fork出2号内核线程(kthreadd)作为内核的守护进程;3、然后0号进程进入idle循环.耗时点1:    ? uart_add_one_port(kernel/drivers/tty/serial/serial_core.c) --> uart_configure_port() --> uart_report_port()        [    0.405601] ff180000.serial: ttyS0 at MMIO 0xff180000 (irq = 34, base_baud = 1500000) is a 16550A        [    0.406749] ff190000.serial: ttyS1 at MMIO 0xff190000 (irq = 35, base_baud = 1500000) is a 16550A    unregister_console(kernel/kernel/printk/printk.c)        [    0.407936] console [ttyS2] disabled    ? uart_add_one_port(kernel/drivers/tty/serial/serial_core.c) --> uart_configure_port() --> uart_report_port()        [    0.408031] ff690000.serial: ttyS2 at MMIO 0xff690000 (irq = 36, base_baud = 1500000) is a 16550A    register_console(kernel/kernel/printk/printk.c)        [    1.216754] console [ttyS2] enableduart0: serial@ff180000uart1: serial@ff190000 uart2: serial@ff690000uart3: serial@ff1b0000uart4: serial@ff1c0000    [    1.220905] rockchip-pinctrl pinctrl: pin gpio7-8 already requested by vcc-3g-regulator; cannot claim for ff1b0000.serial    [    1.231938] rockchip-pinctrl pinctrl: pin-224 (ff1b0000.serial) status -22    [    1.238868] rockchip-pinctrl pinctrl: could not request pin 224 (gpio7-8) from group uart3-xfer  on device rockchip-pinctrl耗时点2gmac: ethernet@ff290000    [    1.400192] tun: Universal TUN/TAP device driver, 1.6    [    1.405307] tun: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>    [    1.413431] rk_gmac-dwmac ff290000.ethernet: clock input or output? (input).    [    1.420514] rk_gmac-dwmac ff290000.ethernet: TX delay(0x30).    [    1.426229] rk_gmac-dwmac ff290000.ethernet: RX delay(0x10).    [    1.432138] rk_gmac-dwmac ff290000.ethernet: clock input from PHY    [    1.438278] rk_gmac-dwmac ff290000.ethernet: init for RGMII    [    1.448987] stmmac - user ID: 0x10, Synopsys ID: 0x35    [    1.454082]  Ring mode enabled    [    1.457155]  DMA HW capability register supported    [    1.461687]  Normal descriptors    [    1.465060]  RX Checksum Offload Engine supported (type 2)    [    1.470560]  TX Checksum insertion supported    [    1.474859]  Wake-Up On Lan supported    [    1.478609]  Enable RX Mitigation via HW Watchdog Timerof_get_named_gpio(kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c)    [    1.484840] of_get_named_gpiod_flags: parsed 'snps,reset-gpio' property of node '/ethernet@ff290000[0]' - status (0)    [    2.517745] libphy: stmmac: probed    [    2.521180] eth0: PHY ID 001cc915 at 0 IRQ POLL (stmmac-0:00) active    [    2.527611] eth0: PHY ID 001cc915 at 1 IRQ POLL (stmmac-0:01)    [    2.534313] PPP generic driver version 2.4.2    [    2.539048] usbcore: registered new interface driver rndis_wlan    [    2.545350] usbcore: registered new interface driver rt2800usb    [    2.551316] Rockchip WiFi SYS interface (V1.00) ... 
原创粉丝点击