mirror of https://mirror.osredm.com/root/redis.git
Using fast_float library for faster parsing of 64 decimal strings. (#11884)
Fixes #8825 We're using the fast_float library[1] in our (compiled-in) floating-point fast_float_strtod implementation for faster and more portable parsing of 64 decimal strings. The single file fast_float.h is an amalgamation of the entire library, which can be (re)generated with the amalgamate.py script (from the fast_float repository) via the command: ``` python3 ./script/amalgamate.py --license=MIT > $REDIS_SRC/deps/fast_float/fast_float.h ``` [1]: https://github.com/fastfloat/fast_float The used commit from fast_float library was the one from https://github.com/fastfloat/fast_float/releases/tag/v3.10.1 --------- Co-authored-by: fcostaoliveira <filipe@redis.com>
This commit is contained in:
parent
9146ac050b
commit
af7fca797a
|
@ -62,7 +62,7 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
- name: make
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install libc6-dev-i386
|
||||
sudo apt-get update && sudo apt-get install libc6-dev-i386 gcc-multilib g++-multilib
|
||||
make REDIS_CFLAGS='-Werror' 32bit
|
||||
|
||||
build-libc-malloc:
|
||||
|
@ -79,7 +79,7 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
- name: make
|
||||
run: |
|
||||
dnf -y install which gcc make
|
||||
dnf -y install which gcc gcc-c++ make
|
||||
make REDIS_CFLAGS='-Werror'
|
||||
|
||||
build-old-chain-jemalloc:
|
||||
|
@ -96,6 +96,7 @@ jobs:
|
|||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5
|
||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
|
||||
apt-get update
|
||||
apt-get install -y make gcc-4.8
|
||||
apt-get install -y make gcc-4.8 g++-4.8
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 100
|
||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 100
|
||||
make CC=gcc REDIS_CFLAGS='-Werror'
|
||||
|
|
|
@ -94,8 +94,9 @@ jobs:
|
|||
ref: ${{ env.GITHUB_HEAD_REF }}
|
||||
- name: make
|
||||
run: |
|
||||
apt-get update && apt-get install -y make gcc-13
|
||||
apt-get update && apt-get install -y make gcc-13 g++-13
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 100
|
||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 100
|
||||
make CC=gcc REDIS_CFLAGS='-Werror -DREDIS_TEST -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3'
|
||||
- name: testprep
|
||||
run: apt-get install -y tcl8.6 tclx procps
|
||||
|
@ -211,7 +212,7 @@ jobs:
|
|||
ref: ${{ env.GITHUB_HEAD_REF }}
|
||||
- name: make
|
||||
run: |
|
||||
sudo apt-get update && sudo apt-get install libc6-dev-i386
|
||||
sudo apt-get update && sudo apt-get install libc6-dev-i386 g++ gcc-multilib g++-multilib
|
||||
make 32bit REDIS_CFLAGS='-Werror -DREDIS_TEST'
|
||||
- name: testprep
|
||||
run: sudo apt-get install tcl8.6 tclx
|
||||
|
@ -456,7 +457,7 @@ jobs:
|
|||
- name: testprep
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install tcl8.6 tclx valgrind -y
|
||||
sudo apt-get install tcl8.6 tclx valgrind g++ -y
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'redis')
|
||||
run: ./runtest --valgrind --no-latency --verbose --clients 1 --timeout 2400 --dump-logs ${{github.event.inputs.test_args}}
|
||||
|
@ -521,7 +522,7 @@ jobs:
|
|||
- name: testprep
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install tcl8.6 tclx valgrind -y
|
||||
sudo apt-get install tcl8.6 tclx valgrind g++ -y
|
||||
- name: test
|
||||
if: true && !contains(github.event.inputs.skiptests, 'redis')
|
||||
run: ./runtest --valgrind --no-latency --verbose --clients 1 --timeout 2400 --dump-logs ${{github.event.inputs.test_args}}
|
||||
|
@ -678,7 +679,7 @@ jobs:
|
|||
ref: ${{ env.GITHUB_HEAD_REF }}
|
||||
- name: make
|
||||
run: |
|
||||
dnf -y install which gcc make
|
||||
dnf -y install which gcc make g++
|
||||
make REDIS_CFLAGS='-Werror'
|
||||
- name: testprep
|
||||
run: |
|
||||
|
@ -720,7 +721,7 @@ jobs:
|
|||
ref: ${{ env.GITHUB_HEAD_REF }}
|
||||
- name: make
|
||||
run: |
|
||||
dnf -y install which gcc make openssl-devel openssl
|
||||
dnf -y install which gcc make openssl-devel openssl g++
|
||||
make BUILD_TLS=module REDIS_CFLAGS='-Werror'
|
||||
- name: testprep
|
||||
run: |
|
||||
|
@ -767,7 +768,7 @@ jobs:
|
|||
ref: ${{ env.GITHUB_HEAD_REF }}
|
||||
- name: make
|
||||
run: |
|
||||
dnf -y install which gcc make openssl-devel openssl
|
||||
dnf -y install which gcc make openssl-devel openssl g++
|
||||
make BUILD_TLS=module REDIS_CFLAGS='-Werror'
|
||||
- name: testprep
|
||||
run: |
|
||||
|
@ -907,6 +908,9 @@ jobs:
|
|||
(github.event_name == 'workflow_dispatch' || (github.event_name != 'workflow_dispatch' && github.repository == 'redis/redis')) &&
|
||||
!contains(github.event.inputs.skipjobs, 'freebsd')
|
||||
timeout-minutes: 14400
|
||||
env:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
steps:
|
||||
- name: prep
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
|
@ -925,7 +929,7 @@ jobs:
|
|||
version: 13.2
|
||||
shell: bash
|
||||
run: |
|
||||
sudo pkg install -y bash gmake lang/tcl86 lang/tclx
|
||||
sudo pkg install -y bash gmake lang/tcl86 lang/tclx gcc
|
||||
gmake
|
||||
./runtest --single unit/keyspace --single unit/auth --single unit/networking --single unit/protocol
|
||||
|
||||
|
@ -1080,8 +1084,9 @@ jobs:
|
|||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5
|
||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
|
||||
apt-get update
|
||||
apt-get install -y make gcc-4.8
|
||||
apt-get install -y make gcc-4.8 g++-4.8
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 100
|
||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 100
|
||||
make CC=gcc REDIS_CFLAGS='-Werror'
|
||||
- name: testprep
|
||||
run: apt-get install -y tcl tcltls tclx
|
||||
|
@ -1128,9 +1133,10 @@ jobs:
|
|||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5
|
||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
|
||||
apt-get update
|
||||
apt-get install -y make gcc-4.8 openssl libssl-dev
|
||||
apt-get install -y make gcc-4.8 g++-4.8 openssl libssl-dev
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 100
|
||||
make CC=gcc BUILD_TLS=module REDIS_CFLAGS='-Werror'
|
||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 100
|
||||
make CC=gcc CXX=g++ BUILD_TLS=module REDIS_CFLAGS='-Werror'
|
||||
- name: testprep
|
||||
run: |
|
||||
apt-get install -y tcl tcltls tclx
|
||||
|
@ -1182,8 +1188,9 @@ jobs:
|
|||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5
|
||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
|
||||
apt-get update
|
||||
apt-get install -y make gcc-4.8 openssl libssl-dev
|
||||
apt-get install -y make gcc-4.8 g++-4.8 openssl libssl-dev
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 100
|
||||
update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 100
|
||||
make BUILD_TLS=module CC=gcc REDIS_CFLAGS='-Werror'
|
||||
- name: testprep
|
||||
run: |
|
||||
|
|
|
@ -30,6 +30,7 @@ deps/lua/src/luac
|
|||
deps/lua/src/liblua.a
|
||||
deps/hdr_histogram/libhdrhistogram.a
|
||||
deps/fpconv/libfpconv.a
|
||||
deps/fast_float/libfast_float.a
|
||||
tests/tls/*
|
||||
.make-*
|
||||
.prerequisites
|
||||
|
|
|
@ -42,6 +42,7 @@ distclean:
|
|||
-(cd jemalloc && [ -f Makefile ] && $(MAKE) distclean) > /dev/null || true
|
||||
-(cd hdr_histogram && $(MAKE) clean) > /dev/null || true
|
||||
-(cd fpconv && $(MAKE) clean) > /dev/null || true
|
||||
-(cd fast_float && $(MAKE) clean) > /dev/null || true
|
||||
-(rm -f .make-*)
|
||||
|
||||
.PHONY: distclean
|
||||
|
@ -74,6 +75,12 @@ fpconv: .make-prerequisites
|
|||
|
||||
.PHONY: fpconv
|
||||
|
||||
fast_float: .make-prerequisites
|
||||
@printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR)
|
||||
cd fast_float && $(MAKE) libfast_float
|
||||
|
||||
.PHONY: fast_float
|
||||
|
||||
ifeq ($(uname_S),SunOS)
|
||||
# Make isinf() available
|
||||
LUA_CFLAGS= -D__C99FEATURES__=1
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
# Fallback to gcc/g++ when $CC or $CXX is not in $PATH.
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
|
||||
CFLAGS=-Wall -O3
|
||||
# This avoids loosing the fastfloat specific compile flags when we override the CFLAGS via the main project
|
||||
FASTFLOAT_CFLAGS=-std=c++11 -DFASTFLOAT_ALLOWS_LEADING_PLUS
|
||||
LDFLAGS=
|
||||
|
||||
libfast_float: fast_float_strtod.o
|
||||
$(AR) -r libfast_float.a fast_float_strtod.o
|
||||
|
||||
32bit: CFLAGS += -m32
|
||||
32bit: LDFLAGS += -m32
|
||||
32bit: libfast_float
|
||||
|
||||
fast_float_strtod.o: fast_float_strtod.cpp
|
||||
$(CXX) $(CFLAGS) $(FASTFLOAT_CFLAGS) -c fast_float_strtod.cpp $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f *.a
|
||||
rm -f *.h.gch
|
||||
rm -rf *.dSYM
|
|
@ -0,0 +1,21 @@
|
|||
README for fast_float v6.1.4
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
We're using the fast_float library[1] in our (compiled-in)
|
||||
floating-point fast_float_strtod implementation for faster and more
|
||||
portable parsing of 64 decimal strings.
|
||||
|
||||
The single file fast_float.h is an amalgamation of the entire library,
|
||||
which can be (re)generated with the amalgamate.py script (from the
|
||||
fast_float repository) via the command
|
||||
|
||||
```
|
||||
git clone https://github.com/fastfloat/fast_float
|
||||
cd fast_float
|
||||
git checkout v6.1.4
|
||||
python3 ./script/amalgamate.py --license=MIT \
|
||||
> $REDIS_SRC/deps/fast_float/fast_float.h
|
||||
```
|
||||
|
||||
[1]: https://github.com/fastfloat/fast_float
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,32 @@
|
|||
#include "fast_float.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <cerrno>
|
||||
|
||||
/* Convert NPTR to a double using the fast_float library.
|
||||
*
|
||||
* This function behaves similarly to the standard strtod function, converting
|
||||
* the initial portion of the string pointed to by `nptr` to a `double` value,
|
||||
* using the fast_float library for high performance. If the conversion fails,
|
||||
* errno is set to EINVAL error code.
|
||||
*
|
||||
* @param nptr A pointer to the null-terminated byte string to be interpreted.
|
||||
* @param endptr A pointer to a pointer to character. If `endptr` is not NULL,
|
||||
* it will point to the character after the last character used
|
||||
* in the conversion.
|
||||
* @return The converted value as a double. If no valid conversion could
|
||||
* be performed, returns 0.0.
|
||||
* If ENDPTR is not NULL, a pointer to the character after the last one used
|
||||
* in the number is put in *ENDPTR. */
|
||||
extern "C" double fast_float_strtod(const char *nptr, char **endptr) {
|
||||
double result = 0.0;
|
||||
auto answer = fast_float::from_chars(nptr, nptr + strlen(nptr), result);
|
||||
if (answer.ec != std::errc()) {
|
||||
errno = EINVAL; // Fallback to for other errors
|
||||
}
|
||||
if (endptr != NULL) {
|
||||
*endptr = (char *)answer.ptr;
|
||||
}
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
#ifndef __FAST_FLOAT_STRTOD_H__
|
||||
#define __FAST_FLOAT_STRTOD_H__
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
double fast_float_strtod(const char *in, char **out);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __FAST_FLOAT_STRTOD_H__ */
|
|
@ -34,7 +34,7 @@ endif
|
|||
ifneq ($(OPTIMIZATION),-O0)
|
||||
OPTIMIZATION+=-fno-omit-frame-pointer
|
||||
endif
|
||||
DEPENDENCY_TARGETS=hiredis linenoise lua hdr_histogram fpconv
|
||||
DEPENDENCY_TARGETS=hiredis linenoise lua hdr_histogram fpconv fast_float
|
||||
NODEPS:=clean distclean
|
||||
|
||||
# Default settings
|
||||
|
@ -127,7 +127,7 @@ endif
|
|||
|
||||
FINAL_CFLAGS=$(STD) $(WARN) $(OPT) $(DEBUG) $(CFLAGS) $(REDIS_CFLAGS)
|
||||
FINAL_LDFLAGS=$(LDFLAGS) $(OPT) $(REDIS_LDFLAGS) $(DEBUG)
|
||||
FINAL_LIBS=-lm
|
||||
FINAL_LIBS=-lm -lstdc++
|
||||
DEBUG=-g -ggdb
|
||||
|
||||
# Linux ARM32 needs -latomic at linking time
|
||||
|
@ -235,7 +235,7 @@ ifdef OPENSSL_PREFIX
|
|||
endif
|
||||
|
||||
# Include paths to dependencies
|
||||
FINAL_CFLAGS+= -I../deps/hiredis -I../deps/linenoise -I../deps/lua/src -I../deps/hdr_histogram -I../deps/fpconv
|
||||
FINAL_CFLAGS+= -I../deps/hiredis -I../deps/linenoise -I../deps/lua/src -I../deps/hdr_histogram -I../deps/fpconv -I../deps/fast_float
|
||||
|
||||
# Determine systemd support and/or build preference (defaulting to auto-detection)
|
||||
BUILD_WITH_SYSTEMD=no
|
||||
|
@ -409,7 +409,7 @@ endif
|
|||
|
||||
# redis-server
|
||||
$(REDIS_SERVER_NAME): $(REDIS_SERVER_OBJ)
|
||||
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/lua/src/liblua.a ../deps/hdr_histogram/libhdrhistogram.a ../deps/fpconv/libfpconv.a $(FINAL_LIBS)
|
||||
$(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/lua/src/liblua.a ../deps/hdr_histogram/libhdrhistogram.a ../deps/fpconv/libfpconv.a ../deps/fast_float/libfast_float.a $(FINAL_LIBS)
|
||||
|
||||
# redis-sentinel
|
||||
$(REDIS_SENTINEL_NAME): $(REDIS_SERVER_NAME)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "bio.h"
|
||||
#include "quicklist.h"
|
||||
#include "fpconv_dtoa.h"
|
||||
#include "fast_float_strtod.h"
|
||||
#include "cluster.h"
|
||||
#include "threads_mngr.h"
|
||||
#include "script.h"
|
||||
|
@ -833,7 +834,7 @@ NULL
|
|||
addReplyError(c,"Wrong protocol type name. Please use one of the following: string|integer|double|bignum|null|array|set|map|attrib|push|verbatim|true|false");
|
||||
}
|
||||
} else if (!strcasecmp(c->argv[1]->ptr,"sleep") && c->argc == 3) {
|
||||
double dtime = strtod(c->argv[2]->ptr,NULL);
|
||||
double dtime = fast_float_strtod(c->argv[2]->ptr,NULL);
|
||||
long long utime = dtime*1000000;
|
||||
struct timespec tv;
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
* ----------------------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "fast_float_strtod.h"
|
||||
#include "resp_parser.h"
|
||||
#include "server.h"
|
||||
|
||||
|
@ -132,7 +133,7 @@ static int parseDouble(ReplyParser *parser, void *p_ctx) {
|
|||
if (len <= MAX_LONG_DOUBLE_CHARS) {
|
||||
memcpy(buf,proto+1,len);
|
||||
buf[len] = '\0';
|
||||
d = strtod(buf,NULL); /* We expect a valid representation. */
|
||||
d = fast_float_strtod(buf,NULL); /* We expect a valid representation. */
|
||||
} else {
|
||||
d = 0;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* (RSALv2) or the Server Side Public License v1 (SSPLv1).
|
||||
*/
|
||||
|
||||
|
||||
#include "fast_float_strtod.h"
|
||||
#include "server.h"
|
||||
#include "pqsort.h" /* Partial qsort for SORT+LIMIT */
|
||||
#include <math.h> /* isnan() */
|
||||
|
@ -472,7 +472,7 @@ void sortCommandGeneric(client *c, int readonly) {
|
|||
if (sdsEncodedObject(byval)) {
|
||||
char *eptr;
|
||||
|
||||
vector[j].u.score = strtod(byval->ptr,&eptr);
|
||||
vector[j].u.score = fast_float_strtod(byval->ptr,&eptr);
|
||||
if (eptr[0] != '\0' || errno == ERANGE ||
|
||||
isnan(vector[j].u.score))
|
||||
{
|
||||
|
|
12
src/t_zset.c
12
src/t_zset.c
|
@ -55,7 +55,7 @@
|
|||
* c) there is a back pointer, so it's a doubly linked list with the back
|
||||
* pointers being only at "level 1". This allows to traverse the list
|
||||
* from tail to head, useful for ZREVRANGE. */
|
||||
|
||||
#include "fast_float_strtod.h"
|
||||
#include "server.h"
|
||||
#include "intset.h" /* Compact integer set structure */
|
||||
#include <math.h>
|
||||
|
@ -566,11 +566,11 @@ static int zslParseRange(robj *min, robj *max, zrangespec *spec) {
|
|||
spec->min = (long)min->ptr;
|
||||
} else {
|
||||
if (((char*)min->ptr)[0] == '(') {
|
||||
spec->min = strtod((char*)min->ptr+1,&eptr);
|
||||
spec->min = fast_float_strtod((char*)min->ptr+1,&eptr);
|
||||
if (eptr[0] != '\0' || isnan(spec->min)) return C_ERR;
|
||||
spec->minex = 1;
|
||||
} else {
|
||||
spec->min = strtod((char*)min->ptr,&eptr);
|
||||
spec->min = fast_float_strtod((char*)min->ptr,&eptr);
|
||||
if (eptr[0] != '\0' || isnan(spec->min)) return C_ERR;
|
||||
}
|
||||
}
|
||||
|
@ -578,11 +578,11 @@ static int zslParseRange(robj *min, robj *max, zrangespec *spec) {
|
|||
spec->max = (long)max->ptr;
|
||||
} else {
|
||||
if (((char*)max->ptr)[0] == '(') {
|
||||
spec->max = strtod((char*)max->ptr+1,&eptr);
|
||||
spec->max = fast_float_strtod((char*)max->ptr+1,&eptr);
|
||||
if (eptr[0] != '\0' || isnan(spec->max)) return C_ERR;
|
||||
spec->maxex = 1;
|
||||
} else {
|
||||
spec->max = strtod((char*)max->ptr,&eptr);
|
||||
spec->max = fast_float_strtod((char*)max->ptr,&eptr);
|
||||
if (eptr[0] != '\0' || isnan(spec->max)) return C_ERR;
|
||||
}
|
||||
}
|
||||
|
@ -789,7 +789,7 @@ double zzlStrtod(unsigned char *vstr, unsigned int vlen) {
|
|||
vlen = sizeof(buf) - 1;
|
||||
memcpy(buf,vstr,vlen);
|
||||
buf[vlen] = '\0';
|
||||
return strtod(buf,NULL);
|
||||
return fast_float_strtod(buf,NULL);
|
||||
}
|
||||
|
||||
double zzlGetScore(unsigned char *sptr) {
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "fmacros.h"
|
||||
#include "fpconv_dtoa.h"
|
||||
#include "fast_float_strtod.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -612,7 +613,7 @@ int string2ld(const char *s, size_t slen, long double *dp) {
|
|||
int string2d(const char *s, size_t slen, double *dp) {
|
||||
errno = 0;
|
||||
char *eptr;
|
||||
*dp = strtod(s, &eptr);
|
||||
*dp = fast_float_strtod(s, &eptr);
|
||||
if (slen == 0 ||
|
||||
isspace(((const char*)s)[0]) ||
|
||||
(size_t)(eptr-(char*)s) != slen ||
|
||||
|
|
Loading…
Reference in New Issue