附录A <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
中断延迟测试代码:
这是一个补丁(patch)文件,在我的Linux-2.2.12版本下编译通过。通过下面的命令粘贴到Linux源文件中:
# cd /usr/src/linux-2.2.12
# patch –p1 < /usr/src/linux-2.2.12/interrupt-latency-2.2.12-patch
粘贴完成后编译Linux内核:
# cd /usr/src/linux-2.2.12
# make config # 配置内核
# make dep
# make bzImage # 编译内核
# make modules # 编译模块
# make modules_install # 装载模块
# cp arch/i386/boot/bzImage /boot/interrupt-lattency
配置LILO,编辑/etc/lilo.conf,把下面几行添加进:
image=/boot/interrupt-latency
label=interrupt-lattency
read-only
root=/dev/hda1
重新装LILO:
# /sbin/lilo
重启后在LILO提示符下输入:
LILO: interrupt-latency
则可以监控系统调用开/关中断的内核就起动完成,还需要运行一个用户空间程序(view.c, 见下面)用于输入命令和打印测试结果。
interrupt-latency-2.2.12-patch文件如下:
diff --exclude=version.h --exclude=config.h -Nru linux-2.2.12/arch/i386/kernel/Makefile linux-2.2.12-interrupt/arch/i386/kernel/Makefile
--- linux-2.2.12/arch/i386/kernel/Makefile Wed Jan 20 <?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /><time hour="10" minute="18"><span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'; LETTER-SPACING: -0.4pt; mso-bidi-font-family: 'Times New Roman'">10:18:53</span></time> 1999
+++ linux-2.2.12-interrupt/arch/i386/kernel/Makefile Mon Mar 6 <time hour="11" minute="4"><span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'; LETTER-SPACING: -0.4pt; mso-bidi-font-family: 'Times New Roman'">11:04:25</span></time> 2000
@@ -14,7 +14,9 @@
O_TARGET := kernel.o
O_OBJS := process.o signal.o entry.o traps.o irq.o vm86.o \
- ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o
+ ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o \
+ intr_blocking.o
+
OX_OBJS := i386_ksyms.o
MX_OBJS :=
diff --exclude=version.h --exclude=config.h -Nru linux-2.2.12/arch/i386/kernel/entry.S linux-2.2.12-interrupt/arch/i386/kernel/entry.S
--- linux-2.2.12/arch/i386/kernel/entry.S Fri Apr 30 <time hour="8" minute="13"><span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'; LETTER-SPACING: -0.4pt; mso-bidi-font-family: 'Times New Roman'">08:13:37</span></time> 1999
+++ linux-2.2.12-interrupt/arch/i386/kernel/entry.S Mon Mar 6 <time hour="11" minute="5"><span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'; LETTER-SPACING: -0.4pt; mso-bidi-font-family: 'Times New Roman'">11:05:10</span></time> 2000
@@ -96,6 +96,7 @@
movl %dx,%es;
#define RESTORE_ALL \
+ incl intrData; \
popl %ebx; \
popl %ecx; \
popl %edx; \
@@ -562,6 +563,8 @@
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork) /* 190 */
+
+ .long SYMBOL_NAME(sys_get_intrData) /* 191 */
/*
* NOTE!! This doesn't have to be exact - we just have
diff --exclude=version.h --exclude=config.h -Nru linux-2.2.12/arch/i386/kernel/head.S linux-2.2.12-interrupt/arch/i386/kernel/head.S
--- linux-2.2.12/arch/i386/kernel/head.S Thu Jan 14 <time hour="22" minute="57"><span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'; LETTER-SPACING: -0.4pt; mso-bidi-font-family: 'Times New Roman'">22:57:25</span></time> 1999
+++ linux-2.2.12-interrupt/arch/i386/kernel/head.S Mon Mar 6 <time hour="11" minute="14"><span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'; LETTER-SPACING: -0.4pt; mso-bidi-font-family: 'Times New Roman'">11:14:26</span></time> 2000
@@ -316,6 +316,7 @@
movl %ax,%es
pushl $int_msg
call SYMBOL_NAME(printk)
+ incl intrData
popl %eax
popl %ds
popl %es
diff --exclude=version.h --exclude=config.h -Nru linux-2.2.12/arch/i386/kernel/intr_blocking.c linux-2.2.12-interrupt/arch/i386/kernel/intr_blocking.c
--- linux-2.2.12/arch/i386/kernel/intr_blocking.c Wed Dec 31 <time hour="16" minute="0"><span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'; LETTER-SPACING: -0.4pt; mso-bidi-font-family: 'Times New Roman'">16:00:00</span></time> 1969
+++ linux-2.2.12-interrupt/arch/i386/kernel/intr_blocking.c Mon Mar 6 <time hour="11" minute="41"><span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'; LETTER-SPACING: -0.4pt; mso-bidi-font-family: 'Times New Roman'">11:41:50</span></time> 2000
@@ -0,0 +1,322 @@
+#include <asm/system.h>
+
+
+/**** platform ****/
+#define readclock(low) \
+ __asm__ __volatile__ ("rdtsc" : "=a" (low) : : "edx")
+
+/**** configure ****/
+#define NUM_LOG_ENTRY 4
+#define INTR_IENABLE 0x200
+
+/**** data structure ****/
+struct IntrData {
+ /* count interrupt and iret */
+ int breakCount;
+
+ /* the test name */
+ const char * testName;
+
+ /* flag to control logging */
+ unsigned logFlag; /* 0 - no logging; 1 - logging */
+
+ /* panic flag - set to 1 if something is realy wrong */
+ unsigned panicFlag;
+
+ /* for synchro between start and end */
+ unsigned syncFlag;
+
+ /* we only log interrupts within certain range */
+ unsigned rangeLow;
+ unsigned rangeHigh;
+
+ /* count the total number interrupts and intrs in range*/
+ unsigned numIntrs;
+ unsigned numInRangeIntrs;
+
+
+ /* error accounting */
+ unsigned skipSti;
+ unsigned skipCli;
+ unsigned syncStiError;
+ unsigned syncCliError;
+ unsigned stiBreakError;
+ unsigned restoreSti;
+ unsigned restoreCli;
+
+ struct {
+ /* worst blocking time */
+ unsigned blockingTime;
+
+ const char * startFileName;
+ unsigned startFileLine;
+ unsigned startCount;
+
+ const char *endFileName;
+ unsigned endFileLine;
+ unsigned endCount;
+ } count[NUM_LOG_ENTRY];
+};
+
+struct IntrData intrData = {
+ 0,
+ "interrupt latency test (4 distinctive entries)",
+ 0,
+ 0,
+ 0,
+
+ 1,
+ 0xffffffff,
+
+ 0,
+ 0,
+
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+
+/**** functions ****/
+#if 0
+void intr_check_int(int x)
+{
+
+ unsigned flag;
+ __intr_save_flags(flag);
+
+ if ((flag & INTR_IENABLE) != 0) {
+ switch(x) {
+ case 0 :
+ intrData.count[0].blockingTime ++;
+ break;
+ case 1 :
+ intrData.count[0].startFileLine ++;
+ break;
+ case 2 :
+ intrData.count[0].startCount ++;
+ break;
+ case 3 :
+ intrData.count[0].endFileLine ++;
+ break;
+ case 4 :
+ intrData.count[0].endCount ++;
+ break;
+ default :
+ intrData.count[0].startFileName = "Wrong check number";
+ break;
+ }
+ } else {
+ switch(x) {
+ case 0 :
+ intrData.count[1].blockingTime ++;
+ break;
+ case 1 :
+ intrData.count[1].startFileLine ++;
+ break;
+ case 2 :
+ intrData.count[1].startCount ++;
+ break;
+ case 3 :
+ intrData.count[1].endFileLine ++;
+ break;
+ case 4 :
+ intrData.count[1].endCount ++;
+ break;
+ default :
+ intrData.count[1].startFileName = "Wrong check number";
+ break;
+ }
+ }
+}
+
+#endif
+
+
+static inline void intr_SetPanic(unsigned x, const char *fname, unsigned l)
+{
+ if (intrData.panicFlag != 0) {
+ /* double error; impossible */
+ intrData.panicFlag = 99;
+ return;
+ }
+ intrData.panicFlag = x;
+ intrData.count[0].startFileName = fname;
+ intrData.count[0].startFileLine = l;
+}
+
+static const char *intrStartFileName;
+static unsigned intrStartFileLine;
+static unsigned intrStartCount;
+
+/* strategy :
+ * if it is true "cli", i.e., clearing the IF, we remember
+ * everything, and clear breakCount.
+ */
+void intr_cli(const char *fname, unsigned lineno)
+{
+ unsigned flag;
+ __intr_save_flags(flag);
+
+ __intr_cli();
+
+ /* if we are not logging or we have an error, do nothing */
+ if ((intrData.logFlag == 0) || ( intrData.panicFlag != 0)) {
+ return;
+ }
+
+ /* do nothing we had IF cleared before we call this function */
+ if ((flag & INTR_IENABLE) == 0) {
+ intrData.skipCli ++;
+ return;
+ }
+
+ /* debug */
+ if (intrData.syncFlag == 1) {
+ intrData.syncCliError ++;
+ }
+ intrData.syncFlag = 1;
+
+ intrData.breakCount = 0;
+
+ /* Read the Time Stamp Counter */
+ intrStartFileName = fname;
+ intrStartFileLine = lineno;
+ readclock(intrStartCount);
+}
+
+
+/* strategy:
+ * we do a count only if
+ * 1. syncFlag is 1 (a valid cli() was called)
+ * 2. breakCount is 0 (no iret is called between cli() and this sti()
+ */
+void intr_sti(const char *fname, unsigned lineno)
+{
+ unsigned flag;
+ unsigned endCount;
+ unsigned diff;
+ int i;
+
+ __intr_save_flags(flag);
+
+ /* if we are not logging or we have an error, do nothing */
+ if ((intrData.logFlag == 0) || ( intrData.panicFlag != 0)) {
+ __intr_sti();
+ return;
+ }
+
+
+ /* check if this is a real sti() */
+ if ((flag & INTR_IENABLE) != 0) {
+ intrData.skipSti ++;
+ __intr_sti();
+ return;
+ }
+
+ /* check 1*/
+ if (intrData.syncFlag != 1) {
+ intrData.syncStiError ++;
+ __intr_sti();
+ return;
+ }
+
+ /* check 2 */
+ if (intrData.breakCount != 0) {
+ intrData.stiBreakError ++;
+ __intr_sti();
+ return;
+ }
+
+ /* read count again */
+ readclock(endCount);
+
+ intrData.syncFlag = 0;
+
+ diff = endCount - intrStartCount;
+
+ if ((diff >= intrData.rangeLow) && (diff <= intrData.rangeHigh)) {
+ unsigned lowest=0xffffffff;
+ unsigned lowestIndex;
+ unsigned sameIndex = 0xffffffff;
+
+ intrData.numInRangeIntrs++;
+
+ /* check if we need to log this event */
+ for (i=0; i< NUM_LOG_ENTRY; i++) {
+
+ if (lowest > intrData.count[i].blockingTime) {
+ lowest = intrData.count[i].blockingTime;
+ lowestIndex = i;
+ }
+
+ if ( (lineno == intrData.count[i].endFileLine) &&
+ (intrStartFileLine == intrData.count[i].startFileLine) &&
+ (fname[0] == intrData.count[i].endFileName[0]) &&
+ (intrStartFileName[0] == intrData.count[i].startFileName[0]) ) {
+ /* if the line numbers are same, the first chars in
+ * both file names are same, we consider it is the same
+ * entry. */
+ sameIndex = i;
+ }
+ }
+
+ if (sameIndex == 0xffffffff) {
+ i = lowestIndex;
+ } else {
+ i = sameIndex;
+ }
+
+ if (diff > intrData.count[i].blockingTime) {
+ intrData.count[i].blockingTime = diff;
+ intrData.count[i].endFileName = fname;
+ intrData.count[i].endFileLine = lineno;
+ intrData.count[i].endCount = endCount;
+ intrData.count[i].startFileName = intrStartFileName;
+ intrData.count[i].startFileLine = intrStartFileLine;
+ intrData.count[i].startCount = intrStartCount;
+ }
+ }
+
+ intrData.numIntrs++;
+ __intr_sti();
+}
+
+
+void intr_restore_flags(const char *fname, unsigned lineno, unsigned x)
+{
+ unsigned flag;
+
+ /* if we are not logging or we have an error, do nothing */
+ if ((intrData.logFlag == 0) || ( intrData.panicFlag != 0)) {
+ __intr_restore_flags(x);
+ return;
+ }
+
+ __intr_save_flags(flag);
+
+ if (((flag & INTR_IENABLE) == 0) &&
+ ((x & INTR_IENABLE) != 0) ) {
+ intrData.restoreSti ++;
+ intr_sti(fname, lineno);
+ }
+
+ if ( ((flag & INTR_IENABLE) != 0) &&
+ ((x & INTR_IENABLE) == 0) ) {
+ intrData.restoreCli ++;
+ intr_cli(fname, lineno);
+ }
+
+ __intr_restore_flags(x);
+}
+
+#include <asm/uaccess.h>
+
+asmlinkage int sys_get_intrData(void ** ptr)
+{
+ return put_user(&intrData, ptr);
+}
diff --exclude=version.h --exclude=config.h -Nru linux-2.2.12/include/asm-i386/system.h linux-2.2.12-interrupt/include/asm-i386/system.h
--- linux-2.2.12/include/asm-i386/system.h Mon Oct 11 <time hour="21" minute="28"><span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'; LETTER-SPACING: -0.4pt; mso-bidi-font-family: 'Times New Roman'">21:28:12</span></time> 1999
+++ linux-2.2.12-interrupt/include/asm-i386/system.h Mon Mar 6 <time hour="11" minute="8"><span lang="EN-US" style="FONT-SIZE: 9pt; FONT-FAMILY: 'Courier New'; LETTER-SPACING: -0.4pt; mso-bidi-font-family: 'Times New Roman'">11:08:02</span></time> 2000
@@ -174,13 +174,33 @@
#define wmb() __asm__ __volatile__ ("": : :"memory")
/* interrupt control.. */
+#if 0
#define __sti() __asm__ __volatile__ ("sti": : :"memory")
#define __cli() __asm__ __volatile__ ("cli": : :"memory")
#define __save_flags(x) \
__asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory")
#define __restore_flags(x) \
__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
+#endif
+#define __intr_sti() __asm__ __volatile__ ("sti": : :"memory")
+#define __intr_cli() __asm__ __volatile__ ("cli": : :"memory")
+#define __intr_save_flags(x) \
+__asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory")
+#define __intr_restore_flags(x) \
+__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
+
+/* jsun */
+extern void intr_cli(const char *, unsigned);
+extern void intr_sti(const char *, unsigned);
+extern void intr_restore_flags(const char *, unsigned, unsigned);
+extern void intr_sync_flag(const char *, unsigned lineno);
+
+#define __cli() intr_cli(__FILE__, __LINE__)
+#define __sti() intr_sti(__FILE__, __LINE__)
+#define __save_flags(x) \
+__asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */ :"memory")
+#define __restore_flags(x) intr_restore_flags(__FILE__, __LINE__, x)
#ifdef __SMP__
@@ -197,9 +217,8 @@
#define cli() __cli()
#define sti() __sti()
-#define save_flags(x) __save_flags(x)
+#define save_flags(x) __save_flags(x)
#define restore_flags(x) __restore_flags(x)
-
#endif
/*
用户空间程序view.c如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
/****************** CONFIG ****************/
#define<span sty