linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [git pull] fastboot tree for v2.6.28
@ 2008-10-10  0:32 Ingo Molnar
  2008-10-10 20:10 ` Linus Torvalds
  0 siblings, 1 reply; 8+ messages in thread
From: Ingo Molnar @ 2008-10-10  0:32 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: linux-kernel, Arjan van de Ven, Andrew Morton, Thomas Gleixner,
	H. Peter Anvin

Linus,

Please pull the latest fastboot-v28-for-linus git tree from:

   git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git fastboot-v28-for-linus

the (opt-in) fastboot async bootup feature, as described by Arjan in his 
v2.6.28 announcement:

   http://lwn.net/Articles/299591/

tested and maintained in -tip because tip/tracing embedd-merges this 
topic. (for the fastboot tracer)

Thanks,

	Ingo

------------------>
Arjan van de Ven (16):
      fastboot: create a "asynchronous" initlevel
      fastboot: turn the USB hostcontroller initcalls into async initcalls
      fastboot: convert a few non-critical ACPI drivers to async initcalls
      fastboot: hold the BKL over the async init call sequence
      fastboot: sync the async execution before late_initcall and move level 6s (sync) first
      fastboot: make fastboot a config option
      modules: extend initcall_debug functionality to the module loader
      fastboot: retry mounting the root fs if we can't find init
      fastboot: make the raid autodetect code wait for all devices to init
      fastboot: remove "wait for all devices before mounting root" delay
      fastboot: make the RAID autostart code print a message just before waiting
      fastboot: fix blackfin breakage due to vmlinux.lds change
      Add a script to visualize the kernel boot process / time
      fastboot: fix issues and improve output of bootgraph.pl
      use the fancy new printk flags to print the function pointer
      raid: make RAID autodetect default a KConfig option

Arnaud Patard (1):
      fastboot: Fix bootgraph.pl initcall name regexp

Ingo Molnar (2):
      fastboot: fix typo in init/Kconfig text
      warning: fix init do_mounts_md c

KOSAKI Motohiro (1):
      fastboot: fix build error of autodetect_raid()

Li, Shaohua (1):
      fastboot: remove duplicate unpack_to_rootfs()

Steven Noonan (1):
      init/initramfs.c: unused function when compiling without CONFIG_BLK_DEV_RAM


 drivers/acpi/battery.c            |    2 +-
 drivers/acpi/button.c             |    2 +-
 drivers/acpi/thermal.c            |    2 +-
 drivers/md/Kconfig                |   14 ++++
 drivers/pci/pci.c                 |    2 +-
 drivers/usb/host/ehci-hcd.c       |    2 +-
 drivers/usb/host/ohci-hcd.c       |    2 +-
 drivers/usb/host/uhci-hcd.c       |    2 +-
 include/asm-generic/vmlinux.lds.h |    6 +-
 include/linux/init.h              |    8 ++
 init/Kconfig                      |   11 +++
 init/do_mounts.c                  |    2 +
 init/do_mounts_md.c               |   41 ++++++++--
 init/initramfs.c                  |   73 +++++++++++++++----
 init/main.c                       |   84 +++++++++++++++++++--
 scripts/bootgraph.pl              |  147 +++++++++++++++++++++++++++++++++++++
 16 files changed, 361 insertions(+), 39 deletions(-)
 create mode 100644 scripts/bootgraph.pl

diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index b1c723f..d5d30ca 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -904,5 +904,5 @@ static void __exit acpi_battery_exit(void)
 #endif
 }
 
-module_init(acpi_battery_init);
+module_init_async(acpi_battery_init);
 module_exit(acpi_battery_exit);
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 1dfec41..46b3805 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -545,5 +545,5 @@ static void __exit acpi_button_exit(void)
 	remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
 }
 
-module_init(acpi_button_init);
+module_init_async(acpi_button_init);
 module_exit(acpi_button_exit);
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 9127036..c07f9ba 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -1876,5 +1876,5 @@ static void __exit acpi_thermal_exit(void)
 	return;
 }
 
-module_init(acpi_thermal_init);
+module_init_async(acpi_thermal_init);
 module_exit(acpi_thermal_exit);
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 07d92c1..8e72c91 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -30,6 +30,20 @@ config BLK_DEV_MD
 
 	  If unsure, say N.
 
+config MD_AUTODETECT
+	bool "Autodetect RAID arrays during kernel boot"
+	depends on BLK_DEV_MD
+	default y
+	---help---
+	  If you say Y here, then the kernel will try to autodetect raid
+	  arrays as part of its boot process. 
+
+	  If you don't use raid and say Y, this autodetection can cause 
+	  a several-second delay in the boot time due to various
+	  synchronisation steps that are part of this step.
+
+	  If unsure, say Y.
+
 config MD_LINEAR
 	tristate "Linear (append) mode"
 	depends on BLK_DEV_MD
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index c9884bb..a9301a2 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1909,7 +1909,7 @@ static int __devinit pci_setup(char *str)
 }
 early_param("pci", pci_setup);
 
-device_initcall(pci_init);
+device_initcall_sync(pci_init);
 
 EXPORT_SYMBOL(pci_reenable_device);
 EXPORT_SYMBOL(pci_enable_device_io);
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 8409e07..209f64c 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1107,7 +1107,7 @@ clean0:
 #endif
 	return retval;
 }
-module_init(ehci_hcd_init);
+module_init_async(ehci_hcd_init);
 
 static void __exit ehci_hcd_cleanup(void)
 {
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 8990196..868c509 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1186,7 +1186,7 @@ static int __init ohci_hcd_mod_init(void)
 
 	return retval;
 }
-module_init(ohci_hcd_mod_init);
+module_init_async(ohci_hcd_mod_init);
 
 static void __exit ohci_hcd_mod_exit(void)
 {
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 3a7bfe7..f2a05ac 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -999,7 +999,7 @@ static void __exit uhci_hcd_cleanup(void)
 	kfree(errbuf);
 }
 
-module_init(uhci_hcd_init);
+module_init_async(uhci_hcd_init);
 module_exit(uhci_hcd_cleanup);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index cb752ba..ccabc4e 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -376,8 +376,12 @@
   	*(.initcall5.init)						\
   	*(.initcall5s.init)						\
 	*(.initcallrootfs.init)						\
+	*(.initcall6s.init)						\
+	VMLINUX_SYMBOL(__async_initcall_start) = .;			\
+	*(.initcall6a.init)						\
+	VMLINUX_SYMBOL(__async_initcall_end) = .;			\
   	*(.initcall6.init)						\
-  	*(.initcall6s.init)						\
+	VMLINUX_SYMBOL(__device_initcall_end) = .;			\
   	*(.initcall7.init)						\
   	*(.initcall7s.init)
 
diff --git a/include/linux/init.h b/include/linux/init.h
index 93538b6..b6201c0 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -143,6 +143,8 @@ extern int do_one_initcall(initcall_t fn);
 extern char __initdata boot_command_line[];
 extern char *saved_command_line;
 extern unsigned int reset_devices;
+extern int do_one_initcall(initcall_t fn);
+
 
 /* used by init/main.c */
 void setup_arch(char **);
@@ -197,11 +199,13 @@ extern void (*late_time_init)(void);
 #define fs_initcall_sync(fn)		__define_initcall("5s",fn,5s)
 #define rootfs_initcall(fn)		__define_initcall("rootfs",fn,rootfs)
 #define device_initcall(fn)		__define_initcall("6",fn,6)
+#define device_initcall_async(fn)	__define_initcall("6a", fn, 6a)
 #define device_initcall_sync(fn)	__define_initcall("6s",fn,6s)
 #define late_initcall(fn)		__define_initcall("7",fn,7)
 #define late_initcall_sync(fn)		__define_initcall("7s",fn,7s)
 
 #define __initcall(fn) device_initcall(fn)
+#define __initcall_async(fn) device_initcall_async(fn)
 
 #define __exitcall(fn) \
 	static exitcall_t __exitcall_##fn __exit_call = fn
@@ -257,6 +261,7 @@ void __init parse_early_param(void);
  * be one per module.
  */
 #define module_init(x)	__initcall(x);
+#define module_init_async(x)	__initcall_async(x);
 
 /**
  * module_exit() - driver exit entry point
@@ -279,10 +284,13 @@ void __init parse_early_param(void);
 #define subsys_initcall(fn)		module_init(fn)
 #define fs_initcall(fn)			module_init(fn)
 #define device_initcall(fn)		module_init(fn)
+#define device_initcall_async(fn)	module_init(fn)
 #define late_initcall(fn)		module_init(fn)
 
 #define security_initcall(fn)		module_init(fn)
 
+#define module_init_async(fn)		module_init(fn)
+
 /* Each module must use one module_init(). */
 #define module_init(initfn)					\
 	static inline initcall_t __inittest(void)		\
diff --git a/init/Kconfig b/init/Kconfig
index c11da38..0090c99 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -524,6 +524,17 @@ config CC_OPTIMIZE_FOR_SIZE
 
 	  If unsure, say Y.
 
+config FASTBOOT
+	bool "Fast boot support"
+	help
+	  The fastboot option will cause the kernel to try to optimize
+	  for faster boot. 
+
+	  This includes doing some of the device initialization asynchronously
+	  as well as opportunistically trying to mount the root fs early.
+
+	  If unsure, say N.
+
 config SYSCTL
 	bool
 
diff --git a/init/do_mounts.c b/init/do_mounts.c
index 3715feb..d64e01d 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -365,9 +365,11 @@ void __init prepare_namespace(void)
 		ssleep(root_delay);
 	}
 
+#ifndef CONFIG_FASTBOOT
 	/* wait for the known devices to complete their probing */
 	while (driver_probe_done() != 0)
 		msleep(100);
+#endif
 
 	md_run_setup();
 
diff --git a/init/do_mounts_md.c b/init/do_mounts_md.c
index 693d246..4c87ee1 100644
--- a/init/do_mounts_md.c
+++ b/init/do_mounts_md.c
@@ -1,5 +1,6 @@
 
 #include <linux/raid/md.h>
+#include <linux/delay.h>
 
 #include "do_mounts.h"
 
@@ -12,7 +13,12 @@
  * The code for that is here.
  */
 
-static int __initdata raid_noautodetect, raid_autopart;
+#ifdef CONFIG_MD_AUTODETECT
+static int __initdata raid_noautodetect;
+#else
+static int __initdata raid_noautodetect=1;
+#endif
+static int __initdata raid_autopart;
 
 static struct {
 	int minor;
@@ -252,6 +258,8 @@ static int __init raid_setup(char *str)
 
 		if (!strncmp(str, "noautodetect", wlen))
 			raid_noautodetect = 1;
+		if (!strncmp(str, "autodetect", wlen))
+			raid_noautodetect = 0;
 		if (strncmp(str, "partitionable", wlen)==0)
 			raid_autopart = 1;
 		if (strncmp(str, "part", wlen)==0)
@@ -264,17 +272,32 @@ static int __init raid_setup(char *str)
 __setup("raid=", raid_setup);
 __setup("md=", md_setup);
 
+static void autodetect_raid(void)
+{
+	int fd;
+
+	/*
+	 * Since we don't want to detect and use half a raid array, we need to
+	 * wait for the known devices to complete their probing
+	 */
+	printk(KERN_INFO "md: Waiting for all devices to be available before autodetect\n");
+	printk(KERN_INFO "md: If you don't use raid, use raid=noautodetect\n");
+	while (driver_probe_done() < 0)
+		msleep(100);
+	fd = sys_open("/dev/md0", 0, 0);
+	if (fd >= 0) {
+		sys_ioctl(fd, RAID_AUTORUN, raid_autopart);
+		sys_close(fd);
+	}
+}
+
 void __init md_run_setup(void)
 {
 	create_dev("/dev/md0", MKDEV(MD_MAJOR, 0));
+
 	if (raid_noautodetect)
-		printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n");
-	else {
-		int fd = sys_open("/dev/md0", 0, 0);
-		if (fd >= 0) {
-			sys_ioctl(fd, RAID_AUTORUN, raid_autopart);
-			sys_close(fd);
-		}
-	}
+		printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=autodetect will force)\n");
+	else
+		autodetect_raid();
 	md_setup_drive();
 }
diff --git a/init/initramfs.c b/init/initramfs.c
index 644fc01..2f056e2 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -5,6 +5,7 @@
 #include <linux/fcntl.h>
 #include <linux/delay.h>
 #include <linux/string.h>
+#include <linux/dirent.h>
 #include <linux/syscalls.h>
 
 static __initdata char *message;
@@ -121,8 +122,6 @@ static __initdata char *victim;
 static __initdata unsigned count;
 static __initdata loff_t this_header, next_header;
 
-static __initdata int dry_run;
-
 static inline void __init eat(unsigned n)
 {
 	victim += n;
@@ -183,10 +182,6 @@ static int __init do_header(void)
 	parse_header(collected);
 	next_header = this_header + N_ALIGN(name_len) + body_len;
 	next_header = (next_header + 3) & ~3;
-	if (dry_run) {
-		read_into(name_buf, N_ALIGN(name_len), GotName);
-		return 0;
-	}
 	state = SkipIt;
 	if (name_len <= 0 || name_len > PATH_MAX)
 		return 0;
@@ -257,8 +252,6 @@ static int __init do_name(void)
 		free_hash();
 		return 0;
 	}
-	if (dry_run)
-		return 0;
 	clean_path(collected, mode);
 	if (S_ISREG(mode)) {
 		int ml = maybe_link();
@@ -423,10 +416,9 @@ static void __init flush_window(void)
 	outcnt = 0;
 }
 
-static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
+static char * __init unpack_to_rootfs(char *buf, unsigned len)
 {
 	int written;
-	dry_run = check_only;
 	header_buf = kmalloc(110, GFP_KERNEL);
 	symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL);
 	name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL);
@@ -520,10 +512,59 @@ skip:
 	initrd_end = 0;
 }
 
+#ifdef CONFIG_BLK_DEV_RAM
+#define BUF_SIZE 1024
+static void __init clean_rootfs(void)
+{
+	int fd;
+	void *buf;
+	struct linux_dirent64 *dirp;
+	int count;
+
+	fd = sys_open("/", O_RDONLY, 0);
+	WARN_ON(fd < 0);
+	if (fd < 0)
+		return;
+	buf = kzalloc(BUF_SIZE, GFP_KERNEL);
+	WARN_ON(!buf);
+	if (!buf) {
+		sys_close(fd);
+		return;
+	}
+
+	dirp = buf;
+	count = sys_getdents64(fd, dirp, BUF_SIZE);
+	while (count > 0) {
+		while (count > 0) {
+			struct stat st;
+			int ret;
+
+			ret = sys_newlstat(dirp->d_name, &st);
+			WARN_ON_ONCE(ret);
+			if (!ret) {
+				if (S_ISDIR(st.st_mode))
+					sys_rmdir(dirp->d_name);
+				else
+					sys_unlink(dirp->d_name);
+			}
+
+			count -= dirp->d_reclen;
+			dirp = (void *)dirp + dirp->d_reclen;
+		}
+		dirp = buf;
+		memset(buf, 0, BUF_SIZE);
+		count = sys_getdents64(fd, dirp, BUF_SIZE);
+	}
+
+	sys_close(fd);
+	kfree(buf);
+}
+#endif
+
 static int __init populate_rootfs(void)
 {
 	char *err = unpack_to_rootfs(__initramfs_start,
-			 __initramfs_end - __initramfs_start, 0);
+			 __initramfs_end - __initramfs_start);
 	if (err)
 		panic(err);
 	if (initrd_start) {
@@ -531,13 +572,15 @@ static int __init populate_rootfs(void)
 		int fd;
 		printk(KERN_INFO "checking if image is initramfs...");
 		err = unpack_to_rootfs((char *)initrd_start,
-			initrd_end - initrd_start, 1);
+			initrd_end - initrd_start);
 		if (!err) {
 			printk(" it is\n");
-			unpack_to_rootfs((char *)initrd_start,
-				initrd_end - initrd_start, 0);
 			free_initrd();
 			return 0;
+		} else {
+			clean_rootfs();
+			unpack_to_rootfs(__initramfs_start,
+				 __initramfs_end - __initramfs_start);
 		}
 		printk("it isn't (%s); looks like an initrd\n", err);
 		fd = sys_open("/initrd.image", O_WRONLY|O_CREAT, 0700);
@@ -550,7 +593,7 @@ static int __init populate_rootfs(void)
 #else
 		printk(KERN_INFO "Unpacking initramfs...");
 		err = unpack_to_rootfs((char *)initrd_start,
-			initrd_end - initrd_start, 0);
+			initrd_end - initrd_start);
 		if (err)
 			panic(err);
 		printk(" done\n");
diff --git a/init/main.c b/init/main.c
index 3820323..2dc22fa 100644
--- a/init/main.c
+++ b/init/main.c
@@ -708,7 +708,7 @@ int do_one_initcall(initcall_t fn)
 	int result;
 
 	if (initcall_debug) {
-		printk("calling  %pF\n", fn);
+		printk("calling  %pF @ %i\n", fn, task_pid_nr(current));
 		t0 = ktime_get();
 	}
 
@@ -718,9 +718,8 @@ int do_one_initcall(initcall_t fn)
 		t1 = ktime_get();
 		delta = ktime_sub(t1, t0);
 
-		printk("initcall %pF returned %d after %Ld msecs\n",
-			fn, result,
-			(unsigned long long) delta.tv64 >> 20);
+		printk("initcall %pF returned %d after %Ld msecs\n", fn,
+			result, (unsigned long long) delta.tv64 >> 20);
 	}
 
 	msgbuf[0] = 0;
@@ -745,16 +744,68 @@ int do_one_initcall(initcall_t fn)
 
 
 extern initcall_t __initcall_start[], __initcall_end[], __early_initcall_end[];
+extern initcall_t __async_initcall_start[], __async_initcall_end[];
+extern initcall_t __device_initcall_end[];
 
-static void __init do_initcalls(void)
+static void __init do_async_initcalls(struct work_struct *dummy)
 {
 	initcall_t *call;
 
-	for (call = __early_initcall_end; call < __initcall_end; call++)
+	/*
+	 * For compatibility with normal init calls... take the BKL
+	 * not pretty, not desirable, but compatibility first
+	 */
+	lock_kernel();
+	for (call = __async_initcall_start; call < __async_initcall_end; call++)
 		do_one_initcall(*call);
+	unlock_kernel();
+}
+
+static struct workqueue_struct *async_init_wq;
 
-	/* Make sure there is no pending stuff from the initcall sequence */
+
+
+static void __init do_initcalls(void)
+{
+	initcall_t *call;
+	static DECLARE_WORK(async_work, do_async_initcalls);
+	/*
+	 * 0 = levels 0 - 6,
+	 * 1 = level 6a,
+	 * 2 = after level 6a,
+	 * 3 = after level 6
+	 */
+	int phase = 0;
+
+	async_init_wq = create_singlethread_workqueue("kasyncinit");
+
+	for (call = __early_initcall_end; call < __initcall_end; call++) {
+		if (phase == 0 && call >= __async_initcall_start) {
+			phase = 1;
+#ifdef CONFIG_FASTBOOT
+			queue_work(async_init_wq, &async_work);
+#else
+			do_async_initcalls(NULL);
+#endif
+		}
+		if (phase == 1 && call >= __async_initcall_end)
+			phase = 2;
+		if (phase == 2 && call >= __device_initcall_end) {
+			phase = 3;
+			/* make sure all async work is done before level 7 */
+			flush_workqueue(async_init_wq);
+		}
+		if (phase != 1)
+			do_one_initcall(*call);
+	}
+
+	/*
+	 * Make sure there is no pending stuff from the initcall sequence,
+	 * including the async initcalls
+	 */
 	flush_scheduled_work();
+	flush_workqueue(async_init_wq);
+	destroy_workqueue(async_init_wq);
 }
 
 /*
@@ -794,6 +845,7 @@ static void run_init_process(char *init_filename)
  */
 static int noinline init_post(void)
 {
+	int retry_count = 1;
 	free_initmem();
 	unlock_kernel();
 	mark_rodata_ro();
@@ -814,6 +866,7 @@ static int noinline init_post(void)
 				ramdisk_execute_command);
 	}
 
+retry:
 	/*
 	 * We try each of these until one succeeds.
 	 *
@@ -826,6 +879,23 @@ static int noinline init_post(void)
 					"defaults...\n", execute_command);
 	}
 	run_init_process("/sbin/init");
+
+	if (retry_count > 0) {
+		retry_count--;
+		/* 
+		 * We haven't found init yet... potentially because the device
+		 * is still being probed. We need to
+		 * - flush keventd and friends
+		 * - wait for the known devices to complete their probing
+		 * - try to mount the root fs again
+		 */
+		flush_scheduled_work();
+		while (driver_probe_done() != 0)
+			msleep(100);
+		prepare_namespace();
+		goto retry;
+	}
+	
 	run_init_process("/etc/init");
 	run_init_process("/bin/init");
 	run_init_process("/bin/sh");
diff --git a/scripts/bootgraph.pl b/scripts/bootgraph.pl
new file mode 100644
index 0000000..2243353
--- /dev/null
+++ b/scripts/bootgraph.pl
@@ -0,0 +1,147 @@
+#!/usr/bin/perl
+
+# Copyright 2008, Intel Corporation
+#
+# This file is part of the Linux kernel
+#
+# This program file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+# Authors:
+# 	Arjan van de Ven <arjan@linux.intel.com>
+
+
+#
+# This script turns a dmesg output into a SVG graphic that shows which
+# functions take how much time. You can view SVG graphics with various
+# programs, including Inkscape, The Gimp and Firefox.
+#
+#
+# For this script to work, the kernel needs to be compiled with the
+# CONFIG_PRINTK_TIME configuration option enabled, and with
+# "initcall_debug" passed on the kernel command line.
+#
+# usage:
+# 	dmesg | perl scripts/bootgraph.pl > output.svg
+#
+
+my @rows;
+my %start, %end, %row;
+my $done = 0;
+my $rowcount = 0;
+my $maxtime = 0;
+my $firsttime = 100;
+my $count = 0;
+while (<>) {
+	my $line = $_;
+	if ($line =~ /([0-9\.]+)\] calling  ([a-zA-Z0-9\_]+)\+/) {
+		my $func = $2;
+		if ($done == 0) {
+			$start{$func} = $1;
+			if ($1 < $firsttime) {
+				$firsttime = $1;
+			}
+		}
+		$row{$func} = 1;
+		if ($line =~ /\@ ([0-9]+)/) {
+			my $pid = $1;
+			if (!defined($rows[$pid])) {
+				$rowcount = $rowcount + 1;
+				$rows[$pid] = $rowcount;
+			}
+			$row{$func} = $rows[$pid];
+		}
+		$count = $count + 1;
+	}
+
+	if ($line =~ /([0-9\.]+)\] initcall ([a-zA-Z0-9\_]+)\+.*returned/) {
+		if ($done == 0) {
+			$end{$2} = $1;
+			$maxtime = $1;
+		}
+	}
+	if ($line =~ /Write protecting the/) {
+		$done = 1;
+	}
+	if ($line =~ /Freeing unused kernel memory/) {
+		$done = 1;
+	}
+}
+
+if ($count == 0) {
+	print "No data found in the dmesg. Make sure that 'printk.time=1' and\n";
+	print "'initcall_debug' are passed on the kernel command line.\n\n";
+	print "Usage: \n";
+	print "      dmesg | perl scripts/bootgraph.pl > output.svg\n\n";
+	exit;
+}
+
+print "<?xml version=\"1.0\" standalone=\"no\"?> \n";
+print "<svg width=\"1000\" height=\"100%\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n";
+
+my @styles;
+
+$styles[0] = "fill:rgb(0,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[1] = "fill:rgb(0,255,0);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[2] = "fill:rgb(255,0,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[3] = "fill:rgb(255,255,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[4] = "fill:rgb(255,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[5] = "fill:rgb(0,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[6] = "fill:rgb(0,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[7] = "fill:rgb(0,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[8] = "fill:rgb(255,0,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[9] = "fill:rgb(255,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[10] = "fill:rgb(255,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[11] = "fill:rgb(128,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+
+my $mult = 950.0 / ($maxtime - $firsttime);
+my $threshold = ($maxtime - $firsttime) / 60.0;
+my $stylecounter = 0;
+while (($key,$value) = each %start) {
+	my $duration = $end{$key} - $start{$key};
+
+	if ($duration >= $threshold) {
+		my $s, $s2, $e, $y;
+		$s = ($value - $firsttime) * $mult;
+		$s2 = $s + 6;
+		$e = ($end{$key} - $firsttime) * $mult;
+		$w = $e - $s;
+
+		$y = $row{$key} * 150;
+		$y2 = $y + 4;
+
+		$style = $styles[$stylecounter];
+		$stylecounter = $stylecounter + 1;
+		if ($stylecounter > 11) {
+			$stylecounter = 0;
+		};
+
+		print "<rect x=\"$s\" width=\"$w\" y=\"$y\" height=\"145\" style=\"$style\"/>\n";
+		print "<text transform=\"translate($s2,$y2) rotate(90)\">$key</text>\n";
+	}
+}
+
+
+# print the time line on top
+my $time = $firsttime;
+my $step = ($maxtime - $firsttime) / 15;
+while ($time < $maxtime) {
+	my $s2 = ($time - $firsttime) * $mult;
+	my $tm = int($time * 100) / 100.0;
+	print "<text transform=\"translate($s2,89) rotate(90)\">$tm</text>\n";
+	$time = $time + $step;
+}
+
+print "</svg>\n";

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [git pull] fastboot tree for v2.6.28
  2008-10-10  0:32 [git pull] fastboot tree for v2.6.28 Ingo Molnar
@ 2008-10-10 20:10 ` Linus Torvalds
  2008-10-10 22:49   ` Arjan van de Ven
  0 siblings, 1 reply; 8+ messages in thread
From: Linus Torvalds @ 2008-10-10 20:10 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: linux-kernel, Arjan van de Ven, Andrew Morton, Thomas Gleixner,
	H. Peter Anvin



On Fri, 10 Oct 2008, Ingo Molnar wrote:
>
> Please pull the latest fastboot-v28-for-linus git tree from:
> 
>    git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git fastboot-v28-for-linus
> 
> the (opt-in) fastboot async bootup feature, as described by Arjan in his 
> v2.6.28 announcement:
> 
>    http://lwn.net/Articles/299591/
> 
> tested and maintained in -tip because tip/tracing embedd-merges this 
> topic. (for the fastboot tracer)

Ok, so I finally looked at the patch, I quite frankly, I think it's 
fundamentally wrong.

This is just an example of the wrongness:

	-module_init(uhci_hcd_init);
	+module_init_async(uhci_hcd_init);
	-module_init(ehci_hcd_init);
	+module_init_async(ehci_hcd_init);
	-module_init(ohci_hcd_mod_init);
	+module_init_async(ohci_hcd_mod_init);

	-device_initcall(pci_init);
	+device_initcall_sync(pci_init);

because there is absolutely _no_ excuse for doing the PCI part of the 
probing asynchronously.

The "ohci_hcd_mod_init" part is _especially_ dangerous, because clearly 
nobody looked at the OHCI setup sequence, which includes a lot of odd 
devices and not all of them at all PCI-related etc. Making it asynchronous 
is not safe, nor is it appropriate.

The fact is, those things all have one thing in common:

 - they call usb_add_hcd, and usb_add_hcd is a horrible and slow piece of 
   crap that doesn't just add the host controller, but does all the 
   probing too.

In other words, what should be fixed is not the initcall sequence, and 
certainly not make PCI device probing (or other random buses) be partly 
asynchronous, but simply make that USB host controller startup function be 
asynchronous.

There are other devices too that may need synchronous core hub discovery 
(eg the actual controller), but that want to do the "devices hanging off 
this controller" asynchronously. Disks come to mind. That shouldn't mean 
that the IDE driver discovery should be asynchronous, it should just mean 
that the driver has some simple way to execute something asynchronously.

In other words, I really think it's very wrong to make that 
"async_init_wq" be somethign that is internal to do_initcalls. It should 
be a workqueue that the initcalls can _choose_ to use at the appropriate 
level (which may be deeper down, like 'usb_add_hcd()'), not be forced to 
use at the outermost one.

You can try to convince me otherwise, but I really do think this patch is 
fundamentally the wrong approach.

			Linus

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [git pull] fastboot tree for v2.6.28
  2008-10-10 20:10 ` Linus Torvalds
