tags:

views:

31

answers:

3

Is it possible (on any reasonable OS, preferably Linux) to swap the contents of two memory pages by only modifying the page table and not actually moving any data?

The motivation is a dense matrix transpose. If the data were blocked by page size it would be possible to transpose the data within a page (fits in cache) then swap pages to move the blocks into their final place. A large matrix would have many many pages moved, so hopefully flushing the TLB wouldn't cause trouble.

A: 

I think memory mapped files may do the trick, but I reckon I never tried this myself. Use mmap with MAP_ANONYMOUS to map over pure virtual address (no physical file backing). Then you can remap your 'file' into various areas of the VA obtaining in effect zero-copy semantics. In Windows you'd use MapViewOfFile with a file mapping handle created using CreateMapOfFile(INVALID_HANDLE_VALUE, ...), but note than on NT you cannot control the target of your remapping (ie. the newly mapped VA address is the output of the function call), and on Linux the desired address is taken as a hint.

If this doesn't work, then you'd probably need to create a memory manager module in kernel, which is not feasible for any practical project.

Remus Rusanu
This worked exactly.on Linux mremap can move pages allocated by mmap.
Adam
A: 

In theory, certainly. In practice, I think you can use mmap() to move system V-style shared memory blocks this way.

Anonymous
A: 
#include <stdio.h>
#include <string.h>

#define __USE_GNU
#include <unistd.h>
#include <sys/mman.h>

int main() {
    int PAGE_SIZE = getpagesize();
    char* m = NULL;
    void* temp;

    printf("page size = %d\n", PAGE_SIZE);

    m = (char*)mmap(0, PAGE_SIZE*3, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    temp = m+PAGE_SIZE*2;

    memset(m, '0', PAGE_SIZE);
    memset(m+PAGE_SIZE, '1', PAGE_SIZE);

    printf("before %c %c\n", m[0], m[PAGE_SIZE]);

    mremap(m + PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, MREMAP_FIXED | MREMAP_MAYMOVE, temp); 
    mremap(m, PAGE_SIZE, PAGE_SIZE, MREMAP_FIXED | MREMAP_MAYMOVE, m+PAGE_SIZE); 
    mremap(temp, PAGE_SIZE, PAGE_SIZE, MREMAP_FIXED | MREMAP_MAYMOVE, m); 


    printf("after %c %c\n", m[0], m[PAGE_SIZE]);
    return 0;
}
Adam