mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
Reduce MKDEPS.COM latency from 60ms to 18ms
This commit is contained in:
parent
e96aceae41
commit
517267a577
5 changed files with 140 additions and 76 deletions
Binary file not shown.
|
@ -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 \
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue