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

Re: kmap_kiobuf()



"Stephen C. Tweedie" wrote:
> 
> Hi,
> 
> On Wed, Jun 28, 2000 at 11:52:40AM -0500, lord@sgi.com wrote:
> >
> > I am not a VM guy either, Ben, is the cost of the TLB flush mostly in
> > the synchronization between CPUs, or is it just expensive anyway you
> > look at it?
> 
> The TLB IPI is by far the biggest factor here.
> 
I tried it on my Dual Pentium II/350, 100 MHz FSB:

* an empty IPI returns after ~ 1630 cpu ticks.
* a tlb flush IPI needs ~ 2130 cpu ticks.

The computer was idle, and obviously I only measure the cost as seen
from the primary cpu, I don't know how long the second cpu needs until
it returns from the interrupt.


--
	Manfred
--- 2.4/drivers/net/dummy.c	Sat Jun 24 11:07:56 2000
+++ build-2.4/drivers/net/dummy.c	Wed Jun 28 20:55:44 2000
@@ -132,17 +132,171 @@
 	dummy_init(dev);
 	return 0;
 }
-
 static struct net_device dev_dummy = {
 		"",
 		0, 0, 0, 0,
 	 	0x0, 0,
 	 	0, 0, 0, NULL, dummy_probe };
 
+/* kernel benchmark hook (C) Manfred Spraul manfreds@colorfullife.com */
+
+int p_shift = -1;
+MODULE_PARM     (p_shift, "1i");
+MODULE_PARM_DESC(p_shift, "Shift for the profile buffer");
+
+#define STAT_TABLELEN		16384
+static unsigned long totals[STAT_TABLELEN];
+static unsigned int overflows;
+
+static unsigned long long stime;
+static void start_measure(void)
+{
+	 __asm__ __volatile__ (
+		".align 64\n\t"
+	 	"pushal\n\t"
+		"cpuid\n\t"
+		"popal\n\t"
+		"rdtsc\n\t"
+		"movl %%eax,(%0)\n\t"
+		"movl %%edx,4(%0)\n\t"
+		: /* no output */
+		: "c"(&stime)
+		: "eax", "edx", "memory" );
+}
+
+static void end_measure(void)
+{
+static unsigned long long etime;
+	__asm__ __volatile__ (
+		"pushal\n\t"
+		"cpuid\n\t"
+		"popal\n\t"
+		"rdtsc\n\t"
+		"movl %%eax,(%0)\n\t"
+		"movl %%edx,4(%0)\n\t"
+		: /* no output */
+		: "c"(&etime)
+		: "eax", "edx", "memory" );
+	{
+		unsigned long time = (unsigned long)(etime-stime);
+		time >>= p_shift;
+		if(time < STAT_TABLELEN) {
+			totals[time]++;
+		} else {
+			overflows++;
+		}
+	}
+}
+
+static void clean_buf(void)
+{
+	memset(totals,0,sizeof(totals));
+	overflows = 0;
+}
+
+static void print_line(unsigned long* array)
+{
+	int i;
+	for(i=0;i<32;i++) {
+		if((i%32)==16)
+			printk(":");
+		printk("%lx ",array[i]); 
+	}
+}
+
+static void print_buf(char* caption)
+{
+	int i, other = 0;
+	printk("Results - %s - shift %d",
+		caption, p_shift);
+
+	for(i=0;i<STAT_TABLELEN;i+=32) {
+		int j;
+		int local = 0;
+		for(j=0;j<32;j++)
+			local += totals[i+j];
+
+		if(local) {
+			printk("\n%3x: ",i);
+			print_line(&totals[i]);
+			other += local;
+		}
+	}
+	printk("\nOverflows: %d.\n",
+		overflows);
+	printk("Sum: %ld\n",other+overflows);
+}
+
+static void return_immediately(void* dummy)
+{
+	return;
+}
+
+/* gross hack */
+static unsigned long mmu_cr4_features;
+
+static void do_flush_tlb(void* dummy)
+{
+	__flush_tlb_all();
+}
+
 int init_module(void)
 {
 	/* Find a name for this unit */
-	int err=dev_alloc_name(&dev_dummy,"dummy%d");
+	int err;
+
+	if(p_shift != -1) {
+		int i;
+		/* empty test measurement: */
+		printk("******** kernel cpu benchmark activated **********\n");
+		clean_buf();
+		schedule_timeout(100);
+		for(i=0;i<100;i++) {
+			start_measure();
+			return_immediately(NULL);
+			return_immediately(NULL);
+			return_immediately(NULL);
+			return_immediately(NULL);
+			end_measure();
+		}
+		print_buf("zero");
+		clean_buf();
+		schedule_timeout(100);
+		for(i=0;i<100;i++) {
+			start_measure();
+			return_immediately(NULL);
+			return_immediately(NULL);
+			smp_call_function(return_immediately,NULL,1,1);
+			return_immediately(NULL);
+			return_immediately(NULL);
+			end_measure();
+		}
+		print_buf("empty smp call");
+		clean_buf();
+		{
+			int tmp;
+			__asm__ __volatile__(
+					"movl %%cr4,%0\n\t"
+					"movl %0,%1\n\t"
+					: "=&r"(tmp)
+					: "m" (mmu_cr4_features));
+		}
+		schedule_timeout(100);
+		for(i=0;i<100;i++) {
+			start_measure();
+			return_immediately(NULL);
+			return_immediately(NULL);
+			smp_call_function(do_flush_tlb,NULL,1,1);
+			return_immediately(NULL);
+			return_immediately(NULL);
+			end_measure();
+		}
+		print_buf("tlb flush");
+		clean_buf();
+	return -EINVAL;
+	}
+
+	err=dev_alloc_name(&dev_dummy,"dummy%d");
 	if(err<0)
 		return err;
 	if (register_netdev(&dev_dummy) != 0)