Files
simdjson-simdjson/md_doc_2performance.html
2026-05-06 21:54:39 +00:00

349 lines
37 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen 1.9.8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>simdjson: Performance Notes</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="doxygen-awesome.css" rel="stylesheet" type="text/css"/>
<link href="doxygen-awesome-sidebar-only.css" rel="stylesheet" type="text/css"/>
<link href="doxygen-awesome-sidebar-only-darkmode-toggle.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr id="projectrow">
<td id="projectlogo"><img alt="Logo" src="logotiny.png"/></td>
<td id="projectalign">
<div id="projectname">simdjson<span id="projectnumber">&#160;4.6.4</span>
</div>
<div id="projectbrief">Ridiculously Fast JSON</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.9.8 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
var searchBox = new SearchBox("searchBox", "search/",'.html');
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(function() {
initMenu('',true,false,'search.php','Search');
$(document).ready(function() { init_search(); });
});
/* @license-end */
</script>
<div id="main-nav"></div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
<div id="nav-tree">
<div id="nav-tree-contents">
<div id="nav-sync" class="sync"></div>
</div>
</div>
<div id="splitbar" style="-moz-user-select:none;"
class="ui-resizable-handle">
</div>
</div>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&amp;dn=expat.txt MIT */
$(document).ready(function(){initNavTree('md_doc_2performance.html',''); initResizable(); });
/* @license-end */
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<div id="MSearchResults">
<div class="SRPage">
<div id="SRIndex">
<div id="SRResults"></div>
<div class="SRStatus" id="Loading">Loading...</div>
<div class="SRStatus" id="Searching">Searching...</div>
<div class="SRStatus" id="NoMatches">No Matches</div>
</div>
</div>
</div>
</div>
<div><div class="header">
<div class="headertitle"><div class="title">Performance Notes</div></div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>simdjson strives to be at its fastest <em>without tuning</em>, and generally achieves this. However, there are still some scenarios where tuning can enhance performance. Once your code is tested, we further encourage you to define <code>NDEBUG</code> in your release builds to disable additional runtime testing and get the best performance.</p><ul>
<li>NDEBUG macro</li>
<li>Reusing the parser for maximum efficiency</li>
<li>Reusing string buffers</li>
<li>Server Loops: Long-Running Processes and Memory Capacity</li>
<li>Large files and huge page support</li>
<li>Number parsing</li>
<li>Visual Studio</li>
<li>Power Usage and Downclocking</li>
<li>Free Padding</li>
</ul>
<h1><a class="anchor" id="autotoc_md149"></a>
NDEBUG macro</h1>
<p>We recommend that you set <code>NDEBUG</code> macro in your release builds.</p>
<p>In C/C++, the <code>NDEBUG</code> macro is not set by default. When it is not set, the software may do many additional checks that may impact negatively the performance. We recommend that, once your code is well tested, you define <code>NDEBUG</code> directive in your release builds.</p>
<p>The <code>NDEBUG</code> directive is generally independent from optimization flags. For example, setting <code>-O3</code> under GCC does not set the <code>NDEBUG</code> directive. However, tools like <code>CMake</code> automatically set <code>NDEBUG</code> for release builds.</p>
<p>In the simdjson library, we check the <code>NDEBUG</code> macro as well as other macros to make performant release builds. However, the C++ standard does not provide a definitive approach to determine whether you are compiling for a release build. Thus we recommend that you follow the practice of setting the <code>NDEBUG</code> macro in release mode to make sure that you do not get undesirable expensive checks.</p>
<h1><a class="anchor" id="autotoc_md150"></a>
Reusing the parser for maximum efficiency</h1>
<p>If you're using simdjson to parse multiple documents, or in a loop, you should make a parser once and reuse it. The simdjson library will allocate and retain internal buffers between parses, keeping buffers hot in cache and keeping memory allocation and initialization to a minimum. In this manner, you can parse terabytes of JSON data without doing any new allocation.</p>
<div class="fragment"><div class="line">ondemand::parser parser;</div>
<div class="line"> </div>
<div class="line"><span class="comment">// This initializes buffers big enough to handle this JSON.</span></div>
<div class="line"><span class="keyword">auto</span> json = <span class="stringliteral">&quot;[ true, false ]&quot;</span>_padded;</div>
<div class="line"><span class="keyword">auto</span> doc = parser.iterate(json);</div>
<div class="line"><span class="keywordflow">for</span>(<span class="keywordtype">bool</span> i : doc.get_array()) {</div>
<div class="line"> cout &lt;&lt; i &lt;&lt; endl;</div>
<div class="line">}</div>
<div class="line"> </div>
<div class="line"><span class="comment">// This reuses the existing buffers</span></div>
<div class="line"><span class="keyword">auto</span> number_json = <span class="stringliteral">&quot;[1, 2, 3]&quot;</span>_padded;</div>
<div class="line">doc = parser.iterate(number_json);</div>
<div class="line"><span class="keywordflow">for</span>(int64_t i : doc.get_array()) {</div>
<div class="line"> cout &lt;&lt; i &lt;&lt; endl;</div>
<div class="line">}</div>
</div><!-- fragment --><h1><a class="anchor" id="autotoc_md151"></a>
Reusing string buffers</h1>
<p>We recommend against creating many <code>std::string</code> or <code><a class="el" href="structsimdjson_1_1padded__string.html" title="String with extra allocation for ease of use with parser::parse()">simdjson::padded_string</a></code> instances to store the JSON content in your application. <a href="https://lemire.me/blog/2020/08/08/performance-tip-constructing-many-non-trivial-objects-is-slow/">Creating many non-trivial objects is convenient but often surprisingly slow</a>. Instead, as much as possible, you should allocate (once or a few times) reusable memory buffers where you write your JSON content. If you have a buffer <code>json_str</code> (of type <code>char*</code>) allocated for <code>capacity</code> bytes and you store a JSON document spanning <code>length</code> bytes, you can pass it to simdjson as follows:</p>
<div class="fragment"><div class="line"><span class="keyword">auto</span> doc = parser.iterate(padded_string_view(json_str, length, capacity));</div>
</div><!-- fragment --><p>or simply</p>
<div class="fragment"><div class="line"><span class="keyword">auto</span> doc = parser.iterate(json_str, length, capacity);</div>
</div><!-- fragment --><h1><a class="anchor" id="autotoc_md152"></a>
Server Loops: Long-Running Processes and Memory Capacity</h1>
<p>The On-Demand approach also automatically expands its memory capacity when larger documents are parsed. However, for longer processes where very large files are processed (such as server loops), this capacity is not resized down. On-Demand also lets you adjust the maximal capacity that the parser can process:</p>
<ul>
<li>You can set an upper bound (<em>max_capacity</em>) when construction the parser: <div class="fragment"><div class="line">ondemand::parser parser(1000*1000); <span class="comment">// Never grows past documents &gt; 1 MB</span></div>
<div class="line"><span class="keyword">auto</span> doc = parser.iterate(json);</div>
<div class="line"><span class="keywordflow">for</span> (web_request request : listen()) {</div>
<div class="line"> padded_string json;</div>
<div class="line"> padded_string json = padded_string::load(request.body);</div>
<div class="line"> <span class="keyword">auto</span> error = parser.iterate(json);</div>
<div class="line"> <span class="comment">// If the document was above our limit, emit 413 = payload too large</span></div>
<div class="line"> <span class="keywordflow">if</span> (error == CAPACITY) { request.respond(413); <span class="keywordflow">continue</span>; }</div>
<div class="line"> <span class="comment">// ...</span></div>
<div class="line">}</div>
</div><!-- fragment --></li>
</ul>
<p>The capacity will grow as the parser encounters larger documents up to 1 MB.</p>
<ul>
<li>You can also allocate a <em>fixed capacity</em> that will never grow: <div class="fragment"><div class="line">ondemand::parser parser(1000*1000);</div>
<div class="line">parser.allocate(1000*1000) <span class="comment">// Fix the capacity to 1 MB</span></div>
<div class="line"><span class="keyword">auto</span> doc = parser.iterate(json);</div>
<div class="line"><span class="keywordflow">for</span> (web_request request : listen()) {</div>
<div class="line"> padded_string json;</div>
<div class="line"> padded_string json = padded_string::load(request.body);</div>
<div class="line"> <span class="keyword">auto</span> error = parser.iterate(json);</div>
<div class="line"> <span class="comment">// If the document was above our limit, emit 413 = payload too large</span></div>
<div class="line"> <span class="keywordflow">if</span> (error == CAPACITY) { request.respond(413); <span class="keywordflow">continue</span>; }</div>
<div class="line"> <span class="comment">// ...</span></div>
<div class="line">}</div>
</div><!-- fragment --> You can also manually set the maximal capacity using the method <code>set_max_capacity()</code>.</li>
</ul>
<h1><a class="anchor" id="autotoc_md153"></a>
Large files and huge page support</h1>
<p>There is a memory allocation performance cost the first time you process a large file (e.g. 100MB). Between the cost of allocation, the fact that the memory is not in cache, and the initial zeroing of memory, <a href="https://lemire.me/blog/2020/01/14/how-fast-can-you-allocate-a-large-block-of-memory-in-c/">on some systems, allocation runs far slower than parsing (e.g., 1.4GB/s)</a>. Reusing the parser mitigates this by paying the cost once, but does not eliminate it.</p>
<p>In large file use cases, enabling transparent huge page allocation on the OS can help a lot. We haven't found the right way to do this on Windows or OS/X, but on Linux, you can enable transparent huge page allocation with a command like:</p>
<div class="fragment"><div class="line">echo always &gt; /sys/kernel/mm/transparent_hugepage/enabled</div>
</div><!-- fragment --><p>In general, when running benchmarks over large files, we recommend that you report performance numbers with and without huge pages if possible. Furthermore, you should amortize the parsing (e.g., by parsing several large files) to distinguish the time spent parsing from the time spent allocating memory. If you are using the <code>parse</code> benchmarking tool provided with the simdjson library, you can use the <code>-H</code> flag to omit the memory allocation cost from the benchmark results.</p>
<div class="fragment"><div class="line">./parse largefile # includes memory allocation cost</div>
<div class="line">./parse -H largefile # without memory allocation</div>
</div><!-- fragment --><h1><a class="anchor" id="autotoc_md154"></a>
Number parsing</h1>
<p>Some JSON files contain many floating-point values. It is the case with many GeoJSON files. Accurately parsing decimal strings into binary floating-point values with proper rounding is challenging. To our knowledge, it is not possible, in general, to parse streams of numbers at gigabytes per second using a single core. While using the simdjson library, it is possible that you might be limited to a few hundred megabytes per second if your JSON documents are densely packed with floating-point values.</p>
<ul>
<li>When possible, you should favor integer values written without a decimal point, as it simpler and faster to parse decimal integer values.</li>
<li>When serializing numbers, you should not use more digits than necessary: 17 digits is all that is needed to exactly represent double-precision floating-point numbers. Using many more digits than necessary will make your files larger and slower to parse.</li>
<li>When benchmarking parsing speeds, always report whether your JSON documents are made mostly of floating-point numbers when it is the case, since number parsing can then dominate the parsing time.</li>
</ul>
<h1><a class="anchor" id="autotoc_md155"></a>
Visual Studio</h1>
<p>On Intel and AMD Windows platforms, Microsoft Visual Studio enables programmers to build either 32-bit (x86) or 64-bit (x64 or ARM64) binaries. We urge you to always use 64-bit mode. Visual Studio 2019 should default on 64-bit builds when you have a 64-bit version of Windows, which we recommend.</p>
<p>When compiling with Visual Studio, we recommend the flags <code>/Ob2 /O2</code> or better. We do not recommend that you compile simdjson with architecture-specific flags such as <code>arch:AVX2</code>. The simdjson library automatically selects the best execution kernel at runtime.</p>
<p>Recent versions of Microsoft Visual Studio on Windows provides support for the LLVM Clang compiler. You only need to install the "Clang compiler" optional component (clang-cl). You may also get a copy of the 64-bit LLVM CLang compiler for <a href="https://releases.llvm.org/download.html">Windows directly from LLVM</a>. The simdjson library fully supports the LLVM Clang compiler under Windows. In fact, you may get better performance out of simdjson with the LLVM Clang compiler than with the regular Visual Studio compiler. Meanwhile the <a href="https://clang.llvm.org/docs/MSVCCompatibility.html">LLVM CLang compiler is binary compatible with Visual Studio</a> which means that you can combine their binaries (executables and libraries).</p>
<p>We recommend Visual Studio users prefer LLVM (clang-cl). It compiles to faster release binaries. Furthermore, it compilers faster in release mode.</p>
<h1><a class="anchor" id="autotoc_md156"></a>
Power Usage and Downclocking</h1>
<p>The simdjson library relies on SIMD instructions. SIMD instructions are the public transportation of computing. Instead of using 4 distinct instructions to add numbers, you can replace them with a single instruction that does the same work. Though the one instruction is slightly more expensive, the energy used per unit of work is much less with SIMD. If you can increase your speed using SIMD instructions (NEON, SSE, AVX), you should expect to reduce your power usage.</p>
<p>The SIMD instructions that simdjson relies upon (SSE and AVX under x64, NEON under ARM, ALTIVEC under PPC) are routinely part of runtime libraries (e.g., <a href="https://golang.org/src/runtime/memmove_amd64.s">Go</a>, <a href="https://github.com/ihtsae/glibc/commit/5f3d0b78e011d2a72f9e88b0e9ef5bc081d18f97">Glibc</a>, <a href="https://github.com/llvm/llvm-project/blob/96f3ea0d21b48ca088355db10d4d1a2e9bc9f884/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp">LLVM</a>, <a href="https://github.com/rust-lang/rust/commit/070fad1701fb36b112853b0a6a9787a7bb7ff34c">Rust</a>, <a href="http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/c1374141598c/src/cpu/x86/vm/stubGenerator_x86_64.cpp#l1297">Java</a>, <a href="https://github.com/php/php-src/blob/e5cb53ec68603d4dbdd780fd3ecfca943b4fd383/ext/standard/string.c">PHP</a>). What distinguishes the simdjson library is that it is built from the ground up to benefit from these instructions.</p>
<p>You should not expect the simdjson library to cause <em>downclocking</em> of your recent Intel CPU cores. On some Intel processors, using SIMD instructions in a sustained manner on the same CPU core may result in a phenomenon called downclocking whereas the processor initially runs these instructions at a slow speed before reducing the frequency of the core for a short time (milliseconds). Intel refers to these states as licenses. On some current Intel processors, it occurs under two scenarios:</p>
<ul>
<li><a href="https://lemire.me/blog/2018/09/07/avx-512-when-and-how-to-use-these-new-instructions/">Whenever 512-bit AVX-512 instructions are used</a>.</li>
<li>Whenever heavy 256-bit or wider instructions are used. Heavy instructions are those involving floating point operations or integer multiplications (since these execute on the floating point unit).</li>
</ul>
<p>The simdjson library does not generally make use of heavy 256-bit instructions. On AVX2 kernels, we use vectorized multiplications, but only using 128-bit registers. On recent processors (Ice Lake/Tiger Lake or better, AMD Zen 4 or better) <a href="https://travisdowns.github.io/blog/2020/08/19/icl-avx512-freq.html">no frequency throttling is found</a> due to SIMD instructions: we are thus more aggressive with SIMD on these machines. If you can still concerned, you can easily disable AVX-512 with the CMake option <code>SIMDJSON_AVX512_ALLOWED</code> set to <code>OFF</code> (e.g., <code>cmake -D SIMDJSON_AVX512_ALLOWED=OFF -B build &amp;&amp; cmake --build build</code>) or by setting the macro <code>SIMDJSON_AVX512_ALLOWED</code> to <code>0</code> in C++ prior to importing the headers.</p>
<p>You may still be worried about which SIMD instruction set is used by simdjson. Thankfully, <a class="el" href="md_doc_2implementation-selection.html">you can always determine and change which architecture-specific implementation is used</a> by simdjson. Thus even if your CPU supports AVX2, you do not need to use AVX2. You are in control.</p>
<h1><a class="anchor" id="autotoc_md157"></a>
Free Padding</h1>
<p>For performance reasons, the simdjson library requires that the JSON input contain at least <code><a class="el" href="namespacesimdjson.html#aecdd750132f0eb123a6d61113b4197bf" title="The amount of padding needed in a buffer to parse JSON.">simdjson::SIMDJSON_PADDING</a></code> bytes at the end of the stream. The value <code><a class="el" href="namespacesimdjson.html#aecdd750132f0eb123a6d61113b4197bf" title="The amount of padding needed in a buffer to parse JSON.">simdjson::SIMDJSON_PADDING</a></code> is small (e.g., 64 bytes). On modern systems, you can safely read beyond an allocated buffers, as long as you remain within an allocated page. Pages on modern systems span at least 4 kilobytes, but can be significantly larger. E.g., Apple systems favour pages spanning 16 kilobytes.</p>
<p>In effect, it means that you can almost always read a few bytes beyond your current buffer&mdash;without allocating extra memory. However, tools such as valgrind or memory sanitizers will flag such behavior as unsafe. Nevertheless, you can still make sure of this capability in your code if you are an expert programmer and you are willing to silence sanitizer warnings. The following code provides a portable example.</p>
<p>The conditional compilation checks for the <code>_MSC_VER</code> macro (indicating Microsoft Visual Studio) and includes platform-specific headers accordingly. The <code>page_size()</code> function determines the default size of a memory page in bytes on the system. On Windows (when <code>_WIN32</code> is defined), it uses <code>GetSystemInfo()</code> to retrieve system information and obtain the page size. On other platforms (non-Windows), it uses <code>sysconf(_SC_PAGESIZE)</code> to get the page size. The function returns the page size. The <code>need_allocation()</code> function checks whether the buffer (given by <code>buf</code>) plus the specified length (<code>len</code>) is near a page boundary. If the buffer extends beyond the current page when padded by <code><a class="el" href="namespacesimdjson.html#aecdd750132f0eb123a6d61113b4197bf" title="The amount of padding needed in a buffer to parse JSON.">simdjson::SIMDJSON_PADDING</a></code>, it returns true, indicating that reallocation is needed. Otherwise, it returns false. The <code>get_padded_string_view()</code> creates a <code>padded_string_view</code> from the input buffer. If reallocation is needed (unlikely case), it allocates a new padded_string and assigns it to <code>jsonbuffer</code>. Otherwise (very likely), it creates a <code>padded_string_view</code> directly from the buffer. The <code><a class="el" href="namespacesimdjson.html#aecdd750132f0eb123a6d61113b4197bf" title="The amount of padding needed in a buffer to parse JSON.">simdjson::SIMDJSON_PADDING</a></code> ensures that there is additional padding for parsing efficiency. The calling code just needs to provide <code>jsonbuffer</code> (an instance of <code><a class="el" href="structsimdjson_1_1padded__string.html" title="String with extra allocation for ease of use with parser::parse()">simdjson::padded_string</a></code>) and pass <code>get_padded_string_view(buf, len, jsonbuffer)</code> to <code>parser.iterate</code>. Most of the time, this code will not allocate new memory.</p>
<div class="fragment"><div class="line"><span class="preprocessor">#ifdef _WIN32</span></div>
<div class="line"><span class="preprocessor">#include &lt;windows.h&gt;</span></div>
<div class="line"><span class="preprocessor">#include &lt;sysinfoapi.h&gt;</span></div>
<div class="line"><span class="preprocessor">#else</span></div>
<div class="line"><span class="preprocessor">#include &lt;unistd.h&gt;</span></div>
<div class="line"><span class="preprocessor">#endif</span></div>
<div class="line"><span class="preprocessor">#include &quot;<a class="code" href="simdjson_8h.html">simdjson.h</a>&quot;</span></div>
<div class="line"><span class="preprocessor">#include &lt;cstdio&gt;</span></div>
<div class="line"> </div>
<div class="line"><span class="comment">// Returns the default size of the page in bytes on this system.</span></div>
<div class="line"><span class="keywordtype">long</span> page_size() {</div>
<div class="line"><span class="preprocessor">#ifdef _WIN32</span></div>
<div class="line"> SYSTEM_INFO sysInfo;</div>
<div class="line"> GetSystemInfo(&amp;sysInfo);</div>
<div class="line"> <span class="keywordtype">long</span> pagesize = sysInfo.dwPageSize;</div>
<div class="line"><span class="preprocessor">#else</span></div>
<div class="line"> <span class="keywordtype">long</span> pagesize = sysconf(_SC_PAGESIZE);</div>
<div class="line"><span class="preprocessor">#endif</span></div>
<div class="line"> <span class="keywordflow">return</span> pagesize;</div>
<div class="line">}</div>
<div class="line"> </div>
<div class="line"><span class="comment">// Returns true if the buffer + len + simdjson::SIMDJSON_PADDING crosses the</span></div>
<div class="line"><span class="comment">// page boundary.</span></div>
<div class="line"><span class="keywordtype">bool</span> need_allocation(<span class="keyword">const</span> <span class="keywordtype">char</span> *buf, <span class="keywordtype">size_t</span> len) {</div>
<div class="line"> <span class="keywordflow">return</span> ((<span class="keyword">reinterpret_cast&lt;</span>uintptr_t<span class="keyword">&gt;</span>(buf + len - 1) % page_size())</div>
<div class="line"> + <a class="code hl_variable" href="namespacesimdjson.html#aecdd750132f0eb123a6d61113b4197bf">simdjson::SIMDJSON_PADDING</a> &gt;= <span class="keyword">static_cast&lt;</span>uintptr_t<span class="keyword">&gt;</span>(page_size()));</div>
<div class="line">}</div>
<div class="line"> </div>
<div class="line"><a class="code hl_class" href="classsimdjson_1_1padded__string__view.html">simdjson::padded_string_view</a></div>
<div class="line">get_padded_string_view(<span class="keyword">const</span> <span class="keywordtype">char</span> *buf, <span class="keywordtype">size_t</span> len,</div>
<div class="line"> <a class="code hl_struct" href="structsimdjson_1_1padded__string.html">simdjson::padded_string</a> &amp;jsonbuffer) {</div>
<div class="line"> <span class="keywordflow">if</span> (need_allocation(buf, len)) { <span class="comment">// unlikely case</span></div>
<div class="line"> jsonbuffer = <a class="code hl_struct" href="structsimdjson_1_1padded__string.html">simdjson::padded_string</a>(buf, len);</div>
<div class="line"> <span class="keywordflow">return</span> jsonbuffer;</div>
<div class="line"> } <span class="keywordflow">else</span> { <span class="comment">// no reallcation needed (very likely)</span></div>
<div class="line"> <span class="keywordflow">return</span> <a class="code hl_class" href="classsimdjson_1_1padded__string__view.html">simdjson::padded_string_view</a>(buf, len,</div>
<div class="line"> len + <a class="code hl_variable" href="namespacesimdjson.html#aecdd750132f0eb123a6d61113b4197bf">simdjson::SIMDJSON_PADDING</a>);</div>
<div class="line"> }</div>
<div class="line">}</div>
<div class="line"> </div>
<div class="line"><span class="keywordtype">int</span> main() {</div>
<div class="line"> printf(<span class="stringliteral">&quot;page_size: %ld\n&quot;</span>, page_size());</div>
<div class="line"> <span class="keyword">const</span> <span class="keywordtype">char</span> *jsonpoiner = R<span class="stringliteral">&quot;(</span></div>
<div class="line"><span class="stringliteral"> {</span></div>
<div class="line"><span class="stringliteral"> &quot;key&quot;: &quot;value&quot;</span></div>
<div class="line"><span class="stringliteral"> }</span></div>
<div class="line"><span class="stringliteral"> )&quot;;</span></div>
<div class="line"><span class="stringliteral"> </span><span class="keywordtype">size_t</span> len = strlen(jsonpoiner);</div>
<div class="line"> <a class="code hl_struct" href="structsimdjson_1_1padded__string.html">simdjson::padded_string</a> jsonbuffer; <span class="comment">// only allocate if needed</span></div>
<div class="line"> simdjson::ondemand::parser parser;</div>
<div class="line"> simdjson::ondemand::document doc;</div>
<div class="line"> <a class="code hl_enumeration" href="namespacesimdjson.html#a7b735a3a50ba79e3f7f14df5f77d8da9">simdjson::error_code</a> error =</div>
<div class="line"> parser.iterate(get_padded_string_view(jsonpoiner, len, jsonbuffer))</div>
<div class="line"> .get(doc);</div>
<div class="line"> <span class="keywordflow">if</span> (error) {</div>
<div class="line"> printf(<span class="stringliteral">&quot;error: %s\n&quot;</span>, <a class="code hl_function" href="namespacesimdjson.html#a65b00a7a7a9c8fafe9eb3b9b413a36fa">simdjson::error_message</a>(error));</div>
<div class="line"> <span class="keywordflow">return</span> EXIT_FAILURE;</div>
<div class="line"> }</div>
<div class="line"> std::string_view value;</div>
<div class="line"> error = doc[<span class="stringliteral">&quot;key&quot;</span>].get_string().get(value);</div>
<div class="line"> <span class="keywordflow">if</span> (error) {</div>
<div class="line"> <span class="keywordflow">return</span> EXIT_FAILURE;</div>
<div class="line"> }</div>
<div class="line"> printf(<span class="stringliteral">&quot;Value: \&quot;%.*s\&quot;\n&quot;</span>, (<span class="keywordtype">int</span>)value.size(), value.data());</div>
<div class="line"> <span class="keywordflow">if</span> (value != <span class="stringliteral">&quot;value&quot;</span>) {</div>
<div class="line"> <span class="keywordflow">return</span> EXIT_FAILURE;</div>
<div class="line"> }</div>
<div class="line"> <span class="keywordflow">return</span> EXIT_SUCCESS;</div>
<div class="line">}</div>
<div class="ttc" id="aclasssimdjson_1_1padded__string__view_html"><div class="ttname"><a href="classsimdjson_1_1padded__string__view.html">simdjson::padded_string_view</a></div><div class="ttdoc">User-provided string that promises it has extra padded bytes at the end for use with parser::parse().</div><div class="ttdef"><b>Definition</b> <a href="padded__string__view_8h_source.html#l00018">padded_string_view.h:18</a></div></div>
<div class="ttc" id="anamespacesimdjson_html_a65b00a7a7a9c8fafe9eb3b9b413a36fa"><div class="ttname"><a href="namespacesimdjson.html#a65b00a7a7a9c8fafe9eb3b9b413a36fa">simdjson::error_message</a></div><div class="ttdeci">const char * error_message(error_code error) noexcept</div><div class="ttdoc">It is the convention throughout the code that the macro SIMDJSON_DEVELOPMENT_CHECKS determines whethe...</div><div class="ttdef"><b>Definition</b> <a href="error-inl_8h_source.html#l00025">error-inl.h:25</a></div></div>
<div class="ttc" id="anamespacesimdjson_html_a7b735a3a50ba79e3f7f14df5f77d8da9"><div class="ttname"><a href="namespacesimdjson.html#a7b735a3a50ba79e3f7f14df5f77d8da9">simdjson::error_code</a></div><div class="ttdeci">error_code</div><div class="ttdoc">All possible errors returned by simdjson.</div><div class="ttdef"><b>Definition</b> <a href="error_8h_source.html#l00019">error.h:19</a></div></div>
<div class="ttc" id="anamespacesimdjson_html_aecdd750132f0eb123a6d61113b4197bf"><div class="ttname"><a href="namespacesimdjson.html#aecdd750132f0eb123a6d61113b4197bf">simdjson::SIMDJSON_PADDING</a></div><div class="ttdeci">constexpr size_t SIMDJSON_PADDING</div><div class="ttdoc">The amount of padding needed in a buffer to parse JSON.</div><div class="ttdef"><b>Definition</b> <a href="base_8h_source.html#l00033">base.h:33</a></div></div>
<div class="ttc" id="asimdjson_8h_html"><div class="ttname"><a href="simdjson_8h.html">simdjson.h</a></div></div>
<div class="ttc" id="astructsimdjson_1_1padded__string_html"><div class="ttname"><a href="structsimdjson_1_1padded__string.html">simdjson::padded_string</a></div><div class="ttdoc">String with extra allocation for ease of use with parser::parse()</div><div class="ttdef"><b>Definition</b> <a href="padded__string_8h_source.html#l00023">padded_string.h:23</a></div></div>
</div><!-- fragment --><p>Further, whenever you allocate N bytes, memory allocators tend to allocate more memory, without you necessarily knowing about it. Under linux, you can use the <code>malloc_usable_size</code> function to see how much memory was actually allocated. Under an Apple plateform, you can <code>malloc_size</code>. The following program illustrates the usage.</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include &lt;iostream&gt;</span></div>
<div class="line"><span class="preprocessor">#include &lt;cstddef&gt;</span></div>
<div class="line"><span class="preprocessor">#include &lt;memory&gt;</span></div>
<div class="line"><span class="preprocessor">#include &lt;cstdlib&gt;</span></div>
<div class="line"><span class="preprocessor">#ifdef __APPLE__</span></div>
<div class="line"><span class="preprocessor">#include &lt;malloc/malloc.h&gt;</span> <span class="comment">// for malloc_size on macOS</span></div>
<div class="line"><span class="preprocessor">#endif</span></div>
<div class="line"><span class="preprocessor">#ifdef __linux__</span></div>
<div class="line"><span class="preprocessor">#include &lt;malloc.h&gt;</span> <span class="comment">// for malloc_usable_size on Linux</span></div>
<div class="line"><span class="preprocessor">#endif</span></div>
<div class="line"><span class="keywordtype">size_t</span> get_usable_size(<span class="keywordtype">void</span>* ptr) {</div>
<div class="line"><span class="preprocessor">#ifdef __linux__</span></div>
<div class="line"> <span class="keywordflow">return</span> malloc_usable_size(ptr);</div>
<div class="line"><span class="preprocessor">#elif defined(__APPLE__)</span></div>
<div class="line"> <span class="keywordflow">return</span> malloc_size(ptr);</div>
<div class="line"><span class="preprocessor">#else</span></div>
<div class="line"> <span class="keywordflow">return</span> 0; <span class="comment">// Unsupported platform</span></div>
<div class="line"><span class="preprocessor">#endif</span></div>
<div class="line">}</div>
<div class="line"> </div>
<div class="line"><span class="keywordtype">int</span> main() {</div>
<div class="line"> std::cout &lt;&lt; <span class="stringliteral">&quot;Demonstrating allocation overhead and rounding with operator new\n\n&quot;</span>;</div>
<div class="line"> </div>
<div class="line"><span class="preprocessor">#ifdef __linux__</span></div>
<div class="line"> std::cout &lt;&lt; <span class="stringliteral">&quot;Platform: Linux\n&quot;</span>;</div>
<div class="line"><span class="preprocessor">#elif defined(__APPLE__)</span></div>
<div class="line"> std::cout &lt;&lt; <span class="stringliteral">&quot;Platform: macOS (using malloc_size)\n&quot;</span>;</div>
<div class="line"><span class="preprocessor">#else</span></div>
<div class="line"> std::cout &lt;&lt; <span class="stringliteral">&quot;Platform: Other/unsupported (usable size will show 0)\n&quot;</span>;</div>
<div class="line"><span class="preprocessor">#endif</span></div>
<div class="line"> </div>
<div class="line"> std::cout &lt;&lt; <span class="stringliteral">&quot;Requested size | Actual usable size\n&quot;</span>;</div>
<div class="line"> std::cout &lt;&lt; <span class="stringliteral">&quot;---------------|-------------------\n&quot;</span>;</div>
<div class="line"> <span class="keywordtype">size_t</span> total_requested = 0;</div>
<div class="line"> <span class="keywordtype">size_t</span> total_usable = 0;</div>
<div class="line"> <span class="keywordflow">for</span> (<span class="keywordtype">size_t</span> requested = 1; requested &lt;= 4096; requested++) {</div>
<div class="line"> total_requested += requested;</div>
<div class="line"> std::unique_ptr&lt;char[]&gt; ptr(<span class="keyword">new</span> <span class="keywordtype">char</span>[requested]); <span class="comment">// Allocate</span></div>
<div class="line"> <span class="keywordtype">size_t</span> usable = get_usable_size(ptr.get()); <span class="comment">// Get usable size</span></div>
<div class="line"> total_usable += usable;</div>
<div class="line"> </div>
<div class="line"> std::cout &lt;&lt; requested &lt;&lt; <span class="stringliteral">&quot;\t | &quot;</span> &lt;&lt; usable &lt;&lt; <span class="stringliteral">&quot;\n&quot;</span>;</div>
<div class="line"> }</div>
<div class="line"> std::cout &lt;&lt; <span class="stringliteral">&quot;---------------|-------------------\n&quot;</span>;</div>
<div class="line"> std::cout &lt;&lt; <span class="stringliteral">&quot;Total requested: &quot;</span> &lt;&lt; total_requested &lt;&lt; <span class="stringliteral">&quot; bytes\n&quot;</span>;</div>
<div class="line"> std::cout &lt;&lt; <span class="stringliteral">&quot;Total usable: &quot;</span> &lt;&lt; total_usable &lt;&lt; <span class="stringliteral">&quot; bytes\n&quot;</span>;</div>
<div class="line"> std::cout &lt;&lt; <span class="stringliteral">&quot;Total overhead: &quot;</span> &lt;&lt; (total_usable - total_requested) &lt;&lt; <span class="stringliteral">&quot; bytes\n&quot;</span>;</div>
<div class="line"> std::cout &lt;&lt; <span class="stringliteral">&quot;Percentage overhead: &quot;</span></div>
<div class="line"> &lt;&lt; ((total_usable - total_requested) * 100.0 / total_requested) &lt;&lt; <span class="stringliteral">&quot; %\n&quot;</span>;</div>
<div class="line"> </div>
<div class="line"> <span class="keywordflow">return</span> EXIT_SUCCESS;</div>
<div class="line">}</div>
</div><!-- fragment --> </div></div><!-- contents -->
</div><!-- PageDoc -->
</div><!-- doc-content -->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
<li class="footer">Generated by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.9.8 </li>
</ul>
</div>
</body>
</html>