mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Reduce GNU Make latency 17% for cosmo
fgets() is now 4x faster which makes Make 2% faster. Landlock Make now has a builtin $(uniq ...) function that uses critbit trees rather than functional programming. Since uniq is the most important function this optimization makes our cold start latency 15% faster.
This commit is contained in:
parent
8835b82a7c
commit
d76dfadc7a
7 changed files with 96 additions and 11 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -11,3 +11,5 @@ __pycache__
|
||||||
/TAGS
|
/TAGS
|
||||||
/bx_enh_dbg.ini
|
/bx_enh_dbg.ini
|
||||||
/tool/emacs/*.elc
|
/tool/emacs/*.elc
|
||||||
|
/perf.data
|
||||||
|
/perf.data.old
|
||||||
|
|
|
@ -12,5 +12,9 @@
|
||||||
|
|
||||||
tail = $(wordlist 2,$(words $1),$1)
|
tail = $(wordlist 2,$(words $1),$1)
|
||||||
reverse = $(if $1,$(call reverse,$(call tail,$1)) $(firstword $1))
|
reverse = $(if $1,$(call reverse,$(call tail,$1)) $(firstword $1))
|
||||||
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
|
|
||||||
uniqr = $(if $1,$(call uniqr,$(filter-out $(firstword $1),$1)) $(firstword $1))
|
uniqr = $(if $1,$(call uniqr,$(filter-out $(firstword $1),$1)) $(firstword $1))
|
||||||
|
|
||||||
|
# polyfill uniq native (landlock make 1.4)
|
||||||
|
ifneq ($(call uniq,c b c a),c b a)
|
||||||
|
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
|
||||||
|
endif
|
||||||
|
|
|
@ -16,8 +16,12 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads line from stream.
|
* Reads line from stream.
|
||||||
|
@ -33,11 +37,23 @@
|
||||||
* zero characters have been read
|
* zero characters have been read
|
||||||
*/
|
*/
|
||||||
char *fgets_unlocked(char *s, int size, FILE *f) {
|
char *fgets_unlocked(char *s, int size, FILE *f) {
|
||||||
int c;
|
int c, n;
|
||||||
char *p;
|
char *p, *b, *t;
|
||||||
p = s;
|
p = s;
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
while (--size > 0) {
|
while (--size > 0) {
|
||||||
|
if (!IsTiny() && f->beg < f->end) {
|
||||||
|
b = f->buf + f->beg;
|
||||||
|
n = MIN(f->end - f->beg, size);
|
||||||
|
if ((t = memchr(b, '\n', n))) {
|
||||||
|
n = t + 1 - b;
|
||||||
|
}
|
||||||
|
memcpy(p, b, n);
|
||||||
|
f->beg += n;
|
||||||
|
size -= n - 1;
|
||||||
|
p += n;
|
||||||
|
if (t) break;
|
||||||
|
} else {
|
||||||
if ((c = fgetc_unlocked(f)) == -1) {
|
if ((c = fgetc_unlocked(f)) == -1) {
|
||||||
if (ferror_unlocked(f) == EINTR) {
|
if (ferror_unlocked(f) == EINTR) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -48,6 +64,7 @@ char *fgets_unlocked(char *s, int size, FILE *f) {
|
||||||
*p++ = c & 255;
|
*p++ = c & 255;
|
||||||
if (c == '\n') break;
|
if (c == '\n') break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
}
|
}
|
||||||
return p > s ? s : NULL;
|
return p > s ? s : NULL;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/gc.internal.h"
|
#include "libc/runtime/gc.internal.h"
|
||||||
#include "libc/stdio/stdio.h"
|
#include "libc/stdio/stdio.h"
|
||||||
|
#include "libc/testlib/ezbench.h"
|
||||||
#include "libc/testlib/hyperion.h"
|
#include "libc/testlib/hyperion.h"
|
||||||
#include "libc/testlib/testlib.h"
|
#include "libc/testlib/testlib.h"
|
||||||
|
|
||||||
|
@ -31,3 +32,19 @@ TEST(fgets, test) {
|
||||||
ASSERT_STREQ("John Keats\n", fgets(buf, sizeof(buf), f));
|
ASSERT_STREQ("John Keats\n", fgets(buf, sizeof(buf), f));
|
||||||
fclose(f);
|
fclose(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Benchmark(void) {
|
||||||
|
FILE *f;
|
||||||
|
char *line;
|
||||||
|
char buf[512];
|
||||||
|
f = fmemopen(gc(strdup(kHyperion)), kHyperionSize, "r+");
|
||||||
|
for (;;) {
|
||||||
|
line = fgets(buf, sizeof(buf), f);
|
||||||
|
if (!line) break;
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCH(fgets, bench) {
|
||||||
|
EZBENCH2("fgets", donothing, Benchmark());
|
||||||
|
}
|
||||||
|
|
1
third_party/make/commands.c
vendored
1
third_party/make/commands.c
vendored
|
@ -520,6 +520,7 @@ fatal_error_signal (int sig)
|
||||||
if (sig == SIGTERM || sig == SIGINT
|
if (sig == SIGTERM || sig == SIGINT
|
||||||
|| sig == SIGHUP
|
|| sig == SIGHUP
|
||||||
|| sig == SIGQUIT
|
|| sig == SIGQUIT
|
||||||
|
|| sig == SIGPIPE
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
struct child *c;
|
struct child *c;
|
||||||
|
|
1
third_party/make/expand.c
vendored
1
third_party/make/expand.c
vendored
|
@ -441,6 +441,7 @@ expand_argument (const char *str, const char *end)
|
||||||
|
|
||||||
r = allocated_variable_expand (tmp);
|
r = allocated_variable_expand (tmp);
|
||||||
|
|
||||||
|
if (alloc)
|
||||||
free (alloc);
|
free (alloc);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
|
43
third_party/make/function.c
vendored
43
third_party/make/function.c
vendored
|
@ -23,6 +23,9 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
#include "third_party/make/job.h"
|
#include "third_party/make/job.h"
|
||||||
#include "third_party/make/os.h"
|
#include "third_party/make/os.h"
|
||||||
#include "third_party/make/commands.h"
|
#include "third_party/make/commands.h"
|
||||||
|
#include "libc/mem/critbit0.h"
|
||||||
|
#include "libc/log/rop.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
#include "third_party/make/debug.h"
|
#include "third_party/make/debug.h"
|
||||||
|
|
||||||
struct function_table_entry
|
struct function_table_entry
|
||||||
|
@ -1160,6 +1163,45 @@ func_sort (char *o, char **argv, const char *funcname UNUSED)
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
chop argv[0] into words, and remove duplicates.
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
func_uniq (char *o, char **argv, const char *funcname UNUSED)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
size_t len;
|
||||||
|
int mutated;
|
||||||
|
bool once = false;
|
||||||
|
const char *s = argv[0];
|
||||||
|
struct critbit0 t = {0};
|
||||||
|
|
||||||
|
while ((p = find_next_token (&s, &len)))
|
||||||
|
{
|
||||||
|
++s;
|
||||||
|
p[len] = 0;
|
||||||
|
RETURN_ON_ERROR ((mutated = critbit0_insert (&t, p)));
|
||||||
|
if (mutated)
|
||||||
|
{
|
||||||
|
if (once)
|
||||||
|
o = variable_buffer_output (o, " ", 1);
|
||||||
|
else
|
||||||
|
once = true;
|
||||||
|
o = variable_buffer_output (o, p, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
critbit0_clear (&t);
|
||||||
|
|
||||||
|
return o;
|
||||||
|
|
||||||
|
OnError:
|
||||||
|
critbit0_clear (&t);
|
||||||
|
OSS (error, NILF, "%s: function failed: %s",
|
||||||
|
"uniq", strerror (errno));
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
$(if condition,true-part[,false-part])
|
$(if condition,true-part[,false-part])
|
||||||
|
|
||||||
|
@ -2137,6 +2179,7 @@ static struct function_table_entry function_table_init[] =
|
||||||
FT_ENTRY ("value", 0, 1, 1, func_value),
|
FT_ENTRY ("value", 0, 1, 1, func_value),
|
||||||
FT_ENTRY ("eval", 0, 1, 1, func_eval),
|
FT_ENTRY ("eval", 0, 1, 1, func_eval),
|
||||||
FT_ENTRY ("file", 1, 2, 1, func_file),
|
FT_ENTRY ("file", 1, 2, 1, func_file),
|
||||||
|
FT_ENTRY ("uniq", 0, 1, 1, func_uniq),
|
||||||
#ifdef EXPERIMENTAL
|
#ifdef EXPERIMENTAL
|
||||||
FT_ENTRY ("eq", 2, 2, 1, func_eq),
|
FT_ENTRY ("eq", 2, 2, 1, func_eq),
|
||||||
FT_ENTRY ("not", 0, 1, 1, func_not),
|
FT_ENTRY ("not", 0, 1, 1, func_not),
|
||||||
|
|
Loading…
Reference in a new issue