diff options
| author | Glenn Elliott <gelliott@cs.unc.edu> | 2013-03-08 00:43:41 -0500 |
|---|---|---|
| committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2013-08-07 03:47:07 -0400 |
| commit | bcaacec1ca714224807728a63eccb37e3d685cd6 (patch) | |
| tree | 4c4fb3e05af0d9ad03428414cd8c2bb97105435a | |
| parent | 3bd7e43d778163e9e1b696fdb5030b7717aba236 (diff) | |
uncachedev: mmap memory that is not cached by CPUs2013.1archived-2013.1
This patch creates a new character device, uncachedev.
Pages of RAM allocated by this device are not cached by
CPUs.
Uses for such pages:
1) Determining *very* pessimistic emperical worst-
case execution times.
2) Compare against performance with caches (quantify
the avg. case benefit).
3) Deterministic memory accesses (access cannot cause a
cache eviction.)
4) Theoretically, increased performance can be achieved
by storing infrequently accessed data in uncache pages.
uncachedev allocates pages with the pgprot_noncached() page
attribute for user applications. Since pages allocated by
uncachedev are not locked in memory by default, applications
with any access level may mmap pages with uncachedev.
Limitations:
1) Uncache pages must be MAP_PRIVATE.
2) Remapping not supported.
Usage (user level):
int size = NR_PAGES*PAGE_SIZE;
int fd = open("/dev/litmus/uncache", O_RDWR);
char *data = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE, fd, 0);
<...do stuff...>
munmap(data, size);
| -rw-r--r-- | litmus/Makefile | 1 | ||||
| -rw-r--r-- | litmus/uncachedev.c | 102 |
2 files changed, 103 insertions, 0 deletions
diff --git a/litmus/Makefile b/litmus/Makefile index d26ca7076b62..2bddc94a399f 100644 --- a/litmus/Makefile +++ b/litmus/Makefile | |||
| @@ -18,6 +18,7 @@ obj-y = sched_plugin.o litmus.o \ | |||
| 18 | bheap.o \ | 18 | bheap.o \ |
| 19 | binheap.o \ | 19 | binheap.o \ |
| 20 | ctrldev.o \ | 20 | ctrldev.o \ |
| 21 | uncachedev.o \ | ||
| 21 | sched_gsn_edf.o \ | 22 | sched_gsn_edf.o \ |
| 22 | sched_psn_edf.o \ | 23 | sched_psn_edf.o \ |
| 23 | sched_pfp.o | 24 | sched_pfp.o |
diff --git a/litmus/uncachedev.c b/litmus/uncachedev.c new file mode 100644 index 000000000000..06a6a7c17983 --- /dev/null +++ b/litmus/uncachedev.c | |||
| @@ -0,0 +1,102 @@ | |||
| 1 | #include <linux/sched.h> | ||
| 2 | #include <linux/kernel.h> | ||
| 3 | #include <linux/mm.h> | ||
| 4 | #include <linux/fs.h> | ||
| 5 | #include <linux/errno.h> | ||
| 6 | #include <linux/highmem.h> | ||
| 7 | #include <asm/page.h> | ||
| 8 | #include <linux/miscdevice.h> | ||
| 9 | #include <linux/module.h> | ||
| 10 | |||
| 11 | #include <litmus/litmus.h> | ||
| 12 | |||
| 13 | /* device for allocating pages not cached by the CPU */ | ||
| 14 | |||
| 15 | #define UNCACHE_NAME "litmus/uncache" | ||
| 16 | |||
| 17 | void litmus_uncache_vm_open(struct vm_area_struct *vma) | ||
| 18 | { | ||
| 19 | } | ||
| 20 | |||
| 21 | void litmus_uncache_vm_close(struct vm_area_struct *vma) | ||
| 22 | { | ||
| 23 | } | ||
| 24 | |||
| 25 | int litmus_uncache_vm_fault(struct vm_area_struct* vma, | ||
| 26 | struct vm_fault* vmf) | ||
| 27 | { | ||
| 28 | /* modeled after SG DMA video4linux, but without DMA. */ | ||
| 29 | /* (see drivers/media/video/videobuf-dma-sg.c) */ | ||
| 30 | struct page *page; | ||
| 31 | |||
| 32 | page = alloc_page(GFP_USER); | ||
| 33 | if (!page) | ||
| 34 | return VM_FAULT_OOM; | ||
| 35 | |||
| 36 | clear_user_highpage(page, (unsigned long)vmf->virtual_address); | ||
| 37 | vmf->page = page; | ||
| 38 | |||
| 39 | return 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | static struct vm_operations_struct litmus_uncache_vm_ops = { | ||
| 43 | .open = litmus_uncache_vm_open, | ||
| 44 | .close = litmus_uncache_vm_close, | ||
| 45 | .fault = litmus_uncache_vm_fault, | ||
| 46 | }; | ||
| 47 | |||
| 48 | static int litmus_uncache_mmap(struct file* filp, struct vm_area_struct* vma) | ||
| 49 | { | ||
| 50 | /* first make sure mapper knows what he's doing */ | ||
| 51 | |||
| 52 | /* you can only map the "first" page */ | ||
| 53 | if (vma->vm_pgoff != 0) | ||
| 54 | return -EINVAL; | ||
| 55 | |||
| 56 | /* you can't share it with anyone */ | ||
| 57 | if (vma->vm_flags & (VM_MAYSHARE | VM_SHARED)) | ||
| 58 | return -EINVAL; | ||
| 59 | |||
| 60 | /* cannot be expanded, and is not a "normal" page. */ | ||
| 61 | vma->vm_flags |= VM_DONTEXPAND; | ||
| 62 | |||
| 63 | /* noncached pages are not explicitly locked in memory (for now). */ | ||
| 64 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
| 65 | |||
| 66 | vma->vm_ops = &litmus_uncache_vm_ops; | ||
| 67 | |||
| 68 | return 0; | ||
| 69 | } | ||
| 70 | |||
| 71 | static struct file_operations litmus_uncache_fops = { | ||
| 72 | .owner = THIS_MODULE, | ||
| 73 | .mmap = litmus_uncache_mmap, | ||
| 74 | }; | ||
| 75 | |||
| 76 | static struct miscdevice litmus_uncache_dev = { | ||
| 77 | .name = UNCACHE_NAME, | ||
| 78 | .minor = MISC_DYNAMIC_MINOR, | ||
| 79 | .fops = &litmus_uncache_fops, | ||
| 80 | /* pages are not locked, so there is no reason why | ||
| 81 | anyone cannot allocate an uncache pages */ | ||
| 82 | .mode = (S_IRUGO | S_IWUGO), | ||
| 83 | }; | ||
| 84 | |||
| 85 | static int __init init_litmus_uncache_dev(void) | ||
| 86 | { | ||
| 87 | int err; | ||
| 88 | |||
| 89 | printk("Initializing LITMUS^RT uncache device.\n"); | ||
| 90 | err = misc_register(&litmus_uncache_dev); | ||
| 91 | if (err) | ||
| 92 | printk("Could not allocate %s device (%d).\n", UNCACHE_NAME, err); | ||
| 93 | return err; | ||
| 94 | } | ||
| 95 | |||
| 96 | static void __exit exit_litmus_uncache_dev(void) | ||
| 97 | { | ||
| 98 | misc_deregister(&litmus_uncache_dev); | ||
| 99 | } | ||
| 100 | |||
| 101 | module_init(init_litmus_uncache_dev); | ||
| 102 | module_exit(exit_litmus_uncache_dev); | ||
