mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 06:48:31 +00:00
Improve performance of printf functions
This commit is contained in:
parent
b107d2709f
commit
dc6d11a031
39 changed files with 577 additions and 650 deletions
|
@ -228,6 +228,7 @@ int gethostname_bsd(char *, size_t) hidden;
|
|||
int gethostname_nt(char *, size_t) hidden;
|
||||
size_t __iovec_size(const struct iovec *, size_t) hidden;
|
||||
void __rusage2linux(struct rusage *) hidden;
|
||||
ssize_t WritevUninterruptible(int, struct iovec *, int);
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § syscalls » windows nt » veneers ─╬─│┼
|
||||
|
|
|
@ -70,10 +70,6 @@ long double ConvertTicksToNanos(uint64_t ticks) {
|
|||
return ticks * g_now.cpn; /* pico scale */
|
||||
}
|
||||
|
||||
static long double ConvertTicksToSeconds(uint64_t ticks) {
|
||||
return 1 / 1e9 * ConvertTicksToNanos(ticks);
|
||||
}
|
||||
|
||||
long double nowl_sys(void) {
|
||||
return dtime(CLOCK_REALTIME);
|
||||
}
|
||||
|
@ -82,5 +78,5 @@ long double nowl_art(void) {
|
|||
uint64_t ticks;
|
||||
if (!g_now.once) RefreshTime();
|
||||
ticks = unsignedsubtract(rdtsc(), g_now.k0);
|
||||
return g_now.r0 + ConvertTicksToSeconds(ticks);
|
||||
return g_now.r0 + (1 / 1e9L * (ticks * g_now.cpn));
|
||||
}
|
||||
|
|
|
@ -22,43 +22,55 @@
|
|||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/sock/sock.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
struct VdprintfState {
|
||||
int n;
|
||||
int fd;
|
||||
unsigned char buf[1024];
|
||||
int n, t, fd;
|
||||
char b[1024];
|
||||
};
|
||||
|
||||
static int vdprintf_flush(struct VdprintfState *df, int n) {
|
||||
int i, rc;
|
||||
for (i = 0; i < n; i += rc) {
|
||||
if ((rc = write(df->fd, df->buf + i, n - i)) == -1) {
|
||||
return -1;
|
||||
static int vdprintf_putc(const char *s, struct VdprintfState *t, size_t n) {
|
||||
struct iovec iov[2];
|
||||
if (n) {
|
||||
if (t->n + n < sizeof(t->b)) {
|
||||
memcpy(t->b + t->n, s, n);
|
||||
t->n += n;
|
||||
} else {
|
||||
iov[0].iov_base = t->b;
|
||||
iov[0].iov_len = t->n;
|
||||
iov[1].iov_base = s;
|
||||
iov[1].iov_len = n;
|
||||
if (WritevUninterruptible(t->fd, iov, 2) == -1) {
|
||||
return -1;
|
||||
}
|
||||
t->t += t->n;
|
||||
t->n = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vdprintf_putc(int c, struct VdprintfState *df) {
|
||||
df->buf[df->n++ & (ARRAYLEN(df->buf) - 1)] = c & 0xff;
|
||||
if ((df->n & (ARRAYLEN(df->buf) - 1))) {
|
||||
return 0;
|
||||
} else {
|
||||
return vdprintf_flush(df, ARRAYLEN(df->buf));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats string directly to system i/o device.
|
||||
* @asyncsignalsafe
|
||||
* @vforksafe
|
||||
*/
|
||||
int(vdprintf)(int fd, const char *fmt, va_list va) {
|
||||
struct VdprintfState df;
|
||||
df.n = 0;
|
||||
df.fd = fd;
|
||||
if (__fmt(vdprintf_putc, &df, fmt, va) == -1) return -1;
|
||||
if (vdprintf_flush(&df, df.n & (ARRAYLEN(df.buf) - 1)) == -1) return -1;
|
||||
return df.n;
|
||||
struct iovec iov[1];
|
||||
struct VdprintfState t;
|
||||
t.n = 0;
|
||||
t.t = 0;
|
||||
t.fd = fd;
|
||||
if (__fmt(vdprintf_putc, &t, fmt, va) == -1) return -1;
|
||||
if (t.n) {
|
||||
iov[0].iov_base = t.b;
|
||||
iov[0].iov_len = t.n;
|
||||
if (WritevUninterruptible(t.fd, iov, 1) == -1) {
|
||||
return -1;
|
||||
}
|
||||
t.t += t.n;
|
||||
}
|
||||
return t.t;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi│
|
||||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
|
@ -16,28 +16,30 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/x86feature.h"
|
||||
#include "libc/notice.inc"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/sock/sock.h"
|
||||
|
||||
// Computes 32-bit Castagnoli Cyclic Redundancy Check.
|
||||
//
|
||||
// @param edi is the initial hash value (0 is fine)
|
||||
// @param rsi points to the data
|
||||
// @param rdx is the byte size of data
|
||||
// @return eax is the new hash value
|
||||
// @note Used by ISCSI, TensorFlow, etc.
|
||||
.initbss 300,_init_crc32c
|
||||
crc32c: .quad 0
|
||||
.endobj crc32c,globl
|
||||
.previous
|
||||
|
||||
.init.start 300,_init_crc32c
|
||||
ezlea crc32c_pure,ax
|
||||
ezlea crc32c_sse42,cx
|
||||
testb X86_HAVE(SSE4_2)+kCpuids(%rip)
|
||||
cmovnz %rcx,%rax
|
||||
stosq
|
||||
.init.end 300,_init_crc32c
|
||||
.source __FILE__
|
||||
ssize_t WritevUninterruptible(int fd, struct iovec *iov, int iovlen) {
|
||||
ssize_t rc;
|
||||
size_t wrote;
|
||||
do {
|
||||
if ((rc = writev(fd, iov, iovlen)) != -1) {
|
||||
wrote = rc;
|
||||
do {
|
||||
if (wrote >= iov->iov_len) {
|
||||
wrote -= iov->iov_len;
|
||||
++iov;
|
||||
--iovlen;
|
||||
} else {
|
||||
iov->iov_base = (char *)iov->iov_base + wrote;
|
||||
iov->iov_len -= wrote;
|
||||
wrote = 0;
|
||||
}
|
||||
} while (wrote);
|
||||
} else if (errno != EINTR) {
|
||||
return -1;
|
||||
}
|
||||
} while (iovlen);
|
||||
return 0;
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
|
@ -31,11 +32,12 @@
|
|||
#include "libc/sysv/errfuns.h"
|
||||
#include "third_party/gdtoa/gdtoa.h"
|
||||
|
||||
#define PUT(C) \
|
||||
do { \
|
||||
if (out(C, arg) == -1) { \
|
||||
return -1; \
|
||||
} \
|
||||
#define PUT(C) \
|
||||
do { \
|
||||
char Buf[1] = {C}; \
|
||||
if (out(Buf, arg, 1) == -1) { \
|
||||
return -1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static const char kSpecialFloats[2][2][4] = {{"INF", "inf"}, {"NAN", "nan"}};
|
||||
|
@ -121,14 +123,18 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
uint32_t u[2];
|
||||
uint64_t q;
|
||||
} pun;
|
||||
long ld;
|
||||
void *p;
|
||||
unsigned u;
|
||||
char ibuf[21];
|
||||
bool longdouble;
|
||||
long double ldbl;
|
||||
unsigned long lu;
|
||||
wchar_t charbuf[1];
|
||||
const char *alphabet;
|
||||
int (*out)(long, void *);
|
||||
int (*out)(const char *, void *, size_t);
|
||||
unsigned char signbit, log2base;
|
||||
int c, d, k, w, i1, ui, bw, bex;
|
||||
int c, d, k, w, n, i1, ui, bw, bex;
|
||||
char *s, *q, *se, qchar, special[8];
|
||||
int sgn, alt, sign, prec, prec1, flags, width, decpt, lasterr;
|
||||
|
||||
|
@ -136,18 +142,64 @@ hidden int __fmt(void *fn, void *arg, const char *format, va_list va) {
|
|||
out = fn ? fn : (void *)missingno;
|
||||
|
||||
while (*format) {
|
||||
/* %[flags][width][.prec][length] */
|
||||
if (*format != '%') {
|
||||
/* no */
|
||||
PUT(*format);
|
||||
format++;
|
||||
for (n = 1; format[n]; ++n) {
|
||||
if (format[n] == '%') break;
|
||||
}
|
||||
if (out(format, arg, n) == -1) return -1;
|
||||
format += n;
|
||||
continue;
|
||||
} else {
|
||||
/* yes, evaluate it */
|
||||
format++;
|
||||
}
|
||||
|
||||
/* evaluate flags */
|
||||
if (!IsTiny()) {
|
||||
if (format[1] == 's') { /* FAST PATH: PLAIN STRING */
|
||||
s = va_arg(va, char *);
|
||||
if (!s) s = "(null)";
|
||||
if (out(s, arg, strlen(s)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'd') { /* FAST PATH: PLAIN INTEGER */
|
||||
d = va_arg(va, int);
|
||||
if (out(ibuf, arg, int64toarray_radix10(d, ibuf)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'u') { /* FAST PATH: PLAIN UNSIGNED */
|
||||
u = va_arg(va, unsigned);
|
||||
if (out(ibuf, arg, uint64toarray_radix10(u, ibuf)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'x') { /* FAST PATH: PLAIN HEX */
|
||||
u = va_arg(va, unsigned);
|
||||
if (out(ibuf, arg, uint64toarray_radix16(u, ibuf)) == -1) return -1;
|
||||
format += 2;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'x') {
|
||||
lu = va_arg(va, unsigned long); /* FAST PATH: PLAIN LONG HEX */
|
||||
if (out(ibuf, arg, uint64toarray_radix16(lu, ibuf)) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'd') {
|
||||
ld = va_arg(va, long); /* FAST PATH: PLAIN LONG */
|
||||
if (out(ibuf, arg, int64toarray_radix10(ld, ibuf)) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == 'l' && format[2] == 'u') {
|
||||
lu = va_arg(va, unsigned long); /* FAST PATH: PLAIN UNSIGNED LONG */
|
||||
if (out(ibuf, arg, int64toarray_radix10(lu, ibuf)) == -1) return -1;
|
||||
format += 3;
|
||||
continue;
|
||||
} else if (format[1] == '.' && format[2] == '*' && format[3] == 's') {
|
||||
n = va_arg(va, unsigned); /* FAST PATH: PRECISION STRING */
|
||||
s = va_arg(va, const char *);
|
||||
if (!s) s = "(null)", n = MIN(6, n);
|
||||
if (out(s, arg, n) == -1) return -1;
|
||||
format += 4;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* GENERAL PATH */
|
||||
format++;
|
||||
sign = 0;
|
||||
flags = 0;
|
||||
getflag:
|
||||
|
|
|
@ -6,13 +6,14 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int __fmt_pad(int (*)(long, void *), void *, unsigned long) hidden;
|
||||
int __fmt_stoa(int (*)(long, void *), void *, void *, unsigned long,
|
||||
unsigned long, unsigned long, unsigned char,
|
||||
unsigned char) hidden;
|
||||
int __fmt_ntoa(int (*)(long, void *), void *, va_list, unsigned char,
|
||||
int __fmt_pad(int (*)(const char *, void *, size_t), void *,
|
||||
unsigned long) hidden;
|
||||
int __fmt_stoa(int (*)(const char *, void *, size_t), void *, void *,
|
||||
unsigned long, unsigned long, unsigned long, unsigned char,
|
||||
const char *) hidden;
|
||||
unsigned char) hidden;
|
||||
int __fmt_ntoa(int (*)(const char *, void *, size_t), void *, va_list,
|
||||
unsigned char, unsigned long, unsigned long, unsigned long,
|
||||
unsigned char, const char *) hidden;
|
||||
char *__fmt_dtoa(double, int, int, int *, int *, char **) hidden;
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/reverse.internal.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
|
@ -25,12 +26,11 @@
|
|||
|
||||
uintmax_t __udivmodti4(uintmax_t, uintmax_t, uintmax_t *);
|
||||
|
||||
static int __fmt_ntoa_format(int out(long, void *), void *arg, char *buf,
|
||||
unsigned len, bool negative, unsigned log2base,
|
||||
unsigned prec, unsigned width,
|
||||
static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
|
||||
char *buf, unsigned len, bool negative,
|
||||
unsigned log2base, unsigned prec, unsigned width,
|
||||
unsigned char flags) {
|
||||
unsigned i, idx;
|
||||
idx = 0;
|
||||
unsigned i;
|
||||
|
||||
/* pad leading zeros */
|
||||
if (!(flags & FLAGS_LEFT)) {
|
||||
|
@ -82,24 +82,21 @@ static int __fmt_ntoa_format(int out(long, void *), void *arg, char *buf,
|
|||
}
|
||||
}
|
||||
|
||||
/* reverse string */
|
||||
for (i = 0U; i < len; i++) {
|
||||
if (out(buf[len - i - 1], arg) == -1) return -1;
|
||||
idx++;
|
||||
}
|
||||
reverse(buf, len);
|
||||
if (out(buf, arg, len) == -1) return -1;
|
||||
|
||||
/* append pad spaces up to given width */
|
||||
if (flags & FLAGS_LEFT) {
|
||||
if (idx < width) {
|
||||
if (__fmt_pad(out, arg, width - idx) == -1) return -1;
|
||||
if (len < width) {
|
||||
if (__fmt_pad(out, arg, width - len) == -1) return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __fmt_ntoa2(int out(long, void *), void *arg, uintmax_t value, bool neg,
|
||||
unsigned log2base, unsigned prec, unsigned width,
|
||||
unsigned flags, const char *alphabet) {
|
||||
int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
|
||||
uintmax_t value, bool neg, unsigned log2base, unsigned prec,
|
||||
unsigned width, unsigned flags, const char *alphabet) {
|
||||
uintmax_t remainder;
|
||||
unsigned len, count, digit;
|
||||
char buf[BUFFER_SIZE];
|
||||
|
@ -130,7 +127,7 @@ int __fmt_ntoa2(int out(long, void *), void *arg, uintmax_t value, bool neg,
|
|||
flags);
|
||||
}
|
||||
|
||||
int __fmt_ntoa(int out(long, void *), void *arg, va_list va,
|
||||
int __fmt_ntoa(int out(const char *, void *, size_t), void *arg, va_list va,
|
||||
unsigned char signbit, unsigned long log2base,
|
||||
unsigned long prec, unsigned long width, unsigned char flags,
|
||||
const char *lang) {
|
||||
|
|
|
@ -18,8 +18,9 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/fmts.h"
|
||||
|
||||
int __fmt_pad(int out(long, void *), void *arg, unsigned long n) {
|
||||
int __fmt_pad(int out(const char *, void *, size_t), void *arg,
|
||||
unsigned long n) {
|
||||
int i, rc;
|
||||
for (rc = i = 0; i < n; ++i) rc |= out(' ', arg);
|
||||
for (rc = i = 0; i < n; ++i) rc |= out(" ", arg, 1);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -16,9 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/fmt/fmts.h"
|
||||
#include "libc/fmt/internal.h"
|
||||
#include "libc/nexgen32e/bsr.h"
|
||||
#include "libc/nexgen32e/tinystrlen.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/str/thompike.h"
|
||||
|
@ -26,56 +29,50 @@
|
|||
#include "libc/str/utf16.h"
|
||||
#include "libc/unicode/unicode.h"
|
||||
|
||||
typedef int (*emit_f)(int (*)(long, void *), void *, wint_t);
|
||||
typedef int (*out_f)(const char *, void *, size_t);
|
||||
typedef int (*emit_f)(out_f, void *, uint64_t);
|
||||
|
||||
static noinstrument int __fmt_stoa_byte(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
return f(c, a);
|
||||
static int __fmt_stoa_byte(out_f out, void *a, uint64_t c) {
|
||||
char buf[1] = {c};
|
||||
return out(buf, a, 1);
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_word(int f(long, void *), void *a,
|
||||
uint64_t w) {
|
||||
do {
|
||||
if (f(w & 0xff, a) == -1) {
|
||||
return -1;
|
||||
static int __fmt_stoa_wide(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
if (!isascii(w)) w = tpenc(w);
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static int __fmt_stoa_bing(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
w = tpenc((*weaken(kCp437))[w & 0xFF]);
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static int __fmt_stoa_quoted(out_f out, void *a, uint64_t w) {
|
||||
char buf[8];
|
||||
if (w <= 0x7F) {
|
||||
if (w < 0x20 || w == 0x7F) {
|
||||
w = cescapec(w);
|
||||
}
|
||||
} while ((w >>= 8));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_wide(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
if (isascii(c)) {
|
||||
return f(c, a);
|
||||
} else {
|
||||
return __fmt_stoa_word(f, a, tpenc(c));
|
||||
w = tpenc(w);
|
||||
}
|
||||
WRITE64LE(buf, w);
|
||||
return out(buf, a, w ? (bsr(w) >> 3) + 1 : 1);
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_bing(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
return __fmt_stoa_wide(f, a, (*weaken(kCp437))[c]);
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_quoted(int f(long, void *), void *a,
|
||||
wint_t c) {
|
||||
if (isascii(c)) {
|
||||
return __fmt_stoa_word(f, a, cescapec(c));
|
||||
} else {
|
||||
return __fmt_stoa_word(f, a, tpenc(c));
|
||||
}
|
||||
}
|
||||
|
||||
static noinstrument int __fmt_stoa_quote(int out(long, void *), void *arg,
|
||||
unsigned flags, char ch,
|
||||
unsigned char signbit) {
|
||||
static int __fmt_stoa_quote(out_f out, void *arg, unsigned flags, char ch,
|
||||
unsigned char signbit) {
|
||||
if (flags & FLAGS_REPR) {
|
||||
if (signbit == 63) {
|
||||
if (out('L', arg) == -1) return -1;
|
||||
if (out("L", arg, 1) == -1) return -1;
|
||||
} else if (signbit == 15) {
|
||||
if (out('u', arg) == -1) return -1;
|
||||
if (out("u", arg, 1) == -1) return -1;
|
||||
}
|
||||
if (out(ch, arg) == -1) return -1;
|
||||
if (out(&ch, arg, 1) == -1) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -89,23 +86,25 @@ static noinstrument int __fmt_stoa_quote(int out(long, void *), void *arg,
|
|||
*
|
||||
* @see __fmt()
|
||||
*/
|
||||
int __fmt_stoa(int out(long, void *), void *arg, void *data,
|
||||
int __fmt_stoa(int out(const char *, void *, size_t), void *arg, void *data,
|
||||
unsigned long flags, unsigned long precision,
|
||||
unsigned long width, unsigned char signbit,
|
||||
unsigned char qchar) {
|
||||
char *p;
|
||||
wint_t wc;
|
||||
unsigned n;
|
||||
emit_f emit;
|
||||
char *p, buf[1];
|
||||
unsigned w, c, pad;
|
||||
bool justdobytes, ignorenul;
|
||||
|
||||
p = data;
|
||||
if (!p) {
|
||||
p = ((flags & FLAGS_REPR) ? "NULL" : "(null)");
|
||||
flags &= ~FLAGS_PRECISION;
|
||||
flags |= FLAGS_NOQUOTE;
|
||||
signbit = 0;
|
||||
flags |= FLAGS_NOQUOTE;
|
||||
if (flags & FLAGS_PRECISION) {
|
||||
precision = min(strlen(p), precision);
|
||||
}
|
||||
} else {
|
||||
if (__fmt_stoa_quote(out, arg, flags, qchar, signbit) == -1) return -1;
|
||||
}
|
||||
|
@ -215,7 +214,8 @@ int __fmt_stoa(int out(long, void *), void *arg, void *data,
|
|||
}
|
||||
|
||||
if (!(flags & FLAGS_NOQUOTE) && (flags & FLAGS_REPR)) {
|
||||
if (out(qchar, arg) == -1) return -1;
|
||||
buf[0] = qchar;
|
||||
if (out(buf, arg, 1) == -1) return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
struct SprintfStr {
|
||||
|
@ -28,10 +28,13 @@ struct SprintfStr {
|
|||
size_t n;
|
||||
};
|
||||
|
||||
static noinstrument int vsnprintfputchar(unsigned char c,
|
||||
struct SprintfStr *str) {
|
||||
if (str->i < str->n) str->p[str->i] = c;
|
||||
str->i++;
|
||||
static int vsnprintfputchar(const char *s, struct SprintfStr *t, size_t n) {
|
||||
if (t->i + n <= t->n) {
|
||||
memcpy(t->p + t->i, s, n);
|
||||
} else if (t->i < t->n) {
|
||||
memcpy(t->p + t->i, s, t->n - t->i);
|
||||
}
|
||||
t->i += n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -51,6 +54,6 @@ static noinstrument int vsnprintfputchar(unsigned char c,
|
|||
int(vsnprintf)(char *buf, size_t size, const char *fmt, va_list va) {
|
||||
struct SprintfStr str = {buf, 0, size};
|
||||
__fmt(vsnprintfputchar, &str, fmt, va);
|
||||
if (str.n) str.p[min(str.i, str.n - 1)] = '\0';
|
||||
if (str.n) str.p[MIN(str.i, str.n - 1)] = '\0';
|
||||
return str.i;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
|
@ -43,17 +46,8 @@
|
|||
bool cancolor(void) {
|
||||
static bool once;
|
||||
static bool result;
|
||||
const char *term;
|
||||
if (!once) {
|
||||
if (!result) {
|
||||
if ((term = getenv("TERM"))) {
|
||||
/* anything but emacs basically */
|
||||
result = strcmp(term, "dumb") != 0;
|
||||
} else {
|
||||
/* TODO(jart): Why does Mac bash login shell exec nuke TERM? */
|
||||
result = IsXnu();
|
||||
}
|
||||
}
|
||||
result = !!strcmp(nulltoempty(getenv("DONTANSIMEBRO")), "1");
|
||||
once = true;
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -21,9 +21,6 @@
|
|||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Checks if we're probably running inside Emacs.
|
||||
*/
|
||||
bool IsTerminalInarticulate(void) {
|
||||
return strcmp(nulltoempty(getenv("TERM")), "dumb") == 0;
|
||||
return !strcmp(nulltoempty(getenv("TERM")), "dumb");
|
||||
}
|
||||
|
|
|
@ -29,26 +29,26 @@
|
|||
* @see xasprintf() for a better API
|
||||
*/
|
||||
int(vasprintf)(char **strp, const char *fmt, va_list va) {
|
||||
int wrote;
|
||||
char *p;
|
||||
size_t size;
|
||||
va_list va2;
|
||||
va_list vb;
|
||||
int wrote, rc = -1;
|
||||
if ((*strp = malloc((size = 512)))) {
|
||||
va_copy(va2, va);
|
||||
va_copy(vb, va);
|
||||
wrote = (vsnprintf)(*strp, size, fmt, va);
|
||||
if (wrote == -1) return -1;
|
||||
if (wrote < size) {
|
||||
if ((p = realloc(*strp, wrote + 1))) *strp = p;
|
||||
return wrote;
|
||||
rc = wrote;
|
||||
} else {
|
||||
size = wrote + 1;
|
||||
if ((p = realloc(*strp, size))) {
|
||||
*strp = p;
|
||||
wrote = (vsnprintf)(*strp, size, fmt, va2);
|
||||
wrote = (vsnprintf)(*strp, size, fmt, vb);
|
||||
assert(wrote == size - 1);
|
||||
return wrote;
|
||||
rc = wrote;
|
||||
}
|
||||
}
|
||||
va_end(vb);
|
||||
}
|
||||
return -1;
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
// @param dil contains byte to escape
|
||||
// @see libc/nexgen32e/cescapec.c
|
||||
cescapec:
|
||||
.leafprologue
|
||||
.profilable
|
||||
movzbl %dil,%edi
|
||||
lea -7(%rdi),%ecx
|
||||
cmp $85,%cl
|
||||
|
@ -36,28 +38,28 @@ cescapec:
|
|||
jmp *cescapectab(,%rcx,8)
|
||||
.Lanchorpoint:
|
||||
.LBEL: mov $'a',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LBS: mov $'b',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LHT: mov $'t',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LLF: mov $'n',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LVT: mov $'v',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LFF: mov $'f',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LCR: mov $'r',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LDQ: mov $'\"',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LSQ: mov $'\'',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
.LBSL: mov $'\\',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
#ifdef __STRICT_ANSI__
|
||||
.LQM: mov $'?',%ah
|
||||
ret
|
||||
.leafepilogue
|
||||
#else
|
||||
.LQM:
|
||||
#endif
|
||||
|
@ -65,7 +67,7 @@ cescapec:
|
|||
lea -0x20(%rax),%ecx
|
||||
cmp $0x5E,%ecx
|
||||
ja 2f
|
||||
ret
|
||||
.leafepilogue
|
||||
2: and $-64,%eax
|
||||
mov %edi,%ecx
|
||||
and $56,%ecx
|
||||
|
@ -75,7 +77,7 @@ cescapec:
|
|||
or %ecx,%edi
|
||||
lea (%rdi,%rax,4),%eax
|
||||
add $'0'<<030|'0'<<020|'0'<<010|'\\',%eax
|
||||
ret
|
||||
.leafepilogue
|
||||
.endfn cescapec,globl
|
||||
|
||||
.initro 300,_init_cescapec
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern const uint32_t kCrc32cTab[256];
|
||||
|
||||
void crc32init(uint32_t[hasatleast 256], uint32_t);
|
||||
uint32_t crc32c(uint32_t, const void *, size_t);
|
||||
uint32_t crc32_z(uint32_t, const void *, size_t);
|
||||
|
|
|
@ -28,7 +28,8 @@
|
|||
// @return rax is address of last %sil in %rdi, or NULL
|
||||
// @note AVX2 requires Haswell (2014+) or Excavator (2015+)
|
||||
// @asyncsignalsafe
|
||||
memrchr:.leafprologue
|
||||
memrchr:
|
||||
.leafprologue
|
||||
.profilable
|
||||
#if !IsTiny()
|
||||
cmp $32,%rdx
|
||||
|
|
|
@ -106,44 +106,12 @@ privileged noasan void ftrace(void) {
|
|||
noreentry = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables plaintext function tracing if `--ftrace` flag is passed.
|
||||
*
|
||||
* The `--ftrace` CLI arg is removed before main() is called. This code
|
||||
* is intended for diagnostic purposes and assumes binaries are
|
||||
* trustworthy and stack isn't corrupted. Logging plain text allows
|
||||
* program structure to easily be visualized and hotspots identified w/
|
||||
* `sed | sort | uniq -c | sort`. A compressed trace can be made by
|
||||
* appending `--ftrace 2>&1 | gzip -4 >trace.gz` to the CLI arguments.
|
||||
*
|
||||
* @see libc/runtime/_init.S for documentation
|
||||
*/
|
||||
textstartup int ftrace_init(int argc, char *argv[]) {
|
||||
int i;
|
||||
bool foundflag;
|
||||
foundflag = false;
|
||||
for (i = 1; i <= argc; ++i) {
|
||||
if (!foundflag) {
|
||||
if (argv[i]) {
|
||||
if (strcmp(argv[i], "--ftrace") == 0) {
|
||||
foundflag = true;
|
||||
} else if (strcmp(argv[i], "----ftrace") == 0) {
|
||||
strcpy(argv[i], "--ftrace");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
argv[i - 1] = argv[i];
|
||||
}
|
||||
textstartup void ftrace_install(void) {
|
||||
g_buf[0] = '+';
|
||||
g_buf[1] = ' ';
|
||||
if ((g_symbols = OpenSymbolTable(FindDebugBinary()))) {
|
||||
__hook(ftrace_hook, g_symbols);
|
||||
} else {
|
||||
write(2, "error: --ftrace needs the concomitant .com.dbg binary\n", 54);
|
||||
}
|
||||
if (foundflag) {
|
||||
--argc;
|
||||
g_buf[0] = '+';
|
||||
g_buf[1] = ' ';
|
||||
if ((g_symbols = OpenSymbolTable(FindDebugBinary()))) {
|
||||
__hook(ftrace_hook, g_symbols);
|
||||
} else {
|
||||
write(2, "error: --ftrace needs the concomitant .com.dbg binary\n", 54);
|
||||
}
|
||||
}
|
||||
return argc;
|
||||
}
|
||||
|
|
56
libc/runtime/ftraceinit.c
Normal file
56
libc/runtime/ftraceinit.c
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
/**
|
||||
* Enables plaintext function tracing if `--ftrace` flag is passed.
|
||||
*
|
||||
* The `--ftrace` CLI arg is removed before main() is called. This code
|
||||
* is intended for diagnostic purposes and assumes binaries are
|
||||
* trustworthy and stack isn't corrupted. Logging plain text allows
|
||||
* program structure to easily be visualized and hotspots identified w/
|
||||
* `sed | sort | uniq -c | sort`. A compressed trace can be made by
|
||||
* appending `--ftrace 2>&1 | gzip -4 >trace.gz` to the CLI arguments.
|
||||
*
|
||||
* @see libc/runtime/_init.S for documentation
|
||||
*/
|
||||
textstartup int ftrace_init(int argc, char *argv[]) {
|
||||
int i;
|
||||
bool foundflag;
|
||||
foundflag = false;
|
||||
for (i = 1; i <= argc; ++i) {
|
||||
if (!foundflag) {
|
||||
if (argv[i]) {
|
||||
if (strcmp(argv[i], "--ftrace") == 0) {
|
||||
foundflag = true;
|
||||
} else if (strcmp(argv[i], "----ftrace") == 0) {
|
||||
strcpy(argv[i], "--ftrace");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
argv[i - 1] = argv[i];
|
||||
}
|
||||
}
|
||||
if (foundflag) {
|
||||
--argc;
|
||||
ftrace_install();
|
||||
}
|
||||
return argc;
|
||||
}
|
|
@ -88,6 +88,7 @@ void _weakfree(void *);
|
|||
void free_s(void *) paramsnonnull() libcesque;
|
||||
int close_s(int *) paramsnonnull() libcesque;
|
||||
int OpenExecutable(void);
|
||||
void ftrace_install(void);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
|
@ -28,30 +29,6 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
static ssize_t WritevAll(int fd, struct iovec *iov, int iovlen) {
|
||||
ssize_t rc;
|
||||
size_t wrote;
|
||||
do {
|
||||
if ((rc = writev(fd, iov, iovlen)) != -1) {
|
||||
wrote = rc;
|
||||
do {
|
||||
if (wrote >= iov->iov_len) {
|
||||
wrote -= iov->iov_len;
|
||||
++iov;
|
||||
--iovlen;
|
||||
} else {
|
||||
iov->iov_base = (char *)iov->iov_base + wrote;
|
||||
iov->iov_len -= wrote;
|
||||
wrote = 0;
|
||||
}
|
||||
} while (wrote);
|
||||
} else if (errno != EINTR) {
|
||||
return -1;
|
||||
}
|
||||
} while (iovlen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes data to stream.
|
||||
*
|
||||
|
@ -102,7 +79,7 @@ size_t fwrite(const void *data, size_t stride, size_t count, FILE *f) {
|
|||
iov[1].iov_base = data;
|
||||
iov[1].iov_len = n;
|
||||
n += f->beg;
|
||||
if (WritevAll(f->fd, iov, 2) == -1) {
|
||||
if (WritevUninterruptible(f->fd, iov, 2) == -1) {
|
||||
f->state = errno;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
|
@ -26,9 +27,17 @@ struct state {
|
|||
int n;
|
||||
};
|
||||
|
||||
static noinstrument int vfprintfputchar(int c, struct state *st) {
|
||||
st->n++;
|
||||
return fputc(c, st->f);
|
||||
static int vfprintfputchar(const char *s, struct state *t, size_t n) {
|
||||
if (n) {
|
||||
if (n == 1 && *s != '\n' && t->f->beg < t->f->size &&
|
||||
t->f->bufmode != _IONBF) {
|
||||
t->f->buf[t->f->beg++] = *s;
|
||||
} else if (!fwrite(s, 1, n, t->f)) {
|
||||
return -1;
|
||||
}
|
||||
t->n += n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int(vfprintf)(FILE *f, const char *fmt, va_list va) {
|
||||
|
|
|
@ -1,79 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
|
||||
extern const uint32_t kCrc32cTab[256];
|
||||
|
||||
/**
|
||||
* Computes Castagnoli CRC-32 on old computers.
|
||||
*/
|
||||
uint32_t crc32c_pure(uint32_t init, const void *data, size_t size) {
|
||||
const unsigned char *p = data;
|
||||
uint32_t h = init ^ 0xffffffff;
|
||||
unsigned i;
|
||||
for (i = 0; i < size; i++) {
|
||||
h = h >> 8 ^ kCrc32cTab[(h & 0xff) ^ p[i]];
|
||||
}
|
||||
return h ^ 0xffffffff;
|
||||
}
|
||||
|
||||
/*
|
||||
bench_crc32c_pure for #c per n where c ≈ 0.293ns
|
||||
N x1 x8 x64 mBps
|
||||
------------------------------------------------------------
|
||||
1 4305.000 91.375 44.203 74
|
||||
1 75.000 55.875 44.703 73
|
||||
2 46.500 35.188 24.617 132
|
||||
3 40.333 26.625 19.193 169
|
||||
4 32.250 19.969 16.215 200
|
||||
7 18.429 15.089 12.033 270
|
||||
8 20.625 13.547 11.607 280
|
||||
15 15.667 10.775 9.589 339
|
||||
16 17.562 10.695 9.419 345
|
||||
31 12.226 8.891 8.317 391
|
||||
32 13.219 8.480 8.078 402
|
||||
63 9.571 8.065 7.731 420
|
||||
64 9.672 7.955 7.633 426
|
||||
127 8.433 7.548 7.329 443
|
||||
128 8.492 7.528 7.352 442
|
||||
255 7.557 7.366 7.239 449
|
||||
256 7.699 7.342 7.305 445
|
||||
511 7.376 7.243 7.223 450
|
||||
512 7.408 7.233 7.225 450
|
||||
1023 7.188 7.192 7.098 458
|
||||
1024 7.171 7.194 7.097 458
|
||||
2047 7.130 7.172 7.085 459
|
||||
2048 7.117 7.170 7.169 453
|
||||
4095 7.063 7.076 7.085 459
|
||||
4096 7.078 7.161 7.081 459
|
||||
8191 7.041 7.095 7.055 461
|
||||
8192 7.051 7.098 7.087 459
|
||||
16383 7.039 7.114 7.067 460
|
||||
16384 6.876 6.931 7.133 456
|
||||
32767 7.055 7.108 7.290 446
|
||||
32768 6.868 6.887 6.974 466
|
||||
65535 6.984 6.885 6.967 467
|
||||
65536 6.877 6.924 10.994 296
|
||||
131071 7.166 7.141 7.011 464
|
||||
131072 6.853 6.971 7.694 422
|
||||
262143 6.853 7.213 7.406 439
|
||||
262144 6.852 6.968 7.290 446
|
||||
524287 7.398 7.389 7.166 454
|
||||
524288 6.851 7.094 7.159 454
|
||||
*/
|
|
@ -1,95 +0,0 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/str/internal.h"
|
||||
|
||||
/**
|
||||
* Hashes data with hardware acceleration at 10GBps.
|
||||
* @note needs Nehalem+ c. 2008 or Bulldozer+ c. 2011
|
||||
*/
|
||||
optimizespeed uint32_t crc32c_sse42(uint32_t init, const void *data, size_t n) {
|
||||
const unsigned char *p = (const unsigned char *)data;
|
||||
const unsigned char *pe = (const unsigned char *)data + n;
|
||||
uint32_t h = init ^ 0xffffffff;
|
||||
if (n >= 16 + 8) {
|
||||
while ((uintptr_t)p & 7) asm("crc32b\t%1,%0" : "+r"(h) : "rm"(*p++));
|
||||
uint64_t hl = h;
|
||||
while (p < pe - 16ul) {
|
||||
asm("crc32q\t%1,%0" : "+r"(hl) : "rm"(*(const uint64_t *)p));
|
||||
p += 8;
|
||||
asm("crc32q\t%1,%0" : "+r"(hl) : "rm"(*(const uint64_t *)p));
|
||||
p += 8;
|
||||
}
|
||||
h = (uint32_t)hl;
|
||||
}
|
||||
while (p < pe) asm("crc32b\t%1,%0" : "+r"(h) : "rm"(*p++));
|
||||
return h ^ 0xffffffff;
|
||||
}
|
||||
|
||||
/*
|
||||
bench_crc32c_sse42 for #c per n where c ≈ 0.293ns
|
||||
N x1 x8 x64 mBps
|
||||
------------------------------------------------------------
|
||||
1 877.000 43.375 40.359 81
|
||||
1 45.000 39.625 40.484 80
|
||||
2 34.500 27.562 20.461 159
|
||||
3 23.000 16.708 14.245 228
|
||||
4 18.250 13.094 11.449 284
|
||||
7 10.429 8.339 8.185 397
|
||||
8 42.125 8.734 6.850 475
|
||||
15 9.400 5.375 4.884 665
|
||||
16 7.312 5.070 4.882 666
|
||||
31 5.258 2.923 2.680 1213
|
||||
32 3.969 2.676 2.562 1269
|
||||
63 3.095 1.581 1.428 2276
|
||||
64 2.234 1.623 1.478 2199
|
||||
127 1.205 0.901 0.900 3610
|
||||
128 1.164 0.960 0.915 3552
|
||||
255 0.922 0.651 0.618 5260
|
||||
256 0.715 0.650 0.609 5341
|
||||
511 0.558 0.482 0.477 6819
|
||||
512 0.529 0.475 0.469 6932
|
||||
1023 0.425 0.400 0.396 8204
|
||||
1024 0.417 0.392 0.388 8383
|
||||
2047 0.367 0.355 0.353 9199
|
||||
2048 0.374 0.366 0.364 8929
|
||||
4095 0.351 0.338 0.337 9644
|
||||
4096 0.353 0.338 0.338 9624
|
||||
8191 0.335 0.338 0.337 9641
|
||||
8192 0.335 0.329 0.329 9870
|
||||
16383 0.336 0.325 0.325 10011
|
||||
16384 0.336 0.326 0.375 8666
|
||||
32767 0.329 0.323 0.323 10070
|
||||
32768 0.327 0.324 0.323 10062
|
||||
65535 0.322 0.322 0.322 10103
|
||||
65536 0.321 0.322 0.322 10102
|
||||
131071 0.322 0.321 0.321 10125
|
||||
131072 0.321 0.321 0.321 10124
|
||||
262143 0.322 0.321 0.335 9699
|
||||
262144 0.321 0.321 0.321 10134
|
||||
524287 0.321 0.321 0.499 6516
|
||||
524288 0.321 0.321 0.339 9575
|
||||
1048575 0.322 0.321 0.322 10095
|
||||
1048576 0.320 1.001 0.323 10048
|
||||
2097151 0.325 0.321 0.322 10086
|
||||
2097152 0.330 0.320 0.323 10076
|
||||
4194303 0.331 0.322 0.321 10128
|
||||
4194304 0.332 0.321 0.325 10004
|
||||
8388607 0.334 0.332 0.331 9829
|
||||
8388608 0.334 0.329 0.327 9934
|
||||
*/
|
|
@ -22,16 +22,29 @@
|
|||
/**
|
||||
* Computes 32-bit Castagnoli Cyclic Redundancy Check.
|
||||
*
|
||||
* @param h is the initial hash value (0 is fine)
|
||||
* @param p points to the data
|
||||
* @param n is the byte size of data
|
||||
* @param init is the initial hash value
|
||||
* @param data points to the data
|
||||
* @param size is the byte size of data
|
||||
* @return eax is the new hash value
|
||||
* @note Used by ISCSI, TensorFlow, etc.
|
||||
*/
|
||||
uint32_t crc32c(uint32_t h, const void *p, size_t n) {
|
||||
uint32_t crc32c(uint32_t init, const void *data, size_t size) {
|
||||
uint64_t h;
|
||||
const unsigned char *p, *pe;
|
||||
p = data;
|
||||
pe = p + size;
|
||||
h = init ^ 0xffffffff;
|
||||
if (X86_HAVE(SSE4_2)) {
|
||||
return crc32c_sse42(h, p, n);
|
||||
for (; p + 8 <= pe; p += 8) {
|
||||
asm("crc32q\t%1,%0" : "+r"(h) : "rm"(*(const uint64_t *)p));
|
||||
}
|
||||
while (p < pe) {
|
||||
asm("crc32b\t%1,%0" : "+r"(h) : "rm"(*p++));
|
||||
}
|
||||
} else {
|
||||
return crc32c_pure(h, p, n);
|
||||
while (p < pe) {
|
||||
h = h >> 8 ^ kCrc32cTab[(h & 0xff) ^ *p++];
|
||||
}
|
||||
}
|
||||
return h ^ 0xffffffff;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "libc/intrin/pmovmskb.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
static noasan size_t stpcpy_sse2(char *d, const char *s, size_t i) {
|
||||
static inline noasan size_t stpcpy_sse2(char *d, const char *s, size_t i) {
|
||||
uint8_t v1[16], v2[16], vz[16];
|
||||
for (;;) {
|
||||
memset(vz, 0, 16);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue