Reduce MKDEPS.COM latency from 60ms to 18ms

This commit is contained in:
Justine Tunney 2022-06-11 12:21:42 -07:00
parent e96aceae41
commit 517267a577
5 changed files with 140 additions and 76 deletions

Binary file not shown.

View file

@ -36,7 +36,8 @@ EXAMPLES_COMS = \
EXAMPLES_BINS = \ EXAMPLES_BINS = \
$(EXAMPLES_COMS) \ $(EXAMPLES_COMS) \
$(EXAMPLES_COMS:%=%.dbg) $(EXAMPLES_COMS:%=%.dbg) \
o/$(MODE)/examples/life-nomod.com
EXAMPLES_DIRECTDEPS = \ EXAMPLES_DIRECTDEPS = \
DSP_CORE \ DSP_CORE \

View file

@ -49,7 +49,6 @@
*/ */
int close(int fd) { int close(int fd) {
int rc; int rc;
__fds_lock();
if (fd == -1) { if (fd == -1) {
rc = 0; rc = 0;
} else if (fd < 0) { } else if (fd < 0) {
@ -78,10 +77,9 @@ int close(int fd) {
} }
} }
if (!__vforked) { if (!__vforked) {
__releasefd_unlocked(fd); __releasefd(fd);
} }
} }
__fds_unlock();
STRACE("%s(%d) → %d% m", "close", fd, rc); STRACE("%s(%d) → %d% m", "close", fd, rc);
return rc; return rc;
} }

View file

@ -44,6 +44,7 @@ TEST(getargs, test) {
EXPECT_STREQ("dawg", getargs_next(&ga)); EXPECT_STREQ("dawg", getargs_next(&ga));
EXPECT_STREQ("fun", getargs_next(&ga)); EXPECT_STREQ("fun", getargs_next(&ga));
EXPECT_EQ(NULL, getargs_next(&ga)); EXPECT_EQ(NULL, getargs_next(&ga));
EXPECT_EQ(NULL, getargs_next(&ga));
getargs_destroy(&ga); getargs_destroy(&ga);
} }

View file

@ -29,21 +29,28 @@
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
#include "libc/intrin/spinlock.h"
#include "libc/log/check.h" #include "libc/log/check.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/alloca.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nexgen32e/crc32.h" #include "libc/nexgen32e/crc32.h"
#include "libc/nexgen32e/threaded.h"
#include "libc/runtime/ezmap.internal.h" #include "libc/runtime/ezmap.internal.h"
#include "libc/runtime/gc.internal.h" #include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h"
#include "libc/runtime/sysconf.h"
#include "libc/stdio/append.internal.h" #include "libc/stdio/append.internal.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/clone.h"
#include "libc/sysv/consts/madv.h" #include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
#include "libc/time/time.h"
#include "libc/x/x.h" #include "libc/x/x.h"
#include "third_party/getopt/getopt.h" #include "third_party/getopt/getopt.h"
#include "tool/build/lib/getargs.h" #include "tool/build/lib/getargs.h"
@ -113,14 +120,21 @@ struct Edges {
}; };
char *out; char *out;
char *bout; char **tls;
int threads;
char **bouts;
char **stack;
unsigned counter; unsigned counter;
uint32_t *visited; struct GetArgs ga;
struct Edges edges; struct Edges edges;
struct Sauce *sauces; struct Sauce *sauces;
struct Strings strings; struct Strings strings;
struct Sources sources; struct Sources sources;
const char *buildroot; const char *buildroot;
_Alignas(64) int galock;
_Alignas(64) int readlock;
_Alignas(64) int writelock;
_Alignas(64) int reportlock;
unsigned Hash(const void *s, size_t l) { unsigned Hash(const void *s, size_t l) {
return max(1, crc32c(0, s, l)); return max(1, crc32c(0, s, l));
@ -232,25 +246,33 @@ wontreturn void OnMissingFile(const char *list, const char *src) {
exit(1); exit(1);
} }
void LoadRelationships(int argc, char *argv[]) { int LoadRelationshipsWorker(void *arg) {
int fd; int fd;
char *buf;
ssize_t rc; ssize_t rc;
bool skipme; bool skipme;
struct Edge edge; struct Edge edge;
struct GetArgs ga; char *buf, *freeme;
char srcbuf[PATH_MAX];
size_t i, n, inclen, size;
unsigned srcid, dependency; unsigned srcid, dependency;
size_t i, inclen, size;
const char *p, *pe, *src, *path, *pathend; const char *p, *pe, *src, *path, *pathend;
inclen = strlen(kIncludePrefix); inclen = strlen(kIncludePrefix);
buf = gc(xmemalign(PAGESIZE, PAGESIZE + MAX_READ + 16)); freeme = buf = memalign(PAGESIZE, PAGESIZE + MAX_READ + 16);
buf += PAGESIZE; buf += PAGESIZE;
buf[-1] = '\n'; buf[-1] = '\n';
getargs_init(&ga, argv + optind); for (;;) {
while ((src = getargs_next(&ga))) { _spinlock(&galock);
if ((src = getargs_next(&ga))) strcpy(srcbuf, src);
_spunlock(&galock);
if (!src) break;
src = srcbuf;
if (ShouldSkipSource(src)) continue; if (ShouldSkipSource(src)) continue;
srcid = GetSourceId(src, strlen(src)); n = strlen(src);
_spinlock(&readlock);
srcid = GetSourceId(src, n);
_spunlock(&readlock);
if ((fd = open(src, O_RDONLY)) == -1) { if ((fd = open(src, O_RDONLY)) == -1) {
_spinlock(&reportlock);
OnMissingFile(ga.path, src); OnMissingFile(ga.path, src);
} }
CHECK_NE(-1, (rc = read(fd, buf, MAX_READ))); CHECK_NE(-1, (rc = read(fd, buf, MAX_READ)));
@ -263,14 +285,39 @@ void LoadRelationships(int argc, char *argv[]) {
path = p + inclen; path = p + inclen;
pathend = memchr(path, '"', pe - path); pathend = memchr(path, '"', pe - path);
if (pathend && (p[-1] == '#' || p[-1] == '.') && p[-2] == '\n') { if (pathend && (p[-1] == '#' || p[-1] == '.') && p[-2] == '\n') {
_spinlock(&readlock);
dependency = GetSourceId(path, pathend - path); dependency = GetSourceId(path, pathend - path);
_spunlock(&readlock);
edge.from = srcid; edge.from = srcid;
edge.to = dependency; edge.to = dependency;
_spinlock(&writelock);
append(&edges, &edge); append(&edges, &edge);
_spunlock(&writelock);
p = pathend; p = pathend;
} }
} }
} }
free(freeme);
return 0;
}
void LoadRelationships(int argc, char *argv[]) {
int i;
getargs_init(&ga, argv + optind);
for (i = 0; i < threads; ++i) {
if (clone(LoadRelationshipsWorker, stack[i], GetStackSize(),
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
CLONE_SETTLS | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID,
(void *)(intptr_t)i, 0, __initialize_tls(tls[i]), 64,
(int *)(tls[i] + 0x38)) == -1) {
_spinlock(&reportlock);
kprintf("error: clone(%d) failed %m\n", i);
exit(1);
}
}
for (i = 0; i < threads; ++i) {
_spinlock((int *)(tls[i] + 0x38));
}
getargs_destroy(&ga); getargs_destroy(&ga);
} }
@ -294,19 +341,12 @@ void GetOpts(int argc, char *argv[]) {
if (isempty(buildroot)) kprintf("need -r o/$(MODE)"), exit(1); if (isempty(buildroot)) kprintf("need -r o/$(MODE)"), exit(1);
} }
const char *StripExt(const char *s) { const char *StripExt(char pathbuf[PATH_MAX], const char *s) {
static bool once; static char *dot;
static size_t i, n; strcpy(pathbuf, s);
static char *p, *dot; dot = strrchr(pathbuf, '.');
if (!once) {
once = true;
__cxa_atexit(free_s, &p, NULL);
}
i = 0;
CONCAT(&p, &i, &n, s, strlen(s) + 1);
dot = strrchr(p, '.');
if (dot) *dot = '\0'; if (dot) *dot = '\0';
return p; return pathbuf;
} }
bool IsObjectSource(const char *name) { bool IsObjectSource(const char *name) {
@ -329,16 +369,6 @@ forceinline bool Bts(uint32_t *p, size_t i) {
return false; return false;
} }
void Dive(unsigned id) {
int i;
for (i = FindFirstFromEdge(id); i < edges.i && edges.p[i].from == id; ++i) {
if (Bts(visited, edges.p[i].to)) continue;
appendw(&bout, READ32LE(" \\\n\t"));
appends(&bout, strings.p + sauces[edges.p[i].to].name);
Dive(edges.p[i].to);
}
}
size_t GetFileSizeOrZero(const char *path) { size_t GetFileSizeOrZero(const char *path) {
struct stat st; struct stat st;
st.st_size = 0; st.st_size = 0;
@ -346,66 +376,100 @@ size_t GetFileSizeOrZero(const char *path) {
return st.st_size; return st.st_size;
} }
/* prevents gnu make from restarting unless necessary */ void Dive(char **bout, uint32_t *visited, unsigned id) {
bool HasSameContent(void) { int i;
bool r; for (i = FindFirstFromEdge(id); i < edges.i && edges.p[i].from == id; ++i) {
int fd; if (Bts(visited, edges.p[i].to)) continue;
char *m; appendw(bout, READ32LE(" \\\n\t"));
size_t s; appends(bout, strings.p + sauces[edges.p[i].to].name);
s = GetFileSizeOrZero(out); Dive(bout, visited, edges.p[i].to);
if (s == appendz(bout).i) {
if (s) {
CHECK_NE(-1, (fd = open(out, O_RDONLY)), "open(%#s)", out);
CHECK_NE(MAP_FAILED, (m = mmap(0, s, PROT_READ, MAP_SHARED, fd, 0)));
r = !bcmp(bout, m, s);
munmap(m, s);
close(fd);
} else {
r = true;
} }
} else {
r = false;
}
return r;
} }
int main(int argc, char *argv[]) { int Diver(void *arg) {
int fd; char *bout = 0;
const char *path; const char *path;
uint32_t *visited;
size_t i, visilen; size_t i, visilen;
if (argc == 2 && !strcmp(argv[1], "-n")) exit(0); char pathbuf[PATH_MAX];
out = "/dev/stdout"; int tid = (intptr_t)arg;
GetOpts(argc, argv);
LoadRelationships(argc, argv);
Crunch();
visilen = (sources.i + sizeof(*visited) * CHAR_BIT - 1) / visilen = (sources.i + sizeof(*visited) * CHAR_BIT - 1) /
(sizeof(*visited) * CHAR_BIT); (sizeof(*visited) * CHAR_BIT);
visited = malloc(visilen * sizeof(*visited)); visited = malloc(visilen * sizeof(*visited));
for (i = 0; i < sources.i; ++i) { for (i = tid; i < sources.i; i += threads) {
path = strings.p + sauces[i].name; path = strings.p + sauces[i].name;
if (!IsObjectSource(path)) continue; if (!IsObjectSource(path)) continue;
appendw(&bout, '\n'); appendw(&bout, '\n');
if (!startswith(path, "o/")) { if (!startswith(path, "o/")) {
appends(&bout, buildroot); appends(&bout, buildroot);
} }
appends(&bout, StripExt(path)); appends(&bout, StripExt(pathbuf, path));
appendw(&bout, READ64LE(".o: \\\n\t")); appendw(&bout, READ64LE(".o: \\\n\t"));
appends(&bout, path); appends(&bout, path);
bzero(visited, visilen * sizeof(*visited)); bzero(visited, visilen * sizeof(*visited));
Bts(visited, i); Bts(visited, i);
Dive(i); Dive(&bout, visited, i);
appendw(&bout, '\n'); appendw(&bout, '\n');
} }
/* if (!fileexists(out) || !HasSameContent()) { */
CHECK_NE(-1, (fd = open(out, O_CREAT | O_WRONLY, 0644)), "open(%#s)", out);
CHECK_NE(-1, ftruncate(fd, appendz(bout).i));
CHECK_NE(-1, xwrite(fd, bout, appendz(bout).i));
CHECK_NE(-1, close(fd));
/* } */
free(strings.p);
free(edges.p);
free(visited); free(visited);
free(sauces); appendw(&bout, '\n');
free(bout); bouts[tid] = bout;
return 0;
}
void Explore(void) {
int i;
for (i = 0; i < threads; ++i) {
if (clone(Diver, stack[i], GetStackSize(),
CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
CLONE_SETTLS | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID,
(void *)(intptr_t)i, 0, __initialize_tls(tls[i]), 64,
(int *)(tls[i] + 0x38)) == -1) {
_spinlock(&reportlock);
kprintf("error: clone(%d) failed %m\n", i);
exit(1);
}
}
for (i = 0; i < threads; ++i) {
_spinlock((int *)(tls[i] + 0x38));
}
}
int main(int argc, char *argv[]) {
int i, fd;
if (argc == 2 && !strcmp(argv[1], "-n")) exit(0);
out = "/dev/stdout";
GetOpts(argc, argv);
threads = GetCpuCount();
tls = calloc(threads, sizeof(*tls));
stack = calloc(threads, sizeof(*stack));
bouts = calloc(threads, sizeof(*bouts));
for (i = 0; i < threads; ++i) {
if (!(tls[i] = malloc(64)) ||
(stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE,
MAP_STACK | MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) {
kprintf("error: mmap(%d) failed %m\n", i);
exit(1);
}
}
LoadRelationships(argc, argv);
Crunch();
Explore();
CHECK_NE(-1, (fd = open(out, O_CREAT | O_WRONLY, 0644)), "open(%#s)", out);
for (i = 0; i < threads; ++i) {
CHECK_NE(-1, xwrite(fd, bouts[i], appendz(bouts[i]).i));
}
CHECK_NE(-1, close(fd));
for (i = 0; i < threads; ++i) {
munmap(stack[i], GetStackSize());
free(bouts[i]);
free(tls[i]);
}
free(strings.p);
free(edges.p);
free(sauces);
free(stack);
free(bouts);
free(tls);
return 0; return 0;
} }