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耗时点2:gmac: 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) ...
阅读全文
0 0
- linux -- 启动分析及耗时分析
- 嵌入式linux文件系统启动脚本及分析
- linux编译及启动过程分析
- linux内核启动流程及busybox分析
- H264 解码耗时分析
- IOS--分析耗时操作
- Linux启动分析
- ARM linux启动分析
- Linux启动代码分析
- Linux 内核启动分析
- linux启动分析
- linux启动分析
- Linux内核启动分析
- Linux启动过程分析
- linux启动分析 S3C2410
- linux mips启动分析
- Linux 内核启动分析
- Linux 启动过程分析
- 多交互智能手套Miiglove
- Android计步模块优化(今日步数)
- Mysql有两种存储引擎:InnoDB与Myisam
- linux下安装pip
- 浅谈算法和数据结构: 十 平衡查找树之B树
- linux -- 启动分析及耗时分析
- 树莓派3BWIFI配置(ssh方式配置)
- springboot thymeleaf简单整合
- 【python】 os.path模块介绍
- Centos7下jdk安装
- Mysql中Cardinality
- Retrofit、RxJava和OkHttp使用
- "Apache Shiro介绍"阅读与吸收
- javascript来实现无缝文字的滚屏