(I tried to include all arch maintianers and memory maintainers, if I
missed someone, please let me know).
OK, as promised, I've got a working VM percpu solution.
A little history: please read the thread http://lkml.org/lkml/2006/4/14/137
Preivously I noticed that the per_cpu variables were implemented with
a little hack that Rusty Russell wrote up. I call it a hack because,
for modules an arbitrary number was used to hold all per_cpu variables
that would be used in the kernel or in modules. If this number was too
big, you waste the memory that is allocated for it, and if it were
too small, you wont be able to load all the modules that are required.
My first attempt to fix this introduced another dereference, to allow
for modules to allocate their own memory. This was quickly shot down,
and for good reason, because dereferences kill performance, and don't
play nice with large SMP systems that depend on per_cpu being fast.
But that first attempt had one benefit. It had good responses on how
to actually fix the problem. Without the first try, I would not have
tried this approach.
So what is this solution?
I now place the per_cpu variables into VM, such that the pages are
only allocated when needed. All the architecture needs to do is
supply a VM address range, size for each CPU to use (note this
implementation expects all the VM CPU areas to be together), and
three functions to allow for allocating page tables at bootup.
The bootup page table allocations are needed because the percpu
variables are used before the system initializes the memory. So
bootmem is needed to load the page tables.
But that's it! No more hacks for architectures with lots of CPUS and
NUMA to implement their own percpu algorithms. They just supply the
functions to allocate the variables, and the memory will be loaded
appropriately. So all architectures with VM can use the generic
solution. Does the main-line kernel support any architectures that
doesn't have a VM?
Another benefit is that this approach removes the one redirection that
was already used in the generic solution. Since the virtual memory
of the architecture for the per_cpu is static, the calculation to
find the variable is done with constants. So this is another win
for this solution.
So the three things that this patch gives us are:
1) Robust per_cpu. No more guessing the size of the per_cpu variable
sections. Default VM is 1 Meg per cpu. If you use more than that
I guess you're SOL.
2) Generic solution for all architectures. No more fancy hacks to
get the per cpu offest.
3) Removes the inderection of the current per_cpu generic solution.
The set of patches that I have implement this for the i386 architecture
and lays out the ground work for others. The i386 implementation I did
was mainly a hack. Nick Piggin suggested that before I do too much
work, I should post my stuff and ask for comments. That's what I'm doing
now.
This patch set works for my laptop (P4 HT) and I haven't tested
it with any other configuration. The implementation that I did for
i386 was only to get it to work and is not flexible. It needs much
better implementation, and I ask for help with that.
I basically concentrated to the core stuff. Another nice thing about
this patch set is that it needs both CONFIG_HAS_VM_PERCPU and
__ARCH_HAS_VM_PERCPU to take advantage of the VM percpu implementation.
Without these set, it defaults to the old usage. This way we
can slowly implement each architecture, in an incremental fashion.
OK, let'er rip. Flame me, yell at me, curse me, but please give me
feedback.
Thanks for your time.
-- Steve
PS. The attached module was used to test this patch on my laptop.
#include <linux/module.h>
#include <linux/percpu.h>
#define BIG_SIZE 4200
DEFINE_PER_CPU(int , bigarray[BIG_SIZE]);
static int __init percpu_init(void)
{
int i, x;
for (i=0; cpu_possible(i) ; i++)
for (x=0; x < BIG_SIZE; x++) {
if (!(x%100))
printk("processing %d:%d\n", i, x);
per_cpu(bigarray[x], i) = 10000 + x;
}
return 0;
}
static void __exit percpu_exit(void)
{
int i;
for (i=1; i < BIG_SIZE; i <<= 1)
printk("bigarray[%d] = %d\n", i, per_cpu(bigarray[i],0));
}
module_init(percpu_init);
module_exit(percpu_exit);
MODULE_AUTHOR("My name here");
MODULE_DESCRIPTION("percpu!");
MODULE_LICENSE("GPL");
[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]