diff -u -ruN linux-2.4.20.orig/Documentation/Configure.help linux-2.4.20.time_bootup/Documentation/Configure.help
--- linux-2.4.20.orig/Documentation/Configure.help	Thu Nov 28 15:53:08 2002
+++ linux-2.4.20.time_bootup/Documentation/Configure.help	Fri Sep 19 14:43:39 2003
@@ -25505,6 +25505,15 @@
   early in the boot process, but only if you have a VGA screen
   attached.  If you're unsure, select N.
 
+Configure timing instrumentation for printk
+CONFIG_TIME_BOOTUP
+  Selecting this option causes extra timing information to be included
+  in printks from the kernel, which allows you to see how long
+  bootup operations take.  It also moves console_init to later in the
+  kernel initialization sequence, to avoid having console output overhead
+  interfere with the timing measurements.  This option should only be
+  used during development for identifying long delays in kernel startup.
+
 Print possible IA64 hazards to console
 CONFIG_IA64_PRINT_HAZARDS
   Selecting this option prints more information for Illegal Dependency
diff -u -ruN linux-2.4.20.orig/arch/i386/config.in linux-2.4.20.time_bootup/arch/i386/config.in
--- linux-2.4.20.orig/arch/i386/config.in	Thu Nov 28 15:53:09 2002
+++ linux-2.4.20.time_bootup/arch/i386/config.in	Fri Sep 26 13:14:13 2003
@@ -316,6 +316,11 @@
    bool '    Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF
 fi
 
+bool 'Configure timing instrumentation in printk' CONFIG_TIME_BOOTUP
+if [ "$CONFIG_TIME_BOOTUP" != "n" ]; then
+   define_bool CONFIG_DELAY_CONSOLE_INIT y
+fi
+
 endmenu
 
 source drivers/mtd/Config.in
diff -u -ruN linux-2.4.20.orig/include/asm-i386/timex.h linux-2.4.20.time_bootup/include/asm-i386/timex.h
--- linux-2.4.20.orig/include/asm-i386/timex.h	Wed Oct  1 10:30:52 2003
+++ linux-2.4.20.time_bootup/include/asm-i386/timex.h	Fri Sep 26 16:06:36 2003
@@ -9,6 +9,10 @@
 #include <linux/config.h>
 #include <asm/msr.h>
 
+#ifdef CONFIG_TIME_BOOTUP
+#include <linux/time.h>
+#endif
+
 #ifdef CONFIG_MELAN
 #  define CLOCK_TICK_RATE 1189200 /* AMD Elan has different frequency! */
 #else
@@ -52,6 +56,38 @@
 
 extern unsigned long cpu_khz;
 
+#ifdef CONFIG_TIME_BOOTUP
+static inline void highres_timer_read_ticks (u32 *slow, u32 *fast)
+{
+#ifndef CONFIG_X86_TSC
+	fast = slow = 0;
+	return;
+#else
+	/* rdtsc(fast, slow); */
+	unsigned long long ticks;
+	rdtscll(ticks);
+	*slow = ticks>>32;
+	*fast = ticks & 0xffffffff;
+
+#endif
+}
+
+
+static inline void highres_timer_ticks_to_timeval(u32 slow, u32 fast, struct timeval *tv)
+{
+	/* would be nice to use probed cpu_khz here, but it
+	 * likely isn't set yet.  Set the following for your
+	 * machine! Hint: boot once and look at /proc/cpuinfo */
+	u32 fixed_cpu_khz = 645206;
+
+	/* a little sloppy math here... */
+	tv->tv_sec = slow*(0xffffffff/(fixed_cpu_khz*1000));
+	tv->tv_sec += fast/(fixed_cpu_khz*1000);
+	tv->tv_usec = (fast%(fixed_cpu_khz*1000))/(fixed_cpu_khz/1000);
+}
+#endif
+
+
 #define vxtime_lock()		do {} while (0)
 #define vxtime_unlock()		do {} while (0)
 
diff -u -ruN linux-2.4.20.orig/kernel/printk.c linux-2.4.20.time_bootup/kernel/printk.c
--- linux-2.4.20.orig/kernel/printk.c	Fri Aug  2 17:39:46 2002
+++ linux-2.4.20.time_bootup/kernel/printk.c	Mon Sep 22 13:38:05 2003
@@ -29,6 +29,11 @@
 
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_TIME_BOOTUP
+#include <linux/time.h>
+#include <asm/timex.h>
+#endif
+
 #if defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64)
 #define LOG_BUF_LEN	(65536)
 #elif defined(CONFIG_ARCH_S390)
@@ -434,11 +439,44 @@
 	 */
 	for (p = printk_buf; *p; p++) {
 		if (log_level_unknown) {
+#ifdef CONFIG_TIME_BOOTUP
+			int loglev_char;
+			char tbuf[50], *tp;
+			unsigned tlen;
+			u32 slow, fast;
+			struct timeval tv;
+
+			highres_timer_read_ticks (&slow, &fast);
+			highres_timer_ticks_to_timeval (slow, fast, &tv);
+
+			/* Force the log level token to be
+			   before our diagnostic output.  */
+			if (p[0] == '<' && p[1] >= '0'
+			    && p[1] <= '7' && p[2] == '>')
+			{
+				loglev_char = p[1];
+				p += 3;
+			} else
+				loglev_char = default_message_loglevel + '0';
+
+			tlen = sprintf (tbuf,
+					"<%c>[%5lu.%06lu <%5lu:%5lu>] ",
+					loglev_char,
+					tv.tv_sec, tv.tv_usec,
+					(unsigned long)slow,
+				        (unsigned long)fast);
+			
+			for (tp = tbuf; tp < tbuf + tlen; tp++)
+				emit_log_char (*tp);
+
+#else /* !CONFIG_TIME_BOOTUP */
 			if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') {
 				emit_log_char('<');
 				emit_log_char(default_message_loglevel + '0');
 				emit_log_char('>');
 			}
+#endif /* CONFIG_TIME_BOOTUP */
+
 			log_level_unknown = 0;
 		}
 		emit_log_char(*p);
