Appendix A
Interrupt delay test code:
This is a patch file, compiling under my Linux-2.2.12 version. Paste it into the Linux source file by the following command:
# cd /usr/src/linux-2.2.12
# patch -p1
Compile the Linux kernel after the paste is completed:
# cd /usr/src/linux-2.2.12
# Make config # Configure the kernel
# Make Dep
# Make Bzimage # Compile the kernel
# MAKE MODULES # Compilation Module
# Make Modules_Install # loading module
# CP Arch / i386 / boot / bzimage / boot / interrupt-lattency
Configure LILO, edit /etc/lilo.conf, add the following lines to:
Image = / boot / interrupt-latency
Label = interrupt-lattency
Read-only
Root = / dev / hda1
Re-decorate LILO:
# / sbin / lilo
Enter the LILO prompt after restart:
INTERRUPT-LATENCY
The kernel that can monitor the system call open / off interrupt is completed, and you need to run a user spatial program (see.c, see below) for entering commands and printing test results.
The interrupt-latency-2.2.12-patch file is as follows:
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
10:18:53
1999
Linux-2.2.12-Interrupt / Arch / I386 / KERNEL / MAKEFILE MON Mar 6
11:04:25
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
08:13:37
1999
Linux-2.2.12-Interrupt / Arch / I386 / KERNEL / ENTRY.S MON Mar 6
11: 05: 102000
@@ -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
22:57:25
1999
Linux-2.2.12-Interrupt / Arch / I386 / KERNEL / Head.s Mon Mar 6
11:14:26
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
16:00:00
1969
Linux-2.2.12-Interrupt / Arch / I386 / KERNEL / INTR_BLOCKING.C MON Mar 6
11:41:50
2000
@@ -0, 0 1,322 @@
# include
/ **** Platform **** /
# Define Readclock (low) /
__ASM__ __Volatile__ ("RDTSC": "= a" (low): "EDX")
/ **** configure **** /
# define num_log_entry 4
# define INTR_IENABLE 0x200
/ **** Data structure **** / struct intertata {
/ * 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 ceertheng @ /
Unsigned Rangelow;
Unsigned rangehigh;
/ * Count the total number interrupts and intrs in inn * /
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 clean cout.
* /
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 (INTDATA.LOGFLAG == 0) || (INTRDATA.PANICFLAG! = 0) {
Return
}
/ * Do nothing We Had if clear 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;
INTRSTARTFILINE = LINENO;
ReadClock (intrstartcount);
}
/ * Strategy:
* We do a count online
* 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 (INTDATA.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 (INTDATA.SYNCFLAG! = 1) {
INTRDATA.SYNCSTIROR ;
__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 = 0xffffffffff;
Unsigned lowestindex;
Unsigned SameIndex = 0xffffffffff;
INTRDATA.NUMINRANGEINTRS ;
/ * Check if we need to log this event * /
For (i = 0; 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 number area is the first chars in * Both File Names Are Same, We consider it is the same * Entry. * / SameIndex = i; } } IF (SameIndex == 0xfffffffff) { 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 (INTDATA.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 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 21:28:12 1999 Linux-2.2.12-Interrupt / include / ASM-I386 / System.h Mon Mar 6 11:08:02 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": / * 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": / * 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 / * The user spatial program View.c is as follows: #include #include #include #include #include / ***************** CONFIG **************** / #define Num_Log_ENTRY 4 #define clock_frequency 266 / * cycles per microsecond * / #define syscall_number 191 / ****************** * End of config ************** / #define cmd_exit 0 # Define cmd_display 1 #define cmd_start 2 #define cmd_stop 3 #define cmd_continue 4 #define cmd_set_Range 5 #define cmd_last 6 Struct intertata { / * 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 ceertheng @ / UNSIGNED RANGELOW; UNSIGNED RANGEHIGH; / * Count the total number interrupts and intrs in inn * / UNSIGNED NUMINTRS; UNSIGNED NUMINRANGEINTRS; / * Error Accounting * / UNSIGNED SKIPSTI; UNSIGNED SKIPCLI; UNSIGNED SYNCSTIROR; 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]; } UNSIGNED PDATA; Struct intrdata data; INT KMEM; Char BUF [81]; Unsigned int Getint (const char * prompt) { Unsigned Int i; Printf ("% s", prompt); Scanf ("% D", & i); Return I; } Unsigned int getHex (const char * prompt) { Unsigned Int i; Printf ("% s", prompt); Scanf ("% x", & i); Return I; } Unsigned getcommand () { For (;;) { UNSIGNED CMD; Printf ("/ n"); Printf ("Command Menu / N"); Printf ("============== / n"); Printf ("0-EXIT 1-Display 2-start logging 3-stop logging 4-payging / n"); Printf ("5-SET RANGE / N"); Printf ("/ n"); Printf ("Your Choice:"); Scanf ("% u", & cmd); IF ((cmd> = 0) && (cmd Return CMD; } else { Printf ("INVALID Choice !!!!! / N / N"); } } } Unsigned getkMemint (unsigned offset) { OFF_T Seekerror; SSIZE_T SIZE; Unsigned Num = 0; Assert ((Offset & 3) == 0); Seekerror = lseek (kmem, offset, seek_set); Assert (seekerror! = (OFF_T) -1); Size = Read (KMEM, & Num, SizeOf (NUM); Assert (sizeof (num) == 4); assert (size == 4); Return Num; } Char * getkMemString (unsigned offset) { OFF_T Seekerror; SSIZE_T SIZE; BUF [80] = 0; BUF [0] = 0; IF (Offset == 0) Return BUF; Seekerror = lseek (kmem, offset, seek_set); Assert (seekerror! = (OFF_T) -1); Size = read (KMEM, BUF, 80); Assert (size == 80); Return BUF; } Void getkmemblock (unsigned offset, void * buf, unsigned bufsize) { OFF_T Seekerror; SSIZE_T SIZE; Seekerror = lseek (kmem, offset, seek_set); Assert (seekerror! = (OFF_T) -1); Size = Read (KMEM, BUF, BUFSIZE); Assert (size == buffsize); } Void SetKMemBlock (unsigned offset, void * buf, unsigned bufsize) { OFF_T Seekerror; SSIZE_T SIZE; Seekerror = lseek (kmem, offset, seek_set); Assert (seekerror! = (OFF_T) -1); Size = Write (KMEM, BUF, BUFSIZE); Assert (size == buffsize); } Void setkMemint (unsigned offset, unsigned x) { OFF_T Seekerror; SSIZE_T SIZE; Seekerror = lseek (kmem, offset, seek_set); Assert (seekerror! = (OFF_T) -1); size = write (kmem, & x, sizeof (x)); askERT (size == sizeof (x)); } Void Display () { UNSIGNED I; GetKMemBlock (PDATA, & DATA, SIZEOF (DATA); Printf ("% s: / n", getkMemString ((unsigned) data.testname); Printf ("BreakCount:% D / N", DATA.BREAKCOUNT); Printf ("Logflag:% D / N", Data.logflag; Printf ("PanicFlag:% D / N", Data.PanicFlag; Printf ("SyncFlag:% D / N", DATA.SyncFlag; Printf ("Range: [% U):% u (0x% x)] / N", Data.rangelow, Data.Rangelow, Data.Rangehigh, Data.Rangehigh Printf ("NUMINTRS:% U / N", DATA.NUMINTRS; Printf ("NUMINRANGEINTS:% U / N", DATA.NUMINRANGEINTRS Printf ("Skipsti SkipCli Syncsti SyncCli Stibreak Reststi RESTCLI / N"); Printf ("% D / T% D / T% D / T% D / T% D / T% D / T% D / T / N", Data.skipsti, Data.skipCli, Data.syncstierror, Data.syncClierror, Data.stibreakerror, Data.restoSti, Data.restoreCli); For (i = 0; i Printf ("Log Entry:% D / N", I); Printf ("/ TBLOCKINGTIME:% U (% U US) / N", Data.count [i] .blockingtime, Data.count [i] .bockingTime / clock_frequency); Printf ("/ tstartfilename:% s / n", GetkMemString ((unsigned) Data.count [i] .startfilename); Printf ("/ tstartfileline:% u / n", data.count [i] .startfileline); Printf ("/ tstartcount:% u / n", data.count [i] .startcount); Printf ("/ TENDFILENAME:% S / N", GetkMemString ((unsigned) Data.count [i] .endfilename); Printf ("/ TENDFILINE:% u / n", data.count [i] .endfileline); Printf ("/ tendcount:% u / n", data.count [i] .endcount); } Printf ("/ n"); } Void startlogging () { UNSIGNED I; / * init first * / Data.breakcount = 0; DATA.LOGFLAG = 0; Data.panicflag = 0; Data.syncflag = 0; Data.numIntrs = 0; Data.numinRangeInTRS = 0; DATA.SKIPSTI = Data.skipCli = Data.syncstierror = Data.syncClierRor = Data.stibreakerror = Data.Restoresti = Data.RestoreCli = 0; For (i = 0; i Data.count [i] .blockingTime = 0; Data.count [i] .StartFileName = 0; Data.count [i] .StartFileLine = 0; Data.count [i] .startcount = 0; Data.count [i] .endfilename = 0; Data.count [i] .endfileline = 0; Data.count [i] .endcount = 0; } SetKMemBlock (PDATA, & DATA, SIZEOF (DATA); / * Turn the logging flag * / SetKMEMINT (PDATA & DATA.LOGFLAG - & DATA), 1); } void endlogging () { / * Turn the logging flag * / SetKMEMINT (PDATA & data.logflag - (unsigned) & data), 0); } Void Continueloggin () { / * Turn the logging flag * / SetKMEMINT (PDATA & DATA.LOGFLAG - & DATA), 1); } Void setRange () { Data.rangelow = GetInt ("INPUT LOWER Bound (Decimal):"); Printf ("/ TLOWER BOUND IS% U (0x% x) / n", DATA.RANGELOW, DATA.RANGELOW); Data.Rangehigh = GetInt ("INPUT UPPER Bound (Decimal):"); Printf ("/ Tupper Bound IS% U (0x% x) / N", DATA.RANGEHIGH, DATA.RANGEHIGH); SetKMEMINT (PDATA & DATA.RANGELOW - & DATA), Data.rangelow; SetKMEMINT (PDATA & DATA.RANGEHIGH - & DATA), Data.RangehiGH; } Main () { Unsigned int CMD; unsigned long offset; KMEM = Open ("/ dev / kmem", o_rdwr); Assert (kmem> 0); IF (Syscall_Number, & PDATA)! = 0) { Printf ("Failed to Get Jsundata Address Through Syscall 191! / N"); PDATA = GetHex ("INPUT ManNually The Address of Jsundata:"); } GetKMemBlock (PDATA, & DATA, SIZEOF (DATA); For (;;) { CMD = getcommand (); Switch (cmd) { Case cmd_display: DISPLAY (); Break; Case cmd_start: StartLogging (); Break; Case cmd_stop: ENDLOGGING (); Break; Case cmd_continue: Continueloggin (); Break; Case cmd_set_range: SetRANge (); Break; Case cmd_exit: Close (KMEM); Return; DEFAULT: Assert (0 == 1); } } } Appendix B Context switching test program lat_ctx.c: / * * LAT_CTX.C - Context Switch Timer * * usage: lat_ctx [-s size] #procs [#procs ....] * * Copyright (c) 1994 Larry McVoy. Distributed Under The FSF GPL with * Additional Restriction That Results May Published Only IF * (1) The Benchmark IS unmodified, and * (2) The Version in The Sccsid Below Is Included in The Report. * Support for this development by Sun Microsystems is gratefully Acknowledged. * / Char * id = "$ ID $ / n"; #include "bench.h" #if Defined (SGI) && Defined (PIN) #include #include Int ncpus; #ENDIF #define maxProc 2048 #define chunk (4 << 10) #define Trips 5 #ifndef max #define max (a, b) ((a)> (b)? (a): (b)) #ENDIF INT process_size, * data; / * size & pointer to an array what big * / INT PIDS [MAXPROC]; INT P [MAXPROC] [2]; Double PIPE_COST (INT P [】 [2], int procs); INT CTX (int procs, int nprocs); Int Sumit (int); Void Killem (INT Procs); Void DOIT (int P [MaxProc] [2], int RD, int WR); INT CREATE_PIPES (INT P [], int procs; INT CREATE_DAEMONS (int P [], int PIDS [], int procs; int Main (int AC, char ** av) { INT I, MAX_PROCS; Double Overhead = 0; IF (AC <2) { USAGE: Printf ("Usage:% s [-s kbytes] processes [Processes ...] / N", AV [0]); Exit (1); } / * * NEED 4 BYTE INTS. * / IF (SIZEOF (int)! = 4) { FPRINTF (stderr, "fix sumit () in ctx.c./n"); Exit (1); } / * * If The specified a context size, get it. * / IF (! Strcmp (AV [1], "-s")) { IF (AC <4) { Goto usage; } Process_size = ATOI (AV [2]) * 1024; IF (Process_Size> 0) { Data = (int *) Calloc (1, Max (Process_Size, Chunk); Bencho (SUMIT (CHUNK), SUMIT (0), 0); Overhead = gettime (); Overhead / = GET_N (); Overhead * = process_size; Overhead / = chunk; } AC - = 2; AV = 2; } #if Defined (SGI) && Defined (PIN) NCPUS = SYSMP (MP_nprocs); SYSMP (MP_MUSTRUN, 0); #ENDIF For (Max_Procs = ATOI (AV [1]), i = 1; i INT procs = atoi (AV [i]); IF (MAX_PROCS } Max_Procs = Create_pipes (p, max_procs); Overhead = PIPE_COST (p, max_procs); Max_Procs = CREATE_DAEMONS (P, PIDS, MAX_PROCS); FPRINTF (stderr, "/ n /" size =% DK OVR =%. 2F / n ", process_size / 1024, overhead); For (i = 1; i Double Time; INT procs = atoi (AV [i]); IF (Procs> Max_Procs) Continue; Bench (CTX (Procs, Max_Procs), 0); Time = USECS_SPENT (); Time / = GET_N (); TIME / = procs; Time / = trips; Time - = Overhead; FPRINTF (stderr, "% D% .2f / n", procs, time); } / * * Close The Pipes and kill the children. * / Killem (MAX_PROCS); For (i = 0; i Close (p [i] [1]); IF (i> 0) { Wait (0); } } Return (0); } int CTX (int procs, int nprocs) { Int msg; INT I; Int sum; / * * Main Process - All Others Should Be Ready To Roll, Time The * loop. * / For (i = 0; i IF (Write (P [NPROCS - PROCS] [1], & MSG, SIZEOF (MSG))! = SizeOf (MSG)) { PERROR ("Read / Write on Pipe"); Exit (1); } IF (read (p [nprocs-1] [0], & msg, sizeof (msg))! = sizeof (msg)) { PERROR ("Read / Write on Pipe"); Exit (1); } SUM = SUMIT (Process_Size); } Return (SUM); } Void Killem (int procs) { INT I; For (i = 1; i IF (PIDS [i]> 0) { Kill (PIDS [I], SIGTERM; } } } Void DOIT (int P [】 [2], int RD, INT WR) { INT MSG, SUM = 0 / * LINT * / Signal (SIGTERM, SIG_DFL); IF (data) Bzero ((void *) data, process_size); For (;;) { IF (read (p [rd], & msg, sizeof (msg))! = SizeOf (msg)) { PERROR ("Read / Write on Pipe"); Break; } SUM = SUMIT (Process_Size); IF (Write (P [P [WR], & MSG, SIZEOF (MSG))! = SizeOf (MSG)) { PERROR ("Read / Write on Pipe"); Break; } } USE_INT (SUM); Exit (1); } int DOIT_COST (int P [】 [2], int procs { Static Int K; INT msg = 1; INT I; For (i = 0; i IF (WRITE (P [K] [1], & MSG, SIZEOF (MSG))! = SizeOf (MSG)) { PERROR ("Read / Write on Pipe"); Exit (1); } IF (read (p [k] [0], & msg, sizeof (msg))! = sizeof (msg)) { PERROR ("Read / Write on Pipe"); Exit (1); } IF ( k == procs) { K = 0; } } Return (MSG); } / * * The cost return is the cost of going through one pipe overca. * No Memory Costs Are Included Here, This Is Different Than Lmbench1. * / Double PIPE_COST (int P [】 [2], int procs) { Double Result; / * * Measure the overhead of passing a byte arround the ring. * / Bench (DOIT_COST (P, Procs), 0); Result = USECS_SPENT (); Result / = GET_N (); Result / = trips; Return Result; } int Create_daemons (int P [】 [2], int pids [], int procs { INT I; Int msg; / * * Use the pipes as a ring, and fork off a bunch of processes * to pass the byte through their part of the ring. * * Do The Sum in Each Process And Get Time Before Moving ON. * / Signal (SIGTERM, SIG_IGN); For (i = 1; i Switch (PIDS [i] = fork ()) { Case -1: / * could Not fork, Out of Processes? * / procs = i; Break; Case 0: / * child * / #if Defined (SGI) && Defined (PIN) SYSMP (MP_MUSTRUN, I% NCPUS); #ENDIF DOIT (P, I-1, I); / * NotReached * / Default: / * parent * / ; } } / * * Go ONCE AROUND THE LOOP To Make Sure That Everyone Is Ready and * to get the token in the pipeline. * / IF (Write (P [0] [1], & MSG, SIZEOF (MSG))! = SizeOf (MSG) || Read (p [procs-1], & msg, sizeof (msg))! = SizeOf (MSG)) { PERROR ("Write / Read / Write on Pipe); Exit (1); } IF (data) Bzero ((void *) data, process_size); Return procs; } int Create_pipes (int P [】 [2], int procs { INT I; / * * Get a bunch of pipes. * / Morefds (); For (i = 0; i IF (Pipe (P [I]) == -1) { Return I; } } Return procs; } / * * Bring hoWMUCH DATA INTO The Cache, Assuming That The smallest cache * LINE IS 16 bytes. * / int SUMIT (int howmuch) { INT DONE, SUM = 0; Register int * D = data; #if 0 #define a sum = d [0] D [4] D [8] D [12] D [16] D [20] D [24] D [28] / D [32] D [36] D [40] D [44] D [48] D [52] D [56] D [60] / D [64] D [68] D [72] D [76] D [80] D [84] D [88] D [92] / D [96] D [100] D [104] D [108] D [112] D [116] D [120] D [124]; / D = 128; #define twokb a a a a a a #ELSE #define a sum = d [0] D [1] D [2] D [3] D [4] D [5] D [6] D [7] D [8] D [9] / D [10] D [11] D [12] D [13] D [14] D [15] D [16] D [17] D [18] D [19] / D [20] D [21] D [22] D [25] D [26] D [27] D [28] D [29] / D [30] D [31] D [32] D [33] D [34] D [35] D [36] D [37] D [38] D [39] / D [40] D [41] D [42] D [43] D [44] D [45] D [46] D [47] D [48] D [49] / D [50] D [51] D [52] D [53] D [54] D [55] D [56] D [57] D [58] D [59] / D [60] D [61] D [62] D [63] D [64] D [65] D [66] D [67] D [68] D [69] / D [70] D [71] D [72] D [73] D [74] D [75] D [76] D [77] D [78] D [79] / D [80] D [81] D [82] D [83] D [84] D [85] D [86] D [87] D [88] D [89] / D [90] D [91] D [92] D [93] D [94] D [95] D [96] D [97] D [98] D [99] / D [100] D [101] D [102] D [103] D [104] / D [105] D [106] D [107] D [108] D [109] / D [110] D [111] D [112] D [113] D [114] / D [115] D [116] D [117] D [118] D [119] / D [120] D [121] D [122] D [123] D [124] D [125] D [126] D [127]; / D = 128; / * INTS; BYTES == 512 * / #define twokb a a a a a a #ENDIF For (DONE = 0; DONE Twokb } Return (SUM); } / * Bench.h * / #ifndef _bench_h #define _bench_h #ifdef Win32 #include Typedef unsigned char bool_t; #ENDIF #include #include #include #ifndef Win32 #include #ENDIF #include #include #include #include #ifndef Win32 #include #ENDIF #include #ifndef Win32 #include #ENDIF #include #ifndef Win32 #include #include #include #include #include #include #define portmap #include #ENDIF #ifndef Have_uint Typedef unsigned int uint #ENDIF #ifdef Have_UINT64_T Typedef uint64_t uint64; #ELSE TYPEDEF UNSIGNED Long Long uint64; #ENDIF #define no_portmapper / * Needs to be up here, lib_ *. h look at it * / #include "stats.h" #include "Timing.h" #include "lib_tcp.h" #include "lib_udp.h" #include "lib_unix.h" #ifdef debug # Define debug (x) fprintf x #ELSE # Define debug (x) #ENDIF #ifdef no_portmapper #define TCP_SELECT-31233 #define tcp_xact -31234 #define TCP_Control -31235 #define tcp_data -31236 # Define TCP_CONNECT -31237 #define udp_xact -31238 #define udp_data -31239 #ELSE #define tcp_select (u_long) 404038 / * xxx - unregistered * / #define tcp_xact (u_long) 404039 / * xxx - unregistered * / #define tcp_control (u_long) 404040 / * xxx - unregistered * / #define TCP_DATA (U_LONG) 404041 / * XXX - Unregistered * / #define TCP_CONNECT (U_LONG) 404042 / * xxx - unregistered * / #define udp_xact (u_long) 404032 / * xxx - unregistered * / #define udp_data (u_long) 404033 / * xxx - unregistered * / #define VERS (U_LONG) 1 #ENDIF #define unix_control "/tmp/lmbench.ctl" #define unix_data "/tmp/lmbench.data" #define unix_lat "/tmp/lmbench.lat" / * * Socket Send / Recv Buffer Optimizations * / #define sockopt_read 0x0001 #define sockopt_write 0x0002 #define sockopt_rdwr 0x0003 #define sockopt_pid 0x0004 #define sockopt_reuse 0x0008 #define sockopt_none 0 #ifndef sockbuf #define sockbuf (1024 * 1024) #ENDIF #ifndef XFERSIZE #define XFERSIZE (64 * 1024) / * All Bandwidth I / O SHOULD USE * / #ENDIF #if defined (Sys5) || Defined (Win32) #define Bzero (B, LEN) MEMSET (B, 0, LEN) #define bcopy (S, D, L) Memcpy (D, S, L) #define rindex (s, c) Strrchr (s, c) #ENDIF #define gettime usecs_spent #define streq! Strcmp #define ulong unsigned long #ifdef use_rand #define SRAND48 SRAND #define Drand48 () (Double) RAND () / (double) Rand_max) #ENDIF #ifdef use_random #define SRAND48 SRAND #define Drand48 () (Double) RAND () / (double) Rand_max) #ENDIF #ifdef Win32 #include #define getpid _getpid INT getTimeOfDay (struct timeval * tv, struct timezone * tz); # endif #define smallest_line 32 / * Smallst Cache Line Size * / #define Time_Open2Close #define Go_Away Signal (SIGALRM, EXIT); ALARM (60 * 60); #define real_short 50000 #define Short 1000000 #define Medium 2000000 #define longer 7500000 / * for networking data transfer * / #define enough real_short #define Tries 11 Typedef struct { Int n; UINT64 U [Tries]; UINT64 N [Tries]; } result_t; Void insertinit (Result_t * r); Void insertsort (uint64, uint64, result_t *); Void save_median (); Void save_minimum (); Void Save_Results (Result_t * R); Void get_results; result_t * r); #define bencho (loop_body, overhead_body, enough) {/ INT __I, __N; / Double __oh; / Result_t __overhead, __r; / Insertinit (& __ overhead); InsertInit (& __ R); / __N = (Enough == 0 || GET_ENOUGH (Enough) <= 100000)? Tries: 1; / IF (Enough FOR (__i = 0; __i <__n; __ i) {/ Bench1 (Overhead_Body, Enough; / IF (getTime ()> 0) / INSERTSORT (GetTime (), get_n (), & __ overhead); / Bench1 (Loop_Body, Enough; / IF (getTime ()> 0) / INSERTSORT (GetTime (), get_n (), & __ r); / } / FOR (__i = 0; __i <__r.n; __ i) {/ __oh = __OverHead.u [__ i] / (double) __ overhead.n [__ i]; / __r.u [__ i] - = (uint64) ((double) __ r.N [__ i] * __oh); / } / Save_results (& __ r); / } #define Bench (loop_body, enough) {/ Long __i, __n; / Result_t __r; / Insertinit (& __ r); / __N = (Enough == 0 || GET_ENOUGH (Enough) <= 100000)? Tries: 1; / IF (Enough FOR (__i = 0; __i <__n; __ i) {/ Bench1 (Loop_Body, Enough; / IF (getTime ()> 0) / INSERTSORT (GetTime (), get_n (), & __ r); / } / Save_Results (& __ r); / } #define beench1 (loop_body, enough) {/ Double __Usecs; / Bench_inner (loop_body, enough); / __Usecs = getTime (); / __Usecs - = t_overhead () GET_N () * l_overhead (); / Settime (__ usecs> = 0.? (uint64) __ @ecs: 0.); / } #define bench_inner (loop_body, enough) {/ Static u_long __Item = 1; / INT __ENOUGH = GET_ENUGH (Enough); / u_long __n; / Double __Result = 0 .; / / While (__ result <0.95 * __enough) {/ Start (0); / For (__n = __Ipect); __n> 0; __n--) {/ LOOP_BODY; / } / __RESULT = STOP (0, 0); / IF (__Result <0.99 * __enough / || __Result> 1.2 * __enough) {/ IF (__Result> 150.) {/ double tmp = __Items / __RESULT; / TMP * = 1.1 * __enough; / __Item = (U_LONG) (TMP 1); / } else {/ IF (__Iterations> (u_long) 1 << 27) {/ __RESULT = 0 .; / Break; / } / __IpectInces << = 3; / } / } / } / * while * / / Save_n ((uint64) __ ipiography; settime ((uint64) __ result); / } / * * Generated from msg.x which is includD here: Program XACT_PROG { Version XACT_VERS { charr RPC_XACT (CHAR) = 1; } = 1; = 3970; * Please do not edit this file. * IT WAS generated using rpcgen. * / #include #define XACT_PROG ((u_long) 404040) #define XACT_VERS ((U_LONG) 1) #define rpc_xact (u_long) 1) #define rpc_exit (u_long) 2) EXTERN CHAR * RPC_XACT_1 (); EXTERN CHAR * Client_rpc_xact_1 (); #ENDIF / * _BENCH_H * /