Compare commits

...

854 Commits

Author SHA1 Message Date
Daniel Lemire a410c723c8 Patch release. 2022-05-26 16:25:57 -04:00
Daniel Lemire f91a1ae07e Let us time minify and make sure AVX-512 is used by default. (#1830)
* Let us time minify
* Making AVX-512 available by default.
* Silencing some maybe-uninitialized warning under GCC (warning appears in the standard library).
* Making the Python amalgamation script a bit more Windows friendly.
* We do not try to silence -Wmaybe-uninitialized under clang.
2022-05-26 16:15:49 -04:00
Daniel Lemire c3954b1fb8 Update README.md 2022-05-25 17:25:01 -04:00
Daniel Lemire ce74ece545 Preparing release. 2022-05-25 11:43:06 -04:00
Daniel Lemire dd4dce848e Update CONTRIBUTORS 2022-05-25 11:24:40 -04:00
Daniel Lemire e8f370b085 Basic AVX-512 implementation (icelake or better) (#1813)
* Add cascadelake implementation, which use AVX512 Intrinsics to optimize performance(#1811)

Co-authored-by: mellonyou <fangzheng.zhang@intel.com>
Co-authored-by: wanweiqiangintel <weiqiang.wan@intel.com>
2022-05-25 11:14:02 -04:00
Daniel Lemire 645033a8c8 This runs the streaming amazon benchmarks in two modes: threaded and (#1828)
unthreaded. In the large case, we find that the threaded scenario with
ondemand has a 40% speed benefit over the unthreaded scenario.
2022-05-24 17:06:54 -04:00
Daniel Lemire 3b5ceeb80d Making the python script more robust. (#1827) 2022-05-20 13:32:15 -04:00
Dirk Stolle 82433a67f9 fix a few typos (#1829) 2022-05-20 13:31:30 -04:00
Daniel Lemire 8c1bfe782b Adds 'current_depth()'. (#1824) 2022-05-17 18:06:42 -04:00
Daniel Lemire 730939f01c Better documentation regarding the direct get_number_type() method. (#1821) 2022-05-13 15:31:09 -04:00
Daniel Lemire b169dc2ea7 Fixing get_number_type() (#1819) 2022-05-12 12:15:38 -04:00
Andrea Pappacoda 1aa1d537fe docs(basics): ondemand::element -> ::document (#1810)
simdjson::ondemand::element doesn't exist
2022-05-05 14:55:22 -04:00
Richard Ebeling c122462278 [skip ci] Fix accidental pastes in doc/basics.md (#1809)
Co-authored-by: Richard Ebeling <He3lixxx@users.noreply.github.com>
2022-05-02 08:13:55 -04:00
Daniel Lemire b6b338bea9 This simplifies the build somewhat by always including developer-options.cmake (#1806) 2022-04-27 12:51:04 -04:00
Dirk Stolle f72636b5b0 fix a typo in documentation (#1807) 2022-04-26 18:01:12 -04:00
Daniel Lemire f6a2bac11b what happens if we remove this check for CI? (#1804) 2022-04-23 14:09:22 -04:00
Daniel Lemire e4ddc5446b Fixing typo. 2022-04-10 08:16:46 -04:00
PavelP e0e0aa9e7b Update simdjson.h to include simdjson_version.h (#1794)
After this change amalgamated simdjson.h has version info at the beginning of the file.
2022-03-19 08:00:24 -04:00
Daniel Lemire 9f0a2e0e86 Update to vs17 (required) (#1795)
* Update to vs17 (required)

* Moving to windows-latest.

* Dropping old vs
2022-03-19 08:00:06 -04:00
Andrei Gritsiuk 203c03e90b resolves #1784 - GCC 11.1.0 and CLang 12.0.0 complain on 'and' operator in padded_string-inl.h (#1785)
Co-authored-by: Andrei <C:\Users\Andrei\AppData\Roaming\The Bat!>
2022-01-31 11:38:54 -05:00
Ivan Volnov 6698eb96b9 Fix C++20 build warnings (#1782) (#1787)
* Fix C++20 build warnings (#1782)

* Build fix for ppc64 (#1782)
2022-01-20 14:16:27 -05:00
pkubaj 30f7de387c Fix build on FreeBSD/powerpc64* (#1786)
FreeBSD uses sys/endian.h and bswap64().
2022-01-18 11:21:47 -05:00
Piotr Doan e0788507fe Missing value::get() template specialization for number (#1779) 2022-01-11 12:07:20 -05:00
Daniel Lemire e4740c87fb Update README.md 2022-01-11 12:05:16 -05:00
Daniel Lemire 5beef701e7 Update CONTRIBUTORS 2022-01-03 15:55:47 -05:00
Daniel Lemire c6f9c93c33 Use static variables to enforce initialization order. (#1773) (#1777)
Fixes https://github.com/simdjson/simdjson/issues/1771

Co-authored-by: Hao Chen <chenhao.yalier@gmail.com>
2022-01-03 15:54:57 -05:00
Daniel Lemire 3a93e45dd1 Removing scoop support. 2021-12-30 12:10:11 -05:00
Daniel Lemire 6db8ceb46c Verify and fix 1768. (#1769)
* Verify and fix 1768.

* Breaking down the namespaces for C++11 compilers.
2021-12-21 15:12:38 -05:00
Daniel Lemire 23651f0d41 Updating a macro. 2021-12-21 09:54:02 -05:00
N. Kolotov 7e1893db42 Added SIMDJSON_ prefix to STRINGIFY and to NO_SANITIZE_UNDEFINED macros. (#1766) 2021-12-21 09:53:06 -05:00
Daniel Lemire b4b1927b0f Making the documentation more explicit. (#1765) 2021-12-21 09:51:20 -05:00
Daniel Lemire e275589832 Update implementation-selection.md 2021-12-07 13:15:05 -05:00
epoll-reactor 69ee84973a Fix some typos in source files. (#1761)
Co-authored-by: epoll-reactor <>
2021-12-06 16:56:15 -05:00
epoll-reactor 76bed68ec3 Fix broken link in basics documentation. (#1760) 2021-12-04 12:21:08 -05:00
epoll-reactor 003d970cd2 Fix -Wredundant-decls warning in json_type.h. (#1759)
Co-authored-by: threadpoolexecutor <davidkor77@gmail.com>
2021-12-02 13:49:48 -05:00
DavidKorczynski 4aaf3f030c Add CIFuzz integration (#1757)
Signed-off-by: David Korczynski <david@adalogics.com>
2021-11-30 10:14:26 -05:00
Daniel Lemire 2763f7e719 Fixing issue 1755 (#1756) 2021-11-24 09:28:28 -05:00
strager 39035c39be Fix typos in comments (#1754) 2021-11-19 09:44:10 -05:00
strager ac179ff40f Fix broken links in documentation (#1753) 2021-11-12 08:47:22 -05:00
Tyler Kennedy b41bece32c Fix a couple of broken links in the basics.md TOC (#1752) 2021-11-07 19:58:32 -05:00
Daniel Lemire 9cb0c5f92d Patching. (#1750) 2021-11-05 19:46:57 -04:00
Daniel Lemire 1dec7b04fe Remark. 2021-11-05 13:32:45 -04:00
strager c6eb6f98b8 Fix typos in documentation (#1747)
The variable is called LOG_ENABLED, not ENABLE_LOGGING. Fix the
documentation in json_iterator.h.
2021-11-03 10:13:13 -04:00
Daniel Lemire 1b01969bda Adding tests for issue 1745. (#1746)
* Adding tests for issue 1745.

* Tweaking the documentation so that it is clearer.
2021-11-03 10:12:18 -04:00
Daniel Lemire 17f3148ac7 Version 1.0.2. 2021-10-27 19:29:42 -04:00
Daniel Lemire 35b4a48e99 Fixing issue 1742 (#1743)
* Fix for issue 1742.

* Some additional tests.
2021-10-27 19:25:23 -04:00
mir4cle c0d18452fc Add an option to get current location from value (#1738)
Co-authored-by: Igor Logvanev <igor.logvanev@aimtech.team>
2021-10-24 16:55:49 -04:00
Daniel Lemire e5c9a310cf Preparing release 1.0.1. 2021-10-20 12:18:04 -04:00
Daniel Lemire 6d308a08c5 Fixing issue 1736 (#1737)
* Fixing issue 1736

* Updating google benchmark.

* Minor trimming.

* Using the variable (to silence a warning).

* Adding assignment operator.
2021-10-20 12:15:35 -04:00
Daniel Lemire 9e477ddb00 Let us try to improve the documentation so that it is clearer. (#1733)
* Let us try to improve the documentation so that it is clearer.

* Minor tweaks.
2021-10-19 13:09:41 -04:00
Daniel Lemire b7c4d1eeef Adding test for issue 1729. (#1730)
* Adding test for issue 1729.

* Adding comment.

* Trying to move to 11.7.

* Tweaking.

* More tweaking.

* Adding additional test.

* Missing "<<".

* Minor update.

* Removing legacy systems.
2021-10-13 09:30:37 -04:00
Daniel Lemire 4a2f10ebcf Let us trim out these legacy systems from CI. 2021-10-12 18:24:03 -04:00
Daniel Lemire 41cb909604 Minor change to handle paranoid compilers. (#1732) 2021-10-12 17:23:45 -04:00
Daniel Lemire 91908ade4d Additional documentation following issue 1723 (#1724)
* Some extra documentation regarding issue 1723.

* Adding comments.

* Minor fix.

* [no ci] more documentation
2021-10-09 11:41:20 -04:00
Daniel Lemire 9a32c48098 Cleaning up the single-header demo. (#1731)
* Cleaning up the single-header demo.

* Updating xcode
2021-10-09 11:34:21 -04:00
Daniel Lemire d996ffc494 Minor typo. (#1721)
* Minor typo.

* Minor fixes.

* Patching...
2021-09-25 11:34:44 -04:00
Daniel Lemire d56fdc3d04 [no ci] deleting an irrelevant comment. 2021-09-22 18:06:59 -04:00
Daniel Lemire 1dce4fed6e [no ci] moving documentation bit to the right location. (#1719) 2021-09-20 09:33:21 -04:00
Daniel Lemire cae5e5342f Additional ndjson tests. (#1717)
* Additional ndjson tests.

* Switching the data source.

* Fixing.
2021-09-18 16:29:10 -04:00
Madhur Chauhan 4e609aa955 fix redundant ; in document-inl.h (#1715) 2021-09-17 14:02:03 -04:00
Paul Dreik d28e5534d9 ignore unused variable (#1714) 2021-09-12 17:37:58 -04:00
Daniel Lemire 3bd8b0b575 Refreshing the single-header files. 2021-09-07 14:36:17 -04:00
Daniel Lemire af4ff7cc33 Adding fast "get_number_type()" function, bypassing "get_number()" (#1713)
* Adding fast "get_number_type" function, bypassing "get_number"

* Minor tweak.

* Adding missing get_number_type().
2021-09-07 14:34:40 -04:00
Nicolas Boyer c9179ad81d Add count_fields method for objects (#1712)
* Implement count_elements for object

* Add count_elements() for simdjson_result

* Add count_elements for documents(arrays,objects).

* Add tests for objects.

* Add tests for documents array. Typos.

* Renaming to count_fields() for objects.

* Update doc.

* Apply patch
2021-09-02 16:18:48 -04:00
Daniel Lemire d6b5124c88 Pushing the release 1.0.0 candidate. (#1709) 2021-09-01 15:25:45 -04:00
Dougall Johnson 64b62fd3b3 simd8x64::compress optimisation for Apple M1 (#1708)
* Optimized the arm64 implementation of simd8x64::compress

This is ~35% faster on the fast_minify benchmarks on Apple M1

* Return byte-count from simd8x64::compress

This avoids a redundant popcount on ARM, for ~3% faster minify
on Apple M1
2021-09-01 15:25:11 -04:00
Daniel Lemire cebe3fb299 Tweaking current_location(). (#1707)
* Tweaking current_location().

* Well.
2021-08-28 20:19:30 -04:00
Nicolas Boyer ed7343f7f2 Provide current location in JSON input (#1695)
* Setup.

* Add current_location().

* Make return simdjson_result and fix cast issues.

* Whitespace.

* Add broken JSON tests. Add null parser check.

* Remove unused variables.

* Alive fix.

* Fix merge issues.

* Simplification for out of bounds.

* More tests.

* Move pointer back for unrecoverable errors.

* Add new error OUT_OF_BOUNDS

* Remove unnecessary include and fix OUT_OF_BOUNDS.

* Add more tests. Fix unrecoverable errors.

* Fix tests.

* Modify one test.

* Update doc.

* Typos.

* Add read_me tests.

* Update doc.

* Add current_location for simdjson_result and document_reference

* Typos.

Co-authored-by: Daniel Lemire <lemire@gmail.com>
2021-08-27 13:41:59 -04:00
Daniel Lemire 35158257c6 Implementing get_number for the document instances. (#1706) 2021-08-27 10:26:01 -04:00
Daniel Lemire b935ce2e06 Allowing casts instead of get_double, get_uint64 and get_int64 (#1705) 2021-08-27 10:25:17 -04:00
Daniel Lemire 4afe7565b4 ondemand dynamically-typed numbers (#1704)
* Building up a number type.

* Implemented is_integer and is_negative.

* Implemented get_number in value_iterator.

* Final prototype.

* [no ci] typo
2021-08-26 12:16:44 -04:00
Daniel Lemire 6bed34ad61 This exposes 'reset' for object and array instances. (#1696)
* This exposes 'rewind' for object and array instances.

* Putting really_inline back to count_elements()

* Update array.h

* Adding empty array rewind.

* Adds "is_empty" method to arrays.

* More fragmentation.

* Tweaking implementation.

* Fixing issue with get_value() on document instances.

* Changing the name of the new rewind functions to reset.
2021-08-21 10:23:59 -04:00
Daniel Lemire 0ad52a7e22 Renaming scalar to is_scalar. (#1698) 2021-08-21 10:23:22 -04:00
Daniel Lemire aa52cf6868 Alive fix. (#1700) 2021-08-21 10:22:59 -04:00
Daniel Lemire cd11838e5f Update parse_many.md 2021-08-20 14:52:43 -04:00
Daniel Lemire c31157bafe Update iterate_many.md 2021-08-20 14:15:38 -04:00
Daniel Lemire 419b7b2ce8 Update parse_many.md 2021-08-20 14:09:54 -04:00
Daniel Lemire ca3f3cc49d Update iterate_many.md 2021-08-20 14:09:30 -04:00
Paul Dreik d3f0e2afb3 [no ci] remove references to bintray (#1702)
* download fuzz corpus from www.pauldreik.se

* remove reference to bintray
2021-08-19 08:39:07 -04:00
Daniel Lemire eac3832ec0 [no ci] removing space 2021-08-17 08:35:21 -04:00
Daniel Lemire db19c7675f [no ci] tweaking documentation 2021-08-15 10:32:11 -04:00
strager d036fdf919 Reduce #include bloat (<iostream>) (#1697)
Including <iostream> has two problems:

* Compile times are worse because of over-inclusion
* Binary sizes are worse when statically linking libstdc++ because
  iostreams cannot be dead-code-stripped

simdjson only needs std::ostream. Include the header declaring only what
we need (<ostream>), omitting stuff we don't need (std::cout and its
initialization, for example).

This commit should not change behavior, but it might break users who
assume that including <simdjson/simdjson.h> will make std::cout
available (such as many of simdjson's own files).
2021-08-13 11:24:36 -04:00
Daniel Lemire fc0934755a [no ci] Adding new "include <iostream>" lines in the documentation following the recent removal of iostream from our headers. 2021-08-13 11:23:16 -04:00
Daniel Lemire de4deb8c4e Makes it possible to cast a document to a value. (#1690)
* Makes it possible to cast a document to a value.
2021-08-11 20:02:30 -04:00
Daniel Lemire ba46616cbc Small test for document_reference usage. (#1694) 2021-08-10 21:08:59 -04:00
Daniel Lemire a552638373 removing trailing spaces 2021-08-10 15:12:05 -04:00
Daniel Lemire e30123d58f [no ci] 2021-08-10 15:02:51 -04:00
Daniel Lemire b7dee3e9c8 [no ci] remark 2021-08-09 13:04:20 -04:00
Daniel Lemire 717d0c24a6 [no ci] tuning documentation 2021-08-09 12:09:40 -04:00
Daniel Lemire 40813752f4 This will update the amalgamate_demo.cpp file to use On Demand. (#1689)
* This will update the amalgamate_demo.cpp file to use On Demand.

* Making the demo exceptionless.
2021-08-07 12:43:40 -04:00
Daniel Lemire 19902abaf8 Guarding first/second access. (#1688)
* Guarding first/second access.

* Correcting our own usage.

* Adding more documentation.
2021-08-06 20:25:05 -04:00
Daniel Lemire 06643fc9f5 Additional tests and document tuning (#1684)
* Additional example.

* Adds more tests.

* Actually using the variable.
2021-08-02 16:35:02 -04:00
Daniel Lemire 0fa68d8930 Fixing noexcept on operator << with simdjson_result. (#1678)
* Additional tests.

* Finishing touch.

* Extending to IO.
2021-07-31 17:54:27 -04:00
Daniel Lemire cc98358453 Adding error handing examples to the documentation (#1679)
* Adding error handing examples.

* Guarding the exception-throwing test.
2021-07-31 14:31:48 -04:00
Dirk Stolle 5f0b35b2c5 update string_view lite to version 1.6.0 (#1677)
This is the header as seen in the current master branch,
commit d27d7b5081406a35b41cb16b321be8833b4cd811, on
<https://github.com/martinmoene/string-view-lite>.
2021-07-31 11:19:51 -04:00
Daniel Lemire bd0f5e9322 [no ci] details 2021-07-30 18:20:37 -04:00
Daniel Lemire cb0e4b23c7 [no ci] clearing headings 2021-07-30 18:12:06 -04:00
Daniel Lemire d83e69d977 Fix an issue with truncated-byte function. (#1674) 2021-07-30 13:12:42 -04:00
Daniel Lemire f657516a7e Pruning some white spaces. 2021-07-27 13:16:18 -04:00
Daniel Lemire 8d29c5f931 [no ci] README update 2021-07-27 11:10:56 -04:00
Daniel Lemire eeac91579c [no ci] additional examples 2021-07-27 11:08:24 -04:00
Daniel Lemire e5a4b8b81b [no ci] minor indentation issue 2021-07-27 11:05:15 -04:00
Daniel Lemire 7b8f775893 Update basics.md 2021-07-27 11:04:01 -04:00
Daniel Lemire c6ef2105ab Minor tweak. 2021-07-27 10:56:05 -04:00
Daniel Lemire e681234e45 [no ci] update to power usage section 2021-07-27 10:30:19 -04:00
Daniel Lemire eb93b98d6a verify and fix issue 1668 (#1673)
* Adding test.

* Verifies and fix issue 1668. This commit updates the previous behavior of the
On Demand stream support by return a value type (document_reference) instead
of a reference to a document. This allows us to bridge with the usually simdjson
error system, with its simdjson_result types.

* Minor reformat.

* Adds a test with initial tests passing.

* Adding an example.
2021-07-27 08:51:07 -04:00
Nicolas Boyer 7d887fdc1e Parse numbers inside strings (#1667)
* Update basic.md to document JSON pointer for On Demand.

* Add automatic rewind for at_pointer

* Remove DOM examples in basics.md and update documentation reflecting addition of at_pointer automatic rewinding.

* Review

* Add test

* Naive implementation for doubles in string.

* Add double from string in atom doc.

* Simplification (removed all *_from_string())

* Add int and uint parsing in string.

* Make duplicates instead.

* Make tests exceptionless.

* Add missing declarations.

* Add more tests (errors, JSON pointer).

* Add crypto json tests.

* Update doc.

* Update doc after review.

Co-authored-by: Daniel Lemire <lemire@gmail.com>
2021-07-27 08:50:44 -04:00
Daniel Lemire 9d405a5df4 [skip ci] made requirements more precise 2021-07-26 08:47:21 -04:00
Daniel Lemire 18c003e8bf Adding CI for old LLVM in GitHub Actions (#1672)
* Adding CI for old LLVM

* Simplifying.
2021-07-26 08:37:29 -04:00
Daniel Lemire ec4316aa84 Adding macos testing. (#1670) 2021-07-25 12:25:31 -04:00
Daniel Lemire b79261eebc This cleans a bit the current code, especially with respect to EOF guards. (#1669)
* Upgrading the GitHub Actions.

* Upgrading appveyor

* Upgrading circle ci.

* Cleaning.
2021-07-25 10:36:22 -04:00
Daniel Lemire 47a62db559 Isolated jkeiser fix for issue 1632: make it so that INCORRECT_TYPE is a recoverable condition in On Demand (#1663) 2021-07-23 11:32:26 -04:00
Daniel Lemire 01645cbd69 Update bug_report.md 2021-07-22 13:22:49 -04:00
Daniel Lemire 3dbecab494 Trimming the documentation a bit. 2021-07-20 15:05:39 -04:00
Nicolas Boyer 5c590b8434 Bringing ndjson(document_stream) to On Demand (#1643)
* Update basic.md to document JSON pointer for On Demand.

* Add automatic rewind for at_pointer

* Remove DOM examples in basics.md and update documentation reflecting addition of at_pointer automatic rewinding.

* Review

* Add test

* Add document_stream constructors and iterate_many

* Attempt to implement streaming.

* Kind of fixed next() for getting next document

* Temporary save.

* Putting in working order.

* Add working doc_index and add function next_document()

* Attempt to implement streaming.

* Re-anchoring json_iterator after a call to stage 1

* I am convinced it should be a 'while'.

* Add source() with test.

* Add truncated_bytes().

* Fix casting issues.

* Fix old style cast.

* Fix privacy issue.

* Fix privacy issues.

* Again

* .

* Add more tests. Add error() for iterator class.

* Fix source() to not included whitespaces between documents.

* Fixing CI.

* Fix source() for multiple batches. Add new tests.

* Fix batch_start when document has leading spaces. Add new tests for that.

* Add new tests.

* Temporary save.

* Working hacky multithread version.

* Small fix in header files.

* Correct version (not working).

* Adding a move assignment to ondemand::parser.

* Fix attempt by changing std::swap.

* Moving DEFAULT_BATCH_SIZE and MINIMAL_BATCH_SIZE.

* Update doc and readme tests.

* Update basics.md

* Update readme_examples tests.

* Fix exceptions in test.

* Partial setup for amazon_cellphones.

* Benchmark with vectors.

* Benchmark with maps

* With vectors again.

* Fix for weighted average.

* DOM benchmark.

* Fix typos. Add On Demand benchmark.

* Add large amazon_cellphones benchmark for DOM

* Add benchmark for On demand.

* Fix broken read_me test.

* Add parser.threaded to enable/disable thread usage.

Co-authored-by: Daniel Lemire <lemire@gmail.com>
2021-07-20 14:17:23 -04:00
Daniel Lemire 2dac3705d2 renames 'to_string' to 'to_json_string' and makes it ridiculously fast (#1642)
* Changing the name of the function to 'to_json_string' from 'to_string' to avoid confusion.

* Moving to a fast string_view model

* Making it exception-safe.

* Tweaking.

* Workaround for exceptions.

* more robust to_json_string (#1651)

* WIP.

* Fuzzing timeout  (bug fix) (#1650)

* prove pull request #1648 introduces an infinite loop

* Interesting bug!

* Tweak.

Co-authored-by: Paul Dreik <github@pauldreik.se>

* It should now work.

* Moving car examples to exception mode

* Simplifying somewhat.

* I forgot to abandon. Let us do that.

* Adding more tests.

* WIP.

* It should now work.

* Moving car examples to exception mode

* Simplifying somewhat.

* I forgot to abandon. Let us do that.

* Adding more tests.

Co-authored-by: Paul Dreik <github@pauldreik.se>

Co-authored-by: Paul Dreik <github@pauldreik.se>
2021-07-19 10:24:36 -04:00
Daniel Lemire 774999ee95 Adds some benchmarks for the minifier. 2021-07-16 11:54:55 -04:00
Daniel Lemire c906f864d7 Update basics.md 2021-07-16 09:33:43 -04:00
Daniel Lemire 68e3c4f984 Update basics.md 2021-07-16 09:27:34 -04:00
Daniel Lemire b08818fab9 Update basics.md 2021-07-15 12:31:53 -04:00
Daniel Lemire 33f73b577c Another attempt at producing problems with threads (more tests) (#1655)
* Another attempt at producing problems with threads.

* Fixing code

* Trying to please visual studio
2021-07-13 17:30:29 -04:00
Daniel Lemire 30422cfdd3 I am getting tired of conflicts in settings.json. (#1652) 2021-07-13 09:28:49 -04:00
Daniel Lemire b085b56e32 This solves a minor issue with our legacy benchmark tools. (#1653)
* This solves a minor issue with our legacy benchmark tools.

* Slightly better code.

* Removing bad typo.
2021-07-13 09:18:58 -04:00
Daniel Lemire ea3d4e7ce5 Fuzzing timeout (bug fix) (#1650)
* prove pull request #1648 introduces an infinite loop

* Interesting bug!

* Tweak.

Co-authored-by: Paul Dreik <github@pauldreik.se>
2021-07-06 14:36:38 -04:00
Daniel Lemire bea1483cde Fixing minor issue with document stream (DOM). (#1648)
* Fixing minor issue with document stream (DOM).

* Porting over the fix.
2021-07-05 17:40:04 -04:00
Paul Dreik 90efd79055 Get fuzzing working again (#1646)
* upload corpus to https://www.pauldreik.se/ from the x64 github action job (keep the github action cache)
* drop the github action cache (which was not working anyway) for power fuzzer and download the fuzz corpus from https://www.pauldreik.se/ instead
* resurrect arm64 fuzzing on drone CI, downloading the fuzz corpus from https://www.pauldreik.se/
* update the fuzzing documentation
2021-07-05 09:42:57 +02:00
Daniel Lemire 7e646efd0f This should print out (once) some instructions to interpret the logging traces. (#1637)
* This should print out (once) some instructions to interpret the logging traces.

* More details.
2021-06-26 11:38:38 -04:00
Nicolas Boyer eb849662c0 Update basic.md to document JSON pointer for On Demand. (#1618)
* Update basic.md to document JSON pointer for On Demand.

* Add automatic rewind for at_pointer

* Remove DOM examples in basics.md and update documentation reflecting addition of at_pointer automatic rewinding.

* Review

* Add test

Co-authored-by: Daniel Lemire <lemire@gmail.com>
2021-06-26 11:38:17 -04:00
Daniel Lemire f146294a85 Partial documentation regarding relative JSON pointers. (#1630)
* Attempt at bringing some sanity to partial/relative JSON pointers.

* Removing some white spaces.
2021-06-26 11:36:38 -04:00
Daniel Lemire 374de826ab This introduces a reset functionality for object and array containers (#1639)
* This introduces a reset functionality.

* Minor simplification.

* Tweaking further.

* This should fix the tests.
2021-06-26 11:33:37 -04:00
Daniel Lemire 1fd3e32051 Removes is_at_container_start() and documents is_at_iterator_start(), move_at_start(), enter_at_container_start() (#1638)
* Removes is_at_container_start() and documents is_at_iterator_start()

* More documentation.
2021-06-25 13:26:43 -04:00
Daniel Lemire e607958a7b Update README.md 2021-06-24 14:13:26 -04:00
Daniel Lemire 0f068fb7c4 Update README.md 2021-06-24 14:13:04 -04:00
Daniel Lemire b991a4c7f3 We should be more generously testing in debug mode. (#1635) 2021-06-24 12:44:28 -04:00
Daniel Lemire 5b99a75ae1 count_elements did not like empty arrays. (#1631)
* count_elements did not like empty arrays.

* Minor cleaning.

* I don't understand.

* More cleaning.
2021-06-24 11:08:13 -04:00
John Keiser 1ba73b9e6b Merge pull request #1629 from simdjson/jkeiser/vscode-config
Add .vscode workspace settings
2021-06-23 19:29:21 -06:00
Daniel Lemire cfe3adb599 Added tests over invalid documents. (#1626)
* Added tests over invalid documents.

* Tweaking.
2021-06-23 18:02:00 -04:00
John Keiser be6052bcdc Diff json using text diff 2021-06-23 12:28:03 -06:00
John Keiser ca8e21583c Add basic workspace configuration for vscode 2021-06-23 12:28:00 -06:00
Daniel Lemire 1c01fc35eb This better documents invalidation. (#1625)
* This better documents invalidation.

* Tweak.
2021-06-22 11:33:25 -04:00
Nicolas Boyer ce38fe7bea Add automatic rewind for at_pointer (#1624) 2021-06-21 15:17:24 -04:00
Daniel Lemire 6cd04aa858 Improving the documentation: escaping keys and "validate what you use" (#1621)
* Improving the documentation.

* Removing trailing spaces.
2021-06-18 09:59:20 -04:00
Nicolas Boyer 03f7396d50 Fix branches. (#1619) 2021-06-17 18:31:40 -04:00
Nicolas Boyer a4803d50c5 Add JSON Pointer for On Demand (#1615)
* Add working JSON pointer for array of atoms.

* Add working JSON pointer for object with key-atom pairs.

* Add first version of JSON pointer.

* Update tests (2 tests).

* Make tests exceptionless.

* Fix builing issues.

* Add more tests. Add json_pointer validation in array-inl.h and object-inl.h and empty json_pointer in document-inl.h.

* Fix errors in tests.

* Review.

* Add missing comment.
2021-06-11 14:20:05 -04:00
Daniel Lemire 40cba172ed Adds compile-test for Visual Studio + ARM and turn developer mode throughout CI. (#1609)
* Adds compile-test for Visual Studio + ARM and turn developer mode throughout CI.

* Correcting YAML error.

* Disabling google benchmarks under Windows ARM.

* Turning off exceptions under ARM.
2021-06-09 16:42:37 -04:00
Nicolas Boyer 3ba221eb8e Add max_capacity setting for On Demand (#1610)
* First try at implementing max_capacity for simdjson_ondemand.

* Add max_capacity check.

* Update doc.

* Add one more example in doc for fixed capacity.

* Make allocate() public.

* Remove whitespace

* Found culprit whitespace.

* Duplicating variable.
2021-06-08 14:42:42 -04:00
Daniel Lemire 8bc12fe7cb Update basics.md 2021-06-07 14:54:18 -04:00
Daniel Lemire 34bb2079e7 Adding documentation regarding versions. (#1611)
* Adding documentation regarding versions.

* Minor tweaks.
2021-06-07 14:19:23 -04:00
Daniel Lemire 7ca016652e Update README.md 2021-06-07 11:27:48 -04:00
Daniel Lemire 13ab123daf Testing issue 1607. (#1608) 2021-06-07 10:50:48 -04:00
Daniel Lemire f54bd69b5b Update bug_report.md 2021-06-07 09:57:43 -04:00
Daniel Lemire 16e8db1f17 Adding 'count_elements' method. (#1577)
* Adding 'count_elements' method.

* Actually reporting errors.

* removing white space.

* Removing white space again.

* Adding an extra example.

* Prettier.

* Making the functionality more error-proof.

* Avoiding exceptions.

* Various fixes including extending count_elements to value types.

* Various fixes.

* Minor fixes.

* Correcting comment.

* Trimming white spaces.
2021-06-06 17:56:00 -04:00
Daniel Lemire eb0ae041e3 Verification and bug fix of issue 1511 (#1602)
* Verification and bug fix.

* Removing comment.

* Removing spaces.

* Guarding exceptions.

* Tweaking the test
2021-06-06 17:55:33 -04:00
John Keiser 893e613faa Don't #include "simdjson.cpp" in tests (#1605) 2021-06-06 14:44:04 -04:00
Daniel Lemire 714f0ba222 This deletes most of our data files making the repository much smaller (#1582)
* This deletes most of our data files making the repository much smaller.

* Removing dead code.

* Various minor fixes.
2021-06-04 09:24:03 -04:00
Daniel Lemire 19c3b1315a Rewind functionality. (#1539)
* Rewind functionality.


* Keeping just the document rewind.
2021-06-04 09:22:33 -04:00
Daniel Lemire f44a53271d Documentation for issue 1562 (Accessing escaped key with on-demand API) (#1563)
* Documentation for issue 1562.

* Making exception-free.

* Improving wording.
2021-06-04 09:21:52 -04:00
Nicolas Boyer d90714e8df Add RapidJSON and nlohmann_json SAX to partial_tweets benchmark (#1597)
* Add first working version of rapidjson_sax for partial tweets.

* Add cleaner and faster rapidjson_sax

* Add nlohmann_json_sax.

* Replace array of bool by bitsets.

* Replace strdup to copy string in rapidjson_sax.

* Change std::string_view assignment in rapidjson_sax.
2021-06-03 16:41:20 -04:00
Nicolas Boyer c7fd7353a8 Add RapidJSON and nlohmann_json SAX to top_tweet benchmark (#1599)
* Add rapidjson_sax.h and fix typo in rapidjson.h

* Add nlohmann_json_sax.h and add user key check for screen_name in rapidjson_sax

* Change std::string_view assignement for text and screen_name.
2021-06-03 16:41:00 -04:00
Nicolas Boyer 05f15d88b6 Add large_random/rapidjson_sax.h and large_random/nlohmann_json_sax.h. Clean up kostya/rapidjson_sax.h (add flags also) and kostya/nlohmann_json_sax.h (#1600) 2021-06-03 16:40:39 -04:00
Nicolas Boyer d7d81c7152 Add RapidJSON and nlohmann_json SAX to find_tweet benchmark (#1598)
* Add rapidjson_sax.h .

* Add nlohmann_json_sax.h . Fix typos distinct_user_id/nlohmann_json_sax.h, find_tweet/rapidjson.h and find_tweet/rapidjson_sax.h .

* Add extra check for id key when looking for find_id.
2021-06-03 12:43:54 -04:00
Nicolas Boyer 73b510225f Add RapidJSON and nlohmann_json SAX to distinct_user_id benchmark (#1593)
* Add rapidjson_sax for distinct_user_id

* Add nlohmann_json_sax.h for distinct_user_id

* Add flags for RapidJSON.

* Fix revisions.

* Fix revisions again.

* Replace strcpy with memcpy. Increase performance fix.
2021-06-01 14:51:27 -04:00
Daniel Lemire 5d2eca2363 Correcting a couple of typographic errors. 2021-06-01 13:59:32 -04:00
Daniel Lemire 939b6b854a This adds /permissive- to recent visual studio builds (#1596)
* This adds /permissive-.

* Typo.

* Trying this simple fix.
2021-06-01 10:57:37 -04:00
Daniel Lemire 4f8bdf517a Adds a warning message when SIMDJSON_DEVELOPER_MODE is OFF. (#1594) 2021-06-01 10:29:11 -04:00
Nicolas Boyer 369f66be35 Add RapidJSON and nlohmann_json SAX to kostya benchmark (#1592)
* Add RapidJSON and nlohmann_json SAX to kostya benchmark

* Remove trailing whitespaces

* Fix typo
2021-05-31 10:15:50 -04:00
Daniel Lemire 8a75dbf719 Update README.md 2021-05-28 09:05:56 -04:00
Daniel Lemire 1032f70ddf Verifies and fixes issue 1588 (#1589)
* Verifies and fix issue 1588

* Removing a trailing space.
2021-05-27 19:35:42 -04:00
strager 16e2323153 Fix UB in dev checks when iterating empty object (#1587)
When find_field_unordered is used on an empty object, it calls
json_iterator::reenter_child. reenter_child asserts that it doesn't
rewind too far back by consulting parser->start_positions.

When the On Demand parser sees an empty object, it fails to update
parser->start_positions. This means that the assertion in
json_iterator::reenter_child reads stale data, or potentially
uninitialized memory. Reading uninitialized memory can cause spurious
assertion failures and Valgrind memcheck reports:

    Running missing_keys_for_empty_top_level_object ...
    ==170679== Conditional jump or move depends on uninitialised value(s)
    ==170679==    at 0x4943D7: reenter_child (json_iterator-inl.h:208)
    ==170679==    by 0x4943D7: find_field_unordered_raw (value_iterator-inl.h:197)
    ==170679==    by 0x4943D7: find_field_unordered (object-inl.h:13)
    ==170679==    by 0x4943D7: find_field_unordered (object-inl.h:96)
    ==170679==    by 0x4943D7: find_field_unordered (value-inl.h:110)
    ==170679==    by 0x4943D7: find_field_unordered (document-inl.h:105)
    ==170679==    by 0x4943D7: object_tests::missing_keys_for_empty_top_level_object() (ondemand_object_tests.cpp:117)
    ==170679==    by 0x4CA761: object_tests::run() (ondemand_object_tests.cpp:1085)
    ==170679==    by 0x8BA314: int test_main<bool ()>(int, char**, bool ( const&)()) (test_ondemand.h:81)
    ==170679==    by 0x4CA9C8: main (ondemand_object_tests.cpp:1119)
    ==170679==

Fix the read of uninitialized or stale memory by updating
parser->start_positions regardless of whether we see an empty object or
an object with some keys.

This commit only affects builds where development checks
(SIMDJSON_DEVELOPMENT_CHECKS) are enabled. Builds where development
checks are disabled are unaffected by this bug.
2021-05-27 08:34:28 -04:00
Pavel Novikov 2ec23bdf37 fixed some typos (#1585) 2021-05-24 09:21:00 -04:00
Daniel Lemire 4fb09824bf Restricting how we can end key searches (#1575)
* Verifies bug with missing keys.

* Allowing search from any key.

* Workaround for buggy msys

* Restricting how we can end key searches.

* Adding a few tests.
2021-05-20 16:23:38 -04:00
Daniel Lemire ad1cd6a2ce Documenting raw string access. (#1566)
* Documenting raw string access.

* Removing trailing space.
2021-05-20 13:57:48 -04:00
Daniel Lemire a27367210a Improving how to_string is explained. (#1583) 2021-05-20 11:22:31 -04:00
Daniel Lemire efe9761f80 Fixing issue 1579. (#1580) 2021-05-19 12:23:17 -04:00
Ivan Volnov 0b75de12ef Don't allocate std::string just for padded_string::load() (#1578)
* Don't allocate std::string just for padded_string::load()

Use std::string_view

* Remove reference from string_view
2021-05-18 12:32:51 -04:00
Daniel Lemire af5c8175b4 By default, we should not do the DOM checkperf… (#1571)
* By default, we should not do the DOM checkperf. These targets assume that main branch remains
compatible, an assumption that will break over time.
2021-05-15 15:28:59 -04:00
Amos Bird 8df32cea33 Return err when alloc failure (#1567) 2021-05-14 22:51:07 -04:00
Luigi Pinca e4150443ca Update journal reference (#1565)
Update the journal reference of the "Validating UTF-8 In Less Than One
Instruction Per Byte" paper.
2021-05-10 08:16:37 -04:00
Daniel Lemire d539781cf3 This attempts to fix the fuzzers. (#1564)
* This attempts to fix the fuzzers.

* Retiring bintray.

* Disabling ARM fuzzing.
2021-05-07 22:59:26 -04:00
PavelP 2bbab7d892 Update CONTRIBUTORS (#1560) 2021-05-02 12:30:25 -04:00
Daniel Lemire 729c35c0f8 Removes docker file which is unused and untested, and updates the path to dom/parse. 2021-05-01 10:31:00 -04:00
Dirk Stolle 2abcc35031 fix serveral typos (#1558)
* fix typos in markdown files

* fix typos in CMake files

* fix typos in headers and test code
2021-05-01 10:19:53 -04:00
Daniel Lemire 85b910814e Under ARM, it is slightly better to reverse the word once and then extract the bits. (#1545)
* Under ARM, it is slightly better to reverse the word once and then extract the bits.

* Guarding the zero_leading_bit call to avoid sanitizer warnings.
2021-04-30 18:34:21 -04:00
Daniel Lemire c1dffac28c This moves all DOM (benchmark + test) files to a subdir (#1549)
* This moves all DOM (benchmark + test) files to a subdir

* Missing file.

* CMake + DLL is not pretty.

* Capitalizing AND

* Fixing mismatch endif

* Flipping the order.

* onedemand => ondemand
2021-04-30 18:33:45 -04:00
Daniel Lemire 911b06186b Delete Dockerfile 2021-04-26 09:08:34 -04:00
D. Stolle be9d5d4e31 adjust GitHub links to current repository URL (#1553)
Switch links (mostly in comments) from old repository URL
<https://github.com/lemire/simdjson/> to the current URL
<https://github.com/simdjson/simdjson/>.
2021-04-26 09:08:14 -04:00
Daniel Lemire b32d66e7b6 Update README.md 2021-04-24 16:59:41 -04:00
Daniel Lemire 939bfc701a Update README.md 2021-04-24 16:58:57 -04:00
Daniel Lemire 9c470822a1 Putting back the rstrip. 2021-04-23 10:54:21 -04:00
Daniel Lemire 59195bd5dc Removing unsupported '--parallel'. 2021-04-23 10:14:10 -04:00
bobergj ef8c2c434e When realloc_if_needed, use loaded_bytes buffer rather always allocating a tmp one. (#1518) 2021-04-23 10:10:03 -04:00
friendlyanon 5ec85197f8 CMake refactor stage1 (#1512)
* Remove CMP0025 policy

This policy is already set to NEW by the minimum required version.

* Use HOMEPAGE_URL in the project call

* Use VERSION in the project call

* Detect if this is the top project

* Port simdjson-user-cmakecache to a CMake script

* Create a developer mode

The SIMDJSON_DEVELOPER_MODE option set to ON will enable targets that
are only useful for developers of simdjson.

* Consolidate root CML commands into logical sections

* Warn about intended use of developer mode

* Prettify the just_ascii test

* Remove redundant CMake variables

* Inline CML contents from include and src

* Raise minimum CMake requirement to 3.14

* Define proper install rules

* Restore thread support variable

* Add BUILD_SHARED_LIBS as a top level only option

* Force developer mode to be on in CI

* Include flags earlier in developer mode

* Set CMAKE_BUILD_TYPE conditionally

CMAKE_BUILD_TYPE is used only by single configuration generators and is
otherwise completely ignored.

* Remove useless static/shared options

simdjson now uses the CMake builtin BUILD_SHARED_LIBS to switch the
built artifact's type.

* Remove unused CMAKE_MODULE_PATH variable

* Refactor implementation switching into a module

* Factor exception option out into a module

* Reformat simdjson-flags.cmake

* Rename simdjson-flags to developer-options

* Accumulate properties into an include module

This is done this way to avoid using utility targets that must be
exported and installed, which could potentially be misused by users of
the library.

* Port impl definitions to props

* Port exception options to props

* Lift normal options to the top

* Port developer options to props

* Remove simdjson-flags from benchmark

* Document the developer mode in HACKING

* Fix include path in installed config file

* Fix formatting of prop commands

* Fix tests that include .cpp files

* Change GCC AVX fixes back to compile options

* Deprecate SIMDJSON_BUILD_STATIC

* Always link fuzz targets to simdjson

* Install CMake from simdjson's debian repo

* Add gnupg for apt-key

* Make sure ASan link flags come first

* Pass CI env variable to cmake invocation

* Install package for apt-add-repository

* Remove return() from flush macro

* Use directory level commands instead of props

* Restore the github repository variable

* Set developer mode unconditionally for checkperf

The CI env variable is only set in the CI and this target is always run
in developer mode.

* Attempt to fix ODR violation in parsing checks

These tests were compiling the simdjson.cpp file again and linking to
the simdjson library target causes ODR violations.

Instead of linking to the target, just inherit its props.

* Move variables before the source dir

* Mark props to be flushed after adding more

* Use props for every command for the library

* Use keyword form for linking libs

* Handle deprecation of SIMDJSON_JUST_LIBRARY

* Handle deprecations in a separate module

Co-authored-by: friendlyanon <friendlyanon@users.noreply.github.com>
2021-04-23 09:24:56 -04:00
Daniel Lemire 8eed8f5155 Document stream: truncate final unfinished document and give access to the number of truncated bytes. (#1534)
* Truncate final unclosed string.

* Adding more precise remarks.

* Better documentation and more robust code.

* ARM + PPC corrections.

* Patching ARM implementation with new stage1_mode parameter.

* Fixed most problems.

* Correcting white spaces and adding a remark.

* This adds the truncated_bytes() method to the stream instances.
2021-04-23 09:24:00 -04:00
Daniel Mangum 48f5e8b6c3 Fix minor typo in basics.md (#1547)
Updates basics.md with typo correction of were --> where.

Signed-off-by: hasheddan <georgedanielmangum@gmail.com>
2021-04-22 11:37:47 -04:00
Daniel Lemire 0a2da45794 Adding another license note. 2021-04-13 10:25:02 -04:00
Paul Dreik a79bbd63a3 use github action cache instead of bintray (#1536)
* use github action cache instead of bintray

* add note on where to get the corpus

Co-authored-by: Paul Dreik <paul@simdjson>
2021-04-12 16:58:30 -04:00
Daniel Lemire c667b0cfdf Update basics.md 2021-04-08 14:34:10 -04:00
Daniel Lemire b3a22bea56 My third attempt at fixing issue 1521 (not being merged due to performance concerns) (#1530)
* Reduction of the missing-key bug.

* Adding the other test cases.

* Really simple fix for 1529
2021-04-05 11:55:39 -04:00
Daniel Lemire 6ca6ee5a6f Correcting what seems to be a typo and adding some extra logging. (#1535) 2021-04-04 12:25:05 -04:00
Daniel Lemire 78cff7518b Update README.md 2021-04-01 22:53:31 -04:00
Daniel Lemire d0821adf0e This implements string serialization for On Demand instances. (#1527)
* This implementations string serialization for On Demand instances.

* Adding more documentation.

* Another remark.

* Marking the new functions as inline.

* casts apparently do not work.

* Upgrading the API.

* Making the code really free from exceptions.

* At another fix for exceptionless.

* Modify to_chars so that it does not pad integers with '.0'.

* Negative 0 cannot be expressed as an integer.

* Again, accomodating exceptionless usage.

* Using x <= -0 does not allow you to determine the sign since 0 <= -0. I am not sure where
this bug comes from.
2021-04-01 11:25:00 -04:00
Daniel Lemire 461bc4c47e Removing a misleading comment in the tests. (#1526) 2021-03-29 12:56:20 -04:00
Daniel Lemire 99406266b1 This will disable the sanitizer runs on travis. (#1523) 2021-03-26 13:51:39 -04:00
Daniel Lemire a6576f1d09 We should be able to open empty files (paranoid test) (#1519)
* We should be able to open empty files.

* Testing also the ondemand API.
2021-03-26 11:43:40 -04:00
Daniel Lemire 95b4870e20 Avoiding stack allocation. (#1515) 2021-03-23 11:32:04 -04:00
John Keiser 5607253be5 Merge pull request #1509 from simdjson/jkeiser/all-tests
Make ctest succeed after running make all_tests
2021-03-20 18:16:33 -07:00
John Keiser 94563328c4 Make ctest succeed after running make all_tests 2021-03-20 14:01:52 -07:00
Daniel Lemire ddf610125f Easy fix. (#1507) 2021-03-19 19:53:22 -04:00
Daniel Lemire b6cce3d744 Let us stop evoluating. (#1506) 2021-03-18 22:42:36 -04:00
Daniel Lemire 8a3b2f20e4 Version 0.9.1 2021-03-18 11:31:38 -04:00
Daniel Lemire 62cd5f7984 get_root_value is dead code that should have been removed. 2021-03-18 11:30:40 -04:00
Daniel Lemire 2db4592571 Last commit for version 0.9.0. (#1503)
* Last commit for version 0.9.0.

* Removing space.
2021-03-17 11:08:44 -04:00
Daniel Lemire e35088d6ff Update performance.md 2021-03-16 17:57:23 -04:00
Daniel Lemire 156b1b20e3 Update basics.md 2021-03-16 17:56:32 -04:00
Daniel Lemire 9294e8b098 Update performance.md 2021-03-16 17:52:59 -04:00
Daniel Lemire 6dc98561a9 Port the performance notes to "on demand". (#1496)
* Port the performance notes to "on demand".

* No more white space.

* Trimmed another space.
2021-03-16 17:32:38 -04:00
Daniel Lemire 4cfad7adf2 Update README.md 2021-03-12 15:02:47 -05:00
Daniel Lemire 3ab0d3ed94 Update README.md 2021-03-12 15:01:52 -05:00
Daniel Lemire 430f230940 Update README.md 2021-03-12 15:01:12 -05:00
Daniel Lemire 727644c13a Add files via upload 2021-03-12 14:57:39 -05:00
Daniel Lemire 3ab8eca09b Update basics.md 2021-03-12 14:24:14 -05:00
Daniel Lemire 0dc07b34a7 Update basics.md 2021-03-12 14:23:01 -05:00
Daniel Lemire 221c55b620 Update README.md 2021-03-12 14:21:23 -05:00
Daniel Lemire 02f9b83353 This moves us to On Demand as the default front-end. (#1494)
* This moves us to On Demand as the default front-end.

* Made casting magical

* Adding another section

* Undoing my damage.
2021-03-12 14:19:11 -05:00
John Keiser cfc965ff9a Merge pull request #1490 from simdjson/jkeiser/single-ondemand
Don't compile On Demand with extra flags
2021-03-09 16:03:58 -08:00
Daniel Lemire 033df0ebfb Update README.md 2021-03-09 16:29:36 -05:00
Daniel Lemire ac34640224 Update README.md 2021-03-09 16:29:05 -05:00
John Keiser a987192040 Remove SIMDJSON_CPP 2021-03-09 09:10:27 -08:00
John Keiser 751696d7eb Move implementation selection to implementations.h 2021-03-09 09:10:08 -08:00
Daniel Lemire 50aa1566ae Under Apple's compiler, mixing the undefined-behavior sanitizer with the address sanitizer is calling for trouble (#1493)
* Nicer support for Apple's compiler.

* Extending to SIMDJSON_SANITIZE_UNDEFINED

* Better wording.
2021-03-09 11:39:43 -05:00
Daniel Lemire 0a5bba7235 Provides a more correct simdjson::ondemand implementation message. (#1492) 2021-03-09 11:39:19 -05:00
Daniel Lemire 8b8af6aee5 Making input capacity more robust. (#1488) 2021-03-09 09:58:38 -05:00
Daniel Lemire 8e8fbc4cff fixing issue 1480 (#1485) 2021-03-08 19:31:42 -05:00
John Keiser 985dfab2c4 Don't use TARGET unless the target options are *not* specified
This eliminates the possibility of inlining target failures for ondemand

Also makes it so we always compile common architectures needed by simdjson.cpp in simdjson.h, since amalgamation has no way to reason about whether to include / exclude it.
2021-03-08 13:49:09 -08:00
John Keiser 633161fe86 Don't include target flags if the compiler already has them on 2021-03-08 13:48:58 -08:00
John Keiser f51d50399c Only include builtin implementation from header 2021-03-08 13:48:53 -08:00
John Keiser cf4e538536 Separate builtin implementation from "all implementations" 2021-03-06 13:08:42 -08:00
John Keiser ec5ba79447 Add base.h to allow src/ to pick and choose includes 2021-03-05 11:48:34 -08:00
John Keiser 0948573e63 Merge pull request #1479 from simdjson/jkeiser/raw_json_token
Add value.raw_json_token()
2021-03-05 10:24:36 -08:00
John Keiser bad582c2d3 Add value.raw_json_token() 2021-03-05 09:07:41 -08:00
John Keiser f55893807a Merge pull request #1473 from simdjson/jkeiser/promise-padded
Support user-provided buffers in On Demand
2021-03-04 20:56:34 -08:00
Daniel Lemire dc2f767171 Ensuring that stage 1's json_block and cie are never copied and using explicit constructors (issue 1475) (#1478) 2021-03-04 07:59:36 -05:00
John Keiser f0e92e3bdd Pass "capacity" straight to iterate, support std::string 2021-03-03 12:51:00 -08:00
John Keiser 3db1a214ce Support user-provided buffers via promise_padded 2021-03-03 12:50:56 -08:00
John Keiser 79e94227c2 Merge pull request #1472 from simdjson/jkeiser/ondemand-type
Add ondemand::value.type()
2021-03-03 12:49:20 -08:00
John Keiser 665514692a Remove UTF-8 from source code 2021-03-03 12:10:59 -08:00
John Keiser 9944db6d73 Move json_type to ondemand to prevent target mismatch inline errors 2021-03-02 18:31:17 -08:00
John Keiser 2ed24666b5 Add value.type() 2021-03-02 17:02:50 -08:00
Daniel Lemire 0c199cffc3 Removing mallocs in main library. (#1468) 2021-03-02 13:09:22 -05:00
John Keiser 29fe1866ef Move dom / implementations include into their own spots 2021-03-02 09:53:28 -08:00
Daniel Lemire 4811c8036b Update the tape description and the dump_tape function (#1465)
* Would fix issue 1446

* Trimming spaces.
2021-03-01 18:47:11 -05:00
Daniel Lemire 036151c1e3 Test that we can copy the iterators. (#1466) 2021-03-01 18:46:50 -05:00
rychale 9d22372cc9 Make dom::document_stream::iterator copyable and default-constructible by holding pointer to document_stream instead of ref (#1463)
Co-authored-by: Alexey Rychkov <arychkov@defytrading.com>
2021-03-01 14:40:51 -05:00
Daniel Lemire a3d3e347a2 Adding -mno-avx256-split-unaligned-load -mno-avx256-split-unaligned-store at GNU GCC under x86/x64 systems. (#1462) 2021-03-01 14:16:30 -05:00
Daniel Lemire 9577c54999 Provide the CMake install the necessarily information (and flags) to hand Windows DLL and add Windows installation tests (#1457)
* This gives the CMake install the necessarily information (and flags) to know
whether we have a Windows DLL and in such cases how to handle the linkage.
2021-02-26 16:17:05 -05:00
Daniel Lemire 72c40be553 This adds tests without threads under linux. (#1460) 2021-02-26 16:16:10 -05:00
Daniel Lemire 6aa8877bf6 This adds tests for the no-exception variant of the library usage under linux. (#1459)
* This adds tests for the no-exception variant of the library usage under linux.

* Fixed name.

* Syntax fix.
2021-02-26 16:15:34 -05:00
Daniel Lemire ef1e256fa7 Workaround for SIMDJSON_ASSUME "side-effect" warning under some compilers. (#1456) 2021-02-25 08:50:57 -05:00
Daniel Lemire ad37651726 Guarding undefined templates with a static_assert. (#1454)
* Guarding undefined templates with a static_assert.

* Fixing comments.

* Undeprecating (or whatever you want to call it).
2021-02-22 16:54:47 -05:00
John Keiser 92caeb039f Merge pull request #1453 from simdjson/jkeiser/number-overrun
Fix ridiculously unlikely buffer overrun in ondemand
2021-02-22 09:39:43 -08:00
John Keiser cdb607f202 Add comments on confusing "simdjson_unused" 2021-02-22 09:39:09 -08:00
John Keiser bcab8d3abf Check for end object/array at top level
This avoids a very unlikely buffer overrun that can occur in a particular kind of invalid JSON:
- the document is invalid with an unclosed top level array or object
- the last thing in the document is a number that ends at EOF
- the padding is filled entirely with numeric digits
2021-02-22 09:35:21 -08:00
John Keiser 9d747642fe Merge pull request #1452 from simdjson/jkeiser/safe-iter-fix
Fix bug reporting out of order iteration
2021-02-22 09:34:49 -08:00
John Keiser a755203aee Update value_iterator-inl.h 2021-02-22 09:34:20 -08:00
John Keiser 814726e5d4 Merge pull request #1432 from simdjson/jkeiser/safe-lookup
Alert user when they use object indexing incorrectly
2021-02-22 09:31:59 -08:00
John Keiser c4a312e6c3 Fix strict overflow warning 2021-02-21 14:06:58 -08:00
Daniel Lemire 81609393f1 Fixing issue 1449. (#1451) 2021-02-21 16:33:05 -05:00
John Keiser 0634958329 Don't emit out of order iteration error for empty array 2021-02-21 11:43:36 -08:00
John Keiser b352b903e7 Fix bug where iterators didn't always report errors 2021-02-21 11:43:36 -08:00
John Keiser 74d6658f39 Make out of order iteration tests actually test errors in the loop 2021-02-21 11:43:36 -08:00
John Keiser 3076de0405 Use SIMDJSON_DEVELOPMENT_CHECKS instead of SIMDJSON_PRODUCTION
Don't enable in retail
2021-02-20 11:46:01 -08:00
John Keiser 4a0a0ed4c6 Split more tests into separate methods 2021-02-20 11:22:24 -08:00
Vadim Peretokin c5def8f706 Document SIMDJSON_EXCEPTIONS (#1443)
* Document SIMDJSON_EXCEPTIONS

* Add an example

* Enchance clarity
2021-02-17 14:30:58 -05:00
Daniel Lemire 610b3ad302 Adds Visual Studio 2017 to CI (for real) and adapt our build/tests (#1444) 2021-02-15 19:49:12 -05:00
Daniel Lemire 4c63a929bc This makes it possible to a have document instance (DOM) that is separate from the parser if you would like. (#1430)
* This makes it possible to a have document instance that is separate from the parser if you would like.
2021-02-10 14:44:53 -05:00
Daniel Lemire 0f72ff3a57 Adding Visual studio 2017 CI tests to GitHub actions. (#1438)
* Adding Visual studio 2017 CI tests to GitHub actions.

* Fixing the name.
2021-02-09 10:05:45 -05:00
Daniel Lemire 67afcd4edd Adding legacy Win32 / Visual Studio 2017 CI tests to GitHub Actions. (#1439) 2021-02-09 10:05:33 -05:00
David CARLIER 6e9ada2d6c unit test macos build fix (#1434) 2021-02-08 14:12:39 -05:00
John Keiser 9651efe626 Split up tests for compile times 2021-02-06 11:07:14 -08:00
John Keiser df7201ba42 Fix Windows assume error 2021-02-06 11:06:53 -08:00
John Keiser 14315ec5cd Default SIMDJSON_PRODUCTION to OFF for bare header usage 2021-02-06 11:06:37 -08:00
John Keiser 0f10fc9ad9 Fix Windows _assume warning 2021-02-05 18:53:39 -08:00
John Keiser ce678fd986 Fix GCC 7 strict-overflow warning 2021-02-05 18:53:31 -08:00
John Keiser 9d693da852 Only set container depth when a container iteration starts 2021-02-05 17:20:24 -08:00
John Keiser 22742b6bd6 Make max_depth() a simple check 2021-02-05 17:11:03 -08:00
John Keiser a33bf40a7d Add tests for sibling indexing detection 2021-02-05 16:39:52 -08:00
John Keiser 3801ea7777 Disable all OUT_OF_ORDER_ITERATION checks when SIMDJSON_API_USAGE_CHECKS
is off
2021-02-05 16:39:44 -08:00
John Keiser c7935ceed1 Put parser capacity / max_depth back into parser 2021-02-05 16:39:36 -08:00
John Keiser ea119a5679 Start parsing at depth 1 instead of using descend_to for it 2021-02-05 16:39:34 -08:00
John Keiser 7a324da548 Add -DSIMDJSON_PRODUCTION flag 2021-02-05 16:34:27 -08:00
John Keiser 0d1c99a6ad Allow object lookup safety to be disabled
Use cmake -DSIMDJSON_API_USAGE_CHECKS=OFF ..
2021-02-05 10:18:01 -08:00
John Keiser e4626d233c Descend into fields at the value position, not the key 2021-02-05 10:18:01 -08:00
John Keiser 9934f65987 Store start index of each depth for safety 2021-02-05 10:17:28 -08:00
John Keiser b2de2dfd1b Merge pull request #1416 from simdjson/jkeiser/safe-iterators-2
Add safety checks for out of order array/object iteration+indexing
2021-02-05 09:47:03 -08:00
John Keiser 3f2639a655 Merge pull request #1414 from simdjson/jkeiser/array-assert
Fix #1409 (assert when trying to get one value as multiple types)
2021-02-05 09:45:49 -08:00
Daniel Lemire 26b5b19f88 Unneeded. 2021-02-02 17:58:10 -05:00
Daniel Lemire 5449365658 This should make issue 1370 easier to track. (#1429)
* This should make issue 1370 easier to track.

* Avoiding exceptions.
2021-02-02 16:12:16 -05:00
Daniel Lemire 96536239c2 Deleting the function. (#1428) 2021-02-02 09:48:01 -05:00
Daniel Lemire 0e18453e34 Potential optimizations applied to jkeiser/array-assert (#1421)
* Some tuning.
* Using table lookups...
2021-02-01 12:39:10 -05:00
Daniel Lemire 777202e1f1 Why would you use a reference when looping? (#1422)
* Why would you use a reference?

* I missed a few cases.
2021-02-01 12:30:36 -05:00
Daniel Lemire 6f61ed1477 It appears that Qt uses macros for common terms like slots, signals and so forth. (#1425) 2021-02-01 11:31:29 -05:00
Daniel Lemire a509e04f9b Let us actually test the find package functionality. (#1418)
* Let us actually test the find package functionality.

* Specifying the path.

* Fixing the path.
2021-01-28 13:59:35 -05:00
tobim 152eb983ff Fix the CMake generated install target (#1412)
* Re-enable installation of simdjson-config.cmake

* Install a simdjson-config-version.cmake file
2021-01-27 18:39:05 -05:00
Daniel Lemire d6f33e4830 This adds a little test to see if we can compiler with very strict flags (conventional casts) (#1417)
* This adds a little test to see if we can compiler with very strict flags.

* Trimming a leftover old-style cast.

* More cleaning.

* A few more pedantic casts.
2021-01-27 18:37:30 -05:00
Tibbel 5613d30e97 partly replacement old-style-cast to c++ *_cast (#1403)
Co-authored-by: Tibbel <tibbel@ma-gi.de>
2021-01-27 13:33:48 -05:00
John Keiser 1bfbb6448a Check out-of-order error in object index 2021-01-26 20:49:14 -08:00
John Keiser c5b44f44f9 Add partial out-of-order check for field lookup 2021-01-26 20:00:39 -08:00
John Keiser 22b3ea93a8 Emit an error if user tries to iterate arrays out of order 2021-01-26 20:00:19 -08:00
John Keiser fe726b0f80 Split up ondemand_dom_api_tests for sanitize build times 2021-01-26 19:42:37 -08:00
John Keiser 18ecc0032d Reenable test that is now working 2021-01-26 15:15:09 -08:00
John Keiser 1a1532c8cc Return INCORRECT_TYPE when numbers fail to parse
Also add tests for trying to get multiple types in a row
2021-01-26 14:59:13 -08:00
John Keiser e6d2b7759a Fix assertion when getting array after failing to get a scalar
Also remove distinction between & and && for array start, acting like
other types
2021-01-26 14:09:54 -08:00
Daniel Lemire c96ff018fe Version 0.8. 2021-01-22 12:04:08 -05:00
Daniel Lemire 1005c62e90 It seems that we export too many targets. (#1385)
* It seems that we export too many targets.

* Adding missing word.

* Let us try this.

* Restoring dead line.

* Some fixes.

* Update src/CMakeLists.txt

Co-authored-by: Alexander Neumann <30894796+Neumann-A@users.noreply.github.com>

* Update cmake/simdjson-config.nothread.cmake.in

Co-authored-by: Alexander Neumann <30894796+Neumann-A@users.noreply.github.com>

* Update cmake/simdjson-config.cmake.in

Co-authored-by: Alexander Neumann <30894796+Neumann-A@users.noreply.github.com>

* Update CMakeLists.txt

Co-authored-by: Alexander Neumann <30894796+Neumann-A@users.noreply.github.com>

* Update CMakeLists.txt

Co-authored-by: Alexander Neumann <30894796+Neumann-A@users.noreply.github.com>

* Removing useless file

* Simplifying the PR somewhat.

Co-authored-by: Alexander Neumann <30894796+Neumann-A@users.noreply.github.com>
2021-01-20 13:20:49 -05:00
Daniel Lemire 2a714f4e37 Hide the std::pair inheritance in our result instances (#1396)
* Fixing issue 1243

* The tie must go.

* Having std::pair be a protected inheritance breaks on demand.

* Putting it back.

* You really want to use emplace.

* Fixing one botched test.

* Prettier test.

* Using safer code.

* Fixing unsafe code.

* Simplifying the fuzzer.

* Trying another way.

* Ok. It should work without exceptions.

* Removing trailing spaces.
2021-01-18 12:00:02 -05:00
Daniel Lemire 73063e2dab This adds a test to explain better the issue 1341: Support conversion of simdjson_result lvalue to dom::element (#1397)
* This adds a test to explain better the issue.

* Guarding it since it can throw.
2021-01-16 15:08:27 -05:00
Daniel Lemire 6e5d232ccc Fixing forgotten namespace. 2021-01-16 02:50:55 +00:00
Daniel Lemire 8e96e38099 We should trim out old benchmarks. (#1379) 2021-01-15 14:46:05 -05:00
Daniel Lemire 7517b9b122 Updating headers. 2021-01-14 17:37:43 -05:00
John Keiser 55faf4c5bc Recommend simdjson::ondemand over simdjson::builtin::ondemand (#1380)
Co-authored-by: Daniel Lemire <lemire@gmail.com>
2021-01-14 17:33:49 -05:00
John Keiser 92372412d9 Merge pull request #1387 from simdjson/jkeiser/ondemand-scalar-order
Allow JSON values to be parsed later / out of order
2021-01-14 11:02:53 -08:00
Daniel Lemire 990da22249 Merge branch 'master' into jkeiser/ondemand-scalar-order 2021-01-13 14:21:16 -05:00
John Keiser 3849cc400e Merge pull request #1372 from simdjson/jkeiser/ondemand-sajson
Add sajson and nlohmann_json benchmarks
2021-01-13 09:33:53 -08:00
ihsinme 84b0e84447 fix function was exited without releasing (#1389)
* Update jsoncheck.cpp

* Update minefieldcheck.cpp

* Update jsoncheck.cpp

* Update minefieldcheck.cpp
2021-01-12 18:08:27 -05:00
Daniel Lemire 3b8486665a Removing trailing white space. 2021-01-12 18:04:51 -05:00
friendlyanon 451c393ef1 [skip ci] Skip CI for Github (#1336)
* Add conditional to github workflows

* [skip ci] Document and encourage skipping CI

Co-authored-by: friendlyanon <friendlyanon@users.noreply.github.com>
2021-01-11 19:08:01 -05:00
Nicolai Grodzitski 095691160b Add element representation trivially_copyable property test (#1377)
* Add element representation trivially_copyable property test

Releates to issue #1374

* Change test label
2021-01-11 19:06:59 -05:00
Daniel Lemire 7597cb354c Folding the line. 2021-01-11 18:49:35 -05:00
Daniel Lemire bd2a31a0fe Minor edits regarding the On Demand documentation. (#1384)
* Minor edits regarding the On Demand documentation.

* Adding more instructions for CMake

* Tweaking.

* Adding changes requested by John.

* Bringing back detailed explanations of -march=native.
2021-01-11 18:48:02 -05:00
John Keiser be61650102 Add top_tweet benchmark to test laziness 2021-01-11 15:19:26 -08:00
John Keiser 3279c2f15b Remove unnecessary "try_get_XXX" methods
Also don't distinguish between & and && (instead, advance the first time
you encounter a scalar no matter what)
2021-01-11 15:19:26 -08:00
John Keiser 38da15b501 Rename checkpoint() -> position(), add token_position type 2021-01-11 15:19:24 -08:00
John Keiser 0f515785c6 Support reading scalars out of order 2021-01-11 15:17:46 -08:00
John Keiser 66db102c70 Use imprecise double comparison for sajson 2021-01-11 15:12:12 -08:00
John Keiser ab859f7952 Add nlohmann_json benchmarks 2021-01-11 15:12:12 -08:00
John Keiser 6367e55a5f Use new double differ in kostya/large_random benchmarks 2021-01-11 15:12:12 -08:00
Daniel Lemire b61f2799a8 This makes the float errors explicit. 2021-01-11 15:12:12 -08:00
John Keiser 1b4d3bcbb6 Add sajson benchmarks 2021-01-11 15:12:12 -08:00
John Keiser 45479558ba Merge pull request #1376 from simdjson/jkeiser/ondemand-runtime
Use runtime-selected implementation for stage 1 on demand
2021-01-11 14:59:52 -08:00
John Keiser 6fed8d2a26 Use active implementation for stage 1 on demand 2021-01-11 14:57:52 -08:00
Daniel Lemire 7dbe4caf3f Taking a float and adding hundreds of zeros, you may get a truncated value that is just one over the desired value (bug fix) (#1388)
* Found a bug where if take some float and add many zeros, you may get a truncated value that is just one over the desired value.
2021-01-11 17:07:25 -05:00
John Keiser ce1756425f Merge pull request #1360 from simdjson/jkeiser/ondemand-docs
Add On Demand documentation
2021-01-09 13:34:08 -08:00
John Keiser 920f535500 Reamalgamate 2021-01-07 08:49:54 -08:00
Daniel Lemire f29b70c63e Adding GitHub Actions VS - without exceptions. (#1362)
* Adding GitHub Actions VS - without exceptions.

* Rename.
2021-01-06 09:40:35 -05:00
John Keiser 1e690e505b Merge pull request #1371 from simdjson/jkeiser/ondemand-insitu-manualtime
Add yyjson_insitu tests, make insitu tests more accurate
2021-01-05 14:38:52 -08:00
John Keiser cd27bf0745 Add yyjson_insitu tests 2021-01-05 12:16:19 -08:00
John Keiser 62ded15cd8 Rename tweets/text/points -> result 2021-01-05 11:55:57 -08:00
John Keiser bc6907d280 Handle in situ document copies outside of the loop 2021-01-05 11:52:05 -08:00
John Keiser dcd2e13aec Measure time more accurately 2021-01-05 10:45:49 -08:00
John Keiser cfff8a5ed5 Merge pull request #1368 from simdjson/jkeiser/ondemand-rapidjson
Head-to-head rapidjson benchmarks
2021-01-05 09:58:22 -08:00
John Keiser 2d760e75dc Remove public: from structs 2021-01-05 09:10:22 -08:00
John Keiser f071a15591 Add insitu versions of rapidjson benchmark 2021-01-04 20:30:54 -08:00
John Keiser 6a595231b0 Get rid of templates from rapidjson benchmarks 2021-01-04 20:20:24 -08:00
John Keiser 065ea00066 Fix kostya<yyjson> issue 2021-01-04 20:03:22 -08:00
John Keiser 680cd6df34 Add usage benchmarks for rapidjson 2021-01-04 20:03:21 -08:00
John Keiser 22846f7577 Merge pull request #1363 from simdjson/jkeiser/ondemand-benchmarks
Head-to-head yyjson / ondemand benchmarks
2021-01-04 15:24:28 -08:00
John Keiser 5583a3c89b Add error handling to yyjson 2021-01-04 13:05:37 -08:00
John Keiser 25d1c7e622 Fix yyjson double reading 2021-01-04 12:37:25 -08:00
John Keiser 5add8ac255 Rearrange benchmarks to be easier to create 2021-01-04 12:33:41 -08:00
John Keiser 3af54a9978 Add Yyjson benchmarks 2021-01-01 23:04:19 -08:00
John Keiser 1dc4e9a84c Create custom result printers to show actual differences 2021-01-01 22:03:44 -08:00
John Keiser 9af41dd988 Add PartialTweets<Yyjson> benchmark 2021-01-01 22:03:38 -08:00
John Keiser 0039c5b981 Disallow parser.iterate("1"_padded), as it won't work 2021-01-01 19:18:00 -08:00
John Keiser 17f4f82827 Ondemand usage docs (and associated tests)
Also disallowed parsing a temporary padded_string, since the JSON *must*
live through the whole parse.
2021-01-01 19:17:58 -08:00
John Keiser 0314889c6d Merge pull request #1357 from simdjson/jkeiser/ondemand-quickstart
Add quick start for On Demand
2021-01-01 17:39:55 -08:00
John Keiser 7387e9f9a8 Add quick start for On Demand 2021-01-01 14:50:47 -08:00
John Keiser 158a3c53d8 Merge pull request #1351 from simdjson/jkeiser/unordered-lookup
Make `object["field"]` order-insensitive in On Demand
2020-12-24 13:33:09 -08:00
John Keiser 98666e84ea Add unordered version of LargeRandom ondemand benchmark 2020-12-23 09:14:45 -08:00
John Keiser d91491bf13 Update documentation for out-of-order fields 2020-12-23 09:14:45 -08:00
John Keiser 92443772d2 Enable all acceptance tests on mingw 2020-12-23 09:14:45 -08:00
John Keiser 041d59cc17 Create acceptance_tests, all_tests, etc. make targets
And use them for mingw build and test
2020-12-23 09:14:45 -08:00
John Keiser a405173d59 Break up ondemand_basictests into smaller executables
(Allows for faster compilation speeds)
2020-12-23 09:14:44 -08:00
John Keiser 93807bf230 Merge pull request #1352 from simdjson/jkeiser/assert-test-release
Make assert test succeed (not run anything) in Release builds
2020-12-23 08:34:18 -08:00
Daniel Lemire 0b67847b56 Adding clang/msys-ci (#1354) 2020-12-22 17:53:53 -05:00
ihsinme a72cb8a37a Update minifiercompetition.cpp (#1353)
as described in the description for the allocate_padded_buffer function: // The caller is responsible to free the memory (e.g., delete [] (...)).
but your code used the function free.
I propose to fix this error.
2020-12-22 16:50:37 -05:00
John Keiser ad4f718e0c Make assert test succeed (not run anything) in Release builds 2020-12-21 10:52:01 -08:00
John Keiser 5f92cd2b00 Merge pull request #1349 from simdjson/dlemire/prune_validate_utf8
We don't include anything but lookup4 ?
2020-12-21 10:05:31 -08:00
John Keiser a1cf588d5f Fix GCC 7 warning when inlining does its job 2020-12-21 09:19:07 -08:00
John Keiser dfc510f009 Add bench_ondemand_largerandom to check theory about executable format 2020-12-20 11:39:56 -08:00
John Keiser e7e09e444c Use find_field in benchmark 2020-12-20 11:39:56 -08:00
John Keiser 195acc3e45 Add find_field / find_field_unordered to object 2020-12-20 11:39:50 -08:00
John Keiser b8426584fc Make field lookup order-insensitive. 2020-12-19 13:57:29 -08:00
Daniel Lemire 6a2435ab32 Merge branch 'master' into dlemire/prune_validate_utf8 2020-12-19 10:46:14 -05:00
Daniel Lemire 85001c55fb Fixing UTF-8 validation under PPC64 (#1346)
* Entering a new UTF-8 test

* Maybe *I* had a bug in the tests.

* Replacing nulls with 1s.

* Let us try to be more verbose.

* Return 0.

* Fixing issue.

* Adding puzzler scenario.

* Fixing PPC64

Co-authored-by: Daniel Lemire <dlemire@rcs-power9-talos>
2020-12-19 10:42:27 -05:00
Daniel Lemire 8c4cf7757f I meant to remove these files a while ago. 2020-12-18 15:29:08 -05:00
John Keiser f785f76d98 Merge pull request #1342 from simdjson/jkeiser/iter-safety
Safety: assert in debug mode when on demand values are used out of order
2020-12-16 15:58:29 -08:00
Daniel Lemire c90ee57203 This might make the fuzzer error debuggable. (#1345) 2020-12-16 18:31:29 -05:00
John Keiser d670906ff3 Don't keep a separate at_start boolean in object 2020-12-15 11:29:31 -08:00
Daniel Lemire c578f63f34 Fixing issue 1337 (#1338)
* Fixing issue 1337

* This test should always run.

* Removing bad attribute access.
2020-12-14 16:20:36 -05:00
Daniel Lemire 9a404bdcdc Reenabling the optimized kernels (main branch). (#1344)
* Reenabling the optimized kernels (main branch).

* Defining SIMDJSON_CAN_ALWAYS_RUN_PPC64 and SIMDJSON_CAN_ALWAYS_RUN_ARM64

* Adding the bad UTF8 string from the fuzzer.

* Taking into account John's comments.

* Bumping the lib version.

* Update CMakeLists.txt
2020-12-14 14:28:45 -05:00
friendlyanon 91b07ba075 Allow build without download (#1334)
* Add option for downloading dependencies

* Format the boost json import code

Co-authored-by: friendlyanon <friendlyanon@users.noreply.github.com>
2020-12-13 19:07:29 -05:00
John Keiser f9c6dedca1 Add test for out-of-order parse asserts 2020-12-13 13:39:47 -08:00
John Keiser 73c7b7db3d Safety: check index of scalar values before use 2020-12-11 11:57:09 -08:00
John Keiser 6b02b06581 Merge pull request #1330 from simdjson/jkeiser/depth-tracking
Permit partial iteration in On Demand
2020-12-09 12:40:58 -08:00
Paul Dreik 5f7b2bac12 fuzz on power (#1326)
* first try

* use ubuntu 20.04, do the fuzzing

* new try at power fuzz

* hard code clang version

* setting env variables does not seem to work

* use fuzzer-no-link

* switch to Debian Buster for power fuzz

* use non-sanitizer build for power

* me not like yaml

* fix bad syntax
2020-12-07 18:12:36 -05:00
John Keiser 806cb39103 Clean up some more benchmark/test code 2020-12-07 13:44:58 -08:00
John Keiser 2eaeac53e4 Revamp design documentation to match new design 2020-12-07 13:09:44 -08:00
John Keiser 3baba73cf5 Don't call functions in assume (VS2019 Clang doesn't like it) 2020-12-07 11:17:24 -08:00
John Keiser db6bf15361 Allow all array/object/etc. to be copied 2020-12-06 16:29:53 -08:00
John Keiser 3aa3175378 Add tests for recovering from partial child iteration 2020-12-06 16:19:06 -08:00
John Keiser 4c63956624 Enable object["x"]["y"] 2020-12-06 15:23:52 -08:00
John Keiser c89647af9e Make all values use same underlying iterator 2020-12-06 15:23:52 -08:00
John Keiser 1303a88769 Unconditionally track depth 2020-12-06 15:23:52 -08:00
John Keiser aa1eabbb56 Add benchmark that stops early 2020-12-06 15:23:51 -08:00
Daniel Lemire cbacec0760 Releasing 0.7.0. 2020-12-04 18:56:15 -05:00
0xflotus 82fcf141f7 fix: small typo error (#1328) 2020-12-03 13:16:45 -05:00
Daniel Lemire aaa12c8fb6 more thread testing (#1324)
* Adding a few tests.

* More tests.

* Trailing.

* More links/documentations.
2020-12-02 11:33:36 -05:00
Daniel Lemire 9b5150daef Fixing issue 1247 (#1325) 2020-12-01 19:09:55 -05:00
Daniel Lemire 9304d88920 Prototype test for issue 1299: using parse_many, find the location of the end of the last document (#1301)
* Prototype test for issue 1299.

* This improves the documentation.

* Removing trailing white spaces.

* Removing trailing spaces

* Trailing.
2020-12-01 15:59:20 -05:00
Paul Dreik 725ca010e7 add ndjson fuzzer (#1304)
* add ndjson fuzzer

* reproduce #1310 in the newly added unit test

Had to replace the input, because:
1)
the fuzzer uses the first part of the input to determine
the batch_size to use, so that has to be cut off

2)
the master now protects against low values of batch_size

I also made the test not return early, so the error is triggered.
2020-12-01 15:58:41 -05:00
Daniel Lemire 59c857e969 Merge branch 'master' of github.com:simdjson/simdjson 2020-12-01 15:31:44 -05:00
Daniel Lemire 45c9136443 Fixed odd issue. 2020-12-01 15:31:24 -05:00
Daniel Lemire bc4087ac96 Hunting for data races in document_stream (#1323)
* Adding matching tests.

* Actually adding thread testing actions.
2020-12-01 12:40:15 -05:00
Daniel Lemire d9c4191e8a This should fix an issue we have with unclosed strings with document_stream (#1321)
* This should fix an issue we have with unclosed strings.

* Patching the fallback kernel.

* Better guarding the code.

* Patching the fallback.
2020-11-30 13:43:57 -05:00
Daniel Lemire 3fa40b8dc2 Adding an example corresponding to issue 1316 (documentation enhancement) (#1317)
* Adding an example.

* Updated other doc file.

* Trying to take into account @jkeiser's comments.

* Some people prefer empty final lines.
2020-11-27 17:40:29 -05:00
Daniel Lemire dc69bc28ae Trying to verify recent document stream issues. (#1318)
* Trying to verify recent document stream issues.

* Adding another one.

* More thorough tests.

* Removing trailing spaces.

* Working toward exposing some issues.

* Tweaking.
2020-11-27 17:04:10 -05:00
Daniel Lemire 53577f11e1 Explicit worker disposal. 2020-11-27 15:39:43 -05:00
Daniel Lemire 1abb64f6f6 This fixes issue 1302 (#1303)
* This verifies issue 1302

* I believe that this fixes the issue.

* Let us do it differently.

* Better comments.
2020-11-27 14:19:36 -05:00
Mikhail Matrosov b442b29ccf Mark comparison operators as const (#1320)
Co-authored-by: Mikhail Matrosov <mikhail.matrosov@aimtech.com>
2020-11-27 14:18:42 -05:00
Daniel Lemire 5609851747 This will guard the batch_size so it cannot be so low as to accidentally burn through your CPU. (#1319)
* This will guard the batch_size so it cannot be so low as to accidentally burn through your CPU.
2020-11-27 09:37:54 -05:00
Paul Dreik 68a8004518 don't memcpy after failed alloc (#1315)
Should fix https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=27675
2020-11-21 07:52:24 +01:00
Paul Dreik 0b39e3a6cf add fuzzer for padded_string (#1312)
This also fixes an overflow problem.
2020-11-19 16:51:56 +01:00
Paul Dreik 924ad2d592 when amalagamating, replace the SIMDJSON_IMPLEMENTATION (#1306) 2020-11-17 20:50:49 +01:00
Paul Dreik 5202d07a77 add script and instructions for minimizing and cleansing fuzz crashes (#1305) 2020-11-17 20:49:29 +01:00
friendlyanon b632107a7a Use the org's own PPA for CMake (#1295)
Co-authored-by: friendlyanon <friendlyanon@users.noreply.github.com>
2020-11-10 13:55:59 -05:00
Paul Dreik f62ca21dd1 enable boost json (#1292)
* bump boost.json and see if it works in simdjson CI

* enable boost json

* clean up

* add boost json to deps

* use boost if std::string_view is available

* add build with c++20

* use docker image which has the proper libc++ installed
2020-11-10 13:55:04 -05:00
friendlyanon 553befa012 Disable Github CI in feature branches (#1298)
Forks that would like to contribute via PRs from feature branches
needlessly run CI on those branches on top of the PRs.
This is a waste of resources.

Co-authored-by: friendlyanon <friendlyanon@users.noreply.github.com>
2020-11-10 13:52:58 -05:00
Paul Dreik def624a50c update version tag (#1297) 2020-11-08 10:17:06 -05:00
Daniel Lemire 268f26a84f Tweak of the documentation. 2020-11-07 16:33:12 -05:00
Paul Dreik d9456b3030 fix numeric_limits usage problem on windows caused by the max macro (#1293)
See https://stackoverflow.com/questions/2789481/problem-calling-stdmax/2789509#2789509
2020-11-06 06:55:27 +01:00
Daniel Lemire f195f849d0 Helping contributors. (#1289) 2020-11-05 10:27:35 -05:00
friendlyanon 669e5b91b4 Improve CI workflows (#1291)
* Fix Cirrus CI

CMake is not installed at this point yet.

* Add caching in Circle CI

* Add caching to the MinGW Github workflows

* Fix Circle CI config

Co-authored-by: friendlyanon <friendlyanon@users.noreply.github.com>
2020-11-05 08:42:00 -05:00
Daniel Lemire a06e0958ca We do not want the amalgamate.py script to run *ever* if you do not have at least Python 3. (#1290) 2020-11-04 13:52:52 -05:00
friendlyanon a56149e79a Cache CMake dependencies in CI (#1282)
Co-authored-by: friendlyanon <friendlyanon@users.noreply.github.com>
2020-11-04 13:35:33 -05:00
friendlyanon c805fc28a4 Remove git modules (#1258)
* Bump minimum CMake version

* Remove unnecessary git checks

* Move benchmark options where they are used

* Declare helper functions for dependencies

The custom solution here is tailored for fast configure times, but only
works for dependencies on Github.

* Import dependencies using the declared commands

* Remove git submodules

* Call target_link_libraries properly

target_link_libraries must not be called without a requirement
specifier.

* Fix includes for competition

Co-authored-by: friendlyanon <friendlyanon@users.noreply.github.com>
2020-11-04 13:34:29 -05:00
Daniel Lemire 218c274090 Updating main branch for legacy libc++ support (#1288)
* Updating main branch for legacy libc++ support

* Adopting

* Removing unnecessary math header.

* Updating the single-header files so we can pass the new tests.

* Portable infinite-value detection is hard.

* Working toward disabling boost json selectively.

* Selectively disabling Boost JSON

* More work toward selectively disabling boost json.
2020-11-04 12:24:42 -05:00
Tyler Kennedy 921c79f26f Add method to get the total number of slots used by an array in the t… (#1253)
* Add method to get the total number of slots used by an array in the tape.

* Whoops
2020-11-04 10:35:54 -05:00
Paul Dreik af4db55e66 remove trailing whitespace (#1284) 2020-11-03 21:48:09 +01:00
Paul Dreik 9f78559cc8 detect trailing whitespace in a CI job (#1268) 2020-11-03 20:41:19 +01:00
Paul Dreik 23b4bc93aa move amalgamate from bash to python (#1278)
This is much faster (from 3.5 to 0.14 seconds)
2020-11-03 07:35:16 +01:00
Daniel Lemire 6321df078a This fixes very minor "mistakes". (#1281) 2020-11-02 20:04:04 -05:00
Convery e6258377d9 Additional define to silence the 32-bit portability warning. (#1279)
Under compilers like MSVC the `#pragma message` about portability will be issued for each translation module; regardless of whether or not `SIMDJSON_PORTABILITY_H` has already been defined. As such a new define `SIMDJSON_NO_PORTABILITY_WARNING`, can be defined prior to the inclusion of `<simdjson.h>` to silence it.
2020-11-02 08:37:13 -05:00
Jeremy Ong b3a26fd0cc Do not enable -fPIC when compiling on Windows (#1280)
Regardless of the compiler, Windows targets do not support -fPIC,
as position independent code is already implicitly enabled. Compiling
simdjson with Clang on Windows will error because -fPIC is an
unsupported option for target 'x86_64-pc-windows-msvc'.
2020-11-02 08:18:04 -05:00
Paul Dreik 47669566da fix unintended early return in ondemand unit test loops (#1263)
fix uninteded early return in ondemand unit test loops

go through and fix warnings appearing in qtcreator,

qualify with std::, add const, abort on error

get rid of ulp_distance, not needed anymore when parsing is exact
2020-11-01 19:08:40 +01:00
Paul Dreik 03a1bb0a5b detect if amalgamation is needed (#1269)
output amalgamation date to be locale and timezone independent
2020-11-01 19:07:15 +01:00
Paul Dreik 54ffbbe7db remove asserts from compute_float_64 (#1276) 2020-11-01 18:34:42 +01:00
Paul Dreik 0b82f07115 fix segfault in numberparsing #1273 (#1274)
This was a read overflow.
2020-11-01 18:27:21 +01:00
Paul Dreik 265db2e533 fix non ascii sources (#1275)
Master does not build because of non-ascii sources, merging without waiting for CI.
2020-11-01 11:14:01 +01:00
Paul Dreik 2b2abf4895 reamalgamate 2020-11-01 07:03:17 +01:00
Paul Dreik f93fb21c95 optionally disable deprecated apis (#1271)
Introduce cmake option SIMDJSON_DISABLE_DEPRECATED_API (default Off)
which turns off deprecated simdjson api functions by setting the macro
 SIMDJSON_DISABLE_DEPRECATED_API.

For non-cmake users, users will have to set SIMDJSON_DISABLE_DEPRECATED_API
by some other means to disable the api.

Closes #1264
2020-11-01 06:38:52 +01:00
Paul Dreik b7fe764e6c fuzz more of generic/numberparsing.h (#1272)
make the ondemand fuzzer use more of the api
2020-11-01 06:29:16 +01:00
Paul Dreik 500e4c3572 fuzz with the intended clang version (#1267)
This builds the CI fuzzers with the intended clang version. It also allows users to set the clang version locally,
in case they need to.

It also switches the CI fuzzers to use an optimized sanitizer build, to do something oss-fuzz doesn't and get more done in the short time the CI fuzzer runs.
2020-10-31 08:22:49 +01:00
friendlyanon 55281c01fb Fix unintended Drone CI break (#1266)
* Use 'set -e' as it is portable

* Install git on the i386 images

* Remove CMake PPA from arm64 images

CMake's PPA doesn't actually distribute arm64 binary packages. See
related issues:
https://gitlab.kitware.com/cmake/cmake/-/issues/17923
https://gitlab.kitware.com/cmake/cmake/-/issues/20122

* Use Debian Buster instead of Ubuntu Bionic Beaver

Buster has all the packages in apt that is needed, which is convenient

* Install Clang 6.0 explicitly

Make sure that what gets installed is clang 6.0 as the step name
suggests.
https://packages.debian.org/buster/clang-6.0

* Install CMake from buster-backports

Co-authored-by: friendlyanon <friendlyanon@users.noreply.github.com>
2020-10-30 22:47:40 -04:00
Daniel Lemire a8bf10ea5a Minor patch. 2020-10-30 14:51:50 -04:00
friendlyanon 9f60093b41 Update CMake to at least 3.16 in Drone CI (#1261)
* Add script for CMake PPA

* Call the CMake PPA script in Drone CI

"apt-get update -qq" can be omitted, as that command is already called
by the script to pull in necessary packages for the CMake GPG keys.

* Remove sudo calls in the CMake PPA script

This script is intended to be run in Docker images, where the default
user is already root.

* Use echo instead of printf

* Use /etc/os-release instead of lsb_release

lsd_release could be installed, but os-release is just more convenient
to grab the version code from at this point.

* On Debian images grab CMake from buster-backports

It's not wise to mix Ubuntu PPAs with Debian and buster-backports has
CMake 3.16, which is recent enough for our purposes.

Co-authored-by: friendlyanon <friendlyanon@users.noreply.github.com>
2020-10-30 13:55:35 -04:00
Daniel Lemire 562d4f4f58 Fixing a minor logical error. 2020-10-29 16:42:50 -04:00
Paul Dreik ac87437588 fuzz the on demand api (#1220) 2020-10-29 19:14:44 +01:00
Daniel Lemire b1444b4dfb Mostly tiny changes, with one optimization to fallback for number parsing. (#1265)
* Mostly tiny changes, with one optimization to fallback for number parsing.

* Missed an update.
2020-10-29 11:18:11 -04:00
friendlyanon ed21875083 Remove old CMake version (#1259)
The images used by github already come with a sufficiently recent CMake
version instead of a very outdated one. See:
https://github.com/actions/virtual-environments

Co-authored-by: friendlyanon <friendlyanon@users.noreply.github.com>
2020-10-28 09:44:13 -04:00
Daniel Lemire 0249b5b311 Update CONTRIBUTORS 2020-10-27 18:44:28 -04:00
Danila Kutenin f46a0f64f2 PPC64 support (#1254)
* Initial PPC64 support

* Add travis CI

* Fix outdated cmake version for travis

* Fix indendtation

* Try another workaround for outdated cmake in travis

* Try beta cmake

* Add dash before beta

* Use builtin snaps

* Use cmake as rocksdb

* Test cmake on bionic

* Remove unnecessary things from travis

* Remove unnecessary things from travis

* Another try of compiler install

* Add all major compilers

* Add all major compilers

* Add all major compilers

* Tweak travis a bit

* Typo

* More robust travis

* Typos typos typos

* Add fewer compilers, add non specific build for clang and gcc, should be the final config

* CMAKE_FLAGS is in incorrect place

* Remove default implementation

* Limit build thread number

* Fall back prefix_xor to a usual implementation, no performance boost is noticed

* Test for power9 as it is the main architecture for OpenPOWER right now

* Add to documentation to build with power9 as the implementation is compatible but compiler optimizations is not

* Replace ARM with PPC in the comment
2020-10-27 18:43:39 -04:00
Jonathan Wakely 1fd0447dbb Remove repeated words (#1252) 2020-10-26 20:41:01 -04:00
Jeremy Ong 9856201f5c Disable exceptions when compiling with MSVC (#1256)
Projects that link simdjson from MSVC with exceptions off will
include simdjson headers which transitively include STL headers.
The MSVC STL stipulates that _HAS_EXCEPTIONS=0 be defined or code
requiring exceptions will be enabled. This change adds a new job
to the appveyor build matrix to verify the build and tests with
exceptions disabled, and disables exceptions at the compiler level
when SIMDJSON_EXCEPTIONS is specified to OFF.
2020-10-26 14:11:25 -04:00
Daniel Lemire a75c07065f Fix for issue 1246. We document the relationship between parser instances and elements (#1250)
* Fix for issue 1246.

* Adopting John's wording.
2020-10-26 08:40:45 -04:00
Daniel Lemire 6a86ef5a7d Issue release 2020-10-23 09:32:25 -04:00
Daniel Lemire 500e5d6759 Update README.md 2020-10-23 09:21:16 -04:00
Daniel Lemire e3f2c9f29a Update README.md 2020-10-23 09:18:47 -04:00
Daniel Lemire 3458e6248b Update README.md 2020-10-23 09:15:04 -04:00
Daniel Lemire 14039d05a9 Adding a new benchmark for ondemand: distinct user id (#1239)
* Adding a distinct user id benchmark

* reenabling everything

* Removing an unnecessary "value()".

* Better tests of the examples and some fixes.

* Guarding exception code.
2020-10-23 08:47:01 -04:00
Daniel Lemire c592da4937 Adds yyjson to our internal benchmarks. (#1244) 2020-10-21 16:23:20 -04:00
Daniel Lemire 61fb4244f2 There are a couple of extra value() that should not be there (#1242) 2020-10-21 12:37:22 -04:00
Daniel Lemire a503e022d8 Update README.md 2020-10-21 11:43:36 -04:00
Daniel Lemire 0942dc0764 This fixes a typo and makes the types more explicit (#1241) 2020-10-20 17:41:37 -04:00
Daniel Lemire 0d6919dd99 Reenable the on-demand tests and allows us to convert a raw string into a C++ string. (#1232)
* Reenable the on-demand tests and allows us to convert a raw string into a C++ string.

* Fixing a 1-byte buffer overrun.

* More documentation.

* Adding more tests.

* Enabling the new tests

* Committing a nicer example.

* Not yet happy but this should fix our failures.

* Duh.

* Ok. Making it easier to get string_view instances from field instances.

* It is a struct.

* Trying to satisfy VS.

* Adopting John's name.
2020-10-19 20:22:24 -04:00
Daniel Lemire 3e8e797bc2 Typo. 2020-10-19 17:30:52 -04:00
Daniel Lemire 0a907ec694 Tweaking further the documentation. (#1237)
* Tweaking further the documentation.

* More details.

* Another sentence.

* Saving.

* Tweaking more
2020-10-19 16:51:04 -04:00
Paul Dreik f1b4a54991 add fuzz element (#1204)
* add definitions for is_number and tie (by lemire)
* add fuzzer for element
* update fuzz documentation
* fix UB in creating an empty padded string
* don't bother null terminating padded_string, it is done by the std::memset already
*  refactor fuzz data splitting into a separate class
2020-10-17 05:48:50 +02:00
Paul Dreik 58e7106df1 remove unused function parse_unsigned 2020-10-16 22:17:11 +02:00
Paul Dreik 7bf391c54a fix potential use of uninitialized value warning, avoid casting away const
This fixes a "potentially use of uninitialized value" warning, as well as a cstyle cast to non-const.
2020-10-16 22:14:42 +02:00
Daniel Lemire 07a6e098c8 This would allow users to find out what builtin is. (#1227)
* This would allow users to find out what builtin is.

* Trying another approach.

* Added instructions.

* Cleaning up the printout.

* Let us be less invasive.

* Adding a comment.
2020-10-15 21:58:42 -04:00
Daniel Lemire e4897d6b54 We have hardcoded 32 (#1236) 2020-10-15 21:57:10 -04:00
Daniel Lemire 23026d966b Tweaking. 2020-10-15 21:55:23 -04:00
Daniel Lemire 3cd98df30d This adds new tests regarding ordering. (#1233)
* This adds new tests regarding ordering.

* Updating the documentation with more examples.

* Adding compilation tests.

* Pruning code for exceptions.

* Guarding exceptionless.
2020-10-15 16:41:14 -04:00
Daniel Lemire 001be23258 Being more specific regarding the padding. (#1228)
* Being more specific regarding the padding.

* Even more precise.
2020-10-14 13:35:51 -04:00
Daniel Lemire c85b6682e0 This is a cleaner on-demand documentation (for discussion). (#1226)
* This is a cleaner on-demand documentation (for discussion).

* Added stable APIs.
2020-10-14 13:35:28 -04:00
Daniel Lemire bb2bc98a22 Fix issue https://github.com/simdjson/simdjson/issues/1127 (#1224) 2020-10-13 09:18:54 -04:00
Daniel Lemire 43da4f7ccc Corrected number 2020-10-12 17:59:13 -04:00
Daniel Lemire 37e6d1e9c7 new number parsing (#1222)
* Remove our dependency on strtod_l by bundling our own slow path.

* Ok. Let us drop strtod entirely.

* Trimming down the powers to -342.

* Removing useless line.

* Many more comments.

* Adding some DLL exports.

* Let the gods help those who rely on windows+gcc.

* Marking the subnormals as unlikely. This is pretty much "performance neutral", but it might help just a bit with twitter.json.
2020-10-10 12:47:49 -04:00
Paul Dreik 1d9926698e update how boost.json is invoked, fix missing separators (#1203)
* initial try at adding boost json to the benchmark

* clean up

* qualify memcpy etc. with std::

* clang format

* extra space

* update benchmark with help from Vinnie Falco from Boost.json

* add missing separators
2020-10-09 18:22:37 -04:00
Daniel Lemire b04f64e02c Simplifying slightly the logic in the cmake (#1219) 2020-10-09 18:10:58 -04:00
Daniel Lemire c6d710b14b Merge branch 'master' of github.com:simdjson/simdjson 2020-10-09 16:46:51 -04:00
Daniel Lemire 2e07850622 Updating cxxopts to latest. 2020-10-09 16:46:30 -04:00
Daniel Lemire 1b6888281e Update README.md 2020-10-09 10:54:48 -04:00
Daniel Lemire ce94411dff Tweaking the documentation to better answer https://github.com/simdjson/simdjson/issues/1218 2020-10-09 10:02:56 -04:00
Paul Dreik 58a3098cd8 fix broken fuzzing github action job (#1221) 2020-10-09 12:44:17 +02:00
Paul Dreik 8a68163905 simplify fuzzing only dynamically supported implementations (#1201)
This refactors the dynamic check of which implementations are supported at runtime.

It also reduces duplicated effort in the CI fuzzing job, the differential fuzzers don't need to run with different values of SIMDJSON_FORCE_IMPLEMENTATION.

There is also a convenience script to run the fuzzers locally, to quickly check that the fuzzers still build, run and no easy to find bugs are there. It should be handy not only when developing the fuzzers, but also when modifying simdjson.
2020-10-09 05:29:54 +02:00
Paul Dreik 1f98e64b71 fix merge conflict on master (#1217) 2020-10-07 10:05:31 +02:00
John Keiser a9480a768b Merge pull request #947 from simdjson/jkeiser/stream-parse
On-Demand Parsing
2020-10-06 16:04:27 -07:00
John Keiser ed94514fc2 Remove ondemand_basictests from Win32 for now 2020-10-06 14:38:28 -07:00
Daniel Lemire 1f41cc2030 Making it clearer that parse_many is meant for *small* documents. (#1205)
* Making it clearer that parse_many is meant for *small* documents.

* Update parse_many.md
2020-10-06 17:19:34 -04:00
John Keiser 6455ec36ec Reamalgamate 2020-10-06 11:29:46 -07:00
John Keiser 676a3d068c Add non-top-level array iteration test 2020-10-06 11:29:46 -07:00
John Keiser 5533f8d87b Add object iteration error tests 2020-10-06 11:29:46 -07:00
John Keiser 93af7b61ce Add array iteration error tests 2020-10-06 11:29:46 -07:00
John Keiser 364ad5529d Add basic error tests 2020-10-06 11:29:46 -07:00
John Keiser 1974a46fe0 Remove validate tests and unimplemented cast tests from ondemand 2020-10-06 11:29:46 -07:00
John Keiser 5327ab9903 Remove ondemand minify and format tests 2020-10-06 11:29:46 -07:00
John Keiser 235d191bae Add Twitter exception tests 2020-10-06 11:29:46 -07:00
John Keiser 4eb80ec75a Add DOM API exception tests 2020-10-06 11:29:45 -07:00
John Keiser 2900459222 Separate twitter tests from DOM API tests 2020-10-06 11:29:45 -07:00
John Keiser 9088792b0e Disable value["x"] (unsafe, convert to object first) 2020-10-06 11:29:45 -07:00
John Keiser b41fe7beab Add object indexing tests 2020-10-06 11:29:45 -07:00
John Keiser 00f9bb8a07 Add null tests 2020-10-06 11:29:45 -07:00
John Keiser a90e1637cb Add boolean tests 2020-10-06 11:29:45 -07:00
John Keiser 4bad5c0241 Add numeric value tests 2020-10-06 11:29:45 -07:00
John Keiser ce09d82fc7 Test strings 2020-10-06 11:29:45 -07:00
John Keiser 5b926b8196 Support array iteration over document 2020-10-06 11:29:45 -07:00
John Keiser c719ccdb48 Add tests for empty object/array 2020-10-06 11:29:45 -07:00
John Keiser 9f1786aeb1 Add .get(T) to value/document 2020-10-06 11:29:45 -07:00
John Keiser 0bb83e06bc Fix root number parsing 2020-10-06 11:29:45 -07:00
John Keiser 2ba67c2bc2 [WIP] && and & versions of each operator 2020-10-06 11:29:45 -07:00
John Keiser cae91983ec Fix issue with early destruction 2020-10-06 11:29:45 -07:00
John Keiser 3190ef0c1f Check benchmark results in release builds 2020-10-06 11:29:45 -07:00
John Keiser c7c1372833 Allow reuse of value to try multiple types 2020-10-06 11:29:45 -07:00
John Keiser ba02cda55f Allow direct document iteration 2020-10-06 11:29:45 -07:00
John Keiser 512a94afaa Move error to json_iterator 2020-10-06 11:29:45 -07:00
John Keiser 6d978c383a Kinder, gentler implementation selection
- Allow user to specify SIMDJSON_BUILTIN_IMPLEMENTATION
- Make cmake -DSIMDJSON_IMPLEMENTATION=haswell *only* specify haswell
- Move negative implementation selection to
-DSIMDJSON_EXCLUDE_IMPLEMENTATION
- Automatically select SIMDJSON_BUILTIN_IMPLEMENTATION if
SIMDJSON_IMPLEMENTATION is set
- Move implementation enablement mostly to implementation files
- Make implementation enablement and selection simpler and more robust
- Fix bug where programs linked against simdjson were not passed
SIMDJSON_XXX_IMPLEMENTATION or SIMDJSON_EXCEPTIONS
2020-10-06 11:29:45 -07:00
John Keiser 938678f87f Complete draft design doc 2020-10-06 11:29:45 -07:00
John Keiser 9dcf5fca5b Add ondemand rationale to beginning of document 2020-10-06 11:29:45 -07:00
John Keiser 88f0dc4726 Add API docs, ensure parser and field methods called with & 2020-10-06 11:29:45 -07:00
John Keiser 8ae7910aba Namespace documentation 2020-10-06 11:29:45 -07:00
John Keiser b70e85fd10 Only include source in bench_sax 2020-10-06 11:29:45 -07:00
John Keiser 99bc591366 Don't enable fallback test unless fallback is explicitly selected 2020-10-06 11:29:45 -07:00
John Keiser f4963cd1c5 Ensure CI builds all tested implementations 2020-10-06 11:29:45 -07:00
John Keiser 4859cb8528 Add SIMDJSON_ONDEMAND_SAFETY_RAILS 2020-10-06 11:29:45 -07:00
John Keiser c42b91980b Fix VC++ forward friend declarations 2020-10-06 11:29:45 -07:00
John Keiser 8b3c8820e0 Fix numberparsingcheck to define found_invalid_number before simdjson.h 2020-10-06 11:29:39 -07:00
John Keiser 29bc78a486 Add ondemand to arm64/fallback/westmere 2020-10-04 12:47:30 -07:00
John Keiser 30fe86ed32 Use simdjson::builtin instead of haswell/begin+end 2020-10-04 12:47:30 -07:00
John Keiser 85cefd5a00 Alias simdjson::builtin to simdjson::SIMDJSON_BUILTIN_IMPLEMENTATION 2020-10-04 12:47:30 -07:00
John Keiser b5a328e0ca Set SIMDJSON_BUILTIN_IMPLEMENTATION to minimum supported 2020-10-04 12:47:30 -07:00
John Keiser 209a2e8fc3 Fix ARM compile 2020-10-04 12:47:30 -07:00
John Keiser 8b978e6aea Don't call functions max() (conflicts with Windows macro) 2020-10-04 12:47:30 -07:00
John Keiser b4df0e7c9e Fix domnoexcept to actually be noexcept 2020-10-04 12:47:30 -07:00
John Keiser 76aeda6b00 Fix [] on simdjson_result<value> to require temp object 2020-10-04 12:47:30 -07:00
John Keiser 1a0ad6d9c3 Fix bug document.get_xxx() 2020-10-04 12:47:30 -07:00
John Keiser 6b219e3e25 Use ::stage2 where it's needed 2020-10-04 12:47:30 -07:00
John Keiser 1e90691013 Add parse_unsigned/parse_integer/parse_double to SKIP_NUMBERPARSING 2020-10-04 12:47:30 -07:00
John Keiser 3577c87c88 Fix amalgamation with generic/ files in include/ 2020-10-04 12:47:30 -07:00
John Keiser baf6607e74 Make ondemand build without #include "simdjson.cpp" 2020-10-04 12:47:30 -07:00
John Keiser a700848bae Move ondemand implementation to include/ 2020-10-04 12:47:30 -07:00
John Keiser 9bbfd5804e Put haswell/westmere/fallback/amd64 in simdjson namespace 2020-10-04 12:47:30 -07:00
John Keiser b234d74f43 Remove unnamed namespace from ondemand 2020-10-04 12:47:30 -07:00
John Keiser cd49ff330d Fix g++-7 quickstart errors 2020-10-04 12:47:30 -07:00
John Keiser 49faf7af1a Make simdjson_result implementation-specific 2020-10-04 12:47:30 -07:00
John Keiser c892b83c93 Make ondemand classes usable from simdjson_result 2020-10-04 12:47:30 -07:00
John Keiser 985b52331a Require object to be exact and in order 2020-10-04 12:47:30 -07:00
John Keiser 021dded9dd Add Kostya benchmarks 2020-10-04 12:47:30 -07:00
John Keiser 8fd0cdc732 Iterate value without going through indirection
Avoids issues with value being released early
2020-10-04 12:47:30 -07:00
John Keiser fe7a4d42d3 Fix top level values 2020-10-04 12:47:30 -07:00
John Keiser e89d6353af Add a "sum" benchmark with no appending to vector 2020-10-04 12:47:30 -07:00
John Keiser c5bb74d184 Pave the way for non-record-based benchmarks 2020-10-04 12:47:30 -07:00
Daniel Lemire 874349c928 Making the code cleaner. 2020-10-04 12:47:30 -07:00
Daniel Lemire 157604b3a5 I think that this is better (fairer) code. 2020-10-04 12:47:30 -07:00
John Keiser b935544d65 Make benchmark output easier to follow 2020-10-04 12:47:30 -07:00
Daniel Lemire 03271df579 This adds a frequency column (useful because if the frequency tanks, then other numbers are suspect). 2020-10-04 12:47:30 -07:00
John Keiser 0633d3a07d Make branch miss numbers integers 2020-10-04 12:47:30 -07:00
John Keiser 045377a594 Fix errors with g++ 2020-10-04 12:47:30 -07:00
John Keiser b5c8030f19 Fix LargeRandom<OnDemand> 2020-10-04 12:47:30 -07:00
John Keiser 7c2072789c Fix issue with strings not including their first character 2020-10-04 12:47:30 -07:00
John Keiser f75e856d2b Compare records to ensure benchmarks work 2020-10-04 12:47:30 -07:00
John Keiser 44d689bc6e Make instructions / cycle counters more useful 2020-10-04 12:47:30 -07:00
John Keiser 9e433c2f19 Move benchmarks into their own directories 2020-10-04 12:47:30 -07:00
John Keiser 21b6279b74 Add document-level number/atom parsing 2020-10-04 12:47:30 -07:00
John Keiser 4d89076bdc Check for EOF when skipping containers
Revert that?

Or not
2020-10-04 12:47:30 -07:00
John Keiser 71e4ff7e03 Fix compile errors on C++11/noexcept 2020-10-04 12:47:30 -07:00
John Keiser d2dfda6583 Ensure iterator is kept alive while iterators are active 2020-10-04 12:47:30 -07:00
John Keiser 6a855f528b Ensure only leaf values can push the iterator 2020-10-04 12:47:30 -07:00
John Keiser fb93109c2d Use default constructors/assignment where possible 2020-10-04 12:47:30 -07:00
John Keiser bd190af7a3 Require iterators to finish cleanly and release 2020-10-04 12:47:30 -07:00
John Keiser 44268b0c6b Remove object::has_next 2020-10-04 12:47:30 -07:00
John Keiser 6451e5e7d1 Remove array::has_next 2020-10-04 12:47:30 -07:00
John Keiser 2b3c4c68e4 Ride the lightning 2020-10-04 12:47:30 -07:00
John Keiser 7030cf2433 Release object/array after finished 2020-10-04 12:47:30 -07:00
John Keiser 26d7881b80 Require value to be deleted after most value conversions 2020-10-04 12:47:29 -07:00
John Keiser 21fe42b28c Release the iterator after use 2020-10-04 12:47:29 -07:00
John Keiser d5ecf68d26 Make json_iterator_ref unique 2020-10-04 12:47:29 -07:00
John Keiser 0ddff4ec7d json_iterator * -> json_iterator_ref 2020-10-04 12:47:29 -07:00
John Keiser 283ac3191f Rename parse->iterate, add iterate_raw 2020-10-04 12:47:29 -07:00
John Keiser 4dd0c80dad Move current_string_buf_loc to json_iterator 2020-10-04 12:47:29 -07:00
John Keiser 3b53c6ca47 Use json_iterator as shared state instead of document 2020-10-04 12:47:29 -07:00
John Keiser 4e3b4809ea [WIP] Nascent design doc for on demand 2020-10-04 12:47:29 -07:00
John Keiser a90b8fb449 Remove depth tracking from ondemand api 2020-10-04 12:47:29 -07:00
John Keiser 1da509027e Add root number/atom parsing functions 2020-10-04 12:47:29 -07:00
John Keiser 5b96e4761e Remove side-effecting assumption 2020-10-04 12:47:29 -07:00
John Keiser 311ea79238 Fix noexceptions builds 2020-10-04 12:47:29 -07:00
John Keiser 98be2c91df Fix SAX benchmarks to actually push to vector 2020-10-04 12:47:29 -07:00
John Keiser 2657e5e226 Fix points SAX to actually record points 2020-10-04 12:47:29 -07:00
John Keiser cfcb0d4fb7 Use json_iterator in array/object 2020-10-04 12:47:29 -07:00
John Keiser 97d03f3215 token_iterator -> json_iterator 2020-10-04 12:47:29 -07:00
John Keiser 4065529bdf Don't try to compile Haswell benchmarks on ARM 2020-10-04 12:47:29 -07:00
John Keiser 0a6260b1d8 Fix clang 6 compile issue 2020-10-04 12:47:29 -07:00
John Keiser 12caf2510e Mark unused variables 2020-10-04 12:47:29 -07:00
John Keiser a58d2f710d Fix C++11 error 2020-10-04 12:47:29 -07:00
John Keiser 6be2db8c42 Fix SAX benchmark to actually add tweets 2020-10-04 12:47:29 -07:00
John Keiser 5cf68416d8 Don't bother comparing field names in parserandom 2020-10-04 12:47:29 -07:00
John Keiser ebcb3c6b3b On-demand parse implementation 2020-10-04 12:47:29 -07:00
Paul Dreik 04267e0f6b add boost.json to benchmark (#1202)
Add boost.json to the benchmark.
It was accepted into boost 20201003, see https://lists.boost.org/Archives/boost/2020/10/250129.php.

The upstream repo is (expected to eventually be migrated to boost): https://github.com/CPPAlliance/json
2020-10-04 10:00:09 +02:00
Daniel Lemire a540e6afc5 Testing on minimalist alpine (linux) images (#1200)
* Tweaking header includes to make it safer.

* Adding the actual tests.

* Fixing my syntax.
2020-10-02 13:32:09 -04:00
Daniel Lemire f1841e48b3 Minor fixes to some headers (tweak) (#1198) 2020-10-02 12:29:05 -04:00
Daniel Lemire 9865bb6904 Make it possible to check that an implementation is supported at runtime (#1197)
* Make it possible to check that an implementation is supported at runtime.

* add CI fuzzing on arm 64 bit

This adds fuzzing on drone.io arm64

For some reason, leak detection had to be disabled. If it is enabled, the fuzzer falsely reports a crash at the end of fuzzing.

Closes: #1188

* Guarding the implementation accesses.

* Better doc.

* Updating cxxopts.

* Make it possible to check that an implementation is supported at runtime.

* Guarding the implementation accesses.

* Better doc.

* Updating cxxopts.

* We need to accomodate cxxopts

Co-authored-by: Paul Dreik <github@pauldreik.se>
2020-10-02 11:04:51 -04:00
Paul Dreik e06ddea784 add CI fuzzing on arm 64 bit
This adds fuzzing on drone.io arm64

For some reason, leak detection had to be disabled. If it is enabled, the fuzzer falsely reports a crash at the end of fuzzing.

Closes: #1188
2020-10-01 10:12:37 +02:00
Daniel Lemire 8b5a89c136 Parsing floats with 19 significant digits should be fine. (#1191)
* Parsing floats with 19 significant digits should be fine.

* Adding more tests with very long mantissa.
2020-09-29 19:42:43 -04:00
Daniel Lemire da093c1982 Fixing "undefined behavior" issue in new fast_itoa functions (#1186)
* Fixing "undefined behavior" issue.

* Simplifying our custom atoi

* Fixing minor bug
2020-09-29 19:17:03 -04:00
Daniel Lemire 048fb6278a This adds two tests to verify a new fuzzer issue. (So far I could not verify.) (#1194) 2020-09-29 11:45:41 -04:00
Paul Dreik f1b0778f79 add utf8 fuzzer
This enables the utf8 fuzzer, now when #1187 is fixed
2020-09-27 21:11:13 +02:00
Daniel Lemire 0e584fa4a5 Attempt to fix issue 1187. (#1192) 2020-09-27 12:04:47 -04:00
Paul Dreik f44386008c add minifier fuzzers (#1172)
This adds a minifier fuzzer. There is also an utf-8 fuzzer, but it is disabled until  #1187 is fixed.

Run all fuzzers bug the utf-8 one in the github CI fuzz.
2020-09-26 14:25:00 +02:00
Daniel Lemire 60c139a844 Faster and more correct serialization (#1168)
* Adding new files.

* Better.

* Fixing minifier and adding tests.

* Adding benchmarks.

* Including the array header.

* Replacing old stream-based code by the new code.

* Doubling up the itoa.

* Hidden away to_chars in internal namespace.

* Removing the repetitions.

* Documented the atoi functions.

* Tuning the escape sequences.

* Moving the operators off the main namespace.

* Added more tests.

* Tweaking the implementation so that it works with and without exp.

* The string_builder template and mini_formatter class
 are not part of  our public API and are subject to change
 at any time!

* Adding a benchmark and some optimization.

* Cleaning.

* Strictly speaking, this header is needed.
2020-09-23 10:00:39 -04:00
Daniel Lemire f410213003 Improve documentation on padding
- Improves and clarifies the documentation on padding.
 - Use std:: prefix for memcpy, strlen etc.

Related to issues #1175 and #1178
2020-09-23 09:07:14 +02:00
Daniel Lemire 19cb5d57db Some minor documentation fixes. (#1177) 2020-09-17 13:17:35 -04:00
Paul Dreik 30b912fc81 fuzz at_pointer
This adds a fuzzer for at_pointer() which recently had a bug.

The #1142 bug had been found with this fuzzer

Also, it polishes the github action job:

    cross pollinate the fuzzer corpora (lets fuzzers reuse results from other fuzzers)
    use github action syntax instead of bash checks
    only run on push if on master
2020-09-16 21:17:43 +02:00
Daniel Lemire 7fc07e2d5e Correcting typo 2020-09-16 11:11:49 -04:00
Daniel Lemire 72c83d9430 This avoids locale-dependent number parsing at the standard library level (#1157)
* This avoids locale-dependent number parsing at the standard library level.

* Adding missing cast.

* Inserting the missing "endif"

* Trial and error.

* Another attempt.

* Another tweak.

* Another fix.

* Restricting it even more.

* Tweaking our symbol checks.

* Somewhat smarter tests.

* Nice comments.

* Minor simplification.

* Adding cerr.
2020-09-15 11:36:18 -04:00
Daniel Lemire bfbac12f76 We were forgetting to check the end bytes at the end of the UTF8 validation. (#1173)
* We were forgetting to check the end bytes at the end of the UTF8 validation.

* Silencing the sanitizer

* Better explanation.
2020-09-15 11:33:09 -04:00
Daniel Lemire 461f7dc9f9 Remove unnecessary comment. 2020-09-14 10:44:10 -04:00
Daniel Lemire 3e5497e2f9 Fixes issue 1170 and makes the usage of minify easier. (#1171)
* Fixes issue 1170 and makes the usage of minify easier.

* This should get the fallback implementation to detect unclosed strings.
2020-09-12 16:20:20 -04:00
Paul Dreik 6ecbcc7c19 add multi implementation fuzzer (#1162)
This adds a fuzzer which parses the same input using all the available implementations (haswell, westmere, fallback on x64).

This should get the otherwise uncovered sourcefiles (mostly fallback) to show up in the fuzz coverage.
For instance, the fallback directory has only one line covered.
As of the 20200909 report, 1866 lines are covered out of 4478.

Also, it will detect if the implementations behave differently:

    by making sure they all succeed, or all error
    turning the parsed data into text again, should produce equal results

While at it, I corrected some minor things:

    clean up building too many variants, run with forced implementation (closes #815 )
    always store crashes as artefacts, good in case the fuzzer finds something
    return value of the fuzzer function should always be 0
    reduce log spam
    introduce max size for the seed corpus and the CI fuzzer
2020-09-11 23:46:22 +02:00
John Keiser 8cef02e8e8 Merge pull request #1167 from simdjson/jkeiser/isolate-checkperf-more
Isolate checkperf more
2020-09-11 11:58:37 -07:00
John Keiser caabfd14b3 Isolate checkperf more 2020-09-11 08:53:41 -07:00
Daniel Lemire 2ffbaa9578 This will isolate the perf checks in CI (#1164)
* This will isolate the perf checks.

* Fixed typo
2020-09-10 18:15:45 -04:00
Daniel Lemire c40aeaec3a Fix for issue 1147 (#1153)
* This must be a typo

* Improving documentation of the string conversion.

* Minor update.
2020-09-03 13:18:15 -04:00
John Keiser 80e84a3ad0 Merge pull request #1143 from simdjson/jkeiser/classify
Simplify operator classification lookup on Intel
2020-09-03 10:08:14 -07:00
Daniel Lemire 0552335ec1 Fixing the issue. (#1151) 2020-09-02 18:41:59 -04:00
Daniel Lemire 7aea774b21 Adding a tests and a fix for empty strings in at_pointer (#1148)
* Adding a test.

* More tests.
2020-09-02 17:04:56 -04:00
Daniel Lemire 4d4ed92055 Removes 5 KB of tables in the number parsing routine (#1139)
* Removes 5 KB of tables at the expense, and a load, at the expense
of a multiplication and a shift. I have not benchmarked this new
code, but my expectation is that it should be largely performance
neutral. The motivation is to reduce the size of the library slightly.
There is also a matter of elegance.
2020-09-02 15:47:11 -04:00
John Keiser f0ec26992a Remove bit_or (bad perf on Windows) 2020-09-01 08:43:09 -07:00
John Keiser 62e8332b34 Use simd8x64 abstractions in classification 2020-09-01 08:43:09 -07:00
John Keiser 0925f71987 Simplify operator classification lookup on Intel 2020-09-01 08:43:07 -07:00
Daniel Lemire 4c11652808 This must be a typo (#1140) 2020-08-28 20:35:13 -04:00
Daniel Lemire 5b10c38e43 Make parse_many safer. (#1137) 2020-08-20 22:22:46 -04:00
Daniel Lemire 3316df9195 Adding test for issue 1133 and improving documentation (#1134)
* Adding test.

* Saving.

* With exceptions.

* Added extensive tests.

* Better documentation.

* Tweaking CI

* Cleaning.

* Do not assume make.

* Let us make the build verbose

* Reorg

* I do not understand how circle ci works.

* Breaking it up.

* Better syntax.
2020-08-20 14:03:14 -04:00
Daniel Lemire 5d355f1a8b release candidate (#1132) 2020-08-19 18:12:23 -04:00
John Keiser 2ff91103ca Remove SIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT (#1131) 2020-08-19 17:11:13 -04:00
Daniel Lemire a954d50ad4 This improves our documentation. (#1128)
* This improves our documentation.

* Removing tags for doxygen.

* You need a recent cmake remark.
2020-08-19 14:02:08 -04:00
John Keiser 5be4d37aff Merge pull request #1129 from simdjson/jkeiser/inl
Move inline/* to *-inl.h
2020-08-19 09:52:34 -07:00
John Keiser 1e6c9dbcfa Reamalgamate 2020-08-19 09:16:25 -07:00
John Keiser 708a56872d Move inline/* to *-inl.h 2020-08-19 09:09:31 -07:00
John Keiser 0a2bca3f73 Merge pull request #1101 from simdjson/jkeiser/yakety-sax
Basic SAX interface with benchmarks
2020-08-19 09:05:44 -07:00
Daniel Lemire 1ec710c985 Updating the documentation for hackers. 2020-08-19 10:59:24 -04:00
Daniel Lemire d5a44f9ad4 Merge branch 'master' of github.com:simdjson/simdjson 2020-08-19 10:36:01 -04:00
Daniel Lemire e64dca7144 Tweaking. 2020-08-19 10:35:49 -04:00
John Keiser b2779c35df Fix issue with unsupported unreachable on Windows 2020-08-18 21:35:12 -07:00
John Keiser 9b11e119d4 Make skip_double() comment more explicit 2020-08-18 21:25:03 -07:00
John Keiser 988c62baed Encapsulate significant_digits() 2020-08-18 21:25:03 -07:00
John Keiser eb3e640003 Return bool from compute_float_64 2020-08-18 21:25:03 -07:00
John Keiser 9475b947f5 Return error codes from parse_number 2020-08-18 21:25:03 -07:00
John Keiser 18564f1ae2 Don't benchmark unless haswell is available 2020-08-18 21:25:03 -07:00
John Keiser 638f1deb62 Add DOM tweet reader for comparison 2020-08-18 21:25:03 -07:00
John Keiser 7e74d30f45 [WIP] tweet reader SAX benchmark 2020-08-18 21:25:03 -07:00
John Keiser ce8d0f8135 Add visit_primitive() helper in iterator 2020-08-18 21:25:03 -07:00
John Keiser 872127b722 Move is_array management together with depth 2020-08-18 21:25:03 -07:00
John Keiser e180dc44bc Move container logging into json_iterator 2020-08-18 21:25:03 -07:00
John Keiser 268b8845a9 Document tape_builder 2020-08-18 21:25:03 -07:00
John Keiser 74c47995a3 Document json_iterator 2020-08-18 21:25:03 -07:00
John Keiser 24f5936cbf Give is_array responsibility to json_iterator 2020-08-18 21:25:03 -07:00
John Keiser bdfa8aca28 Separate interface from implementation to make interface clearer 2020-08-18 21:25:03 -07:00
John Keiser 15eb1ad922 Preface visitor methods with visit() 2020-08-18 21:25:03 -07:00
John Keiser 6ec98ee8b1 Add error codes to all things 2020-08-18 21:25:03 -07:00
John Keiser c5862d6de9 Remove empty_object/empty_array 2020-08-18 21:25:03 -07:00
John Keiser 57eb55446f Cache string value locally 2020-08-18 21:25:03 -07:00
John Keiser abd1399a7f Don't check depth at the end (unnecessary check) 2020-08-18 21:25:03 -07:00
John Keiser 57eba21ee5 Fall through goto labels where possible 2020-08-18 21:25:03 -07:00
John Keiser 1b56211a70 Give start_*/end_* error codes 2020-08-18 21:25:03 -07:00
John Keiser d8974d53b2 Keep value around between states 2020-08-18 21:25:03 -07:00
John Keiser 5ecd17f49e Log unconsumed input as an error 2020-08-18 21:25:03 -07:00
John Keiser 6bb99aec3c Merge structural_parser+iterator into json_iterator 2020-08-18 21:25:03 -07:00
John Keiser a67e83e24e Remove parse_* from visitor method names 2020-08-18 21:25:03 -07:00
John Keiser 5a3c3134ec Move value into common place to be shared across states 2020-08-18 21:25:03 -07:00
John Keiser ce8b9ee8c4 Move finish() out to walk_document 2020-08-18 21:25:03 -07:00
John Keiser 970dfc9f67 builder -> visitor, parser -> iter 2020-08-18 21:25:03 -07:00
John Keiser 04d39c0961 Make tape_builder primary entry point to stage 2 2020-08-18 21:25:01 -07:00
John Keiser d6339aa015 Set is_array in builder 2020-08-18 17:41:48 -07:00
John Keiser 11076bf337 containing_scope -> open_container 2020-08-18 17:41:16 -07:00
Daniel Lemire 8a8eea53a2 Prefixing macros (issue 1035) (#1124)
* Renaming partially done.

* More prefixing.

* I thought that this was fixed.

* Missed one.

* Missed a few.

* Missed another one.

* Minor fixes.
2020-08-18 18:25:36 -04:00
Daniel Lemire 09bd7e8ef8 Verification and fix for issue 1063 (JSON Pointers) (#1064)
* Specification is not followed.

* Fixes.

* Do not pass string_view by reference.

* Better documentation.

* The example is written for exceptions.

* Better documentation.

* Updating with deprecation.

* Updating example.

* Updating example.
2020-08-18 17:23:18 -04:00
John Keiser 9356619380 Merge pull request #1110 from simdjson/jkeiser/number-corruption
Fix potential buffer overrun with heavily customized input and padding
2020-08-18 14:17:25 -07:00
Daniel Lemire fc15147cf5 This allows the users to disable threading. (#1122)
* This allows the users to disable threading.

* This would disable bash scripts under FreeBSD. (#1118)

* This would disable bash scripts under FreeBSD.

* Let us also disable GIT.

* Let us try to just disable GIT

* Nope. We must have both bash and git disabled.

* This allows the users to disable threading.
2020-08-18 16:43:08 -04:00
John Keiser ab6b7a8044 Make last_structural() helper 2020-08-18 10:12:42 -07:00
John Keiser 07c2fe726e Fail if hash is unclosed at start 2020-08-18 10:10:01 -07:00
John Keiser fa355603fb Add test for corruption while parsing a number 2020-08-18 10:10:01 -07:00
Daniel Lemire 109bb505d8 Adding a new test file. (#922)
* Adding a new test file.

* Renaming.
2020-08-18 10:42:45 -04:00
Daniel Lemire 4a6eebc0e4 This corrects a small typo in the documentation. (#1121)
* This corrects a small typo in the documentation.

* Modifying the test as well.
2020-08-18 08:36:15 -04:00
PavelP 78ce2b473e Copy README.md/amalgamate_demo.cpp only if output dir isn't the same as ${SCRIPTPATH} (#1113)
+ use test's `-ef` file operator to check if ${SCRIPTPATH} and ${AMALGAMATE_OUTPUT_PATH} are not the same
2020-08-18 08:35:21 -04:00
Daniel Lemire 6beb5f5587 This adds debug tests in CI. (#1123)
* This adds debug tests in CI.

* Removing silly labels.

* Typo
2020-08-17 13:36:30 -04:00
Daniel Lemire 501fed6c4f This would disable bash scripts under FreeBSD. (#1118)
* This would disable bash scripts under FreeBSD.

* Let us also disable GIT.

* Let us try to just disable GIT

* Nope. We must have both bash and git disabled.
2020-08-17 11:50:57 -04:00
Daniel Lemire b1bd8e9ee2 Update issue templates 2020-08-17 08:16:39 -04:00
Daniel Lemire daeca1bb18 Basics. (#1116) 2020-08-14 17:28:09 -04:00
Daniel Lemire 17f6d5208f Documenting and fixing the case where a string is immediately followed by a scalar (#1106)
* Documenting and fixing.

* More cleaning.

* Being a bit cleaner.
2020-08-14 16:19:57 -04:00
John Keiser bee4d7a12b Merge pull request #1108 from simdjson/jkeiser/ncgdoc
Remove information about nonexistent computed gotos :)
2020-08-12 10:39:20 -07:00
Daniel Lemire f32e3e0c7c Please don't use GNU-specific flags. (#1109) 2020-08-11 09:12:39 -04:00
John Keiser 1b69612246 Remove information about nonexistent computed gotos :) 2020-08-10 16:29:24 -07:00
Daniel Lemire 9e93509a56 Fix number parsing (too lenient). (#1107)
* Fix number parsing (too lenient).

* Minor tweak.

* These are Booleans.

* Tweaking test config
2020-08-10 18:10:11 -04:00
Daniel Lemire ef45cd3342 Let us be explicit about standard compliance (#1099)
* Let us be explicit about standard compliance

* More explicit.
2020-08-06 18:24:36 -04:00
Daniel Lemire 46fe2e6b44 Update README.md 2020-08-06 18:03:10 -04:00
John Keiser 1133c2cc1d Merge pull request #1070 from pps83/bugfix/Do-not-update-README-and-amalgamate_demo
Do not update README.md and amalgamate_demo.cpp from amalgamate.sh
2020-08-06 12:43:56 -07:00
Daniel Lemire fde10553e0 Update HACKING.md 2020-08-06 15:06:31 -04:00
Daniel Lemire 83615ff351 Fixes issue 1088 (#1096) 2020-08-06 11:42:13 -04:00
Pavel P 352eb4cb6d Do not update README.md and amalgamate_demo.cpp from amalgamate.sh
README.md and amalgamate_demo.cpp are always the same, there is no point to keep a copy and recreate them from amalgamate.sh
2020-08-06 09:11:20 +06:00
Daniel Lemire 75c75ac00c This is dead code. (#1095) 2020-08-05 16:48:10 -04:00
John Keiser d9bcf52db2 Merge pull request #1062 from simdjson/jkeiser/reamalgamate
Fix C++ 20 compilation
2020-08-04 21:08:24 -07:00
Daniel Lemire 43f0362e6d Update README.md 2020-08-04 19:44:52 -04:00
John Keiser ed5e313c73 Reamalgamate 2020-08-04 13:17:23 -07:00
John Keiser c0010f60e6 Add view support to simdjson_result<array/object> 2020-08-04 13:17:23 -07:00
John Keiser 75301e4cf5 Fix C++20 compilation 2020-08-04 13:17:23 -07:00
John Keiser 875c8fdcbe Merge pull request #1071 from pps83/quick-example-at-the-top-of-simdjson.h
Add a quick example at the top of simdjson.h
2020-08-04 11:07:21 -07:00
John Keiser a0b1642dc0 Merge pull request #1090 from simdjson/jkeiser/sax
Split stage 2 in SAX fashion
2020-08-04 10:58:59 -07:00
John Keiser 1d7e54f8c9 Merge pull request #1089 from simdjson/jkeiser/stage2misc
Special case empty objects and arrays
2020-08-04 10:57:11 -07:00
Daniel Lemire 77c8581bc0 Flipping the flags 2020-08-04 12:59:23 -04:00
John Keiser 5dd625916b Decrement depth just before checking 2020-08-03 23:09:21 -07:00
John Keiser e3d7718cf3 Simplify value switch statements 2020-08-03 23:09:21 -07:00
John Keiser 9eccd7b1fb Inline start_object/start_array 2020-08-03 23:09:21 -07:00
John Keiser 5b05d126b4 Consolidate start_object calls 2020-08-03 23:09:20 -07:00
John Keiser 03aaf189c1 Use parse_primitive (negative perf!) 2020-08-03 23:09:20 -07:00
John Keiser 6ef9395419 "parser.parser" -> "parser.dom_parser" 2020-08-03 23:09:20 -07:00
John Keiser 3a56e13b78 Make parse() a method 2020-08-03 23:09:19 -07:00
John Keiser ec28acba3d De-templatize stage2::structural_parser 2020-08-03 23:09:15 -07:00
John Keiser ee6647ce40 Make parse part of structural_parser 2020-08-03 17:50:51 -07:00
John Keiser 03d54f8f6e Use SAX model for stage 2 2020-08-03 17:50:51 -07:00
John Keiser 553e6d7549 Don't check max depth on startup 2020-08-03 17:49:14 -07:00
John Keiser e6896ee71e Keep current JSON after checking primitive type 2020-08-03 13:30:13 -07:00
John Keiser e6762f9b48 Advance immediately upon evaluating a character 2020-08-03 13:26:56 -07:00
John Keiser 099bb1afef Pass buffer to primitive parse functions 2020-08-03 12:56:35 -07:00
John Keiser 9c33093c91 Name goto labels consistently 2020-08-03 11:47:38 -07:00
John Keiser 634d8038b9 Increment depth before starting a scope 2020-08-03 11:35:46 -07:00
John Keiser ad46154f2f Hardcode document start/end creation 2020-08-03 10:23:32 -07:00
Daniel Lemire c7fbb4615c Update README.md 2020-08-03 12:51:21 -04:00
John Keiser fa81068ea8 Simplify structural_parser.start() 2020-08-03 09:49:15 -07:00
John Keiser 70c2a1c9f9 Short-circuit empty objects/arrays 2020-08-03 09:36:18 -07:00
Pavel P 164fcb49d9 + reformat sample code 2020-08-03 19:48:41 +06:00
John Keiser 64cf18aa1e Merge pull request #1079 from simdjson/jkeiser/no-error
[3/3] Return errors immediately instead of using goto
2020-08-02 12:22:53 -07:00
John Keiser 66a68ce264 Return errors immediately instead of using goto 2020-08-02 12:04:12 -07:00
John Keiser 86162aaddb Merge pull request #1078 from simdjson/jkeiser/no-computed-goto
[2/3] Remove computed GOTOs
2020-08-02 11:49:35 -07:00
John Keiser 9cc7a94a94 Merge pull request #1065 from simdjson/jkeiser/anonymous-namespace
[1/3] Wrap simdjson kernels in anonymous namespaces
2020-08-02 11:37:11 -07:00
John Keiser 6bca1225e6 Add unlikely in strategic places 2020-08-01 18:19:36 -07:00
John Keiser 379a4e6a01 namespace { -> unnamed namespace 2020-08-01 14:46:23 -07:00
John Keiser 460cfcaf3e Make parse_structurals inline 2020-08-01 14:43:50 -07:00
John Keiser 8e69103822 Remove computed GOTO 2020-08-01 14:43:50 -07:00
John Keiser 2f67dab2b6 Remove extraneous machine addresses 2020-08-01 14:43:50 -07:00
John Keiser bb65ebd8be Remove computed gotos from parse_value 2020-08-01 14:43:50 -07:00
John Keiser c46ea0390c Move { and [ to the start of the switch 2020-08-01 14:43:50 -07:00
John Keiser bc8a6dd2e3 Remove dead code 2020-08-01 14:43:10 -07:00
John Keiser b1478c37f6 Fix arm64 build 2020-08-01 14:43:10 -07:00
John Keiser 4e944a9f3c Eliminate unused functions in fallback 2020-08-01 14:43:10 -07:00
John Keiser c7fa9b5fe8 Make entire implementation namespaces anonymous 2020-08-01 14:43:10 -07:00
John Keiser 65148b123b Put anonymous namespace in front of everything 2020-08-01 14:43:10 -07:00
Daniel Lemire 2f92a34bb7 Turns out that passing dom::element by reference can be a performance killer. (#1086)
* Turns out that passing dom::element by reference can be a performance killer.

* Tweaking.
2020-08-01 10:31:47 -04:00
Daniel Lemire 54ed24f481 Update README.md 2020-07-31 15:47:42 -04:00
Daniel Lemire 268df9f67a Update basics.md 2020-07-31 15:43:34 -04:00
Daniel Lemire 84dc398d32 Adding a couple of tests. 2020-07-31 15:29:10 -04:00
Daniel Lemire f6a3205d10 Avoid allocations in global objects (#1082) 2020-07-30 13:14:56 -04:00
Christoph Reiter 522cb66582 Make MSYS2 CI jobs actually use MSYS2 (#1081)
The jobs were executed in powershell using the globally installed cmake.
This makes things actually run in a MSYS2 shell.

This also removes the msys/cygwin job because it doesn't build
(it complains about undeclared posix_memalign)
2020-07-29 19:34:14 -04:00
Daniel Lemire f873a140ce Tweaking 2020-07-27 16:24:27 -04:00
PavelP 36dfc5bbd1 Add missing strings.h include for non-windows builds (required by strcasecmp) (#1067)
addresses #1066
2020-07-27 16:23:06 -04:00
Daniel Lemire f80668e87f This removes the crazy alignment requirements. (#1073)
* This removes the crazy alignment requirements.
2020-07-27 16:19:01 -04:00
Daniel Lemire dcb5d47ee6 Being clearer. 2020-07-26 15:58:35 -04:00
PavelP e95c22eb21 Add MSYS target for msys2 github workflow (#1075)
* Add MSYS target for msys2 github workflow

* Minimized differences in mingw/mingw64 CI workflows
2020-07-26 15:33:57 -04:00
Daniel Lemire 9fb83e61ea We want the tests to run on PR. 2020-07-26 14:39:47 -04:00
Pavel P 1513cdf7bc Add a quick example at the top of simdjson.h 2020-07-26 14:31:03 -04:00
Daniel Lemire e33af1a3f8 Adding strings.h header. (#1074) 2020-07-25 15:27:19 -04:00
Daniel Lemire 857d77a10a Adding msys2 tests. 2020-07-25 14:32:30 -04:00
PavelP 0e431a0250 Use Unix line endings for c/c++ code (#1069)
This is required for amalgamate.sh to produce correct results
2020-07-25 13:53:31 -04:00
John Keiser 3acfc0b630 Merge pull request #1045 from simdjson/jkeiser/generic-2
Define namespaces inside generic files
2020-07-24 12:42:39 -07:00
Daniel Lemire 2ce5f69def fix recently introduced overflow (#1060)
* Various fixes.

* Clearer comment.
2020-07-24 13:59:24 -04:00
John Keiser 7d347be902 Untangle amalgamated headers 2020-07-24 02:56:41 -07:00
John Keiser a456d78fe0 really_inline more things 2020-07-24 02:56:41 -07:00
John Keiser bf67c967d6 Inline jsoncharutils per-implementation 2020-07-24 02:56:41 -07:00
John Keiser 44b7a7145c Include bitmanip/simd everywhere 2020-07-24 02:56:39 -07:00
John Keiser 3867ee71ed Include files where they are used 2020-07-24 02:56:37 -07:00
John Keiser 464f4813e3 Define namespaces inside generic files 2020-07-24 02:56:36 -07:00
John Keiser af8b52e7e8 Target region for entire compilation of an implementation 2020-07-24 02:48:25 -07:00
Daniel Lemire 796588900c Reenabling C++ 20 features. (#1059) 2020-07-21 18:12:04 -04:00
Daniel Lemire 4beb2ed507 Make simd8 64 uncopyable and other Visual Studio optimizations (#1031)
* Working on making simd8x64 immutable


* Even less invasive
2020-07-21 18:11:21 -04:00
Daniel Lemire 0ff6833e96 Update basics.md 2020-07-21 17:29:10 -04:00
Daniel Lemire e2cfcc52b3 Disabling cxx20 (#1058)
* Disabling C++ 20 features.

* Updating single-header.
2020-07-21 17:15:31 -04:00
Daniel Lemire fc8a46025e Better documentation of default_batch_size (#1056)
* Better documentation of default_batch_size

* Retweaking.
2020-07-21 15:15:21 -04:00
Joe Jevnik d2bea0c228 Add support for C++ 20 ranges. (#1050)
C++ 20 adds a new feature called "ranges", which provides components for dealing
with sequences of values: https://en.cppreference.com/w/cpp/ranges.

A range is like a normal object containing `begin` and `end`, except there are
also composable operations like maps, filters, joins, etc.
The iterator objects returned by a range's `begin` and `end` require a more
strict set of operations than is needed for a range-for loop.

This PR adds the extra operations needed to support turning `dom::array` and
`dom::object` into a range.
This PR does not depend on any C++ 20 behavior, the added operators are all
valid C++ 11, and are already part of the LegacyIterator concepts.
This PR adds extra code behind: `#if defined(__cpp_lib_ranges)` guards, which is
the new C++ 20 specified feature test macro for ranges support. When ranges
support is detected, extra compile time checks are added to ensure that
`dom::array` and `dom::object` satisfy the range concept. No runtime tests have
been added yet because these compile time checks should be sufficient.

If desired, the `static_assert` code could be moved out of the actual code
headers and put into a test file.
2020-07-21 13:27:39 -04:00
Daniel Lemire f016c2b72f Update README.md 2020-07-21 12:02:30 -04:00
Daniel Lemire be62058696 Adds some C++20 tests (only headers). (#1053)
* Adds some C++20 tests (only headers).

* Tweaking.
2020-07-21 10:37:52 -04:00
Daniel Lemire af18d5ed81 This adds a validation benchmark (#1040) 2020-07-20 18:56:39 -04:00
Daniel Lemire e9c91a1ce2 lookup4 (new UTF-8 validation) (#993)
* lookup4

* Self-document lookup4 and clean up extra bits

* Maintenance, to match against upcoming PR.

Co-authored-by: Daniel Lemire <lemire@gmai.com>
Co-authored-by: John Keiser <john@johnkeiser.com>
2020-07-20 18:20:07 -04:00
Daniel Lemire 29767b2886 Moving gcc 7 out of circle ci (#1052) 2020-07-20 17:49:55 -04:00
Daniel Lemire 96a31c69c5 Update README.md 2020-07-17 15:41:54 -04:00
Daniel Lemire 534632dc52 Minor tweak on number parsing (#1041)
* Tweak.
2020-07-17 12:14:10 -04:00
Daniel Lemire 8bf5f3d869 Trying to document more carefully the use of memcpy. (#1038)
* Trying to document more carefully the use of memcpy.

* Patching spelling.
2020-07-17 09:58:34 -04:00
Daniel Lemire c4f92322f5 Update README.md 2020-07-17 09:27:19 -04:00
Vitaly Baranov 1e4aa116e5 Choose active implementation only once. (#1044) 2020-07-16 18:17:56 -04:00
John Keiser 90cc1411da Merge pull request #1018 from simdjson/jkeiser/simplify-integer-parse
Remove some branches from number parsing
2020-07-16 12:21:43 -07:00
Daniel Lemire d13ce6768c Update README.md 2020-07-16 13:05:28 -04:00
gerrymanoim fd4a7f2150 DOC: Add another python binding to README (#1043) 2020-07-16 13:04:18 -04:00
Vitaly Baranov 6bd64c6873 Fix clang warning -Wused-but-marked-unused. (#1042)
* Fix clang warning -Wused-but-marked-unused.

* Fix build.
2020-07-15 13:28:51 -04:00
Daniel Lemire ba58d868e5 Update performance.md 2020-07-14 15:00:31 -04:00
Ben McMorran c50799ba3b Fix TOC links in basics documentation
The "++" in "C++" gets stripped from the generated anchors, so the links in the table of contents didn't work.
2020-07-13 17:02:35 -04:00
Daniel Lemire 039d82ff1b Returning basictests to its original function: basic tests (only) (#1010)
* The initial motivation behind basictests was for a quick set of sanity tests to check whether your code made sense. It
was not meant for thorough testing to find corner cases. However, over time, it grew to include such expensive tests.
This PR takes them out. It also allows us to bring back basictests to MinGW tests, since it is now cheap.

This is not an exercise in software engineering and making things prettier. This is a pragmatic change to improve our
test coverage and quality of life.

* Adds many more cheap tests.

Co-authored-by: Daniel Lemire <lemire@gmai.com>
2020-07-13 09:39:35 -04:00
Vitaly Baranov a2f0933d01 Fix undefined behavior: load of misaligned address in atomparsing.h (#1037) 2020-07-13 08:46:52 -04:00
Daniel Lemire 77e1e3cc18 Update performance.md 2020-07-12 18:35:15 -04:00
Daniel Lemire 7bdd41350a Update performance.md 2020-07-12 18:31:45 -04:00
John Keiser 6797a6ab56 Use const uint8_t * in number parsing 2020-07-10 09:17:23 -07:00
John Keiser 86b5928f5e Use parse_digit for decimal and exp parsing as well 2020-07-10 09:16:43 -07:00
John Keiser 6dbd15aa71 Move SIMDJSON_SKIPNUMBERPARSING method out 2020-07-09 15:55:10 -07:00
John Keiser 22e5b081c4 Remove is_integer 2020-07-09 15:55:10 -07:00
John Keiser d848f33c48 Simplify integer parsing 2020-07-09 15:55:10 -07:00
John Keiser c64367536d Eliminate "found_minus" parse_number() parameter 2020-07-09 15:55:09 -07:00
John Keiser fc0102b079 Use common parse_digit() funtion in int parsing 2020-07-09 15:33:22 -07:00
Daniel Lemire 62a39639c2 Update performance.md 2020-07-09 11:47:33 -04:00
Daniel Lemire 158aaff384 Update performance.md 2020-07-09 11:46:35 -04:00
Daniel Lemire fd836145fe Update performance.md 2020-07-09 11:45:47 -04:00
Daniel Lemire 697bafdd0a Update performance.md 2020-07-08 08:32:41 -04:00
Daniel Lemire 9675dcac44 Update performance.md 2020-07-06 19:03:18 -04:00
Daniel Lemire 48849d7866 Update README.md 2020-07-06 18:59:45 -04:00
Daniel Lemire d0ce2f0b5a Fixing clang under visual studio (#1028)
* Lots of fixes

* Removing some lambdas

* Removing some functional programming.

Co-authored-by: Daniel Lemire <lemire@gmai.com>
2020-07-06 18:58:19 -04:00
Daniel Lemire a19f635a6a clang is busted under appveyor (#1029)
Co-authored-by: Daniel Lemire <lemire@gmai.com>
2020-07-06 18:28:23 -04:00
Daniel Lemire 676ed59342 Adding more github actions (#1027)
* Adding more github actions


Co-authored-by: Daniel Lemire <lemire@gmai.com>
2020-07-06 18:20:06 -04:00
Daniel Lemire 4015f46b7d Adding a new flag to tell Visual Studio to include debugging information (#1026)
in the release builds. This makes it easier to profile inside Intel
VTune when needed.
2020-07-06 17:53:57 -04:00
Daniel Lemire 770cee7139 Fail when we "force inline" and visual studio bypasses us. (#1025) 2020-07-06 17:53:32 -04:00
Daniel Lemire a4619a54a7 Update README.md 2020-07-04 11:53:53 -04:00
Daniel Lemire f7d99f97a3 Update performance.md 2020-07-04 11:52:40 -04:00
Daniel Lemire 8b7df0c12e Update performance.md 2020-07-03 23:14:01 -04:00
Daniel Lemire bd780817f7 Update performance.md 2020-07-02 15:33:36 -04:00
John Keiser 82fb45aa2a Merge pull request #990 from simdjson/jkeiser/fast-large-integer
Don't reparse large integers
2020-07-01 12:49:43 -07:00
Daniel Lemire 74870a8189 Fixing issue 1013. (#1016)
* Fixing issue 1013.

* Bumping to 0.4.6

Co-authored-by: Daniel Lemire <lemire@gmai.com>
2020-07-01 14:14:51 -04:00
John Keiser 7a9f6b48f4 Replace TODOs with comments about why we DIDNTDO 2020-07-01 10:31:10 -07:00
John Keiser d3c089130d Check overflow without reparsing integers 2020-07-01 09:51:48 -07:00
John Keiser e0f3060527 Add negative/positive integer writing 2020-07-01 09:51:48 -07:00
John Keiser 4c1256acc4 Reduce nesting somewhat with different if() order 2020-07-01 09:51:48 -07:00
John Keiser 85f6f5bd29 Use macros to remove #ifdefs on every write 2020-07-01 09:51:48 -07:00
John Keiser 4d9eac663a Use a macro to get rid of #ifdefs on each invalid number check 2020-07-01 09:51:48 -07:00
Daniel Lemire 0ef4d90ad0 Fix for issue 1014. (#1015)
* Fix for issue 1014.

* Explanation.

Co-authored-by: Daniel Lemire <lemire@gmai.com>
2020-06-30 19:36:26 -04:00
Daniel Lemire 1a1e7edb02 Tweaking the recently introduced mingw tests. (#1011)
Co-authored-by: Daniel Lemire <lemire@gmai.com>
2020-06-30 12:47:44 -04:00
Daniel Lemire 51b835f71b Correcting typo (#1007)
Co-authored-by: Daniel Lemire <lemire@gmai.com>
2020-06-30 10:19:37 -04:00
Daniel Lemire e38fe3d361 Version update 2020-06-30 09:41:20 -04:00
myd7349 cc042c9936 CMAKE_VS_PLATFORM_TOOLSET might be empty (#1009)
According to https://gitlab.kitware.com/cmake/cmake/-/issues/17976,
CMAKE_VS_PLATFORM_TOOLSET is set only when using a Visual Studio generator.

When we use Ninja as the generator, CMAKE_VS_PLATFORM_TOOLSET will be empty.
As a result:
if(${CMAKE_VS_PLATFORM_TOOLSET} STREQUAL "v140")
will be treated as:
if( STREQUAL "v140")

We may also quote it like this:
if("${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v140")
but that won't make the warnings disappeared in VS2015.
2020-06-30 09:40:19 -04:00
Daniel Lemire 599e3bc937 Update README.md 2020-06-29 21:52:08 -04:00
Daniel Lemire 1fa0d940bc Update README.md 2020-06-29 21:44:05 -04:00
Daniel Lemire 7dc4a9525b Update README.md 2020-06-29 21:43:07 -04:00
Daniel Lemire b6f1f4ef64 Update basics.md 2020-06-29 21:41:50 -04:00
Daniel Lemire 3faae67663 New release 2020-06-29 21:11:58 -04:00
Daniel Lemire ccc94c9b05 Mingw tests (32-bit and 64-bit) (#1004) 2020-06-29 21:10:54 -04:00
Daniel Lemire 1fd30db726 This example in our documentation would not compile (#1005)
Co-authored-by: Daniel Lemire <lemire@gmai.com>
2020-06-29 16:25:11 -04:00
Daniel Lemire 0ba76ac066 This enables building the library under Visual Studio 2015 (#1002)
Co-authored-by: Daniel Lemire <lemire@gmai.com>
2020-06-29 08:43:47 -04:00
Daniel Lemire 8b661fe556 Merge pull request #1001 from simdjson/dlemire/justlib_install
We do not properly test just library.
2020-06-28 13:12:42 -04:00
Daniel Lemire 077907b7c3 Preparing a new patch release. 2020-06-28 12:40:13 -04:00
Daniel Lemire 172d669780 We do not properly test just library. 2020-06-28 12:25:17 -04:00
2118 changed files with 85627 additions and 326838 deletions
+21 -9
View File
@@ -4,28 +4,40 @@ configuration: Release
image: Visual Studio 2019
platform: x64
cache:
- C:\dependencies -> dependencies\CMakeLists.txt
environment:
# Forward slash is used because this is used in CMake as is
simdjson_DEPENDENCY_CACHE_DIR: C:/dependencies
matrix:
- job_name: VS2019
CMAKE_ARGS: -A %Platform%
- job_name: VS2019CLANG
CMAKE_ARGS: -A %Platform% -T ClangCL
CMAKE_ARGS: -A %Platform%
- job_name: VS2019ARM
CMAKE_ARGS: -A ARM64 -DCMAKE_CROSSCOMPILING=1 -D SIMDJSON_GOOGLE_BENCHMARKS=OFF # Does Google Benchmark builds under VS ARM?
CMAKE_ARGS: -A ARM64 -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_CROSSCOMPILING=1 -D SIMDJSON_GOOGLE_BENCHMARKS=OFF # Does Google Benchmark builds under VS ARM?
- job_name: VS2017 (Static, No Threads)
image: Visual Studio 2017
CMAKE_ARGS: -A %Platform% -DSIMDJSON_BUILD_STATIC=ON -DSIMDJSON_ENABLE_THREADS=OFF
CTEST_ARGS: -E checkperf
CMAKE_ARGS: -A %Platform% -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_ENABLE_THREADS=OFF
CTEST_ARGS: -LE explicitonly
- job_name: VS2019 (Win32)
platform: Win32
CMAKE_ARGS: -A %Platform% -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_ENABLE_THREADS=ON # This should be the default. Testing anyway.
CTEST_ARGS: -E checkperf
CMAKE_ARGS: -A %Platform% -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON -DSIMDJSON_ENABLE_THREADS=ON # This should be the default. Testing anyway.
CTEST_ARGS: -LE explicitonly
- job_name: VS2019 (Win32, No Exceptions)
platform: Win32
CMAKE_ARGS: -A %Platform% -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=ON -DSIMDJSON_ENABLE_THREADS=ON -DSIMDJSON_EXCEPTIONS=OFF
CTEST_ARGS: -LE explicitonly
- job_name: VS2015
image: Visual Studio 2015
CMAKE_ARGS: -A %Platform% -DSIMDJSON_DEVELOPER_MODE=ON -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_ENABLE_THREADS=OFF
CTEST_ARGS: -LE explicitonly
build_script:
- mkdir build
- cd build
- cmake --version
- cmake %CMAKE_ARGS% --parallel ..
- cmake %CMAKE_ARGS% ..
- cmake -LH ..
- cmake --build . --config %Configuration% --verbose --parallel
+127 -60
View File
@@ -1,24 +1,18 @@
version: 2.1
# We constantly run out of memory so please do not use parallelism (-j, -j4).
# Reusable image / compiler definitions
executors:
gcc7:
docker:
- image: gcc:7
environment:
CXX: g++
CC: gcc
BUILD_FLAGS: -j
CTEST_FLAGS: -j4 --output-on-failure
gcc8:
docker:
- image: conanio/gcc8
environment:
CXX: g++-8
CC: gcc-8
BUILD_FLAGS: -j
CTEST_FLAGS: -j4 --output-on-failure
CMAKE_BUILD_FLAGS:
CTEST_FLAGS: --output-on-failure
gcc9:
docker:
@@ -26,8 +20,8 @@ executors:
environment:
CXX: g++-9
CC: gcc-9
BUILD_FLAGS: -j
CTEST_FLAGS: -j4 --output-on-failure
CMAKE_BUILD_FLAGS:
CTEST_FLAGS: --output-on-failure
gcc10:
docker:
@@ -35,8 +29,8 @@ executors:
environment:
CXX: g++-10
CC: gcc-10
BUILD_FLAGS: -j
CTEST_FLAGS: -j4 --output-on-failure
CMAKE_BUILD_FLAGS:
CTEST_FLAGS: --output-on-failure
clang10:
docker:
@@ -44,8 +38,8 @@ executors:
environment:
CXX: clang++-10
CC: clang-10
BUILD_FLAGS: -j
CTEST_FLAGS: -j4 --output-on-failure
CMAKE_BUILD_FLAGS:
CTEST_FLAGS: --output-on-failure
clang9:
docker:
@@ -53,8 +47,8 @@ executors:
environment:
CXX: clang++-9
CC: clang-9
BUILD_FLAGS: -j
CTEST_FLAGS: -j4 --output-on-failure
CMAKE_BUILD_FLAGS:
CTEST_FLAGS: --output-on-failure
clang6:
docker:
@@ -62,11 +56,24 @@ executors:
environment:
CXX: clang++-6.0
CC: clang-6.0
BUILD_FLAGS: -j
CTEST_FLAGS: -j4 --output-on-failure
CMAKE_BUILD_FLAGS:
CTEST_FLAGS: --output-on-failure
# Reusable test commands (and initializer for clang 6)
commands:
dependency_restore:
steps:
- restore_cache:
keys:
- cmake-cache-{{ checksum "dependencies/CMakeLists.txt" }}
dependency_cache:
steps:
- save_cache:
key: cmake-cache-{{ checksum "dependencies/CMakeLists.txt" }}
paths:
- dependencies/.cache
install_cmake:
steps:
- run: apt-get update -qq
@@ -77,95 +84,140 @@ commands:
- checkout
- run: mkdir -p build
cmake_build:
cmake_build_cache:
steps:
- cmake_prep
- run: |
cd build &&
cmake $CMAKE_FLAGS -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
make $BUILD_FLAGS all
- dependency_restore
- run: cmake -DSIMDJSON_DEVELOPER_MODE=ON $CMAKE_FLAGS -DCMAKE_INSTALL_PREFIX:PATH=destination -B build .
- dependency_cache # dependencies are produced in the configure step
cmake_build:
steps:
- cmake_build_cache
- run: cmake --build build
cmake_test:
steps:
- cmake_build
- run: |
cd build && tools/json2json -h &&
cd build &&
tools/json2json -h &&
ctest $CTEST_FLAGS -L acceptance &&
ctest $CTEST_FLAGS -LE acceptance -E checkperf
ctest $CTEST_FLAGS -LE acceptance -LE explicitonly
cmake_assert_test:
steps:
- run: |
cd build &&
tools/json2json -h &&
ctest $CTEST_FLAGS -L assert
cmake_test_all:
steps:
- cmake_build
- run: |
cd build && tools/json2json -h &&
ctest $CTEST_FLAGS -L acceptance -LE 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 &&
cd build &&
tools/json2json -h &&
ctest $CTEST_FLAGS -DSIMDJSON_IMPLEMENTATION="haswell;westmere;fallback" -L acceptance -LE per_implementation &&
SIMDJSON_FORCE_IMPLEMENTATION=haswell ctest $CTEST_FLAGS -L per_implementation -LE explicitonly &&
SIMDJSON_FORCE_IMPLEMENTATION=westmere ctest $CTEST_FLAGS -L per_implementation -LE explicitonly &&
SIMDJSON_FORCE_IMPLEMENTATION=fallback ctest $CTEST_FLAGS -L per_implementation -LE explicitonly &&
ctest $CTEST_FLAGS -LE "acceptance|per_implementation" # Everything we haven't run yet, run now.
cmake_perftest:
steps:
- cmake_build_cache
- run: |
cmake -DSIMDJSON_ENABLE_DOM_CHECKPERF=ON --build build --target checkperf &&
cd build &&
ctest --output-on-failure -R checkperf
# we not only want cmake to build and run tests, but we want also a successful installation from which we can build, link and run programs
cmake_install_test: # this version builds, install, test and then verify from the installation
steps:
- run: cd build && make install
- run: 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++ -Ibuild/destination/include -Lbuild/destination/lib -std=c++17 -Wl,-rpath,build/destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json
cmake_installed_test_cxx20: # assuming that it was installed, this tries to build using C++20
steps:
- run: 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++ -Ibuild/destination/include -Lbuild/destination/lib -std=c++20 -Wl,-rpath,build/destination/lib -o linkandrun tmp.cpp -lsimdjson && ./linkandrun jsonexamples/twitter.json
jobs:
# static
gcc7:
description: Build and run tests on GCC 7 and AVX 2 with a cmake static build
executor: gcc7
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON }
steps: [ install_cmake, cmake_test, cmake_install_test ]
justlib-gcc10:
description: Build just the library, install it and do a basic test
executor: gcc10
environment: { CMAKE_FLAGS: -SIMDJSON_JUST_LIBRARY=ON }
steps: [ cmake_build, cmake_install_test ]
gcc10:
description: Build and run tests on GCC 10 and AVX 2 with a cmake static build, this test performance regression
environment: { CMAKE_FLAGS: -DSIMDJSON_JUST_LIBRARY=ON }
steps: [ cmake_build, cmake_install_test, cmake_installed_test_cxx20 ]
assert-gcc10:
description: Build the library with asserts on, install it and run tests
executor: gcc10
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON }
steps: [ cmake_test_all, cmake_install_test ]
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DCMAKE_CXX_FLAGS_RELEASE=-O3 }
steps: [ cmake_test, cmake_assert_test ]
assert-clang10:
description: Build just the library, install it and do a basic test
executor: clang10
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DCMAKE_CXX_FLAGS_RELEASE=-O3 }
steps: [ cmake_test, cmake_assert_test ]
gcc10-perftest:
description: Build and run performance tests on GCC 10 and AVX 2 with a cmake static build, this test performance regression
executor: gcc10
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DBUILD_SHARED_LIBS=OFF }
steps: [ cmake_perftest ]
gcc10:
description: Build and run tests on GCC 10 and AVX 2 with a cmake static build
executor: gcc10
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF }
steps: [ cmake_test, cmake_install_test, cmake_installed_test_cxx20 ]
clang6:
description: Build and run tests on clang 6 and AVX 2 with a cmake static build
executor: clang6
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON }
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF }
steps: [ cmake_test, cmake_install_test ]
clang10:
description: Build and run tests on clang 10 and AVX 2 with a cmake static build
executor: clang10
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_BUILD_STATIC=ON }
steps: [ cmake_test, cmake_install_test ]
environment: { CMAKE_FLAGS: -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF }
steps: [ cmake_test, cmake_install_test, cmake_installed_test_cxx20 ]
# libcpp
libcpp-clang10:
description: Build and run tests on clang 10 and AVX 2 with a cmake static build and libc++
executor: clang10
environment: { CMAKE_FLAGS: -DSIMDJSON_USE_LIBCPP=ON -DSIMDJSON_BUILD_STATIC=ON }
steps: [ cmake_test, cmake_install_test ]
environment: { CMAKE_FLAGS: -DSIMDJSON_USE_LIBCPP=ON -DBUILD_SHARED_LIBS=OFF }
steps: [ cmake_test, cmake_install_test, cmake_installed_test_cxx20 ]
# sanitize
sanitize-gcc10:
description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build
executor: gcc10
environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE=ON, BUILD_FLAGS: "", CTEST_FLAGS: -j4 --output-on-failure -E checkperf }
environment: { CMAKE_FLAGS: -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
steps: [ cmake_test ]
sanitize-clang10:
description: Build and run tests on clang 10 and AVX 2 with a cmake sanitize build
executor: clang10
environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: -j4 --output-on-failure -E checkperf }
environment: { CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
steps: [ cmake_test ]
threadsanitize-gcc10:
description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build
executor: gcc10
environment: { CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_SANITIZE_THREADS=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
steps: [ cmake_test ]
threadsanitize-clang10:
description: Build and run tests on clang 10 and AVX 2 with a cmake sanitize build
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 ]
# dynamic
dynamic-gcc10:
description: Build and run tests on GCC 10 and AVX 2 with a cmake dynamic build
executor: gcc10
environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF }
environment: { CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON }
steps: [ cmake_test, cmake_install_test ]
dynamic-clang10:
description: Build and run tests on clang 10 and AVX 2 with a cmake dynamic build
executor: clang10
environment: { CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF }
environment: { CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON }
steps: [ cmake_test, cmake_install_test ]
# unthreaded
@@ -198,19 +250,24 @@ jobs:
# make (test and checkperf)
arch-haswell-gcc10:
description: Build, run tests and check performance on GCC 7 with -march=haswell
description: Build, run tests and check performance on GCC 10 with -march=haswell
executor: gcc10
environment: { CXXFLAGS: -march=haswell }
steps: [ cmake_test ]
arch-nehalem-gcc10:
description: Build, run tests and check performance on GCC 7 with -march=nehalem
description: Build, run tests and check performance on GCC 10 with -march=nehalem
executor: gcc10
environment: { CXXFLAGS: -march=nehalem }
steps: [ cmake_test ]
no-computed-goto-gcc10:
description: Build, run tests and check performance on GCC 7 with -DSIMDJSON_NO_COMPUTED_GOTO=true
sanitize-haswell-gcc10:
description: Build and run tests on GCC 10 and AVX 2 with a cmake sanitize build
executor: gcc10
environment: { CXXFLAGS: -DSIMDJSON_NO_COMPUTED_GOTO=true }
environment: { CXXFLAGS: -march=haswell, CMAKE_FLAGS: -DCMAKE_BUILD_TYPE=Debug -DBUILD_SHARED_LIBS=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
steps: [ cmake_test ]
sanitize-haswell-clang10:
description: Build and run tests on clang 10 and AVX 2 with a cmake sanitize build
executor: clang10
environment: { CXXFLAGS: -march=haswell, CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON -DSIMDJSON_NO_FORCE_INLINING=ON -DSIMDJSON_SANITIZE=ON, CTEST_FLAGS: --output-on-failure -LE explicitonly }
steps: [ cmake_test ]
workflows:
@@ -218,7 +275,7 @@ workflows:
build_and_test:
jobs:
# full multi-implementation tests
- gcc7
#- gcc7 tested on GitHub actions
- gcc10 # do not delete this as it tests our performance
- clang6
#- clang10 # this gets tested a lot below
@@ -229,6 +286,8 @@ workflows:
# full single-implementation tests
- sanitize-gcc10
- sanitize-clang10
- threadsanitize-gcc10
- threadsanitize-clang10
- dynamic-gcc10
- dynamic-clang10
- unthreaded-gcc10
@@ -241,9 +300,17 @@ workflows:
# quicker make single-implementation tests
- arch-haswell-gcc10
- arch-nehalem-gcc10
- no-computed-goto-gcc10
# sanitized single-implementation tests
- sanitize-haswell-gcc10
- sanitize-haswell-clang10
# testing "just the library"
- justlib-gcc10
# testing asserts
- assert-gcc10
- assert-clang10
# TODO add windows: https://circleci.com/docs/2.0/configuration-reference/#windows
+8 -3
View File
@@ -6,6 +6,11 @@ task:
env:
ASSUME_ALWAYS_YES: YES
simdjson_DEPENDENCY_CACHE_DIR: $HOME/.dep_cache
dep_cache:
folder: $HOME/.dep_cache
reupload_on_changes: false
fingerprint_script: cat dependencies/CMakeLists.txt
setup_script:
- pkg update -f
- pkg install bash
@@ -14,8 +19,8 @@ task:
build_script:
- mkdir build
- cd build
- cmake ..
- make -j4
- cmake -DSIMDJSON_BASH=OFF -DSIMDJSON_GIT=OFF ..
- make
test_script:
- cd build
- ctest -j4 --output-on-failure -E checkperf
- ctest --output-on-failure -LE explicitonly
+2 -2
View File
@@ -1,7 +1,7 @@
*
!.git
!Makefile
!amalgamate.sh
!amalgamate.py
!benchmark
!dependencies
!include
@@ -12,4 +12,4 @@
!src
!style
!tests
!tools
!tools
+122 -91
View File
@@ -1,46 +1,4 @@
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: -DSIMDJSON_BUILD_STATIC=ON
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
commands:
- apt-get update -qq
- apt-get install -y g++ cmake gcc
- 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: -DSIMDJSON_BUILD_STATIC=ON
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
commands:
- apt-get update -qq
- apt-get install -y clang++-6.0 cmake
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ctest $CTEST_FLAGS
---
kind: pipeline
name: gcc9
platform: { os: linux, arch: amd64 }
steps:
@@ -50,16 +8,18 @@ steps:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;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
- apt-get update -qq
- apt-get install -y cmake
- apt-get -t buster-backports install -y cmake
- mkdir build
- cd build
- 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
@@ -76,14 +36,15 @@ steps:
CC: clang-6.0
CXX: clang++-6.0
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- mkdir build
- cd build
- 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
@@ -99,11 +60,12 @@ steps:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
CMAKE_FLAGS: -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
- apt-get update -qq
- apt-get install -y cmake
- apt-get -t buster-backports install -y cmake
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
@@ -120,9 +82,9 @@ steps:
environment:
CC: clang-9
CXX: clang++-9
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON
BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- mkdir build
- cd build
@@ -140,16 +102,18 @@ steps:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=icelake;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
- apt-get update -qq
- apt-get install -y cmake
- apt-get -t buster-backports install -y cmake
- mkdir build
- cd build
- 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
@@ -165,21 +129,43 @@ steps:
environment:
CC: clang-9
CXX: clang++-9
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=icelake;haswell;westmere;fallback
BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- mkdir build
- cd build
- 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
- ASAN_OPTIONS="detect_leaks=0" ctest $CTEST_FLAGS -LE "acceptance|per_implementation" # Everything we haven't run yet, run now.
---
kind: pipeline
name: cpp20-clang11-libcpp
platform: { os: linux, arch: amd64 }
steps:
- name: Build and Test
image: pauldreik/llvm-11
user: root
environment:
CC: clang-11
CXX: clang++-11
CMAKE_FLAGS: -GNinja
BUILD_FLAGS:
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CXXFLAGS: -std=c++20 -stdlib=libc++
commands:
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ctest $CTEST_FLAGS
---
kind: pipeline
name: arm64-gcc8
platform: { os: linux, arch: arm64 }
steps:
@@ -189,11 +175,12 @@ steps:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
CMAKE_FLAGS: -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
- apt-get update -qq
- apt-get install -y cmake
- apt-get -t buster-backports install -y cmake
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
@@ -208,16 +195,17 @@ name: arm64-clang6
platform: { os: linux, arch: arm64 }
steps:
- name: Build and Test
image: ubuntu:18.04
image: debian:buster-backports
environment:
CC: clang-6.0
CXX: clang++-6.0
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON
BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- apt-get update -qq
- apt-get install -y clang cmake git
- apt-get -qq update
- apt-get -t buster-backports install -y cmake
- apt-get install -y clang-6.0 git
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
@@ -234,11 +222,12 @@ steps:
CC: gcc
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
CMAKE_FLAGS: -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
- apt-get update -qq
- apt-get install -y cmake
- apt-get -t buster-backports install -y cmake
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
@@ -250,16 +239,17 @@ name: arm64-dynamic-clang6
platform: { os: linux, arch: arm64 }
steps:
- name: Build and Test
image: ubuntu:18.04
image: debian:buster-backports
environment:
CC: clang-6.0
CXX: clang++-6.0
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=OFF
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=ON
BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- apt-get update -qq
- apt-get install -y clang cmake git
- apt-get -qq update
- apt-get -t buster-backports install -y cmake
- apt-get install -y clang-6.0 git
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
@@ -274,13 +264,15 @@ steps:
image: gcc:8
environment:
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_IMPLEMENTATION=arm64;fallback
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CC: gcc
CXX: g++
commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
- apt-get update -qq
- apt-get install -y cmake libstdc++6
- apt-get -t buster-backports install -y cmake
- apt-get install -y libstdc++6
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
@@ -295,16 +287,17 @@ name: arm64-sanitize-clang6
platform: { os: linux, arch: arm64 }
steps:
- name: Build and Test
image: ubuntu:18.04
image: debian:buster-backports
environment:
CC: clang-6.0
CXX: clang++-6.0
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON
CMAKE_FLAGS: -DSIMDJSON_SANITIZE=ON -DSIMDJSON_IMPLEMENTATION=arm64;fallback
BUILD_FLAGS: -- -j
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- apt-get update -qq
- apt-get install -y clang cmake git
- apt-get -qq update
- apt-get -t buster-backports install -y cmake
- apt-get install -y clang-6.0 git
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
@@ -325,12 +318,10 @@ steps:
CC: clang-9
CXX: clang++-9
BUILD_FLAGS: -- -j 4
CMAKE_FLAGS: -GNinja -DSIMDJSON_BUILD_STATIC=ON
CTEST_FLAGS: -j4 --output-on-failure
CMAKE_FLAGS: -GNinja -DBUILD_SHARED_LIBS=OFF
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CXXFLAGS: -stdlib=libc++
commands:
- apt-get update -qq
- apt-get install -y cmake
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
@@ -348,12 +339,31 @@ steps:
CC: clang-9
CXX: clang++-9
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_BUILD_STATIC=ON
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CXXFLAGS: -stdlib=libc++
commands:
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
- cmake --build . $BUILD_FLAGS
- ctest $CTEST_FLAGS
---
kind: pipeline
name: libcpp-clang7
platform: { os: linux, arch: amd64 }
steps:
- name: Build and Test
image: conanio/clang7
user: root
environment:
CC: clang-7
CXX: clang++-7
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DBUILD_SHARED_LIBS=OFF
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
CXXFLAGS: -stdlib=libc++
commands:
- apt-get update -qq
- apt-get install -y cmake
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
@@ -371,10 +381,11 @@ steps:
CXX: g++
BUILD_FLAGS: -- -j
CMAKE_FLAGS: -DSIMDJSON_EXCEPTIONS=OFF
CTEST_FLAGS: -j4 --output-on-failure -E checkperf
CTEST_FLAGS: -j4 --output-on-failure -LE explicitonly
commands:
- echo "deb http://deb.debian.org/debian buster-backports main" >> /etc/apt/sources.list
- apt-get update -qq
- apt-get install -y cmake
- apt-get -t buster-backports install -y cmake
- mkdir build
- cd build
- cmake $CMAKE_FLAGS ..
@@ -382,6 +393,26 @@ steps:
- ctest $CTEST_FLAGS
---
kind: pipeline
name: arm64-fuzz
platform: { os: linux, arch: arm64 }
steps:
- name: Build and run fuzzers shortly
image: ubuntu:20.04
environment:
CC: clang
CXX: clang++
DEBIAN_FRONTEND: noninteractive
ASAN_OPTIONS: detect_leaks=0
commands:
- apt-get -qq update
- apt-get install -q -y clang cmake git wget zip ninja-build
- wget -O corpus.tar.gz https://readonly:readonly@www.pauldreik.se/fuzzdata/index.php?project=simdjson
- tar xf corpus.tar.gz && rm corpus.tar.gz
- fuzz/build_like_ossfuzz.sh
- mkdir -p common_out
- for fuzzer in build/fuzz/fuzz_* ; do echo $fuzzer;$fuzzer common_out out/* -max_total_time=40; done
---
kind: pipeline
name: stylecheck
platform: { os: linux, arch: amd64 }
steps:
+10 -10
View File
@@ -3,7 +3,7 @@
* text=auto
# we don't want json files to be modified for this project
*.json binary
*.json binary diff=astextplain
# Common settings that generally should always be used with your language specific settings
@@ -80,15 +80,15 @@
.gitignore export-ignore
# Sources
*.c text diff=c
*.cc text diff=cpp
*.cxx text diff=cpp
*.cpp text diff=cpp
*.c++ text diff=cpp
*.hpp text diff=cpp
*.h text diff=c
*.h++ text diff=cpp
*.hh text diff=cpp
*.c text eol=lf diff=c
*.cc text eol=lf diff=cpp
*.cxx text eol=lf diff=cpp
*.cpp text eol=lf diff=cpp
*.c++ text eol=lf diff=cpp
*.hpp text eol=lf diff=cpp
*.h text eol=lf diff=c
*.h++ text eol=lf diff=cpp
*.hh text eol=lf diff=cpp
# Compiled Object files
*.slo binary
+26 -3
View File
@@ -2,7 +2,7 @@
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
labels: bug (unverified)
assignees: ''
---
@@ -12,22 +12,45 @@ Before submitting an issue, please ensure that you have read the documentation:
* Basics is an overview of how to use simdjson and its APIs: https://github.com/simdjson/simdjson/blob/master/doc/basics.md
* Performance shows some more advanced scenarios and how to tune for them: https://github.com/simdjson/simdjson/blob/master/doc/performance.md
* Contributing: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md
* We follow the [JSON specification as described by RFC 8259](https://www.rfc-editor.org/rfc/rfc8259.txt) (T. Bray, 2017).
**Describe the bug**
A clear and concise description of what the bug is.
A compiler or static-analyzer warning is not a bug.
We are committed to providing good documentation. We accept the lack of documentation or a misleading documentation as a bug (a 'documentation bug').
We accept the identification of an issue by a sanitizer or some checker tool (e.g., valgrind) as a bug, but you must first ensure that it is not a false positive.
We recommend that you run your tests using different optimization levels.
Before reporting a bug, please ensure that you have read our documentation.
**To Reproduce**
Steps to reproduce the behaviour: provide a code sample if possible.
**Configuration (please complete the following information if relevant):**
If we cannot reproduce the issue, then we cannot address it. Note that a stack trace from your own program is not enough. A sample of your source code is insufficient: please provide a complete test for us to reproduce the issue. Please reduce the issue: use as small and as simple an example of the bug as possible.
It should be possible to trigger the bug by using solely simdjson with our default build setup. If you can only observe the bug within some specific context, with some other software, please reduce the issue first.
**simjson release**
Unless you plan to contribute to simdjson, you should only work from releases. Please be mindful that our main branch may have additional features, bugs and documentation items.
It is fine to report bugs against our main branch, but if that is what you are doing, please be explicit.
**Configuration (please complete the following information if relevant)**
- OS: [e.g. Ubuntu 16.04.6 LTS]
- Compiler [e.g. Apple clang version 11.0.3 (clang-1103.0.32.59) x86_64-apple-darwin19.4.0]
- Version [e.g. 22]
- Optimization setting (e.g., -O3)
We support up-to-date 64-bit ARM and x64 FreeBSD, macOS, Windows and Linux systems. Please ensure that your configuration is supported before labelling the issue as a bug. In particular, we do not support legacy 32-bit systems.
**Indicate whether you are willing or able to provide a bug fix as a pull request**
If you plan to contribute to simdjson, please read our
If you plan to contribute to simdjson, please read our
* CONTRIBUTING guide: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md and our
* HACKING guide: https://github.com/simdjson/simdjson/blob/master/HACKING.md
+3 -2
View File
@@ -2,7 +2,7 @@
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature request
labels: ''
assignees: ''
---
@@ -12,6 +12,7 @@ Before submitting an issue, please ensure that you have read the documentation:
* Basics is an overview of how to use simdjson and its APIs: https://github.com/simdjson/simdjson/blob/master/doc/basics.md
* Performance shows some more advanced scenarios and how to tune for them: https://github.com/simdjson/simdjson/blob/master/doc/performance.md
* Contributing: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md
* We follow the [JSON specification as described by RFC 8259](https://www.rfc-editor.org/rfc/rfc8259.txt) (T. Bray, 2017).
We do not make changes to simdjson without clearly identifiable benefits, which typically means either performance improvements, bug fixes or new features. Avoid bike-shedding: we all have opinions about how to write code, but we want to focus on what makes simdjson objectively better.
@@ -31,6 +32,6 @@ A clear and concise description of any alternative solutions or features you've
Add any other context or screenshots about the feature request here.
** Are you willing to contribute code or documentation toward this new feature? **
If you plan to contribute to simdjson, please read our
If you plan to contribute to simdjson, please read our
* CONTRIBUTING guide: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md and our
* HACKING guide: https://github.com/simdjson/simdjson/blob/master/HACKING.md
@@ -12,6 +12,7 @@ Before submitting an issue, please ensure that you have read the documentation:
* Basics is an overview of how to use simdjson and its APIs: https://github.com/simdjson/simdjson/blob/master/doc/basics.md
* Performance shows some more advanced scenarios and how to tune for them: https://github.com/simdjson/simdjson/blob/master/doc/performance.md
* Contributing: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md
* We follow the [JSON specification as described by RFC 8259](https://www.rfc-editor.org/rfc/rfc8259.txt) (T. Bray, 2017).
We do not make changes to simdjson without clearly identifiable benefits, which typically means either performance improvements, bug fixes or new features. Avoid bike-shedding: we all have opinions about how to write code, but we want to focus on what makes simdjson objectively better.
@@ -26,6 +27,6 @@ Is your issue:
4. A documentation issue? Can you suggest an improvement?
If you plan to contribute to simdjson, please read our
If you plan to contribute to simdjson, please read our
* CONTRIBUTING guide: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md and our
* HACKING guide: https://github.com/simdjson/simdjson/blob/master/HACKING.md
+8
View File
@@ -0,0 +1,8 @@
Our tests check whether you have introduced trailing white space. If such a test fails, please check the "artifacts button" above, which if you click it gives a link to a downloadable file to help you identify the issue. You can also run scripts/remove_trailing_whitespace.sh locally if you have a bash shell and the sed command available on your system.
If you plan to contribute to simdjson, please read our
CONTRIBUTING guide: https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md and our
HACKING guide: https://github.com/simdjson/simdjson/blob/master/HACKING.md
+34
View File
@@ -0,0 +1,34 @@
name: Alpine Linux
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-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: start docker
run: |
docker run -w /src -dit --name alpine -v $PWD:/src alpine:latest
echo 'docker exec alpine "$@";' > ./alpine.sh
chmod +x ./alpine.sh
- name: install packages
run: |
./alpine.sh apk update
./alpine.sh apk add build-base cmake g++ linux-headers git bash
- name: cmake
run: |
./alpine.sh cmake -DSIMDJSON_DEVELOPER_MODE=ON -B build_for_alpine
- name: build
run: |
./alpine.sh cmake --build build_for_alpine
- name: test
run: |
./alpine.sh bash -c "cd build_for_alpine && ctest -LE explicitonly"
+24
View File
@@ -0,0 +1,24 @@
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
@@ -0,0 +1,34 @@
name: Detect trailing whitespace
on: [push, pull_request]
jobs:
whitespace:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Remove whitespace and check the diff
run: |
set -eu
scripts/remove_trailing_whitespace.sh
git diff >whitespace.patch
cat whitespace.patch
if [ $(wc -c <whitespace.patch) -ne 0 ] ; then
echo " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! "
echo "You have trailing whitespace, please download the artifact"
echo "and apply with git apply <whitespace.patch or"
echo "run scripts/remove_trailing_whitespace.sh locally."
echo " !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! "
exit 1
else
echo "no trailing whitespace found, good!"
fi
- name: Archive whitespace patch
uses: actions/upload-artifact@v2
if: always()
with:
name: whitespace-patch
path: |
whitespace.patch
if-no-files-found: ignore
+112 -73
View File
@@ -1,21 +1,33 @@
name: Run fuzzers on stored corpus and test it with valgrind
name: Fuzz and run valgrind
# In the case of a pull request happening at the same time as a cron
# job, there is a risk two jobs run at the same time. Therefore,
# the corpus is only uploaded for the master branch. Pull requests will
# fuzz for a short while, but the results are not uploaded.
on:
push:
branches:
- master
pull_request:
branches:
- master
schedule:
- cron: 23 */8 * * *
jobs:
build:
build:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
runs-on: ubuntu-latest
env:
allfuzzers: parser dump dump_raw_tape print_json
artifactsprefix: -artifact_prefix=fuzzfailure/
# fuzzers that change behaviour with SIMDJSON_FORCE_IMPLEMENTATION
defaultimplfuzzers: atpointer dump dump_raw_tape element minify parser print_json
# fuzzers that loop over the implementations themselves, or don't need to switch.
implfuzzers: implementations minifyimpl ndjson ondemand padded utf8
implementations: haswell westmere fallback
UBSAN_OPTIONS: halt_on_error=1
MAXLEN: -max_len=4000
CLANGVERSION: 11
# which optimization level to use for the sanitizer build (see build_fuzzer.variants.sh)
OPTLEVEL: -O3
steps:
- name: Install packages necessary for building
run: |
@@ -23,105 +35,132 @@ jobs:
sudo apt-get install --quiet ninja-build valgrind zip unzip
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 9
sudo ./llvm.sh $CLANGVERSION
- uses: actions/checkout@v1
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- uses: actions/cache@v2
id: cache-corpus
with:
path: out/
key: corpus-${{ github.run_id }}
restore-keys: corpus-
- name: show statistics for the cached corpus
run: |
echo number of files in github action corpus cache:
find out -type f |wc -l
- name: Create and prepare the initial seed corpus
run: |
fuzz/build_corpus.sh
mv corpus.zip seed_corpus.zip
- name: Download the corpus from the last run
run: |
wget --quiet https://dl.bintray.com/pauldreik/simdjson-fuzz-corpus/corpus/corpus.tar
tar xf corpus.tar
rm corpus.tar
mkdir seedcorpus
unzip -q -d seedcorpus seed_corpus.zip
- name: List clang versions
run: |
ls /usr/bin/clang*
which clang++
clang++ --version
- name: Build all the variants
run: fuzz/build_fuzzer_variants.sh
- name: Verify that the oss-fuzz seed corpus passes without problems
run: CLANGSUFFIX=-$CLANGVERSION fuzz/build_fuzzer_variants.sh
- name: Explore fast (release build, default implementation)
run: |
mkdir seedcorpus
unzip -q -d seedcorpus seed_corpus.zip
for buildvariant in noavx withavx; do
for fuzzer in $allfuzzers; do
build-ossfuzz-$buildvariant/fuzz/fuzz_$fuzzer seedcorpus -max_total_time=1
set -eux
for fuzzer in $defaultimplfuzzers $implfuzzers; do
mkdir -p out/$fuzzer # in case this is a new fuzzer, or the github action cached corpus is broken
# get input from everyone else (corpus cross pollination)
others=$(find out -type d -not -name $fuzzer -not -name out -not -name cmin)
build-fast/fuzz/fuzz_$fuzzer out/$fuzzer $others seedcorpus -max_total_time=30 $MAXLEN
done
- name: Fuzz default impl. fuzzers with sanitizer+asserts (good at detecting errors)
run: |
set -eux
for fuzzer in $defaultimplfuzzers; do
# get input from everyone else (corpus cross pollination)
others=$(find out -type d -not -name $fuzzer -not -name out -not -name cmin)
for implementation in $implementations; do
export SIMDJSON_FORCE_IMPLEMENTATION=$implementation
build-sanitizers$OPTLEVEL/fuzz/fuzz_$fuzzer out/$fuzzer $others seedcorpus -max_total_time=20 $MAXLEN
done
done
- name: Run the fastest fuzzer to explore fast
run: |
for fuzzer in $allfuzzers; do
mkdir -p out/$fuzzer # in case this is a new fuzzer, or corpus.tar is broken
build-ossfuzz-fast9/fuzz/fuzz_$fuzzer out/$fuzzer -max_total_time=30 $artifactsprefix || touch failed
# make sure the failing output is visible in the log
if [ -e failed ] ; then
ls fuzzfailure/* |xargs -n1 base64
exit 1
fi
done
- name: Run the other fuzzer variants for $fuzzer, with sanitizers etc
run: |
set -x
for fuzzer in $allfuzzers; do
build-ossfuzz-withavx/fuzz/fuzz_$fuzzer out/$fuzzer -max_total_time=20 $artifactsprefix || touch failed
build-ossfuzz-noavx/fuzz/fuzz_$fuzzer out/$fuzzer -max_total_time=10 $artifactsprefix || touch failed
build-ossfuzz-noavx9/fuzz/fuzz_$fuzzer out/$fuzzer -max_total_time=10 $artifactsprefix || touch failed
if [ -e failed ] ; then
# make sure the failing output is visible in the log
ls fuzzfailure/* |xargs -n1 base64
exit 1
fi
echo disable msan runs, it fails inside the fuzzing engine and not the fuzzed code!
echo build-ossfuzz-msan-noavx9/fuzz/fuzz_$fuzzer out/$fuzzer -max_total_time=10 -reload=0 $artifactsprefix
echo build-ossfuzz-msan-withavx9/fuzz/fuzz_$fuzzer out/$fuzzer -max_total_time=10 -reload=0 $artifactsprefix
echo now have $(ls out/$fuzzer |wc -l) files in corpus
done
- name: Minimize the corpus with the fast fuzzer
- name: Fuzz differential impl. fuzzers with sanitizer+asserts (good at detecting errors)
run: |
for fuzzer in $allfuzzers; do
set -eux
for fuzzer in $implfuzzers; do
# get input from everyone else (corpus cross pollination)
others=$(find out -type d -not -name $fuzzer -not -name out -not -name cmin)
build-sanitizers$OPTLEVEL/fuzz/fuzz_$fuzzer out/$fuzzer $others seedcorpus -max_total_time=20 $MAXLEN
echo now have $(ls out/$fuzzer |wc -l) files in corpus
done
- name: Minimize the corpus with the fast fuzzer on the default implementation
run: |
set -eux
for fuzzer in $defaultimplfuzzers $implfuzzers; do
mkdir -p out/cmin/$fuzzer
build-ossfuzz-fast9/fuzz/fuzz_$fuzzer -merge=1 out/cmin/$fuzzer out/$fuzzer
# get input from everyone else (corpus cross pollination)
others=$(find out -type d -not -name $fuzzer -not -name out -not -name cmin)
build-fast/fuzz/fuzz_$fuzzer -merge=1 $MAXLEN out/cmin/$fuzzer out/$fuzzer $others seedcorpus
rm -rf out/$fuzzer
mv out/cmin/$fuzzer out/$fuzzer
done
- name: Package the corpus into an artifact
run: |
for fuzzer in $allfuzzers; do
for fuzzer in $defaultimplfuzzers $implfuzzers; do
tar rf corpus.tar out/$fuzzer
done
- name: Save the corpus as a github artifact
uses: actions/upload-artifact@v1
uses: actions/upload-artifact@v2
with:
name: corpus
path: corpus.tar
- name: Run the corpus through valgrind (normal build)
- name: Store the corpus externally
run: |
for fuzzer in $allfuzzers; do
find out/$fuzzer -type f |sort|xargs valgrind build-plain-noavx/fuzz/fuzz_$fuzzer 2>&1|tee valgrind-$fuzzer-noavx.txt
done
- name: Run the corpus through valgrind (noavx build)
gzip --keep corpus.tar
curl -F"filedata=@corpus.tar.gz" https://simdjson:${{ secrets.fuzzdatapassword }}@www.pauldreik.se/fuzzdata/index.php
# This takes a subset of the minimized corpus and run it through valgrind. It is slow,
# therefore take a "random" subset. The random selection is accomplished by sorting on filenames,
# which are hashes of the content.
- name: Run some of the minimized corpus through valgrind (replay build, default implementation)
run: |
for fuzzer in $allfuzzers; do
find out/$fuzzer -type f |sort|xargs valgrind build-plain-normal/fuzz/fuzz_$fuzzer 2>&1|tee valgrind-$fuzzer-normal.txt
done
for fuzzer in $defaultimplfuzzers $implfuzzers; do
find out/$fuzzer -type f |sort|head -n200|xargs -n40 valgrind build-replay/fuzz/fuzz_$fuzzer 2>&1|tee valgrind-$fuzzer.txt
done
- name: Compress the valgrind output
run: tar cf valgrind.tar valgrind-*.txt
- name: Save valgrind output as a github artifact
uses: actions/upload-artifact@v1
uses: actions/upload-artifact@v2
if: always()
with:
name: valgrindresults
path: valgrind.tar
- name: Upload the corpus and results to bintray if we are on master
run: |
if [ $(git rev-parse --verify HEAD) = $(git rev-parse --verify origin/master) ] ; then
echo uploading each artifact twice, otherwise it will not be published
curl -T corpus.tar -upauldreik:${{ secrets.bintrayApiKey }} https://api.bintray.com/content/pauldreik/simdjson-fuzz-corpus/corpus/0/corpus/corpus.tar";publish=1;override=1"
curl -T corpus.tar -upauldreik:${{ secrets.bintrayApiKey }} https://api.bintray.com/content/pauldreik/simdjson-fuzz-corpus/corpus/0/corpus/corpus.tar";publish=1;override=1"
curl -T valgrind.tar -upauldreik:${{ secrets.bintrayApiKey }} https://api.bintray.com/content/pauldreik/simdjson-fuzz-corpus/corpus/0/corpus/valgrind.tar";publish=1;override=1"
curl -T valgrind.tar -upauldreik:${{ secrets.bintrayApiKey }} https://api.bintray.com/content/pauldreik/simdjson-fuzz-corpus/corpus/0/corpus/valgrind.tar";publish=1;override=1"
else
echo "not on master, won't upload to bintray"
fi
if-no-files-found: ignore
- name: Archive any crashes as an artifact
uses: actions/upload-artifact@v2
if: always()
with:
name: crashes
path: |
crash-*
leak-*
timeout-*
if-no-files-found: ignore
+34
View File
@@ -0,0 +1,34 @@
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@v2
- uses: actions/cache@v2
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
@@ -0,0 +1,33 @@
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@v2
- uses: actions/cache@v2
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 .
+43
View File
@@ -0,0 +1,43 @@
name: MSYS2-CLANG-CI
on: [push, pull_request]
jobs:
windows-mingw:
name: ${{ matrix.msystem }}
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
strategy:
fail-fast: false
matrix:
include:
- 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: "MINGW64"
install: mingw-w64-x86_64-libxml2 mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-clang
type: Debug
env:
CMAKE_GENERATOR: Ninja
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- uses: msys2/setup-msys2@v2
with:
update: true
msystem: ${{ matrix.msystem }}
install: ${{ matrix.install }}
- name: Build and Test
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 --build . --verbose
ctest -j4 --output-on-failure -LE explicitonly
+45
View File
@@ -0,0 +1,45 @@
name: MSYS2-CI
on: [push, pull_request]
jobs:
windows-mingw:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
name: ${{ matrix.msystem }}
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
strategy:
fail-fast: false
matrix:
include:
- msystem: "MINGW64"
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
type: Release
- msystem: "MINGW64"
install: mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-gcc
type: Debug
env:
CMAKE_GENERATOR: Ninja
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- uses: msys2/setup-msys2@v2
with:
update: true
msystem: ${{ matrix.msystem }}
install: ${{ matrix.install }}
- name: Build and Test
run: |
mkdir build
cd build
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DCMAKE_BUILD_TYPE=${{ matrix.type }} -DBUILD_SHARED_LIBS=OFF -DSIMDJSON_DO_NOT_USE_THREADS_NO_MATTER_WHAT=ON ..
cmake --build . --verbose
ctest -j4 --output-on-failure -LE explicitonly
+71
View File
@@ -0,0 +1,71 @@
name: short fuzz on the power arch
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
armv7_job:
if: >-
! contains(toJSON(github.event.commits.*.message), '[skip ci]') &&
! contains(toJSON(github.event.commits.*.message), '[skip github]')
# The host should always be Linux
runs-on: ubuntu-20.04
name: Build on ubuntu-20.04 ppc64le
steps:
- uses: actions/checkout@v2.1.0
- uses: uraimo/run-on-arch-action@v2.0.5
name: Run commands
id: runcmd
env:
DEBIAN_FRONTEND: noninteractive
with:
arch: ppc64le
distro: buster
# Not required, but speeds up builds by storing container images in
# a GitHub package registry.
githubToken: ${{ github.token }}
run: |
export CLANGSUFFIX="-7"
apt-get -qq update
apt-get install -q -y clang-7 libfuzzer-7-dev git wget zip ninja-build gnupg software-properties-common
wget -q -O - "https://raw.githubusercontent.com/simdjson/debian-ppa/master/key.gpg" | apt-key add -
apt-add-repository "deb https://raw.githubusercontent.com/simdjson/debian-ppa/master simdjson main"
apt-get -qq update
apt-get purge cmake cmake-data
apt-get -t simdjson -y install cmake
mkdir -p build ; cd build
cmake .. -GNinja \
-DCMAKE_CXX_COMPILER=clang++$CLANGSUFFIX \
-DCMAKE_C_COMPILER=clang$CLANGSUFFIX \
-DBUILD_SHARED_LIBS=OFF \
-DSIMDJSON_DEVELOPER_MODE=ON \
-DSIMDJSON_ENABLE_FUZZING=On \
-DSIMDJSON_COMPETITION=OFF \
-DSIMDJSON_GOOGLE_BENCHMARKS=OFF \
-DSIMDJSON_DISABLE_DEPRECATED_API=On \
-DSIMDJSON_FUZZ_LDFLAGS=-lFuzzer \
-DCMAKE_CXX_FLAGS="-fsanitize=fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=" \
-DCMAKE_C_FLAGS="-fsanitize=fuzzer-no-link" \
-DCMAKE_BUILD_TYPE=Release \
-DSIMDJSON_FUZZ_LINKMAIN=Off
cd ..
builddir=build
cmake --build $builddir
wget -O corpus.tar.gz https://readonly:readonly@www.pauldreik.se/fuzzdata/index.php?project=simdjson
tar xf corpus.tar.gz
fuzzernames=$(cmake --build $builddir --target print_all_fuzzernames |tail -n1)
for fuzzer in $fuzzernames ; do
exe=$builddir/fuzz/$fuzzer
shortname=$(echo $fuzzer |cut -f2- -d_)
echo found fuzzer $shortname with executable $exe
mkdir -p out/$shortname
others=$(find out -type d -not -name $shortname -not -name out -not -name cmin)
$exe -max_total_time=20 -max_len=4000 out/$shortname $others
echo "*************************************************************************"
done
echo "all is good, no errors found in any of these fuzzers: $fuzzernames"
+29
View File
@@ -0,0 +1,29 @@
name: Performance check on Ubuntu 18.04 CI (GCC 7)
on:
push:
branches:
- master
pull_request:
branches:
- master
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
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
mkdir build &&
cd build &&
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_ENABLE_DOM_CHECKPERF=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . --target checkperf &&
ctest --output-on-failure -R checkperf ubuntu18-checkperf.yml
+31
View File
@@ -0,0 +1,31 @@
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@v2
- uses: actions/cache@v2
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
+25
View File
@@ -0,0 +1,25 @@
name: Ubuntu 18.04 CI (GCC 7) with Thread Sanitizer
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
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
mkdir build &&
cd build &&
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_SANITIZE_THREADS=ON .. &&
cmake --build . --target document_stream_tests --target ondemand_document_stream_tests --target parse_many_test &&
ctest --output-on-failure -R parse_many_test &&
ctest --output-on-failure -R document_stream_tests
+25
View File
@@ -0,0 +1,25 @@
name: Ubuntu 18.04 CI (GCC 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
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- 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 &&
make 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
+29
View File
@@ -0,0 +1,29 @@
name: Performance check on Ubuntu 20.04 CI (GCC 9)
on:
push:
branches:
- master
pull_request:
branches:
- master
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
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
mkdir build &&
cd build &&
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_ENABLE_DOM_CHECKPERF=ON -DCMAKE_CXX_FLAGS="-Werror=old-style-cast -pedantic -Wpedantic" -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . --target checkperf &&
ctest --output-on-failure -R checkperf
+34
View File
@@ -0,0 +1,34 @@
name: Ubuntu 20.04 CI (GCC 9) without exceptions
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
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
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 -DSIMDJSON_EXCEPTIONS=OFF -DBUILD_SHARED_LIBS=OFF .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
cd .. &&
mkdir build &&
cd build &&
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_EXCEPTIONS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
make 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 &&
mkdir testfindpackage &&
cd testfindpackage &&
echo -e 'cmake_minimum_required(VERSION 3.1)\nproject(simdjsontester)\nset(CMAKE_CXX_STANDARD 17)\nfind_package(simdjson REQUIRED)'> CMakeLists.txt && mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../destination .. && cmake --build .
+34
View File
@@ -0,0 +1,34 @@
name: Ubuntu 20.04 CI (GCC 9) Without Threads
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
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
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_ENABLE_THREADS=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_DEVELOPER_MODE=ON -DSIMDJSON_GOOGLE_BENCHMARKS=ON -DSIMDJSON_ENABLE_THREADS=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
cmake --build . &&
ctest -j --output-on-failure -LE explicitonly &&
make 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 &&
mkdir testfindpackage &&
cd testfindpackage &&
echo -e 'cmake_minimum_required(VERSION 3.1)\nproject(simdjsontester)\nset(CMAKE_CXX_STANDARD 17)\nfind_package(simdjson REQUIRED)'> CMakeLists.txt && mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=../destination .. && cmake --build .
+23
View File
@@ -0,0 +1,23 @@
name: Ubuntu 20.04 CI (GCC 9) With Memory Sanitizer
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
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
mkdir builddebug &&
cd builddebug &&
cmake -DSIMDJSON_SANITIZE=ON -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
+24
View File
@@ -0,0 +1,24 @@
name: Ubuntu 20.04 CI (GCC 9) with Thread Sanitizer
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
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: dependencies/.cache
key: ${{ hashFiles('dependencies/CMakeLists.txt') }}
- name: Use cmake
run: |
mkdir build &&
cd build &&
cmake -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_SANITIZE_THREADS=ON .. &&
cmake --build . --target document_stream_tests --target ondemand_document_stream_tests --target parse_many_test &&
ctest --output-on-failure -R parse_many_test &&
ctest --output-on-failure -R document_stream_tests
+33
View File
@@ -0,0 +1,33 @@
name: Ubuntu 20.04 CI (GCC 9)
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
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
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 .
+33
View File
@@ -0,0 +1,33 @@
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@v2
- uses: actions/cache@v2
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 .
+21
View File
@@ -0,0 +1,21 @@
name: VS17-ARM-CI
on: [push, pull_request]
jobs:
ci:
name: windows-vs17
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- {arch: ARM}
- {arch: ARM64}
steps:
- name: checkout
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 &&
cmake --build build --verbose
+44
View File
@@ -0,0 +1,44 @@
name: VS17-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-vs17
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}
steps:
- name: checkout
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
- name: Build Debug
run: cmake --build build --config Debug --verbose
- name: Build Release
run: cmake --build build --config Release --verbose
- name: Run Release tests
run: |
cd build
ctest -C Release -LE explicitonly --output-on-failure
- name: Run Debug tests
run: |
cd build
ctest -C Debug -LE explicitonly --output-on-failure
- name: Install
run: |
cmake --install build --config Release
- name: Test Installation
run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -B build_install_test tests/installation_tests/find
cmake --build build_install_test --config Release
+41
View File
@@ -0,0 +1,41 @@
name: VS17-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-vs17
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- {gen: Visual Studio 17 2022, arch: x64}
steps:
- name: checkout
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
- name: Build Debug
run: cmake --build build --config Debug --verbose
- name: Build Release
run: cmake --build build --config Release --verbose
- name: Run Release tests
run: |
cd build
ctest -C Release -LE explicitonly --output-on-failure
- name: Run Debug tests
run: |
cd build
ctest -C Debug -LE explicitonly --output-on-failure
- name: Install
run: |
cmake --install build --config Release
- name: Test Installation
run: |
cmake -G "${{matrix.gen}}" -A ${{matrix.arch}} -B build_install_test tests/installation_tests/find
cmake --build build_install_test --config Release
+30
View File
@@ -0,0 +1,30 @@
name: VS17-NoExcept-CI
on: [push, pull_request]
jobs:
ci:
name: windows-vs17
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 VS17'
uses: lukka/run-cmake@v3
with:
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
cmakeListsTxtPath: '${{ github.workspace }}/CMakeLists.txt'
buildDirectory: "${{ github.workspace }}/../../_temp/windows"
cmakeBuildType: Release
buildWithCMake: true
cmakeGenerator: VS16Win64
cmakeAppendedArgs: -DSIMDJSON_COMPETITION=OFF -DSIMDJSON_DEVELOPER_MODE=ON -DSIMDJSON_EXCEPTIONS=OFF
buildWithCMakeArgs: --config Release
- name: 'Run CTest'
run: ctest -C Release -LE explicitonly --output-on-failure
working-directory: "${{ github.workspace }}/../../_temp/windows"
+8
View File
@@ -96,3 +96,11 @@ objs
# Generated docs
/doc/api
*.orig
# VSCode workspace files
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
-36
View File
@@ -1,36 +0,0 @@
[submodule "scalarvssimd/rapidjson"]
path = dependencies/rapidjson
url = https://github.com/Tencent/rapidjson.git
[submodule "dependencies/sajson"]
path = dependencies/sajson
url = https://github.com/chadaustin/sajson.git
[submodule "dependencies/json11"]
path = dependencies/json11
url = https://github.com/dropbox/json11.git
[submodule "dependencies/fastjson"]
path = dependencies/fastjson
url = https://github.com/mikeando/fastjson.git
[submodule "dependencies/gason"]
path = dependencies/gason
url = https://github.com/vivkin/gason.git
[submodule "dependencies/ujson4c"]
path = dependencies/ujson4c
url = https://github.com/esnme/ujson4c.git
[submodule "dependencies/jsmn"]
path = dependencies/jsmn
url = https://github.com/zserge/jsmn.git
[submodule "dependencies/cJSON"]
path = dependencies/cJSON
url = https://github.com/DaveGamble/cJSON.git
[submodule "dependencies/jsoncpp"]
path = dependencies/jsoncpp
url = https://github.com/open-source-parsers/jsoncpp.git
[submodule "dependencies/json"]
path = dependencies/json
url = https://github.com/nlohmann/json.git
[submodule "dependencies/benchmark"]
path = dependencies/benchmark
url = https://github.com/google/benchmark.git
[submodule "dependencies/cxxopts"]
path = dependencies/cxxopts
url = https://github.com/jarro2783/cxxopts
+187 -27
View File
@@ -1,30 +1,190 @@
language: cpp
sudo: false
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-7
- g++-7
- clang-format
- python
branches:
only:
- master
script:
- export CXX=g++-7
- export CC=gcc-7
- make
- make test
- make everything
- make amalgamate
- make clean
- make SANITIZEGOLD=1 test
- make clean
- ARCHFLAGS="-march=nehalem" make
- ARCHFLAGS="-march=nehalem" make test
- ARCHFLAGS="-march=nehalem" make everything
- ./style/run-clang-format.py -r include/ benchmark/ src/ tests/
dist: bionic
arch:
- ppc64le
cache:
directories:
- $HOME/.dep_cache
env:
global:
- simdjson_DEPENDENCY_CACHE_DIR=$HOME/.dep_cache
matrix:
include:
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
env:
- COMPILER="CC=gcc-8 && CXX=g++-8"
compiler: gcc-8
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-9
env:
- COMPILER="CC=gcc-9 && CXX=g++-9"
compiler: gcc-9
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-10
env:
- COMPILER="CC=gcc-10 && CXX=g++-10"
compiler: gcc-10
# The sanitizer runs fail systematically
# - os: linux
# addons:
# apt:
# sources:
# - ubuntu-toolchain-r-test
# packages:
# - g++-10
# env:
# - COMPILER="CC=gcc-10 && CXX=g++-10"
# - SANITIZE="on"
# compiler: gcc-10-sanitize
- os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-10
env:
- COMPILER="CC=gcc-10 && CXX=g++-10"
- STATIC="on"
compiler: gcc-10-static
- os: linux
addons:
apt:
sources:
- llvm-toolchain-bionic-6.0
packages:
- clang-6.0
env:
- COMPILER="CC=clang-6.0 && CXX=clang++-6.0"
compiler: clang-6
- os: linux
addons:
apt:
sources:
- llvm-toolchain-bionic-7
packages:
- clang-7
env:
- COMPILER="CC=clang-7 && CXX=clang++-7"
compiler: clang-7
- os: linux
addons:
apt:
sources:
- llvm-toolchain-bionic-8
packages:
- clang-8
env:
- COMPILER="CC=clang-8 && CXX=clang++-8"
compiler: clang-8
- os: linux
addons:
apt:
sources:
- llvm-toolchain-bionic-9
packages:
- clang-9
env:
- COMPILER="CC=clang-9 && CXX=clang++-9"
compiler: clang-9
- os: linux
addons:
apt:
packages:
- clang-10
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
env:
- COMPILER="CC=clang-10 && CXX=clang++-10"
compiler: clang-10
- os: linux
addons:
apt:
packages:
- clang-10
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
env:
- COMPILER="CC=clang-10 && CXX=clang++-10"
- STATIC="on"
compiler: clang-10-static
# The clang sanitizer runs fail frequently at setup time
# - os: linux
# addons:
# apt:
# packages:
# - clang-10
# sources:
# - ubuntu-toolchain-r-test
# - sourceline: 'deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main'
# key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
# env:
# - COMPILER="CC=clang-10 && CXX=clang++-10"
# - SANITIZE="on"
# compiler: clang-10-sanitize
before_install:
- eval "${COMPILER}"
install:
- wget -q -O - "https://raw.githubusercontent.com/simdjson/debian-ppa/master/key.gpg" | sudo apt-key add -
- sudo apt-add-repository "deb https://raw.githubusercontent.com/simdjson/debian-ppa/master simdjson main"
- sudo apt-get -qq update
- sudo apt-get purge cmake cmake-data
- sudo apt-get -t simdjson -y install cmake
- export CMAKE_CXX_FLAGS="-maltivec -mcpu=power9 -mtune=power9"
- 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 ASAN_OPTIONS="detect_leaks=0";
fi
- if [[ "${STATIC}" == "on" ]]; then
export CMAKE_FLAGS="${CMAKE_FLAGS} -DBUILD_SHARED_LIBS=OFF";
fi
- export CTEST_FLAGS="-j4 --output-on-failure -LE explicitonly"
script:
- mkdir build
- cd build
- cmake $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
- ctest $CTEST_FLAGS -LE "acceptance|per_implementation"
+17
View File
@@ -0,0 +1,17 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
// Syntax
"ms-vscode.cpptools",
"ms-vscode.cmake-tools",
"ms-python.python",
"twxs.cmake"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": [
]
}
+91
View File
@@ -0,0 +1,91 @@
{
"editor.rulers": [
{"column": 95 },
{"column": 120 }
],
"files.trimTrailingWhitespace": true,
"files.associations": {
"array": "cpp",
"iterator": "cpp",
"chrono": "cpp",
"optional": "cpp",
"__locale": "cpp",
"__tuple": "cpp",
"__bit_reference": "cpp",
"__config": "cpp",
"__debug": "cpp",
"__errc": "cpp",
"__functional_base": "cpp",
"__hash_table": "cpp",
"__mutex_base": "cpp",
"__node_handle": "cpp",
"__nullptr": "cpp",
"__split_buffer": "cpp",
"__string": "cpp",
"__threading_support": "cpp",
"__tree": "cpp",
"algorithm": "cpp",
"atomic": "cpp",
"bit": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"cinttypes": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"codecvt": "cpp",
"complex": "cpp",
"condition_variable": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"exception": "cpp",
"forward_list": "cpp",
"fstream": "cpp",
"functional": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"ios": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"list": "cpp",
"locale": "cpp",
"map": "cpp",
"memory": "cpp",
"mutex": "cpp",
"new": "cpp",
"numeric": "cpp",
"ostream": "cpp",
"random": "cpp",
"ratio": "cpp",
"regex": "cpp",
"set": "cpp",
"sstream": "cpp",
"stack": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"thread": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"utility": "cpp",
"valarray": "cpp",
"vector": "cpp",
"*.ipp": "cpp",
"__functional_base_03": "cpp",
"filesystem": "cpp"
}
}
+256 -64
View File
@@ -1,60 +1,222 @@
cmake_minimum_required(VERSION 3.9) # CMP0069 NEW
cmake_minimum_required(VERSION 3.14)
project(simdjson
DESCRIPTION "Parsing gigabytes of JSON per second"
LANGUAGES CXX C
project(
simdjson
# The version number is modified by tools/release.py
VERSION 2.0.1
DESCRIPTION "Parsing gigabytes of JSON per second"
HOMEPAGE_URL "https://simdjson.org/"
LANGUAGES CXX C
)
set(PROJECT_VERSION_MAJOR 0)
set(PROJECT_VERSION_MINOR 4)
set(PROJECT_VERSION_PATCH 1)
set(SIMDJSON_LIB_VERSION "0.4.1" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "2" CACHE STRING "simdjson library soversion")
set(SIMDJSON_GITHUB_REPOSITORY https://github.com/simdjson/simdjson)
set(SIMDJSON_GITHUB_REPOSITORY "https://github.com/simdjson/simdjson")
string(
COMPARE EQUAL
"${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}"
is_top_project
)
# ---- Options, variables ----
# These version numbers are modified by tools/release.py
set(SIMDJSON_LIB_VERSION "11.0.0" CACHE STRING "simdjson library version")
set(SIMDJSON_LIB_SOVERSION "11" CACHE STRING "simdjson library soversion")
option(SIMDJSON_ENABLE_THREADS "Link with thread support" ON)
include(cmake/simdjson-props.cmake)
include(cmake/implementation-flags.cmake)
include(cmake/exception-flags.cmake)
option(SIMDJSON_DISABLE_DEPRECATED_API "Disables deprecated APIs" OFF)
if(SIMDJSON_DISABLE_DEPRECATED_API)
simdjson_add_props(
target_compile_definitions PUBLIC
SIMDJSON_DISABLE_DEPRECATED_API=1
)
endif()
option(SIMDJSON_DEVELOPMENT_CHECKS "Enable development-time aids, such as \
checks for incorrect API usage. Enabled by default in DEBUG." OFF)
if(SIMDJSON_DEVELOPMENT_CHECKS)
simdjson_add_props(
target_compile_definitions PUBLIC
SIMDJSON_DEVELOPMENT_CHECKS
)
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)
endif()
include(cmake/handle-deprecations.cmake)
include(cmake/developer-options.cmake)
# ---- simdjson library ----
add_library(simdjson src/simdjson.cpp)
add_library(simdjson::simdjson ALIAS simdjson)
set_target_properties(
simdjson PROPERTIES
VERSION "${SIMDJSON_LIB_VERSION}"
SOVERSION "${SIMDJSON_LIB_SOVERSION}"
# FIXME: symbols should be hidden by default
WINDOWS_EXPORT_ALL_SYMBOLS YES
)
# FIXME: Use proper CMake integration for exports
if(MSVC AND BUILD_SHARED_LIBS)
target_compile_definitions(
simdjson
PRIVATE SIMDJSON_BUILDING_WINDOWS_DYNAMIC_LIBRARY=1
INTERFACE SIMDJSON_USING_WINDOWS_DYNAMIC_LIBRARY=1
)
endif()
simdjson_add_props(
target_include_directories
PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
PRIVATE "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>"
)
simdjson_add_props(target_compile_features PUBLIC cxx_std_11)
# workaround for GNU GCC poor AVX load/store code generation
if(
CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
AND CMAKE_SYSTEM_PROCESSOR MATCHES "^(i.86|x86(_64)?)$"
)
simdjson_add_props(
target_compile_options PRIVATE
-mno-avx256-split-unaligned-load -mno-avx256-split-unaligned-store
)
endif()
if(SIMDJSON_ENABLE_THREADS)
find_package(Threads REQUIRED)
simdjson_add_props(target_link_libraries PUBLIC Threads::Threads)
simdjson_add_props(target_compile_definitions PUBLIC SIMDJSON_THREADS_ENABLED=1)
endif()
simdjson_apply_props(simdjson)
# ---- Install rules ----
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
include(cmake/simdjson-flags.cmake)
include(cmake/simdjson-user-cmakecache.cmake)
install(
FILES singleheader/simdjson.h
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
COMPONENT simdjson_Development
)
install(
TARGETS simdjson
EXPORT simdjsonTargets
RUNTIME COMPONENT simdjson_Runtime
LIBRARY COMPONENT simdjson_Runtime
NAMELINK_COMPONENT simdjson_Development
ARCHIVE COMPONENT simdjson_Development
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)
if(SIMDJSON_JUST_LIBRARY)
message( STATUS "Building just the library, omitting all tests, tools and benchmarks." )
configure_file(cmake/simdjson-config.cmake.in simdjson-config.cmake @ONLY)
write_basic_package_version_file(
simdjson-config-version.cmake
COMPATIBILITY SameMinorVersion
)
set(
SIMDJSON_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/simdjson"
CACHE STRING "CMake package config location relative to the install prefix"
)
mark_as_advanced(SIMDJSON_INSTALL_CMAKEDIR)
install(
FILES
"${PROJECT_BINARY_DIR}/simdjson-config.cmake"
"${PROJECT_BINARY_DIR}/simdjson-config-version.cmake"
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
COMPONENT simdjson_Development
)
install(
EXPORT simdjsonTargets
NAMESPACE simdjson::
DESTINATION "${SIMDJSON_INSTALL_CMAKEDIR}"
COMPONENT example_Development
)
#
# CPack
#
if(is_top_project)
set(CPACK_PACKAGE_VENDOR "Daniel Lemire")
set(CPACK_PACKAGE_CONTACT "lemire@gmail.com")
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${PROJECT_SOURCE_DIR}/README.md")
set(CPACK_RPM_PACKAGE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
set(CPACK_SOURCE_GENERATOR "TGZ;ZIP")
include(CPack)
endif()
#
# Set up test data
#
if(NOT(SIMDJSON_JUST_LIBRARY))
enable_testing()
add_subdirectory(jsonchecker)
add_subdirectory(jsonexamples)
add_library(test-data INTERFACE)
target_link_libraries(test-data INTERFACE jsonchecker-data jsonexamples-data)
# ---- 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")
endif()
#
# Create the top level simdjson library (must be done at this level to use both src/ and include/
# directories) and tools
#
add_subdirectory(include)
add_subdirectory(src)
simdjson_apply_props(simdjson-internal-flags)
set(
SIMDJSON_USER_CMAKECACHE
"${CMAKE_BINARY_DIR}/.simdjson-user-CMakeCache.txt"
)
add_custom_target(
simdjson-user-cmakecache
COMMAND "${CMAKE_COMMAND}"
-D "BINARY_DIR=${CMAKE_BINARY_DIR}"
-D "USER_CMAKECACHE=${SIMDJSON_USER_CMAKECACHE}"
-P "${PROJECT_SOURCE_DIR}/cmake/simdjson-user-cmakecache.cmake"
VERBATIM
)
# Setup tests
enable_testing()
# So we can build just tests with "make all_tests"
add_custom_target(all_tests)
add_subdirectory(windows)
if(NOT(SIMDJSON_JUST_LIBRARY))
add_subdirectory(dependencies) ## This needs to be before tools because of cxxopts
add_subdirectory(tools) ## This needs to be before tests because of cxxopts
add_subdirectory(singleheader)
endif()
add_subdirectory(dependencies) ## This needs to be before tools because of cxxopts
add_subdirectory(tools) ## This needs to be before tests because of cxxopts
# Data: jsonexamples is left with only the bare essential.
# most of the data has been moved to https://github.com/simdjson/simdjson-data
add_subdirectory(jsonexamples)
add_subdirectory(singleheader)
#
# Compile tools / tests / benchmarks
#
if(NOT(SIMDJSON_JUST_LIBRARY))
add_subdirectory(tests)
add_subdirectory(examples)
add_subdirectory(benchmark)
add_subdirectory(fuzz)
endif()
add_subdirectory(tests)
add_subdirectory(examples)
add_subdirectory(benchmark)
add_subdirectory(fuzz)
#
# Source files should be just ASCII
@@ -62,29 +224,59 @@ endif()
find_program(FIND find)
find_program(FILE file)
find_program(GREP grep)
if((FIND) AND (FILE) AND (GREP))
add_test(
NAME "just_ascii"
COMMAND sh -c "${FIND} include src windows tools singleheader tests examples benchmark -path benchmark/checkperf-reference -prune -name '*.h' -o -name '*.cpp' -type f -exec ${FILE} '{}' \; |${GREP} -v ASCII || exit 0 && exit 1"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
if(FIND AND FILE AND GREP)
add_test(
NAME just_ascii
COMMAND sh -c "\
${FIND} include src windows tools singleheader tests examples benchmark \
-path benchmark/checkperf-reference -prune -name '*.h' -o -name '*.cpp' \
-type f -exec ${FILE} '{}' \; | ${GREP} -qv ASCII || exit 0 && exit 1"
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
)
endif()
#
# CPack
#
set(CPACK_PACKAGE_VENDOR "Daniel Lemire")
set(CPACK_PACKAGE_CONTACT "lemire@gmail.com")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Parsing gigabytes of JSON per second")
set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RPM_PACKAGE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_SOURCE_GENERATOR "TGZ;ZIP")
include(CPack)
##
## In systems like R, libraries must not use stderr or abort to be acceptable.
## Thus we make it a hard rule that one is not allowed to call abort or stderr.
## The sanitized builds are allowed to abort.
##
if(NOT SIMDJSON_SANITIZE)
find_program(GREP grep)
find_program(NM nm)
if((NOT GREP) OR (NOT NM))
message("grep and nm are unavailable on this system.")
else()
add_test(
NAME "avoid_abort"
# Under FreeBSD, the __cxa_guard_abort symbol may appear but it is fine.
# So we want to look for <space><possibly _>abort as a test.
COMMAND sh -c "${NM} $<TARGET_FILE_NAME:simdjson> | ${GREP} ' _*abort' || exit 0 && exit 1"
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
)
add_test(
NAME "avoid_cout"
COMMAND sh -c "${NM} $<TARGET_FILE_NAME:simdjson> | ${GREP} ' _*cout' || exit 0 && exit 1"
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
)
add_test(
NAME "avoid_cerr"
COMMAND sh -c "${NM} $<TARGET_FILE_NAME:simdjson> | ${GREP} ' _*cerr' || exit 0 && exit 1"
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
)
add_test(
NAME "avoid_printf"
COMMAND sh -c "${NM} $<TARGET_FILE_NAME:simdjson> | ${GREP} ' _*printf' || exit 0 && exit 1"
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
)
add_test(
NAME "avoid_stdout"
COMMAND sh -c "${NM} $<TARGET_FILE_NAME:simdjson> | ${GREP} stdout || exit 0 && exit 1"
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
)
add_test(
NAME "avoid_stderr"
COMMAND sh -c "${NM} $<TARGET_FILE_NAME:simdjson> | ${GREP} stderr || exit 0 && exit 1"
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
)
endif()
endif()
+11 -1
View File
@@ -41,6 +41,8 @@ We have few hard rules, but we have some:
- Printing to standard output or standard error (`stderr`, `stdout`, `std::cerr`, `std::cout`) in the core library is forbidden. This follows from the [Writing R Extensions](https://cran.r-project.org/doc/manuals/R-exts.html) manual which states that "Compiled code should not write to stdout or stderr".
- Calls to `abort()` are forbidden in the core library. This follows from the [Writing R Extensions](https://cran.r-project.org/doc/manuals/R-exts.html) manual which states that "Under no circumstances should your compiled code ever call abort or exit".
- All source code files (.h, .cpp) must be ASCII.
- All C macros introduced in public headers need to be prefixed with either `SIMDJSON_` or `simdjson_`.
- We avoid trailing white space characters within lines. That is, your lines of code should not terminate with unnecessary spaces. Generally, please avoid making unnecessary changes to white-space characters when contributing code.
Tools, tests and benchmarks are not held to these same strict rules.
@@ -67,10 +69,18 @@ Pull requests are always invited. However, we ask that you follow these guidelin
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 of new tests, in general.
- Your code should pass our continuous-integration tests. It is your responsability to ensure that your proposal pass the tests. We do not merge pull requests that would break our build.
- 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.
If the benefits of your proposed code remain unclear, we may choose to discard your code: that is not an insult, we frequently discard our own code. We may also consider various alternatives and choose another path. Again, that is not an insult or a sign that you have wasted your time.
Style
-----
Our formatting style is inspired by the LLVM style.
The simdjson library is written using the snake case: when a variable or a function is a phrase, each space is replaced by an underscore character, and the first letter of each word written in lowercase. Compile-time constants are written entirely in uppercase with the same underscore convention.
Code of Conduct
---------------
+7 -1
View File
@@ -35,5 +35,11 @@ Matjaž Ostroveršnik
Nong Li
Furkan Taşkale
Brendan Knapp
# if you have contributed to the project and your name does not
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
# appear in this list, please let us know!
-88
View File
@@ -1,88 +0,0 @@
###
#
# Though simdjson requires only commonly available compilers and tools, it can
# be convenient to build it and test it inside a docker container: it makes it
# possible to test and benchmark simdjson under even relatively out-of-date
# Linux servers. It should also work under macOS and Windows, though not
# at native speeds, maybe.
#
# Assuming that you have a working docker server, this file
# allows you to build, test and benchmark simdjson.
#
# We build the library and associated files in the dockerbuild subdirectory.
# It may be necessary to delete it before creating the image:
#
# rm -r -f dockerbuild
#
# The need to delete the directory has nothing to do with docker per se: it is
# simply cleaner in CMake to start from a fresh directory. This is important: if you
# reuse the same directory with different configurations, you may get broken builds.
#
#
# Then you can build the image as follows:
#
# docker build -t simdjson --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g) .
#
# Please note that the image does not contain a copy of the code. However, the image will contain the
# the compiler and the build system. This means that if you change the source code, after you have built
# the image, you won't need to rebuild the image. In fact, unless you want to try a different compiler, you
# do not need to ever rebuild the image, even if you do a lot of work on the source code.
#
# We specify the users to avoid having files owned by a privileged user (root) in our directory. Some
# people like to run their machine as the "root" user. We do not think it is cool.
#
# Then you need to build the project:
#
# docker run -v $(pwd):/project:Z simdjson
#
# Should you change a source file, you may need to call this command again. Because the output
# files are persistent between calls to this command (they reside in the dockerbuild directory),
# this command can be fast.
#
# Next you can test it as follows:
#
# docker run -it -v $(pwd):/project:Z simdjson sh -c "cd dockerbuild && ctest . --output-on-failure -E checkperf"
#
# The run the complete tests requires you to have built all of simdjson.
#
# Building all of simdjson takes a long time. Instead, you can build just one target:
#
# docker run -it -v $(pwd):/project:Z simdjson sh -c "[ -d dockerbuild ] || mkdir dockerbuild && cd dockerbuild && cmake .. && cmake --build . --target parse"
#
# Note that it is safe to remove dockerbuild before call the previous command, as the repository gets rebuild. It is also possible, by changing the command, to use a different directory name.
#
# You can run performance tests:
#
# docker run -it --privileged -v $(pwd):/project:Z simdjson sh -c "cd dockerbuild && for i in ../jsonexamples/*.json; do echo \$i; ./benchmark/parse \$i; done"
#
# The "--privileged" is recommended so you can get performance counters under Linux.
#
# You can also grab a fresh copy of simdjson and rebuild it, to make comparisons:
#
# docker run -it -v $(pwd):/project:Z simdjson sh -c "git clone https://github.com/simdjson/simdjson.git && cd simdjson && mkdir build && cd build && cmake .. && cmake --build . --target parse "
#
# Then you can run comparisons:
#
# docker run -it --privileged -v $(pwd):/project:Z simdjson sh -c "for i in jsonexamples/*.json; do echo \$i; dockerbuild/benchmark/parse \$i| grep GB| head -n 1; simdjson/build/benchmark/parse \$i | grep GB |head -n 1; done"
#
####
FROM ubuntu:20.10
################
# We would prefer to use the conan io images but they do not support 64-bit ARM? The small gcc images appear to
# be broken on ARM.
# Furthermore, we would not expect users to frequently rebuild the container, so using ubuntu is probably fine.
###############
ARG USER_ID
ARG GROUP_ID
RUN apt-get update -qq
RUN DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata
RUN apt-get install -y cmake g++ git
RUN mkdir project
RUN addgroup --gid $GROUP_ID user; exit 0
RUN adduser --disabled-password --gecos '' --uid $USER_ID --gid $GROUP_ID user; exit 0
USER user
RUN gcc --version
WORKDIR /project
CMD ["sh","-c","[ -d dockerbuild ] || mkdir dockerbuild && cd dockerbuild && cmake .. && cmake --build . "]
+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 = "0.4.1"
PROJECT_NUMBER = "2.0.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
+87 -434
View File
@@ -1,11 +1,50 @@
Hacking simdjson
================
Here is wisdom about how to build, test and run simdjson from within the repository. *Users* of
simdjson should use the released simdjson.h and simdjson.cpp files.
Here is wisdom about how to build, test and run simdjson from within the repository. This is mostly useful for people who plan to contribute simdjson, or maybe study the design.
If you plan to contribute to simdjson, please read our [CONTRIBUTING](https://github.com/simdjson/simdjson/blob/master/CONTRIBUTING.md) guide.
Design notes
------------------------------
The parser works in two stages:
- Stage 1. (Find marks) Identifies quickly structure elements, strings, and so forth. We validate UTF-8 encoding at that stage.
- Stage 2. (Structure building) Involves constructing a "tree" of sort (materialized as a tape) to navigate through the data. Strings and numbers are parsed at this stage.
The role of stage 1 is to identify pseudo-structural characters as quickly as possible. A character is pseudo-structural if and only if:
1. Not enclosed in quotes, AND
2. Is a non-whitespace character, AND
3. Its preceding character is either:
(a) a structural character, OR
(b) whitespace OR
(c) the final quote in a string.
This helps as we redefine some new characters as pseudo-structural such as the characters 1, G, n in the following:
> { "foo" : 1.5, "bar" : 1.5 GEOFF_IS_A_DUMMY bla bla , "baz", null }
Stage 1 also does unicode validation.
Stage 2 handles all of the rest: number parsings, recognizing atoms like true, false, null, and so forth.
Developer mode
--------------
Build system targets that are only useful for developers of the simdjson
library are behind the `SIMDJSON_DEVELOPER_MODE` option. Enabling this option
makes tests, examples, benchmarks and other developer targets available. Not
enabling this option means that you are a consumer of simdjson and thus you
only get the library targets and options.
Developer mode is forced to be on when the `CI` environment variable is set to
a value that CMake recognizes as "on", which is set to `true` in all of the CI
workflows used by simdjson.
Directory Structure and Source
------------------------------
@@ -13,15 +52,15 @@ simdjson's source structure, from the top level, looks like this:
* **CMakeLists.txt:** The main build system.
* **include:** User-facing declarations and inline definitions (most user-facing functions are inlined).
* simdjson.h: A "master include" that includes files from include/simdjson/. This is equivalent to
* simdjson.h: A "main include" that includes files from include/simdjson/. This is equivalent to
the distributed simdjson.h.
* simdjson/*.h: Declarations for public simdjson classes and functions.
* simdjson/inline/*.h: Definitions for public simdjson classes and functions.
* simdjson/*-inl.h: Definitions for public simdjson classes and functions.
* **src:** The source files for non-inlined functionality (e.g. the architecture-specific parser
implementations).
* simdjson.cpp: A "master source" that includes all implementation files from src/. This is
* simdjson.cpp: A "main source" that includes all implementation files from src/. This is
equivalent to the distributed simdjson.cpp.
* arm64/|fallback/|haswell/|westmere/: Architecture-specific implementations. All functions are
* arm64/|fallback/|haswell/|ppc64/|westmere/: Architecture-specific implementations. All functions are
Each architecture defines its own namespace, e.g. simdjson::haswell.
* generic/: Generic implementations of the simdjson parser. These files may be included and
compiled multiple times, from whichever architectures use them. They assume they are already
@@ -38,44 +77,52 @@ Other important files and directories:
* **.drone.yml:** Definitions for Drone CI.
* **.appveyor.yml:** Definitions for Appveyor CI (Windows).
* **.circleci:** Definitions for Circle CI.
* **amalgamate.sh:** Generates singleheader/simdjson.h and singleheader/simdjson.cpp for release.
* **.github/workflows:** Definitions for GitHub Actions (CI).
* **singleheader:** Contains generated `simdjson.h` and `simdjson.cpp` that we release. The files `singleheader/simdjson.h` and `singleheader/simdjson.cpp` should never be edited by hand.
* **singleheader/amalgamate.py:** Generates `singleheader/simdjson.h` and `singleheader/simdjson.cpp` for release (python script).
* **benchmark:** This is where we do benchmarking. Benchmarking is core to every change we make; the
cardinal rule is don't regress performance without knowing exactly why, and what you're trading
for it. Many of our benchmarks are microbenchmarks. We are effectively doing controlled scientific experiments for the purpose of understanding what affects our performance. So we simplify as much as possible. We try to avoid irrelevant factors such as page faults, interrupts, unnnecessary system calls. We recommend checking the performance as follows:
```bash
mkdir build
cd build
cmake ..
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
cmake --build . --config Release
benchmark/parse ../jsonexamples/twitter.json
benchmark/dom/parse ../jsonexamples/twitter.json
```
The last line becomes `./benchmark/Release/parse.exe ../jsonexample/twitter.json` under Windows. You may also use Google Benchmark:
```bash
mkdir build
cd build
cmake ..
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
cmake --build . --target bench_parse_call --config Release
./benchmark/bench_parse_call
```
The last line becomes `./benchmark/Release/bench_parse_call.exe` under Windows. Under Windows, you can also build with the clang compiler by adding `-T ClangCL` to the call to `cmake ..`: `cmake .. - TClangCL`.
The last line becomes `./benchmark/Release/bench_parse_call.exe` under Windows. Under Windows, you can also build with the clang compiler by adding `-T ClangCL` to the call to `cmake ..`: `cmake -T ClangCL ..`.
* **fuzz:** The source for fuzz testing. This lets us explore important edge and middle cases
* **fuzz:** The source for fuzz testing. This lets us explore important edge and middle cases
automatically, and is run in CI.
* **jsonchecker:** A set of JSON files used to check different functionality of the parser.
* **pass*.json:** Files that should pass validation.
* **fail*.json:** Files that should fail validation.
* **jsonchecker/minefield/y_*.json:** Files that should pass validation.
* **jsonchecker/minefield/n_*.json:** Files that should fail validation.
* **jsonexamples:** A wide spread of useful, real-world JSON files with different characteristics
and sizes.
* **singleheader:** Contains generated simdjson.h and simdjson.cpp that we release.
* **test:** The tests are here. basictests.cpp and errortests.cpp are the primary ones.
* **tools:** Source for executables that can be distributed with simdjson
* **tools:** Source for executables that can be distributed with simdjson. Some examples:
* `json2json mydoc.json` parses the document, constructs a model and then dumps back the result to standard output.
* `json2json -d mydoc.json` parses the document, constructs a model and then dumps model (as a tape) to standard output. The tape format is described in the accompanying file `tape.md`.
* `minify mydoc.json` minifies the JSON document, outputting the result to standard output. Minifying means to remove the unneeded white space characters.
*`jsonpointer mydoc.json <jsonpath> <jsonpath> ... <jsonpath>` parses the document, constructs a model and then processes a series of [JSON Pointer paths](https://tools.ietf.org/html/rfc6901). The result is itself a JSON document.
> **Don't modify the files in singleheader/ directly; these are automatically generated.**
>
> While we distribute those files on release, we *maintain* the files under include/ and src/.
While simdjson distributes just two files from the singleheader/ directory, we *maintain* the code in
multiple files under include/ and src/. include/simdjson.h and src/simdjson.cpp are the "spine" for
these, and you can include
multiple files under include/ and src/. The files include/simdjson.h and src/simdjson.cpp are the "spine" for
these, and you can include them as if they were the corresponding singleheader/ files.
@@ -112,7 +159,7 @@ processor.
At this point, we are require to use one of two main strategies.
1. On POSIX systems, the main compilers (LLVM clang, GNU gcc) allow us to use any intrinsic function after including the header, but they fail to inline the resulting instruction if the target processor does not support them. Because we compile for a generic processor, we would not be able to use most intrinsic functions. Thankfully, more recent versions of these compilers allow us to flag a region of code with a specific target, so that we can compile only some of the code with support for advanced instructions. Thus in our C++, one might notice macros like `TARGET_HASWELL`. It is then our responsability, at runtime, to only run the regions of code (that we call kernels) matching the properties of the runtime processor. The benefit of this approach is that the compiler not only let us use intrinsic functions, but it can also optimize the rest of the code in the kernel with advanced instructions we enabled.
1. On POSIX systems, the main compilers (LLVM clang, GNU gcc) allow us to use any intrinsic function after including the header, but they fail to inline the resulting instruction if the target processor does not support them. Because we compile for a generic processor, we would not be able to use most intrinsic functions. Thankfully, more recent versions of these compilers allow us to flag a region of code with a specific target, so that we can compile only some of the code with support for advanced instructions. Thus in our C++, one might notice macros like `TARGET_HASWELL`. It is then our responsibility, at runtime, to only run the regions of code (that we call kernels) matching the properties of the runtime processor. The benefit of this approach is that the compiler not only let us use intrinsic functions, but it can also optimize the rest of the code in the kernel with advanced instructions we enabled.
2. Under Visual Studio, the problem is somewhat simpler. Visual Studio will not only provide the intrinsic functions, but it will also allow us to use them. They will compile just fine. It is at runtime that they may cause a crash. So we do not need to mark regions of code for compilation toward advanced processors (e.g., with `TARGET_HASWELL` macros). The downside of the Visual Studio approach is that the compiler is not allowed to use advanced instructions others than those we specify. In principle, this means that Visual Studio has weaker optimization opportunities.
@@ -124,26 +171,29 @@ We also handle the special case where a user is compiling using LLVM clang under
Regenerating Single Headers From Master
Regenerating Single-Header Files
---------------------------------------
simdjson.h and simdjson.cpp are not always up to date in master. To ensure you have the latest copy,
you can regenerate them by running this at the top level:
The simdjson.h and simdjson.cpp files in the singleheader directory are not always up-to-date with the rest of the code; they are only ever
systematically regenerated on releases. To ensure you have the latest code, you can regenerate them by running this at the top level:
```bash
mkdir build
cd build
cmake ..
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
cmake --build . # needed, because currently dependencies do not work fully for the amalgamate target
cmake --build . --target amalgamate
```
The amalgamator is at `amalgamate.sh` at the top level. It generates singleheader/simdjson.h by
You need to have python3 installed on your system.
The amalgamator script `amalgamate.py` generates singleheader/simdjson.h by
reading through include/simdjson.h, copy/pasting each header file into the amalgamated file at the
point it gets included (but only once per header). singleheader/simdjson.cpp is generated from
src/simdjson.cpp the same way, except files under generic/ may be included and copy/pasted multiple
times.
### Usage (CMake on 64-bit platforms like Linux, freeBSD or macOS)
### Usage (CMake on 64-bit platforms like Linux, FreeBSD or macOS)
Requirements: In addition to git, we require a recent version of CMake as well as bash.
@@ -156,7 +206,7 @@ brew install cmake
apt-get update -qq
apt-get install -y cmake
```
3. On freeBSD, you might be able to install bash and CMake as follows:
3. On FreeBSD, you might be able to install bash and CMake as follows:
```
pkg update -f
pkg install bash
@@ -171,31 +221,31 @@ Building: While in the project repository, do the following:
```
mkdir build
cd build
cmake ..
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
cmake --build .
ctest
```
CMake will build a library. By default, it builds a shared library (e.g., libsimdjson.so on Linux).
CMake will build a library. By default, it builds a static library (e.g., libsimdjson.a on Linux).
You can build a static library:
You can build a shared library:
```
mkdir buildstatic
cd buildstatic
cmake -DSIMDJSON_BUILD_STATIC=ON ..
mkdir buildshared
cd buildshared
cmake -D BUILD_SHARED_LIBS=ON -D SIMDJSON_DEVELOPER_MODE=ON ..
cmake --build .
ctest
```
In some cases, you may want to specify your compiler, especially if the default compiler on your system is too old. You need to tell cmake which compiler you wish to use by setting the CC and CXX variables. Under bash, you can do so with commands such as `export CC=gcc-7` and `export CXX=g++-7`. You can also do it as part of the `cmake` command: `cmake .. -DCMAKE_CXX_COMPILER=g++`. You may proceed as follows:
In some cases, you may want to specify your compiler, especially if the default compiler on your system is too old. You need to tell cmake which compiler you wish to use by setting the CC and CXX variables. Under bash, you can do so with commands such as `export CC=gcc-7` and `export CXX=g++-7`. You can also do it as part of the `cmake` command: `cmake -DCMAKE_CXX_COMPILER=g++ ..`. You may proceed as follows:
```
brew install gcc@8
mkdir build
cd build
export CXX=g++-8 CC=gcc-8
cmake ..
cmake -D SIMDJSON_DEVELOPER_MODE=ON ..
cmake --build .
ctest
```
@@ -206,15 +256,15 @@ Note that the name of directory (`build`) is arbitrary, you can name it as you w
### Usage (CMake on 64-bit Windows using Visual Studio)
### Usage (CMake on 64-bit Windows using Visual Studio 2019)
We assume you have a common 64-bit Windows PC with at least Visual Studio 2017 and an x64 processor with AVX2 support (2013 Intel Haswell or later) or SSE 4.2 + CLMUL (2010 Westmere or later).
We assume you have a common 64-bit Windows PC with at least Visual Studio 2019.
- Grab the simdjson code from GitHub, e.g., by cloning it using [GitHub Desktop](https://desktop.github.com/).
- Install [CMake](https://cmake.org/download/). When you install it, make sure to ask that `cmake` be made available from the command line. Please choose a recent version of cmake.
- Create a subdirectory within simdjson, such as `build`.
- Using a shell, go to this newly created directory. You can start a shell directly from GitHub Desktop (Repository > Open in Command Prompt).
- Type `cmake -DCMAKE_GENERATOR_PLATFORM=x64 ..` in the shell while in the `build` repository. (Alternatively, if you want to build a DLL, you may use the command line `cmake -DCMAKE_GENERATOR_PLATFORM=x64 -DSIMDJSON_BUILD_STATIC=OFF ..`.)
- Type `cmake ..` in the shell while in the `build` repository.
- This last command (`cmake ...`) created a Visual Studio solution file in the newly created directory (e.g., `simdjson.sln`). Open this file in Visual Studio. You should now be able to build the project and run the tests. For example, in the `Solution Explorer` window (available from the `View` menu), right-click `ALL_BUILD` and select `Build`. To test the code, still in the `Solution Explorer` window, select `RUN_TESTS` and select `Build`.
@@ -231,384 +281,15 @@ Furthermore, if you have installed LLVM clang on Windows, for example as a compo
- `mkdir build`
- `cd build`
- `cmake .. -T ClangCL`
- `cmake -T ClangCL ..`
- `cmake --build . -config Release`
### Usage (Using `vcpkg` on 64-bit Windows, Linux and macOS)
[vcpkg](https://github.com/Microsoft/vcpkg) users on Windows, Linux and macOS can download and install `simdjson` with one single command from their favorite shell.
On 64-bit Linux and macOS:
```
$ ./vcpkg install simdjson
```
will build and install `simdjson` as a static library.
On Windows (64-bit):
```
.\vcpkg.exe install simdjson:x64-windows
```
will build and install `simdjson` as a shared library.
```
.\vcpkg.exe install simdjson:x64-windows-static
```
will build and install `simdjson` as a static library.
These commands will also print out instructions on how to use the library from MSBuild or CMake-based projects.
If you find the version of `simdjson` shipped with `vcpkg` is out-of-date, feel free to report it to
`vcpkg` community either by submitting an issue or by creating a PR.
### Usage (Docker)
One can run tests and benchmarks using docker. It especially makes sense under Linux. Privileged
access may be needed to get performance counters.
```
git clone https://github.com/simdjson/simdjson.git
cd simdjson
docker build -t simdjson .
docker run --privileged -t simdjson
```
## Architecture and Design Notes
### Requirements
- 64-bit platforms like Linux or macOS, as well as Windows through Visual Studio 2017 or later.
- Any 64-bit processor:
- AVX2 (i.e., Intel processors starting with the Haswell microarchitecture released 2013 and AMD
processors starting with the Zen microarchitecture released 2017),
- SSE 4.2 and CLMUL (i.e., Intel processors going back to Westmere released in 2010 or AMD
processors starting with the Jaguar used in the PS4 and XBox One),
- 64-bit ARM processor (ARMv8-A NEON): this covers a wide range of mobile processors, including
all Apple processors currently available for sale, going as far back as the iPhone 5s (2013).
- Any 64-bit processor (simdjson has a fallback generic 64-bit implementation that is still super
fast).
- A recent C++ compiler (e.g., GNU GCC or LLVM CLANG or Visual Studio 2017), we assume C++17. GNU
GCC 7 or better or LLVM's clang 6 or better.
- Some benchmark scripts assume bash and other common utilities, but they are optional.
### Scope
We provide a fast parser, that fully validates an input according to various specifications.
The parser builds a useful immutable (read-only) DOM (document-object model) which can be later accessed.
To simplify the engineering, we make some assumptions.
- We support UTF-8 (and thus ASCII), nothing else (no Latin, no UTF-16). We do not believe this is a
genuine limitation, because we do not think there is any serious application that needs to process
JSON data without an ASCII or UTF-8 encoding. If the UTF-8 contains a leading BOM, it should be
omitted: the user is responsible for detecting and skipping the BOM; UTF-8 BOMs are discouraged.
- All strings in the JSON document may have up to 4294967295 bytes in UTF-8 (4GB). To enforce this
constraint, we refuse to parse a document that contains more than 4294967295 bytes (4GB). This
should accommodate most JSON documents.
- As allowed by the specification, we allow repeated keys within an object (other parsers like
sajson do the same).
- [The simdjson library is fast for JSON documents spanning a few bytes up to many megabytes](https://github.com/lemire/simdjson/issues/312).
_We do not aim to provide a general-purpose JSON library._ A library like RapidJSON offers much more
than just parsing, it helps you generate JSON and offers various other convenient functions. We
merely parse the document. This may change in the future.
### Features
- The input string is unmodified. (Parsers like sajson and RapidJSON use the input string as a buffer.)
- We parse integers and floating-point numbers as separate types which allows us to support large signed 64-bit integers in [-9223372036854775808,9223372036854775808), like a Java `long` or a C/C++ `long long` and large unsigned integers up to the value 18446744073709551615. Among the parsers that differentiate between integers and floating-point numbers, not all support 64-bit integers. (For example, sajson rejects JSON files with integers larger than or equal to 2147483648. RapidJSON will parse a file containing an overly long integer like 18446744073709551616 as a floating-point number.) When we cannot represent exactly an integer as a signed or unsigned 64-bit value, we reject the JSON document.
- We support the full range of 64-bit floating-point numbers (binary64). The values range from ` std::numeric_limits<double>::lowest()` to `std::numeric_limits<double>::max()`, so from -1.7976e308 all the way to 1.7975e308. Extreme values (less or equal to -1e308, greater or equal to 1e308) are rejected: we refuse to parse the input document.
- We test for accurate float parsing with a perfect accuracy (ULP 0). Many parsers offer only approximate floating parsing. For example, RapidJSON also offers the option of accurate float parsing (`kParseFullPrecisionFlag`) but it comes at a significant performance penalty compared to the default settings. By default, RapidJSON tolerates an error of 3 ULP.
- We do full UTF-8 validation as part of the parsing. (Parsers like fastjson, gason and dropbox json11 do not do UTF-8 validation. The sajson parser does incomplete UTF-8 validation, accepting code point
sequences like 0xb1 0x87.)
- We fully validate the numbers. (Parsers like gason and ultranjson will accept `[0e+]` as valid JSON.)
- We validate string content for unescaped characters. (Parsers like fastjson and ultrajson accept unescaped line breaks and tabs in strings.)
- We fully validate the white-space characters outside of the strings. Parsers like RapidJSON will accept JSON documents with null characters outside of strings.
### Architecture
The parser works in two stages:
- Stage 1. (Find marks) Identifies quickly structure elements, strings, and so forth. We validate UTF-8 encoding at that stage.
- Stage 2. (Structure building) Involves constructing a "tree" of sort (materialized as a tape) to navigate through the data. Strings and numbers are parsed at this stage.
### Remarks on JSON parsing
- The JSON spec defines what a JSON parser is:
> A JSON parser transforms a JSON text into another representation. A JSON parser MUST accept all texts that conform to the JSON grammar. A JSON parser MAY accept non-JSON forms or extensions. An implementation may set limits on the size of texts that it accepts. An implementation may set limits on the maximum depth of nesting. An implementation may set limits on the range and precision of numbers. An implementation may set limits on the length and character contents of strings.
* JSON is not JavaScript:
> All JSON is Javascript but NOT all Javascript is JSON. So {property:1} is invalid because property does not have double quotes around it. {'property':1} is also invalid, because it's single quoted while the only thing that can placate the JSON specification is double quoting. JSON is even fussy enough that {"property":.1} is invalid too, because you should have of course written {"property":0.1}. Also, don't even think about having comments or semicolons, you guessed it: they're invalid. (credit:https://github.com/elzr/vim-json)
* The structural characters are:
begin-array = [ left square bracket
begin-object = { left curly bracket
end-array = ] right square bracket
end-object = } right curly bracket
name-separator = : colon
value-separator = , comma
### Pseudo-structural elements
A character is pseudo-structural if and only if:
1. Not enclosed in quotes, AND
2. Is a non-whitespace character, AND
3. Its preceding character is either:
(a) a structural character, OR
(b) whitespace.
This helps as we redefine some new characters as pseudo-structural such as the characters 1, G, n in the following:
> { "foo" : 1.5, "bar" : 1.5 GEOFF_IS_A_DUMMY bla bla , "baz", null }
### UTF-8 validation (lookup2)
The simdjson library relies on the lookup2 algorithm for UTF-8 validation on x64 platforms.
This algorithm validate the length of multibyte characters (that each multibyte character has the right number of continuation characters, and that all continuation characters are part of a multibyte character).
#### Algorithm
This algorithm compares *expected* continuation characters with *actual* continuation bytes, and emits an error anytime there is a mismatch.
For example, in the string "𝄞₿֏ab", which has a 4-, 3-, 2- and 1-byte
characters, the file will look like this:
| Character | 𝄞 | | | | ₿ | | | ֏ | | a | b |
|-----------------------|----|----|----|----|----|----|----|----|----|----|----|
| Character Length | 4 | | | | 3 | | | 2 | | 1 | 1 |
| Byte | F0 | 9D | 84 | 9E | E2 | 82 | BF | D6 | 8F | 61 | 62 |
| is_second_byte | | X | | | | X | | | X | | |
| is_third_byte | | | X | | | | X | | | | |
| is_fourth_byte | | | | X | | | | | | | |
| expected_continuation | | X | X | X | | X | X | | X | | |
| is_continuation | | X | X | X | | X | X | | X | | |
The errors here are basically (Second Byte OR Third Byte OR Fourth Byte == Continuation):
- **Extra Continuations:** Any continuation that is not a second, third or fourth byte is not
part of a valid 2-, 3- or 4-byte character and is thus an error. It could be that it's just
floating around extra outside of any character, or that there is an illegal 5-byte character,
or maybe it's at the beginning of the file before any characters have started; but it's an
error in all these cases.
- **Missing Continuations:** Any second, third or fourth byte that *isn't* a continuation is an error, because that means
we started a new character before we were finished with the current one.
#### Getting the Previous Bytes
Because we want to know if a byte is the *second* (or third, or fourth) byte of a multibyte
character, we need to "shift the bytes" to find that out. This is what they mean:
- `is_continuation`: if the current byte is a continuation.
- `is_second_byte`: if 1 byte back is the start of a 2-, 3- or 4-byte character.
- `is_third_byte`: if 2 bytes back is the start of a 3- or 4-byte character.
- `is_fourth_byte`: if 3 bytes back is the start of a 4-byte character.
We use shuffles to go n bytes back, selecting part of the current `input` and part of the
`prev_input` (search for `.prev<1>`, `.prev<2>`, etc.). These are passed in by the caller
function, because the 1-byte-back data is used by other checks as well.
#### Getting the Continuation Mask
Once we have the right bytes, we have to get the masks. To do this, we treat UTF-8 bytes as
numbers, using signed `<` and `>` operations to check if they are continuations or leads.
In fact, we treat the numbers as *signed*, partly because it helps us, and partly because
Intel's SIMD presently only offers signed `<` and `>` operations (not unsigned ones).
In UTF-8, bytes that start with the bits 110, 1110 and 11110 are 2-, 3- and 4-byte "leads,"
respectively, meaning they expect to have 1, 2 and 3 "continuation bytes" after them.
Continuation bytes start with 10, and ASCII (1-byte characters) starts with 0.
When treated as signed numbers, they look like this:
| Type | High Bits | Binary Range | Signed |
|--------------|------------|--------------|--------|
| ASCII | `0` | `01111111` | 127 |
| | | `00000000` | 0 |
| 4+-Byte Lead | `1111` | `11111111` | -1 |
| | | `11110000 | -16 |
| 3-Byte Lead | `1110` | `11101111` | -17 |
| | | `11100000 | -32 |
| 2-Byte Lead | `110` | `11011111` | -33 |
| | | `11000000 | -64 |
| Continuation | `10` | `10111111` | -65 |
| | | `10000000 | -128 |
This makes it pretty easy to get the continuation mask! It's just a single comparison:
```
is_continuation = input < -64`
```
We can do something similar for the others, but it takes two comparisons instead of one: "is
the start of a 4-byte character" is `< -32` and `> -65`, for example. And 2+ bytes is `< 0` and
`> -64`. Surely we can do better, they're right next to each other!
#### Getting the is_xxx Masks: Shifting the Range
Notice *why* continuations were a single comparison. The actual *range* would require two
comparisons--`< -64` and `> -129`--but all characters are always greater than -128, so we get
that for free. In fact, if we had *unsigned* comparisons, 2+, 3+ and 4+ comparisons would be
just as easy: 4+ would be `> 239`, 3+ would be `> 223`, and 2+ would be `> 191`.
Instead, we add 128 to each byte, shifting the range up to make comparison easy. This wraps
ASCII down into the negative, and puts 4+-Byte Lead at the top:
| Type | High Bits | Binary Range | Signed |
|----------------------|------------|--------------|-------|
| 4+-Byte Lead (+ 127) | `0111` | `01111111` | 127 |
| | | `01110000 | 112 |
|----------------------|------------|--------------|-------|
| 3-Byte Lead (+ 127) | `0110` | `01101111` | 111 |
| | | `01100000 | 96 |
|----------------------|------------|--------------|-------|
| 2-Byte Lead (+ 127) | `010` | `01011111` | 95 |
| | | `01000000 | 64 |
|----------------------|------------|--------------|-------|
| Continuation (+ 127) | `00` | `00111111` | 63 |
| | | `00000000 | 0 |
|----------------------|------------|--------------|-------|
| ASCII (+ 127) | `1` | `11111111` | -1 |
| | | `10000000` | -128 |
|----------------------|------------|--------------|-------|
*Now* we can use signed `>` on all of them:
```
prev1 = input.prev<1>
prev2 = input.prev<2>
prev3 = input.prev<3>
prev1_flipped = input.prev<1>(prev_input) ^ 0x80; // Same as `+ 128`
prev2_flipped = input.prev<2>(prev_input) ^ 0x80; // Same as `+ 128`
prev3_flipped = input.prev<3>(prev_input) ^ 0x80; // Same as `+ 128`
is_second_byte = prev1_flipped > 63;2+-byte lead
is_third_byte = prev2_flipped > 95;3+-byte lead
is_fourth_byte = prev3_flipped > 111; // 4+-byte lead
```
NOTE: we use `^ 0x80` instead of `+ 128` in the code, which accomplishes the same thing, and even takes the same number
of cycles as `+`, but on many Intel architectures can be parallelized better (you can do 3
`^`'s at a time on Haswell, but only 2 `+`'s).
That doesn't look like it saved us any instructions, did it? Well, because we're adding the
same number to all of them, we can save one of those `+ 128` operations by assembling
`prev2_flipped` out of prev 1 and prev 3 instead of assembling it from input and adding 128
to it. One more instruction saved!
```
prev1 = input.prev<1>
prev3 = input.prev<3>
prev1_flipped = prev1 ^ 0x80; // Same as `+ 128`
prev3_flipped = prev3 ^ 0x80; // Same as `+ 128`
prev2_flipped = prev1_flipped.concat<2>(prev3_flipped): // <shuffle: take the first 2 bytes from prev1 and the rest from prev3
```
#### Bringing It All Together: Detecting the Errors
At this point, we have `is_continuation`, `is_first_byte`, `is_second_byte` and `is_third_byte`.
All we have left to do is check if they match!
```
return (is_second_byte | is_third_byte | is_fourth_byte) ^ is_continuation;
```
But wait--there's more. The above statement is only 3 operations, but they *cannot be done in
parallel*. You have to do 2 `|`'s and then 1 `&`. Haswell, at least, has 3 ports that can do
bitwise operations, and we're only using 1!
#### Epilogue: Addition For Booleans
There is one big case the above code doesn't explicitly talk about--what if is_second_byte
and is_third_byte are BOTH true? That means there is a 3-byte and 2-byte character right next
to each other (or any combination), and the continuation could be part of either of them!
Our algorithm using `&` and `|` won't detect that the continuation byte is problematic.
Never fear, though. If that situation occurs, we'll already have detected that the second
leading byte was an error, because it was supposed to be a part of the preceding multibyte
character, but it *wasn't a continuation*.
We could stop here, but it turns out that we can fix it using `+` and `-` instead of `|` and
`&`, which is both interesting and possibly useful (even though we're not using it here). It
exploits the fact that in SIMD, a *true* value is -1, and a *false* value is 0. So those
comparisons were giving us numbers!
Given that, if you do `is_second_byte + is_third_byte + is_fourth_byte`, under normal
circumstances you will either get 0 (0 + 0 + 0) or -1 (-1 + 0 + 0, etc.). Thus,
`(is_second_byte + is_third_byte + is_fourth_byte) - is_continuation` will yield 0 only if
*both* or *neither* are 0 (0-0 or -1 - -1). You'll get 1 or -1 if they are different. Because
*any* nonzero value is treated as an error (not just -1), we're just fine here :)
Further, if *more than one* multibyte character overlaps,
`is_second_byte + is_third_byte + is_fourth_byte` will be -2 or -3! Subtracting `is_continuation`
from *that* is guaranteed to give you a nonzero value (-1, -2 or -3). So it'll always be
considered an error.
One reason you might want to do this is parallelism. ^ and | are not associative, so
(A | B | C) ^ D will always be three operations in a row: either you do A | B -> | C -> ^ D, or
you do B | C -> | A -> ^ D. But addition and subtraction *are* associative: (A + B + C) - D can
be written as `(A + B) + (C - D)`. This means you can do A + B and C - D at the same time, and
then adds the result together. Same number of operations, but if the processor can run
independent things in parallel (which most can), it runs faster.
This doesn't help us on Intel, but might help us elsewhere: on Haswell, at least, | and ^ have
a super nice advantage in that more of them can be run at the same time (they can run on 3
ports, while + and - can run on 2)! This means that we can do A | B while we're still doing C,
saving us the cycle we would have earned by using +. Even more, using an instruction with a
wider array of ports can help *other* code run ahead, too, since these instructions can "get
out of the way," running on a port other instructions can't.
#### Epilogue II: One More Trick
There's one more relevant trick up our sleeve, it turns out: it turns out on Intel we can "pay
for" the (prev<1> + 128) instruction, because it can be used to save an instruction in
check_special_cases()--but we'll talk about that there :)
## About the Project
### Bindings and Ports of simdjson
We distinguish between "bindings" (which just wrap the C++ code) and a port to another programming language (which reimplements everything).
- [ZippyJSON](https://github.com/michaeleisel/zippyjson): Swift bindings for the simdjson project.
- [pysimdjson](https://github.com/TkTech/pysimdjson): Python bindings for the simdjson project.
- [simdjson-rs](https://github.com/Licenser/simdjson-rs): Rust port.
- [simdjson-rust](https://github.com/SunDoge/simdjson-rust): Rust wrapper (bindings).
- [SimdJsonSharp](https://github.com/EgorBo/SimdJsonSharp): C# version for .NET Core (bindings and full port).
- [simdjson_nodejs](https://github.com/luizperes/simdjson_nodejs): Node.js bindings for the simdjson project.
- [simdjson_php](https://github.com/crazyxman/simdjson_php): PHP bindings for the simdjson project.
- [simdjson_ruby](https://github.com/saka1/simdjson_ruby): Ruby bindings for the simdjson project.
- [simdjson-go](https://github.com/minio/simdjson-go): Go port using Golang assembly.
- [rcppsimdjson](https://github.com/eddelbuettel/rcppsimdjson): R bindings.
### Tools
- `json2json mydoc.json` parses the document, constructs a model and then dumps back the result to standard output.
- `json2json -d mydoc.json` parses the document, constructs a model and then dumps model (as a tape) to standard output. The tape format is described in the accompanying file `tape.md`.
- `minify mydoc.json` minifies the JSON document, outputting the result to standard output. Minifying means to remove the unneeded white space characters.
- `jsonpointer mydoc.json <jsonpath> <jsonpath> ... <jsonpath>` parses the document, constructs a model and then processes a series of [JSON Pointer paths](https://tools.ietf.org/html/rfc6901). The result is itself a JSON document.
### Various References
- [Google double-conv](https://github.com/google/double-conversion/)
- [How to implement atoi using SIMD?](https://stackoverflow.com/questions/35127060/how-to-implement-atoi-using-simd)
- [Parsing JSON is a Minefield 💣](http://seriot.ch/parsing_json.php)
- https://tools.ietf.org/html/rfc7159
- The Mison implementation in rust https://github.com/pikkr/pikkr
- http://rapidjson.org/md_doc_sax.html
- https://github.com/Geal/parser_benchmarks/tree/master/json
- Gron: A command line tool that makes JSON greppable https://news.ycombinator.com/item?id=16727665
@@ -622,31 +303,3 @@ Inspiring links:
- https://auth0.com/blog/beating-json-performance-with-protobuf/
- https://gist.github.com/shijuvar/25ad7de9505232c87034b8359543404a
- https://github.com/frankmcsherry/blog/blob/master/posts/2018-02-11.md
Validating UTF-8 takes no more than 0.7 cycles per byte:
- https://github.com/lemire/fastvalidate-utf-8 https://lemire.me/blog/2018/05/16/validating-utf-8-strings-using-as-little-as-0-7-cycles-per-byte/
### Academic References
- T.Mühlbauer, W.Rödiger, R.Seilbeck, A.Reiser, A.Kemper, and T.Neumann. Instant loading for main memory databases. PVLDB, 6(14):17021713, 2013. (SIMD-based CSV parsing)
- Mytkowicz, Todd, Madanlal Musuvathi, and Wolfram Schulte. "Data-parallel finite-state machines." ACM SIGARCH Computer Architecture News. Vol. 42. No. 1. ACM, 2014.
- Lu, Yifan, et al. "Tree structured data processing on GPUs." Cloud Computing, Data Science & Engineering-Confluence, 2017 7th International Conference on. IEEE, 2017.
- Sidhu, Reetinder. "High throughput, tree automata based XML processing using FPGAs." Field-Programmable Technology (FPT), 2013 International Conference on. IEEE, 2013.
- Dai, Zefu, Nick Ni, and Jianwen Zhu. "A 1 cycle-per-byte XML parsing accelerator." Proceedings of the 18th annual ACM/SIGDA international symposium on Field programmable gate arrays. ACM, 2010.
- Lin, Dan, et al. "Parabix: Boosting the efficiency of text processing on commodity processors." High Performance Computer Architecture (HPCA), 2012 IEEE 18th International Symposium on. IEEE, 2012. http://parabix.costar.sfu.ca/export/1783/docs/HPCA2012/final_ieee/final.pdf
- Deshmukh, V. M., and G. R. Bamnote. "An empirical evaluation of optimization parameters in XML parsing for performance enhancement." Computer, Communication and Control (IC4), 2015 International Conference on. IEEE, 2015.
- Moussalli, Roger, et al. "Efficient XML Path Filtering Using GPUs." ADMS@ VLDB. 2011.
- Jianliang, Ma, et al. "Parallel speculative dom-based XML parser." High Performance Computing and Communication & 2012 IEEE 9th International Conference on Embedded Software and Systems (HPCC-ICESS), 2012 IEEE 14th International Conference on. IEEE, 2012.
- Li, Y., Katsipoulakis, N.R., Chandramouli, B., Goldstein, J. and Kossmann, D., 2017. Mison: a fast JSON parser for data analytics. Proceedings of the VLDB Endowment, 10(10), pp.1118-1129. http://www.vldb.org/pvldb/vol10/p1118-li.pdf
- Cameron, Robert D., et al. "Parallel scanning with bitstream addition: An xml case study." European Conference on Parallel Processing. Springer, Berlin, Heidelberg, 2011.
- Cameron, Robert D., Kenneth S. Herdy, and Dan Lin. "High performance XML parsing using parallel bit stream technology." Proceedings of the 2008 conference of the center for advanced studies on collaborative research: meeting of minds. ACM, 2008.
- Shah, Bhavik, et al. "A data parallel algorithm for XML DOM parsing." International XML Database Symposium. Springer, Berlin, Heidelberg, 2009.
- Cameron, Robert D., and Dan Lin. "Architectural support for SWAR text processing with parallel bit streams: the inductive doubling principle." ACM Sigplan Notices. Vol. 44. No. 3. ACM, 2009.
- Amagasa, Toshiyuki, Mana Seino, and Hiroyuki Kitagawa. "Energy-Efficient XML Stream Processing through Element-Skipping Parsing." Database and Expert Systems Applications (DEXA), 2013 24th International Workshop on. IEEE, 2013.
- Medforth, Nigel Woodland. "icXML: Accelerating Xerces-C 3.1. 1 using the Parabix Framework." (2013).
- Zhang, Qiang Scott. Embedding Parallel Bit Stream Technology Into Expat. Diss. Simon Fraser University, 2010.
- Cameron, Robert D., et al. "Fast Regular Expression Matching with Bit-parallel Data Streams."
- Lin, Dan. Bits filter: a high-performance multiple string pattern matching algorithm for malware detection. Diss. School of Computing Science-Simon Fraser University, 2010.
- Yang, Shiyang. Validation of XML Document Based on Parallel Bit Stream Technology. Diss. Applied Sciences: School of Computing Science, 2013.
- N. Nakasato, "Implementation of a parallel tree method on a GPU", Journal of Computational Science, vol. 3, no. 3, pp. 132-141, 2012.
+60 -57
View File
@@ -1,8 +1,9 @@
[![Build Status](https://cloud.drone.io/api/badges/simdjson/simdjson/status.svg)](https://cloud.drone.io/simdjson/simdjson)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/simdjson.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&q=proj%3Asimdjson&can=2)
[![Build status](https://ci.appveyor.com/api/projects/status/ae77wp5v3lebmu6n/branch/master?svg=true)](https://ci.appveyor.com/project/lemire/simdjson-jmmti/branch/master)
[![CirrusCI](https://api.cirrus-ci.com/github/simdjson/simdjson.svg)](https://cirrus-ci.com/github/simdjson/simdjson)
[![][license img]][license] [![Doxygen Documentation](https://img.shields.io/badge/docs-doxygen-green.svg)](https://simdjson.org/api/0.3.1/index.html)
![Ubuntu 18.04 CI](https://github.com/simdjson/simdjson/workflows/Ubuntu%2018.04%20CI%20(GCC%207)/badge.svg)
[![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)
simdjson : Parsing gigabytes of JSON per second
===============================================
@@ -10,13 +11,15 @@ simdjson : Parsing gigabytes of JSON per second
<img src="images/logo.png" width="10%" style="float: right">
JSON is everywhere on the Internet. Servers spend a *lot* of time parsing it. We need a fresh
approach. The simdjson library uses commonly available SIMD instructions and microparallel algorithms
to parse JSON 2.5x faster than anything else out there.
to parse JSON 4x faster than RapidJSON and 25x faster than JSON for Modern C++.
* **Fast:** Over 2.5x faster than other production-grade JSON parsers.
* **Easy:** First-class, easy to use API.
* **Fast:** Over 4x faster than commonly used production-grade JSON parsers.
* **Record Breaking Features:** Minify JSON at 6 GB/s, validate UTF-8 at 13 GB/s, NDJSON at 3.5 GB/s.
* **Easy:** First-class, easy to use and carefully documented APIs.
* **Strict:** Full JSON and UTF-8 validation, lossless parsing. Performance with no compromises.
* **Automatic:** Selects a CPU-tailored parser at runtime. No configuration needed.
* **Reliable:** From memory allocation to error handling, simdjson's design avoids surprises.
* **Peer Reviewed:** Our research appears in venues like VLDB Journal, Software: Practice and Experience.
This library is part of the [Awesome Modern C++](https://awesomecpp.com) list.
@@ -36,23 +39,30 @@ Table of Contents
Quick Start
-----------
The simdjson library is easily consumable with a single .h and .cpp file.
0. Prerequisites: `g++` (version 7 or better) or `clang++` (version 6 or better), and a 64-bit system with a command-line shell (e.g., Linux, macOS, freeBSD). We also support programming environnements like Visual Studio and Xcode, but different steps are needed.
1. Pull [simdjson.h](singleheader/simdjson.h) and [simdjson.cpp](singleheader/simdjson.cpp) into a directory, along with the sample file [twitter.json](jsonexamples/twitter.json).
0. Prerequisites: `g++` (version 7 or better) or `clang++` (version 6 or better), and a 64-bit
system with a command-line shell (e.g., Linux, macOS, freeBSD). We also support programming
environments like Visual Studio and Xcode, but different steps are needed.
1. Pull [simdjson.h](singleheader/simdjson.h) and [simdjson.cpp](singleheader/simdjson.cpp) into a
directory, along with the sample file [twitter.json](jsonexamples/twitter.json).
```
wget https://raw.githubusercontent.com/simdjson/simdjson/master/singleheader/simdjson.h https://raw.githubusercontent.com/simdjson/simdjson/master/singleheader/simdjson.cpp https://raw.githubusercontent.com/simdjson/simdjson/master/jsonexamples/twitter.json
```
2. Create `quickstart.cpp`:
```c++
#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;
}
```c++
#include <iostream>
#include "simdjson.h"
using namespace simdjson;
int main(void) {
ondemand::parser parser;
padded_string json = padded_string::load("twitter.json");
ondemand::document tweets = parser.iterate(json);
std::cout << uint64_t(tweets["search_metadata"]["count"]) << " results." << std::endl;
}
```
3. `c++ -o quickstart quickstart.cpp simdjson.cpp`
4. `./quickstart`
@@ -69,64 +79,42 @@ 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/0.3.1/annotated.html) contains the automatically generated API documentation.
* [API](https://simdjson.org/api/1.0.0/annotated.html) contains the automatically generated API documentation.
Performance results
-------------------
The simdjson library uses three-quarters less instructions than state-of-the-art parser [RapidJSON](https://rapidjson.org) and
fifty percent less than sajson. To our knowledge, simdjson is the first fully-validating JSON parser
The simdjson library uses three-quarters less instructions than state-of-the-art parser [RapidJSON](https://rapidjson.org). To our knowledge, simdjson is the first fully-validating JSON parser
to run at [gigabytes per second](https://en.wikipedia.org/wiki/Gigabyte) (GB/s) on commodity processors. It can parse millions of JSON documents per second on a single core.
The following figure represents parsing speed in GB/s for parsing various files
on an Intel Skylake processor (3.4 GHz) using the GNU GCC 9 compiler (with the -O3 flag).
We compare against the best and fastest C++ libraries.
on an Intel Skylake processor (3.4 GHz) using the GNU GCC 10 compiler (with the -O3 flag).
We compare against the best and fastest C++ libraries on benchmarks that load and process the data.
The simdjson library offers full unicode ([UTF-8](https://en.wikipedia.org/wiki/UTF-8)) validation and exact
number parsing. The RapidJSON library is tested in two modes: fast and
exact number parsing. The sajson library offers fast (but not exact)
number parsing and partial unicode validation. In this data set, the file
sizes range from 65KB (github_events) all the way to 3.3GB (gsoc-2018).
Many files are mostly made of numbers: canada, mesh.pretty, mesh, random
and numbers: in such instances, we see lower JSON parsing speeds due to the
high cost of number parsing. The simdjson library uses exact number parsing which
is particular taxing.
<img src="doc/gbps.png" width="90%">
On a Skylake processor, the parsing speeds (in GB/s) of various processors on the twitter.json file are as follows, using again GNU GCC 9.1 (with the -O3 flag). The popular JSON for Modern C++ library is particularly slow: it obviously trades parsing speed for other desirable features.
| parser | GB/s |
| ------------------------------------- | ---- |
| simdjson | 2.5 |
| RapidJSON UTF8-validation | 0.29 |
| RapidJSON UTF8-valid., exact numbers | 0.28 |
| RapidJSON insitu, UTF8-validation | 0.41 |
| RapidJSON insitu, UTF8-valid., exact | 0.39 |
| sajson (insitu, dynamic) | 0.62 |
| sajson (insitu, static) | 0.88 |
| dropbox | 0.13 |
| fastjson | 0.27 |
| gason | 0.59 |
| ultrajson | 0.34 |
| jsmn | 0.25 |
| cJSON | 0.31 |
| JSON for Modern C++ (nlohmann/json) | 0.11 |
number parsing.
<img src="doc/rome.png" width="60%">
The simdjson library offers high speed whether it processes tiny files (e.g., 300 bytes)
or larger files (e.g., 3MB). The following plot presents parsing
speed for [synthetic files over various sizes generated with a script](https://github.com/simdjson/simdjson_experiments_vldb2019/blob/master/experiments/growing/gen.py) on a 3.4 GHz Skylake processor (GNU GCC 9, -O3).
<img src="doc/growing.png" width="90%">
<img src="doc/growing.png" width="60%">
[All our experiments are reproducible](https://github.com/simdjson/simdjson_experiments_vldb2019).
For NDJSON files, we can exceed 3 GB/s with [our multithreaded parsing functions](https://github.com/simdjson/simdjson/blob/master/doc/parse_many.md).
Real-world usage
----------------
- [Microsoft FishStore](https://github.com/microsoft/FishStore)
- [Yandex ClickHouse](https://github.com/yandex/ClickHouse)
- [Clang Build Analyzer](https://github.com/aras-p/ClangBuildAnalyzer)
- [Shopify HeapProfiler](https://github.com/Shopify/heap-profiler)
If you are planning to use simdjson in a product, please work from one of our releases.
@@ -136,15 +124,22 @@ Bindings and Ports of simdjson
We distinguish between "bindings" (which just wrap the C++ code) and a port to another programming language (which reimplements everything).
- [ZippyJSON](https://github.com/michaeleisel/zippyjson): Swift bindings for the simdjson project.
- [libpy_simdjson](https://github.com/gerrymanoim/libpy_simdjson/): high-speed Python bindings for simdjson using [libpy](https://github.com/quantopian/libpy).
- [pysimdjson](https://github.com/TkTech/pysimdjson): Python bindings for the simdjson project.
- [cysimdjson](https://github.com/TeskaLabs/cysimdjson): high-speed Python bindings for the simdjson project.
- [simdjson-rs](https://github.com/simd-lite): Rust port.
- [simdjson-rust](https://github.com/SunDoge/simdjson-rust): Rust wrapper (bindings).
- [SimdJsonSharp](https://github.com/EgorBo/SimdJsonSharp): C# version for .NET Core (bindings and full port).
- [simdjson_nodejs](https://github.com/luizperes/simdjson_nodejs): Node.js bindings for the simdjson project.
- [simdjson_php](https://github.com/crazyxman/simdjson_php): PHP bindings for the simdjson project.
- [simdjson_ruby](https://github.com/saka1/simdjson_ruby): Ruby bindings for the simdjson project.
- [fast_jsonparser](https://github.com/anilmaurya/fast_jsonparser): Ruby bindings for the simdjson project.
- [simdjson-go](https://github.com/minio/simdjson-go): Go port using Golang assembly.
- [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
--------------
@@ -154,14 +149,18 @@ instructions, reducing branch misprediction, and reducing data dependency to tak
CPU's multiple execution cores.
Some people [enjoy reading our paper](https://arxiv.org/abs/1902.08318): A description of the design
and implementation of simdjson is in our research article: Geoff Langdale, Daniel
Lemire, [Parsing Gigabytes of JSON per Second](https://arxiv.org/abs/1902.08318), VLDB Journal 28 (6), 2019.
and implementation of simdjson is in our research article:
- Geoff Langdale, Daniel Lemire, [Parsing Gigabytes of JSON per Second](https://arxiv.org/abs/1902.08318), VLDB Journal 28 (6), 2019.
We have an in-depth paper focused on the UTF-8 validation:
- John Keiser, Daniel Lemire, [Validating UTF-8 In Less Than One Instruction Per Byte](https://arxiv.org/abs/2010.03090), Software: Practice & Experience 51 (5), 2021.
We also have an informal [blog post providing some background and context](https://branchfree.org/2019/02/25/paper-parsing-gigabytes-of-json-per-second/).
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
-------
@@ -185,4 +184,8 @@ This code is made available under the [Apache License 2.0](https://www.apache.or
Under Windows, we build some tools using the windows/dirent_portable.h file (which is outside our library code): it under the liberal (business-friendly) MIT license.
For compilers that do not support [C++17](https://en.wikipedia.org/wiki/C%2B%2B17), we bundle the string-view library which is published under the Boost license (http://www.boost.org/LICENSE_1_0.txt). Like the Apache license, the Boost license is a permissive license allowing commercial redistribution.
For compilers that do not support [C++17](https://en.wikipedia.org/wiki/C%2B%2B17), we bundle the string-view library which is published under the [Boost license](http://www.boost.org/LICENSE_1_0.txt). Like the Apache license, the Boost license is a permissive license allowing commercial redistribution.
For efficient number serialization, we bundle Florian Loitsch's implementation of the Grisu2 algorithm for binary to decimal floating-point numbers. The implementation was slightly modified by JSON for Modern C++ library. Both Florian Loitsch's implementation and JSON for Modern C++ are provided under the MIT license.
For runtime dispatching, we use some code from the PyTorch project licensed under 3-clause BSD.
+36
View File
@@ -1,3 +1,39 @@
# 0.5
## Highlights
Performance
* Faster and simpler UTF-8 validation with the lookup4 algorithm https://github.com/simdjson/simdjson/pull/993
* We improved the performance of simdjson under Visual Studio by about 25%. Users will still get better performance with clang-cl (+30%) but the gap has been reduced. https://github.com/simdjson/simdjson/pull/1031
Code usability
* In `parse_many`, when parsing streams of JSON documetns, we give to the users runtime control as to whether threads are used (via the parser.threaded attribute). https://github.com/simdjson/simdjson/issues/925
* Prefixed public macros to avoid name clashes with other libraries. https://github.com/simdjson/simdjson/issues/1035
* Better documentation regarding package managers (brew, MSYS2, conan, apt, vcpkg, FreeBSD package manager, etc.).
* Better documentation regarding CMake usage.
Standards
* We improved standard compliance with respect to both the JSON RFC 8259 and JSON Pointer RFC 6901. We added the at_pointer method to nodes for standard-compliant JSON Pointer queries. The legacy `at(std::string_view)` method remains but is deprecated since it is not standard-compliant as per RFC 6901.
* We removed computed GOTOs without sacrificing performance thus improving the C++ standard compliance (since computed GOTOs are compiler-specific extensions).
* Better support for C++20 https://github.com/simdjson/simdjson/pull/1050
# 0.4
## Highlights
- Test coverage has been greatly improved and we have resolved many static-analysis warnings on different systems.
- We added a fast (8GB/s) minifier that works directly on JSON strings.
- We added fast (10GB/s) UTF-8 validator that works directly on strings (any strings, including non-JSON).
- The array and object elements have a constant-time size() method.
- Performance improvements to the API (type(), get<>()).
- The parse_many function (ndjson) has been entirely reworked. It now uses a single secondary thread instead of several new threads.
- We have introduced a faster UTF-8 validation algorithm (lookup3) for all kernels (ARM, x64 SSE, x64 AVX).
- C++11 support for older compilers and systems.
- FreeBSD support (and tests).
- We support the clang front-end compiler (clangcl) under Visual Studio.
- It is now possible to target ARM platforms under Visual Studio.
- The simdjson library will never abort or print to standard output/error.
# 0.3
## Highlights
+21 -27
View File
@@ -1,37 +1,31 @@
add_subdirectory(dom)
include_directories( . linux )
link_libraries(simdjson simdjson-flags simdjson-windows-headers test-data)
link_libraries(simdjson-windows-headers test-data)
link_libraries(simdjson)
add_executable(benchfeatures benchfeatures.cpp)
add_executable(get_corpus_benchmark get_corpus_benchmark.cpp)
add_executable(perfdiff perfdiff.cpp)
add_executable(parse parse.cpp)
add_executable(parse_stream parse_stream.cpp)
add_executable(statisticalmodel statisticalmodel.cpp)
add_executable(parse_noutf8validation parse.cpp)
target_compile_definitions(parse_noutf8validation PRIVATE SIMDJSON_SKIPUTF8VALIDATION)
add_executable(parse_nonumberparsing parse.cpp)
target_compile_definitions(parse_nonumberparsing PRIVATE SIMDJSON_SKIPNUMBERPARSING)
add_executable(parse_nostringparsing parse.cpp)
target_compile_definitions(parse_nostringparsing PRIVATE SIMDJSON_SKIPSTRINGPARSING)
if (TARGET benchmark::benchmark)
link_libraries(benchmark::benchmark)
add_executable(bench_parse_call bench_parse_call.cpp)
add_executable(bench_dom_api bench_dom_api.cpp)
if(SIMDJSON_EXCEPTIONS)
add_executable(bench_ondemand bench_ondemand.cpp)
if(TARGET yyjson)
target_link_libraries(bench_ondemand PRIVATE yyjson)
endif()
if(TARGET rapidjson)
target_link_libraries(bench_ondemand PRIVATE rapidjson)
endif()
if(TARGET sajson)
target_link_libraries(bench_ondemand PRIVATE sajson)
endif()
if(TARGET nlohmann_json)
target_link_libraries(bench_ondemand PRIVATE nlohmann_json)
endif()
endif()
endif()
if (TARGET competition-all)
add_executable(distinctuseridcompetition distinctuseridcompetition.cpp)
target_link_libraries(distinctuseridcompetition competition-core)
add_executable(minifiercompetition minifiercompetition.cpp)
target_link_libraries(minifiercompetition competition-core)
add_executable(parseandstatcompetition parseandstatcompetition.cpp)
target_link_libraries(parseandstatcompetition competition-core)
add_executable(parsingcompetition parsingcompetition.cpp)
target_link_libraries(parsingcompetition competition-core)
add_executable(allparsingcompetition parsingcompetition.cpp)
target_link_libraries(allparsingcompetition competition-all)
target_compile_definitions(allparsingcompetition PRIVATE ALLPARSER)
endif()
include(checkperf.cmake)
-19
View File
@@ -1,19 +0,0 @@
# From the ROOT, run:
# docker build -t simdjsonbench -f benchmark/Dockerfile . && docker run --privileged -t simdjsonbench
FROM gcc:8.3
# # Build latest
# ENV latest_release=v0.2.1
# WORKDIR /usr/src/$latest_release/
# RUN git clone --depth 1 https://github.com/lemire/simdjson/ -b $latest_release .
# RUN make parse
# # Build master
# WORKDIR /usr/src/master/
# RUN git clone --depth 1 https://github.com/lemire/simdjson/ .
# RUN make parse
# Build the current source
COPY . /usr/src/current/
WORKDIR /usr/src/current/
RUN make checkperf
@@ -0,0 +1,73 @@
#pragma once
#include "json_benchmark/file_runner.h"
#include <map>
#include <string>
namespace amazon_cellphones {
const bool UNTHREADED = false;
const bool THREADED = true;
using namespace json_benchmark;
struct brand {
double cumulative_rating;
uint64_t reviews_count;
simdjson_really_inline bool operator==(const brand &other) const {
return cumulative_rating == other.cumulative_rating &&
reviews_count == other.reviews_count;
}
simdjson_really_inline bool operator!=(const brand &other) const { return !(*this == other); }
};
simdjson_unused static std::ostream &operator<<(std::ostream &o, const brand &b) {
o << "cumulative_rating: " << b.cumulative_rating << std::endl;
o << "reviews_count: " << b.reviews_count << std::endl;
return o;
}
template<typename StringType>
simdjson_unused static std::ostream &operator<<(std::ostream &o, const std::pair<const StringType, brand> &p) {
o << "brand: " << p.first << std::endl;
o << p.second;
return o;
}
template<typename I>
struct runner : public file_runner<I> {
std::map<typename I::StringType, brand> result{};
bool setup(benchmark::State &state) {
return this->load_json(state, AMAZON_CELLPHONES_NDJSON);
}
bool before_run(benchmark::State &state) {
if (!file_runner<I>::before_run(state)) { return false; }
result.clear();
return true;
}
bool run(benchmark::State &) {
return this->implementation.run(this->json, result);
}
template<typename R>
bool diff(benchmark::State &state, runner<R> &reference) {
return diff_results(state, result, reference.result, diff_flags::NONE);
}
size_t items_per_iteration() {
return result.size();
}
};
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);
}
} // namespace amazon_cellphones
@@ -0,0 +1,51 @@
#pragma once
#if SIMDJSON_EXCEPTIONS
#include "amazon_cellphones.h"
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
for (;i != stream.end(); ++i) {
auto doc = *i;
StringType copy(std::string_view(doc.at(1)));
auto x = result.find(copy);
if (x == result.end()) { // If key not found, add new key
result.emplace(copy, amazon_cellphones::brand{
double(doc.at(5)) * uint64_t(doc.at(7)),
uint64_t(doc.at(7))
});
} else { // Otherwise, update key data
x->second.cumulative_rating += double(doc.at(5)) * uint64_t(doc.at(7));
x->second.reviews_count += uint64_t(doc.at(7));
}
}
return true;
}
};
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_dom<UNTHREADED>)->UseManualTime();
#ifdef SIMDJSON_THREADS_ENABLED
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_dom<THREADED>)->UseManualTime();
#endif
} // namespace amazon_cellphones
#endif // SIMDJSON_EXCEPTIONS
@@ -0,0 +1,72 @@
#pragma once
#if SIMDJSON_EXCEPTIONS
#include "amazon_cellphones.h"
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;
size_t index{0};
StringType copy;
double rating;
uint64_t reviews;
for ( auto value : doc ) {
switch (index)
{
case 1:
copy = StringType(std::string_view(value));
break;
case 5:
rating = double(value);
break;
case 7:
reviews = uint64_t(value);
break;
default:
break;
}
index++;
}
auto x = result.find(copy);
if (x == result.end()) { // If key not found, add new key
result.emplace(copy, amazon_cellphones::brand{
rating * reviews,
reviews
});
} else { // Otherwise, update key data
x->second.cumulative_rating += rating * reviews;
x->second.reviews_count += reviews;
}
}
return true;
}
};
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_ondemand<UNTHREADED>)->UseManualTime();
#ifdef SIMDJSON_THREADS_ENABLED
BENCHMARK_TEMPLATE(amazon_cellphones, simdjson_ondemand<THREADED>)->UseManualTime();
#endif
} // namespace amazon_cellphones
#endif // SIMDJSON_EXCEPTIONS
+234 -40
View File
@@ -1,4 +1,5 @@
#include <benchmark/benchmark.h>
#include <iostream>
#include "simdjson.h"
#include <sstream>
@@ -8,9 +9,189 @@ using namespace std;
const padded_string EMPTY_ARRAY("[]", 2);
const char *TWITTER_JSON = SIMDJSON_BENCHMARK_DATA_DIR "twitter.json";
const char *NUMBERS_JSON = SIMDJSON_BENCHMARK_DATA_DIR "numbers.json";
static const char *TWITTER_JSON = SIMDJSON_BENCHMARK_DATA_DIR "twitter.json";
static const char *NUMBERS_JSON = SIMDJSON_BENCHMARK_DATA_DIR "numbers.json";
static void recover_one_string(State& state) {
dom::parser parser;
const std::string_view data = "\"one string\"";
padded_string docdata{data};
// we do not want mem. alloc. in the loop.
auto error = parser.allocate(docdata.size());
if(error) {
cout << error << endl;
return;
}
dom::element doc;
if ((error = parser.parse(docdata).get(doc))) {
cerr << "could not parse string" << error << endl;
return;
}
for (simdjson_unused auto _ : state) {
std::string_view v;
error = doc.get(v);
if (error) {
cerr << "could not get string" << error << endl;
return;
}
benchmark::DoNotOptimize(v);
}
}
BENCHMARK(recover_one_string);
static void serialize_twitter(State& state) {
dom::parser parser;
padded_string docdata;
auto error = padded_string::load(TWITTER_JSON).get(docdata);
if(error) {
cerr << "could not parse twitter.json" << error << endl;
return;
}
// we do not want mem. alloc. in the loop.
if((error = parser.allocate(docdata.size()))) {
cout << error << endl;
return;
}
dom::element doc;
if ((error = parser.parse(docdata).get(doc))) {
cerr << "could not parse twitter.json" << error << endl;
return;
}
size_t bytes = 0;
for (simdjson_unused auto _ : state) {
std::string serial = simdjson::minify(doc);
bytes += serial.size();
benchmark::DoNotOptimize(serial);
}
// we validate the result
{
auto serial = simdjson::minify(doc);
dom::element doc2; // we parse the minified output
if ((error = parser.parse(serial).get(doc2))) { throw std::runtime_error("serialization error"); }
auto serial2 = simdjson::minify(doc2); // we minify a second time
if(serial != serial2) { throw std::runtime_error("serialization mismatch"); }
}
// Gigabyte: https://en.wikipedia.org/wiki/Gigabyte
state.counters["Gigabytes"] = benchmark::Counter(
double(bytes), benchmark::Counter::kIsRate,
benchmark::Counter::OneK::kIs1000); // For GiB : kIs1024
state.counters["docs"] = Counter(double(state.iterations()), benchmark::Counter::kIsRate);
}
BENCHMARK(serialize_twitter)->ComputeStatistics("max", [](const std::vector<double>& v) -> double {
return *(std::max_element(std::begin(v), std::end(v)));
})->DisplayAggregatesOnly(true);
static void serialize_big_string_to_string(State& state) {
dom::parser parser;
std::vector<char> content;
content.push_back('\"');
for(size_t i = 0 ; i < 100000; i ++) {
content.push_back('0' + char(i%10)); // we add what looks like a long list of digits
}
content.push_back('\"');
dom::element doc;
simdjson::error_code error;
if ((error = parser.parse(content.data(), content.size()).get(doc))) {
cerr << "could not parse big string" << error << endl;
return;
}
size_t bytes = 0;
for (simdjson_unused auto _ : state) {
auto serial = simdjson::to_string(doc);
bytes += serial.size();
benchmark::DoNotOptimize(serial);
}
// Gigabyte: https://en.wikipedia.org/wiki/Gigabyte
state.counters["Gigabytes"] = benchmark::Counter(
double(bytes), benchmark::Counter::kIsRate,
benchmark::Counter::OneK::kIs1000); // For GiB : kIs1024
state.counters["docs"] = Counter(double(state.iterations()), benchmark::Counter::kIsRate);
}
BENCHMARK(serialize_big_string_to_string)->ComputeStatistics("max", [](const std::vector<double>& v) -> double {
return *(std::max_element(std::begin(v), std::end(v)));
})->DisplayAggregatesOnly(true);
static void serialize_twitter_to_string(State& state) {
dom::parser parser;
padded_string docdata;
auto error = padded_string::load(TWITTER_JSON).get(docdata);
if(error) {
cerr << "could not parse twitter.json" << error << endl;
return;
}
// we do not want mem. alloc. in the loop.
if((error = parser.allocate(docdata.size()))) {
cout << error << endl;
return;
}
dom::element doc;
if ((error = parser.parse(docdata).get(doc))) {
cerr << "could not parse twitter.json" << error << endl;
return;
}
size_t bytes = 0;
for (simdjson_unused auto _ : state) {
auto serial = simdjson::to_string(doc);
bytes += serial.size();
benchmark::DoNotOptimize(serial);
}
// we validate the result
{
auto serial = simdjson::to_string(doc);
dom::element doc2; // we parse the stringify output
if ((error = parser.parse(serial).get(doc2))) { throw std::runtime_error("serialization error"); }
auto serial2 = simdjson::to_string(doc2); // we stringify again
if(serial != serial2) { throw std::runtime_error("serialization mismatch"); }
}
// Gigabyte: https://en.wikipedia.org/wiki/Gigabyte
state.counters["Gigabytes"] = benchmark::Counter(
double(bytes), benchmark::Counter::kIsRate,
benchmark::Counter::OneK::kIs1000); // For GiB : kIs1024
state.counters["docs"] = Counter(double(state.iterations()), benchmark::Counter::kIsRate);
}
BENCHMARK(serialize_twitter_to_string)->ComputeStatistics("max", [](const std::vector<double>& v) -> double {
return *(std::max_element(std::begin(v), std::end(v)));
})->DisplayAggregatesOnly(true);
static void serialize_twitter_string_builder(State& state) {
dom::parser parser;
padded_string docdata;
auto error = padded_string::load(TWITTER_JSON).get(docdata);
if(error) {
cerr << "could not parse twitter.json" << error << endl;
return;
}
// we do not want mem. alloc. in the loop.
if((error = parser.allocate(docdata.size()))) {
cout << error << endl;
return;
}
dom::element doc;
if ((error = parser.parse(docdata).get(doc))) {
cerr << "could not parse twitter.json" << error << endl;
return;
}
size_t bytes = 0;
simdjson::internal::string_builder<> sb;// not part of our public API, for internal use
for (simdjson_unused auto _ : state) {
sb.clear();
sb.append(doc);
std::string_view serial = sb.str();
bytes += serial.size();
benchmark::DoNotOptimize(serial);
}
// Gigabyte: https://en.wikipedia.org/wiki/Gigabyte
state.counters["Gigabytes"] = benchmark::Counter(
double(bytes), benchmark::Counter::kIsRate,
benchmark::Counter::OneK::kIs1000); // For GiB : kIs1024
state.counters["docs"] = Counter(double(state.iterations()), benchmark::Counter::kIsRate);
}
BENCHMARK(serialize_twitter_string_builder)->ComputeStatistics("max", [](const std::vector<double>& v) -> double {
return *(std::max_element(std::begin(v), std::end(v)));
})->DisplayAggregatesOnly(true);
static void numbers_scan(State& state) {
@@ -22,7 +203,7 @@ static void numbers_scan(State& state) {
cerr << "could not read " << NUMBERS_JSON << " as an array: " << error << endl;
return;
}
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
std::vector<double> container;
for (auto e : arr) {
double x;
@@ -31,7 +212,7 @@ static void numbers_scan(State& state) {
}
benchmark::DoNotOptimize(container.data());
benchmark::ClobberMemory();
}
}
}
BENCHMARK(numbers_scan);
@@ -44,7 +225,7 @@ static void numbers_size_scan(State& state) {
cerr << "could not read " << NUMBERS_JSON << " as an array: " << error << endl;
return;
}
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
std::vector<double> container;
container.resize(arr.size());
size_t pos = 0;
@@ -56,7 +237,7 @@ static void numbers_size_scan(State& state) {
if(pos != container.size()) { cerr << "bad count" << endl; }
benchmark::DoNotOptimize(container.data());
benchmark::ClobberMemory();
}
}
}
BENCHMARK(numbers_size_scan);
@@ -70,7 +251,7 @@ static void numbers_type_scan(State& state) {
cerr << "could not read " << NUMBERS_JSON << " as an array" << endl;
return;
}
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
std::vector<double> container;
for (auto e : arr) {
dom::element_type actual_type = e.type();
@@ -96,7 +277,7 @@ static void numbers_type_size_scan(State& state) {
cerr << "could not read " << NUMBERS_JSON << " as an array: " << error << endl;
return;
}
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
std::vector<double> container;
container.resize(arr.size());
size_t pos = 0;
@@ -121,7 +302,7 @@ static void numbers_load_scan(State& state) {
dom::parser parser;
dom::array arr;
simdjson::error_code error;
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
// this may hit the disk, but probably just once
if ((error = parser.load(NUMBERS_JSON).get(arr))) {
cerr << "could not read " << NUMBERS_JSON << " as an array: " << error << endl;
@@ -135,7 +316,7 @@ static void numbers_load_scan(State& state) {
}
benchmark::DoNotOptimize(container.data());
benchmark::ClobberMemory();
}
}
}
BENCHMARK(numbers_load_scan);
@@ -144,7 +325,7 @@ static void numbers_load_size_scan(State& state) {
dom::parser parser;
dom::array arr;
simdjson::error_code error;
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
// this may hit the disk, but probably just once
if ((error = parser.load(NUMBERS_JSON).get(arr))) {
cerr << "could not read " << NUMBERS_JSON << " as an array" << endl;
@@ -161,7 +342,7 @@ static void numbers_load_size_scan(State& state) {
if(pos != container.size()) { cerr << "bad count" << endl; }
benchmark::DoNotOptimize(container.data());
benchmark::ClobberMemory();
}
}
}
BENCHMARK(numbers_load_size_scan);
@@ -173,14 +354,14 @@ static void numbers_exceptions_scan(State& state) {
// Prints the number of results in twitter.json
dom::parser parser;
dom::array arr = parser.load(NUMBERS_JSON);
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
std::vector<double> container;
for (double x : arr) {
container.push_back(x);
}
benchmark::DoNotOptimize(container.data());
benchmark::ClobberMemory();
}
}
}
BENCHMARK(numbers_exceptions_scan);
@@ -188,7 +369,7 @@ static void numbers_exceptions_size_scan(State& state) {
// Prints the number of results in twitter.json
dom::parser parser;
dom::array arr = parser.load(NUMBERS_JSON);
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
std::vector<double> container;
container.resize(arr.size());
size_t pos = 0;
@@ -198,7 +379,7 @@ static void numbers_exceptions_size_scan(State& state) {
if(pos != container.size()) { cerr << "bad count" << endl; }
benchmark::DoNotOptimize(container.data());
benchmark::ClobberMemory();
}
}
}
BENCHMARK(numbers_exceptions_size_scan);
@@ -208,7 +389,7 @@ static void numbers_type_exceptions_scan(State& state) {
// Prints the number of results in twitter.json
dom::parser parser;
dom::array arr = parser.load(NUMBERS_JSON);
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
std::vector<double> container;
for (auto e : arr) {
dom::element_type actual_type = e.type();
@@ -227,7 +408,7 @@ static void numbers_type_exceptions_size_scan(State& state) {
// Prints the number of results in twitter.json
dom::parser parser;
dom::array arr = parser.load(NUMBERS_JSON);
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
std::vector<double> container;
container.resize(arr.size());
size_t pos = 0;
@@ -248,7 +429,7 @@ BENCHMARK(numbers_type_exceptions_size_scan);
static void numbers_exceptions_load_scan(State& state) {
// Prints the number of results in twitter.json
dom::parser parser;
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
// this may hit the disk, but probably just once
dom::array arr = parser.load(NUMBERS_JSON);
std::vector<double> container;
@@ -257,14 +438,14 @@ static void numbers_exceptions_load_scan(State& state) {
}
benchmark::DoNotOptimize(container.data());
benchmark::ClobberMemory();
}
}
}
BENCHMARK(numbers_exceptions_load_scan);
static void numbers_exceptions_load_size_scan(State& state) {
// Prints the number of results in twitter.json
dom::parser parser;
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
// this may hit the disk, but probably just once
dom::array arr = parser.load(NUMBERS_JSON);
std::vector<double> container;
@@ -276,7 +457,7 @@ static void numbers_exceptions_load_size_scan(State& state) {
if(pos != container.size()) { cerr << "bad count" << endl; }
benchmark::DoNotOptimize(container.data());
benchmark::ClobberMemory();
}
}
}
BENCHMARK(numbers_exceptions_load_size_scan);
@@ -285,20 +466,21 @@ static void twitter_count(State& state) {
// Prints the number of results in twitter.json
dom::parser parser;
dom::element doc = parser.load(TWITTER_JSON);
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
uint64_t result_count = doc["search_metadata"]["count"];
if (result_count != 100) { return; }
}
}
BENCHMARK(twitter_count);
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_DEPRECATED_WARNING
static void iterator_twitter_count(State& state) {
// Prints the number of results in twitter.json
padded_string json = padded_string::load(TWITTER_JSON);
ParsedJson pj = build_parsed_json(json);
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
ParsedJson::Iterator iter(pj);
// uint64_t result_count = doc["search_metadata"]["count"];
if (!iter.move_to_key("search_metadata")) { return; }
@@ -311,17 +493,18 @@ static void iterator_twitter_count(State& state) {
}
BENCHMARK(iterator_twitter_count);
SIMDJSON_POP_DISABLE_WARNINGS
#endif // SIMDJSON_DISABLE_DEPRECATED_API
static void twitter_default_profile(State& state) {
// Count unique users with a default profile.
dom::parser parser;
dom::element doc = parser.load(TWITTER_JSON);
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
set<string_view> default_users;
for (dom::object tweet : doc["statuses"]) {
dom::object user = tweet["user"];
if (user["default_profile"]) {
default_users.insert(user["screen_name"]);
default_users.emplace(user["screen_name"]);
}
}
if (default_users.size() != 86) { return; }
@@ -334,14 +517,14 @@ static void twitter_image_sizes(State& state) {
dom::parser parser;
dom::element doc = parser.load(TWITTER_JSON);
simdjson::error_code error;
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
set<tuple<uint64_t, uint64_t>> image_sizes;
for (dom::object tweet : doc["statuses"]) {
dom::array media;
if (not (error = tweet["entities"]["media"].get(media))) {
for (dom::object image : media) {
for (auto size : image["sizes"].get<dom::object>()) {
image_sizes.insert({ size.value["w"], size.value["h"] });
for (auto size : image["sizes"].get_object()) {
image_sizes.emplace(size.value["w"], size.value["h"]);
}
}
}
@@ -359,7 +542,7 @@ static void error_code_twitter_count(State& state) noexcept {
simdjson::error_code error;
dom::element doc;
if ((error = parser.load(TWITTER_JSON).get(doc))) { return; }
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
uint64_t value;
if ((error = doc["search_metadata"]["count"].get(value))) { return; }
if (value != 100) { return; }
@@ -373,7 +556,7 @@ static void error_code_twitter_default_profile(State& state) noexcept {
simdjson::error_code error;
dom::element doc;
if ((error = parser.load(TWITTER_JSON).get(doc))) { std::cerr << error << std::endl; return; }
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
set<string_view> default_users;
dom::array tweets;
@@ -395,15 +578,18 @@ static void error_code_twitter_default_profile(State& state) noexcept {
}
BENCHMARK(error_code_twitter_default_profile);
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_DEPRECATED_WARNING
static void iterator_twitter_default_profile(State& state) {
// Count unique users with a default profile.
padded_string json;
auto error = padded_string::load(TWITTER_JSON).get(json);
if (error) { std::cerr << error << std::endl; return; }
ParsedJson pj = build_parsed_json(json);
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
set<string_view> default_users;
ParsedJson::Iterator iter(pj);
@@ -422,7 +608,7 @@ static void iterator_twitter_default_profile(State& state) {
// default_users.insert(user["screen_name"]);
if (!(iter.move_to_key("screen_name") && iter.is_string())) { return; }
default_users.insert(string_view(iter.get_string(), iter.get_string_length()));
default_users.emplace(iter.get_string(), iter.get_string_length());
}
if (!iter.up()) { return; } // back to user
}
@@ -435,8 +621,10 @@ static void iterator_twitter_default_profile(State& state) {
if (default_users.size() != 86) { return; }
}
}
SIMDJSON_POP_DISABLE_WARNINGS
BENCHMARK(iterator_twitter_default_profile);
#endif // SIMDJSON_DISABLE_DEPRECATED_API
static void error_code_twitter_image_sizes(State& state) noexcept {
// Count unique image sizes
@@ -444,7 +632,7 @@ static void error_code_twitter_image_sizes(State& state) noexcept {
simdjson::error_code error;
dom::element doc;
if ((error = parser.load(TWITTER_JSON).get(doc))) { std::cerr << error << std::endl; return; }
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
set<tuple<uint64_t, uint64_t>> image_sizes;
dom::array statuses;
if ((error = doc["statuses"].get(statuses))) { return; }
@@ -458,7 +646,7 @@ static void error_code_twitter_image_sizes(State& state) noexcept {
uint64_t width, height;
if ((error = size.value["w"].get(width))) { return; }
if ((error = size.value["h"].get(height))) { return; }
image_sizes.insert({ width, height });
image_sizes.emplace(width, height);
}
}
}
@@ -468,6 +656,8 @@ static void error_code_twitter_image_sizes(State& state) noexcept {
}
BENCHMARK(error_code_twitter_image_sizes);
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_DEPRECATED_WARNING
static void iterator_twitter_image_sizes(State& state) {
@@ -476,7 +666,7 @@ static void iterator_twitter_image_sizes(State& state) {
auto error = padded_string::load(TWITTER_JSON).get(json);
if (error) { std::cerr << error << std::endl; return; }
ParsedJson pj = build_parsed_json(json);
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
set<tuple<uint64_t, uint64_t>> image_sizes;
ParsedJson::Iterator iter(pj);
@@ -510,7 +700,7 @@ static void iterator_twitter_image_sizes(State& state) {
if (!(iter.move_to_key("h")) && !iter.is_integer()) { return; }
uint64_t height = iter.get_integer();
if (!iter.up()) { return; } // back to size
image_sizes.insert({ width, height });
image_sizes.emplace(width, height);
} while (iter.next()); // next size
if (!iter.up()) { return; } // back to sizes
@@ -522,7 +712,7 @@ static void iterator_twitter_image_sizes(State& state) {
if (!iter.up()) { return; } // back to entities
}
if (!iter.up()) { return; } // back to status
}
}
} while (iter.next()); // next status
}
@@ -531,6 +721,9 @@ static void iterator_twitter_image_sizes(State& state) {
}
BENCHMARK(iterator_twitter_image_sizes);
#endif // SIMDJSON_DISABLE_DEPRECATED_API
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
static void print_json(State& state) noexcept {
// Prints the number of results in twitter.json
dom::parser parser;
@@ -541,12 +734,13 @@ static void print_json(State& state) noexcept {
int code = json_parse(json, parser);
if (code) { cerr << error_message(code) << endl; return; }
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
std::stringstream s;
if (!parser.print_json(s)) { cerr << "print_json failed" << endl; return; }
}
}
BENCHMARK(print_json);
#endif // SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_POP_DISABLE_WARNINGS
BENCHMARK_MAIN();
BENCHMARK_MAIN();
+92
View File
@@ -0,0 +1,92 @@
#include "simdjson.h"
SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
#ifdef SIMDJSON_COMPETITION_YYJSON
#include "yyjson.h"
#endif
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
#include "rapidjson/document.h"
#include "rapidjson/reader.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
#endif
#ifdef SIMDJSON_COMPETITION_SAJSON
#include "sajson.h"
#endif
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
#include <nlohmann/json.hpp>
#endif
// This has to be last, for reasons I don't yet understand
#include <benchmark/benchmark.h>
SIMDJSON_POP_DISABLE_WARNINGS
#include "amazon_cellphones/simdjson_dom.h"
#include "amazon_cellphones/simdjson_ondemand.h"
#include "large_amazon_cellphones/simdjson_dom.h"
#include "large_amazon_cellphones/simdjson_ondemand.h"
#include "partial_tweets/simdjson_dom.h"
#include "partial_tweets/simdjson_ondemand.h"
#include "partial_tweets/yyjson.h"
#include "partial_tweets/sajson.h"
#include "partial_tweets/rapidjson.h"
#include "partial_tweets/rapidjson_sax.h"
#include "partial_tweets/nlohmann_json.h"
#include "partial_tweets/nlohmann_json_sax.h"
#include "large_random/simdjson_dom.h"
#include "large_random/simdjson_ondemand.h"
#include "large_random/simdjson_ondemand_unordered.h"
#include "large_random/yyjson.h"
#include "large_random/sajson.h"
#include "large_random/rapidjson.h"
#include "large_random/rapidjson_sax.h"
#include "large_random/nlohmann_json.h"
#include "large_random/nlohmann_json_sax.h"
#include "kostya/simdjson_dom.h"
#include "kostya/simdjson_ondemand.h"
#include "kostya/yyjson.h"
#include "kostya/sajson.h"
#include "kostya/rapidjson.h"
#include "kostya/rapidjson_sax.h"
#include "kostya/nlohmann_json.h"
#include "kostya/nlohmann_json_sax.h"
#include "distinct_user_id/simdjson_dom.h"
#include "distinct_user_id/simdjson_dom_json_pointer.h"
#include "distinct_user_id/simdjson_ondemand.h"
#include "distinct_user_id/simdjson_ondemand_json_pointer.h"
#include "distinct_user_id/yyjson.h"
#include "distinct_user_id/sajson.h"
#include "distinct_user_id/rapidjson.h"
#include "distinct_user_id/rapidjson_sax.h"
#include "distinct_user_id/nlohmann_json.h"
#include "distinct_user_id/nlohmann_json_sax.h"
#include "find_tweet/simdjson_dom.h"
#include "find_tweet/simdjson_ondemand.h"
#include "find_tweet/yyjson.h"
#include "find_tweet/sajson.h"
#include "find_tweet/rapidjson.h"
#include "find_tweet/rapidjson_sax.h"
#include "find_tweet/nlohmann_json.h"
#include "find_tweet/nlohmann_json_sax.h"
#include "top_tweet/simdjson_dom.h"
#include "top_tweet/simdjson_ondemand.h"
#include "top_tweet/yyjson.h"
#include "top_tweet/sajson.h"
#include "top_tweet/rapidjson.h"
#include "top_tweet/rapidjson_sax.h"
#include "top_tweet/nlohmann_json.h"
#include "top_tweet/nlohmann_json_sax.h"
BENCHMARK_MAIN();
+105 -11
View File
@@ -1,4 +1,5 @@
#include <benchmark/benchmark.h>
#include <iostream>
#include "simdjson.h"
using namespace simdjson;
using namespace benchmark;
@@ -10,6 +11,94 @@ const char *GSOC_JSON = SIMDJSON_BENCHMARK_DATA_DIR "gsoc-2018.json";
static void fast_minify_twitter(State& state) {
dom::parser parser;
padded_string docdata;
auto error = padded_string::load(TWITTER_JSON).get(docdata);
if(error) {
cerr << "could not parse twitter.json" << error << endl;
return;
}
std::unique_ptr<char[]> buffer{new char[docdata.size()]};
size_t bytes = 0;
for (simdjson_unused auto _ : state) {
size_t new_length{}; // It will receive the minified length.
auto error = simdjson::minify(docdata.data(), docdata.size(), buffer.get(), new_length);
bytes += docdata.size();
benchmark::DoNotOptimize(error);
}
// Gigabyte: https://en.wikipedia.org/wiki/Gigabyte
state.counters["Gigabytes"] = benchmark::Counter(
double(bytes), benchmark::Counter::kIsRate,
benchmark::Counter::OneK::kIs1000); // For GiB : kIs1024
state.counters["docs"] = Counter(double(state.iterations()), benchmark::Counter::kIsRate);
}
BENCHMARK(fast_minify_twitter)->Repetitions(10)->ComputeStatistics("max", [](const std::vector<double>& v) -> double {
return *(std::max_element(std::begin(v), std::end(v)));
})->DisplayAggregatesOnly(true);
static void fast_minify_gsoc(State& state) {
dom::parser parser;
padded_string docdata;
auto error = padded_string::load(GSOC_JSON).get(docdata);
if(error) {
cerr << "could not parse gsoc-2018.json" << error << endl;
return;
}
std::unique_ptr<char[]> buffer{new char[docdata.size()]};
size_t bytes = 0;
for (simdjson_unused auto _ : state) {
size_t new_length{}; // It will receive the minified length.
auto error = simdjson::minify(docdata.data(), docdata.size(), buffer.get(), new_length);
bytes += docdata.size();
benchmark::DoNotOptimize(error);
}
// Gigabyte: https://en.wikipedia.org/wiki/Gigabyte
state.counters["Gigabytes"] = benchmark::Counter(
double(bytes), benchmark::Counter::kIsRate,
benchmark::Counter::OneK::kIs1000); // For GiB : kIs1024
state.counters["docs"] = Counter(double(state.iterations()), benchmark::Counter::kIsRate);
}
BENCHMARK(fast_minify_gsoc)->Repetitions(10)->ComputeStatistics("max", [](const std::vector<double>& v) -> double {
return *(std::max_element(std::begin(v), std::end(v)));
})->DisplayAggregatesOnly(true);
static void unicode_validate_twitter(State& state) {
dom::parser parser;
padded_string docdata;
auto error = padded_string::load(TWITTER_JSON).get(docdata);
if(error) {
cerr << "could not parse twitter.json" << error << endl;
return;
}
// we do not want mem. alloc. in the loop.
error = parser.allocate(docdata.size());
if(error) {
cout << error << endl;
return;
}
size_t bytes = 0;
for (simdjson_unused auto _ : state) {
bool is_ok = simdjson::validate_utf8(docdata.data(), docdata.size());
bytes += docdata.size();
benchmark::DoNotOptimize(is_ok);
}
// Gigabyte: https://en.wikipedia.org/wiki/Gigabyte
state.counters["Gigabytes"] = benchmark::Counter(
double(bytes), benchmark::Counter::kIsRate,
benchmark::Counter::OneK::kIs1000); // For GiB : kIs1024
state.counters["docs"] = Counter(double(state.iterations()), benchmark::Counter::kIsRate);
}
BENCHMARK(unicode_validate_twitter)->Repetitions(10)->ComputeStatistics("max", [](const std::vector<double>& v) -> double {
return *(std::max_element(std::begin(v), std::end(v)));
})->DisplayAggregatesOnly(true);
static void parse_twitter(State& state) {
dom::parser parser;
padded_string docdata;
@@ -25,10 +114,9 @@ static void parse_twitter(State& state) {
return;
}
size_t bytes = 0;
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
dom::element doc;
bytes += docdata.size();
;
if ((error = parser.parse(docdata).get(doc))) {
cerr << "could not parse twitter.json" << error << endl;
return;
@@ -61,7 +149,7 @@ static void parse_gsoc(State& state) {
return;
}
size_t bytes = 0;
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
bytes += docdata.size();
dom::element doc;
if ((error = parser.parse(docdata).get(doc))) {
@@ -82,22 +170,25 @@ BENCHMARK(parse_gsoc)->Repetitions(10)->ComputeStatistics("max", [](const std::v
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_DEPRECATED_WARNING
static void json_parse(State& state) {
ParsedJson pj;
if (!pj.allocate_capacity(EMPTY_ARRAY.length())) { return; }
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
auto error = json_parse(EMPTY_ARRAY, pj);
if (error) { return; }
}
}
SIMDJSON_POP_DISABLE_WARNINGS
BENCHMARK(json_parse);
#endif // SIMDJSON_DISABLE_DEPRECATED_API
static void parser_parse_error_code(State& state) {
dom::parser parser;
if (parser.allocate(EMPTY_ARRAY.length())) { return; }
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
auto error = parser.parse(EMPTY_ARRAY).error();
if (error) { return; }
}
@@ -109,9 +200,9 @@ BENCHMARK(parser_parse_error_code);
static void parser_parse_exception(State& state) {
dom::parser parser;
if (parser.allocate(EMPTY_ARRAY.length())) { return; }
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
try {
UNUSED dom::element doc = parser.parse(EMPTY_ARRAY);
simdjson_unused dom::element doc = parser.parse(EMPTY_ARRAY);
} catch(simdjson_error &j) {
cout << j.what() << endl;
return;
@@ -122,10 +213,11 @@ BENCHMARK(parser_parse_exception);
#endif // SIMDJSON_EXCEPTIONS
#ifndef SIMDJSON_DISABLE_DEPRECATED_API
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_DEPRECATED_WARNING
static void build_parsed_json(State& state) {
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
dom::parser parser = simdjson::build_parsed_json(EMPTY_ARRAY);
if (!parser.valid) { return; }
}
@@ -133,8 +225,10 @@ static void build_parsed_json(State& state) {
SIMDJSON_POP_DISABLE_WARNINGS
BENCHMARK(build_parsed_json);
#endif
static void document_parse_error_code(State& state) {
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
dom::parser parser;
auto error = parser.parse(EMPTY_ARRAY).error();
if (error) { return; }
@@ -145,10 +239,10 @@ BENCHMARK(document_parse_error_code);
#if SIMDJSON_EXCEPTIONS
static void document_parse_exception(State& state) {
for (UNUSED auto _ : state) {
for (simdjson_unused auto _ : state) {
try {
dom::parser parser;
UNUSED dom::element doc = parser.parse(EMPTY_ARRAY);
simdjson_unused dom::element doc = parser.parse(EMPTY_ARRAY);
} catch(simdjson_error &j) {
cout << j.what() << endl;
return;
+11 -5
View File
@@ -63,8 +63,8 @@ void print_usage(ostream& out) {
out << "-s STAGE - Stop after the given stage." << endl;
out << " -s stage1 - Stop after find_structural_bits." << endl;
out << " -s all - Run all stages." << endl;
out << "-a ARCH - Use the parser with the designated architecture (HASWELL, WESTMERE" << endl;
out << " or ARM64). By default, detects best supported architecture." << endl;
out << "-a ARCH - Use the parser with the designated architecture (HASWELL, WESTMERE," << endl;
out << " PPC64 or ARM64). By default, detects best supported architecture." << endl;
}
void exit_usage(string message) {
@@ -96,8 +96,14 @@ struct option_struct {
case 'v':
verbose = true;
break;
case 'a':
simdjson::active_implementation = simdjson::available_implementations[optarg];
case 'a': {
auto impl = simdjson::get_available_implementations()[optarg];
if(impl && impl->supported_by_runtime_system()) {
simdjson::get_active_implementation() = impl;
} else {
std::cerr << "implementation " << optarg << " not found or not supported " << std::endl;
}
}
break;
case 's':
if (!strcmp(optarg, "stage1")) {
@@ -158,7 +164,7 @@ struct feature_benchmarker {
}
really_inline void run_iterations(size_t iterations, bool stage1_only=false) {
simdjson_really_inline void run_iterations(size_t iterations, bool stage1_only=false) {
struct7.run_iterations(iterations, stage1_only);
struct7_miss.run_iterations(iterations, stage1_only);
struct7_full.run_iterations(iterations, stage1_only);
+37 -34
View File
@@ -12,9 +12,9 @@
#define BEST_TIME(name, test, expected, pre, repeat, size, verbose) \
do { \
if (verbose) \
printf("%-40s\t: ", name); \
std::printf("%-40s\t: ", name); \
else \
printf("\"%-40s\"", name); \
std::printf("\"%-40s\"", name); \
fflush(NULL); \
event_collector collector; \
event_aggregate aggregate{}; \
@@ -23,48 +23,50 @@
std::atomic_thread_fence(std::memory_order_acquire); \
collector.start(); \
if (test != expected) { \
fprintf(stderr, "not expected (%d , %d )", (int)test, (int)expected); \
std::fprintf(stderr, "not expected (%d , %d )", (int)test, \
(int)expected); \
break; \
} \
std::atomic_thread_fence(std::memory_order_release); \
event_count allocate_count = collector.end(); \
aggregate << allocate_count; \
} \
uint64_t S = size; \
if (collector.has_events()) { \
printf("%7.3f", aggregate.best.cycles() / static_cast<double>(size)); \
std::printf("%7.3f", \
aggregate.best.cycles() / static_cast<double>(size)); \
if (verbose) { \
printf(" cycles/byte "); \
std::printf(" cycles/byte "); \
} \
printf("\t"); \
printf("%7.3f", \
aggregate.best.instructions() / static_cast<double>(size)); \
std::printf("\t"); \
std::printf("%7.3f", \
aggregate.best.instructions() / static_cast<double>(size)); \
if (verbose) { \
printf(" instructions/byte "); \
std::printf(" instructions/byte "); \
} \
printf("\t"); \
std::printf("\t"); \
} \
double gb = static_cast<double>(size) / 1000000000.0; \
printf("%7.3f", gb / aggregate.best.elapsed_sec()); \
std::printf("%7.3f", gb / aggregate.best.elapsed_sec()); \
if (verbose) { \
printf(" GB/s "); \
std::printf(" GB/s "); \
} \
printf("%7.3f", 1.0 / aggregate.best.elapsed_sec()); \
std::printf("\t"); \
std::printf("%7.3f", 1.0 / aggregate.best.elapsed_sec()); \
if (verbose) { \
printf(" documents/s "); \
std::printf(" documents/s "); \
} \
printf("\n"); \
fflush(NULL); \
std::printf("\n"); \
std::fflush(NULL); \
} while (0)
// like BEST_TIME, but no check
#define BEST_TIME_NOCHECK(name, test, pre, repeat, size, verbose) \
do { \
if (verbose) \
printf("%-40s\t: ", name); \
std::printf("%-40s\t: ", name); \
else \
printf("\"%-40s\"", name); \
fflush(NULL); \
std::printf("\"%-40s\"", name); \
std::fflush(NULL); \
event_collector collector; \
event_aggregate aggregate{}; \
for (decltype(repeat) i = 0; i < repeat; i++) { \
@@ -76,31 +78,32 @@
event_count allocate_count = collector.end(); \
aggregate << allocate_count; \
} \
uint64_t S = size; \
if (collector.has_events()) { \
printf("%7.3f", aggregate.best.cycles() / static_cast<double>(size)); \
std::printf("%7.3f", \
aggregate.best.cycles() / static_cast<double>(size)); \
if (verbose) { \
printf(" cycles/byte "); \
std::printf(" cycles/byte "); \
} \
printf("\t"); \
printf("%7.3f", \
aggregate.best.instructions() / static_cast<double>(size)); \
std::printf("\t"); \
std::printf("%7.3f", \
aggregate.best.instructions() / static_cast<double>(size)); \
if (verbose) { \
printf(" instructions/byte "); \
std::printf(" instructions/byte "); \
} \
printf("\t"); \
std::printf("\t"); \
} \
double gb = static_cast<double>(size) / 1000000000.0; \
printf("%7.3f", gb / aggregate.best.elapsed_sec()); \
std::printf("%7.3f", gb / aggregate.best.elapsed_sec()); \
if (verbose) { \
printf(" GB/s "); \
std::printf(" GB/s "); \
} \
printf("%7.3f", 1.0 / aggregate.best.elapsed_sec()); \
std::printf("\t"); \
std::printf("%7.3f", 1.0 / aggregate.best.elapsed_sec()); \
if (verbose) { \
printf(" documents/s "); \
std::printf(" documents/s "); \
} \
printf("\n"); \
fflush(NULL); \
std::printf("\n"); \
std::fflush(NULL); \
} while (0)
#endif
+44 -33
View File
@@ -2,7 +2,7 @@
#define __BENCHMARKER_H
#include "event_counter.h"
#include "simdjson.h" // For SIMDJSON_DISABLE_DEPRECATED_WARNINGS
#include "simdjson.h"
#include <cassert>
#include <cctype>
@@ -225,8 +225,19 @@ struct progress_bar {
}
};
/**
* The speed at which we can allocate memory is strictly system specific.
* It depends on the OS and the runtime library. It is subject to various
* system-specific knobs. It is not something that we can reasonably
* benchmark with crude timings.
* If someone wants to optimize how simdjson allocate memory, then it will
* almost surely require a distinct benchmarking tool. What is meant by
* "memory allocation" also requires a definition. Doing "new char[size]" can
* do many different things depending on the system.
*/
enum class BenchmarkStage {
ALL,
ALL, // This excludes allocation
ALLOCATE,
STAGE1,
STAGE2
@@ -234,7 +245,7 @@ enum class BenchmarkStage {
const char* benchmark_stage_name(BenchmarkStage stage) {
switch (stage) {
case BenchmarkStage::ALL: return "All";
case BenchmarkStage::ALL: return "All (Without Allocation)";
case BenchmarkStage::ALLOCATE: return "Allocate";
case BenchmarkStage::STAGE1: return "Stage 1";
case BenchmarkStage::STAGE2: return "Stage 2";
@@ -253,8 +264,8 @@ struct benchmarker {
// Statistics about the JSON file independent of its speed (amount of utf-8, structurals, etc.).
// Loaded on first parse.
json_stats* stats;
// Speed and event summary for full parse (including allocation, stage 1 and stage 2)
event_aggregate all_stages{};
// Speed and event summary for full parse (stage 1 and stage 2, but *excluding* allocation)
event_aggregate all_stages_without_allocation{};
// Speed and event summary for stage 1
event_aggregate stage1{};
// Speed and event summary for stage 2
@@ -285,31 +296,32 @@ struct benchmarker {
const event_aggregate& operator[](BenchmarkStage stage) const {
switch (stage) {
case BenchmarkStage::ALL: return this->all_stages;
case BenchmarkStage::ALL: return this->all_stages_without_allocation;
case BenchmarkStage::STAGE1: return this->stage1;
case BenchmarkStage::STAGE2: return this->stage2;
case BenchmarkStage::ALLOCATE: return this->allocate_stage;
default: exit_error("Unknown stage"); return this->all_stages;
default: exit_error("Unknown stage"); return this->all_stages_without_allocation;
}
}
int iterations() const {
return all_stages.iterations;
return all_stages_without_allocation.iterations;
}
really_inline void run_iteration(bool stage1_only, bool hotbuffers=false) {
simdjson_really_inline void run_iteration(bool stage1_only, bool hotbuffers=false) {
// Allocate dom::parser
collector.start();
dom::parser parser;
error_code error = parser.allocate(json.size());
// We always allocate at least 64KB. Smaller allocations may actually be slower under some systems.
error_code error = parser.allocate(json.size() < 65536 ? 65536 : json.size());
if (error) {
exit_error(string("Unable to allocate_stage ") + to_string(json.size()) + " bytes for the JSON result: " + error_message(error));
exit_error(string("Unable to allocate_stage ") + to_string(json.size()) + " bytes for the JSON text: " + error_message(error));
}
event_count allocate_count = collector.end();
allocate_stage << allocate_count;
// Run it once to get hot buffers
if(hotbuffers) {
auto result = parser.parse((const uint8_t *)json.data(), json.size());
auto result = parser.parse(reinterpret_cast<const uint8_t *>(json.data()), json.size());
if (result.error()) {
exit_error(string("Failed to parse ") + filename + string(":") + error_message(result.error()));
}
@@ -319,7 +331,7 @@ struct benchmarker {
// Stage 1 (find structurals)
collector.start();
error = parser.implementation->stage1((const uint8_t *)json.data(), json.size(), false);
error = parser.implementation->stage1(reinterpret_cast<const uint8_t *>(json.data()), json.size(), stage1_mode::regular);
event_count stage1_count = collector.end();
stage1 << stage1_count;
if (error) {
@@ -329,7 +341,7 @@ struct benchmarker {
// Stage 2 (unified machine) and the rest
if (stage1_only) {
all_stages << stage1_count;
all_stages_without_allocation << stage1_count;
} else {
event_count stage2_count;
collector.start();
@@ -339,7 +351,7 @@ struct benchmarker {
}
stage2_count = collector.end();
stage2 << stage2_count;
all_stages << allocate_count + stage1_count + stage2_count;
all_stages_without_allocation << stage1_count + stage2_count;
}
// Calculate stats the first time we parse
if (stats == NULL) {
@@ -355,7 +367,7 @@ struct benchmarker {
void run_loop(size_t iterations) {
dom::parser parser;
auto firstresult = parser.parse((const uint8_t *)json.data(), json.size());
auto firstresult = parser.parse(reinterpret_cast<const uint8_t *>(json.data()), json.size());
if (firstresult.error()) {
exit_error(string("Failed to parse ") + filename + string(":") + error_message(firstresult.error()));
}
@@ -363,7 +375,7 @@ struct benchmarker {
collector.start();
// some users want something closer to "number of documents per second"
for(size_t i = 0; i < iterations; i++) {
auto result = parser.parse((const uint8_t *)json.data(), json.size());
auto result = parser.parse(reinterpret_cast<const uint8_t *>(json.data()), json.size());
if (result.error()) {
exit_error(string("Failed to parse ") + filename + string(":") + error_message(result.error()));
}
@@ -372,7 +384,7 @@ struct benchmarker {
loop << all_loop_count;
}
really_inline void run_iterations(size_t iterations, bool stage1_only, bool hotbuffers=false) {
simdjson_really_inline void run_iterations(size_t iterations, bool stage1_only, bool hotbuffers=false) {
for (size_t i = 0; i<iterations; i++) {
run_iteration(stage1_only, hotbuffers);
}
@@ -386,7 +398,7 @@ struct benchmarker {
prefix,
"Speed",
stage.elapsed_ns() / static_cast<double>(stats->blocks), // per block
percent(stage.elapsed_sec(), all_stages.elapsed_sec()), // %
percent(stage.elapsed_sec(), all_stages_without_allocation.elapsed_sec()), // %
stage.elapsed_ns() / static_cast<double>(stats->bytes), // per byte
stage.elapsed_ns() / static_cast<double>(stats->structurals), // per structural
(static_cast<double>(json.size()) / 1000000000.0) / stage.elapsed_sec() // GB/s
@@ -397,7 +409,7 @@ struct benchmarker {
prefix,
"Cycles",
stage.cycles() / static_cast<double>(stats->blocks),
percent(stage.cycles(), all_stages.cycles()),
percent(stage.cycles(), all_stages_without_allocation.cycles()),
stage.cycles() / static_cast<double>(stats->bytes),
stage.cycles() / static_cast<double>(stats->structurals),
(stage.cycles() / stage.elapsed_sec()) / 1000000000.0
@@ -406,7 +418,7 @@ struct benchmarker {
prefix,
"Instructions",
stage.instructions() / static_cast<double>(stats->blocks),
percent(stage.instructions(), all_stages.instructions()),
percent(stage.instructions(), all_stages_without_allocation.instructions()),
stage.instructions() / static_cast<double>(stats->bytes),
stage.instructions() / static_cast<double>(stats->structurals),
stage.instructions() / static_cast<double>(stage.cycles())
@@ -417,9 +429,9 @@ struct benchmarker {
prefix,
"Misses",
stage.branch_misses(),
percent(stage.branch_misses(), all_stages.branch_misses()),
percent(stage.branch_misses(), all_stages_without_allocation.branch_misses()),
stage.cache_misses(),
percent(stage.cache_misses(), all_stages.cache_misses()),
percent(stage.cache_misses(), all_stages_without_allocation.cache_misses()),
stage.cache_references()
);
}
@@ -434,7 +446,7 @@ struct benchmarker {
void print(bool tabbed_output) const {
if (tabbed_output) {
char* filename_copy = (char*)malloc(strlen(filename)+1);
char* filename_copy = reinterpret_cast<char*>(malloc(strlen(filename)+1));
SIMDJSON_PUSH_DISABLE_WARNINGS
SIMDJSON_DISABLE_DEPRECATED_WARNING // Validated CRT_SECURE safe here
strcpy(filename_copy, filename);
@@ -456,14 +468,14 @@ struct benchmarker {
allocate_stage.best.cycles() / static_cast<double>(json.size()),
stage1.best.cycles() / static_cast<double>(json.size()),
stage2.best.cycles() / static_cast<double>(json.size()),
all_stages.best.cycles() / static_cast<double>(json.size()),
gb / all_stages.best.elapsed_sec(),
all_stages_without_allocation.best.cycles() / static_cast<double>(json.size()),
gb / all_stages_without_allocation.best.elapsed_sec(),
gb / stage1.best.elapsed_sec(),
gb / stage2.best.elapsed_sec());
} else {
printf("\"%s\"\t\t\t\t\t%f\t%f\t%f\n",
base,
gb / all_stages.best.elapsed_sec(),
gb / all_stages_without_allocation.best.elapsed_sec(),
gb / stage1.best.elapsed_sec(),
gb / stage2.best.elapsed_sec());
}
@@ -490,10 +502,10 @@ struct benchmarker {
stats->blocks_with_16_structurals_flipped, percent(stats->blocks_with_16_structurals_flipped, stats->blocks));
}
printf("\n");
printf("All Stages\n");
print_aggregate("| " , all_stages.best);
printf("All Stages (excluding allocation)\n");
print_aggregate("| " , all_stages_without_allocation.best);
// frequently, allocation is a tiny fraction of the running time so we omit it
if(allocate_stage.best.elapsed_sec() > 0.01 * all_stages.best.elapsed_sec()) {
if(allocate_stage.best.elapsed_sec() > 0.01 * all_stages_without_allocation.best.elapsed_sec()) {
printf("|- Allocation\n");
print_aggregate("| ", allocate_stage.best);
}
@@ -504,17 +516,16 @@ struct benchmarker {
if (collector.has_events()) {
double freq1 = (stage1.best.cycles() / stage1.best.elapsed_sec()) / 1000000000.0;
double freq2 = (stage2.best.cycles() / stage2.best.elapsed_sec()) / 1000000000.0;
double freqall = (all_stages.best.cycles() / all_stages.best.elapsed_sec()) / 1000000000.0;
double freqall = (all_stages_without_allocation.best.cycles() / all_stages_without_allocation.best.elapsed_sec()) / 1000000000.0;
double freqmin = min(freq1, freq2);
double freqmax = max(freq1, freq2);
if((freqall < 0.95 * freqmin) or (freqall > 1.05 * freqmax)) {
printf("\nWarning: The processor frequency fluctuates in an expected way!!!\n"
"Expect the overall speed not to match stage 1 and stage 2 speeds.\n"
"Range for stage 1 and stage 2 : [%.3f GHz, %.3f GHz], overall: %.3f GHz.\n",
freqmin, freqmax, freqall);
}
}
printf("\n%.1f documents parsed per second (best)\n", 1.0/static_cast<double>(all_stages.best.elapsed_sec()));
printf("\n%.1f documents parsed per second (best)\n", 1.0/static_cast<double>(all_stages_without_allocation.best.elapsed_sec()));
}
}
};
@@ -0,0 +1,53 @@
#pragma once
#include "json_benchmark/file_runner.h"
#include <vector>
namespace distinct_user_id {
using namespace json_benchmark;
template<typename I>
struct runner : public file_runner<I> {
std::vector<uint64_t> result{};
bool setup(benchmark::State &state) {
return this->load_json(state, TWITTER_JSON);
}
bool before_run(benchmark::State &state) {
if (!file_runner<I>::before_run(state)) { return false; }
result.clear();
return true;
}
bool run(benchmark::State &) {
return this->implementation.run(this->json, result);
}
bool after_run(benchmark::State &state) {
if (!file_runner<I>::after_run(state)) { return false; }
std::sort(result.begin(), result.end());
auto last = std::unique(result.begin(), result.end());
result.erase(last, result.end());
return true;
}
template<typename R>
bool diff(benchmark::State &state, runner<R> &reference) {
return diff_results(state, result, reference.result, diff_flags::NONE);
}
size_t items_per_iteration() {
return result.size();
}
};
struct simdjson_dom;
template<typename I> simdjson_really_inline static void distinct_user_id(benchmark::State &state) {
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
}
} // namespace distinct_user_id
@@ -0,0 +1,27 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
#include "distinct_user_id.h"
namespace distinct_user_id {
struct nlohmann_json {
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
auto root = nlohmann::json::parse(json.data(), json.data() + json.size());
for (auto tweet : root["statuses"]) {
result.push_back(tweet["user"]["id"]);
if (tweet.contains("retweeted_status")) {
result.push_back(tweet["retweeted_status"]["user"]["id"]);
}
}
return true;
}
};
BENCHMARK_TEMPLATE(distinct_user_id, nlohmann_json)->UseManualTime();
} // namespace distinct_user_id
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
@@ -0,0 +1,59 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
#include "distinct_user_id.h"
namespace distinct_user_id {
using json = nlohmann::json;
struct nlohmann_json_sax {
struct Handler : json::json_sax_t
{
std::vector<uint64_t>& result;
bool user = false;
bool user_id = false;
Handler(std::vector<uint64_t> &r) : result(r) { }
bool key(string_t& val) override {
// Assume that valid user/id pairs appear only once in main array of user objects
if (user) { // If already found user object, find id key
if (val.compare("id") == 0) { user_id = true; }
}
else if (val.compare("user") == 0) { user = true; } // Otherwise, find user object
return true;
}
bool number_unsigned(number_unsigned_t val) override {
if (user_id) {
result.emplace_back(val);
user = false;
user_id = false;
}
return true;
}
// Irrelevant events
bool null() override { return true; }
bool boolean(bool val) override { return true; }
bool number_float(number_float_t val, const string_t& s) override { return true; }
bool number_integer(number_integer_t val) override { return true; }
bool string(string_t& val) override { return true; }
bool start_object(std::size_t elements) override { return true; }
bool end_object() override { return true; }
bool start_array(std::size_t elements) override { return true; }
bool end_array() override { return true; }
bool binary(json::binary_t& val) override { return true; }
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) override { return false; }
}; // Handler
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
Handler handler(result);
json::sax_parse(json.data(), &handler);
return true;
}
}; // nlohmann_json_sax
BENCHMARK_TEMPLATE(distinct_user_id, nlohmann_json_sax)->UseManualTime();
} // namespace distinct_user_id
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
+58
View File
@@ -0,0 +1,58 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
#include "distinct_user_id.h"
namespace distinct_user_id {
using namespace rapidjson;
struct rapidjson_base {
Document doc{};
bool run(Document &root, std::vector<uint64_t> &result) {
if (root.HasParseError()) { printf("parse error\n"); return false; }
if (!root.IsObject()) { printf("root is not an object\n"); return false; }
auto statuses = root.FindMember("statuses");
if (statuses == root.MemberEnd() || !statuses->value.IsArray()) { printf("statuses is not an array\n"); return false; }
for (auto &tweet : statuses->value.GetArray()) {
if (!tweet.IsObject()) { return false; }
auto user = tweet.FindMember("user");
if (user == tweet.MemberEnd() || !user->value.IsObject()) { printf("user is not an object\n"); return false; }
auto id = user->value.FindMember("id");
if (id == user->value.MemberEnd() || !id->value.IsUint64()) { printf("id is not an int\n"); return false; }
result.push_back(id->value.GetUint64());
auto retweet = tweet.FindMember("retweeted_status");
if (retweet != tweet.MemberEnd()) {
if (!retweet->value.IsObject()) { printf("retweet is not an object\n"); return false; }
user = retweet->value.FindMember("user");
if (user == retweet->value.MemberEnd() || !user->value.IsObject()) { printf("rewtweet.user is not an object\n"); return false; }
id = user->value.FindMember("id");
if (id == user->value.MemberEnd() || !id->value.IsUint64()) { printf("retweet.id is not an int\n"); return false; }
result.push_back(id->value.GetUint64());
}
}
return true;
}
};
struct rapidjson : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag>(json.data()), result);
}
};
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>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(distinct_user_id, rapidjson_insitu)->UseManualTime();
} // namespace partial_tweets
#endif // SIMDJSON_COMPETITION_RAPIDJSON
@@ -0,0 +1,61 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
#include "distinct_user_id.h"
#include <string.h>
namespace distinct_user_id {
using namespace rapidjson;
struct rapidjson_sax {
struct Handler {
std::vector<uint64_t>& result;
bool user = false;
bool user_id = false;
Handler(std::vector<uint64_t> &r) : result(r) { }
bool Key(const char* key, SizeType length, bool copy) {
// Assume that valid user/id pairs appear only once in main array of user objects
if (user) { // If already found user object, find id key
if ((length == 2) && memcmp(key,"id",2) == 0) { user_id = true; }
}
else if ((length == 4) && memcmp(key,"user",4) == 0) { user = true; } // Otherwise, find user object
return true;
}
bool Uint(unsigned i) { // id values are treated as Uint (not Uint64) by the reader
if (user_id) { // Getting id if previous key was "id" for a user
result.emplace_back(i);
user_id = false;
user = false;
}
return true;
}
// Irrelevant events
bool Null() { return true; }
bool Bool(bool b) { return true; }
bool Double(double d) { return true; }
bool Int(int i) { return true; }
bool Int64(int64_t i) { return true; }
bool Uint64(uint64_t i) { return true; }
bool RawNumber(const char* str, SizeType length, bool copy) { return true; }
bool String(const char* str, SizeType length, bool copy) { return true; }
bool StartObject() { return true; }
bool EndObject(SizeType memberCount) { return true; }
bool StartArray() { return true; }
bool EndArray(SizeType elementCount) { return true; }
}; // handler
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
Reader reader;
Handler handler(result);
InsituStringStream ss(json.data());
reader.Parse<kParseInsituFlag | kParseValidateEncodingFlag | kParseFullPrecisionFlag>(ss,handler);
return true;
}
}; // rapid_jason_sax
BENCHMARK_TEMPLATE(distinct_user_id, rapidjson_sax)->UseManualTime();
} // namespace distinct_user_id
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+80
View File
@@ -0,0 +1,80 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_SAJSON
#include "distinct_user_id.h"
namespace distinct_user_id {
struct sajson {
size_t ast_buffer_size{0};
size_t *ast_buffer{nullptr};
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"; }
return { val.as_cstring(), val.get_string_length() };
}
simdjson_really_inline uint64_t get_str_uint64(const ::sajson::value &obj, std::string_view key) {
// Since sajson only supports 53-bit numbers, and IDs in twitter.json can be > 53 bits, we read the corresponding id_str and parse that.
auto val = obj.get_value_of_key({key.data(), key.length()});
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field not a string"; }
auto str = val.as_cstring();
char *endptr;
uint64_t result = strtoull(str, &endptr, 10);
if (endptr != &str[val.get_string_length()]) { throw "field is a string, but not an integer string"; }
return result;
}
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
using namespace sajson;
if (!ast_buffer) {
ast_buffer_size = json.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(json.size(), json.data())
);
if (!doc.is_valid()) { return false; }
auto root = doc.get_root();
if (root.get_type() != TYPE_OBJECT) { return false; }
auto statuses = root.get_value_of_key({"statuses", strlen("statuses")});
if (statuses.get_type() != TYPE_ARRAY) { return false; }
for (size_t i=0; i<statuses.get_length(); i++) {
auto tweet = statuses.get_array_element(i);
// get tweet.user.id
if (tweet.get_type() != TYPE_OBJECT) { return false; }
auto user = tweet.get_value_of_key({"user", strlen("user")});
if (user.get_type() != TYPE_OBJECT) { return false; }
result.push_back(get_str_uint64(user, "id_str"));
// get tweet.retweeted_status.user.id
auto retweet = tweet.get_value_of_key({"retweeted_status", strlen("retweeted_status")});
switch (retweet.get_type()) {
case TYPE_OBJECT: {
auto retweet_user = retweet.get_value_of_key({"user", strlen("user")});
if (retweet_user.get_type() != TYPE_OBJECT) { return false; }
result.push_back(get_str_uint64(retweet_user, "id_str"));
break;
}
// TODO distinguish null and missing. null is bad. missing is fine.
case TYPE_NULL:
break;
default:
return false;
}
}
return true;
}
};
BENCHMARK_TEMPLATE(distinct_user_id, sajson)->UseManualTime();
} // namespace distinct_user_id
#endif // SIMDJSON_COMPETITION_SAJSON
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#if SIMDJSON_EXCEPTIONS
#include "distinct_user_id.h"
namespace distinct_user_id {
using namespace simdjson;
struct simdjson_dom {
dom::parser parser{};
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
// Walk the document, parsing as we go
auto doc = parser.parse(json);
for (dom::object tweet : doc["statuses"]) {
// We believe that all statuses have a matching
// user, and we are willing to throw when they do not.
result.push_back(tweet["user"]["id"]);
// Not all tweets have a "retweeted_status", but when they do
// we want to go and find the user within.
auto retweet = tweet["retweeted_status"];
if (retweet.error() != NO_SUCH_FIELD) {
result.push_back(retweet["user"]["id"]);
}
}
return true;
}
};
BENCHMARK_TEMPLATE(distinct_user_id, simdjson_dom)->UseManualTime();
} // namespace distinct_user_id
#endif // SIMDJSON_EXCEPTIONS
@@ -0,0 +1,36 @@
#pragma once
#if SIMDJSON_EXCEPTIONS
#include "distinct_user_id.h"
namespace distinct_user_id {
using namespace simdjson;
struct simdjson_dom_json_pointer {
dom::parser parser{};
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
// Walk the document, parsing as we go
auto doc = parser.parse(json);
for (dom::object tweet : doc["statuses"]) {
// We believe that all statuses have a matching
// user, and we are willing to throw when they do not.
result.push_back(tweet.at_pointer("/user/id"));
// Not all tweets have a "retweeted_status", but when they do
// we want to go and find the user within.
auto retweet_id = tweet.at_pointer("/retweeted_status/user/id");
if (retweet_id.error() != NO_SUCH_FIELD) {
result.push_back(retweet_id);
}
}
return true;
}
};
BENCHMARK_TEMPLATE(distinct_user_id, simdjson_dom_json_pointer)->UseManualTime();
} // namespace distinct_user_id
#endif // SIMDJSON_EXCEPTIONS
@@ -0,0 +1,37 @@
#pragma once
#if SIMDJSON_EXCEPTIONS
#include "distinct_user_id.h"
namespace distinct_user_id {
using namespace simdjson;
struct simdjson_ondemand {
ondemand::parser parser{};
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
// Walk the document, parsing as we go
auto doc = parser.iterate(json);
for (ondemand::object tweet : doc.find_field("statuses")) {
// We believe that all statuses have a matching
// user, and we are willing to throw when they do not.
result.push_back(tweet.find_field("user").find_field("id"));
// Not all tweets have a "retweeted_status", but when they do
// we want to go and find the user within.
auto retweet = tweet.find_field("retweeted_status");
if (!retweet.error()) {
result.push_back(retweet.find_field("user").find_field("id"));
}
}
return true;
}
};
BENCHMARK_TEMPLATE(distinct_user_id, simdjson_ondemand)->UseManualTime();
} // namespace distinct_user_id
#endif // SIMDJSON_EXCEPTIONS
@@ -0,0 +1,37 @@
#pragma once
#if SIMDJSON_EXCEPTIONS
#include "distinct_user_id.h"
namespace distinct_user_id {
using namespace simdjson;
struct simdjson_ondemand_json_pointer {
ondemand::parser parser{};
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
// Walk the document, parsing as we go
auto doc = parser.iterate(json);
for (ondemand::object tweet : doc.find_field("statuses")) {
// We believe that all statuses have a matching
// user, and we are willing to throw when they do not.
result.push_back(tweet.at_pointer("/user/id"));
// Not all tweets have a "retweeted_status", but when they do
// we want to go and find the user within.
auto retweet_id = tweet.at_pointer("/retweeted_status/user/id");
if (retweet_id.error() != NO_SUCH_FIELD) {
result.push_back(retweet_id);
}
}
return true;
}
};
BENCHMARK_TEMPLATE(distinct_user_id, simdjson_ondemand_json_pointer)->UseManualTime();
} // namespace distinct_user_id
#endif // SIMDJSON_EXCEPTIONS
+61
View File
@@ -0,0 +1,61 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_YYJSON
#include "distinct_user_id.h"
namespace distinct_user_id {
struct yyjson_base {
bool run(yyjson_doc *doc, std::vector<uint64_t> &result) {
if (!doc) { return false; }
yyjson_val *root = yyjson_doc_get_root(doc);
if (!yyjson_is_obj(root)) { return false; }
yyjson_val *statuses = yyjson_obj_get(root, "statuses");
if (!yyjson_is_arr(statuses)) { return false; }
// Walk the document, parsing the tweets as we go
size_t tweet_idx, tweets_max;
yyjson_val *tweet;
yyjson_arr_foreach(statuses, tweet_idx, tweets_max, tweet) {
auto user = yyjson_obj_get(tweet, "user");
if (!yyjson_is_obj(user)) { return false; }
auto id = yyjson_obj_get(user, "id");
if (!yyjson_is_uint(id)) { return false; }
result.push_back(yyjson_get_uint(id));
// Not all tweets have a "retweeted_status", but when they do
// we want to go and find the user within.
auto retweet = yyjson_obj_get(tweet, "retweeted_status");
if (retweet) {
if (!yyjson_is_obj(retweet)) { return false; }
user = yyjson_obj_get(retweet, "user");
if (!yyjson_is_obj(user)) { return false; }
id = yyjson_obj_get(user, "id");
if (!yyjson_is_uint(id)) { return false; }
result.push_back(yyjson_get_sint(id));
}
}
return true;
}
};
struct yyjson : yyjson_base {
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
return yyjson_base::run(yyjson_read(json.data(), json.size(), 0), result);
}
};
BENCHMARK_TEMPLATE(distinct_user_id, yyjson)->UseManualTime();
struct yyjson_insitu : yyjson_base {
bool run(simdjson::padded_string &json, std::vector<uint64_t> &result) {
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), result);
}
};
BENCHMARK_TEMPLATE(distinct_user_id, yyjson_insitu)->UseManualTime();
} // namespace distinct_user_id
#endif // SIMDJSON_COMPETITION_YYJSON
-406
View File
@@ -1,406 +0,0 @@
#include "simdjson.h"
#include <algorithm>
#include <cstring>
#include <unistd.h>
#include <vector>
#include "benchmark.h"
SIMDJSON_PUSH_DISABLE_ALL_WARNINGS
// #define RAPIDJSON_SSE2 // bad for performance
// #define RAPIDJSON_SSE42 // bad for performance
#include "rapidjson/document.h"
#include "rapidjson/reader.h"
#include "rapidjson/stringbuffer.h"
#include "rapidjson/writer.h"
#include "sajson.h"
SIMDJSON_POP_DISABLE_WARNINGS
using namespace rapidjson;
bool equals(const char *s1, const char *s2) { return strcmp(s1, s2) == 0; }
void remove_duplicates(std::vector<int64_t> &v) {
std::sort(v.begin(), v.end());
auto last = std::unique(v.begin(), v.end());
v.erase(last, v.end());
}
void print_vec(const std::vector<int64_t> &v) {
for (auto i : v) {
std::cout << i << " ";
}
std::cout << std::endl;
}
// clang-format off
// simdjson_recurse below come be implemented like so but it is slow:
/*void simdjson_recurse(std::vector<int64_t> & v, simdjson::dom::element element) {
error_code error;
if (element.is_array()) {
dom::array array;
error = element.get(array);
for (auto child : array) {
if (child.is<simdjson::dom::array>() || child.is<simdjson::dom::object>()) {
simdjson_recurse(v, child);
}
}
} else if (element.is_object()) {
int64_t id;
error = element["user"]["id"].get(id);
if(!error) {
v.push_back(id);
}
for (auto [key, value] : object) {
if (value.is<simdjson::dom::array>() || value.is<simdjson::dom::object>()) {
simdjson_recurse(v, value);
}
}
}
}*/
// clang-format on
really_inline void simdjson_recurse(std::vector<int64_t> & v, simdjson::dom::element element);
void simdjson_recurse(std::vector<int64_t> & v, simdjson::dom::array array) {
for (auto child : array) {
simdjson_recurse(v, child);
}
}
void simdjson_recurse(std::vector<int64_t> & v, simdjson::dom::object object) {
for (auto [key, value] : object) {
if((key.size() == 4) && (memcmp(key.data(), "user", 4) == 0)) {
// we are in an object under the key "user"
simdjson::error_code error;
simdjson::dom::object child_object;
simdjson::dom::object child_array;
if (not (error = value.get(child_object))) {
for (auto [child_key, child_value] : child_object) {
if((child_key.size() == 2) && (memcmp(child_key.data(), "id", 2) == 0)) {
int64_t x;
if (not (error = child_value.get(x))) {
v.push_back(x);
}
}
simdjson_recurse(v, child_value);
}
} else if (not (error = value.get(child_array))) {
simdjson_recurse(v, child_array);
}
// end of: we are in an object under the key "user"
} else {
simdjson_recurse(v, value);
}
}
}
really_inline void simdjson_recurse(std::vector<int64_t> & v, simdjson::dom::element element) {
UNUSED simdjson::error_code error;
simdjson::dom::array array;
simdjson::dom::object object;
if (not (error = element.get(array))) {
simdjson_recurse(v, array);
} else if (not (error = element.get(object))) {
simdjson_recurse(v, object);
}
}
really_inline std::vector<int64_t>
simdjson_just_dom(simdjson::dom::element doc) {
std::vector<int64_t> answer;
simdjson_recurse(answer, doc);
remove_duplicates(answer);
return answer;
}
really_inline std::vector<int64_t>
simdjson_compute_stats(const simdjson::padded_string &p) {
std::vector<int64_t> answer;
simdjson::dom::parser parser;
simdjson::dom::element doc;
auto error = parser.parse(p).get(doc);
if (!error) {
simdjson_recurse(answer, doc);
remove_duplicates(answer);
}
return answer;
}
really_inline simdjson::error_code
simdjson_just_parse(const simdjson::padded_string &p) {
simdjson::dom::parser parser;
return parser.parse(p).error();
}
void sajson_traverse(std::vector<int64_t> &answer, const sajson::value &node) {
using namespace sajson;
switch (node.get_type()) {
case TYPE_ARRAY: {
auto length = node.get_length();
for (size_t i = 0; i < length; ++i) {
sajson_traverse(answer, node.get_array_element(i));
}
break;
}
case TYPE_OBJECT: {
auto length = node.get_length();
// sajson has O(log n) find_object_key, but we still visit each node anyhow
// because we need to visit all values.
for (auto i = 0u; i < length; ++i) {
auto key = node.get_object_key(i); // expected: sajson::string
bool found_user =
(key.length() == 4) && (memcmp(key.data(), "user", 4) == 0);
if (found_user) { // found a user!!!
auto user_value = node.get_object_value(i); // get the value
if (user_value.get_type() ==
TYPE_OBJECT) { // the value should be an object
// now we know that we only need one value
auto user_value_length = user_value.get_length();
auto right_index =
user_value.find_object_key(sajson::string("id", 2));
if (right_index < user_value_length) {
auto v = user_value.get_object_value(right_index);
if (v.get_type() == TYPE_INTEGER) { // check that it is an integer
answer.push_back(v.get_integer_value()); // record it!
} else if (v.get_type() == TYPE_DOUBLE) {
answer.push_back((int64_t)v.get_double_value()); // record it!
}
}
}
}
sajson_traverse(answer, node.get_object_value(i));
}
break;
}
case TYPE_NULL:
case TYPE_FALSE:
case TYPE_TRUE:
case TYPE_STRING:
case TYPE_DOUBLE:
case TYPE_INTEGER:
break;
default:
assert(false && "unknown node type");
}
}
really_inline std::vector<int64_t>
sasjon_just_dom(sajson::document &d) {
std::vector<int64_t> answer;
sajson_traverse(answer, d.get_root());
remove_duplicates(answer);
return answer;
}
really_inline std::vector<int64_t>
sasjon_compute_stats(const simdjson::padded_string &p) {
std::vector<int64_t> answer;
char *buffer = (char *)malloc(p.size());
memcpy(buffer, p.data(), p.size());
auto d = sajson::parse(sajson::dynamic_allocation(),
sajson::mutable_string_view(p.size(), buffer));
if (!d.is_valid()) {
free(buffer);
return answer;
}
sajson_traverse(answer, d.get_root());
free(buffer);
remove_duplicates(answer);
return answer;
}
really_inline bool
sasjon_just_parse(const simdjson::padded_string &p) {
char *buffer = (char *)malloc(p.size());
memcpy(buffer, p.data(), p.size());
auto d = sajson::parse(sajson::dynamic_allocation(),
sajson::mutable_string_view(p.size(), buffer));
bool answer = !d.is_valid();
free(buffer);
return answer;
}
void rapid_traverse(std::vector<int64_t> &answer, const rapidjson::Value &v) {
switch (v.GetType()) {
case kObjectType:
for (Value::ConstMemberIterator m = v.MemberBegin(); m != v.MemberEnd();
++m) {
bool found_user = (m->name.GetStringLength() == 4) &&
(memcmp(m->name.GetString(), "user", 4) == 0);
if (found_user) {
const rapidjson::Value &child = m->value;
if (child.GetType() == kObjectType) {
for (Value::ConstMemberIterator k = child.MemberBegin();
k != child.MemberEnd(); ++k) {
if (equals(k->name.GetString(), "id")) {
const rapidjson::Value &val = k->value;
if (val.GetType() == kNumberType) {
answer.push_back(val.GetInt64());
}
}
}
}
}
rapid_traverse(answer, m->value);
}
break;
case kArrayType:
for (Value::ConstValueIterator i = v.Begin(); i != v.End();
++i) { // v.Size();
rapid_traverse(answer, *i);
}
break;
case kNullType:
case kFalseType:
case kTrueType:
case kStringType:
case kNumberType:
default:
break;
}
}
really_inline std::vector<int64_t>
rapid_just_dom(rapidjson::Document &d) {
std::vector<int64_t> answer;
rapid_traverse(answer, d);
remove_duplicates(answer);
return answer;
}
really_inline std::vector<int64_t>
rapid_compute_stats(const simdjson::padded_string &p) {
std::vector<int64_t> answer;
char *buffer = (char *)malloc(p.size() + 1);
memcpy(buffer, p.data(), p.size());
buffer[p.size()] = '\0';
rapidjson::Document d;
d.ParseInsitu<kParseValidateEncodingFlag>(buffer);
if (d.HasParseError()) {
free(buffer);
return answer;
}
rapid_traverse(answer, d);
free(buffer);
remove_duplicates(answer);
return answer;
}
really_inline bool
rapid_just_parse(const simdjson::padded_string &p) {
char *buffer = (char *)malloc(p.size() + 1);
memcpy(buffer, p.data(), p.size());
buffer[p.size()] = '\0';
rapidjson::Document d;
d.ParseInsitu<kParseValidateEncodingFlag>(buffer);
bool answer = d.HasParseError();
free(buffer);
return answer;
}
int main(int argc, char *argv[]) {
bool verbose = false;
bool just_data = false;
int c;
while ((c = getopt(argc, argv, "vt")) != -1)
switch (c) {
case 't':
just_data = true;
break;
case 'v':
verbose = true;
break;
default:
abort();
}
if (optind >= argc) {
std::cerr
<< "Using different parsers, we compute the content statistics of "
"JSON documents."
<< std::endl;
std::cerr << "Usage: " << argv[0] << " <jsonfile>" << std::endl;
std::cerr << "Or " << argv[0] << " -v <jsonfile>" << std::endl;
exit(1);
}
const char *filename = argv[optind];
if (optind + 1 < argc) {
std::cerr << "warning: ignoring everything after " << argv[optind + 1]
<< std::endl;
}
simdjson::padded_string p;
auto error = simdjson::padded_string::load(filename).get(p);
if (error) {
std::cerr << "Could not load the file " << filename << std::endl;
return EXIT_FAILURE;
}
// Gigabyte: https://en.wikipedia.org/wiki/Gigabyte
if (verbose) {
std::cout << "Input has ";
if (p.size() > 1000 * 1000)
std::cout << p.size() / (1000 * 1000) << " MB ";
else if (p.size() > 1000)
std::cout << p.size() / 1000 << " KB ";
else
std::cout << p.size() << " B ";
std::cout << std::endl;
}
std::vector<int64_t> s1 = simdjson_compute_stats(p);
if (verbose) {
printf("simdjson: ");
print_vec(s1);
}
std::vector<int64_t> s2 = rapid_compute_stats(p);
if (verbose) {
printf("rapid: ");
print_vec(s2);
}
std::vector<int64_t> s3 = sasjon_compute_stats(p);
if (verbose) {
printf("sasjon: ");
print_vec(s3);
}
assert(s1 == s2);
assert(s1 == s3);
size_t size = s1.size();
int repeat = 500;
size_t volume = p.size();
if (just_data) {
printf(
"name cycles_per_byte cycles_per_byte_err gb_per_s gb_per_s_err \n");
}
BEST_TIME("simdjson ", simdjson_compute_stats(p).size(), size, , repeat,
volume, !just_data);
BEST_TIME("rapid ", rapid_compute_stats(p).size(), size, , repeat, volume,
!just_data);
BEST_TIME("sasjon ", sasjon_compute_stats(p).size(), size, , repeat, volume,
!just_data);
BEST_TIME("simdjson (just parse) ", simdjson_just_parse(p), simdjson::error_code::SUCCESS, , repeat,
volume, !just_data);
BEST_TIME("rapid (just parse) ", rapid_just_parse(p), false, , repeat,
volume, !just_data);
BEST_TIME("sasjon (just parse) ", sasjon_just_parse(p), false, , repeat,
volume, !just_data);
simdjson::dom::parser parser;
simdjson::dom::element doc;
error = parser.parse(p).get(doc);
BEST_TIME("simdjson (just dom) ", simdjson_just_dom(doc).size(), size,
, repeat, volume, !just_data);
char *buffer = (char *)malloc(p.size() + 1);
buffer[p.size()] = '\0';
memcpy(buffer, p.data(), p.size());
rapidjson::Document drapid;
drapid.ParseInsitu<kParseValidateEncodingFlag>(buffer);
BEST_TIME("rapid (just dom) ", rapid_just_dom(drapid).size(), size, , repeat,
volume, !just_data);
memcpy(buffer, p.data(), p.size());
auto dsasjon = sajson::parse(sajson::dynamic_allocation(),
sajson::mutable_string_view(p.size(), buffer));
BEST_TIME("sasjon (just dom) ", sasjon_just_dom(dsasjon).size(), size, ,
repeat, volume, !just_data);
free(buffer);
}
+16
View File
@@ -0,0 +1,16 @@
include_directories( .. ../linux )
link_libraries(simdjson-windows-headers test-data)
link_libraries(simdjson)
add_executable(perfdiff perfdiff.cpp)
add_executable(parse parse.cpp)
add_executable(parse_stream parse_stream.cpp)
add_executable(statisticalmodel statisticalmodel.cpp)
add_executable(parse_noutf8validation parse.cpp)
target_compile_definitions(parse_noutf8validation PRIVATE SIMDJSON_SKIPUTF8VALIDATION)
add_executable(parse_nonumberparsing parse.cpp)
target_compile_definitions(parse_nonumberparsing PRIVATE SIMDJSON_SKIPNUMBERPARSING)
add_executable(parse_nostringparsing parse.cpp)
target_compile_definitions(parse_nostringparsing PRIVATE SIMDJSON_SKIPSTRINGPARSING)
include(checkperf.cmake)
@@ -5,9 +5,12 @@
# checkperf-repo: initialize and sync reference repository (first time only)
# TEST checkperf: runs the actual checkperf test
option(SIMDJSON_ENABLE_DOM_CHECKPERF "Enable DOM performance comparison with main branch" OFF)
# Clone the repository if it's not there
find_package(Git QUIET)
if (SIMDJSON_IS_UNDER_GIT AND Git_FOUND AND (GIT_VERSION_STRING VERSION_GREATER "2.1.4") AND (NOT CMAKE_GENERATOR MATCHES Ninja) ) # We use "-C" which requires a recent git
if (SIMDJSON_ENABLE_DOM_CHECKPERF AND Git_FOUND AND (GIT_VERSION_STRING VERSION_GREATER "2.1.4") AND (NOT CMAKE_GENERATOR MATCHES Ninja) AND (NOT MSVC) ) # We use "-C" which requires a recent git
message(STATUS "Git is available and it is recent. We are enabling checkperf targets.")
# sync_git_repository(myrepo ...) creates two targets:
# myrepo - if the repo does not exist, creates and syncs it against the origin branch
@@ -61,7 +64,13 @@ if (SIMDJSON_IS_UNDER_GIT AND Git_FOUND AND (GIT_VERSION_STRING VERSION_GREATER
OUTPUT ${SIMDJSON_CHECKPERF_DIR}/build/cmake_install.cmake # We make many things but this seems the most cross-platform one we can depend on
COMMAND
${CMAKE_COMMAND} -E env CXX=${CMAKE_CXX_COMPILER} CC=${CMAKE_C_COMPILER}
${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DSIMDJSON_GOOGLE_BENCHMARKS=OFF -DSIMDJSON_COMPETITION=OFF -G ${CMAKE_GENERATOR} ..
${CMAKE_COMMAND}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DSIMDJSON_GOOGLE_BENCHMARKS=OFF
-DSIMDJSON_COMPETITION=OFF
-DSIMDJSON_DEVELOPER_MODE=YES
-G ${CMAKE_GENERATOR}
..
WORKING_DIRECTORY ${SIMDJSON_CHECKPERF_DIR}/build
DEPENDS ${SIMDJSON_CHECKPERF_DIR}/build/CMakeCache.txt
)
@@ -70,7 +79,7 @@ if (SIMDJSON_IS_UNDER_GIT AND Git_FOUND AND (GIT_VERSION_STRING VERSION_GREATER
if (CMAKE_CONFIGURATION_TYPES)
set(CHECKPERF_PARSE ${SIMDJSON_CHECKPERF_DIR}/build/benchmark/$<CONFIGURATION>/parse)
else()
set(CHECKPERF_PARSE ${SIMDJSON_CHECKPERF_DIR}/build/benchmark/parse)
set(CHECKPERF_PARSE ${SIMDJSON_CHECKPERF_DIR}/build/benchmark/dom/parse)
endif()
add_custom_target(
checkperf-parse ALL # TODO is ALL necessary?
@@ -89,13 +98,15 @@ if (SIMDJSON_IS_UNDER_GIT AND Git_FOUND AND (GIT_VERSION_STRING VERSION_GREATER
# COMMAND ECHO $<TARGET_FILE:perfdiff> \"$<TARGET_FILE:parse> -t ${SIMDJSON_CHECKPERF_ARGS}\" \"${CHECKPERF_PARSE} -t ${SIMDJSON_CHECKPERF_ARGS}\" }
COMMAND $<TARGET_FILE:perfdiff> $<TARGET_FILE:parse> ${CHECKPERF_PARSE} -H -t ${SIMDJSON_CHECKPERF_ARGS}
)
set_property(TEST checkperf APPEND PROPERTY LABELS per_implementation)
set_property(TEST checkperf APPEND PROPERTY LABELS per_implementation explicitonly)
set_property(TEST checkperf APPEND PROPERTY DEPENDS parse perfdiff ${SIMDJSON_USER_CMAKECACHE})
set_property(TEST checkperf PROPERTY RUN_SERIAL TRUE)
add_dependencies(per_implementation_tests checkperf)
add_dependencies(explicitonly_tests checkperf)
else()
if (CMAKE_GENERATOR MATCHES Ninja)
message(STATUS "We disable the checkperf targets under Ninja.")
else()
else()
message(STATUS "Either git is unavailable or else it is too old. We are disabling checkperf targets.")
endif()
endif ()
@@ -66,8 +66,10 @@ 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::available_implementations) {
out << "-a " << std::left << std::setw(9) << impl->name() << " - Use the " << impl->description() << " parser implementation." << endl;
for (auto impl : simdjson::get_available_implementations()) {
if(impl->supported_by_runtime_system()) {
out << "-a " << std::left << std::setw(9) << impl->name() << " - Use the " << impl->description() << " parser implementation." << endl;
}
}
}
@@ -114,16 +116,18 @@ struct option_struct {
verbose = true;
break;
case 'a': {
const implementation *impl = simdjson::available_implementations[optarg];
if (!impl) {
const implementation *impl = simdjson::get_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::available_implementations) {
exit_message += imple->name();
exit_message += " ";
for (auto imple : simdjson::get_available_implementations()) {
if(imple->supported_by_runtime_system()) {
exit_message += imple->name();
exit_message += " ";
}
}
exit_usage(exit_message);
}
simdjson::active_implementation = impl;
simdjson::get_active_implementation() = impl;
break;
}
case 'C':
@@ -171,7 +175,7 @@ int main(int argc, char *argv[]) {
option_struct options(argc, argv);
if (options.verbose) {
verbose_stream = &cout;
verbose() << "Implementation: " << simdjson::active_implementation->name() << endl;
verbose() << "Implementation: " << simdjson::get_active_implementation()->name() << endl;
}
// Start collecting events. We put this early so if it prints an error message, it's the
@@ -25,11 +25,12 @@ int main(int argc, char *argv[]) {
exit(1);
}
const char *filename = argv[1];
auto[p, err] = simdjson::padded_string::load(filename);
if (err) {
auto v = simdjson::padded_string::load(filename);
if (v.error()) {
std::cerr << "Could not load the file " << filename << std::endl;
return EXIT_FAILURE;
}
const simdjson::padded_string& p = v.value_unsafe();
if (test_baseline) {
std::wclog << "Baseline: Getline + normal parse... " << std::endl;
std::cout << "Gigabytes/second\t"
@@ -41,7 +41,7 @@ using stat_t = struct stat_s;
really_inline void simdjson_process_atom(stat_t &s,
simdjson_really_inline void simdjson_process_atom(stat_t &s,
simdjson::dom::element element) {
if (element.is<int64_t>()) {
s.integer_count++;
@@ -50,9 +50,9 @@ 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;
err = element.get(v);
simdjson::error_code error;
if ((error = element.get(v))) { std::cerr << error << std::endl; abort(); }
if (v) {
s.true_count++;
} else {
@@ -183,7 +183,7 @@ int main(int argc, char *argv[]) {
for (uint32_t i = 0; i < iterations; i++) {
unified.start();
// The default template is simdjson::architecture::NATIVE.
bool isok = (parser.implementation->stage1((const uint8_t *)p.data(), p.size(), false) == simdjson::SUCCESS);
bool isok = (parser.implementation->stage1((const uint8_t *)p.data(), p.size(), simdjson::stage1_mode::regular) == simdjson::SUCCESS);
unified.end(results);
cy1 += results[0];
+5 -5
View File
@@ -116,30 +116,30 @@ struct event_collector {
#if defined(__linux__)
LinuxEvents<PERF_TYPE_HARDWARE> linux_events;
event_collector() : linux_events(vector<int>{
event_collector(bool quiet = false) : linux_events(vector<int>{
PERF_COUNT_HW_CPU_CYCLES,
PERF_COUNT_HW_INSTRUCTIONS,
PERF_COUNT_HW_BRANCH_MISSES,
PERF_COUNT_HW_CACHE_REFERENCES,
PERF_COUNT_HW_CACHE_MISSES
}) {}
}, quiet) {}
bool has_events() {
return linux_events.is_working();
}
#else
event_collector() {}
event_collector(simdjson_unused bool _quiet = false) {}
bool has_events() {
return false;
}
#endif
really_inline void start() {
simdjson_really_inline void start() {
#if defined(__linux)
linux_events.start();
#endif
start_clock = steady_clock::now();
}
really_inline event_count& end() {
simdjson_really_inline event_count& end() {
time_point<steady_clock> end_clock = steady_clock::now();
#if defined(__linux)
linux_events.end(count.event_counts);
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include "json_benchmark/file_runner.h"
namespace find_tweet {
using namespace json_benchmark;
template<typename I>
struct runner : public file_runner<I> {
typename I::StringType result;
bool setup(benchmark::State &state) {
return this->load_json(state, TWITTER_JSON);
}
bool before_run(benchmark::State &state) {
if (!file_runner<I>::before_run(state)) { return false; }
result = "";
return true;
}
bool run(benchmark::State &) {
return this->implementation.run(this->json, 505874901689851904ULL, result);
}
template<typename R>
bool diff(benchmark::State &state, runner<R> &reference) {
return diff_results(state, result, reference.result, diff_flags::NONE);
}
};
struct simdjson_dom;
template<typename I> simdjson_really_inline static void find_tweet(benchmark::State &state) {
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
}
} // namespace find_tweet
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
#include "find_tweet.h"
namespace find_tweet {
struct nlohmann_json {
using StringType=std::string;
bool run(simdjson::padded_string &json, uint64_t find_id, std::string &result) {
auto root = nlohmann::json::parse(json.data(), json.data() + json.size());
for (auto tweet : root["statuses"]) {
if (tweet["id"] == find_id) {
result = tweet["text"];
return true;
}
}
return false;
}
};
BENCHMARK_TEMPLATE(find_tweet, nlohmann_json)->UseManualTime();
} // namespace find_tweet
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
+68
View File
@@ -0,0 +1,68 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
#include "find_tweet.h"
namespace find_tweet {
using json = nlohmann::json;
struct nlohmann_json_sax {
using StringType=std::string;
struct Handler : json::json_sax_t
{
bool text_key = false;
bool id_key = false;
bool found_id = false;
uint64_t find_id;
std::string &result;
Handler(std::string &r,uint64_t id): result(r), find_id(id) { }
// We assume id is found before text
bool key(string_t& val) override {
if (found_id) { // If have found id, find text key
if (val.compare("text") == 0) { text_key = true; }
}
else if (val.compare("id") == 0) { id_key = true; } // Otherwise, find id key
return true;
}
bool number_unsigned(number_unsigned_t val) override {
if (id_key && (val == find_id)) { // If id key, check if id value matches find_id
found_id = true;
}
return true;
}
bool string(string_t& val) override {
if (text_key) {
result = val;
return false; // End parsing
}
return true;
}
// Irrelevant events
bool null() override { return true; }
bool boolean(bool val) override { return true; }
bool number_float(number_float_t val, const string_t& s) override { return true; }
bool number_integer(number_integer_t val) override { return true; }
bool start_object(std::size_t elements) override { return true; }
bool end_object() override { return true; }
bool start_array(std::size_t elements) override { return true; }
bool end_array() override { return true; }
bool binary(json::binary_t& val) override { return true; }
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) override { return false; }
}; // Handler
bool run(simdjson::padded_string &json, uint64_t find_id, std::string &result) {
Handler handler(result,find_id);
json::sax_parse(json.data(), &handler);
return true;
}
}; // nlohmann_json_sax
BENCHMARK_TEMPLATE(find_tweet, nlohmann_json_sax)->UseManualTime();
} // namespace find_tweet
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
+52
View File
@@ -0,0 +1,52 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
#include "find_tweet.h"
namespace find_tweet {
using namespace rapidjson;
struct rapidjson_base {
using StringType=std::string_view;
Document doc{};
bool run(Document &root, uint64_t find_id, std::string_view &result) {
if (root.HasParseError() || !root.IsObject()) { return false; }
auto statuses = root.FindMember("statuses");
if (statuses == root.MemberEnd() || !statuses->value.IsArray()) { return false; }
for (auto &tweet : statuses->value.GetArray()) {
if (!tweet.IsObject()) { return false; }
auto id = tweet.FindMember("id");
if (id == tweet.MemberEnd() || !id->value.IsUint64()) { return false; }
if (id->value.GetUint64() == find_id) {
auto text = tweet.FindMember("text");
if (text == tweet.MemberEnd() || !text->value.IsString()) { return false; }
result = { text->value.GetString(), text->value.GetStringLength() };
return true;
}
}
return false;
}
};
struct rapidjson : rapidjson_base {
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag>(json.data()), find_id, result);
}
};
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>(json.data()), find_id, result);
}
};
BENCHMARK_TEMPLATE(find_tweet, rapidjson_insitu)->UseManualTime();
} // namespace find_tweet
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+70
View File
@@ -0,0 +1,70 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
#include "find_tweet.h"
#include <string.h>
namespace find_tweet {
using namespace rapidjson;
struct rapidjson_sax {
using StringType=std::string_view;
struct Handler {
bool text_key = false;
bool id_key = false;
bool found_id = false;
uint64_t find_id;
std::string_view &result;
Handler(std::string_view &r,uint64_t id): result(r), find_id(id) { }
// We assume id is found before text
bool Key(const char* key, SizeType length, bool copy) {
if (found_id) { // If have found id, find text key
if ((length == 4) && (memcmp(key,"text",4) == 0)) { text_key = true; }
}
else if ((length == 2) && (memcmp(key,"id",2) == 0)) { id_key = true; } // Otherwise, find id key
return true;
}
bool Uint64(uint64_t i) {
if (id_key && (i == find_id)) { // If id key, check if id value matches find_id
found_id = true;
}
return true;
}
bool String(const char* str, SizeType length, bool copy) {
if (text_key) {
result = {str,length};
return false; // End parsing
}
return true;
}
// Irrelevant events
bool Null() { return true; }
bool Bool(bool b) { return true; }
bool Double(double d) { return true; }
bool Int(int i) { return true; }
bool Int64(int64_t i) { return true; }
bool Uint(unsigned i) { return true; }
bool RawNumber(const char* str, SizeType length, bool copy) { return true; }
bool StartObject() { return true; }
bool EndObject(SizeType memberCount) { return true; }
bool StartArray() { return true; }
bool EndArray(SizeType elementCount) { return true; }
}; // handler
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
Reader reader;
Handler handler(result,find_id);
InsituStringStream ss(json.data());
reader.Parse<kParseInsituFlag | kParseValidateEncodingFlag | kParseFullPrecisionFlag>(ss,handler);
return true;
}
}; // rapidjson_sax
BENCHMARK_TEMPLATE(find_tweet, rapidjson_sax)->UseManualTime();
} // namespace find_tweet
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+66
View File
@@ -0,0 +1,66 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_SAJSON
#include "find_tweet.h"
namespace find_tweet {
struct sajson {
using StringType=std::string_view;
size_t ast_buffer_size{0};
size_t *ast_buffer{nullptr};
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"; }
return { val.as_cstring(), val.get_string_length() };
}
simdjson_really_inline uint64_t get_str_uint64(const ::sajson::value &obj, std::string_view key) {
// Since sajson only supports 53-bit numbers, and IDs in twitter.json can be > 53 bits, we read the corresponding id_str and parse that.
auto val = obj.get_value_of_key({key.data(), key.length()});
if (val.get_type() != ::sajson::TYPE_STRING) { throw "field not a string"; }
auto str = val.as_cstring();
char *endptr;
uint64_t result = strtoull(str, &endptr, 10);
if (endptr != &str[val.get_string_length()]) { throw "field is a string, but not an integer string"; }
return result;
}
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
if (!ast_buffer) {
ast_buffer_size = json.size();
ast_buffer = (size_t *)std::malloc(ast_buffer_size * sizeof(size_t));
}
auto doc = ::sajson::parse(
::sajson::bounded_allocation(ast_buffer, ast_buffer_size),
::sajson::mutable_string_view(json.size(), json.data())
);
if (!doc.is_valid()) { return false; }
auto root = doc.get_root();
if (root.get_type() != ::sajson::TYPE_OBJECT) { printf("a\n"); return false; }
auto statuses = root.get_value_of_key({"statuses", strlen("statuses")});
if (statuses.get_type() != ::sajson::TYPE_ARRAY) { return false; }
for (size_t i=0; i<statuses.get_length(); i++) {
auto tweet = statuses.get_array_element(i);
if (tweet.get_type() != ::sajson::TYPE_OBJECT) { printf("b\n"); return false; }
// TODO if there is a way to get the raw string, it might be faster to iota find_id and then
// compare it to each id_str, instead of parsing each int and comparing to find_id.
if (get_str_uint64(tweet, "id_str") == find_id) {
result = get_string_view(tweet, "text");
return true;
}
}
return false;
}
};
BENCHMARK_TEMPLATE(find_tweet, sajson)->UseManualTime();
} // namespace find_tweet
#endif // SIMDJSON_COMPETITION_SAJSON
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#if SIMDJSON_EXCEPTIONS
#include "find_tweet.h"
namespace find_tweet {
using namespace simdjson;
struct simdjson_dom {
using StringType=std::string_view;
dom::parser parser{};
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
result = "";
auto doc = parser.parse(json);
for (auto tweet : doc["statuses"]) {
if (uint64_t(tweet["id"]) == find_id) {
result = tweet["text"];
return true;
}
}
return false;
}
};
BENCHMARK_TEMPLATE(find_tweet, simdjson_dom)->UseManualTime();
} // namespace find_tweet
#endif // SIMDJSON_EXCEPTIONS
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#if SIMDJSON_EXCEPTIONS
#include "find_tweet.h"
namespace find_tweet {
using namespace simdjson;
struct simdjson_ondemand {
using StringType=std::string_view;
ondemand::parser parser{};
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
// Walk the document, parsing as we go
auto doc = parser.iterate(json);
for (auto tweet : doc.find_field("statuses")) {
if (uint64_t(tweet.find_field("id")) == find_id) {
result = tweet.find_field("text");
return true;
}
}
return false;
}
};
BENCHMARK_TEMPLATE(find_tweet, simdjson_ondemand)->UseManualTime();
} // namespace find_tweet
#endif // SIMDJSON_EXCEPTIONS
+53
View File
@@ -0,0 +1,53 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_YYJSON
#include "find_tweet.h"
namespace find_tweet {
struct yyjson_base {
using StringType=std::string_view;
bool run(yyjson_doc *doc, uint64_t find_id, std::string_view &result) {
if (!doc) { return false; }
yyjson_val *root = yyjson_doc_get_root(doc);
if (!yyjson_is_obj(root)) { return false; }
yyjson_val *statuses = yyjson_obj_get(root, "statuses");
if (!yyjson_is_arr(statuses)) { return false; }
// Walk the document, parsing the tweets as we go
size_t tweet_idx, tweets_max;
yyjson_val *tweet;
yyjson_arr_foreach(statuses, tweet_idx, tweets_max, tweet) {
if (!yyjson_is_obj(tweet)) { return false; }
auto id = yyjson_obj_get(tweet, "id");
if (!yyjson_is_uint(id)) { return false; }
if (yyjson_get_uint(id) == find_id) {
auto text = yyjson_obj_get(tweet, "text");
if (yyjson_is_str(id)) { return false; }
result = { yyjson_get_str(text), yyjson_get_len(text) };
return true;
}
}
return false;
}
};
struct yyjson : yyjson_base {
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
return yyjson_base::run(yyjson_read(json.data(), json.size(), 0), find_id, result);
}
};
BENCHMARK_TEMPLATE(find_tweet, yyjson)->UseManualTime();
struct yyjson_insitu : yyjson_base {
bool run(simdjson::padded_string &json, uint64_t find_id, std::string_view &result) {
return yyjson_base::run(yyjson_read_opts(json.data(), json.size(), YYJSON_READ_INSITU, 0, 0), find_id, result);
}
};
BENCHMARK_TEMPLATE(find_tweet, yyjson_insitu)->UseManualTime();
} // namespace find_tweet
#endif // SIMDJSON_COMPETITION_YYJSON
+3 -3
View File
@@ -5,11 +5,11 @@
#include <iostream>
// Gigabyte: https://en.wikipedia.org/wiki/Gigabyte
never_inline
simdjson_never_inline
double bench(std::string filename, simdjson::padded_string& p) {
std::chrono::time_point<std::chrono::steady_clock> start_clock =
std::chrono::steady_clock::now();
simdjson::padded_string::load(filename).first.swap(p);
simdjson::padded_string::load(filename).value_unsafe().swap(p);
std::chrono::time_point<std::chrono::steady_clock> end_clock =
std::chrono::steady_clock::now();
std::chrono::duration<double> elapsed = end_clock - start_clock;
@@ -29,7 +29,7 @@ int main(int argc, char *argv[]) {
<< std::endl;
}
simdjson::padded_string p;
bench(filename, p);
bench(filename, p);
double meanval = 0;
double maxval = 0;
double minval = 10000;
+9
View File
@@ -0,0 +1,9 @@
#pragma once
namespace json_benchmark {
static constexpr const char *TWITTER_JSON = SIMDJSON_BENCHMARK_DATA_DIR "twitter.json";
static constexpr const char *NUMBERS_JSON = SIMDJSON_BENCHMARK_DATA_DIR "numbers.json";
static constexpr const char *AMAZON_CELLPHONES_NDJSON = SIMDJSON_BENCHMARK_DATA_DIR "amazon_cellphones.ndjson";
}
+143
View File
@@ -0,0 +1,143 @@
#pragma once
#include <vector>
#include <map>
#include <sstream>
#include <limits>
namespace json_benchmark {
enum class diff_flags {
NONE = 0,
IMPRECISE_FLOATS = 1
};
template<typename T, typename U>
static bool diff_results(benchmark::State &state, const T &result, const U &reference, diff_flags flags);
template<typename T, typename U>
struct result_differ {
static bool diff(benchmark::State &state, const T &result, const U &reference, diff_flags flags) {
if (result != reference) {
std::stringstream str;
str << "result incorrect: " << result << " ... reference: " << reference;
state.SkipWithError(str.str().data());
return false;
}
return true;
}
};
template<typename T, typename U>
struct result_differ<std::vector<T>, std::vector<U>> {
static bool diff(benchmark::State &state, const std::vector<T> &result, const std::vector<U> &reference, diff_flags flags) {
auto result_iter = result.begin();
auto reference_iter = reference.begin();
while (result_iter != result.end() && reference_iter != reference.end()) {
if (!diff_results(state, *result_iter, *reference_iter, flags)) { return false; }
result_iter++;
reference_iter++;
}
if (result_iter != result.end()) {
std::stringstream str;
str << "extra results (got " << result.size() << ", expected " << reference.size() << "): first extra element: " << *result_iter;
state.SkipWithError(str.str().data());
return false;
} else if (reference_iter != reference.end()) {
std::stringstream str;
str << "missing results (got " << result.size() << ", expected " << reference.size() << "): first missing element: " << *reference_iter;
state.SkipWithError(str.str().data());
return false;
}
return true;
}
};
template<typename T, typename U, typename StringType>
struct result_differ<std::map<StringType,T>, std::map<StringType,U>> {
static bool diff(benchmark::State &state, const std::map<StringType,T> &result, const std::map<StringType,U> &reference, diff_flags flags) {
auto result_iter = result.begin();
auto reference_iter = reference.begin();
while (result_iter != result.end() && reference_iter != reference.end()) {
if (!diff_results(state, *result_iter, *reference_iter, flags)) { return false; }
result_iter++;
reference_iter++;
}
if (result_iter != result.end()) {
std::stringstream str;
str << "extra results (got " << result.size() << ", expected " << reference.size() << "): first extra element: " << *result_iter;
state.SkipWithError(str.str().data());
return false;
} else if (reference_iter != reference.end()) {
std::stringstream str;
str << "missing results (got " << result.size() << ", expected " << reference.size() << "): first missing element: " << *reference_iter;
state.SkipWithError(str.str().data());
return false;
}
return true;
}
};
template<typename T, typename U>
struct result_differ<std::map<std::string_view,T>, std::vector<std::string_view,U>> {
static bool diff(benchmark::State &state, const std::map<std::string_view,T> &result, const std::map<std::string_view,U> &reference, diff_flags flags) {
auto result_iter = result.begin();
auto reference_iter = reference.begin();
while (result_iter != result.end() && reference_iter != reference.end()) {
if (!diff_results(state, *result_iter, *reference_iter, flags)) { return false; }
result_iter++;
reference_iter++;
}
if (result_iter != result.end()) {
std::stringstream str;
str << "extra results (got " << result.size() << ", expected " << reference.size() << "): first extra element: " << *result_iter;
state.SkipWithError(str.str().data());
return false;
} else if (reference_iter != reference.end()) {
std::stringstream str;
str << "missing results (got " << result.size() << ", expected " << reference.size() << "): first missing element: " << *reference_iter;
state.SkipWithError(str.str().data());
return false;
}
return true;
}
};
template<>
struct result_differ<double, double> {
static bool diff(benchmark::State &state, const double &result, const double &reference, diff_flags flags) {
bool different;
if (int(flags) & int(diff_flags::IMPRECISE_FLOATS)) {
different = f64_ulp_dist(result, reference) > 1;
} else {
different = result != reference;
}
if (different) {
std::stringstream str;
// We print it out using full precision.
constexpr auto precision = std::numeric_limits<double>::max_digits10;
str << std::setprecision(precision);
str << "incorrect double result: " << std::endl;
str << " result: " << std::left << std::setw(precision+2) << result << " (hexfloat " << std::hexfloat << result << ")" << std::defaultfloat << std::endl;
str << "reference: " << std::left << std::setw(precision+2) << reference << " (hexfloat " << std::hexfloat << reference << ")" << std::defaultfloat << std::endl;
state.SkipWithError(str.str().data());
}
return true;
}
static uint64_t f64_ulp_dist(double a, double b) {
uint64_t ua, ub;
std::memcpy(&ua, &a, sizeof(ua));
std::memcpy(&ub, &b, sizeof(ub));
if ((int64_t)(ub ^ ua) >= 0)
return (int64_t)(ua - ub) >= 0 ? (ua - ub) : (ub - ua);
return ua + ub + 0x80000000;
}
};
template<typename T, typename U>
static bool diff_results(benchmark::State &state, const T &result, const U &reference, diff_flags flags) {
return result_differ<T, U>::diff(state, result, reference, flags);
}
} // namespace json_benchmark
+48
View File
@@ -0,0 +1,48 @@
#pragma once
#include "json_benchmark/runner_base.h"
#include "simdjson.h"
namespace json_benchmark {
template<typename I>
struct file_runner : public runner_base<I> {
simdjson::padded_string original_json{};
simdjson::padded_string json{};
simdjson_warn_unused bool load_json(benchmark::State &state, const char *file) {
simdjson::error_code error;
if ((error = simdjson::padded_string::load(file).get(original_json))) {
std::stringstream err;
err << "error loading " << file << ": " << error;
state.SkipWithError(err.str().data());
return false;
}
json = simdjson::padded_string(original_json.data(), original_json.size());
return true;
}
simdjson_warn_unused bool before_run(benchmark::State &state) {
if (!runner_base<I>::after_run(state)) { return false; };
// Copy the original json in case we did *in situ* last time
std::memcpy(json.data(), original_json.data(), original_json.size());
return true;
}
/** Get the total number of bytes processed in each iteration. Used for metrics like bytes/second. */
size_t bytes_per_iteration() {
return json.size();
}
/** Get the total number of documents processed in each iteration. Used for metrics like documents/second. */
size_t documents_per_iteration() {
return 1;
}
/** Get the total number of items processed in each iteration. Used for metrics like items/second. */
size_t items_per_iteration() {
return 1;
}
};
} // namespace json_benchmark
+26
View File
@@ -0,0 +1,26 @@
#pragma once
#include "diff_results.h"
namespace json_benchmark {
struct point {
double x;
double y;
double z;
};
template<>
struct result_differ<point, point> {
static bool diff(benchmark::State &state, const point &result, const point &reference, diff_flags flags) {
return diff_results(state, result.x, reference.x, flags)
&& diff_results(state, result.y, reference.y, flags)
&& diff_results(state, result.z, reference.z, flags);
}
};
static simdjson_unused std::ostream &operator<<(std::ostream &o, const point &p) {
return o << p.x << "," << p.y << "," << p.z << std::endl;
}
} // namespace json_benchmark
@@ -0,0 +1,107 @@
#pragma once
#include "simdjson.h"
#include "event_counter.h"
#include <iostream>
namespace json_benchmark {
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::ondemand implementation (stage 2): " << simdjson::builtin_implementation()->name() << std::endl;
}
}
template<typename B, typename R> static void run_json_benchmark(benchmark::State &state) {
maybe_display_implementation();
event_collector collector(true);
event_aggregate events;
// Warmup and equality check (make sure the data is right!)
B bench;
if (!bench.setup(state)) { return; }
if (!bench.before_run(state)) { state.SkipWithError("warmup document before_run failed"); return; }
if (!bench.run(state)) { state.SkipWithError("warmup document reading failed"); return; }
if (!bench.after_run(state)) { state.SkipWithError("warmup document after_run failed"); return; }
{
R reference;
if (!reference.setup(state)) { return; }
if (!reference.before_run(state)) { state.SkipWithError("reference before_run failed"); };
if (!reference.run(state)) { state.SkipWithError("reference document reading failed"); return; }
if (!reference.after_run(state)) { state.SkipWithError("reference before_run failed"); };
if (!bench.diff(state, reference)) { return; }
}
// Run the benchmark
for (simdjson_unused auto _ : state) {
if (!bench.before_run(state)) { state.SkipWithError("before_run failed"); };
collector.start();
if (!bench.run(state)) { state.SkipWithError("run failed"); return; }
auto event = collector.end();
events << event;
state.SetIterationTime(event.elapsed_sec());
if (!bench.after_run(state)) { state.SkipWithError("after_run failed"); return; };
}
state.SetBytesProcessed(bench.bytes_per_iteration() * state.iterations());
state.SetItemsProcessed(bench.items_per_iteration() * state.iterations());
state.counters["best_docs_per_sec"] = benchmark::Counter(double(bench.documents_per_iteration()) / events.best.elapsed_sec());
state.counters["best_bytes_per_sec"] = benchmark::Counter(double(bench.bytes_per_iteration()) / events.best.elapsed_sec());
state.counters["best_items_per_sec"] = benchmark::Counter(double(bench.items_per_iteration()) / events.best.elapsed_sec());
state.counters["docs_per_sec"] = benchmark::Counter(double(bench.documents_per_iteration()), benchmark::Counter::kIsIterationInvariantRate);
if (collector.has_events()) {
state.counters["instructions"] = events.instructions();
state.counters["cycles"] = events.cycles();
state.counters["branch_miss"] = events.branch_misses();
state.counters["cache_miss"] = events.cache_misses();
state.counters["cache_ref"] = events.cache_references();
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());
state.counters["frequency"] = benchmark::Counter(events.cycles(), benchmark::Counter::kIsIterationInvariantRate);
state.counters["best_instructions"] = events.best.instructions();
state.counters["best_cycles"] = events.best.cycles();
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();
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();
state.counters["best_cycles_per_byte"] = events.best.cycles() / double(bench.bytes_per_iteration());
state.counters["best_frequency"] = events.best.cycles() / events.best.elapsed_sec();
}
state.counters["bytes"] = benchmark::Counter(double(bench.bytes_per_iteration()));
state.counters["items"] = benchmark::Counter(double(bench.items_per_iteration()));
// Build the label
using namespace std;
stringstream label;
label << fixed << setprecision(2);
label << "[BEST:";
label << " throughput=" << setw(6) << (double(bench.bytes_per_iteration()) / 1000000000.0 / events.best.elapsed_sec()) << " GB/s";
label << " doc_throughput=" << setw(6) << uint64_t(bench.documents_per_iteration() / events.best.elapsed_sec()) << " docs/s";
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);
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);
}
label << " items=" << setw(10) << bench.items_per_iteration() << setw(0);
label << " avg_time=" << setw(10) << uint64_t(events.elapsed_ns()) << setw(0) << " ns";
label << "]";
state.SetLabel(label.str());
}
} // namespace json_benchmark
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include "constants.h"
#include "run_json_benchmark.h"
#include "diff_results.h"
namespace json_benchmark {
//
// Extend this to create a new type of test (e.g. partial_tweets).
//
template<typename I>
struct runner_base {
/** Run once, before all iterations. */
simdjson_warn_unused bool setup(benchmark::State &) { return true; }
/** Run on each iteration. This is what gets benchmarked. */
simdjson_warn_unused bool run(benchmark::State &state) {
return implementation.run(state);
}
/** Called before each iteration, to clear / set up state. */
simdjson_warn_unused bool before_run(benchmark::State &state) { return true; }
/** Called after each iteration, to tear down / massage state. */
simdjson_warn_unused bool after_run(benchmark::State &) { return true; }
/** Get the total number of bytes processed in each iteration. Used for metrics like bytes/second. */
size_t bytes_per_iteration();
/** Get the total number of documents processed in each iteration. Used for metrics like documents/second. */
size_t documents_per_iteration();
/** Get the total number of items processed in each iteration. Used for metrics like items/second. */
size_t items_per_iteration();
I implementation{};
};
}
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include "runner_base.h"
#include "simdjson.h"
namespace json_benchmark {
template<typename I>
struct string_runner : public runner_base<I> {
const simdjson::padded_string &original_json;
simdjson::padded_string json;
string_runner(const simdjson::padded_string &_json) : original_json{_json}, json(original_json.data(), original_json.size()) {}
simdjson_warn_unused bool before_run(benchmark::State &state) {
if (!runner_base<I>::after_run(state)) { return false; };
// Copy the original json in case we did *in situ*
std::memcpy(json.data(), original_json.data(), original_json.size());
return true;
}
/** Get the total number of bytes processed in each iteration. Used for metrics like bytes/second. */
size_t bytes_per_iteration() {
return json.size();
}
/** Get the total number of documents processed in each iteration. Used for metrics like documents/second. */
size_t documents_per_iteration() {
return 1;
}
/** Get the total number of items processed in each iteration. Used for metrics like items/second. */
size_t items_per_iteration() {
return 1;
}
};
} // namespace json_benchmark
+86
View File
@@ -0,0 +1,86 @@
#pragma once
#include "json_benchmark/string_runner.h"
#include "json_benchmark/point.h"
#include <vector>
#include <random>
namespace kostya {
using namespace json_benchmark;
static const simdjson::padded_string &get_built_json_array();
template<typename I>
struct runner : public string_runner<I> {
std::vector<point> result;
runner() : string_runner<I>(get_built_json_array()) {}
bool before_run(benchmark::State &state) {
if (!string_runner<I>::before_run(state)) { return false; }
result.clear();
return true;
}
bool run(benchmark::State &) {
return this->implementation.run(this->json, result);
}
template<typename R>
bool diff(benchmark::State &state, runner<R> &reference) {
return diff_results(state, result, reference.result, I::DiffFlags);
}
size_t items_per_iteration() {
return result.size();
}
};
static void append_coordinate(std::default_random_engine &e, std::uniform_real_distribution<> &dis, std::stringstream &myss) {
using std::endl;
myss << R"( {)" << endl;
myss << R"( "x": )" << dis(e) << "," << endl;
myss << R"( "y": )" << dis(e) << "," << endl;
myss << R"( "z": )" << dis(e) << "," << endl;
myss << R"( "name": ")" << char('a'+dis(e)*25) << char('a'+dis(e)*25) << char('a'+dis(e)*25) << char('a'+dis(e)*25) << char('a'+dis(e)*25) << char('a'+dis(e)*25) << " " << int(dis(e)*10000) << "\"," << endl;
myss << R"( "opts": {)" << endl;
myss << R"( "1": [)" << endl;
myss << R"( 1,)" << endl;
myss << R"( true)" << endl;
myss << R"( ])" << endl;
myss << R"( })" << endl;
myss << R"( })";
}
static std::string build_json_array(size_t N) {
using namespace std;
default_random_engine e;
uniform_real_distribution<> dis(0, 1);
stringstream myss;
myss << R"({)" << endl;
myss << R"( "coordinates": [)" << endl;
for (size_t i=1; i<N; i++) {
append_coordinate(e, dis, myss); myss << "," << endl;
}
append_coordinate(e, dis, myss); myss << endl;
myss << R"( ],)" << endl;
myss << R"( "info": "some info")" << endl;
myss << R"(})" << endl;
string answer = myss.str();
cout << "Creating a source file spanning " << (answer.size() + 512) / 1024 << " KB " << endl;
return answer;
}
static const simdjson::padded_string &get_built_json_array() {
static simdjson::padded_string json = build_json_array(524288);
return json;
}
struct simdjson_dom;
template<typename I> simdjson_really_inline static void kostya(benchmark::State &state) {
run_json_benchmark<runner<I>, runner<simdjson_dom>>(state);
}
} // namespace kostya
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
#include "kostya.h"
namespace kostya {
struct nlohmann_json {
static constexpr diff_flags DiffFlags = diff_flags::NONE;
bool run(simdjson::padded_string &json, std::vector<point> &result) {
auto root = nlohmann::json::parse(json.data(), json.data() + json.size());
for (auto point : root["coordinates"]) {
result.emplace_back(json_benchmark::point{point["x"], point["y"], point["z"]});
}
return true;
}
};
BENCHMARK_TEMPLATE(kostya, nlohmann_json)->UseManualTime();
} // namespace kostya
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
+74
View File
@@ -0,0 +1,74 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_NLOHMANN_JSON
#include "kostya.h"
namespace kostya {
using json = nlohmann::json;
struct nlohmann_json_sax {
static constexpr diff_flags DiffFlags = diff_flags::NONE;
struct Handler : json::json_sax_t
{
size_t k{0};
double buffer[3];
std::vector<point>& result;
Handler(std::vector<point>& r) : result(r) { }
bool key(string_t& val) override {
switch(val[0]) {
case 'x':
k = 0;
break;
case 'y':
k = 1;
break;
case 'z':
k = 2;
break;
}
return true;
}
bool number_float(number_float_t val, const string_t& s) override {
buffer[k] = val;
if (k == 2) {
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
k = 0;
}
return true;
}
bool number_unsigned(number_unsigned_t val) override { // Need this event because coordinate value can be equal to 1
buffer[k] = val;
if (k == 2) {
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
k = 0;
}
return true;
}
// Irrelevant events
bool null() override { return true; }
bool boolean(bool val) override { return true; }
bool number_integer(number_integer_t val) override { return true; }
bool string(string_t& val) override { return true; }
bool start_object(std::size_t elements) override { return true; }
bool end_object() override { return true; }
bool start_array(std::size_t elements) override { return true; }
bool end_array() override { return true; }
bool binary(json::binary_t& val) override { return true; }
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) override { return false; }
}; // Handler
bool run(simdjson::padded_string &json, std::vector<point> &result) {
Handler handler(result);
json::sax_parse(json.data(), &handler);
return true;
}
}; // nlohmann_json_sax
BENCHMARK_TEMPLATE(kostya, nlohmann_json_sax)->UseManualTime();
} // namespace kostya
#endif // SIMDJSON_COMPETITION_NLOHMANN_JSON
+61
View File
@@ -0,0 +1,61 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
#include "kostya.h"
namespace kostya {
using namespace rapidjson;
struct rapidjson_base {
static constexpr diff_flags DiffFlags = diff_flags::NONE;
Document doc;
simdjson_really_inline double get_double(Value &object, std::string_view key) {
auto field = object.FindMember(key.data());
if (field == object.MemberEnd()) { throw "Missing double field"; }
if (!field->value.IsNumber()) { throw "Field is not double"; }
return field->value.GetDouble();
}
bool run(Document &root, std::vector<point> &result) {
if (root.HasParseError()) { return false; }
if (!root.IsObject()) { return false; }
auto coords = root.FindMember("coordinates");
if (coords == root.MemberEnd()) { return false; }
if (!coords->value.IsArray()) { return false; }
for (auto &coord : coords->value.GetArray()) {
if (!coord.IsObject()) { return false; }
result.emplace_back(json_benchmark::point{get_double(coord, "x"), get_double(coord, "y"), get_double(coord, "z")});
}
return true;
}
};
struct rapidjson : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(kostya, rapidjson)->UseManualTime();
struct rapidjson_lossless : rapidjson_base {
bool run(simdjson::padded_string &json, std::vector<point> &result) {
return rapidjson_base::run(doc.Parse<kParseValidateEncodingFlag | kParseFullPrecisionFlag>(json.data()), result);
}
};
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>(json.data()), result);
}
};
BENCHMARK_TEMPLATE(kostya, rapidjson_insitu)->UseManualTime();
} // namespace kostya
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+70
View File
@@ -0,0 +1,70 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_RAPIDJSON
#include "kostya.h"
namespace kostya {
using namespace rapidjson;
struct rapidjson_sax {
static constexpr diff_flags DiffFlags = diff_flags::NONE;
struct Handler {
size_t k{0};
double buffer[3];
std::vector<point>& result;
Handler(std::vector<point> &r) : result(r) { }
bool Key(const char* key, SizeType length, bool copy) {
switch(key[0]) {
case 'x':
k = 0;
break;
case 'y':
k = 1;
break;
case 'z':
k = 2;
break;
}
return true;
}
bool Double(double d) {
buffer[k] = d;
if (k == 2) {
result.emplace_back(json_benchmark::point{buffer[0],buffer[1],buffer[2]});
k = 0;
}
return true;
}
bool Uint(unsigned i) { return Double(i); } // Need this event because coordinate value can be equal to 1
// Irrelevant events
bool Null() { return true; }
bool Bool(bool b) { return true; }
bool Int(int i) { return true; }
bool Int64(int64_t i) { return true; }
bool Uint64(uint64_t i) { return true; }
bool RawNumber(const char* str, SizeType length, bool copy) { return true; }
bool String(const char* str, SizeType length, bool copy) { return true; }
bool StartObject() { return true; }
bool EndObject(SizeType memberCount) { return true; }
bool StartArray() { return true; }
bool EndArray(SizeType elementCount) { return true; }
}; // handler
bool run(simdjson::padded_string &json, std::vector<point> &result) {
Reader reader;
Handler handler(result);
InsituStringStream ss(json.data());
reader.Parse<kParseInsituFlag | kParseValidateEncodingFlag | kParseFullPrecisionFlag>(ss,handler);
return true;
}
}; // rapid_jason_sax
BENCHMARK_TEMPLATE(kostya, rapidjson_sax)->UseManualTime();
} // namespace kostya
#endif // SIMDJSON_COMPETITION_RAPIDJSON
+65
View File
@@ -0,0 +1,65 @@
#pragma once
#ifdef SIMDJSON_COMPETITION_SAJSON
#include "kostya.h"
namespace kostya {
struct sajson {
static constexpr diff_flags DiffFlags = diff_flags::IMPRECISE_FLOATS;
size_t ast_buffer_size{0};
size_t *ast_buffer{nullptr};
simdjson_really_inline double get_double(const ::sajson::value &obj, std::string_view key) {
using namespace sajson;
auto val = obj.get_value_of_key({key.data(), key.length()});
switch (val.get_type()) {
case TYPE_INTEGER:
case TYPE_DOUBLE:
return val.get_number_value();
default:
throw "field not double";
}
}
bool run(simdjson::padded_string &json, std::vector<point> &result) {
using namespace sajson;
if (!ast_buffer) {
ast_buffer_size = json.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(json.size(), json.data())
);
if (!doc.is_valid()) { return false; }
auto root = doc.get_root();
if (root.get_type() != TYPE_OBJECT) { return false; }
auto points = root.get_value_of_key({"coordinates", strlen("coordinates")});
if (points.get_type() != TYPE_ARRAY) { return false; }
for (size_t i=0; i<points.get_length(); i++) {
auto point = points.get_array_element(i);
if (point.get_type() != TYPE_OBJECT) { return false; }
result.emplace_back(json_benchmark::point{
get_double(point, "x"),
get_double(point, "y"),
get_double(point, "z")
});
}
return true;
}
};
BENCHMARK_TEMPLATE(kostya, sajson)->UseManualTime();
} // namespace kostya
#endif // SIMDJSON_COMPETITION_SAJSON

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