Compare commits

..

88 Commits

Author SHA1 Message Date
Daniel Lemire 450cb7b0f8 Merge branch 'dlemire/nopadding' of github.com:simdjson/simdjson into dlemire/nopadding 2021-07-23 23:40:41 -04:00
Daniel Lemire 2907912b1d Guarding the peek/advance. 2021-07-23 23:40:26 -04:00
Daniel Lemire b6aff44c42 Syncing the singleheader files. 2021-07-23 23:12:03 -04:00
Daniel Lemire ce11f41840 Merge branch 'dlemire/nopadding' of github.com:simdjson/simdjson into dlemire/nopadding 2021-07-23 23:06:32 -04:00
Daniel Lemire 7c8bc650a7 Turning on developer mode explicitly throughout. 2021-07-23 23:06:08 -04:00
Daniel Lemire 657489e387 More fixes. 2021-07-23 22:27:46 -04:00
Daniel Lemire 60b6a16edc Let us stress the memory overflow in more tests. 2021-07-23 21:56:29 -04:00
Daniel Lemire 2ceca3e510 More tweaking to fix problems exposed by the fuzzers. 2021-07-23 21:36:40 -04:00
Daniel Lemire d8b6a8c9d3 Merge branch 'dlemire/nopadding' of github.com:simdjson/simdjson into dlemire/nopadding 2021-07-23 20:35:20 -04:00
Daniel Lemire bbc9bd059a Some tweaking. 2021-07-23 20:35:12 -04:00
Daniel Lemire 68df233b4b Removing a couple of tests from circle ci. 2021-07-23 18:07:43 -04:00
Daniel Lemire dc66d6133a Fixing comment. 2021-07-23 17:48:21 -04:00
Daniel Lemire 13055a4601 Using an alternative instrinsic. 2021-07-23 17:47:05 -04:00
Daniel Lemire a7ff410532 Various fixes for the number parsing in the DOM front-end. Basically, we had
a mess whereas a SWAR optimization processing 8 digits would sometimes be called,
despite the fact that it would be unsafe and/or it would not be called, and we would
end up leaving performance on the floor.
2021-07-23 17:39:09 -04:00
Daniel Lemire d72cba29be Minor tweaks. 2021-07-23 16:25:08 -04:00
Daniel Lemire 757db1b2f0 Removing padding from DOM API. 2021-07-23 15:18:49 -04:00
Daniel Lemire 7175731e09 Removing the special-case 2021-07-23 14:07:32 -04:00
Daniel Lemire f6fc786b05 Disabling some change made to the DOM kernel which was evidently made to allow padding-less parsing. 2021-07-23 14:01:10 -04:00
Daniel Lemire 8ce1e52e4f Merge branch 'master' into dlemire/nopadding 2021-07-23 11:43:39 -04:00
Daniel Lemire b12014f9e4 Let us try some setups in debug mode (for faster builds). 2021-07-23 11:20:51 -04:00
Daniel Lemire 1a433fc5b4 Enabling a broad range of tests. 2021-07-23 10:51:43 -04:00
Daniel Lemire 21845f1f6a Documenting iterate_many + removing remnants of padding in On Demand. 2021-07-23 10:37:08 -04:00
Daniel Lemire dc86daa4ec Removing the padding. 2021-07-22 17:32:06 -04:00
Daniel Lemire 910686ffa8 Merge branch 'dlemire/nopadding' of github.com:simdjson/simdjson into dlemire/nopadding 2021-07-22 15:41:01 -04:00
Daniel Lemire b1a3943a8b We should now be able to iterate over a string_view. 2021-07-22 15:40:45 -04:00
Daniel Lemire 70a0d62f51 Merge branch 'dlemire/backport_jkeiser_fix_for_issue1632' into dlemire/nopadding 2021-07-22 15:27:41 -04:00
Daniel Lemire bb0ed22ab8 Removing some of the padding in the tests. 2021-07-22 15:26:41 -04:00
Daniel Lemire d7770e9a6b Disabling 'json[N-1]' test. 2021-07-22 14:24:39 -04:00
Daniel Lemire 0e8b68683d Merge branch 'dlemire/backport_jkeiser_fix_for_issue1632' into dlemire/nopadding 2021-07-22 14:03:23 -04:00
Daniel Lemire 1fe50cb777 Trimming. 2021-07-22 14:02:30 -04:00
Daniel Lemire f2d419dda6 Basic guarding. 2021-07-22 13:42:49 -04:00
Daniel Lemire 57ca29e151 Merge branch 'dlemire/backport_jkeiser_fix_for_issue1632' into dlemire/nopadding 2021-07-22 13:23:08 -04:00
Daniel Lemire 24068a089e Merge branch 'master' into dlemire/backport_jkeiser_fix_for_issue1632 2021-07-22 12:56:18 -04:00
Daniel Lemire e4bba2df9d Do not needlessly do perf checks. 2021-07-22 10:52:05 -04:00
Daniel Lemire ca9391c5a9 Let us run more CI tests. 2021-07-22 10:44:10 -04:00
Daniel Lemire 91b8fa4c4b Fixing a CI issue. 2021-07-22 10:38:59 -04:00
Daniel Lemire 081c3ca7c8 Merged. 2021-07-22 10:17:37 -04:00
Daniel Lemire bbeec66a93 Merge branch 'jkeiser/no-padding-scalar' into dlemire/nopadding 2021-07-21 13:45:10 -04:00
Daniel Lemire 7dcd43e82a Merge branch 'jkeiser/no-padding' into dlemire/nopadding 2021-07-21 11:19:43 -04:00
Daniel Lemire c3f7eff019 Adding some commentary 2021-07-19 17:08:51 -04:00
Daniel Lemire d0e2a7fb00 Minor fixes 2021-07-19 16:53:11 -04:00
Daniel Lemire 9cace04da3 Adding more tests. 2021-07-19 16:33:58 -04:00
Daniel Lemire 2e688a2825 Removing two other asserts. 2021-07-19 16:27:29 -04:00
Daniel Lemire 4501aebee8 Disabling a couple of asserts. 2021-07-19 16:23:48 -04:00
Daniel Lemire df24da314f Cleaning. 2021-07-19 15:58:17 -04:00
Daniel Lemire 8b2bff981f Messy temporary work. 2021-07-19 15:34:48 -04:00
Daniel Lemire a34996939c Adding a duplicate of the existing test. 2021-07-19 13:55:10 -04:00
Daniel Lemire e8e731a311 Merge branch 'master' into dlemire/backport_jkeiser_fix_for_issue1632 2021-07-19 12:17:17 -04:00
Daniel Lemire f364e354e2 Minor fixes. 2021-07-19 11:54:46 -04:00
Daniel Lemire 3c5c2d2404 This backports (isolate) a fix by jkeiser of issue 1632. 2021-07-19 11:13:37 -04:00
Daniel Lemire 3300d8463b Adding type test. 2021-07-18 20:53:57 -04:00
Daniel Lemire 267e70d550 Adding another case. 2021-07-18 16:53:35 -04:00
Daniel Lemire 4b118bd9e1 Verifying issue. 2021-07-18 13:00:46 -04:00
Daniel Lemire e5d0e92116 Minor correction. 2021-06-23 13:36:41 -06:00
Daniel Lemire b3b108b120 Adding the functions that I meant to add earlier. 2021-06-23 13:36:41 -06:00
Daniel Lemire 40f522ab2d Adding potentially useless definition. 2021-06-23 13:36:41 -06:00
Daniel Lemire 5a6894cd3e This adds "guarded" (i.e., memory-safe) number parsing routines. 2021-06-23 13:36:41 -06:00
John Keiser 90409897eb Add __SIMDJSON_CHECK_EOF feature flag 2021-06-23 13:36:41 -06:00
John Keiser 78d1cd96a9 Split ondemand_object_tests into smaller files 2021-06-23 13:36:41 -06:00
John Keiser 6a1f8fc5c3 Don't step off the end of the index buffer 2021-06-23 13:36:37 -06:00
John Keiser 42a31ad096 Fix ARM compile errors 2021-06-23 11:52:00 -06:00
John Keiser ac647e6c11 Don't change the order of fields to avoid perf changes 2021-06-21 10:46:01 -06:00
John Keiser 45fbd8c4c5 Make len available to any dom_parser_implementation user 2021-06-21 10:38:56 -06:00
John Keiser 6ba9ad3ed9 Remove need for padding from SIMD string parsing 2021-06-19 21:20:31 -07:00
John Keiser bab51e5f08 Remove unlikely from null / bool parsing 2021-06-19 10:35:05 -07:00
Daniel Lemire f45c59f27c I suspect that sanitizers might increase stack usage, to combat that you may set SIMDJSON_NO_FORCE_INLINING (#1614) 2021-06-08 10:58:20 -04:00
Daniel Lemire ba0406f021 Minor changes to compilation test. 2021-06-07 10:21:39 -04:00
John Keiser b02aedb5bb Don't use padding parsing booleans 2021-06-06 16:56:28 -07:00
John Keiser da4de2e0b8 Don't read padding at all for root booleans and numbers 2021-06-06 15:04:08 -07:00
John Keiser eda0f190ea Don't allocate when parsing root number 2021-06-06 13:01:46 -07:00
John Keiser 633784a4a2 Merge issue 2021-06-06 11:51:18 -07:00
Daniel Lemire 10a7b9bd25 Merge branch 'master' into jkeiser/no-padding 2021-06-04 17:15:00 -04:00
Daniel Lemire 0d8f6f5827 Merging again. Fixing issue. 2021-05-27 20:43:51 -04:00
Daniel Lemire 0c14707b78 Merge branch 'master' into jkeiser/no-padding 2021-05-27 20:42:36 -04:00
Daniel Lemire c0fb5f7474 Another merge issue. 2021-05-27 20:30:25 -04:00
Daniel Lemire 930b0beb6d Missing #ifdef SIMDJSON_DEVELOPMENT_CHECKS
that got destroyed in the merge. Putting it back.
2021-05-27 18:27:20 -04:00
Daniel Lemire dadfb519cd Minor correction. 2021-05-27 18:04:01 -04:00
Daniel Lemire 595c628965 Merge branch 'master' into jkeiser/no-padding 2021-05-27 17:53:43 -04:00
Daniel Lemire 76f7e4ae04 Merge branch 'master' into jkeiser/no-padding 2021-05-07 23:03:39 -04:00
Daniel Lemire d7b08c84c7 Merge branch 'master' into jkeiser/no-padding 2021-04-23 10:18:42 -04:00
John Keiser 4d0f1021ff Merge pull request #1516 from simdjson/dlemire/guarded_number_parsing
guarded number parsing (to be merged into Remove padding access from iteration #1511)
2021-03-31 11:18:18 -07:00
Daniel Lemire 42c854124f Adding the functions that I meant to add earlier. 2021-03-23 16:39:53 -04:00
Daniel Lemire 081f954465 Adding potentially useless definition. 2021-03-23 15:20:25 -04:00
Daniel Lemire 1fbd6047c0 This adds "guarded" (i.e., memory-safe) number parsing routines. 2021-03-23 12:00:39 -04:00
John Keiser 09601eb480 Add __SIMDJSON_CHECK_EOF feature flag 2021-03-22 11:03:00 -07:00
John Keiser 02762fa352 Split ondemand_object_tests into smaller files 2021-03-21 14:53:16 -07:00
John Keiser a334303119 Don't step off the end of the index buffer 2021-03-21 14:22:00 -07:00
John Keiser 7f545a8996 Normalize the words "position" and "end" 2021-03-20 14:23:38 -07:00
250 changed files with 5143 additions and 20605 deletions
+10 -2
View File
@@ -208,6 +208,14 @@ jobs:
executor: clang10
environment: { CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE_THREADS=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
steps: [ cmake_test ]
nocheckeof-clang10:
description: Validate that when __SIMDJSON_CHECK_EOF=0, everything still succeeds
environment:
CXXFLAGS: -D__SIMDJSON_CHECK_EOF=0
CMAKE_BUILD_FLAGS: --target ondemand_tests
CTEST_FLAGS: --output-on-failure -R ondemand_
executor: clang10
steps: [ cmake_test ]
# dynamic
dynamic-gcc10:
description: Build and run tests on GCC 10 and AVX 2 with a cmake dynamic build
@@ -284,7 +292,7 @@ workflows:
- libcpp-clang10
# full single-implementation tests
- sanitize-gcc10
# - sanitize-gcc10 # gcc10 + sanitize uses a lot of memory?
- sanitize-clang10
- threadsanitize-gcc10
- threadsanitize-clang10
@@ -303,7 +311,7 @@ workflows:
# sanitized single-implementation tests
- sanitize-haswell-gcc10
# - sanitize-haswell-gcc10 # gcc10 + sanitize uses a lot of memory?
- sanitize-haswell-clang10
# testing "just the library"
+2 -2
View File
@@ -19,8 +19,8 @@ task:
build_script:
- mkdir build
- cd build
- cmake -DSIMDJSON_BASH=OFF -DSIMDJSON_GIT=OFF ..
- make
- cmake -DSIMDJSON_BASH=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GIT=OFF ..
- cmake --build .
test_script:
- cd build
- ctest --output-on-failure -LE explicitonly
+59 -21
View File
@@ -1,4 +1,46 @@
kind: pipeline
name: i386-gcc # we do not support 32-bit systems, but we run tests
platform: { os: linux, arch: amd64 }
steps:
- name: Build and Test
image: i386/ubuntu
environment:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DEVELOPER_MODE=ON
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- scripts/addcmakeppa.sh "$(env -i sh -c '. /etc/os-release; echo $VERSION_CODENAME')"
- apt-get install -y g++ cmake gcc git
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ctest $CTEST_FLAGS
---
kind: pipeline
name: i386-clang # we do not support 32-bit systems, but we run tests
platform: { os: linux, arch: amd64 }
steps:
- name: Build and Test
image: i386/ubuntu
environment:
CC: clang-6.0
CXX: clang++-6.0
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DEVELOPER_MODE=ON
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- scripts/addcmakeppa.sh "$(env -i sh -c '. /etc/os-release; echo $VERSION_CODENAME')"
- apt-get install -y clang++-6.0 cmake git
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ctest $CTEST_FLAGS
---
kind: pipeline
name: gcc9
platform: { os: linux, arch: amd64 }
steps:
@@ -8,7 +50,7 @@ steps:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
@@ -19,7 +61,6 @@ steps:
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ctest $CTEST_FLAGS -L acceptance -LE per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
@@ -36,7 +77,7 @@ steps:
CC: clang-6.0
CXX: clang++-6.0
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- mkdir build
@@ -44,7 +85,6 @@ steps:
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ctest $CTEST_FLAGS -L acceptance -LE per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
@@ -60,7 +100,7 @@ steps:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
@@ -82,7 +122,7 @@ steps:
environment:
CC: clang-9
CXX: clang++-9
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON
BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
@@ -102,7 +142,7 @@ steps:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
@@ -113,7 +153,6 @@ steps:
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L acceptance -LE per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
@@ -129,7 +168,7 @@ steps:
environment:
CC: clang-9
CXX: clang++-9
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=haswell;westmere;fallback
BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
@@ -138,7 +177,6 @@ steps:
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L acceptance -LE per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=icelake ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=haswell ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=westmere ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -L per_implementation
@@ -154,7 +192,7 @@ steps:
environment:
CC: clang-11
CXX: clang++-11
CMAKE_FLAGS: -GNinja
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -GNinja
BUILD_FLAGS:
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CXXFLAGS: -std=c++20 -stdlib=libc++
@@ -175,7 +213,7 @@ steps:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=arm64;fallback
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=arm64;fallback
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
@@ -199,7 +237,7 @@ steps:
environment:
CC: clang-6.0
CXX: clang++-6.0
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON
BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
@@ -222,7 +260,7 @@ steps:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
@@ -243,7 +281,7 @@ steps:
environment:
CC: clang-6.0
CXX: clang++-6.0
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON
BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
@@ -264,7 +302,7 @@ steps:
image: gcc:8
environment:
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=arm64;fallback
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=arm64;fallback
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CC: gcc
CXX: g++
@@ -291,7 +329,7 @@ steps:
environment:
CC: clang-6.0
CXX: clang++-6.0
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=arm64;fallback
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=arm64;fallback
BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
@@ -318,7 +356,7 @@ steps:
CC: clang-9
CXX: clang++-9
BUILD_FLAGS: -- -j 4
CMAKE_FLAGS: -GNinja -DBUILD_SHARED_LIBS=OFF
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -GNinja -DBUILD_SHARED_LIBS=OFF
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CXXFLAGS: -stdlib=libc++
commands:
@@ -339,7 +377,7 @@ steps:
CC: clang-9
CXX: clang++-9
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CXXFLAGS: -stdlib=libc++
commands:
@@ -360,7 +398,7 @@ steps:
CC: clang-7
CXX: clang++-7
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CXXFLAGS: -stdlib=libc++
commands:
@@ -380,7 +418,7 @@ steps:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_EXCEPTIONS=OFF
CMAKE_FLAGS: -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_EXCEPTIONS=OFF
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
+2 -2
View File
@@ -9,8 +9,8 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
-24
View File
@@ -1,24 +0,0 @@
name: CIFuzz
on: [pull_request]
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'simdjson'
dry-run: false
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'simdjson'
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v1
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts
@@ -6,7 +6,7 @@ jobs:
whitespace:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v2
- name: Remove whitespace and check the diff
run: |
set -eu
+3 -3
View File
@@ -37,14 +37,14 @@ jobs:
chmod +x llvm.sh
sudo ./llvm.sh $CLANGVERSION
- uses: actions/checkout@v3
- uses: actions/checkout@v1
- uses: actions/cache@v3
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- uses: actions/cache@v3
- uses: actions/cache@v2
id: cache-corpus
with:
path: out/
-34
View File
@@ -1,34 +0,0 @@
name: Macos (Xcode 11)
on: [push, pull_request]
jobs:
macos-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
xcversion select 11.7
mkdir builddebug &&
cd builddebug &&
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cd .. &&
mkdir build &&
cd build &&
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cmake --install . &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
cd ../tests/installation_tests/find &&
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
-33
View File
@@ -1,33 +0,0 @@
name: Macos
on: [push, pull_request]
jobs:
macos-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
mkdir builddebug &&
cd builddebug &&
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cd .. &&
mkdir build &&
cd build &&
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cmake --install . &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
cd ../tests/installation_tests/find &&
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
+63
View File
@@ -0,0 +1,63 @@
name: MinGW32-CI
on: [push, pull_request]
# Important: scoop will either install 32-bit GCC or 64-bit GCC, not both.
# It is important to build static libraries because cmake is not smart enough under Windows/mingw to take care of the path. So
# with a dynamic library, you could get failures due to the fact that the EXE can't find its DLL.
jobs:
ci:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-gcc
runs-on: windows-2016
env:
CMAKE_GENERATOR: Ninja # This is critical, try ' cmake -GNinja-DBUILD_SHARED_LIBS=OFF .. ' if using the command line
CC: gcc
CXX: g++
steps: # To reproduce what is below, start a powershell with administrative rights, using scoop *is* a good idea
- uses: actions/checkout@v2
- uses: actions/cache@v2 # we cache the scoop setup with 32-bit GCC
id: cache
with:
path: |
C:\ProgramData\scoop
key: scoop32 # static key: should be good forever
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Setup Windows # This should almost never run if the cache works.
if: steps.cache.outputs.cache-hit != 'true'
shell: powershell
run: |
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
scoop install sudo --global
sudo scoop install git --global
sudo scoop install ninja --global
sudo scoop install cmake --global
sudo scoop install gcc --arch 32bit --global
$env:path
Write-Host 'Everything has been installed, you are good!'
- name: Build and Test 32-bit x86
shell: powershell
run: |
$ENV:PATH="C:\ProgramData\scoop\shims;C:\ProgramData\scoop\apps\gcc\current\bin;C:\ProgramData\scoop\apps\ninja\current;$ENV:PATH"
g++ --version
cmake --version
ninja --version
git --version
mkdir build32
cd build32
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
cmake --build . --target acceptance_tests --verbose
ctest -L acceptance --output-on-failure
+69
View File
@@ -0,0 +1,69 @@
name: MinGW64-CI
on: [push, pull_request]
# Important: scoop will either install 32-bit GCC or 64-bit GCC, not both.
# It is important to build static libraries because cmake is not smart enough under Windows/mingw to take care of the path. So
# with a dynamic library, you could get failures due to the fact that the EXE can't find its DLL.
jobs:
ci:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-gcc
runs-on: windows-2016
env:
CMAKE_GENERATOR: Ninja # This is critical, try ' cmake -GNinja-DBUILD_SHARED_LIBS=OFF .. ' if using the command line
CC: gcc
CXX: g++
steps: # To reproduce what is below, start a powershell with administrative rights, using scoop *is* a good idea
- uses: actions/checkout@v2
- uses: actions/cache@v2 # we cache the scoop setup with 64-bit GCC
id: cache
with:
path: |
C:\ProgramData\scoop
key: scoop64 # static key: should be good forever
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Setup Windows # This should almost never run if the cache works.
if: steps.cache.outputs.cache-hit != 'true'
shell: powershell
run: |
Invoke-Expression (New-Object System.Net.WebClient).DownloadString('https://get.scoop.sh')
scoop install sudo --global
sudo scoop install git --global
sudo scoop install ninja --global
sudo scoop install cmake --global
sudo scoop install gcc --arch 64bit --global
$env:path
Write-Host 'Everything has been installed, you are good!'
- name: Build and Test 64-bit x64
shell: powershell
run: |
$ENV:PATH="C:\ProgramData\scoop\shims;C:\ProgramData\scoop\apps\gcc\current\bin;C:\ProgramData\scoop\apps\ninja\current;$ENV:PATH"
g++ --version
cmake --version
ninja --version
git --version
mkdir build64
cd build64
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
cmake --build . --target acceptance_tests --verbose
ctest -L acceptance --output-on-failure
cd ..
mkdir build64debug
cd build64debug
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_ENABLE_THREADS=OFF ..
cmake --build . --target acceptance_tests --verbose
ctest -L acceptance --output-on-failure
+9 -3
View File
@@ -17,15 +17,21 @@ jobs:
- msystem: "MINGW64"
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
type: Release
- msystem: "MINGW32"
install: mingw-w64-i686-libxml2 mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
type: Release
- msystem: "MINGW64"
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
type: Debug
- msystem: "MINGW32"
install: mingw-w64-i686-libxml2 mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-clang
type: Debug
env:
CMAKE_GENERATOR: Ninja
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
@@ -38,6 +44,6 @@ jobs:
run: |
mkdir build
cd build
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON ..
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON ..
cmake --build . --verbose
ctest -j4 --output-on-failure -LE explicitonly
+8 -2
View File
@@ -19,15 +19,21 @@ jobs:
- msystem: "MINGW64"
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
type: Release
- msystem: "MINGW32"
install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-gcc
type: Release
- msystem: "MINGW64"
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
type: Debug
- msystem: "MINGW32"
install: mingw-w64-i686-cmake mingw-w64-i686-ninja mingw-w64-i686-gcc
type: Debug
env:
CMAKE_GENERATOR: Ninja
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
+2 -2
View File
@@ -15,8 +15,8 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
-31
View File
@@ -1,31 +0,0 @@
name: Ubuntu 18.04 CI (LLVM 7)
on: [push, pull_request]
jobs:
ubuntu-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-18.04
env:
CC: clang-7
CXX: clang++-7
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: install clang 7
run: |
sudo apt update
sudo apt install clang-7
- name: Use cmake
run: |
mkdir build &&
cd build &&
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly
+2 -2
View File
@@ -10,8 +10,8 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
+2 -2
View File
@@ -9,8 +9,8 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
+2 -2
View File
@@ -15,8 +15,8 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
-38
View File
@@ -1,38 +0,0 @@
name: Ubuntu 20.04 CI (GCC 8)
on: [push, pull_request]
jobs:
ubuntu-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-20.04
env:
CXX: g++-8
CC: gcc-8
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Install GCC 8
run: sudo apt-get install -y g++-8
- name: Use cmake
run: |
mkdir builddebug &&
cd builddebug &&
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cd .. &&
mkdir build &&
cd build &&
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cmake --install . &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
cd ../tests/installation_tests/find &&
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
+2 -2
View File
@@ -9,8 +9,8 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
+2 -2
View File
@@ -9,8 +9,8 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
+2 -2
View File
@@ -9,8 +9,8 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
+2 -2
View File
@@ -9,8 +9,8 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
+2 -2
View File
@@ -9,8 +9,8 @@ jobs:
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
-25
View File
@@ -1,25 +0,0 @@
name: Ubuntu 22.04 CI (CLANG 13)
on: [push, pull_request]
jobs:
ubuntu-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Install clang++-13
run: sudo apt-get install -y clang++-13
- name: Use cmake
run: |
mkdir build &&
cd build &&
CXX=clang++-13 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly
-25
View File
@@ -1,25 +0,0 @@
name: Ubuntu 22.04 CI (GCC 12)
on: [push, pull_request]
jobs:
ubuntu-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Install gcc12
run: sudo apt-get install -y g++-12
- name: Use cmake
run: |
mkdir build &&
cd build &&
CXX=g++-12 cmake -DSIMDJSON_DEVELOPER_MODE=ON .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly
-33
View File
@@ -1,33 +0,0 @@
name: Ubuntu 22.04 CI (GCC 11)
on: [push, pull_request]
jobs:
ubuntu-build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
mkdir builddebug &&
cd builddebug &&
cmake -DCMAKE_BUILD_TYPE=Debug -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cd .. &&
mkdir build &&
cd build &&
cmake -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cmake --install . &&
echo -e '#include <simdjson.h>\nint main(int argc,char**argv) {simdjson::dom::parser parser;simdjson::dom::element tweets = parser.load(argv[1]); }' > tmp.cpp && c++ -Idestination/include -Ldestination/lib -std=c++17 -Wl,-rpath,destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json &&
cd ../tests/installation_tests/find &&
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../../../build/destination .. && cmake --build .
@@ -1,4 +1,4 @@
name: VS17-CLANG-CI
name: VS15-CI
on: [push, pull_request]
@@ -7,19 +7,22 @@ jobs:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-vs17
runs-on: windows-latest
name: windows-vs15
runs-on: windows-2016
strategy:
fail-fast: false
matrix:
include:
- {gen: Visual Studio 17 2022, arch: x64}
- {gen: Visual Studio 15 2017, arch: Win32, static: ON}
- {gen: Visual Studio 15 2017, arch: Win32, static: OFF}
- {gen: Visual Studio 15 2017, arch: x64, static: ON}
- {gen: Visual Studio 15 2017, arch: x64, static: OFF}
steps:
- name: checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Configure
run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -T ClangCL -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -B build
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_BUILD_STATIC=${{matrix.static}} -B build
- name: Build Debug
run: cmake --build build --config Debug --verbose
- name: Build Release
@@ -1,10 +1,10 @@
name: VS17-ARM-CI
name: VS16-ARM-CI
on: [push, pull_request]
jobs:
ci:
name: windows-vs17
name: windows-vs16
runs-on: windows-latest
strategy:
fail-fast: false
@@ -14,7 +14,7 @@ jobs:
- {arch: ARM64}
steps:
- name: checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Use cmake
run: |
cmake -A ${{ matrix.arch }} -DCMAKE_CROSSCOMPILING=1 -DSIMDJSON_DEVELOPER_MODE=ON -D SIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_EXCEPTIONS=OFF -B build &&
@@ -1,4 +1,4 @@
name: VS17-CI
name: VS16-CI
on: [push, pull_request]
@@ -7,22 +7,22 @@ jobs:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-vs17
name: windows-vs16
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- {gen: Visual Studio 17 2022, arch: Win32, shared: ON}
- {gen: Visual Studio 17 2022, arch: Win32, shared: OFF}
- {gen: Visual Studio 17 2022, arch: x64, shared: ON}
- {gen: Visual Studio 17 2022, arch: x64, shared: OFF}
- {gen: Visual Studio 16 2019, arch: Win32, static: ON}
- {gen: Visual Studio 16 2019, arch: Win32, static: OFF}
- {gen: Visual Studio 16 2019, arch: x64, static: ON}
- {gen: Visual Studio 16 2019, arch: x64, static: OFF}
steps:
- name: checkout
uses: actions/checkout@v3
uses: actions/checkout@v2
- name: Configure
run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DBUILD_SHARED_LIBS=${{matrix.shared}} -B build
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_BUILD_STATIC=${{matrix.static}} -B build
- name: Build Debug
run: cmake --build build --config Debug --verbose
- name: Build Release
+31
View File
@@ -0,0 +1,31 @@
name: VS16-CLANG-CI
on: [push, pull_request]
jobs:
ci:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-vs16
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: 'Run CMake with VS16 Clang'
uses: lukka/run-cmake@v3
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
buildDirectory: "${{ github.workspace }}/../../_temp/windows"
cmakeBuildType: Release
buildWithCMake: true
cmakeAppendedArgs: -T ClangCL -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF
buildWithCMakeArgs: --config Release
- name: 'Run CTest'
run: ctest -C Release -LE explicitonly --output-on-failure
working-directory: "${{ github.workspace }}/../../_temp/windows"
+45
View File
@@ -0,0 +1,45 @@
name: VS16-Ninja-CI
on: [push, pull_request]
jobs:
ci:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: windows-vs16
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: 'Run CMake with VS16'
uses: lukka/run-cmake@v2
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
buildDirectory: "${{ github.workspace }}/../../_temp/windows"
cmakeBuildType: Release
buildWithCMake: true
cmakeAppendedArgs: -G Ninja -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF
buildWithCMakeArgs: --config Release
- name: 'Run CTest'
run: ctest -C Release -LE explicitonly --output-on-failure
working-directory: "${{ github.workspace }}/../../_temp/windows"
- name: 'Install with CMake'
uses: lukka/run-cmake@v3
with:
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
buildWithCMakeArgs: '--target install'
- name: 'Test Installation with CMake'
uses: lukka/run-cmake@v3
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/tests/installation_tests/find/CMakeLists.txt'
cmakeBuildType: Release
buildWithCMake: true
buildDirectory: '${{ github.workspace }}/tests/installation_tests/find/buildDirectory'
cmakeAppendedArgs: -G Ninja
buildWithCMakeArgs: '--config Release --verbose'
@@ -1,18 +1,18 @@
name: VS17-NoExcept-CI
name: VS16-NoExcept-CI
on: [push, pull_request]
jobs:
ci:
name: windows-vs17
name: windows-vs16
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/cache@v3
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: 'Run CMake with VS17'
- name: 'Run CMake with VS16'
uses: lukka/run-cmake@v3
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
+2 -2
View File
@@ -172,7 +172,7 @@ install:
- export CMAKE_C_FLAGS="${CMAKE_CXX_FLAGS}"
- export CMAKE_FLAGS="-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} -DSIMDJSON_IMPLEMENTATION=ppc64;fallback";
- if [[ "${SANITIZE}" == "on" ]]; then
export CMAKE_FLAGS="${CMAKE_FLAGS} -DSIMDJSON_SANITIZE=ON";
export CMAKE_FLAGS="${CMAKE_FLAGS} -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE=ON";
export ASAN_OPTIONS="detect_leaks=0";
fi
- if [[ "${STATIC}" == "on" ]]; then
@@ -183,7 +183,7 @@ install:
script:
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
- cmake -DSIMDJSON_DEVELOPER_MODE=ON $CMAKE_FLAGS ..
- cmake --build . -- -j2
- SIMDJSON_FORCE_IMPLEMENTATION=ppc64 ctest $CTEST_FLAGS -L per_implementation
- SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation
+1 -12
View File
@@ -85,17 +85,6 @@
"valarray": "cpp",
"vector": "cpp",
"*.ipp": "cpp",
"__functional_base_03": "cpp",
"filesystem": "cpp",
"*.inc": "cpp",
"compare": "cpp",
"concepts": "cpp",
"variant": "cpp",
"__bits": "cpp",
"csignal": "cpp",
"future": "cpp",
"queue": "cpp",
"shared_mutex": "cpp",
"ranges": "cpp"
"filesystem": "cpp"
}
}
+13 -5
View File
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14)
project(
simdjson
# The version number is modified by tools/release.py
VERSION 2.1.0
VERSION 0.9.1
DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C
@@ -20,8 +20,8 @@ string(
# ---- Options, variables ----
# These version numbers are modified by tools/release.py
set(SIMDJSON_LIB_VERSION "12.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "12" CACHE STRING "simdjson library soversion")
set(SIMDJSON_LIB_VERSION "8.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "8" CACHE STRING "simdjson library soversion")
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
@@ -49,10 +49,19 @@ endif()
if(is_top_project)
option(SIMDJSON_DEVELOPER_MODE "Enable targets for developing simdjson" OFF)
option(BUILD_SHARED_LIBS "Build simdjson as a shared library" OFF)
if("$ENV{CI}")
set(SIMDJSON_DEVELOPER_MODE ON CACHE INTERNAL "")
endif()
endif()
include(cmake/handle-deprecations.cmake)
include(cmake/developer-options.cmake)
if(SIMDJSON_DEVELOPER_MODE)
include(cmake/developer-options.cmake)
else()
message(STATUS "Building only the library. Advanced users may want to turn SIMDJSON_DEVELOPER_MODE to ON, e.g., via -D SIMDJSON_DEVELOPER_MODE=ON.")
endif()
# ---- simdjson library ----
@@ -171,7 +180,6 @@ endif()
# ---- Developer mode extras ----
if(NOT SIMDJSON_DEVELOPER_MODE)
message(STATUS "Building only the library. Advanced users may want to turn SIMDJSON_DEVELOPER_MODE to ON, e.g., via -D SIMDJSON_DEVELOPER_MODE=ON.")
return()
elseif(NOT is_top_project)
message(AUTHOR_WARNING "Developer mode is intended for developers of simdjson")
+4 -4
View File
@@ -62,13 +62,13 @@ Pull Requests
Pull requests are always invited. However, we ask that you follow these guidelines:
- It is wise to discuss your ideas first as part of an issue before you start coding. If you omit this step and code first, be prepared to have your code receive scrutiny and be dropped.
- Users should provide a rationale for their changes. Does it improve performance? Does it add a feature? Does it improve maintainability? Does it fix a bug? This must be explicitly stated as part of the pull request. Do not propose changes based on taste or intuition. We do not delegate programming to tools: that some tool suggested a code change is not reason enough to change the code.
- It is wiser to discuss your ideas first as part of an issue before you start coding. If you omit this step and code first, be prepare to have your code receive scrutiny and be dropped.
- Users should provide a rationale for their changes. Does it improve performance? Does it add a feature? Does it improve maintainability? Does fix a bug? This must be explicitly stated as part of the pull request. Do not propose changes based on taste or intuition. We do not delegate programming to tools: that some tool suggested a code change is not reason enough to change the code.
1. When your code improves performance, please document the gains with a benchmark using hard numbers.
2. If your code fixes a bug, please either fix a failing test, or propose a new test.
2. If your code fixes a bug, please be either fix a failing test, or propose a new test.
3. Other types of changes must be clearly motivated. We openly discourage changes with no identifiable benefits.
- Changes should be focused and minimal. You should change as few lines of code as possible. Please do not reformat or touch files needlessly.
- New features must be accompanied by new tests, in general.
- New features must be accompanied of new tests, in general.
- Your code should pass our continuous-integration tests. It is your responsibility to ensure that your proposal pass the tests. We do not merge pull requests that would break our build.
- An exception to this would be changes to non-code files, such as documentation and assets, or trivial changes to code, such as comments, where it is encouraged to explicitly ask for skipping a CI run using the `[skip ci]` prefix in your Pull Request title **and** in the first line of the most recent commit in a push. Example for such a commit: `[skip ci] Fixed typo in power_of_ten's docs`
This benefits the project in such a way that the CI pipeline is not burdened by running jobs on changes that don't change any behavior in the code, which reduces wait times for other Pull Requests that do change behavior and require testing.
+1 -5
View File
@@ -37,9 +37,5 @@ Furkan Taşkale
Brendan Knapp
Danila Kutenin
Pavel Pavlov
Hao Chen
Nicolas Boyer
Kim Walisch and Jatin Bhateja (AVX-512 bitset decoder)
Fangzheng Zhang and Weiqiang Wan (AVX-512 kernel)
# if you have contributed to the project and your name does not
# if you have contributed to the project and your name does not
# appear in this list, please let us know!
+1 -1
View File
@@ -38,7 +38,7 @@ PROJECT_NAME = simdjson
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = "2.1.0"
PROJECT_NUMBER = "0.9.1"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
+3 -5
View File
@@ -3,7 +3,7 @@
[![Ubuntu 20.04 CI](https://github.com/simdjson/simdjson/workflows/Ubuntu%2020.04%20CI%20(GCC%209)/badge.svg)](https://simdjson.org/plots.html)
![VS16-CI](https://github.com/simdjson/simdjson/workflows/VS16-CI/badge.svg)
![MinGW64-CI](https://github.com/simdjson/simdjson/workflows/MinGW64-CI/badge.svg)
[![][license img]][license] [![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.org/api/2.0.0/index.html)
[![][license img]][license] [![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.org/api/0.9.0/index.html)
simdjson : Parsing gigabytes of JSON per second
===============================================
@@ -53,7 +53,6 @@ The simdjson library is easily consumable with a single .h and .cpp file.
2. Create `quickstart.cpp`:
```c++
#include <iostream>
#include "simdjson.h"
using namespace simdjson;
int main(void) {
@@ -79,7 +78,7 @@ Usage documentation is available:
* [Performance](doc/performance.md) shows some more advanced scenarios and how to tune for them.
* [Implementation Selection](doc/implementation-selection.md) describes runtime CPU detection and
how you can work with it.
* [API](https://simdjson.org/api/1.0.0/annotated.html) contains the automatically generated API documentation.
* [API](https://simdjson.org/api/0.9.0/annotated.html) contains the automatically generated API documentation.
Performance results
-------------------
@@ -138,7 +137,6 @@ We distinguish between "bindings" (which just wrap the C++ code) and a port to a
- [rcppsimdjson](https://github.com/eddelbuettel/rcppsimdjson): R bindings.
- [simdjson_erlang](https://github.com/ChomperT/simdjson_erlang): erlang bindings.
- [lua-simdjson](https://github.com/FourierTransformer/lua-simdjson): lua bindings.
- [hermes-json](https://hackage.haskell.org/package/hermes-json): haskell bindings.
About simdjson
@@ -160,7 +158,7 @@ We also have an informal [blog post providing some background and context](https
For the video inclined, <br />
[![simdjson at QCon San Francisco 2019](http://img.youtube.com/vi/wlvKAT7SZIQ/0.jpg)](http://www.youtube.com/watch?v=wlvKAT7SZIQ)<br />
(It was the best voted talk, we're kinda proud of it.)
(it was the best voted talk, we're kinda proud of it).
Funding
-------
@@ -4,12 +4,8 @@
#include <map>
#include <string>
namespace amazon_cellphones {
const bool UNTHREADED = false;
const bool THREADED = true;
using namespace json_benchmark;
struct brand {
@@ -63,11 +59,10 @@ struct runner : public file_runner<I> {
}
};
template<bool threaded>
struct simdjson_dom;
template<typename I> simdjson_really_inline static void amazon_cellphones(benchmark::State &state) {
run_json_benchmark<runner<I>, runner<simdjson_dom<UNTHREADED>>>(state);
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
}
} // namespace amazon_cellphones
+1 -8
View File
@@ -8,16 +8,12 @@ namespace amazon_cellphones {
using namespace simdjson;
template<bool threaded>
struct simdjson_dom {
using StringType = std::string;
dom::parser parser{};
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
#ifdef SIMDJSON_THREADS_ENABLED
parser.threaded = threaded;
#endif
auto stream = parser.parse_many(json);
auto i = stream.begin();
++i; // Skip first line
@@ -41,10 +37,7 @@ struct simdjson_dom {
};
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_dom<UNTHREADED>)->UseManualTime();
#ifdef SIMDJSON_THREADS_ENABLED
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_dom<THREADED>)->UseManualTime();
#endif
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_dom)->UseManualTime();
} // namespace amazon_cellphones
@@ -8,21 +8,17 @@ namespace amazon_cellphones {
using namespace simdjson;
template<bool threaded>
struct simdjson_ondemand {
using StringType = std::string;
ondemand::parser parser{};
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
#ifdef SIMDJSON_THREADS_ENABLED
parser.threaded = threaded;
#endif
ondemand::document_stream stream = parser.iterate_many(json);
ondemand::document_stream::iterator i = stream.begin();
++i; // Skip first line
for (;i != stream.end(); ++i) {
auto doc = *i;
auto & doc = *i;
size_t index{0};
StringType copy;
double rating;
@@ -62,10 +58,7 @@ struct simdjson_ondemand {
};
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_ondemand<UNTHREADED>)->UseManualTime();
#ifdef SIMDJSON_THREADS_ENABLED
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_ondemand<THREADED>)->UseManualTime();
#endif
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_ondemand)->UseManualTime();
} // namespace amazon_cellphones
-1
View File
@@ -1,5 +1,4 @@
#include <benchmark/benchmark.h>
#include <iostream>
#include "simdjson.h"
#include <sstream>
-5
View File
@@ -25,11 +25,6 @@ SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
#include <benchmark/benchmark.h>
SIMDJSON_POP_DISABLE_WARNINGS
#include "json2msgpack/simdjson_ondemand.h"
#include "json2msgpack/rapidjson.h"
#include "json2msgpack/yyjson.h"
#include "json2msgpack/sajson.h"
#include "json2msgpack/nlohmann_json.h"
#include "amazon_cellphones/simdjson_dom.h"
#include "amazon_cellphones/simdjson_ondemand.h"
-1
View File
@@ -1,5 +1,4 @@
#include <benchmark/benchmark.h>
#include <iostream>
#include "simdjson.h"
using namespace simdjson;
using namespace benchmark;
+5 -41
View File
@@ -97,9 +97,9 @@ struct option_struct {
verbose = true;
break;
case 'a': {
auto impl = simdjson::get_available_implementations()[optarg];
auto impl = simdjson::available_implementations[optarg];
if(impl && impl->supported_by_runtime_system()) {
simdjson::get_active_implementation() = impl;
simdjson::active_implementation = impl;
} else {
std::cerr << "implementation " << optarg << " not found or not supported " << std::endl;
}
@@ -204,13 +204,10 @@ struct feature_benchmarker {
}
// Rate of 1-7-structural misses per 8-structural flip
double struct1_7_miss_rate(BenchmarkStage stage) const {
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
return 1;
#else
if (!has_events()) { return 1; }
return struct7_miss[stage].best.branch_misses() - struct7[stage].best.branch_misses() / double(struct7_miss.stats->blocks_with_1_structural_flipped);
#endif
}
// Extra cost of an 8-15 structural block over a 1-7 structural block
double struct8_15_cost(BenchmarkStage stage) const {
return cost_per_block(stage, struct15, struct15.stats->blocks_with_8_structurals, struct7);
@@ -221,12 +218,8 @@ struct feature_benchmarker {
}
// Rate of 8-15-structural misses per 8-structural flip
double struct8_15_miss_rate(BenchmarkStage stage) const {
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
return 1;
#else
if (!has_events()) { return 1; }
return double(struct15_miss[stage].best.branch_misses() - struct15[stage].best.branch_misses()) / double(struct15_miss.stats->blocks_with_8_structurals_flipped);
#endif
}
// Extra cost of a 16+-structural block over an 8-15 structural block (actual varies based on # of structurals!)
@@ -239,15 +232,10 @@ struct feature_benchmarker {
}
// Rate of 16-structural misses per 16-structural flip
double struct16_miss_rate(BenchmarkStage stage) const {
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
return 1;
#else
if (!has_events()) { return 1; }
return double(struct23_miss[stage].best.branch_misses() - struct23[stage].best.branch_misses()) / double(struct23_miss.stats->blocks_with_16_structurals_flipped);
#endif
}
// Extra cost of having UTF-8 in a block
double utf8_cost(BenchmarkStage stage) const {
return cost_per_block(stage, utf8, utf8.stats->blocks_with_utf8, struct7_full);
@@ -258,13 +246,10 @@ struct feature_benchmarker {
}
// Rate of UTF-8 misses per UTF-8 flip
double utf8_miss_rate(BenchmarkStage stage) const {
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
return 1;
#else
if (!has_events()) { return 1; }
return double(utf8_miss[stage].best.branch_misses() - utf8[stage].best.branch_misses()) / double(utf8_miss.stats->blocks_with_utf8_flipped);
#endif
}
// Extra cost of having escapes in a block
double escape_cost(BenchmarkStage stage) const {
return cost_per_block(stage, escape, escape.stats->blocks_with_escapes, struct7_full);
@@ -275,15 +260,10 @@ struct feature_benchmarker {
}
// Rate of escape misses per escape flip
double escape_miss_rate(BenchmarkStage stage) const {
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
return 1;
#else
if (!has_events()) { return 1; }
return double(escape_miss[stage].best.branch_misses() - escape[stage].best.branch_misses()) / double(escape_miss.stats->blocks_with_escapes_flipped);
#endif
}
double calc_expected_feature_cost(BenchmarkStage stage, const benchmarker& file) const {
// Expected base ns/block (empty)
json_stats& stats = *file.stats;
@@ -320,6 +300,7 @@ struct feature_benchmarker {
double calc_expected(BenchmarkStage stage, const benchmarker& file) const {
return calc_expected_feature_cost(stage, file) + calc_expected_miss_cost(stage, file);
}
void print(const option_struct& options) const {
printf("\n");
printf("Features in ns/block (64 bytes):\n");
@@ -378,22 +359,6 @@ struct feature_benchmarker {
}
};
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
void print_file_effectiveness(BenchmarkStage stage, const char* filename, const benchmarker& results, const feature_benchmarker& features) {
double actual = results[stage].best.elapsed_ns() / double(results.stats->blocks);
double calc = features.calc_expected(stage, results);
double calc_misses = features.calc_expected_misses(stage, results);
double calc_miss_cost = features.calc_expected_miss_cost(stage, results);
printf(" | %-8s ", benchmark_stage_name(stage));
printf("| %-15s ", filename);
printf("| %8.3g ", features.calc_expected_feature_cost(stage, results));
printf("| %8.3g ", calc_miss_cost);
printf("| %8.3g ", calc);
printf("| %8.3g ", actual);
printf("| %+8.3g ", actual - calc);
printf("| %13llu ", (long long unsigned)(calc_misses));
}
#else
void print_file_effectiveness(BenchmarkStage stage, const char* filename, const benchmarker& results, const feature_benchmarker& features) {
double actual = results[stage].best.elapsed_ns() / double(results.stats->blocks);
double calc = features.calc_expected(stage, results);
@@ -417,7 +382,6 @@ void print_file_effectiveness(BenchmarkStage stage, const char* filename, const
}
printf("|\n");
}
#endif
int main(int argc, char *argv[]) {
// Read options
+2 -3
View File
@@ -2,7 +2,7 @@
#define __BENCHMARKER_H
#include "event_counter.h"
#include "simdjson.h"
#include "simdjson.h" // For SIMDJSON_DISABLE_DEPRECATED_WARNINGS
#include <cassert>
#include <cctype>
@@ -423,7 +423,7 @@ struct benchmarker {
stage.instructions() / static_cast<double>(stats->structurals),
stage.instructions() / static_cast<double>(stage.cycles())
);
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
// NOTE: removed cycles/miss because it is a somewhat misleading stat
printf("%s%-13s: %7.0f branch misses (%6.2f%%) - %.0f cache misses (%6.2f%%) - %.2f cache references\n",
prefix,
@@ -434,7 +434,6 @@ struct benchmarker {
percent(stage.cache_misses(), all_stages_without_allocation.cache_misses()),
stage.cache_references()
);
#endif
}
}
+1 -1
View File
@@ -48,7 +48,7 @@ BENCHMARK_TEMPLATE(distinct_user_id, rapidjson)->UseManualTime();
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(distinct_user_id, rapidjson_insitu)->UseManualTime();
-2
View File
@@ -9,8 +9,6 @@ namespace distinct_user_id {
struct sajson {
size_t ast_buffer_size{0};
size_t *ast_buffer{nullptr};
~sajson() { free(ast_buffer); }
simdjson_really_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
auto val = obj.get_value_of_key({key.data(), key.length()});
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
+5 -5
View File
@@ -66,7 +66,7 @@ void print_usage(ostream& out) {
out << "-H - Make the buffers hot (reduce page allocation and related OS tasks during parsing) [default]" << endl;
out << "-a IMPL - Use the given parser implementation. By default, detects the most advanced" << endl;
out << " implementation supported on the host machine." << endl;
for (auto impl : simdjson::get_available_implementations()) {
for (auto impl : simdjson::available_implementations) {
if(impl->supported_by_runtime_system()) {
out << "-a " << std::left << std::setw(9) << impl->name() << " - Use the " << impl->description() << " parser implementation." << endl;
}
@@ -116,10 +116,10 @@ struct option_struct {
verbose = true;
break;
case 'a': {
const implementation *impl = simdjson::get_available_implementations()[optarg];
const implementation *impl = simdjson::available_implementations[optarg];
if ((!impl) || (!impl->supported_by_runtime_system())) {
std::string exit_message = string("Unsupported option value -a ") + optarg + ": expected -a with one of ";
for (auto imple : simdjson::get_available_implementations()) {
for (auto imple : simdjson::available_implementations) {
if(imple->supported_by_runtime_system()) {
exit_message += imple->name();
exit_message += " ";
@@ -127,7 +127,7 @@ struct option_struct {
}
exit_usage(exit_message);
}
simdjson::get_active_implementation() = impl;
simdjson::active_implementation = impl;
break;
}
case 'C':
@@ -175,7 +175,7 @@ int main(int argc, char *argv[]) {
option_struct options(argc, argv);
if (options.verbose) {
verbose_stream = &cout;
verbose() << "Implementation: " << simdjson::get_active_implementation()->name() << endl;
verbose() << "Implementation: " << simdjson::active_implementation->name() << endl;
}
// Start collecting events. We put this early so if it prints an error message, it's the
+2 -2
View File
@@ -50,9 +50,9 @@ simdjson_really_inline void simdjson_process_atom(stat_t &s,
} else if(element.is<double>()) {
s.float_count++;
} else if (element.is<bool>()) {
simdjson::error_code err;
bool v;
simdjson::error_code error;
if ((error = element.get(v))) { std::cerr << error << std::endl; abort(); }
err = element.get(v);
if (v) {
s.true_count++;
} else {
+2 -25
View File
@@ -1,15 +1,6 @@
#ifndef __EVENT_COUNTER_H
#define __EVENT_COUNTER_H
#ifndef SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
#ifdef __aarch64__
// on ARM, we use just cycles and instructions
#define SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS 1
#else
// elsewhere, we try to use four counters.
#define SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS 0
#endif
#endif
#include <cassert>
#include <cctype>
#ifndef _MSC_VER
@@ -55,12 +46,6 @@ struct event_count {
event_count(const event_count& other): elapsed(other.elapsed), event_counts(other.event_counts) { }
// The types of counters (so we can read the getter more easily)
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
enum event_counter_types {
CPU_CYCLES,
INSTRUCTIONS
};
#else
enum event_counter_types {
CPU_CYCLES,
INSTRUCTIONS,
@@ -68,16 +53,15 @@ struct event_count {
CACHE_REFERENCES,
CACHE_MISSES
};
#endif
double elapsed_sec() const { return duration<double>(elapsed).count(); }
double elapsed_ns() const { return duration<double, std::nano>(elapsed).count(); }
double cycles() const { return static_cast<double>(event_counts[CPU_CYCLES]); }
double instructions() const { return static_cast<double>(event_counts[INSTRUCTIONS]); }
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
double branch_misses() const { return static_cast<double>(event_counts[BRANCH_MISSES]); }
double cache_references() const { return static_cast<double>(event_counts[CACHE_REFERENCES]); }
double cache_misses() const { return static_cast<double>(event_counts[CACHE_MISSES]); }
#endif
event_count& operator=(const event_count& other) {
this->elapsed = other.elapsed;
this->event_counts = other.event_counts;
@@ -121,11 +105,9 @@ struct event_aggregate {
double elapsed_ns() const { return total.elapsed_ns() / iterations; }
double cycles() const { return total.cycles() / iterations; }
double instructions() const { return total.instructions() / iterations; }
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
double branch_misses() const { return total.branch_misses() / iterations; }
double cache_references() const { return total.cache_references() / iterations; }
double cache_misses() const { return total.cache_misses() / iterations; }
#endif
};
struct event_collector {
@@ -135,16 +117,11 @@ struct event_collector {
#if defined(__linux__)
LinuxEvents<PERF_TYPE_HARDWARE> linux_events;
event_collector(bool quiet = false) : linux_events(vector<int>{
#if SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
PERF_COUNT_HW_CPU_CYCLES,
PERF_COUNT_HW_INSTRUCTIONS,
#else
PERF_COUNT_HW_CPU_CYCLES,
PERF_COUNT_HW_INSTRUCTIONS,
PERF_COUNT_HW_BRANCH_MISSES,
PERF_COUNT_HW_CACHE_REFERENCES,
PERF_COUNT_HW_CACHE_MISSES
#endif
}, quiet) {}
bool has_events() {
return linux_events.is_working();
+1 -1
View File
@@ -42,7 +42,7 @@ BENCHMARK_TEMPLATE(find_tweet, rapidjson)->UseManualTime();
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), find_id, result);
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag>(json.data()), find_id, result);
}
};
BENCHMARK_TEMPLATE(find_tweet, rapidjson_insitu)->UseManualTime();
-2
View File
@@ -11,8 +11,6 @@ struct sajson {
size_t ast_buffer_size{0};
size_t *ast_buffer{nullptr};
~sajson() { free(ast_buffer); }
simdjson_really_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
auto val = obj.get_value_of_key({key.data(), key.length()});
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
-48
View File
@@ -1,48 +0,0 @@
#pragma once
#include "json_benchmark/file_runner.h"
namespace json2msgpack {
using namespace json_benchmark;
template <typename I> struct runner : public file_runner<I> {
std::string_view result;
std::unique_ptr<char[]> buffer;
bool setup(benchmark::State &state) {
bool isok = this->load_json(state, TWITTER_JSON);
if (isok) {
// Let us allocate a sizeable buffer.
buffer = std::unique_ptr<char[]>(new char[this->json.size() * 4 + 1024]);
}
return isok;
}
bool before_run(benchmark::State &state) {
if (!file_runner<I>::before_run(state)) {
return false;
}
// Clear the buffer.
::memset(buffer.get(), 0, this->json.size() * 4 + 1024);
return true;
}
bool run(benchmark::State &) {
return this->implementation.run(this->json, buffer.get(), result);
}
template <typename R>
bool diff(benchmark::State &state, runner<R> &reference) {
return diff_results(state, result.size(), reference.result.size(), diff_flags::NONE);
}
};
struct simdjson_ondemand;
template <typename I>
simdjson_really_inline static void json2msgpack(benchmark::State &state) {
run_json_benchmark<runner<I>, runner<simdjson_ondemand>>(state);
}
} // namespace json2msgpack
-117
View File
@@ -1,117 +0,0 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
#include "json2msgpack.h"
namespace json2msgpack {
using namespace nlohmann;
struct nlohmann_json2msgpack {
inline std::string_view to_msgpack(const simdjson::padded_string &json,
uint8_t *buf);
private:
inline void write_double(const double d) noexcept;
inline void write_byte(const uint8_t b) noexcept;
inline void write_uint32(const uint32_t w) noexcept;
inline void write_string(const std::string& str);
inline void recursive_processor(basic_json<> element);
uint8_t *buff{};
};
std::string_view nlohmann_json2msgpack::to_msgpack(const simdjson::padded_string &json,
uint8_t *buf) {
buff = buf;
auto val = nlohmann::json::parse(json.data(), json.data() + json.size());
recursive_processor(val);
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
}
void nlohmann_json2msgpack::write_double(const double d) noexcept {
*buff++ = 0xcb;
::memcpy(buff, &d, sizeof(d));
buff += sizeof(d);
}
void nlohmann_json2msgpack::write_byte(const uint8_t b) noexcept {
*buff = b;
buff++;
}
void nlohmann_json2msgpack::write_uint32(const uint32_t w) noexcept {
::memcpy(buff, &w, sizeof(w));
buff += sizeof(w);
}
void nlohmann_json2msgpack::write_string(const std::string & str) {
write_byte(0xdb);
write_uint32(uint32_t(str.size()));
::memcpy(buff, str.data(), str.size());
buff += str.size();
}
void nlohmann_json2msgpack::recursive_processor(json element) {
switch (element.type()) {
case nlohmann::detail::value_t::array: {
uint32_t counter = 0;
write_byte(0xdd);
std::vector<json> array = element.get<std::vector<json>>();
write_uint32(uint32_t(array.size()));
for (auto child : array) {
recursive_processor(child);
}
} break;
case nlohmann::detail::value_t::object: {
write_byte(0xdf);
std::map<std::string,json> object = element.get<std::map<std::string,json>>();
write_uint32(uint32_t(object.size()));
for (auto field : object) {
write_string(field.first);
recursive_processor(field.second);
}
} break;
case nlohmann::detail::value_t::number_integer:
case nlohmann::detail::value_t::number_unsigned:
case nlohmann::detail::value_t::number_float:
write_double(double(element));
break;
case nlohmann::detail::value_t::string:
write_string(std::string(element));
break;
case nlohmann::detail::value_t::boolean:
write_byte(0xc2 + bool(element));
break;
case nlohmann::detail::value_t::null:
write_byte(0xc0);
break;
case nlohmann::detail::value_t::discarded:
case nlohmann::detail::value_t::binary:
default:
printf("unexpected\n");
break;
}
}
struct nlohmann_json {
using StringType = std::string_view;
nlohmann_json2msgpack parser{};
bool run(simdjson::padded_string &json, char *buffer,
std::string_view &result) {
result = parser.to_msgpack(json, reinterpret_cast<uint8_t *>(buffer));
return true;
}
};
BENCHMARK_TEMPLATE(json2msgpack, nlohmann_json)->UseManualTime();
} // namespace json2msgpack
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
-140
View File
@@ -1,140 +0,0 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
#include "json2msgpack.h"
namespace json2msgpack {
using namespace rapidjson;
template <int parseflag>
struct rapidjson2msgpack {
inline std::string_view to_msgpack(char *json, uint8_t *buf);
private:
inline void write_double(const double d) noexcept;
inline void write_byte(const uint8_t b) noexcept;
inline void write_uint32(const uint32_t w) noexcept;
inline void write_uint32_at(const uint32_t w, uint8_t *p) noexcept;
void write_string(const char * s, size_t length) noexcept;
inline void recursive_processor(Value &v);
uint8_t *buff{};
};
template <int parseflag>
std::string_view rapidjson2msgpack<parseflag>::to_msgpack(char *json, uint8_t *buf) {
buff = buf;
Document doc{};
if(parseflag & kParseInsituFlag) {
doc.ParseInsitu<parseflag>(json);
} else {
doc.Parse<parseflag>(json);
}
recursive_processor(doc);
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
}
template <int parseflag>
void rapidjson2msgpack<parseflag>::write_double(const double d) noexcept {
*buff++ = 0xcb;
::memcpy(buff, &d, sizeof(d));
buff += sizeof(d);
}
template <int parseflag>
void rapidjson2msgpack<parseflag>::write_byte(const uint8_t b) noexcept {
*buff = b;
buff++;
}
template <int parseflag>
void rapidjson2msgpack<parseflag>::write_string(const char * c, size_t len) noexcept {
write_byte(0xdb);
write_uint32(uint32_t(len));
::memcpy(buff, c, len);
buff += len;
}
template <int parseflag>
void rapidjson2msgpack<parseflag>::write_uint32(const uint32_t w) noexcept {
::memcpy(buff, &w, sizeof(w));
buff += sizeof(w);
}
template <int parseflag>
void rapidjson2msgpack<parseflag>::write_uint32_at(const uint32_t w, uint8_t *p) noexcept {
::memcpy(p, &w, sizeof(w));
}
template <int parseflag>
void rapidjson2msgpack<parseflag>::recursive_processor(Value &v) {
switch (v.GetType()) {
case kArrayType:
write_byte(0xdd);
write_uint32(v.Size());
for (Value::ValueIterator i = v.Begin(); i != v.End(); ++i) {
recursive_processor(*i);
}
break;
case kObjectType:
write_byte(0xdf);
write_uint32(uint32_t(v.MemberEnd()-v.MemberBegin()));
for (Value::MemberIterator m = v.MemberBegin(); m != v.MemberEnd();
++m) {
write_string(m->name.GetString(), m->name.GetStringLength());
recursive_processor(m->value);
}
break;
case kStringType:
write_string(v.GetString(), v.GetStringLength());
break;
case kNumberType:
write_double(v.GetDouble());
break;
case kFalseType:
write_byte(0xc2);
break;
case kTrueType:
write_byte(0xc3);
break;
case kNullType:
write_byte(0xc0);
break;
}
}
template <int parseflag>
struct rapidjson_base {
using StringType = std::string_view;
rapidjson2msgpack<parseflag> parser{};
bool run(simdjson::padded_string &json, char *buffer,
std::string_view &result) {
result =
parser.to_msgpack(json.data(), reinterpret_cast<uint8_t *>(buffer));
return true;
}
};
using rapidjson_lossless = rapidjson_base<kParseValidateEncodingFlag|kParseFullPrecisionFlag>;
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_lossless)->UseManualTime();
using rapidjson = rapidjson_base<kParseValidateEncodingFlag>;
BENCHMARK_TEMPLATE(json2msgpack, rapidjson)->UseManualTime();
using rapidjson_insitu = rapidjson_base<kParseValidateEncodingFlag|kParseInsituFlag>;
BENCHMARK_TEMPLATE(json2msgpack, rapidjson_insitu)->UseManualTime();
} // namespace json2msgpack
#endif // SIMDJSON_COMPETITION_RAPIDJSON
-131
View File
@@ -1,131 +0,0 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_SAJSON
#include "json2msgpack.h"
namespace json2msgpack {
using namespace sajson;
struct sajson2msgpack {
inline std::string_view to_msgpack(char *json, size_t size, uint8_t *buf);
virtual ~sajson2msgpack() { free(ast_buffer); }
private:
inline void write_double(const double d) noexcept;
inline void write_byte(const uint8_t b) noexcept;
inline void write_uint32(const uint32_t w) noexcept;
inline void write_string(const char * s, size_t length) noexcept;
inline void recursive_processor(const sajson::value &v);
uint8_t *buff{};
size_t ast_buffer_size{0};
size_t *ast_buffer{nullptr};
};
std::string_view sajson2msgpack::to_msgpack(char *json, size_t size, uint8_t *buf) {
buff = buf;
if (!ast_buffer) {
ast_buffer_size = size;
ast_buffer = (size_t *)std::malloc(ast_buffer_size * sizeof(size_t));
}
auto doc = parse(
bounded_allocation(ast_buffer, ast_buffer_size),
mutable_string_view(size, json)
);
auto root = doc.get_root();
recursive_processor(root);
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
}
void sajson2msgpack::write_string(const char * c, size_t len) noexcept {
write_byte(0xdb);
write_uint32(uint32_t(len));
::memcpy(buff, c, len);
buff += len;
}
void sajson2msgpack::write_double(const double d) noexcept {
*buff++ = 0xcb;
::memcpy(buff, &d, sizeof(d));
buff += sizeof(d);
}
void sajson2msgpack::write_byte(const uint8_t b) noexcept {
*buff = b;
buff++;
}
void sajson2msgpack::write_uint32(const uint32_t w) noexcept {
::memcpy(buff, &w, sizeof(w));
buff += sizeof(w);
}
void sajson2msgpack::recursive_processor(const sajson::value &node) {
using namespace sajson;
switch (node.get_type()) {
case TYPE_NULL:
write_byte(0xc0);
break;
case TYPE_FALSE:
write_byte(0xc2);
break;
case TYPE_TRUE:
write_byte(0xc3);
break;
case TYPE_ARRAY: {
auto length = node.get_length();
write_byte(0xdf);
write_uint32(uint32_t(length));
for (size_t i = 0; i < length; ++i) {
recursive_processor(node.get_array_element(i));
}
break;
}
case TYPE_OBJECT: {
auto length = node.get_length();
write_byte(0xdd);
write_uint32(uint32_t(length));
for (auto i = 0u; i < length; ++i) {
auto s = node.get_object_key(i);
write_string(s.data(), s.length());
recursive_processor(node.get_object_value(i));
}
break;
}
case TYPE_STRING:
write_string(node.as_cstring(), node.get_string_length());
break;
case TYPE_DOUBLE:
case TYPE_INTEGER:
write_double(node.get_number_value());
break;
default:
assert(false && "unknown node type");
}
}
struct sajson {
using StringType = std::string_view;
sajson2msgpack parser{};
bool run(simdjson::padded_string &json, char *buffer,
std::string_view &result) {
result =
parser.to_msgpack(json.data(), json.size(), reinterpret_cast<uint8_t *>(buffer));
return true;
}
};
BENCHMARK_TEMPLATE(json2msgpack, sajson)->UseManualTime();
} // namespace json2msgpack
#endif // SIMDJSON_COMPETITION_SAJSON
-183
View File
@@ -1,183 +0,0 @@
#pragma once
#if SIMDJSON_EXCEPTIONS
#include "json2msgpack.h"
namespace json2msgpack {
using namespace simdjson;
/**
* @brief The simdjson2msgpack struct is used to quickly convert
* JSON strings to msgpack views. You must provide a pointer to
* a large memory region where the msgpack gets written. The
* buffer should be large enough to store the msgpack output (which
* can never be 3x larger than the input JSON) with an additional
* simdjson::SIMDJSON_PADDING bytes.
*
* Recommended usage:
*
* simdjson2msgpack parser{};
* simdjson::padded_string json = "[1,2]"_padded; // some JSON
* uint8_t * buffer = new uint8_t[3*json.size() + simdjson::SIMDJSON_PADDING]; // large buffer
*
* std::string_view msgpack = parser.to_msgpack(json, buffer);
*
* The result (msgpack) is a string view to a msgpack serialization of the input JSON,
* it points inside the buffer you provided.
*
* You may reuse the simdjson2msgpack instance though you should use
* one per thread.
*/
struct simdjson2msgpack {
/**
* @brief Converts the provided JSON into msgpack.
*
* @param json JSON input
* @param buf temporary buffer (must be large enough, with 32 bytes of
* padding)
* @return std::string_view msgpack output, writting to the temporary buffer
*/
inline std::string_view to_msgpack(const simdjson::padded_string &json,
uint8_t *buf);
private:
simdjson_really_inline void write_double(const double d) noexcept;
simdjson_really_inline void write_byte(const uint8_t b) noexcept;
simdjson_really_inline void write_uint32(const uint32_t w) noexcept;
simdjson_really_inline uint8_t *skip_uint32() noexcept;
simdjson_really_inline void write_uint32_at(const uint32_t w,
uint8_t *p) noexcept;
simdjson_really_inline void
write_raw_string(simdjson::ondemand::raw_json_string rjs);
inline void recursive_processor(simdjson::ondemand::value element);
simdjson::ondemand::parser parser;
simdjson::ondemand::document doc;
uint8_t *buff{};
};
std::string_view
simdjson2msgpack::to_msgpack(const simdjson::padded_string &json,
uint8_t *buf) {
buff = buf;
ondemand::document doc = parser.iterate(json);
if (doc.is_scalar()) {
// we have a special case where the JSON document is a single document...
switch (doc.type()) {
case simdjson::ondemand::json_type::number:
write_double(doc.get_double());
break;
case simdjson::ondemand::json_type::string:
write_raw_string(doc.get_raw_json_string());
break;
case simdjson::ondemand::json_type::boolean:
write_byte(0xc2 + doc.get_bool());
break;
case simdjson::ondemand::json_type::null:
write_byte(0xc0);
break;
case simdjson::ondemand::json_type::array:
case simdjson::ondemand::json_type::object:
default:
// impossible
break;
}
} else {
simdjson::ondemand::value val = doc;
recursive_processor(val);
}
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
}
void simdjson2msgpack::write_double(const double d) noexcept {
*buff++ = 0xcb;
::memcpy(buff, &d, sizeof(d));
buff += sizeof(d);
}
void simdjson2msgpack::write_byte(const uint8_t b) noexcept {
*buff = b;
buff++;
}
void simdjson2msgpack::write_uint32(const uint32_t w) noexcept {
::memcpy(buff, &w, sizeof(w));
buff += sizeof(w);
}
uint8_t *simdjson2msgpack::skip_uint32() noexcept {
uint8_t *ret = buff;
buff += sizeof(uint32_t);
return ret;
}
void simdjson2msgpack::write_uint32_at(const uint32_t w, uint8_t *p) noexcept {
::memcpy(p, &w, sizeof(w));
}
void simdjson2msgpack::write_raw_string(
simdjson::ondemand::raw_json_string in) {
write_byte(0xdb);
uint8_t *location = skip_uint32();
std::string_view v = parser.unescape(in, buff);
write_uint32_at(uint32_t(v.size()), location);
}
void simdjson2msgpack::recursive_processor(simdjson::ondemand::value element) {
switch (element.type()) {
case simdjson::ondemand::json_type::array: {
uint32_t counter = 0;
write_byte(0xdd);
uint8_t *location = skip_uint32();
for (auto child : element.get_array()) {
counter++;
recursive_processor(child.value());
}
write_uint32_at(counter, location);
} break;
case simdjson::ondemand::json_type::object: {
uint32_t counter = 0;
write_byte(0xdf);
uint8_t *location = skip_uint32();
for (auto field : element.get_object()) {
counter++;
write_raw_string(field.key());
recursive_processor(field.value());
}
write_uint32_at(counter, location);
} break;
case simdjson::ondemand::json_type::number:
write_double(element.get_double());
break;
case simdjson::ondemand::json_type::string:
write_raw_string(element.get_raw_json_string());
break;
case simdjson::ondemand::json_type::boolean:
write_byte(0xc2 + element.get_bool());
break;
case simdjson::ondemand::json_type::null:
write_byte(0xc0);
break;
default:
SIMDJSON_UNREACHABLE();
}
}
struct simdjson_ondemand {
using StringType = std::string_view;
simdjson2msgpack parser{};
bool run(simdjson::padded_string &json, char *buffer,
std::string_view &result) {
result = parser.to_msgpack(json, reinterpret_cast<uint8_t *>(buffer));
return true;
}
};
BENCHMARK_TEMPLATE(json2msgpack, simdjson_ondemand)->UseManualTime();
} // namespace json2msgpack
#endif // SIMDJSON_EXCEPTIONS
-122
View File
@@ -1,122 +0,0 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_YYJSON
#include "json2msgpack.h"
namespace json2msgpack {
struct yyjson2msgpack {
inline std::string_view to_msgpack(yyjson_doc *doc, uint8_t *buf);
private:
inline void write_double(const double d) noexcept;
inline void write_byte(const uint8_t b) noexcept;
inline void write_uint32(const uint32_t w) noexcept;
inline void write_string(const char *s, size_t length) noexcept;
inline void recursive_processor(yyjson_val *obj);
uint8_t *buff{};
};
std::string_view yyjson2msgpack::to_msgpack(yyjson_doc *doc, uint8_t *buf) {
buff = buf;
yyjson_val *root = yyjson_doc_get_root(doc);
recursive_processor(root);
return std::string_view(reinterpret_cast<char *>(buf), size_t(buff - buf));
}
void yyjson2msgpack::write_string(const char *c, size_t len) noexcept {
write_byte(0xdb);
write_uint32(uint32_t(len));
::memcpy(buff, c, len);
buff += len;
}
void yyjson2msgpack::write_double(const double d) noexcept {
*buff++ = 0xcb;
::memcpy(buff, &d, sizeof(d));
buff += sizeof(d);
}
void yyjson2msgpack::write_byte(const uint8_t b) noexcept {
*buff = b;
buff++;
}
void yyjson2msgpack::write_uint32(const uint32_t w) noexcept {
::memcpy(buff, &w, sizeof(w));
buff += sizeof(w);
}
void yyjson2msgpack::recursive_processor(yyjson_val *obj) {
size_t idx, max;
yyjson_val *val;
yyjson_val *key;
switch (yyjson_get_type(obj)) {
case YYJSON_TYPE_STR:
write_string(yyjson_get_str(obj), yyjson_get_len(obj));
break;
case YYJSON_TYPE_ARR:
write_byte(0xdf);
write_uint32(uint32_t(yyjson_arr_size(obj)));
yyjson_arr_foreach(obj, idx, max, val) { recursive_processor(val); }
break;
case YYJSON_TYPE_OBJ:
write_byte(0xdd);
write_uint32(uint32_t(yyjson_obj_size(obj)));
yyjson_obj_foreach(obj, idx, max, key, val) {
write_string(yyjson_get_str(key), yyjson_get_len(key));
recursive_processor(val);
}
break;
case YYJSON_TYPE_BOOL:
write_byte(0xc2 + yyjson_get_bool(obj));
break;
case YYJSON_TYPE_NULL:
write_byte(0xc0);
break;
case YYJSON_TYPE_NUM:
switch (yyjson_get_subtype(obj)) {
case YYJSON_SUBTYPE_UINT:
write_double(double(yyjson_get_uint(obj)));
break;
case YYJSON_SUBTYPE_SINT:
write_double(double(yyjson_get_sint(obj)));
break;
case YYJSON_SUBTYPE_REAL:
write_double(yyjson_get_real(obj));
break;
default:
SIMDJSON_UNREACHABLE();
}
break;
default:
SIMDJSON_UNREACHABLE();
}
}
struct yyjson : yyjson2msgpack {
bool run(simdjson::padded_string &json, char *buffer,
std::string_view &result) {
yyjson_doc *doc = yyjson_read(json.data(), json.size(), 0);
result = to_msgpack(doc, reinterpret_cast<uint8_t*>(buffer));
return true;
}
};
BENCHMARK_TEMPLATE(json2msgpack, yyjson)->UseManualTime();
struct yyjson_insitu : yyjson2msgpack {
bool run(simdjson::padded_string &json, char *buffer,
std::string_view &result) {
yyjson_doc *doc =
yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0);
result = to_msgpack(doc, reinterpret_cast<uint8_t*>(buffer));
return true;
}
};
BENCHMARK_TEMPLATE(json2msgpack, yyjson_insitu)->UseManualTime();
} // namespace json2msgpack
#endif // SIMDJSON_COMPETITION_YYJSON
@@ -10,8 +10,8 @@ void maybe_display_implementation() {
static bool displayed_implementation = false;
if(!displayed_implementation) {
displayed_implementation = true;
std::cout << "simdjson::dom implementation: " << simdjson::get_active_implementation()->name() << std::endl;
std::cout << "simdjson::ondemand implementation (stage 1): " << simdjson::get_active_implementation()->name() << std::endl;
std::cout << "simdjson::dom implementation: " << simdjson::active_implementation->name() << std::endl;
std::cout << "simdjson::ondemand implementation (stage 1): " << simdjson::active_implementation->name() << std::endl;
std::cout << "simdjson::ondemand implementation (stage 2): " << simdjson::builtin_implementation()->name() << std::endl;
}
}
@@ -58,11 +58,10 @@ template<typename B, typename R> static void run_json_benchmark(benchmark::State
if (collector.has_events()) {
state.counters["instructions"] = events.instructions();
state.counters["cycles"] = events.cycles();
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
state.counters["branch_miss"] = events.branch_misses();
state.counters["cache_miss"] = events.cache_misses();
state.counters["cache_ref"] = events.cache_references();
#endif
state.counters["instructions_per_byte"] = events.instructions() / double(bench.bytes_per_iteration());
state.counters["instructions_per_cycle"] = events.instructions() / events.cycles();
state.counters["cycles_per_byte"] = events.cycles() / double(bench.bytes_per_iteration());
@@ -70,11 +69,9 @@ template<typename B, typename R> static void run_json_benchmark(benchmark::State
state.counters["best_instructions"] = events.best.instructions();
state.counters["best_cycles"] = events.best.cycles();
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
state.counters["best_branch_miss"] = events.best.branch_misses();
state.counters["best_cache_miss"] = events.best.cache_misses();
state.counters["best_cache_ref"] = events.best.cache_references();
#endif
state.counters["best_instructions_per_byte"] = events.best.instructions() / double(bench.bytes_per_iteration());
state.counters["best_instructions_per_cycle"] = events.best.instructions() / events.best.cycles();
@@ -95,11 +92,9 @@ template<typename B, typename R> static void run_json_benchmark(benchmark::State
if (collector.has_events()) {
label << " instructions=" << setw(12) << uint64_t(events.best.instructions()) << setw(0);
label << " cycles=" << setw(12) << uint64_t(events.best.cycles()) << setw(0);
#if !SIMDJSON_SIMPLE_PERFORMANCE_COUNTERS
label << " branch_miss=" << setw(8) << uint64_t(events.best.branch_misses()) << setw(0);
label << " cache_miss=" << setw(8) << uint64_t(events.best.cache_misses()) << setw(0);
label << " cache_ref=" << setw(10) << uint64_t(events.best.cache_references()) << setw(0);
#endif
}
label << " items=" << setw(10) << bench.items_per_iteration() << setw(0);
+1 -1
View File
@@ -42,7 +42,7 @@ struct nlohmann_json_sax {
return true;
}
bool number_unsigned(number_unsigned_t val) override { // Need this event because coordinate value can be equal to 1
buffer[k] = double(val);
buffer[k] = val;
if (k == 2) {
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
k = 0;
+1 -1
View File
@@ -51,7 +51,7 @@ BENCHMARK_TEMPLATE(kostya, rapidjson_lossless)->UseManualTime();
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(kostya, rapidjson_insitu)->UseManualTime();
-1
View File
@@ -11,7 +11,6 @@ struct sajson {
size_t ast_buffer_size{0};
size_t *ast_buffer{nullptr};
~sajson() { free(ast_buffer); }
simdjson_really_inline double get_double(const ::sajson::value &obj, std::string_view key) {
using namespace sajson;
@@ -6,9 +6,6 @@
namespace large_amazon_cellphones {
const bool UNTHREADED = false;
const bool THREADED = true;
static const simdjson::padded_string &get_built_json();
using namespace json_benchmark;
@@ -84,11 +81,11 @@ static const simdjson::padded_string &get_built_json() {
return json;
}
template<bool threaded>
struct simdjson_dom;
template<typename I> simdjson_really_inline static void large_amazon_cellphones(benchmark::State &state) {
run_json_benchmark<runner<I>, runner<simdjson_dom<UNTHREADED>>>(state);
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
}
} // namespace large_amazon_cellphones
@@ -9,16 +9,12 @@ namespace large_amazon_cellphones {
using namespace simdjson;
template<bool threaded>
struct simdjson_dom {
using StringType = std::string;
dom::parser parser{};
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
#ifdef SIMDJSON_THREADS_ENABLED
parser.threaded = threaded;
#endif
auto stream = parser.parse_many(json);
auto i = stream.begin();
++i; // Skip first line
@@ -42,10 +38,7 @@ struct simdjson_dom {
};
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_dom<UNTHREADED>)->UseManualTime();
#ifdef SIMDJSON_THREADS_ENABLED
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_dom<THREADED>)->UseManualTime();
#endif
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_dom)->UseManualTime();
} // namespace large_amazon_cellphones
@@ -8,21 +8,17 @@ namespace large_amazon_cellphones {
using namespace simdjson;
template<bool threaded>
struct simdjson_ondemand {
using StringType = std::string;
ondemand::parser parser{};
bool run(simdjson::padded_string &json, std::map<StringType, brand> &result) {
#ifdef SIMDJSON_THREADS_ENABLED
parser.threaded = threaded;
#endif
ondemand::document_stream stream = parser.iterate_many(json);
ondemand::document_stream::iterator i = stream.begin();
++i; // Skip first line
for (;i != stream.end(); ++i) {
auto doc = *i;
auto & doc = *i;
size_t index{0};
StringType copy;
double rating;
@@ -62,10 +58,7 @@ struct simdjson_ondemand {
};
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_ondemand<UNTHREADED>)->UseManualTime();
#ifdef SIMDJSON_THREADS_ENABLED
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_ondemand<THREADED>)->UseManualTime();
#endif
BENCHMARK_TEMPLATE(large_amazon_cellphones, simdjson_ondemand)->UseManualTime();
} // namespace amazon_cellphones
+1 -1
View File
@@ -34,7 +34,7 @@ struct nlohmann_json_sax {
return true;
}
bool number_unsigned(number_unsigned_t val) override {
buffer[k] = double(val);
buffer[k] = val;
if (k == 2) {
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
k = 0;
+1 -1
View File
@@ -48,7 +48,7 @@ BENCHMARK_TEMPLATE(large_random, rapidjson_lossless)->UseManualTime();
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(large_random, rapidjson_insitu)->UseManualTime();
-1
View File
@@ -11,7 +11,6 @@ struct sajson {
size_t ast_buffer_size{0};
size_t *ast_buffer{nullptr};
~sajson() { free(ast_buffer); }
simdjson_really_inline double get_double(const ::sajson::value &obj, std::string_view key) {
using namespace sajson;
+1 -1
View File
@@ -70,7 +70,7 @@ BENCHMARK_TEMPLATE(partial_tweets, rapidjson)->UseManualTime();
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<tweet<std::string_view>> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), result);
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(partial_tweets, rapidjson_insitu)->UseManualTime();
-2
View File
@@ -11,8 +11,6 @@ struct sajson {
size_t ast_buffer_size{0};
size_t *ast_buffer{nullptr};
~sajson() { free(ast_buffer); }
simdjson_really_inline std::string_view get_string_view(const ::sajson::value &obj, std::string_view key) {
auto val = obj.get_value_of_key({key.data(), key.length()});
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field is not a string"; }
+1 -1
View File
@@ -48,7 +48,7 @@ struct nlohmann_json_sax {
}
bool number_unsigned(number_unsigned_t val) override {
if (values & key_rt && !(values & found_rt)) { // retweet_count
rt = int(val);
rt = val;
values &= ~(key_rt);
values |= (found_rt);
if (rt <= max_rt && rt >= result.retweet_count) { // Check if current tweet has more retweet than previous top tweet
+1 -1
View File
@@ -59,7 +59,7 @@ BENCHMARK_TEMPLATE(top_tweet, rapidjson)->UseManualTime();
struct rapidjson_insitu : rapidjson_base {
bool run(simdjson::padded_string &json, int64_t max_retweet_count, top_tweet_result<StringType> &result) {
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag|kParseInsituFlag>(json.data()), max_retweet_count, result);
return rapidjson_base::run(doc.ParseInsitu<kParseValidateEncodingFlag>(json.data()), max_retweet_count, result);
}
};
BENCHMARK_TEMPLATE(top_tweet, rapidjson_insitu)->UseManualTime();
-1
View File
@@ -11,7 +11,6 @@ struct sajson {
size_t ast_buffer_size{0};
size_t *ast_buffer{nullptr};
~sajson() { free(ast_buffer); }
bool run(simdjson::padded_string &json, int32_t max_retweet_count, top_tweet_result<StringType> &result) {
if (!ast_buffer) {
+8 -13
View File
@@ -3,12 +3,19 @@
#
add_library(simdjson-internal-flags INTERFACE)
option(SIMDJSON_NO_FORCE_INLINING "Do not attempt to force function inlining" OFF)
if(SIMDJSON_NO_FORCE_INLINING)
add_compile_definitions(SIMDJSON_NO_FORCE_INLINING=1)
endif()
option(SIMDJSON_CHECK_EOF "Check for the end of the input buffer. The setting is unnecessary since we require padding of the inputs. You should expect tests to fail with this option turned on." OFF)
option(SIMDJSON_CHECK_EOF "Check for the end of the input buffer (to avoid buffer overflows). We expect this setting to be ON except for performance testing." ON)
if(SIMDJSON_CHECK_EOF)
add_compile_definitions(SIMDJSON_CHECK_EOF=1)
else()
add_compile_definitions(SIMDJSON_CHECK_EOF=0)
endif()
option(SIMDJSON_SANITIZE_UNDEFINED "Sanitize undefined behavior" OFF)
if(SIMDJSON_SANITIZE_UNDEFINED)
add_compile_options(-fsanitize=undefined -fno-sanitize-recover=all)
@@ -175,18 +182,6 @@ if(CMAKE_C_COMPILER_ID MATCHES "Intel")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -static-intel")
endif()
option(
SIMDJSON_AVX512_ALLOWED
"Enable AVX-512 instructions (only affects processors and compilers with AVX-512 support)."
ON
)
if(SIMDJSON_AVX512_ALLOWED)
add_compile_definitions(SIMDJSON_AVX512_ALLOWED=1)
else()
add_compile_definitions(SIMDJSON_AVX512_ALLOWED=0)
message(STATUS "AVX-512 instructions are not allowed.")
endif()
include(CheckSymbolExists)
check_symbol_exists(fork unistd.h HAVE_POSIX_FORK)
check_symbol_exists(wait sys/wait.h HAVE_POSIX_WAIT)
+2 -2
View File
@@ -1,7 +1,7 @@
#
# Implementation selection
#
set(SIMDJSON_ALL_IMPLEMENTATIONS fallback westmere haswell icelake arm64 ppc64)
set(SIMDJSON_ALL_IMPLEMENTATIONS fallback westmere haswell arm64 ppc64)
set(
SIMDJSON_IMPLEMENTATION ""
@@ -15,7 +15,7 @@ set(
SIMDJSON_EXCLUDE_IMPLEMENTATION ""
CACHE STRING "\
Semicolon-separated list of implementations to exclude \
(icelake/haswell/westmere/arm64/ppc64/fallback). By default, excludes any \
(haswell/westmere/arm64/ppc64/fallback). By default, excludes any \
implementations that are unsupported at compile time or cannot be selected at \
runtime."
)
+1 -2
View File
@@ -13,9 +13,8 @@ cmake_dependent_option(SIMDJSON_GOOGLE_BENCHMARKS "compile the Google Benchmark
if(SIMDJSON_GOOGLE_BENCHMARKS)
set_off(BENCHMARK_ENABLE_TESTING)
set_off(BENCHMARK_ENABLE_INSTALL)
set_off(BENCHMARK_ENABLE_WERROR)
import_dependency(google_benchmarks google/benchmark f91b6b4)
import_dependency(google_benchmarks google/benchmark 8982e1e)
add_dependency(google_benchmarks)
endif()
+392 -864
View File
File diff suppressed because it is too large Load Diff
-2
View File
@@ -1,5 +1,3 @@
We take our documentation seriously. Please start reading the documentation before you attempt to use simdjson. We hope you will enjoy reading us.
* Basics: https://github.com/simdjson/simdjson/blob/master/doc/basics.md is an overview of how to use simdjson and its APIs.
* parse_many: https://github.com/simdjson/simdjson/blob/master/doc/parse_many.md describes an interface providing features to work with files or streams containing multiple small JSON documents. As fast and convenient as possible.
* Performance: https://github.com/simdjson/simdjson/blob/master/doc/performance.md shows some more advanced scenarios and how to tune for them.
+31 -66
View File
@@ -3,8 +3,8 @@ The Document-Object-Model (DOM) front-end
An overview of what you need to know to use simdjson, with examples.
* [DOM vs On Demand](#dom-vs-on-demand)
* [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents-using-the-dom-front-end)
* [DOM vs On Demand](#dom-vs-ondemand)
* [The Basics: Loading and Parsing JSON Documents](#the-basics-loading-and-parsing-json-documents)
* [Using the Parsed JSON](#using-the-parsed-json)
* [C++17 Support](#c17-support)
* [JSON Pointer](#json-pointer)
@@ -15,7 +15,6 @@ An overview of what you need to know to use simdjson, with examples.
* [Reusing the parser for maximum efficiency](#reusing-the-parser-for-maximum-efficiency)
* [Server Loops: Long-Running Processes and Memory Capacity](#server-loops-long-running-processes-and-memory-capacity)
* [Best Use of the DOM API](#best-use-of-the-dom-api)
* [Padding and Temporary Copies](#padding-and-temporary-copies)
DOM vs On Demand
----------------------------------------------
@@ -36,12 +35,11 @@ dom::parser parser;
dom::element doc = parser.load(filename); // load and parse a file
```
Or by creating a padded string (for efficiency reasons, simdjson requires a string with
SIMDJSON_PADDING bytes at the end) and calling `parse()`:
Or by creating a string and calling `parse()`:
```c++
dom::parser parser;
dom::element doc = parser.parse("[1,2,3]"_padded); // parse a string, the _padded suffix creates a simdjson::padded_string instance
dom::element doc = parser.parse(std::string("[1,2,3]")); // parse a string
```
The parsed document resulting from the `parser.load` and `parser.parse` calls depends on the `parser` instance. Thus the `parser` instance must remain in scope. Furthermore, you must have at most one parsed document in play per `parser` instance.
@@ -54,8 +52,7 @@ During the`load` or `parse` calls, neither the input file nor the input string a
For best performance, a `parser` instance should be reused over several files: otherwise you will needlessly reallocate memory, an expensive process. It is also possible to avoid entirely memory allocations during parsing when using simdjson. [See our performance notes for details](performance.md).
If you need a lower-level interface, you may call the function `parser.parse(const char * p, size_t l)` on a pointer `p` while specifying the
length of your input `l` in bytes. To see how to get the very best performance from a low-level approach, you way want to read our [performance notes](https://github.com/simdjson/simdjson/blob/master/doc/performance.md#padding-and-temporary-copies) on this topic (see the Padding and Temporary Copies section).
length of your input `l` in bytes.
Using the Parsed JSON
---------------------
@@ -64,12 +61,12 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
* **Extracting Values (with exceptions):** You can cast a JSON element to a native type: `double(element)` or
`double x = json_element`. This works for double, uint64_t, int64_t, bool,
dom::object and dom::array. An exception (`simdjson::simdjson_error`) is thrown if the cast is not possible.
dom::object and dom::array. An exception is thrown if the cast is not possible.
* **Extracting Values (without exceptions):** You can use a variant usage of `get()` with error codes to avoid exceptions. You first declare the variable of the appropriate type (`double`, `uint64_t`, `int64_t`, `bool`,
`dom::object` and `dom::array`) and pass it by reference to `get()` which gives you back an error code: e.g.,
```c++
simdjson::error_code error;
simdjson::padded_string numberstring = "1.2"_padded; // our JSON input ("1.2")
std::string numberstring = "1.2"; // our JSON input ("1.2")
simdjson::dom::parser parser;
double value; // variable where we store the value to be parsed
error = parser.parse(numberstring).get(value);
@@ -81,7 +78,7 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
know the type of the value, you can cast it right there, too! `for (double value : array) { ... }`
* **Object Iteration:** You can iterate through an object's fields, too: `for (auto [key, value] : object)`
* **Array Index:** To get at an array value by index, use the at() method: `array.at(0)` gets the
first element. The at() method has linear-time complexity so it should not be used to iterate over the values of an array.
first element.
> Note that array[0] does not compile, because implementing [] gives the impression indexing is a
> O(1) operation, which it is not presently in simdjson. Instead, you should iterate over the elements
> using a for-loop, as in our examples.
@@ -96,11 +93,11 @@ Once you have an element, you can navigate it with idiomatic C++ iterators, oper
The following code illustrates all of the above:
```c++
auto cars_json = R"( [
std::string cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
] )";
dom::parser parser;
// Iterating through an array of objects
@@ -129,10 +126,10 @@ for (dom::object car : parser.parse(cars_json)) {
Here is a different example illustrating the same ideas:
```C++
auto abstract_json = R"( [
std::string abstract_json = R"( [
{ "12345" : {"a":12.34, "b":56.78, "c": 9998877} },
{ "12545" : {"a":11.44, "b":12.78, "c": 11111111} }
] )"_padded;
] )";
dom::parser parser;
// Parse and iterate through an array of objects
@@ -151,8 +148,8 @@ And another one:
```C++
auto abstract_json = R"(
{ "str" : { "123" : {"abc" : 3.14 } } } )"_padded;
std::string abstract_json = R"(
{ "str" : { "123" : {"abc" : 3.14 } } } )";
dom::parser parser;
double v = parser.parse(abstract_json)["str"]["123"]["abc"];
cout << "number: " << v << endl;
@@ -165,7 +162,7 @@ C++17 Support
While the simdjson library can be used in any project using C++ 11 and above, field iteration has special support C++ 17's destructuring syntax. For example:
```c++
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
std::string json = R"( { "foo": 1, "bar": 2 } )";
dom::parser parser;
dom::object object;
auto error = parser.parse(json).get(object);
@@ -179,7 +176,7 @@ For comparison, here is the C++ 11 version of the same code:
```c++
// C++ 11 version for comparison
padded_string json = R"( { "foo": 1, "bar": 2 } )"_padded;
std::string json = R"( { "foo": 1, "bar": 2 } )";
dom::parser parser;
dom::object object;
auto error = parser.parse(json).get(object);
@@ -197,11 +194,11 @@ The simdjson library also supports [JSON pointer](https://tools.ietf.org/html/rf
`at_pointer()` method, letting you reach further down into the document in a single call:
```c++
auto cars_json = R"( [
std::string cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
] )";
dom::parser parser;
dom::element cars = parser.parse(cars_json);
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
@@ -218,11 +215,11 @@ You can apply a JSON path to any node and the path gets interpreted relatively,
Consider the following example:
```c++
auto cars_json = R"( [
std::string cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
] )";
dom::parser parser;
dom::element cars = parser.parse(cars_json);
cout << cars.at_pointer("/0/tire_pressure/1") << endl; // Prints 39.9
@@ -249,11 +246,7 @@ auto error = parser.parse(json).get(doc);
if (error) { cerr << error << endl; exit(1); }
```
When there is no error, the error code simdjson::SUCCESS is returned: it evaluates as false as a Boolean.
We have several error codes to indicate errors, they all evaluate to true as a Boolean: your software should not generally not depend on exact
error codes. We may change the error codes in future releases and the exact error codes could vary depending on your system.
When you use the code without exceptions, it is your responsibility to check for error before using the
When you use the code this way, it is your responsibility to check for error before using the
result: if there is an error, the result value will not be valid and using it will caused undefined
behavior.
@@ -278,7 +271,6 @@ Our program loads the file, selects value corresponding to key "search_metadata"
it selects the key "count" within that object.
```C++
#include <iostream>
#include "simdjson.h"
int main(void) {
@@ -306,7 +298,6 @@ triggering exceptions. To do this, we use `["statuses"].at(0)["id"]`. We break t
Observe how we use the `at` method when querying an index into an array, and not the bracket operator.
```C++
#include <iostream>
#include "simdjson.h"
int main(void) {
@@ -322,19 +313,16 @@ int main(void) {
}
```
The `at()` method has linear-time complexity: it should not be used to iterate
over the content of an array.
### Error Handling Example
This is how the example in "Using the Parsed JSON" could be written using only error code checking:
```c++
auto cars_json = R"( [
std::string cars_json = R"( [
{ "make": "Toyota", "model": "Camry", "year": 2018, "tire_pressure": [ 40.1, 39.9, 37.7, 40.4 ] },
{ "make": "Kia", "model": "Soul", "year": 2012, "tire_pressure": [ 30.1, 31.0, 28.6, 28.7 ] },
{ "make": "Toyota", "model": "Tercel", "year": 1999, "tire_pressure": [ 29.8, 30.0, 30.2, 30.5 ] }
] )"_padded;
] )";
dom::parser parser;
dom::array cars;
auto error = parser.parse(cars_json).get(cars);
@@ -377,10 +365,10 @@ for (dom::element car_element : cars) {
Here is another example:
```C++
auto abstract_json = R"( [
std::string abstract_json = R"( [
{ "12345" : {"a":12.34, "b":56.78, "c": 9998877} },
{ "12545" : {"a":11.44, "b":12.78, "c": 11111111} }
] )"_padded;
] )";
dom::parser parser;
dom::array array;
auto error = parser.parse(abstract_json).get(array);
@@ -410,8 +398,8 @@ for (dom::element elem : array) {
And another one:
```C++
auto abstract_json = R"(
{ "str" : { "123" : {"abc" : 3.14 } } } )"_padded;
std::string abstract_json = R"(
{ "str" : { "123" : {"abc" : 3.14 } } } )";
dom::parser parser;
double v;
auto error = parser.parse(abstract_json)["str"]["123"]["abc"].get(v);
@@ -466,7 +454,6 @@ program from continuing if there was an error.
If one is willing to trigger exceptions, it is possible to write simpler code:
```C++
#include <iostream>
#include "simdjson.h"
int main(void) {
@@ -546,15 +533,16 @@ you can parse terabytes of JSON data without doing any new allocation.
dom::parser parser;
// This initializes buffers and a document big enough to handle this JSON.
dom::element doc = parser.parse("[ true, false ]"_padded);
dom::element doc = parser.parse(std::string("[ true, false ]"));
// std::string("[ true, false ]") may be replaced by "[ true, false ]"s
cout << doc << endl;
// This reuses the existing buffers, and reuses and *overwrites* the old document
doc = parser.parse("[1, 2, 3]"_padded);
doc = parser.parse(std::string("[1, 2, 3]"));
cout << doc << endl;
// This also reuses the existing buffers, and reuses and *overwrites* the old document
dom::element doc2 = parser.parse("true"_padded);
dom::element doc2 = parser.parse(std::string("true"));
// Even if you keep the old reference around, doc and doc2 refer to the same document.
cout << doc << endl;
cout << doc2 << endl;
@@ -620,26 +608,3 @@ Best Use of the DOM API
-------------------------
The simdjson API provides access to the JSON DOM (document-object-model) content as a tree of `dom::element` instances, each representing an object, an array or an atomic type (null, true, false, number). These `dom::element` instances are lightweight objects (e.g., spanning 16 bytes) and it might be advantageous to pass them by value, as opposed to passing them by reference or by pointer.
Padding and Temporary Copies
--------------
The simdjson function `parser.parse` reads data from a padded buffer, containing SIMDJSON_PADDING extra bytes added at the end.
If you are passing a `padded_string` to `parser.parse` or loading the JSON directly from
disk (`parser.load`), padding is automatically handled.
When calling `parser.parse` on a pointer (e.g., `parser.parse(my_char_pointer, my_length_in_bytes)`) a temporary copy is made by default with adequate padding and you, again, do not need to be concerned with padding.
Some users may not be able use our `padded_string` class or to load the data directly from disk (`parser.load`). They may need to pass data pointers to the library. If these users wish to avoid temporary copies and corresponding temporary memory allocations, they may want to call `parser.parse` with the `realloc_if_needed` parameter set to false (e.g., `parser.parse(my_char_pointer, my_length_in_bytes, false)`). In such cases, they need to ensure that there are at least SIMDJSON_PADDING extra bytes at the end that can be safely accessed and read. They do not need to initialize the padded bytes to any value in particular. The following example is safe:
```C++
const char *json = R"({"key":"value"})";
const size_t json_len = std::strlen(json);
std::unique_ptr<char[]> padded_json_copy{new char[json_len + SIMDJSON_PADDING]};
memcpy(padded_json_copy.get(), json, json_len);
memset(padded_json_copy.get() + json_len, 0, SIMDJSON_PADDING);
simdjson::dom::parser parser;
simdjson::dom::element element = parser.parse(padded_json_copy.get(), json_len, false);
````
Setting the `realloc_if_needed` parameter `false` in this manner may lead to better performance since copies are avoided, but it requires that the user takes more responsibilities: the simdjson library cannot verify that the input buffer was padded with SIMDJSON_PADDING extra bytes.
+14 -15
View File
@@ -17,7 +17,6 @@ different version of the JSON parser for different CPU architectures, often with
algorithms to take better advantage of a given CPU!
The current implementations are:
* icelake: AVX-512F, AVX-512VBMI, etc.
* haswell: AVX2 (2013 Intel Haswell or later)
* westmere: SSE4.2 (2010 Westmere or later).
* arm64: 64-bit ARMv8-A NEON
@@ -29,7 +28,7 @@ compiles *all* the implementations into the executable. On Intel, it will includ
(haswell, westmere and fallback), on ARM it will include 2 (arm64 and fallback), and on PPC it will include 2 (ppc64 and fallback).
If you know more about where you're going to run and want to save the space, you can disable any of
these implementations at compile time with `-DSIMDJSON_IMPLEMENTATION_X=0` (where X is ICELAKE, HASWELL,
these implementations at compile time with `-DSIMDJSON_IMPLEMENTATION_X=0` (where X is HASWELL,
WESTMERE, ARM64, PPC64 and FALLBACK).
The simdjson library automatically sets header flags for each implementation as it compiles; there
@@ -51,9 +50,9 @@ Inspecting the Detected Implementation
You can check what implementation is running with `active_implementation`:
```c++
cout << "simdjson v" << SIMDJSON_STRINGIFY(SIMDJSON_VERSION) << endl;
cout << "Detected the best implementation for your machine: " << simdjson::get_active_implementation()->name();
cout << "(" << simdjson::get_active_implementation()->description() << ")" << endl;
cout << "simdjson v" << STRINGIFY(SIMDJSON_VERSION) << endl;
cout << "Detected the best implementation for your machine: " << simdjson::active_implementation->name();
cout << "(" << simdjson::active_implementation->description() << ")" << endl;
```
Implementation detection will happen in this case when you first call `name()`.
@@ -64,7 +63,7 @@ Querying Available Implementations
You can list all available implementations, regardless of which one was selected:
```c++
for (auto implementation : simdjson::get_available_implementations()) {
for (auto implementation : simdjson::available_implementations) {
cout << implementation->name() << ": " << implementation->description() << endl;
}
```
@@ -72,10 +71,10 @@ for (auto implementation : simdjson::get_available_implementations()) {
And look them up by name:
```c++
cout << simdjson::get_available_implementations()["fallback"]->description() << endl;
cout << simdjson::available_implementations["fallback"]->description() << endl;
```
Though the fallback implementation should always be available, others might be missing. When
an implementation is not available, the bracket call `simdjson::get_available_implementations()[name]`
an implementation is not available, the bracket call `simdjson::available_implementations[name]`
will return the null pointer.
The available implementations have been compiled but may not necessarily be run safely on your system
@@ -91,18 +90,18 @@ can select the CPU architecture yourself:
```c++
// Use the fallback implementation, even though my machine is fast enough for anything
simdjson::get_active_implementation() = simdjson::get_available_implementations()["fallback"];
simdjson::active_implementation = simdjson::available_implementations["fallback"];
```
You are responsible for ensuring that the requirements of the selected implementation match your current system.
Furthermore, you should check that the implementation is available before setting it to `simdjson::get_active_implementation()`
Furthermore, you should check that the implementation is available before setting it to `simdjson::active_implementation`
by comparing it with the null pointer.
```c++
auto my_implementation = simdjson::get_available_implementations()["haswell"];
auto my_implementation = simdjson::available_implementations["haswell"];
if(! my_implementation) { exit(1); }
if(! my_implementation->supported_by_runtime_system()) { exit(1); }
simdjson::get_active_implementation() = my_implementation;
simdjson::active_implementation = my_implementation;
```
Checking that an Implementation can Run on your System
@@ -111,12 +110,12 @@ Checking that an Implementation can Run on your System
You should call `supported_by_runtime_system()` to compare the processor's features with the need of the implementation.
```c++
for (auto implementation : simdjson::get_available_implementations()) {
for (auto implementation : simdjson::available_implementations) {
if(implementation->supported_by_runtime_system()) {
cout << implementation->name() << ": " << implementation->description() << endl;
}
}
```
The call to `supported_by_runtime_system()` may be relatively expensive. Do not call `supported_by_runtime_system()` each
time you parse a JSON input (for example). It is meant to be called a handful of times at most in the life of a program.
The call to `supported_by_runtime_system()` maybe relatively expensive. Do not call `supported_by_runtime_system()` each
time you parse a JSON input (for example). It is meant to be called a handful of times at most in the life of a program.
+7 -17
View File
@@ -1,16 +1,8 @@
iterate_many
==========
When serializing large databases, it is often better to write out many independent JSON
documents, instead of one large monolithic document containing many records. The simdjson
library provides high-speed access to files or streams containing multiple small JSON documents separated by ASCII white-space characters. Given an input such as
```JSON
{"text":"a"}
{"text":"b"}
{"text":"c"}
...
```
... you want to read the entries (individual JSON documents) as quickly and as conveniently as possible. Importantly, the input might span several gigabytes, but you want to use a small (fixed) amount of memory. Ideally, you'd also like the parallelize the processing (using more than one core) to speed up the process.
An interface providing features to work with files or streams containing multiple small JSON documents.
As fast and convenient as possible.
Contents
--------
@@ -116,9 +108,7 @@ Whitespace Characters:
- **Linefeed**
- **Carriage return**
- **Horizontal tab**
If your documents are all objects or arrays, then you may even have nothing between them.
E.g., `[1,2]{"32":1}` is recognized as two documents.
- **Nothing**
Some official formats **(non-exhaustive list)**:
- [Newline-Delimited JSON (NDJSON)](http://ndjson.org/)
@@ -177,7 +167,7 @@ Let us illustrate the idea with code:
```C++
auto json = R"([1,2,3] {"1":1,"2":3,"4":4} [1,2,3] )"_padded;
std::string json = R"([1,2,3] {"1":1,"2":3,"4":4} [1,2,3] )";
simdjson::ondemand::parser parser;
simdjson::ondemand::document_stream stream;
auto error = parser.iterate_many(json).get(stream);
@@ -185,7 +175,7 @@ Let us illustrate the idea with code:
auto i = stream.begin();
size_t count{0};
for(; i != stream.end(); ++i) {
auto doc = *i;
auto & doc = *i;
if(!i.error()) {
std::cout << "got full document at " << i.current_index() << std::endl;
std::cout << i.source() << std::endl;
@@ -218,7 +208,7 @@ Some users may need to work with truncated streams. The simdjson may truncate do
Consider the following example where a truncated document (`{"key":"intentionally unclosed string `) containing 39 bytes has been left within the stream. In such cases, the first two whole documents are parsed and returned, and the `truncated_bytes()` method returns 39.
```C++
auto json = R"([1,2,3] {"1":1,"2":3,"4":4} {"key":"intentionally unclosed string )"_padded;
std::string json = R"([1,2,3] {"1":1,"2":3,"4":4} {"key":"intentionally unclosed string )";
simdjson::ondemand::parser parser;
simdjson::ondemand::document_stream stream;
auto error = parser.iterate_many(json,json.size()).get(stream);
@@ -236,4 +226,4 @@ This will print:
39 bytes
```
Importantly, you should only call `truncated_bytes()` after iterating through all of the documents since the stream cannot tell whether there are truncated documents at the very end when it may not have accessed that part of the data yet.
Importantly, you should only call `truncated_bytes()` after iterating through all of the documents since the stream cannot tell whether there are truncated documents at the very end when it may not have accessed that part of the data yet.
+37
View File
@@ -709,6 +709,42 @@ in production systems:
}
```
### Long-Running Processes and Memory Capacity
The On Demand approach also automatically expands its memory capacity when larger documents are parsed. However, for longer processes where very large files are processed (such as server loops), this capacity is not resized down. Similarly to the DOM-based approach (see [here](https://github.com/simdjson/simdjson/blob/master/doc/dom.md#server-loops-long-running-processes-and-memory-capacity)]), On Demand also lets you adjust the maximal capacity that the parser can process:
* You can set an upper bound (*max_capacity*) when construction the parser:
```C++
ondemand::parser parser(1000*1000); // Never grows past documents > 1 MB
auto doc = parser.iterate(json);
for (web_request request : listen()) {
padded_string json;
padded_string json = padded_string::load(request.body);
auto error = parser.iterate(json);
// If the document was above our limit, emit 413 = payload too large
if (error == CAPACITY) { request.respond(413); continue; }
// ...
}
```
The capacity will grow as the parser encounters larger documents up to 1 MB.
* You can also allocate a *fixed capacity* that will never grow:
```C++
ondemand::parser parser(1000*1000);
parser.allocate(1000*1000) // Fix the capacity to 1 MB
auto doc = parser.iterate(json);
for (web_request request : listen()) {
padded_string json;
padded_string json = padded_string::load(request.body);
auto error = parser.iterate(json);
// If the document was above our limit, emit 413 = payload too large
if (error == CAPACITY) { request.respond(413); continue; }
// ...
}
```
You can also manually set the maximal capacity using the method `set_max_capacity()`.
### Benefits of the On Demand Approach
We expect that the On Demand approach has many of the performance benefits of the schema-based approach, while providing a flexibility that is similar to that of the DOM-based approach.
@@ -728,6 +764,7 @@ There are currently additional technical limitations which we expect to resolve
* The simdjson library offers runtime dispatching which allows you to compile one binary and have it run at full speed on different processors, taking advantage of the specific features of the processor. The On Demand API has limited runtime dispatch support. Under x64 systems, to fully benefit from the On Demand API, we recommend that you compile your code for a specific processor. E.g., if your processor supports AVX2 instructions, you should compile your binary executable with AVX2 instruction support (by using your compiler's commands). If you are sufficiently technically proficient, you can implement runtime dispatching within your application, by compiling your On Demand code for different processors.
* There is an initial phase which scans the entire document quickly, irrespective of the size of the document. We plan to break this phase into distinct steps for large files in a future release as we have done with other components of our API (e.g., `parse_many`).
* The On Demand API does not support JSON Pointer. This capability is currently limited to our core API.
### Applicability of the On Demand Approach
+5 -11
View File
@@ -1,14 +1,8 @@
parse_many
==========
An interface providing features to work with files or streams containing multiple small JSON documents. Given an input such as
```JSON
{"text":"a"}
{"text":"b"}
{"text":"c"}
...
```
... you want to read the entries (individual JSON documents) as quickly and as conveniently as possible. Importantly, the input might span several gigabytes, but you want to use a small (fixed) amount of memory. Ideally, you'd also like the parallelize the processing (using more than one core) to speed up the process.
An interface providing features to work with files or streams containing multiple small JSON documents.
As fast and convenient as possible.
Contents
--------
@@ -180,7 +174,7 @@ Let us illustrate the idea with code:
```C++
auto json = R"([1,2,3] {"1":1,"2":3,"4":4} [1,2,3] )"_padded;
std::string json = R"([1,2,3] {"1":1,"2":3,"4":4} [1,2,3] )";
simdjson::dom::parser parser;
simdjson::dom::document_stream stream;
auto error = parser.parse_many(json).get(stream);
@@ -221,7 +215,7 @@ Some users may need to work with truncated streams. The simdjson may truncate do
Consider the following example where a truncated document (`{"key":"intentionally unclosed string `) containing 39 bytes has been left within the stream. In such cases, the first two whole documents are parsed and returned, and the `truncated_bytes()` method returns 39.
```C++
auto json = R"([1,2,3] {"1":1,"2":3,"4":4} {"key":"intentionally unclosed string )"_padded;
std::string json = R"([1,2,3] {"1":1,"2":3,"4":4} {"key":"intentionally unclosed string )";
simdjson::dom::parser parser;
simdjson::dom::document_stream stream;
auto error = parser.parse_many(json,json.size()).get(stream);
@@ -233,4 +227,4 @@ Consider the following example where a truncated document (`{"key":"intentionall
```
Importantly, you should only call `truncated_bytes()` after iterating through all of the documents since the stream cannot tell whether there are truncated documents at the very end when it may not have accessed that part of the data yet.
Importantly, you should only call `truncated_bytes()` after iterating through all of the documents since the stream cannot tell whether there are truncated documents at the very end when it may not have accessed that part of the data yet.
+12 -53
View File
@@ -10,7 +10,7 @@ are still some scenarios where tuning can enhance performance.
* [Large files and huge page support](#large-files-and-huge-page-support)
* [Number parsing](#number-parsing)
* [Visual Studio](#visual-studio)
* [Power Usage and Downclocking](#power-usage-and-downclocking)
* [Downclocking](#downclocking)
Reusing the parser for maximum efficiency
-----------------------------------------
@@ -24,14 +24,14 @@ you can parse terabytes of JSON data without doing any new allocation.
ondemand::parser parser;
// This initializes buffers big enough to handle this JSON.
auto json = "[ true, false ]"_padded;
std::string json = "[ true, false ]";
auto doc = parser.iterate(json);
for(bool i : doc.get_array()) {
cout << i << endl;
}
// This reuses the existing buffers
auto number_json = "[1, 2, 3]"_padded;
std::string number_json = "[1, 2, 3]";
doc = parser.iterate(number_json);
for(int64_t i : doc.get_array()) {
cout << i << endl;
@@ -45,53 +45,10 @@ Reusing string buffers
We recommend against creating many `std::string` or `simdjson::padded_string` instances to store the JSON content in your application. [Creating many non-trivial objects is convenient but often surprisingly slow](https://lemire.me/blog/2020/08/08/performance-tip-constructing-many-non-trivial-objects-is-slow/). Instead, as much as possible, you should allocate (once or a few times) reusable memory buffers where you write your JSON content. If you have a buffer `json_str` (of type `char*`) allocated for `capacity` bytes and you store a JSON document spanning `length` bytes, you can pass it to simdjson as follows:
```c++
auto doc = parser.iterate(padded_string_view(json_str, length, capacity));
```
or simply
```c++
auto doc = parser.iterate(json_str, length, capacity);
auto doc = parser.iterate(json_str, length));
```
Server Loops: Long-Running Processes and Memory Capacity
---------------------------------
The On Demand approach also automatically expands its memory capacity when larger documents are parsed. However, for longer processes where very large files are processed (such as server loops), this capacity is not resized down. On Demand also lets you adjust the maximal capacity that the parser can process:
* You can set an upper bound (*max_capacity*) when construction the parser:
```C++
ondemand::parser parser(1000*1000); // Never grows past documents > 1 MB
auto doc = parser.iterate(json);
for (web_request request : listen()) {
padded_string json;
padded_string json = padded_string::load(request.body);
auto error = parser.iterate(json);
// If the document was above our limit, emit 413 = payload too large
if (error == CAPACITY) { request.respond(413); continue; }
// ...
}
```
The capacity will grow as the parser encounters larger documents up to 1 MB.
* You can also allocate a *fixed capacity* that will never grow:
```C++
ondemand::parser parser(1000*1000);
parser.allocate(1000*1000) // Fix the capacity to 1 MB
auto doc = parser.iterate(json);
for (web_request request : listen()) {
padded_string json;
padded_string json = padded_string::load(request.body);
auto error = parser.iterate(json);
// If the document was above our limit, emit 413 = payload too large
if (error == CAPACITY) { request.respond(413); continue; }
// ...
}
```
You can also manually set the maximal capacity using the method `set_max_capacity()`.
Large files and huge page support
---------------------------------
@@ -147,21 +104,23 @@ Recent versions of Microsoft Visual Studio on Windows provides support for the L
Under Windows, we also support the GNU GCC compiler via MSYS2. The performance of 64-bit MSYS2 under Windows excellent (on par with Linux).
Power Usage and Downclocking
Downclocking
--------------
The simdjson library relies on SIMD instructions. SIMD instructions are the public transportation of computing. Instead of using 4 distinct instructions to add numbers, you can replace them with a single instruction that does the same work. Though the one instruction is slightly more expensive, the energy used per unit of work is much less with SIMD. If you can increase your speed using SIMD instructions (NEON, SSE, AVX), you should expect to reduce your power usage.
SIMD instructions are the public transportation of computing. Instead of using 4 distinct instructions to add numbers, you can replace them with a single instruction that does the same work. Though the one instruction is slightly more expensive, the energy used per unit of work is much less with SIMD. If you can increase your speed using SIMD instructions (NEON, SSE, AVX), you should expect to reduce your power usage.
The SIMD instructions that simdjson relies upon (SSE and AVX under x64, NEON under ARM, ALTIVEC under PPC) are routinely part of runtime libraries (e.g., [Go](https://golang.org/src/runtime/memmove_amd64.s), [Glibc](https://github.com/ihtsae/glibc/commit/5f3d0b78e011d2a72f9e88b0e9ef5bc081d18f97), [LLVM](https://github.com/llvm/llvm-project/blob/96f3ea0d21b48ca088355db10d4d1a2e9bc9f884/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp), [Rust](https://github.com/rust-lang/rust/commit/070fad1701fb36b112853b0a6a9787a7bb7ff34c), [Java](http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/c1374141598c/src/cpu/x86/vm/stubGenerator_x86_64.cpp#l1297), [PHP](https://github.com/php/php-src/blob/e5cb53ec68603d4dbdd780fd3ecfca943b4fd383/ext/standard/string.c)). What distinguishes the simdjson library is that it is built from the ground up to benefit from these instructions.
You should not expect the simdjson library to cause *downclocking* of your recent Intel CPU cores. On some Intel processors, using SIMD instructions in a sustained manner on the same CPU core may result in a phenomenon called downclocking whereas the processor initially runs these instructions at a slow speed before reducing the frequency of the core for a short time (milliseconds). Intel refers to these states as licenses. On some current Intel processors, it occurs under two scenarios:
You should not expect the simdjson library to cause *downclocking* of your recent Intel CPU cores.
On some Intel processors, using SIMD instructions in a sustained manner on the same CPU core may result in a phenomenon called downclocking whereas the processor initially runs these instructions at a slow speed before reducing the frequency of the core for a short time (milliseconds). Intel refers to these states as licenses. On some current Intel processors, it occurs under two scenarios:
- [Whenever 512-bit AVX-512 instructions are used](https://lemire.me/blog/2018/09/07/avx-512-when-and-how-to-use-these-new-instructions/).
- Whenever heavy 256-bit or wider instructions are used. Heavy instructions are those involving floating point operations or integer multiplications (since these execute on the floating point unit).
The simdjson library does not make use of heavy 256-bit instructions. We do use vectorized multiplications, but only using 128-bit registers. Thus there should be no downclocking due to simdjson on recent processors, except when AVX-512 is allowed and
detected. However, we only allow AVX-512 on recent processors (Ice Lake/Tiger Lake or better) where [little to no frequency throttling is expected](https://travisdowns.github.io/blog/2020/08/19/icl-avx512-freq.html). If you can still concerned, you can easily disable AVX-512 with the CMake option `SIMDJSON_AVX512_ALLOWED` set to `OFF` (e.g., `cmake -D SIMDJSON_AVX512_ALLOWED=OFF -B build && cmake --build build`) or by setting
the macro `SIMDJSON_AVX512_ALLOWED` to `0` in C++ prior to importing the headers.
The simdjson library does not currently support AVX-512 instructions and it does not make use of heavy 256-bit instructions. We do use vectorized multiplications, but only using 128-bit registers. Thus there should be no downclocking due to simdjson on recent processors.
You may still be worried about which SIMD instruction set is used by simdjson. Thankfully, [you can always determine and change which architecture-specific implementation is used](implementation-selection.md) by simdjson. Thus even if your CPU supports AVX2, you do not need to use AVX2. You are in control.
+1 -2
View File
@@ -1,8 +1,7 @@
#include <iostream>
#include "simdjson.h"
int main(void) {
simdjson::dom::parser parser;
simdjson::dom::element tweets = parser.load("twitter.json");
std::cout << tweets["search_metadata"]["count"] << " results." << std::endl;
}
}
-1
View File
@@ -1,4 +1,3 @@
#include <iostream>
#include "simdjson.h"
int main(void) {
@@ -1,4 +1,3 @@
#include <iostream>
#include "simdjson.h"
int main(void) {
@@ -1,4 +1,3 @@
#include <iostream>
#include "simdjson.h"
int main(void) {
@@ -1,4 +1,3 @@
#include <iostream>
#include "simdjson.h"
using namespace simdjson;
int main(void) {
@@ -1,4 +1,3 @@
#include <iostream>
#include "simdjson.h"
using namespace simdjson;
int main(void) {
+2 -2
View File
@@ -18,7 +18,7 @@ The fuzzers are used in several ways.
* oss-fuzz - heavy duty 24/7 fuzzing provided by the google driven oss-fuzz project
## Local fuzzing
Just invoke fuzz/quick_check.sh, it will download the latest corpus (kept up to date by the CI fuzzers) and run the fuzzers for a short time. In case you want to run the fuzzers for longer, modify the timeout value in the script or invoke the fuzzer directly.
Just invoke fuzz/quick_check.sh, it will download the latest corpus from bintray (kept up to date by the CI fuzzers) and run the fuzzers for a short time. In case you want to run the fuzzers for longer, modify the timeout value in the script or invoke the fuzzer directly.
This requires linux with clang and cmake installed (recent Debian and Ubuntu are known to work fine).
@@ -69,7 +69,7 @@ As little code as possible is kept at oss-fuzz since it is inconvenient to chang
The simdjson library does not benefit from a corpus as much as other projects, because the library is very fast and explores the input space very well. With that said, it is still beneficial to have one. The CI job stores the corpus on a remote server between runs, and is available at [www.pauldreik.se](https://readonly:readonly@www.pauldreik.se/fuzzdata/index.php?project=simdjson).
One can also grab the corpus as an artifact from the github actions job if you are logged in at github. Pick a run, then go to artifacts and download.
One can also grab the corpus as an artifact from the github actions job. Pick a run, then go to artifacts and download.
## Fuzzing coverage
+1 -2
View File
@@ -11,7 +11,6 @@
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <string>
#include <array>
#include "supported_implementations.h"
@@ -93,7 +92,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
std::size_t nerrors=0;
for(std::size_t i=0; i<Nimplementations; ++i) {
auto& e=implementations[i];
simdjson::get_active_implementation()=e.impl;
simdjson::active_implementation=e.impl;
e.error=e.parser.parse(Data,Size).get(e.element);
if(e.error) {
++nerrors;
-1
View File
@@ -12,7 +12,6 @@
#include "simdjson.h"
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <vector>
#include "supported_implementations.h"
+15 -17
View File
@@ -8,26 +8,24 @@
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
FuzzData fd(Data, Size);
const auto batch_size = static_cast<size_t>(fd.getInt<0,1000>());
const auto json = simdjson::padded_string{fd.remainder_as_stringview()};
const auto batch_size=static_cast<size_t>(fd.getInt<0,1000>());
const auto json=simdjson::padded_string{fd.remainder_as_stringview()};
simdjson::dom::parser parser;
simdjson::dom::document_stream docs;
if(parser.parse_many(json,batch_size).get(docs)) { return 0; }
size_t bool_count1 = 0;
size_t total_count1 = 0;
#if SIMDJSON_EXCEPTIONS
try {
#endif
simdjson::dom::document_stream docs;
if(parser.parse_many(json,batch_size).get(docs)) {
return 0;
}
size_t bool_count=0;
for (auto doc : docs) {
total_count1++;
bool_count1 += doc.is_bool();
bool_count+=doc.is_bool();
}
// Restart, if we made it this far, the document *must* be accessible.
if(parser.parse_many(json,batch_size).get(docs)) { return EXIT_FAILURE; }
size_t bool_count2 = 0;
size_t total_count2 = 0;
for (auto doc : docs) {
total_count2++;
bool_count2 += doc.is_bool();
#if SIMDJSON_EXCEPTIONS
} catch(...) {
}
// They should agree!!!
if((total_count2 != total_count1) || (bool_count2 != bool_count1)) { return EXIT_FAILURE; }
#endif
return 0;
}
-1
View File
@@ -10,7 +10,6 @@
#include "simdjson.h"
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include "supported_implementations.h"
extern "C" int VerboseTestOneInput(const uint8_t *Data, size_t Size) {
+5 -4
View File
@@ -4,7 +4,7 @@
# good when working locally developing the fuzzers or making
# sure code changes still pass the fuzzers.
#
# It will download the corpus from external store (kept up to date
# It will download the corpus from bintray (kept up to date
# by the crontab github actions) unless a local out/ directory
# already exists.
#
@@ -23,9 +23,10 @@ done
#download the corpus if it does not already exist
if [ ! -d out ] ; then
# the corpus is also available for download from the artifacts page on https://github.com/simdjson/simdjson/actions/workflows/fuzzers.yml
# but that requires being logged in so can not be easily done from this script.
wget -O - https://readonly:readonly@www.pauldreik.se/fuzzdata/index.php?project=simdjson |tar xzf -
# ideally, we would download the github artifact but that requires being logged in which can not
# easily be fixed from this shell script.
echo "NOTE! please go to the artifacts page on https://github.com/simdjson/simdjson/actions/workflows/fuzzers.yml and download the latest corpus.tar.zip artifact manually to speed up fuzzing"
sleep 5s
fi
# By default, use the debug friendly variant since this script is intended
+1 -1
View File
@@ -17,7 +17,7 @@
std::vector<const simdjson::implementation*>
get_runtime_supported_implementations() {
std::vector<const simdjson::implementation*> ret;
for(auto& e: simdjson::get_available_implementations()) {
for(auto& e: simdjson::available_implementations) {
if(e->supported_by_runtime_system()) {
ret.emplace_back(e);
}

Some files were not shown because too many files have changed in this diff Show More