Skip to content

Commit fa93382

Browse files
author
Anastasios Papagiannis
committed
FastMap v1.0
0 parents  commit fa93382

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+12960
-0
lines changed

LICENCE

Lines changed: 467 additions & 0 deletions
Large diffs are not rendered by default.

Makefile

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
SUBDIRS = driver ioctl tests logbench
2+
3+
all: $(SUBDIRS)
4+
sync && sync && sync
5+
6+
$(SUBDIRS):
7+
$(MAKE) -C $(@)
8+
9+
clean:
10+
for dir in $(SUBDIRS); do \
11+
$(MAKE) -C $$dir $(@); \
12+
done
13+
14+
.PHONY: $(SUBDIRS) clean

README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# FastMap
2+
3+
This library provides an optimized memory-mapped I/O path inside the Linux kernel. It is implemented as a kernel module and supported by user-space libraries for management purposes.
4+
5+
## Prerequisites
6+
7+
FastMap runs on a modified version of Linux 4.14. In order to build and run
8+
this version of FastMap you can clone this kernel with:
9+
```bash
10+
git clone https://github.com/tpapagian/linux-4.14.72-spf.git -b fastmap
11+
```
12+
13+
The modifications are minimal as they contain only some exported symbols and
14+
the addition of 2 fields in a single struct. The specific modification can
15+
be found at this [commit](https://github.com/tpapagian/linux-4.14.72-spf/commit/fdca6433c36bad7977ca019470225c54a4ef8fb7).
16+
17+
After that you should configure, build and install this kernel using
18+
specific instruction based on your setup.
19+
20+
## Building FastMap
21+
22+
In order to build FastMap simply run ```make``` on the top level directory. This will build the driver (located in driver directory) and
23+
the associated user space tools (located in ioctl directory). After that it will also install FastMap module and run ```depmod```.
24+
25+
## Running FastMap
26+
27+
The only required parameter is the number of 4KB DRAM pages that it will use as cache. You can define this in the ```driver/main.c``` file in the
28+
```perma_mmap_buf_size``` variable. Alternatively you can use this as a command line argument (i.e. ```modprobe dmap perma_mmap_buf_size=1024``` and in this case it will allocate 1024 4KB pages tottalling in 4GB of DRAM cache).
29+
30+
In ```scripts``` directory you can find several scripts (with the appropriate comments) on how to laod and unload FastMap. These include:
31+
| Script | Description |
32+
|-----------------------------|----------------------------------------|
33+
| scripts/load-it-blkdev.sh | Load FastMap for a block device. |
34+
| scripts/unload-it-blkdev.sh | Unload FastMap for a block device. |
35+
| scripts/load-it-fs.sh | Load FastMap for a file system. |
36+
| scripts/unload-it-fs.sh | Unload FastMap for a file system. |
37+
38+
## Design and Evaluation
39+
40+
The following paper presents the design and experimental analysis of FastMap.
41+
```
42+
Anastasios Papagiannis, Giorgos Xanthakis, Giorgos Saloustros, Manolis Marazakis, and Angelos Bilas. Optimizing Memory-mapped I/O for Fast Storage Devices. In proceedings of the 2020 USENIX Annual Technical Conference (USENIX ATC 20). July 2020.
43+
```
44+
The pdf, slides, and presentation can be found [here](https://www.usenix.org/conference/atc20/presentation/papagiannis).
45+
46+
Please cite this publication if you use/modify/evaluate FastMap.
47+
48+
## Funding
49+
50+
This work is supported by [EVOLVE](https://www.evolve-h2020.eu/) (Grant Agreement ID: 825061) and [ExaNeSt](http://www.exanest.eu/) (Grant Agreement ID: 671553) EU funded projects.

driver/Kbuild

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
obj-m := dmap.o
2+
dmap-objs := main.o \
3+
mmap_fault_handler.o \
4+
mmap_buffer_rbtree.o \
5+
mmap_banked_buffer.o \
6+
mmap_buffer_hash_table.o \
7+
mmap_generational_fifo_buffer.o \
8+
mmap_buffer_sync_daemon.o \
9+
di-mmap_parameters.o \
10+
buffer_runtime_parameters.o \
11+
buffer_loadtime_parameters.o \
12+
helpers.o \
13+
write_tagged_page.o \
14+
write_dirty_pages.o \
15+
tagged_page.o \
16+
dmapfs_dentry.o \
17+
dmapfs_file.o \
18+
dmapfs_inode.o \
19+
dmapfs_lookup.o \
20+
dmapfs_main.o \
21+
dmapfs_mmap.o \
22+
dmapfs_super.o \
23+
lpfifo_non_atomic.o \
24+
dfifo_non_atomic.o

driver/Makefile

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
EXTRA_CFLAGS := -pipe -m64 -ansi -fPIC -O2 -fno-exceptions -fstack-protector -Wl,-z,relro -Wl,-z,now -fvisibility=internal -W -Wall -Wno-unused-parameter -Wno-unused-function -Wno-unused-label -Wpointer-arith -Wformat -Wreturn-type -Wsign-compare -Wmultichar -Wformat-nonliteral -Winit-self -Wuninitialized -Wno-deprecated -Wformat-security -Werror -Wall -Winline -Wextra -Wshadow -funsigned-char -fwrapv -Wmissing-format-attribute -Wwrite-strings -Wenum-compare -Wlogical-op -Wsuggest-attribute=noreturn -Wunreachable-code -fno-omit-frame-pointer
2+
3+
NAME=dmap
4+
KDIR ?= /lib/modules/`uname -r`/build
5+
KVERSION = $(shell uname -r)
6+
7+
default: target install
8+
9+
target:
10+
$(MAKE) -C $(KDIR) M=$$PWD
11+
12+
clean:
13+
$(MAKE) -C $(KDIR) M=$$PWD clean
14+
15+
help:
16+
$(MAKE) -C $(KDIR) M=$$PWD help
17+
18+
install:
19+
/lib/modules/`uname -r`/source/scripts/sign-file sha512 /lib/modules/`uname -r`/source/certs/signing_key.pem /lib/modules/`uname -r`/source/certs/signing_key.x509 dmap.ko
20+
if [ -f $(NAME).ko ]; then \
21+
if ! cp $(NAME).ko /lib/modules/$(KVERSION)/kernel/drivers/char; \
22+
then exit 1; fi; \
23+
fi;
24+
/sbin/depmod -a
25+
26+
uninstall:
27+
if [ -f /lib/modules/$(KVERSION)/kernel/drivers/char/$(NAME).ko ]; then \
28+
if ! rm -f /lib/modules/$(KVERSION)/kernel/drivers/char/$(NAME).ko; \
29+
then exit 1; fi; \
30+
fi;
31+
/sbin/depmod -a

driver/btree_metadata.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#ifndef _BTREE_META_
2+
#define _BTREE_META_
3+
4+
typedef enum
5+
{
6+
leafNode = 590675399,
7+
internalNode = 790393380,
8+
rootNode = 742729384,
9+
leafRootNode = 748939994 /*special case for a newly created tree*/
10+
} nodeType_t;
11+
12+
typedef struct block_header
13+
{
14+
void *next_block;
15+
} block_header;
16+
17+
/*leaf or internal node metadata, place always in the first 4KB data block*/
18+
typedef struct node_header
19+
{
20+
uint64_t epoch; /*epoch of the node. It will be used for knowing when to perform copy on write*/
21+
uint64_t fragmentation;
22+
/*data log info, KV log for leaves private for index*/
23+
block_header *first_key_block;
24+
block_header *last_key_block;
25+
uint64_t key_log_size;
26+
int32_t height; /*0 are leaves, 1 are Bottom Internal nodes, and then we have INs and root*/
27+
nodeType_t type; /*internal or leaf node*/
28+
uint16_t numberOfEntriesInNode;
29+
char pad[8];
30+
} node_header;
31+
32+
#endif // _BTREE_META_
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
#include <linux/mm.h>
2+
3+
#include "dmap.h"
4+
#include "buffer_loadtime_parameters.h"
5+
6+
int init_ld_params(buf_ld_params_t *ld_params)
7+
{
8+
ld_params->mmap_buf_size = 0;
9+
ld_params->superpage_alloc_order = 0;
10+
ld_params->hot_page_fifo_alloc_ratio.mul = 1;
11+
ld_params->hot_page_fifo_alloc_ratio.logb2_shift = HPF_ALLOC_RATIO_SHIFT;
12+
ld_params->victim_queue_alloc_ratio.mul = 1;
13+
ld_params->victim_queue_alloc_ratio.logb2_shift = VQ_ALLOC_RATIO_SHIFT;
14+
return 0;
15+
}
16+
17+
int copy_ld_params(buf_ld_params_t *dst, buf_ld_params_t *src)
18+
{
19+
dst->mmap_buf_size = src->mmap_buf_size;
20+
dst->superpage_alloc_order = src->superpage_alloc_order;
21+
dst->hot_page_fifo_alloc_ratio.mul = src->hot_page_fifo_alloc_ratio.mul;
22+
dst->hot_page_fifo_alloc_ratio.logb2_shift = src->hot_page_fifo_alloc_ratio.logb2_shift;
23+
dst->victim_queue_alloc_ratio.mul = src->victim_queue_alloc_ratio.mul;
24+
dst->victim_queue_alloc_ratio.logb2_shift = src->victim_queue_alloc_ratio.logb2_shift;
25+
return 0;
26+
}
27+
28+
int display_ld_params(buf_ld_params_t *ld_params, char *str)
29+
{
30+
return sprintf(str, "ld_params: mmap_buf_size=%ld superpage_alloc_order=%d",
31+
ld_params->mmap_buf_size, ld_params->superpage_alloc_order);
32+
}
33+
34+
int print_ld_params(buf_ld_params_t *ld_params)
35+
{
36+
return 0;
37+
}
38+
39+
/*************************************************************************
40+
* Sysfs function interface
41+
************************************************************************/
42+
/* Extract the load-time parameters from the top level dimmap_buffer_t data structure */
43+
static ssize_t buf_ld_params_show(struct class *class, struct class_attribute *attr, char *buf, ssize_t (*format)(buf_ld_params_t *ld_params, char *))
44+
{
45+
buf_ld_params_t *ld_params = to_dimmap_buf_ld_params(class);
46+
ssize_t ret = -EINVAL;
47+
ret = (*format)(ld_params, buf);
48+
return ret;
49+
}
50+
51+
/* Generate a show function for a load-time parameter field */
52+
#define SHOW_LD_PARAM(field, format_string) \
53+
static ssize_t ld_param_format_##field(buf_ld_params_t *ld_params, char *buf) \
54+
{ \
55+
return scnprintf(buf, PAGE_SIZE, format_string, ld_params->field); \
56+
} \
57+
ssize_t show_ld_param_##field(struct class *class, struct class_attribute *attr, char *buf) \
58+
{ \
59+
return buf_ld_params_show(class, attr, buf, ld_param_format_##field); \
60+
}
61+
62+
/* Generate a show function for a runtime parameter field */
63+
#define SHOW_LD_PARAM_TUPLE(field, f1, f2, format_string) \
64+
static ssize_t ld_param_format_##field(buf_ld_params_t *ld_params, char *buf) \
65+
{ \
66+
int f2_ = 1 << ld_params->field.f2; \
67+
return scnprintf(buf, PAGE_SIZE, format_string, ld_params->field.f1, f2_); \
68+
} \
69+
ssize_t show_ld_param_##field(struct class *class, struct class_attribute *attr, char *buf) \
70+
{ \
71+
return buf_ld_params_show(class, attr, buf, ld_param_format_##field); \
72+
}
73+
74+
/* Generate a store function for an integer runtime parameter field */
75+
#define STORE_INTEGER_LD_PARAM(field) \
76+
ssize_t store_ld_param_##field(struct class *class, struct class_attribute *attr, const char *buf, size_t count) \
77+
{ \
78+
buf_ld_params_t *ld_params = to_dimmap_buf_ld_params(class); \
79+
int ret = -EINVAL; \
80+
int val = 0; \
81+
ret = kstrtoint(buf, 0, &val); \
82+
if (ret) \
83+
{ \
84+
goto err; \
85+
} \
86+
ld_params->field = val; \
87+
update_dimmap_buf_ld_params(class); \
88+
ret = count; \
89+
err: \
90+
return ret; \
91+
}
92+
93+
SHOW_LD_PARAM(mmap_buf_size, "%ld\n")
94+
95+
ssize_t store_ld_param_mmap_buf_size(struct class *class, struct class_attribute *attr, const char *buf, size_t count)
96+
{
97+
dimmap_buffer_t *dimmap_buf = to_dimmap_buf(class);
98+
buf_ld_params_t *ld_params = to_dimmap_buf_ld_params(class);
99+
int ret = -EINVAL;
100+
long new_size;
101+
102+
ret = kstrtoul(buf, 0, &new_size);
103+
if (ret)
104+
{
105+
goto err;
106+
}
107+
108+
ld_params->mmap_buf_size = new_size >> ld_params->superpage_alloc_order;
109+
ret = count;
110+
update_dimmap_buf_ld_params(class);
111+
112+
init_mmap_params(&dimmap_buf->ld_params);
113+
114+
err:
115+
return ret;
116+
}
117+
118+
SHOW_LD_PARAM(superpage_alloc_order, "%d\n")
119+
STORE_INTEGER_LD_PARAM(superpage_alloc_order)
120+
121+
SHOW_LD_PARAM_TUPLE(hot_page_fifo_alloc_ratio, mul, logb2_shift, "%d/%d\n");
122+
SHOW_LD_PARAM_TUPLE(victim_queue_alloc_ratio, mul, logb2_shift, "%d/%d\n");
123+
124+
ssize_t store_ld_param_hot_page_fifo_alloc_ratio(struct class *class, struct class_attribute *attr, const char *buf, size_t count)
125+
{
126+
dimmap_buffer_t *dimmap_buf = to_dimmap_buf(class);
127+
buf_ld_params_t *ld_params = to_dimmap_buf_ld_params(class);
128+
int ret = -EINVAL;
129+
int mul = 0, logb2_shift = 0, denominator = 0;
130+
int i;
131+
132+
ret = sscanf(buf, "%d/%d", &mul, &denominator);
133+
if (ret != 2)
134+
{
135+
goto err;
136+
}
137+
for (i = 0; (1 << i) < denominator; i++)
138+
{
139+
logb2_shift = i + 1;
140+
}
141+
142+
ret = count;
143+
if (1 << logb2_shift != denominator)
144+
{
145+
printk(KERN_ALERT "The specified denominator (%d) cannot be encoded as the logb2 (%d) of the provided value.\n", denominator, logb2_shift);
146+
goto err;
147+
}
148+
149+
ld_params->hot_page_fifo_alloc_ratio.mul = mul;
150+
ld_params->hot_page_fifo_alloc_ratio.logb2_shift = logb2_shift;
151+
update_dimmap_buf_ld_params(class);
152+
153+
init_mmap_params(&dimmap_buf->ld_params);
154+
155+
err:
156+
return ret;
157+
}
158+
159+
ssize_t store_ld_param_victim_queue_alloc_ratio(struct class *class, struct class_attribute *attr, const char *buf, size_t count)
160+
{
161+
dimmap_buffer_t *dimmap_buf = to_dimmap_buf(class);
162+
buf_ld_params_t *ld_params = to_dimmap_buf_ld_params(class);
163+
int ret = -EINVAL;
164+
int mul = 0, logb2_shift = 0, denominator = 0;
165+
int i;
166+
167+
ret = sscanf(buf, "%d/%d", &mul, &denominator);
168+
if (ret != 2)
169+
{
170+
goto err;
171+
}
172+
for (i = 0; (1 << i) < denominator; i++)
173+
{
174+
logb2_shift = i + 1;
175+
}
176+
177+
ret = count;
178+
if (1 << logb2_shift != denominator)
179+
{
180+
printk(KERN_ALERT "The specified denominator (%d) cannot be encoded as the logb2 (%d) of the provided value.\n", denominator, logb2_shift);
181+
goto err;
182+
}
183+
184+
ld_params->victim_queue_alloc_ratio.mul = mul;
185+
ld_params->victim_queue_alloc_ratio.logb2_shift = logb2_shift;
186+
update_dimmap_buf_ld_params(class);
187+
188+
init_mmap_params(&dimmap_buf->ld_params);
189+
190+
err:
191+
return ret;
192+
}
193+
194+
/* Buffer loadtime parameters */
195+
static struct class_attribute ld_param_class_attrs[] = {
196+
__ATTR(1_buffer_size, S_IRUGO | S_IWUSR, show_ld_param_mmap_buf_size, store_ld_param_mmap_buf_size),
197+
__ATTR(1_superpage_alloc_order, S_IRUGO | S_IWUSR, show_ld_param_superpage_alloc_order, store_ld_param_superpage_alloc_order),
198+
__ATTR(1_hot_page_fifo_alloc_ratio, S_IRUGO | S_IWUSR, show_ld_param_hot_page_fifo_alloc_ratio, store_ld_param_hot_page_fifo_alloc_ratio),
199+
__ATTR(1_victim_queue_alloc_ratio, S_IRUGO | S_IWUSR, show_ld_param_victim_queue_alloc_ratio, store_ld_param_victim_queue_alloc_ratio),
200+
__ATTR_NULL,
201+
};
202+
203+
int copy_ld_param_class_attrs(struct class_attribute *global_class_attrs, int offset)
204+
{
205+
int i = 0;
206+
while (ld_param_class_attrs[i].attr.name != NULL)
207+
{
208+
global_class_attrs[offset + i] = ld_param_class_attrs[i];
209+
i++;
210+
}
211+
return offset + i;
212+
}

0 commit comments

Comments
 (0)