Skip to content

Commit e56a9d0

Browse files
committed
Mold the redbean binary to minimize page faults
This change brings page faults for precompressed static asset serving down from 27 to 20 (or fewer) after fork. This is more of an art than science. Hopefully Blinkenlights can visualize page faults soon.
1 parent 2d34819 commit e56a9d0

File tree

14 files changed

+976
-780
lines changed

14 files changed

+976
-780
lines changed

libc/dos.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#ifndef COSMOPOLITAN_LIBC_DOS_H_
2+
#define COSMOPOLITAN_LIBC_DOS_H_
3+
4+
#define DOS_DATE(YEAR, MONTH_IDX1, DAY_IDX1) \
5+
(((YEAR)-1980) << 9 | (MONTH_IDX1) << 5 | (DAY_IDX1))
6+
#define DOS_TIME(HOUR, MINUTE, SECOND) \
7+
((HOUR) << 11 | (MINUTE) << 5 | (SECOND) >> 1)
8+
9+
#endif /* COSMOPOLITAN_LIBC_DOS_H_ */

libc/runtime/ftrace.c

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,13 @@
2323
#include "libc/calls/internal.h"
2424
#include "libc/calls/struct/sigset.h"
2525
#include "libc/dce.h"
26+
#include "libc/fmt/itoa.h"
2627
#include "libc/intrin/repmovsb.h"
2728
#include "libc/macros.internal.h"
29+
#include "libc/nexgen32e/rdtsc.h"
30+
#include "libc/nexgen32e/rdtscp.h"
2831
#include "libc/nexgen32e/stackframe.h"
32+
#include "libc/nexgen32e/x86feature.h"
2933
#include "libc/nt/files.h"
3034
#include "libc/nt/runtime.h"
3135
#include "libc/nt/thunk/msabi.h"
@@ -49,6 +53,7 @@
4953
void ftrace_hook(void);
5054

