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 /litmus/uncachedev.c | |
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);
Diffstat (limited to 'litmus/uncachedev.c')
-rw-r--r-- | litmus/uncachedev.c | 102 |
1 files changed, 102 insertions, 0 deletions
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); | ||