2020-03-26 01:53:24 +08:00
|
|
|
CPU Architecture-Specific Implementations
|
|
|
|
=========================================
|
|
|
|
|
|
|
|
* [Overview](#overview)
|
|
|
|
* [Runtime CPU Detection](#runtime-cpu-detection)
|
|
|
|
* [Inspecting the Detected Implementation](#inspecting-the-detected-implementation)
|
|
|
|
* [Querying Available Implementations](#querying-available-implementations)
|
|
|
|
* [Manually Selecting the Implementation](#manually-selecting-the-implementation)
|
2020-10-02 23:04:51 +08:00
|
|
|
* [Checking that an Implementation can Run on your System](#checking-that-an-implementation-can-run-on-your-system)
|
2020-03-26 01:53:24 +08:00
|
|
|
|
|
|
|
Overview
|
|
|
|
--------
|
|
|
|
|
|
|
|
The simdjson library takes advantage of SIMD instruction sets such as NEON, SSE and AVX to achieve
|
|
|
|
much of its speed. Because these instruction sets work differently, simdjson has to compile a
|
|
|
|
different version of the JSON parser for different CPU architectures, often with different
|
|
|
|
algorithms to take better advantage of a given CPU!
|
|
|
|
|
|
|
|
The current implementations are:
|
|
|
|
* haswell: AVX2 (2013 Intel Haswell or later)
|
|
|
|
* westmere: SSE4.2 (2010 Westmere or later).
|
|
|
|
* arm64: 64-bit ARMv8-A NEON
|
|
|
|
* fallback: A generic implementation that runs on any 64-bit processor.
|
|
|
|
|
|
|
|
In many cases, you don't know where your compiled binary is going to run, so simdjson automatically
|
|
|
|
compiles *all* the implementations into the executable. On Intel, it will include 3 implementations
|
|
|
|
(haswell, westmere and fallback), and on ARM it will include 2 (arm64 and fallback).
|
|
|
|
|
|
|
|
If you know more about where you're going to run and want to save the space, you can disable any of
|
|
|
|
these implementations at compile time with `-DSIMDJSON_IMPLEMENTATION_X=0` (where X is HASWELL,
|
|
|
|
WESTMERE, ARM64 and FALLBACK).
|
|
|
|
|
|
|
|
The simdjson library automatically sets header flags for each implementation as it compiles; there
|
|
|
|
is no need to set architecture-specific flags yourself (e.g., `-mavx2`, `/AVX2` or
|
|
|
|
`-march=haswell`), and it may even break runtime dispatch and your binaries will fail to run on
|
|
|
|
older processors.
|
|
|
|
|
|
|
|
Runtime CPU Detection
|
|
|
|
---------------------
|
|
|
|
|
|
|
|
When you first use simdjson, it will detect the CPU you're running on, and swap over to the fastest
|
|
|
|
implementation for it. This is a small, one-time cost and for many people will be paid the first
|
|
|
|
time they call `parse()` or `load()`.
|
|
|
|
|
|
|
|
Inspecting the Detected Implementation
|
|
|
|
--------------------------------------
|
|
|
|
|
|
|
|
You can check what implementation is running with `active_implementation`:
|
|
|
|
|
|
|
|
```c++
|
2020-06-30 04:25:11 +08:00
|
|
|
cout << "simdjson v" << STRINGIFY(SIMDJSON_VERSION) << endl;
|
2020-03-26 01:53:24 +08:00
|
|
|
cout << "Detected the best implementation for your machine: " << simdjson::active_implementation->name();
|
|
|
|
cout << "(" << simdjson::active_implementation->description() << ")" << endl;
|
|
|
|
```
|
|
|
|
|
|
|
|
Implementation detection will happen in this case when you first call `name()`.
|
|
|
|
|
|
|
|
Querying Available Implementations
|
|
|
|
----------------------------------
|
|
|
|
|
|
|
|
You can list all available implementations, regardless of which one was selected:
|
|
|
|
|
|
|
|
```c++
|
|
|
|
for (auto implementation : simdjson::available_implementations) {
|
|
|
|
cout << implementation->name() << ": " << implementation->description() << endl;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
And look them up by name:
|
|
|
|
|
|
|
|
```c++
|
|
|
|
cout << simdjson::available_implementations["fallback"]->description() << endl;
|
|
|
|
```
|
2020-10-02 23:04:51 +08:00
|
|
|
Though the fallback implementation should always be available, others might be missing. When
|
|
|
|
an implementation is not available, the bracket call `simdjson::available_implementations[name]`
|
|
|
|
will return the null pointer.
|
|
|
|
|
|
|
|
The available implementations have been compiled but may not necessarily be run safely on your system
|
|
|
|
see [Checking that an Implementation can Run on your System](#checking-that-an-implementation-can-run-on-your-system).
|
|
|
|
|
|
|
|
|
2020-03-26 01:53:24 +08:00
|
|
|
|
|
|
|
Manually Selecting the Implementation
|
|
|
|
-------------------------------------
|
|
|
|
|
|
|
|
If you're trying to do performance tests or see how different implementations of simdjson run, you
|
|
|
|
can select the CPU architecture yourself:
|
|
|
|
|
|
|
|
```c++
|
|
|
|
// Use the fallback implementation, even though my machine is fast enough for anything
|
|
|
|
simdjson::active_implementation = simdjson::available_implementations["fallback"];
|
|
|
|
```
|
2020-10-02 23:04:51 +08:00
|
|
|
|
|
|
|
You are responsible for ensuring that the requirements of the selected implementation match your current system.
|
|
|
|
Furthermore, you should check that the implementation is available before setting it to `simdjson::active_implementation`
|
|
|
|
by comparing it with the null pointer.
|
|
|
|
|
|
|
|
```c++
|
|
|
|
auto my_implementation = simdjson::available_implementations["haswell"];
|
|
|
|
if(! my_implementation) { exit(1); }
|
|
|
|
if(! my_implementation->supported_by_runtime_system()) { exit(1); }
|
|
|
|
simdjson::active_implementation = my_implementation;
|
|
|
|
```
|
|
|
|
|
|
|
|
Checking that an Implementation can Run on your System
|
|
|
|
-------------------------------------
|
|
|
|
|
|
|
|
You should call `supported_by_runtime_system()` to compare the processor's features with the need of the implementation.
|
|
|
|
|
|
|
|
```c++
|
|
|
|
for (auto implementation : simdjson::available_implementations) {
|
|
|
|
if(implementation->supported_by_runtime_system()) {
|
|
|
|
cout << implementation->name() << ": " << implementation->description() << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
The call to `supported_by_runtime_system()` maybe relatively expensive. Do not call `supported_by_runtime_system()` each
|
|
|
|
time you parse a JSON input (for example). It is meant to be called a handful of times at most in the life of a program.
|