5155
static int noreentry;
56+
static uint64_t laststamp;
5257
static char g_buf[512];
5358
static const char *g_lastsymbol;
5459
static struct SymbolTable *g_symbols;
@@ -70,11 +75,14 @@ static noasan int GetNestingLevel(struct StackFrame *frame) {
7075
* according to the System Five NexGen32e ABI.
7176
*/
7277
privileged noasan void ftrace(void) {
73-
size_t i, j, nesting;
78+
char *p;
79+
uint64_t stamp;
7480
const char *symbol;
7581
struct StackFrame *frame;
82+
size_t nesting, symbolsize;
7683
if (!cmpxchg(&noreentry, 0, 1)) return;
7784
if (g_symbols) {
85+
stamp = rdtsc();
7886
frame = __builtin_frame_address(0);
7987
frame = frame->next;
8088
symbol =
@@ -84,31 +92,30 @@ privileged noasan void ftrace(void) {
8492
g_symbols->count,
8593
frame->addr - g_symbols->addr_base)]
8694
.name_rva];
87-
if (symbol != g_lastsymbol &&
88-
(nesting = GetNestingLevel(frame)) * 2 < ARRAYLEN(g_buf) - 4) {
89-
i = 2;
90-
j = 0;
91-
while (nesting--) {
92-
asm volatile("" : : : "memory");
93-
g_buf[i++] = ' ';
94-
g_buf[i++] = ' ';
95+
if (symbol != g_lastsymbol) {
96+
symbolsize = strlen(symbol);
97+
nesting = GetNestingLevel(frame);
98+
if (2 + nesting * 2 + symbolsize + 1 + 21 + 2 <= ARRAYLEN(g_buf)) {
99+
p = g_buf;
100+
*p++ = '+';
101+
*p++ = ' ';
102+
memset(p, ' ', nesting * 2);
103+
p += nesting * 2;
104+
p = mempcpy(p, symbol, symbolsize);
105+
*p++ = ' ';
106+
p += uint64toarray_radix10((stamp - laststamp) / 3.3, p);
107+
*p++ = '\r';
108+
*p++ = '\n';
109+
write(2, g_buf, p - g_buf);
95110
}
96-
while (i < ARRAYLEN(g_buf) - 2 && symbol[j]) {
97-
asm volatile("" : : : "memory");
98-
g_buf[i++] = symbol[j++];
99-
}
100-
g_buf[i++] = '\r';
101-
g_buf[i++] = '\n';
102-
write(2, g_buf, i);
103111
}
104112
g_lastsymbol = symbol;
113+
laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
105114
}
106115
noreentry = 0;
107116
}
108117

109118
textstartup void ftrace_install(void) {
110-
g_buf[0] = '+';
111-
g_buf[1] = ' ';
112119
if ((g_symbols = OpenSymbolTable(FindDebugBinary()))) {
113120
__hook(ftrace_hook, g_symbols);
114121
} else {

libc/str/getzipcdirsize.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
2+
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
3+
╞══════════════════════════════════════════════════════════════════════════════╡
4+
│ Copyright 2021 Justine Alexandra Roberts Tunney │
5+
│ │
6+
│ Permission to use, copy, modify, and/or distribute this software for │
7+
│ any purpose with or without fee is hereby granted, provided that the │
8+
│ above copyright notice and this permission notice appear in all copies. │
9+
│ │
10+
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
11+
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
12+
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
13+
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
14+
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
15+
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
16+
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
17+
│ PERFORMANCE OF THIS SOFTWARE. │
18+
╚─────────────────────────────────────────────────────────────────────────────*/
19+
#include "libc/zip.h"
20+
21+
/**
22+
* Returns size of zip central directory.
23+
*/
24+
uint64_t GetZipCdirSize(const uint8_t *eocd) {
25+
if (READ32LE(eocd) == kZipCdir64HdrMagic) {
26+
return ZIP_CDIR64_SIZE(eocd);
27+
} else {
28+
return ZIP_CDIR_SIZE(eocd);
29+
}
30+
}

libc/str/memmem.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,22 @@
3030
void *memmem(const void *haystack, size_t haystacklen, const void *needle,
3131
size_t needlelen) {
3232
size_t i, j;
33+
const char *p;
3334
if (!needlelen) return haystack;
34-
for (i = 0; i < haystacklen; ++i) {
35-
for (j = 0;; ++j) {
36-
if (j == needlelen) return (/*unconst*/ char *)haystack + i;
37-
if (i + j == haystacklen) break;
38-
if (((char *)needle)[j] != ((char *)haystack)[i + j]) break;
35+
if (needlelen <= haystacklen) {
36+
p = memchr(haystack, *(const char *)needle, haystacklen);
37+
if (needlelen == 1) return p;
38+
if (p) {
39+
haystacklen -= p - (const char *)haystack;
40+
haystack = p;
41+
}
42+
/* TODO: make not quadratic */
43+
for (i = 0; i < haystacklen; ++i) {
44+
for (j = 0;; ++j) {
45+
if (j == needlelen) return (/*unconst*/ char *)haystack + i;
46+
if (i + j == haystacklen) break;
47+
if (((char *)needle)[j] != ((char *)haystack)[i + j]) break;
48+
}
3949
}
4050
}
4151
return NULL;

libc/str/strchr.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include "libc/bits/bits.h"
2121
#include "libc/str/str.h"
2222

23-
noasan static const char *strchr_x64(const char *p, uint64_t c) {
23+
noasan static inline const char *strchr_x64(const char *p, uint64_t c) {
2424
unsigned a, b;
2525
uint64_t w, x, y;
2626
for (c *= 0x0101010101010101;; p += 8) {

libc/str/strstr.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
1717
│ PERFORMANCE OF THIS SOFTWARE. │
1818
╚─────────────────────────────────────────────────────────────────────────────*/
19-
#include "libc/bits/safemacros.internal.h"
2019
#include "libc/str/str.h"
2120

2221
/**
@@ -30,8 +29,13 @@
3029
*/
3130
char *strstr(const char *haystack, const char *needle) {
3231
size_t i;
33-
if (!*needle) return haystack;
34-
haystack = firstnonnull(strchr(haystack, *needle), haystack);
32+
const char *p;
33+
if (!needle[0]) return haystack;
34+
if (haystack == needle) return haystack;
35+
p = strchr(haystack, needle[0]);
36+
if (!needle[1]) return p;
37+
if (p) haystack = p;
38+
/* TODO: make not quadratic */
3539
for (;;) {
3640
for (i = 0;;) {
3741
if (!needle[i]) return (/*unconst*/ char *)haystack;

libc/zip.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ int GetZipCfileMode(const uint8_t *);
185185
uint64_t GetZipCdirOffset(const uint8_t *);
186186
uint64_t GetZipCdirRecords(const uint8_t *);
187187
void *GetZipCdirComment(const uint8_t *);
188+
uint64_t GetZipCdirSize(const uint8_t *);
188189
uint64_t GetZipCdirCommentSize(const uint8_t *);
189190
uint64_t GetZipCfileUncompressedSize(const uint8_t *);
190191
uint64_t GetZipCfileCompressedSize(const uint8_t *);

test/libc/nexgen32e/memrchr_test.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
2+
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
3+
╞══════════════════════════════════════════════════════════════════════════════╡
4+
│ Copyright 2021 Justine Alexandra Roberts Tunney │
5+
│ │
6+
│ Permission to use, copy, modify, and/or distribute this software for │
7+
│ any purpose with or without fee is hereby granted, provided that the │
8+
│ above copyright notice and this permission notice appear in all copies. │
9+
│ │
10+
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
11+
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
12+
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
13+
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
14+
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
15+
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
16+
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
17+
│ PERFORMANCE OF THIS SOFTWARE. │
18+
╚─────────────────────────────────────────────────────────────────────────────*/
19+
#include "libc/nexgen32e/nexgen32e.h"
20+
#include "libc/testlib/ezbench.h"
21+
#include "libc/testlib/testlib.h"
22+
23+
TEST(memrchr, test) {
24+
EXPECT_STREQ(".there", memrchr("yo.hi.there", '.', 11));
25+
}
26+
27+
BENCH(memrchr, bench) {
28+
EZBENCH2("memrchr", donothing, EXPROPRIATE(memrchr("yo.hi.there", '.', 11)));
29+
}

test/libc/str/memmem_test.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include "libc/mem/mem.h"
2222
#include "libc/str/internal.h"
2323
#include "libc/str/str.h"
24+
#include "libc/testlib/ezbench.h"
25+
#include "libc/testlib/hyperion.h"
2426
#include "libc/testlib/testlib.h"
2527

2628
#define MakeMemory(SL) memcpy(malloc(sizeof(SL) - 1), SL, sizeof(SL) - 1)
@@ -60,6 +62,22 @@ TEST(memmem, testEndOfMemory) {
6062
free(needle);
6163
}
6264

65+
TEST(memmem, testOneNo) {
66+
char *needle = MakeMemory("z");
67+
char *haystk = MakeMemory("abc123");
68+
EXPECT_EQ(0, memmem(haystk, 6, needle, 1));
69+
free(haystk);
70+
free(needle);
71+
}
72+
73+
TEST(memmem, testOneYes) {
74+
char *needle = MakeMemory("3");
75+
char *haystk = MakeMemory("abc123");
76+
EXPECT_EQ(&haystk[5], memmem(haystk, 6, needle, 1));
77+
free(haystk);
78+
free(needle);
79+
}
80+
6381
TEST(memmem, testCrossesSseRegister) {
6482
char *needle = MakeMemory("eeeeeeeeeeeeefffffffffffff");
6583
char *haystk = MakeMemory("eeeeeeeeeeeeeeeeffffffffffffffffrrrrrrrrrrrrrrrr");
@@ -113,3 +131,12 @@ TEST(memmem, testEmptyHaystackAndNeedle_returnsHaystack) {
113131
TEST(memmem, testWut) {
114132
ASSERT_STREQ("x", memmem("x", 1, "x", 1));
115133
}
134+
135+
BENCH(memmem, bench) {
136+
EZBENCH2("memmem", donothing,
137+
EXPROPRIATE(memmem(kHyperion, kHyperionSize, "THE END", 7)));
138+
EZBENCH2("memmem", donothing,
139+
EXPROPRIATE(memmem(
140+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",
141+
62, "aaaaaab", 7)));
142+
}

test/libc/str/strstr_test.c

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ TEST(strstr, test_notFound) {
4646
free(haystack);
4747
}
4848

49+
TEST(strstr, test_notFound1) {
50+
MAKESTRING(haystack, "abc123def");
51+
ASSERT_EQ(NULL, strstr(haystack, gc(strdup("x"))));
52+
free(haystack);
53+
}
54+
4955
TEST(strstr, test_middleOfString) {
5056
MAKESTRING(haystack, "abc123def");
5157
ASSERT_STREQ(&haystack[3], strstr(haystack, gc(strdup("123"))));
@@ -80,8 +86,40 @@ TEST(strstr, test) {
8086

8187
BENCH(strstr, bench) {
8288
EZBENCH2("strstr", donothing, EXPROPRIATE(strstr(kHyperion, "THE END")));
83-
EZBENCH2("strstr", donothing,
89+
EZBENCH2("strstr torture 1", donothing,
90+
EXPROPRIATE(strstr(
91+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
92+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
93+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",
94+
"b")));
95+
EZBENCH2("strstr torture 2", donothing,
96+
EXPROPRIATE(strstr(
97+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
98+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
99+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",
100+
"ab")));
101+
EZBENCH2("strstr torture 4", donothing,
102+
EXPROPRIATE(strstr(
103+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
104+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
105+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",
106+
"aaab")));
107+
EZBENCH2("strstr torture 8", donothing,
108+
EXPROPRIATE(strstr(
109+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
110+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
111+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",
112+
"aaaaaaab")));
113+
EZBENCH2("strstr torture 16", donothing,
114+
EXPROPRIATE(strstr(
115+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
116+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
117+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",
118+
"aaaaaaaaaaaaaaab")));
119+
EZBENCH2("strstr torture 32", donothing,
84120
EXPROPRIATE(strstr(
85-
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",
86-
"aaaaaab")));
121+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
122+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
123+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",
124+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab")));
87125
}

0 commit comments

Comments
 (0)