Re: Using %cr2 to reference "current"

Benjamin LaHaise
2001-11-06T18:43:09Z

On Tue, Nov 06, 2001 at 09:49:15AM -0800, Linus Torvalds wrote:
> That said, how expensive is loading %cr2 anyway? We can do all the same
> tricks with a 16kB stack and just playing games with using the higher bits
> as the "offset", ie things like

Here are some numbers:

read cr2 best: 11 av: 11.12
write cr2 cr2 best: 61 av: 64.42
read cr2 best: 11 av: 11.12
write cr2 cr2 best: 61 av: 65.01
read stk best: 10 av: 11.03
write cr2 stk best: 61 av: 64.95
read stk best: 10 av: 11.03
write cr2 stk best: 61 av: 65.23

Which come from insmod of the below two modules. I didn't test writing to
the stack register, but I expect it's similarly expensive as it affects the
call return stack and other behind the scenes dependancies. Suffice it to
say that reading %cr2 is essentially free on my box (athlon mp). Maybe
we should use it as a pointer into a per-cpu area to avoid writing it?

-ben

----teststk_k.c----
#define USE_STK 1
#include "testcr2_k.c"
----testcr2_k.c----
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/errno.h>
#include <linux/init.h>

static inline long long rdtsc(void)
{
unsigned int low,high;
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high));
return low + (((long long)high)<<32);
}

long dummy;

long doit(void)
{
long long start, end;
long val;

start = rdtsc();
#ifdef USE_STK
#define WHICH "stk"
__asm__ __volatile__(
"movl $0x0003c000,%%eax \n" // 4 bits at bit 14
"movl $-16384,%%edx \n" // remove low 14 bits
"andl %%esp,%%eax \n"
"andl %%esp,%%edx \n"
"shrl $7,%%eax \n" // color it by 128 bytes
"addl %%edx,%%eax \n"
: "=a" (val) :: "edx");
#else
#define WHICH "cr2"
__asm__ __volatile__("movl %%cr2,%0" : "=r" (val));
#endif
val += 100;
dummy = val;
end = rdtsc();

return end - start;
}

long doit2(void)
{
long long start, end;
long val;

start = rdtsc();
val = dummy;
__asm__ __volatile__("movl %0,%%cr2" : "=r" (val));
end = rdtsc();

return end - start;
}

int test_init (void)
{
long min = 1000000000, av = 0;
int i;
for (i=0; i<100; i++) {
long dur = doit();
if (dur < min)
min = dur;
av += dur;
}
printk("read " WHICH " best: %ld av: %ld.%02ld\n", min, av / 100, av % 100);

min = 10000000;
av = 0;
for (i=0; i<100; i++) {
long dur = doit2();
if (dur < min)
min = dur;
av += dur;
}
printk("write cr2 " WHICH " best: %ld av: %ld.%02ld\n", min, av / 100, av % 100);
return -ENODEV;
}

void test_exit(void)
{
return;
}

module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
---snip---