@ 2008-10-10 22:49   ` Arjan van de Ven
  2008-10-11  6:47     ` Ingo Molnar
  0 siblings, 1 reply; 8+ messages in thread
From: Arjan van de Ven @ 2008-10-10 22:49 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Ingo Molnar, linux-kernel, Andrew Morton, Thomas Gleixner,
	H. Peter Anvin

On Fri, 10 Oct 2008 13:10:30 -0700 (PDT)
Linus Torvalds <torvalds@linux-foundation.org> wrote:

> 
> 
> On Fri, 10 Oct 2008, Ingo Molnar wrote:
> >
> > Please pull the latest fastboot-v28-for-linus git tree from:
> > 
> >    git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git
> > fastboot-v28-for-linus
> > 
> > the (opt-in) fastboot async bootup feature, as described by Arjan
> > in his v2.6.28 announcement:
> > 
> >    http://lwn.net/Articles/299591/
> > 
> > tested and maintained in -tip because tip/tracing embedd-merges
> > this topic. (for the fastboot tracer)
> 
> Ok, so I finally looked at the patch, I quite frankly, I think it's 
> fundamentally wrong.
> 
> This is just an example of the wrongness:
> 
> 	-module_init(uhci_hcd_init);
> 	+module_init_async(uhci_hcd_init);
> 	-module_init(ehci_hcd_init);
> 	+module_init_async(ehci_hcd_init);
> 	-module_init(ohci_hcd_mod_init);
> 	+module_init_async(ohci_hcd_mod_init);
> 
> 	-device_initcall(pci_init);
> 	+device_initcall_sync(pci_init);

(I know you saw this, but I want to just point out to more casual
readers that the pci_init call above is not "async", there's
deliberately no "a" there)
> 
> because there is absolutely _no_ excuse for doing the PCI part of the 
> probing asynchronously.

The PCI layer is absolutely not asychronous indeed, that would be
totally insane, and I really don't want to go there (nor do I think we
would need to to get to a fast boot). The initcall_sync above is to fix
a bug in the PCI layer where there was a subsystem level required call
stuck in the device level, and by sticking it in device_initcall_sync
it is at least guaranteed to run before any device initcalls.
>
> The "ohci_hcd_mod_init" part is _especially_ dangerous, because
> clearly nobody looked at the OHCI setup sequence, which includes a
> lot of odd devices and not all of them at all PCI-related etc. Making
> it asynchronous is not safe, nor is it appropriate.
> 
> The fact is, those things all have one thing in common:
> 
>  - they call usb_add_hcd, and usb_add_hcd is a horrible and slow
> piece of crap that doesn't just add the host controller, but does all
> the probing too.
> 
> In other words, what should be fixed is not the initcall sequence,
> and certainly not make PCI device probing (or other random buses) be
> partly asynchronous, but simply make that USB host controller startup
> function be asynchronous.

You are right and when you pull the USB tree later this week you'll get
that into your tree. You are right that for subsystem level components
that that is absolutely the right approach
> 
> In other words, I really think it's very wrong to make that 
> "async_init_wq" be somethign that is internal to do_initcalls. It
> should be a workqueue that the initcalls can _choose_ to use at the
> appropriate level (which may be deeper down, like 'usb_add_hcd()'),
> not be forced to use at the outermost one.
> 
> You can try to convince me otherwise, but I really do think this
> patch is fundamentally the wrong approach.

there's an angle here which I would like to bring up.
There is a fundamental difference between a spider functionality like
USB, and "leaf drivers". Yes USB should do it right, it's drivers are
effectively a midlayer. (and again, pull gregkh's tree and you'll get
that; although even with that there's a noticeable amount of time
spent there).

For leaf drivers, it's a matter of where you want to push the
functionality. With leaf drivers I mean things like the ACPI battery
driver (or other ACPI drivers), but also various PCI drivers that don't
have or are elaborate subsystems or boot dependencies. We could make all
their probing functions async in each driver, or we could provide the
most simple interface as is done in this case, they just change how
they declare their initcall.
(I'll grant you that we could also do a pci_register_device_async()
like of helper, but that's just solving part of the same problem)

Personally for leaf drivers, I think the initcall-level approach is much
less error prone. 

-- 
Arjan van de Ven 	Intel Open Source Technology Centre
For development, discussion and tips for power savings, 
visit http://www.lesswatts.org

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [git pull] fastboot tree for v2.6.28
  2008-10-10 22:49   ` Arjan van de Ven
@ 2008-10-11  6:47     ` Ingo Molnar
  2008-10-11  7:48       ` Andrew Morton
  0 siblings, 1 reply; 8+ messages in thread
From: Ingo Molnar @ 2008-10-11  6:47 UTC (permalink / raw)
  To: Arjan van de Ven
  Cc: Linus Torvalds, linux-kernel, Andrew Morton, Thomas Gleixner,
	H. Peter Anvin


* Arjan van de Ven <arjan@infradead.org> wrote:

> > You can try to convince me otherwise, but I really do think this 
> > patch is fundamentally the wrong approach.
> 
> there's an angle here which I would like to bring up. There is a 
> fundamental difference between a spider functionality like USB, and 
> "leaf drivers". Yes USB should do it right, it's drivers are 
> effectively a midlayer. (and again, pull gregkh's tree and you'll get 
> that; although even with that there's a noticeable amount of time 
> spent there).
> 
> For leaf drivers, it's a matter of where you want to push the 
> functionality. With leaf drivers I mean things like the ACPI battery 
> driver (or other ACPI drivers), but also various PCI drivers that 
> don't have or are elaborate subsystems or boot dependencies. We could 
> make all their probing functions async in each driver, or we could 
> provide the most simple interface as is done in this case, they just 
> change how they declare their initcall. (I'll grant you that we could 
> also do a pci_register_device_async() like of helper, but that's just 
> solving part of the same problem)
> 
> Personally for leaf drivers, I think the initcall-level approach is 
> much less error prone.

i'd like to inject my first-hand testing experience with your patches: 

When i saw your patches then initially my impression was "oh my, this 
will break a ton of stuff", so i asked you to: make it default-off 
(against Andrew's suggestion to just remove the config and make it a 
compulsory feature), to add various mechanisms to disable and isolate 
it, should it break something - which i expected to be a near certainty.

But i was wrong. We had only a single bug in fastboot-v1 three months 
ago which i bisected back to this series, and you fixed that quickly. 
And CONFIG_FASTBOOT=y is definitely one of the popular features that 
testers enable and there's all sorts of weird systems that are being 
tested with tip/master.

So tip/fastboot has certainly been a problem free topic in its 3 months 
of lifetime - and it got propagated to linux-next early on as well.

Our -tip testsystems boot with CONFIG_FASTBOOT=y about 50% of the time, 
once every couple of minutes on this test-system:

 config-Fri_Oct_10_23_06_21_CEST_2008.good:CONFIG_FASTBOOT=y
 config-Fri_Oct_10_23_07_54_CEST_2008.good:CONFIG_FASTBOOT=y
 config-Fri_Oct_10_23_14_08_CEST_2008.good:CONFIG_FASTBOOT=y
 config-Fri_Oct_10_23_15_54_CEST_2008.good:CONFIG_FASTBOOT=y
 config-Fri_Oct_10_23_21_37_CEST_2008.good:CONFIG_FASTBOOT=y
 config-Fri_Oct_10_23_22_56_CEST_2008.good:CONFIG_FASTBOOT=y
 config-Fri_Oct_10_23_27_14_CEST_2008.good:CONFIG_FASTBOOT=y

i checked the logs, just yesterday that meant 354 fastboot-enabled 
bootups on just that single test-system. So while i fully expected 
fragility from this topic, neither our testing nor our testers saw 
fragility in practice.

	Ingo

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [git pull] fastboot tree for v2.6.28
  2008-10-11  6:47     ` Ingo Molnar
@ 2008-10-11  7:48       ` Andrew Morton
  2008-10-11  8:28         ` Ingo Molnar
  0 siblings, 1 reply; 8+ messages in thread
From: Andrew Morton @ 2008-10-11  7:48 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Arjan van de Ven, Linus Torvalds, linux-kernel, Thomas Gleixner,
	H. Peter Anvin

On Sat, 11 Oct 2008 08:47:12 +0200 Ingo Molnar <mingo@elte.hu> wrote:

> When i saw your patches then initially my impression was "oh my, this 
> will break a ton of stuff", so i asked you to: make it default-off 
> (against Andrew's suggestion to just remove the config and make it a 
> compulsory feature)

hm, that must have been the other Andrew.

A feature like this I think should not have a config option but should
be enabled by a boot option.

We can waffle about the default setting of that option.  Maybe turn it
on for a few weeks and see what happens.


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [git pull] fastboot tree for v2.6.28
  2008-10-11  7:48       ` Andrew Morton
@ 2008-10-11  8:28         ` Ingo Molnar
  2008-10-11 14:11           ` H. Peter Anvin
  0 siblings, 1 reply; 8+ messages in thread
From: Ingo Molnar @ 2008-10-11  8:28 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Arjan van de Ven, Linus Torvalds, linux-kernel, Thomas Gleixner,
	H. Peter Anvin


* Andrew Morton <akpm@linux-foundation.org> wrote:

> On Sat, 11 Oct 2008 08:47:12 +0200 Ingo Molnar <mingo@elte.hu> wrote:
> 
> > When i saw your patches then initially my impression was "oh my, 
> > this will break a ton of stuff", so i asked you to: make it 
> > default-off (against Andrew's suggestion to just remove the config 
> > and make it a compulsory feature)
> 
> hm, that must have been the other Andrew.

on 14th August you wrote:

|| Making it a config options seems a bad idea - it'll split our 
|| testing/debugging space yet again.  If this stuff works, then 
|| everyone should be able to use it.  If it doesn't work, well....

this i understood as: "if we take this stuff then it should be 
always-on". [You didnt say whether we should take it though.]

> A feature like this I think should not have a config option but should 
> be enabled by a boot option.
>
> We can waffle about the default setting of that option.  Maybe turn it 
> on for a few weeks and see what happens.

a config option is definitely useful for users and distros. Having the 
boot option is a good idea. Arjan, i thought we had a fastboot=0/1 boot 
option but i cannot find it - could you please add it?

	Ingo

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [git pull] fastboot tree for v2.6.28
  2008-10-11  8:28         ` Ingo Molnar
@ 2008-10-11 14:11           ` H. Peter Anvin
  2008-10-24 18:26             ` Olivier Blin
  0 siblings, 1 reply; 8+ messages in thread
From: H. Peter Anvin @ 2008-10-11 14:11 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Andrew Morton, Arjan van de Ven, Linus Torvalds, linux-kernel,
	Thomas Gleixner

Ingo Molnar wrote:
> 
> a config option is definitely useful for users and distros. Having the 
> boot option is a good idea. Arjan, i thought we had a fastboot=0/1 boot 
> option but i cannot find it - could you please add it?
> 

In general, boolean options should be fastboot/nofastboot.  We have 
plenty of inconsistency in that area, but we really don't need to add more.

	-hpa

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [git pull] fastboot tree for v2.6.28
  2008-10-11 14:11           ` H. Peter Anvin
@ 2008-10-24 18:26             ` Olivier Blin
  0 siblings, 0 replies; 8+ messages in thread
From: Olivier Blin @ 2008-10-24 18:26 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Ingo Molnar, Andrew Morton, Arjan van de Ven, Linus Torvalds,
	linux-kernel, Thomas Gleixner, Pascal Terjan

"H. Peter Anvin" <hpa@zytor.com> writes:

> Ingo Molnar wrote:
>>
>> a config option is definitely useful for users and distros. Having
>> the boot option is a good idea. Arjan, i thought we had a
>> fastboot=0/1 boot option but i cannot find it - could you please add
>> it?
>
> In general, boolean options should be fastboot/nofastboot.  We have
> plenty of inconsistency in that area, but we really don't need to add
> more.

Actually, the fastboot boot option is already used in RedHat's
rc.sysinit (to skip fsck). Can't we have async_init/sync_init boot
options to control this feature?

BTW, is there already some patch available for this option?

-- 
Olivier Blin (blino) - Mandriva

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2008-10-24 18:57 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-10-10  0:32 [git pull] fastboot tree for v2.6.28 Ingo Molnar
2008-10-10 20:10 ` Linus Torvalds
2008-10-10 22:49   ` Arjan van de Ven
2008-10-11  6:47     ` Ingo Molnar
2008-10-11  7:48       ` Andrew Morton
2008-10-11  8:28         ` Ingo Molnar
2008-10-11 14:11           ` H. Peter Anvin
2008-10-24 18:26             ` Olivier Blin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).