Skip to content

Commit 8c645fa

Browse files
committed
Make mmap() scalable
It's now possible to create thousands of thousands of sparse independent memory mappings, without any slowdown. The memory manager is better with tracking memory protection now, particularly on Windows in a precise way that can be restored during fork(). You now have the highest quality mem manager possible. It's even better than some OSes like XNU, where mmap() is implemented as an O(n) operation which means sadly things aren't much improved over there. With this change the llamafile HTTP server endpoint at /tokenize with a prompt of 50 tokens is now able to handle 2.6m r/sec
1 parent 3756870 commit 8c645fa

Some content is hidden

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

59 files changed

+1222
-1051
lines changed

libc/calls/setrlimit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ int setrlimit(int resource, const struct rlimit *rlim) {
8585
rc = efault();
8686
} else if (IsXnuSilicon()) {
8787
rc = _sysret(__syslib->__setrlimit(resource, rlim));
88-
} else if (!IsWindows()) {
88+
} else if (!IsWindows() && !(IsNetbsd() && resource == RLIMIT_AS)) {
8989
rc = sys_setrlimit(resource, rlim);
9090
} else if (resource == RLIMIT_STACK) {
9191
rc = enotsup();

libc/intrin/BUILD.mk

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ o/$(MODE)/libc/intrin/kprintf.o: private \
6262
-Wframe-larger-than=128 \
6363
-Walloca-larger-than=128
6464

65+
o/$(MODE)/libc/intrin/tree.o: private \
66+
CFLAGS += \
67+
-ffunction-sections
68+
6569
o//libc/intrin/memmove.o: private \
6670
CFLAGS += \
6771
-fno-toplevel-reorder

libc/intrin/describemapping.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
static char DescribeMapType(int flags) {
2525
switch (flags & MAP_TYPE) {
2626
case MAP_FILE:
27-
return 'f';
27+
return '-';
2828
case MAP_PRIVATE:
2929
return 'p';
3030
case MAP_SHARED:
@@ -47,7 +47,7 @@ const char *(DescribeMapping)(char p[8], int prot, int flags) {
4747
DescribeProt(p, prot);
4848
p[3] = DescribeMapType(flags);
4949
p[4] = (flags & MAP_ANONYMOUS) ? 'a' : '-';
50-
p[5] = (flags & MAP_FIXED) ? 'F' : '-';
50+
p[5] = (flags & MAP_FIXED) ? 'f' : '-';
5151
p[6] = 0;
5252
return p;
5353
}

libc/intrin/describeprotflags.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@
2020
#include "libc/macros.internal.h"
2121
#include "libc/sysv/consts/prot.h"
2222

23-
static const struct DescribeFlags kProtFlags[] = {
24-
{PROT_READ, "READ"}, //
25-
{PROT_WRITE, "WRITE"}, //
26-
{PROT_EXEC, "EXEC"}, //
27-
};
28-
2923
const char *(DescribeProtFlags)(char buf[48], int x) {
24+
const struct DescribeFlags kProtFlags[] = {
25+
{PROT_READ, "READ"}, //
26+
{PROT_WRITE, "WRITE"}, //
27+
{PROT_EXEC, "EXEC"}, //
28+
{PROT_GUARD, "GUARD"}, //
29+
};
3030
return DescribeFlags(buf, 48, kProtFlags, ARRAYLEN(kProtFlags), "PROT_", x);
3131
}

libc/intrin/describerlimit.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818
╚─────────────────────────────────────────────────────────────────────────────*/
1919
#include "libc/calls/struct/rlimit.h"
2020
#include "libc/dce.h"
21+
#include "libc/fmt/itoa.h"
2122
#include "libc/intrin/kprintf.h"
2223
#include "libc/intrin/strace.internal.h"
24+
#include "libc/str/str.h"
25+
#include "libc/sysv/consts/rlim.h"
2326

2427
const char *DescribeRlimit(char buf[64], int rc, const struct rlimit *rlim) {
2528
if (rc == -1)
@@ -29,7 +32,18 @@ const char *DescribeRlimit(char buf[64], int rc, const struct rlimit *rlim) {
2932
if (kisdangerous(rlim)) {
3033
ksnprintf(buf, 64, "%p", rlim);
3134
} else {
32-
ksnprintf(buf, 64, "{%'ld, %'ld}", rlim->rlim_cur, rlim->rlim_max);
35+
char str[2][21];
36+
if (rlim->rlim_cur == RLIM_INFINITY) {
37+
strcpy(str[0], "RLIM_INFINITY");
38+
} else {
39+
FormatInt64(str[0], rlim->rlim_cur);
40+
}
41+
if (rlim->rlim_max == RLIM_INFINITY) {
42+
strcpy(str[1], "RLIM_INFINITY");
43+
} else {
44+
FormatInt64(str[1], rlim->rlim_max);
45+
}
46+
ksnprintf(buf, 64, "{%s, %s}", str[0], str[1]);
3347
}
3448
return buf;
3549
}

libc/intrin/directmap-nt.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,8 @@ textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
8686
if ((dm.addr = MapViewOfFileEx(dm.maphandle, fl.flags2, off >> 32, off,
8787
size, addr))) {
8888
uint32_t oldprot;
89-
if (VirtualProtect(dm.addr, size, __prot2nt(prot, iscow), &oldprot)) {
89+
if (VirtualProtect(dm.addr, size, __prot2nt(prot, iscow), &oldprot))
9090
return dm;
91-
}
9291
UnmapViewOfFile(dm.addr);
9392
}
9493
CloseHandle(dm.maphandle);

libc/intrin/dll.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
*
2929
* It's required that `elem` and `succ` aren't part of the same list.
3030
*/
31-
privileged void dll_splice_after(struct Dll *elem, struct Dll *succ) {
31+
void dll_splice_after(struct Dll *elem, struct Dll *succ) {
3232
struct Dll *tmp1, *tmp2;
3333
tmp1 = elem->next;
3434
tmp2 = succ->prev;
@@ -43,7 +43,7 @@ privileged void dll_splice_after(struct Dll *elem, struct Dll *succ) {
4343
*
4444
* @param list is a doubly-linked list, where `!*list` means empty
4545
*/
46-
privileged void dll_remove(struct Dll **list, struct Dll *elem) {
46+
void dll_remove(struct Dll **list, struct Dll *elem) {
4747
if (*list == elem) {
4848
if ((*list)->prev == *list) {
4949
*list = 0;
@@ -66,7 +66,7 @@ privileged void dll_remove(struct Dll **list, struct Dll *elem) {
6666
* @param list is a doubly-linked list, where `!*list` means empty
6767
* @param elem must not be a member of `list`, or null for no-op
6868
*/
69-
privileged void dll_make_first(struct Dll **list, struct Dll *elem) {
69+
void dll_make_first(struct Dll **list, struct Dll *elem) {
7070
if (elem) {
7171
if (!*list) {
7272
*list = elem->prev;
@@ -85,7 +85,7 @@ privileged void dll_make_first(struct Dll **list, struct Dll *elem) {
8585
* @param list is a doubly-linked list, where `!*list` means empty
8686
* @param elem must not be a member of `list`, or null for no-op
8787
*/
88-
privileged void dll_make_last(struct Dll **list, struct Dll *elem) {
88+
void dll_make_last(struct Dll **list, struct Dll *elem) {
8989
if (elem) {
9090
dll_make_first(list, elem->next);
9191
*list = elem;

libc/intrin/kprintf.greg.c

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include "libc/fmt/magnumstrs.internal.h"
2626
#include "libc/intrin/asmflag.h"
2727
#include "libc/intrin/atomic.h"
28-
#include "libc/intrin/dll.h"
2928
#include "libc/intrin/getenv.internal.h"
3029
#include "libc/intrin/kprintf.h"
3130
#include "libc/intrin/likely.h"
@@ -154,27 +153,18 @@ __funline bool kischarmisaligned(const char *p, signed char t) {
154153
return false;
155154
}
156155

157-
privileged static bool32 kisdangerous_unlocked(const char *addr) {
158-
struct Dll *e;
159-
if ((e = dll_first(__maps.used))) {
160-
do {
161-
struct Map *map = MAP_CONTAINER(e);
162-
if (map->addr <= addr && addr < map->addr + map->size) {
163-
dll_remove(&__maps.used, e);
164-
dll_make_first(&__maps.used, e);
165-
return !(map->prot & PROT_READ);
166-
}
167-
} while ((e = dll_next(__maps.used, e)));
168-
return true;
169-
} else {
170-
return false;
171-
}
172-
}
173-
174156
privileged bool32 kisdangerous(const void *addr) {
175-
bool32 res;
157+
bool32 res = true;
176158
__maps_lock();
177-
res = kisdangerous_unlocked(addr);
159+
if (__maps.maps) {
160+
struct Map *map;
161+
if ((map = __maps_floor(addr)))
162+
if ((const char *)addr >= map->addr &&
163+
(const char *)addr < map->addr + map->size)
164+
res = false;
165+
} else {
166+
res = false;
167+
}
178168
__maps_unlock();
179169
return res;
180170
}

libc/intrin/maps.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "ape/sections.internal.h"
2121
#include "libc/dce.h"
2222
#include "libc/intrin/dll.h"
23+
#include "libc/intrin/maps.h"
2324
#include "libc/runtime/runtime.h"
2425
#include "libc/runtime/stack.h"
2526
#include "libc/sysv/consts/auxv.h"
@@ -32,8 +33,7 @@ __static_yoink("_init_maps");
3233
struct Maps __maps;
3334

3435
void __maps_add(struct Map *map) {
35-
dll_init(&map->elem);
36-
dll_make_first(&__maps.used, &map->elem);
36+
tree_insert(&__maps.maps, &map->tree, __maps_compare);
3737
++__maps.count;
3838
}
3939

libc/intrin/maps.h

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,41 @@
1-
#ifndef COSMOPOLITAN_LIBC_RUNTIME_MAPS_H_
2-
#define COSMOPOLITAN_LIBC_RUNTIME_MAPS_H_
1+
#ifndef COSMOPOLITAN_MAPS_H_
2+
#define COSMOPOLITAN_MAPS_H_
33
#include "libc/intrin/atomic.h"
44
#include "libc/intrin/dll.h"
5+
#include "libc/intrin/tree.h"
6+
#include "libc/runtime/runtime.h"
57
#include "libc/thread/tls2.internal.h"
68
COSMOPOLITAN_C_START_
79

8-
#define MAP_CONTAINER(e) DLL_CONTAINER(struct Map, elem, e)
10+
#define MAP_TREE_CONTAINER(e) TREE_CONTAINER(struct Map, tree, e)
11+
#define MAP_FREE_CONTAINER(e) DLL_CONTAINER(struct Map, free, e)
912

1013
struct Map {
1114
char *addr; /* granule aligned */
1215
size_t size; /* must be nonzero */
13-
struct Dll elem; /* for __maps.free */
14-
int64_t off; /* -1 if anonymous */
16+
int64_t off; /* ignore for anon */
1517
int prot; /* memory protects */
1618
int flags; /* memory map flag */
1719
bool iscow; /* windows nt only */
1820
bool readonlyfile; /* windows nt only */
1921
unsigned visited; /* used for checks */
22+
unsigned oldprot; /* in windows fork */
2023
intptr_t hand; /* windows nt only */
24+
union {
25+
struct Tree tree;
26+
struct Dll free;
27+
};
2128
};
2229

2330
struct Maps {
24-
unsigned mono;
2531
atomic_int lock;
32+
struct Tree *maps;
2633
struct Dll *free;
27-
struct Dll *used;
2834
size_t count;
2935
size_t pages;
36+
atomic_ulong rollo;
3037
struct Map stack;
3138
struct Map guard;
32-
bool once;
33-
atomic_ulong rollo;
3439
};
3540

3641
struct AddrSize {
@@ -45,10 +50,37 @@ bool __maps_lock(void);
4550
void __maps_check(void);
4651
void __maps_unlock(void);
4752
void __maps_add(struct Map *);
48-
struct Map *__maps_alloc(void);
4953
void __maps_free(struct Map *);
54+
struct Map *__maps_alloc(void);
55+
struct Map *__maps_floor(const char *);
5056
void __maps_stack(char *, int, int, size_t, int, intptr_t);
57+
int __maps_compare(const struct Tree *, const struct Tree *);
5158
struct AddrSize __get_main_stack(void);
5259

60+
forceinline optimizespeed int __maps_search(const void *key,
61+
const struct Tree *node) {
62+
const char *addr = (const char *)key;
63+
const struct Map *map = (const struct Map *)MAP_TREE_CONTAINER(node);
64+
if (addr < map->addr)
65+
return +1;
66+
if (addr >= map->addr + map->size)
67+
return -1;
68+
return 0;
69+
}
70+
71+
static struct Map *__maps_next(struct Map *map) {
72+
struct Tree *node;
73+
if ((node = tree_next(&map->tree)))
74+
return MAP_TREE_CONTAINER(node);
75+
return 0;
76+
}
77+
78+
static struct Map *__maps_first(void) {
79+
struct Tree *node;
80+
if ((node = tree_first(__maps.maps)))
81+
return MAP_TREE_CONTAINER(node);
82+
return 0;
83+
}
84+
5385
COSMOPOLITAN_C_END_
54-
#endif /* COSMOPOLITAN_LIBC_RUNTIME_MAPS_H_ */
86+
#endif /* COSMOPOLITAN_MAPS_H_ */

0 commit comments

Comments
 (0)