[PATCH] i386-pda UP optimization

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Seeing %gs prefixes used now by i386 port, I recalled seeing strange oprofile 
results on Opteron machines.

I really think %gs prefixes can be expensive in some (most ?) cases, even if 
the Intel/AMD docs say they are free.

I wrote this trivial User program to benchmark vfs_read()/vfs_write() that 
happens to use 'current' many times.

#include <unistd.h>
#include <errno.h>

int main()
{
        int i, fd[2];
        char c = 0;
        pipe(fd);
        for (i = 0; i < 10000000; i++) {
                errno = 0; // glibc also use %gs
                write(fd[1], &c, 1);
                read(fd[0], &c, 1);
        }
        return 0;
}

The best elap time I got for this program on 10 runs was : 12.811 s
(Intel(R) Pentium(R) M processor 1.60GHz)

With the attached patch, I got 12.212 s, and a kernel text size reduction of 
3400 bytes.

I wish Jeremy give us patches for UP machines so that %gs can be let untouched 
in entry.S (syscall entry/exit). A lot of ia32 machines are still using one 
CPU.

Note : I dont have a x86_64 machine here, but I suspect a similar patch could 
be done for x86_64 too.

Thank you

[PATCH] i386-pda UP optimization

On a !CONFIG_SMP machine, there is only one PDA, (one CPU).
We can avoid %gs prefixes when reading/writing fields in PDA.
This reduce kernel text size and also give better performance.

Signed-off-by: Eric Dumazet <[email protected]>
--- linux-2.6.19-rc5-mm2/include/asm-i386/pda.h	2006-11-15 11:21:24.000000000 +0100
+++ linux-2.6.19-rc5-mm2-ed/include/asm-i386/pda.h	2006-11-15 11:23:49.000000000 +0100
@@ -91,10 +91,19 @@
 	((typeof(_proxy_pda.field) *)((unsigned char *)read_pda(_pda) + \
 				      pda_offset(field)))
 
+#if defined(CONFIG_SMP)
 #define read_pda(field) pda_from_op("mov",field)
 #define write_pda(field,val) pda_to_op("mov",field,val)
 #define add_pda(field,val) pda_to_op("add",field,val)
 #define sub_pda(field,val) pda_to_op("sub",field,val)
 #define or_pda(field,val) pda_to_op("or",field,val)
+#else
+extern struct i386_pda boot_pda;
+#define read_pda(field)      boot_pda.field 
+#define write_pda(field,val) do { boot_pda.field = (val);} while (0)
+#define add_pda(field,val) ) do { boot_pda.field += (val);} while (0)
+#define sub_pda(field,val)   do { boot_pda.field -= (val);} while (0)
+#define or_pda(field,val)    do { boot_pda.field |= (val);} while (0)
+#endif
 
 #endif	/* _I386_PDA_H */
--- linux-2.6.19-rc5-mm2/arch/i386/kernel/cpu/common.c	2006-11-15 11:21:25.000000000 +0100
+++ linux-2.6.19-rc5-mm2-ed/arch/i386/kernel/cpu/common.c	2006-11-15 11:45:09.000000000 +0100
@@ -609,6 +609,14 @@
 	return regs;
 }
 
+/* Initial PDA used by boot CPU */
+struct i386_pda boot_pda = {
+	._pda = &boot_pda,
+	.cpu_number = 0,
+	.pcurrent = &init_task,
+};
+EXPORT_SYMBOL(boot_pda);
+
 static __cpuinit int alloc_gdt(int cpu)
 {
 	struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
@@ -628,11 +636,10 @@
 		BUG_ON(gdt != NULL || pda != NULL);
 
 		gdt = alloc_bootmem_pages(PAGE_SIZE);
-		pda = alloc_bootmem(sizeof(*pda));
+		pda = &boot_pda;
 		/* alloc_bootmem(_pages) panics on failure, so no check */
 
 		memset(gdt, 0, PAGE_SIZE);
-		memset(pda, 0, sizeof(*pda));
 	} else {
 		/* GDT and PDA might already have been allocated if
 		   this is a CPU hotplug re-insertion. */
@@ -655,13 +662,6 @@
 	return 1;
 }
 
-/* Initial PDA used by boot CPU */
-struct i386_pda boot_pda = {
-	._pda = &boot_pda,
-	.cpu_number = 0,
-	.pcurrent = &init_task,
-};
-
 static inline void set_kernel_gs(void)
 {
 	/* Set %gs for this CPU's PDA.  Memory clobber is to create a

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux