mirror of https://github.com/orefkov/simstr.git
3809 lines
226 KiB
HTML
3809 lines
226 KiB
HTML
<html>
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<link href="results.css" rel="stylesheet" />
|
||
<title>SimStr benchmarks results</title>
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||
<script>
|
||
let bench_sets = {};
|
||
let activeBuilder = buildTestsByPlatformsBar;
|
||
let buildAsLine = {
|
||
"Copy not literal Str with N symbols": "Length of the copied string",
|
||
"Replace All Str To Longer Size": "Length of the string to be replaced",
|
||
"Replace All Str To Same Size": "Length of the string to be replaced"
|
||
};
|
||
function hl() {
|
||
document.querySelectorAll('.tooltiptext.code').forEach((el) => {
|
||
hljs.highlightElement(el);
|
||
});
|
||
}
|
||
function addBarChart(id, data) {
|
||
let canvas = document.getElementById('chart' + id);
|
||
new Chart(canvas, {
|
||
type: 'bar',
|
||
data: data,
|
||
options: {
|
||
scales: {
|
||
y: {
|
||
beginAtZero: true
|
||
},
|
||
x: {
|
||
title: {
|
||
text: "Time (ns)",
|
||
display: true
|
||
}
|
||
}
|
||
},
|
||
indexAxis: 'y',
|
||
plugins: {
|
||
legend: {
|
||
position: 'right',
|
||
labels: {
|
||
font: {
|
||
family: "'Cascadia Code', Consolas, 'Courier New', Courier, monospace"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
});
|
||
}
|
||
function platformChecked(idx) {
|
||
return document.getElementById('pl' + idx).checked;
|
||
}
|
||
function buildPlatformsByTestsBar(bsName) {
|
||
if (buildAsLine[bsName]) {
|
||
buildPlatformsByTestsLine(bsName, buildAsLine[bsName]);
|
||
return;
|
||
}
|
||
let data = { labels: [], datasets: [] };
|
||
for (const i in platform_names) {
|
||
if (platformChecked(i))
|
||
data.datasets.push({ label: platform_names[i], data: [], borderWidth: 1 });
|
||
}
|
||
let bs = bench_sets[bsName];
|
||
for (const test of bs.tests) {
|
||
data.labels.push(test.name);
|
||
let ds = 0;
|
||
for (const i in test.data) {
|
||
if (platformChecked(i)) {
|
||
data.datasets[ds++].data.push(test.data[i]);
|
||
}
|
||
}
|
||
}
|
||
addBarChart(bs.id, data);
|
||
}
|
||
function buildTestsByPlatformsBar(bsName) {
|
||
if (buildAsLine[bsName], buildAsLine[bsName]) {
|
||
buildTestsByPlatformsLine(bsName, buildAsLine[bsName]);
|
||
return;
|
||
}
|
||
let data = { labels: [], datasets: [] };
|
||
let bs = bench_sets[bsName];
|
||
for (const test of bs.tests) {
|
||
data.datasets.push({ label: test.name, data: [], borderWidth: 1 });
|
||
}
|
||
for (const i in platform_names) {
|
||
if (platformChecked(i)) {
|
||
data.labels.push(platform_names[i]);
|
||
for (const j in bs.tests) {
|
||
data.datasets[j].data.push(bs.tests[j].data[i]);
|
||
}
|
||
}
|
||
}
|
||
addBarChart(bs.id, data);
|
||
}
|
||
function buildCanvas(plCount) {
|
||
document.querySelectorAll("canvas.bench_chart").forEach(e => e.remove());
|
||
for (var bs_name in bench_sets) {
|
||
let bs = bench_sets[bs_name];
|
||
if (plCount) {
|
||
let canvas = document.createElement('canvas');
|
||
canvas.id = "chart" + bs.id;
|
||
canvas.classList.add('bench_chart');
|
||
let h = 20 * plCount * bs.tests.length;
|
||
canvas.style.width = "100%";
|
||
canvas.style.height = h + "px";
|
||
canvas.height = h * devicePixelRatio;
|
||
document.getElementById(bs.id).after(canvas);
|
||
}
|
||
}
|
||
}
|
||
function addLineChart(canvas, data, title, scaleTitle) {
|
||
new Chart(canvas, {
|
||
type: 'line',
|
||
data: data,
|
||
options: {
|
||
scales: {
|
||
y: {
|
||
beginAtZero: true,
|
||
title: {
|
||
text: scaleTitle,
|
||
display: true
|
||
}
|
||
},
|
||
x: {
|
||
title: {
|
||
text: "Time (ns)",
|
||
display: true
|
||
}
|
||
}
|
||
},
|
||
indexAxis: 'y',
|
||
plugins: {
|
||
title: {
|
||
display: true,
|
||
text: title,
|
||
},
|
||
legend: {
|
||
position: 'right',
|
||
labels: {
|
||
font: {
|
||
family: "'Cascadia Code', Consolas, 'Courier New', Courier, monospace"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
});
|
||
}
|
||
function buildTestsByPlatformsLineOne(bs, canvas, plIdx, scaleTitle) {
|
||
let data = { datasets: [] };
|
||
let prevTest = '';
|
||
let curData = undefined;
|
||
for (const test of bs.tests) {
|
||
let m = test.name.match(/(.+)[\/\|](\d+)$/);
|
||
if (m[1] != prevTest) {
|
||
prevTest = m[1];
|
||
curData = { label: prevTest, data: [], borderWidth: 1 };
|
||
data.datasets.push(curData);
|
||
}
|
||
curData.data.push([test.data[plIdx], m[2]]);
|
||
}
|
||
addLineChart(canvas, data, platform_names[plIdx], scaleTitle);
|
||
}
|
||
function buildTestsByPlatformsLine(bsName, scaleTitle) {
|
||
let bs = bench_sets[bsName];
|
||
let canvas = document.getElementById('chart' + bs.id);
|
||
let after = null;
|
||
|
||
for (const i in platform_names) {
|
||
if (platformChecked(i)) {
|
||
if (!canvas) {
|
||
canvas = document.createElement('canvas');
|
||
canvas.classList.add('bench_chart');
|
||
canvas.style.width = "100%";
|
||
after.after(canvas);
|
||
}
|
||
canvas.style.height = "300px";
|
||
canvas.height = 300 * devicePixelRatio;
|
||
buildTestsByPlatformsLineOne(bs, canvas, i, scaleTitle);
|
||
after = canvas;
|
||
canvas = null;
|
||
}
|
||
}
|
||
}
|
||
function buildPlatformsByTestsLineOne(bs, canvas, after, testData, title, scaleTitle) {
|
||
let data = { datasets: [] };
|
||
for (const i in platform_names) {
|
||
if (platformChecked(i)) {
|
||
ds = {label: platform_names[i], data: []};
|
||
for (const test of testData) {
|
||
ds.data.push([test.data[i], test.count]);
|
||
}
|
||
data.datasets.push(ds);
|
||
}
|
||
}
|
||
if (!canvas) {
|
||
canvas = document.createElement('canvas');
|
||
canvas.classList.add('bench_chart');
|
||
canvas.style.width = "100%";
|
||
after.after(canvas);
|
||
}
|
||
canvas.style.height = "300px";
|
||
canvas.height = 300 * devicePixelRatio;
|
||
addLineChart(canvas, data, title, scaleTitle);
|
||
return canvas;
|
||
}
|
||
function buildPlatformsByTestsLine(bsName, scaleTitle) {
|
||
let bs = bench_sets[bsName];
|
||
let canvas = document.getElementById('chart' + bs.id);
|
||
let after = null;
|
||
let data = [];
|
||
let prevTest = '';
|
||
for (const test of bs.tests) {
|
||
let m = test.name.match(/(.+)[\/\|](\d+)$/);
|
||
if (m[1] != prevTest) {
|
||
if (data.length) {
|
||
after = buildPlatformsByTestsLineOne(bs, canvas, after, data, prevTest, scaleTitle);
|
||
canvas = null;
|
||
}
|
||
prevTest = m[1];
|
||
data = [];
|
||
}
|
||
data.push({count: m[2], data: test.data});
|
||
}
|
||
if (data.length) {
|
||
buildPlatformsByTestsLineOne(bs, canvas, after, data, prevTest, scaleTitle);
|
||
}
|
||
}
|
||
function buildCharts() {
|
||
let plCount = 0;
|
||
for (const i in platform_names) {
|
||
if (platformChecked(i))
|
||
plCount++;
|
||
}
|
||
buildCanvas(plCount);
|
||
for (var bs_name in bench_sets) {
|
||
activeBuilder(bs_name);
|
||
}
|
||
}
|
||
function switchGrouping() {
|
||
activeBuilder = document.getElementById('gbp').checked ? buildTestsByPlatformsBar : buildPlatformsByTestsBar;
|
||
buildCharts();
|
||
}
|
||
document.addEventListener('DOMContentLoaded', (event) => {
|
||
if (!hljs) {
|
||
let scriptTag = document.createElement('script');
|
||
scriptTag.src = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js";
|
||
scriptTag.onload = hl;
|
||
scriptTag.onreadystatechange = hl;
|
||
document.body.appendChild(scriptTag);
|
||
} else {
|
||
hl();
|
||
}
|
||
if (!Chart) {
|
||
let scriptTag = document.createElement('script');
|
||
scriptTag.src = "https://cdn.jsdelivr.net/npm/chart.js";
|
||
scriptTag.onload = buildCharts;
|
||
scriptTag.onreadystatechange = buildCharts;
|
||
document.body.appendChild(scriptTag);
|
||
} else {
|
||
buildCharts();
|
||
}
|
||
});
|
||
</script>
|
||
</head><body><div class="header"><h2>SimStr benchmarks results</h2>
|
||
<span>All times in ns.</span>
|
||
<span><a href="https://github.com/orefkov/simstr/blob/main/bench/bench_str.cpp">Source for benchmarks</a></span>
|
||
<div>Group tests by platforms in charts: <input type="checkbox" id="gbp" checked onchange="switchGrouping()"/></div><div class="test_platforms"><h3>Test configurations:</h3><ul>
|
||
<li><span class="platform">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</span><span class="tooltip">32 X 2494.22 MHz CPU s<span class="tooltiptext">CPU Caches:
|
||
L1 Data 32 KiB (x16)
|
||
L1 Instruction 32 KiB (x16)
|
||
L2 Unified 256 KiB (x16)
|
||
L3 Unified 40960 KiB (x1)
|
||
Load Average: 0.10, 0.62, 0.73</span></span> Include in charts: <input type="checkbox" id="pl0" checked onchange="buildCharts()"/></li>
|
||
<li><span class="platform">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</span><span class="tooltip">32 X 2494.22 MHz CPU s<span class="tooltiptext">CPU Caches:
|
||
L1 Data 32 KiB (x16)
|
||
L1 Instruction 32 KiB (x16)
|
||
L2 Unified 256 KiB (x16)
|
||
L3 Unified 40960 KiB (x1)
|
||
Load Average: 0.02, 0.05, 0.12</span></span> Include in charts: <input type="checkbox" id="pl1" checked onchange="buildCharts()"/></li>
|
||
<li><span class="platform">Xeon E5-2682 v4, Windows 10, Clang-19</span><span class="tooltip">32 X 2494 MHz CPU s<span class="tooltiptext">CPU Caches:
|
||
L1 Data 32 KiB (x16)
|
||
L1 Instruction 32 KiB (x16)
|
||
L2 Unified 256 KiB (x16)
|
||
L3 Unified 40960 KiB (x1)</span></span> Include in charts: <input type="checkbox" id="pl2" checked onchange="buildCharts()"/></li>
|
||
<li><span class="platform">Xeon E5-2682 v4, Windows 10, MSVC-19</span><span class="tooltip">32 X 2494 MHz CPU s<span class="tooltiptext">CPU Caches:
|
||
L1 Data 32 KiB (x16)
|
||
L1 Instruction 32 KiB (x16)
|
||
L2 Unified 256 KiB (x16)
|
||
L3 Unified 40960 KiB (x1)</span></span> Include in charts: <input type="checkbox" id="pl3" checked onchange="buildCharts()"/></li>
|
||
<li><span class="platform">Xeon E5-2682 v4, WASM Chrome, Clang-21</span><span class="tooltip">32 X 2513.96 MHz CPU s<span class="tooltiptext">Chromium: 142.0.7444.60 webasm</span></span> Include in charts: <input type="checkbox" id="pl4" checked onchange="buildCharts()"/></li>
|
||
</ul></div></div>
|
||
<script>const platform_names=['Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21','Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13','Xeon E5-2682 v4, Windows 10, Clang-19','Xeon E5-2682 v4, Windows 10, MSVC-19','Xeon E5-2682 v4, WASM Chrome, Clang-21'];</script>
|
||
|
||
|
||
<div class="benchset" id="bs1"><h4>Create Empty Str</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string e;<span class="tooltiptext code">template<typename T>
|
||
void CreateEmpty(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string;
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Пустые строки, ничего необычного.</span></span></td><td class="benchmarkresult">1.11</td><td class="benchmarkresult">1.15</td><td class="benchmarkresult">1.11</td><td class="benchmarkresult">2.95</td><td class="benchmarkresult">5.87</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string_view e;<span class="tooltiptext code">template<typename T>
|
||
void CreateEmpty(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string;
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">0.369</td><td class="benchmarkresult">0.743</td><td class="benchmarkresult">0.368</td><td class="benchmarkresult">1.85</td><td class="benchmarkresult">5.26</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">ssa e;<span class="tooltiptext code">template<typename T>
|
||
void CreateEmpty(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string;
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">0.369</td><td class="benchmarkresult">0.185</td><td class="benchmarkresult">0.361</td><td class="benchmarkresult">1.52</td><td class="benchmarkresult">4.67</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa e;<span class="tooltiptext code">template<typename T>
|
||
void CreateEmpty(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string;
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">0.742</td><td class="benchmarkresult">0.759</td><td class="benchmarkresult">0.736</td><td class="benchmarkresult">2.25</td><td class="benchmarkresult">4.82</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<20> e;<span class="tooltiptext code">template<typename T>
|
||
void CreateEmpty(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string;
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1.13</td><td class="benchmarkresult">1.13</td><td class="benchmarkresult">1.12</td><td class="benchmarkresult">2.58</td><td class="benchmarkresult">4.64</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<40> e;<span class="tooltiptext code">template<typename T>
|
||
void CreateEmpty(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string;
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1.13</td><td class="benchmarkresult">1.13</td><td class="benchmarkresult">1.13</td><td class="benchmarkresult">2.59</td><td class="benchmarkresult">4.76</td></tr>
|
||
</tbody></table></div><script>bench_sets['Create Empty Str'] = {id:'bs1', tests:[
|
||
{name:'std::string e;',data:[1.11,1.15,1.11,2.95,5.87]},
|
||
{name:'std::string_view e;',data:[0.369,0.743,0.368,1.85,5.26]},
|
||
{name:'ssa e;',data:[0.369,0.185,0.361,1.52,4.67]},
|
||
{name:'stringa e;',data:[0.742,0.759,0.736,2.25,4.82]},
|
||
{name:'lstringa<20> e;',data:[1.13,1.13,1.12,2.58,4.64]},
|
||
{name:'lstringa<40> e;',data:[1.13,1.13,1.13,2.59,4.76]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs2"><h4>Create Str from short literal (9 symbols)</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string e = "Test text";<span class="tooltiptext code">template<typename T>
|
||
void CreateShortLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string = TEST_TEXT;
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Короткий литерал помещается во внутренний буфер std::string,
|
||
время тратится только на копирование 10 байтов.</span></span></td><td class="benchmarkresult">1.91</td><td class="benchmarkresult">1.85</td><td class="benchmarkresult">1.87</td><td class="benchmarkresult">2.58</td><td class="benchmarkresult">5.17</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string_view e = "Test text";<span class="tooltiptext code">template<typename T>
|
||
void CreateShortLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string = TEST_TEXT;
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">И string_view, и ssa - по сути одно и то же:
|
||
указатель на текст и его длина.</span></span></td><td class="benchmarkresult">0.748</td><td class="benchmarkresult">0.751</td><td class="benchmarkresult">0.727</td><td class="benchmarkresult">1.90</td><td class="benchmarkresult">5.57</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">ssa e = "Test text";<span class="tooltiptext code">template<typename T>
|
||
void CreateShortLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string = TEST_TEXT;
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">0.374</td><td class="benchmarkresult">0.781</td><td class="benchmarkresult">0.364</td><td class="benchmarkresult">1.85</td><td class="benchmarkresult">3.41</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa e = "Test text";<span class="tooltiptext code">template<typename T>
|
||
void CreateShortLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string = TEST_TEXT;
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">stringa при инициализации константным литералом так же
|
||
сохраняет только указатель на текст и его длину.</span></span></td><td class="benchmarkresult">1.11</td><td class="benchmarkresult">1.13</td><td class="benchmarkresult">1.10</td><td class="benchmarkresult">2.92</td><td class="benchmarkresult">5.07</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<20> e = "Test text";<span class="tooltiptext code">template<typename T>
|
||
void CreateShortLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string = TEST_TEXT;
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Внутреннего буфера хватает для размещения символов,
|
||
время уходит только на копирование байтов.</span></span></td><td class="benchmarkresult">1.88</td><td class="benchmarkresult">1.86</td><td class="benchmarkresult">1.85</td><td class="benchmarkresult">2.59</td><td class="benchmarkresult">5.37</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<40> e = "Test text";<span class="tooltiptext code">template<typename T>
|
||
void CreateShortLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string = TEST_TEXT;
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1.86</td><td class="benchmarkresult">1.88</td><td class="benchmarkresult">1.84</td><td class="benchmarkresult">2.61</td><td class="benchmarkresult">5.37</td></tr>
|
||
</tbody></table></div><script>bench_sets['Create Str from short literal (9 symbols)'] = {id:'bs2', tests:[
|
||
{name:'std::string e = "Test text";',data:[1.91,1.85,1.87,2.58,5.17]},
|
||
{name:'std::string_view e = "Test text";',data:[0.748,0.751,0.727,1.90,5.57]},
|
||
{name:'ssa e = "Test text";',data:[0.374,0.781,0.364,1.85,3.41]},
|
||
{name:'stringa e = "Test text";',data:[1.11,1.13,1.10,2.92,5.07]},
|
||
{name:'lstringa<20> e = "Test text";',data:[1.88,1.86,1.85,2.59,5.37]},
|
||
{name:'lstringa<40> e = "Test text";',data:[1.86,1.88,1.84,2.61,5.37]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs3"><h4>Create Str from long literal (30 symbols)</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string e = "123456789012345678901234567890";<span class="tooltiptext code">template<typename T>
|
||
void CreateLongLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string{LONG_TEXT};
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Вот тут уже литерал не помещается во внутренний буфер,
|
||
возникает аллокация и копирование 30-и байтов.
|
||
Но как же отстает аллокация под Windows от Linux'а, 20 vs 70 ns...</span></span></td><td class="benchmarkresult">18.8</td><td class="benchmarkresult">19.9</td><td class="benchmarkresult">78.5</td><td class="benchmarkresult">76.0</td><td class="benchmarkresult">63.4</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string_view e = "123456789012345678901234567890";<span class="tooltiptext code">template<typename T>
|
||
void CreateLongLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string{LONG_TEXT};
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">string_view и ssa по прежнему ничего не делают, кроме
|
||
запоминания указателя на текст и его размера.</span></span></td><td class="benchmarkresult">0.747</td><td class="benchmarkresult">0.808</td><td class="benchmarkresult">0.731</td><td class="benchmarkresult">1.82</td><td class="benchmarkresult">5.58</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">ssa e = "123456789012345678901234567890";<span class="tooltiptext code">template<typename T>
|
||
void CreateLongLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string{LONG_TEXT};
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">0.373</td><td class="benchmarkresult">0.754</td><td class="benchmarkresult">0.371</td><td class="benchmarkresult">1.82</td><td class="benchmarkresult">3.33</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa e = "123456789012345678901234567890";<span class="tooltiptext code">template<typename T>
|
||
void CreateLongLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string{LONG_TEXT};
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">stringa на константных литералах не отстает!</span></span></td><td class="benchmarkresult">1.13</td><td class="benchmarkresult">1.12</td><td class="benchmarkresult">1.12</td><td class="benchmarkresult">2.58</td><td class="benchmarkresult">4.95</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<20> e = "123456789012345678901234567890";<span class="tooltiptext code">template<typename T>
|
||
void CreateLongLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string{LONG_TEXT};
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">lstringa<20> может вместить в себя до 23 символов,
|
||
Очевидно, что для 30-и символов уже нужна аллокация.</span></span></td><td class="benchmarkresult">21.2</td><td class="benchmarkresult">19.6</td><td class="benchmarkresult">80.1</td><td class="benchmarkresult">76.8</td><td class="benchmarkresult">63.1</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<40> e = "123456789012345678901234567890";<span class="tooltiptext code">template<typename T>
|
||
void CreateLongLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
T empty_string{LONG_TEXT};
|
||
benchmark::DoNotOptimize(empty_string);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">А в lstringa<40> влезает до 47 символов, так что просто
|
||
копируется 30 байтов.</span></span></td><td class="benchmarkresult">2.57</td><td class="benchmarkresult">1.86</td><td class="benchmarkresult">2.53</td><td class="benchmarkresult">3.33</td><td class="benchmarkresult">5.86</td></tr>
|
||
</tbody></table></div><script>bench_sets['Create Str from long literal (30 symbols)'] = {id:'bs3', tests:[
|
||
{name:'std::string e = "123456789012345678901234567890";',data:[18.8,19.9,78.5,76.0,63.4]},
|
||
{name:'std::string_view e = "123456789012345678901234567890";',data:[0.747,0.808,0.731,1.82,5.58]},
|
||
{name:'ssa e = "123456789012345678901234567890";',data:[0.373,0.754,0.371,1.82,3.33]},
|
||
{name:'stringa e = "123456789012345678901234567890";',data:[1.13,1.12,1.12,2.58,4.95]},
|
||
{name:'lstringa<20> e = "123456789012345678901234567890";',data:[21.2,19.6,80.1,76.8,63.1]},
|
||
{name:'lstringa<40> e = "123456789012345678901234567890";',data:[2.57,1.86,2.53,3.33,5.86]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs4"><h4>Create copy of Str with 9 symbols</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string e = "Test text"; auto c{e};<span class="tooltiptext code">template<typename T>
|
||
void CopyShortString(benchmark::State& state) {
|
||
T x{TEST_TEXT};
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Строка в пределах SSO, так что просто копирует байты.</span></span></td><td class="benchmarkresult">4.98</td><td class="benchmarkresult">4.95</td><td class="benchmarkresult">1.85</td><td class="benchmarkresult">6.00</td><td class="benchmarkresult">11.0</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string_view e = "Test text"; auto c{e};<span class="tooltiptext code">template<typename T>
|
||
void CopyShortString(benchmark::State& state) {
|
||
T x{TEST_TEXT};
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">0.373</td><td class="benchmarkresult">0.381</td><td class="benchmarkresult">0.370</td><td class="benchmarkresult">3.46</td><td class="benchmarkresult">5.91</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">ssa e = "Test text"; auto c{e};<span class="tooltiptext code">template<typename T>
|
||
void CopyShortString(benchmark::State& state) {
|
||
T x{TEST_TEXT};
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">ssa и string_view не владеют строкой, копируется
|
||
только информация о строке.</span></span></td><td class="benchmarkresult">0.376</td><td class="benchmarkresult">0.377</td><td class="benchmarkresult">0.370</td><td class="benchmarkresult">3.51</td><td class="benchmarkresult">6.84</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa e = "Test text"; auto c{e};<span class="tooltiptext code">template<typename T>
|
||
void CopyShortString(benchmark::State& state) {
|
||
T x{TEST_TEXT};
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Копирование stringa происходит быстро,
|
||
особенно если она инициализирована литералом.</span></span></td><td class="benchmarkresult">1.13</td><td class="benchmarkresult">1.35</td><td class="benchmarkresult">1.30</td><td class="benchmarkresult">4.03</td><td class="benchmarkresult">5.18</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<20> e = "Test text"; auto c{e};<span class="tooltiptext code">template<typename T>
|
||
void CopyShortString(benchmark::State& state) {
|
||
T x{TEST_TEXT};
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">В обоих случаях хватает внутреннего буфера.</span></span></td><td class="benchmarkresult">4.84</td><td class="benchmarkresult">4.49</td><td class="benchmarkresult">5.25</td><td class="benchmarkresult">8.51</td><td class="benchmarkresult">17.5</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<40> e = "Test text"; auto c{e};<span class="tooltiptext code">template<typename T>
|
||
void CopyShortString(benchmark::State& state) {
|
||
T x{TEST_TEXT};
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Только копируются байты.</span></span></td><td class="benchmarkresult">4.53</td><td class="benchmarkresult">4.93</td><td class="benchmarkresult">5.36</td><td class="benchmarkresult">8.43</td><td class="benchmarkresult">17.4</td></tr>
|
||
</tbody></table></div><script>bench_sets['Create copy of Str with 9 symbols'] = {id:'bs4', tests:[
|
||
{name:'std::string e = "Test text"; auto c{e};',data:[4.98,4.95,1.85,6.00,11.0]},
|
||
{name:'std::string_view e = "Test text"; auto c{e};',data:[0.373,0.381,0.370,3.46,5.91]},
|
||
{name:'ssa e = "Test text"; auto c{e};',data:[0.376,0.377,0.370,3.51,6.84]},
|
||
{name:'stringa e = "Test text"; auto c{e};',data:[1.13,1.35,1.30,4.03,5.18]},
|
||
{name:'lstringa<20> e = "Test text"; auto c{e};',data:[4.84,4.49,5.25,8.51,17.5]},
|
||
{name:'lstringa<40> e = "Test text"; auto c{e};',data:[4.53,4.93,5.36,8.43,17.4]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs5"><h4>Create copy of Str with 30 symbols</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string e = "123456789012345678901234567890"; auto c{e};<span class="tooltiptext code">template<typename T>
|
||
void CopyLongString(benchmark::State& state) {
|
||
T x = LONG_TEXT;
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Копирования длинной строки вызывает аллокацию,
|
||
SSO уже не хватает. И снова как же отстаёт аллокация под Windows...</span></span></td><td class="benchmarkresult">19.6</td><td class="benchmarkresult">24.2</td><td class="benchmarkresult">81.7</td><td class="benchmarkresult">83.0</td><td class="benchmarkresult">93.3</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string_view e = "123456789012345678901234567890"; auto c{e};<span class="tooltiptext code">template<typename T>
|
||
void CopyLongString(benchmark::State& state) {
|
||
T x = LONG_TEXT;
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">0.748</td><td class="benchmarkresult">0.747</td><td class="benchmarkresult">0.741</td><td class="benchmarkresult">1.90</td><td class="benchmarkresult">5.57</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">ssa e = "123456789012345678901234567890"; auto c{e};<span class="tooltiptext code">template<typename T>
|
||
void CopyLongString(benchmark::State& state) {
|
||
T x = LONG_TEXT;
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">0.373</td><td class="benchmarkresult">0.746</td><td class="benchmarkresult">0.368</td><td class="benchmarkresult">2.02</td><td class="benchmarkresult">3.32</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa e = "123456789012345678901234567890"; auto c{e};<span class="tooltiptext code">template<typename T>
|
||
void CopyLongString(benchmark::State& state) {
|
||
T x = LONG_TEXT;
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">А вот у stringa копирование литерала не зависит от его длины,
|
||
сравни с предыдущим бенчмарком.</span></span></td><td class="benchmarkresult">1.13</td><td class="benchmarkresult">1.13</td><td class="benchmarkresult">1.86</td><td class="benchmarkresult">3.41</td><td class="benchmarkresult">4.89</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<20> e = "123456789012345678901234567890"; auto c{e};<span class="tooltiptext code">template<typename T>
|
||
void CopyLongString(benchmark::State& state) {
|
||
T x = LONG_TEXT;
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Не влезает, аллокация.</span></span></td><td class="benchmarkresult">20.0</td><td class="benchmarkresult">24.4</td><td class="benchmarkresult">79.3</td><td class="benchmarkresult">90.4</td><td class="benchmarkresult">66.3</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<40> e = "123456789012345678901234567890"; auto c{e};<span class="tooltiptext code">template<typename T>
|
||
void CopyLongString(benchmark::State& state) {
|
||
T x = LONG_TEXT;
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Уложили во внутренний буфер.</span></span></td><td class="benchmarkresult">5.40</td><td class="benchmarkresult">4.61</td><td class="benchmarkresult">4.94</td><td class="benchmarkresult">7.11</td><td class="benchmarkresult">17.0</td></tr>
|
||
</tbody></table></div><script>bench_sets['Create copy of Str with 30 symbols'] = {id:'bs5', tests:[
|
||
{name:'std::string e = "123456789012345678901234567890"; auto c{e};',data:[19.6,24.2,81.7,83.0,93.3]},
|
||
{name:'std::string_view e = "123456789012345678901234567890"; auto c{e};',data:[0.748,0.747,0.741,1.90,5.57]},
|
||
{name:'ssa e = "123456789012345678901234567890"; auto c{e};',data:[0.373,0.746,0.368,2.02,3.32]},
|
||
{name:'stringa e = "123456789012345678901234567890"; auto c{e};',data:[1.13,1.13,1.86,3.41,4.89]},
|
||
{name:'lstringa<20> e = "123456789012345678901234567890"; auto c{e};',data:[20.0,24.4,79.3,90.4,66.3]},
|
||
{name:'lstringa<40> e = "123456789012345678901234567890"; auto c{e};',data:[5.40,4.61,4.94,7.11,17.0]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs6"><h4>Find 9 symbols text in end of 99 symbols text</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string::find;<span class="tooltiptext code">template<typename T>
|
||
void Find(benchmark::State& state) {
|
||
T x{LONG_TEXT LONG_TEXT LONG_TEXT TEST_TEXT};
|
||
for (auto _: state) {
|
||
int i = (int)x.find(TEST_TEXT);
|
||
#ifdef CHECK_RESULT
|
||
if (i != 90) {
|
||
state.SkipWithError("not find?");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(i);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Здесь "победила дружба", у всех типов по колонке примерно одинаково.
|
||
Однако, Windows и Linux явно в разных весовых категориях.</span></span></td><td class="benchmarkresult">6.87</td><td class="benchmarkresult">6.87</td><td class="benchmarkresult">39.5</td><td class="benchmarkresult">45.0</td><td class="benchmarkresult">101</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string_view::find;<span class="tooltiptext code">template<typename T>
|
||
void Find(benchmark::State& state) {
|
||
T x{LONG_TEXT LONG_TEXT LONG_TEXT TEST_TEXT};
|
||
for (auto _: state) {
|
||
int i = (int)x.find(TEST_TEXT);
|
||
#ifdef CHECK_RESULT
|
||
if (i != 90) {
|
||
state.SkipWithError("not find?");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(i);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">7.75</td><td class="benchmarkresult">7.39</td><td class="benchmarkresult">40.0</td><td class="benchmarkresult">44.2</td><td class="benchmarkresult">103</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">ssa::find;<span class="tooltiptext code">template<typename T>
|
||
void Find(benchmark::State& state) {
|
||
T x{LONG_TEXT LONG_TEXT LONG_TEXT TEST_TEXT};
|
||
for (auto _: state) {
|
||
int i = (int)x.find(TEST_TEXT);
|
||
#ifdef CHECK_RESULT
|
||
if (i != 90) {
|
||
state.SkipWithError("not find?");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(i);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">6.96</td><td class="benchmarkresult">6.93</td><td class="benchmarkresult">18.1</td><td class="benchmarkresult">21.8</td><td class="benchmarkresult">102</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa::find;<span class="tooltiptext code">template<typename T>
|
||
void Find(benchmark::State& state) {
|
||
T x{LONG_TEXT LONG_TEXT LONG_TEXT TEST_TEXT};
|
||
for (auto _: state) {
|
||
int i = (int)x.find(TEST_TEXT);
|
||
#ifdef CHECK_RESULT
|
||
if (i != 90) {
|
||
state.SkipWithError("not find?");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(i);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">7.38</td><td class="benchmarkresult">8.00</td><td class="benchmarkresult">19.4</td><td class="benchmarkresult">31.0</td><td class="benchmarkresult">105</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<20>::find;<span class="tooltiptext code">template<typename T>
|
||
void Find(benchmark::State& state) {
|
||
T x{LONG_TEXT LONG_TEXT LONG_TEXT TEST_TEXT};
|
||
for (auto _: state) {
|
||
int i = (int)x.find(TEST_TEXT);
|
||
#ifdef CHECK_RESULT
|
||
if (i != 90) {
|
||
state.SkipWithError("not find?");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(i);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">6.90</td><td class="benchmarkresult">6.92</td><td class="benchmarkresult">18.1</td><td class="benchmarkresult">26.3</td><td class="benchmarkresult">99.9</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<40>::find;<span class="tooltiptext code">template<typename T>
|
||
void Find(benchmark::State& state) {
|
||
T x{LONG_TEXT LONG_TEXT LONG_TEXT TEST_TEXT};
|
||
for (auto _: state) {
|
||
int i = (int)x.find(TEST_TEXT);
|
||
#ifdef CHECK_RESULT
|
||
if (i != 90) {
|
||
state.SkipWithError("not find?");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(i);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">6.83</td><td class="benchmarkresult">6.87</td><td class="benchmarkresult">18.1</td><td class="benchmarkresult">24.9</td><td class="benchmarkresult">100</td></tr>
|
||
</tbody></table></div><script>bench_sets['Find 9 symbols text in end of 99 symbols text'] = {id:'bs6', tests:[
|
||
{name:'std::string::find;',data:[6.87,6.87,39.5,45.0,101]},
|
||
{name:'std::string_view::find;',data:[7.75,7.39,40.0,44.2,103]},
|
||
{name:'ssa::find;',data:[6.96,6.93,18.1,21.8,102]},
|
||
{name:'stringa::find;',data:[7.38,8.00,19.4,31.0,105]},
|
||
{name:'lstringa<20>::find;',data:[6.90,6.92,18.1,26.3,99.9]},
|
||
{name:'lstringa<40>::find;',data:[6.83,6.87,18.1,24.9,100]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs7"><h4>Copy not literal Str with N symbols</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string copy{str_with_len_N};/15<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">4.90</td><td class="benchmarkresult">5.07</td><td class="benchmarkresult">1.86</td><td class="benchmarkresult">4.45</td><td class="benchmarkresult">97.2</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string copy{str_with_len_N};/16<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Явно виден скачок, где заканчивается SSO и начинается аллокация.
|
||
Обратите внимание, что WASM - 32-битный, и там размер
|
||
SSO у std::string меньше, насколько я помню, 11 символов + 0.</span></span></td><td class="benchmarkresult">23.1</td><td class="benchmarkresult">23.7</td><td class="benchmarkresult">81.6</td><td class="benchmarkresult">94.0</td><td class="benchmarkresult">94.6</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string copy{str_with_len_N};/23<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Дальше просто добавляется время на копирование байтов.</span></span></td><td class="benchmarkresult">23.2</td><td class="benchmarkresult">23.9</td><td class="benchmarkresult">79.8</td><td class="benchmarkresult">94.8</td><td class="benchmarkresult">91.6</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string copy{str_with_len_N};/24<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">22.3</td><td class="benchmarkresult">24.9</td><td class="benchmarkresult">80.5</td><td class="benchmarkresult">97.7</td><td class="benchmarkresult">94.5</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string copy{str_with_len_N};/32<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">22.2</td><td class="benchmarkresult">22.6</td><td class="benchmarkresult">86.2</td><td class="benchmarkresult">95.8</td><td class="benchmarkresult">97.0</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string copy{str_with_len_N};/64<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">22.6</td><td class="benchmarkresult">22.9</td><td class="benchmarkresult">79.3</td><td class="benchmarkresult">94.1</td><td class="benchmarkresult">98.1</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string copy{str_with_len_N};/128<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">26.2</td><td class="benchmarkresult">24.2</td><td class="benchmarkresult">85.0</td><td class="benchmarkresult">103</td><td class="benchmarkresult">103</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string copy{str_with_len_N};/256<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">27.3</td><td class="benchmarkresult">25.5</td><td class="benchmarkresult">84.4</td><td class="benchmarkresult">105</td><td class="benchmarkresult">161</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string copy{str_with_len_N};/512<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">28.3</td><td class="benchmarkresult">29.2</td><td class="benchmarkresult">86.6</td><td class="benchmarkresult">97.1</td><td class="benchmarkresult">151</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string copy{str_with_len_N};/1024<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">39.6</td><td class="benchmarkresult">37.2</td><td class="benchmarkresult">95.3</td><td class="benchmarkresult">99.1</td><td class="benchmarkresult">131</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string copy{str_with_len_N};/2048<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">81.3</td><td class="benchmarkresult">81.5</td><td class="benchmarkresult">127</td><td class="benchmarkresult">140</td><td class="benchmarkresult">148</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string copy{str_with_len_N};/4096<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Чем длиннее строка, тем дольше создаётся копия.</span></span></td><td class="benchmarkresult">117</td><td class="benchmarkresult">118</td><td class="benchmarkresult">176</td><td class="benchmarkresult">187</td><td class="benchmarkresult">185</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa copy{str_with_len_N};/15<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Здесь stringa инициализируется не литералом,
|
||
а значит, должна сама хранить символы.</span></span></td><td class="benchmarkresult">1.13</td><td class="benchmarkresult">1.13</td><td class="benchmarkresult">1.34</td><td class="benchmarkresult">4.03</td><td class="benchmarkresult">5.19</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa copy{str_with_len_N};/16<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Под WASM SSO у stringa составляет 15 символов. Кроме того,
|
||
собиралось без поддержки потоков, поэтому возможно атомарный
|
||
инкремент заменён на обычный, судя по времени.</span></span></td><td class="benchmarkresult">1.12</td><td class="benchmarkresult">1.14</td><td class="benchmarkresult">1.35</td><td class="benchmarkresult">4.09</td><td class="benchmarkresult">10.0</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa copy{str_with_len_N};/23<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">SSO в stringa до 23 символов, и даже 23
|
||
копируются быстрее, чем 15 в std::string.</span></span></td><td class="benchmarkresult">1.11</td><td class="benchmarkresult">1.20</td><td class="benchmarkresult">1.35</td><td class="benchmarkresult">4.06</td><td class="benchmarkresult">9.97</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa copy{str_with_len_N};/24<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Всё, не влезаем в SSO, а значит, используем shared буфер.
|
||
Добавляется время на атомарный инкремент счётчика.</span></span></td><td class="benchmarkresult">16.6</td><td class="benchmarkresult">16.3</td><td class="benchmarkresult">15.8</td><td class="benchmarkresult">18.7</td><td class="benchmarkresult">10.1</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa copy{str_with_len_N};/32<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">16.2</td><td class="benchmarkresult">16.2</td><td class="benchmarkresult">15.8</td><td class="benchmarkresult">18.6</td><td class="benchmarkresult">10.0</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa copy{str_with_len_N};/64<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">16.0</td><td class="benchmarkresult">16.2</td><td class="benchmarkresult">16.0</td><td class="benchmarkresult">18.9</td><td class="benchmarkresult">9.95</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa copy{str_with_len_N};/128<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">16.2</td><td class="benchmarkresult">16.3</td><td class="benchmarkresult">15.8</td><td class="benchmarkresult">18.4</td><td class="benchmarkresult">9.93</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa copy{str_with_len_N};/256<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">16.0</td><td class="benchmarkresult">16.2</td><td class="benchmarkresult">15.8</td><td class="benchmarkresult">18.6</td><td class="benchmarkresult">9.95</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa copy{str_with_len_N};/512<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">16.0</td><td class="benchmarkresult">16.1</td><td class="benchmarkresult">16.0</td><td class="benchmarkresult">19.5</td><td class="benchmarkresult">10.0</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa copy{str_with_len_N};/1024<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">16.4</td><td class="benchmarkresult">16.5</td><td class="benchmarkresult">15.9</td><td class="benchmarkresult">18.3</td><td class="benchmarkresult">9.92</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa copy{str_with_len_N};/2048<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">16.1</td><td class="benchmarkresult">16.3</td><td class="benchmarkresult">16.0</td><td class="benchmarkresult">18.5</td><td class="benchmarkresult">10.0</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa copy{str_with_len_N};/4096<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">И как видно, кроме инкремента нет накладных расходов,
|
||
время копирования не зависит от длины строки.</span></span></td><td class="benchmarkresult">16.1</td><td class="benchmarkresult">16.2</td><td class="benchmarkresult">15.9</td><td class="benchmarkresult">18.9</td><td class="benchmarkresult">10.1</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<16> copy{str_with_len_N};/15<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">lstringa<16> использует SSO до 23 символов.
|
||
А в WASM 32-битная архитектура, SSO до 19 символов.</span></span></td><td class="benchmarkresult">5.08</td><td class="benchmarkresult">4.88</td><td class="benchmarkresult">4.96</td><td class="benchmarkresult">7.85</td><td class="benchmarkresult">17.2</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<16> copy{str_with_len_N};/16<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">4.97</td><td class="benchmarkresult">4.89</td><td class="benchmarkresult">4.87</td><td class="benchmarkresult">8.07</td><td class="benchmarkresult">17.0</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<16> copy{str_with_len_N};/23<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">4.90</td><td class="benchmarkresult">5.01</td><td class="benchmarkresult">4.98</td><td class="benchmarkresult">7.94</td><td class="benchmarkresult">77.8</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<16> copy{str_with_len_N};/24<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">И после начинает вести себя при копировании, как std::string.</span></span></td><td class="benchmarkresult">24.2</td><td class="benchmarkresult">25.0</td><td class="benchmarkresult">84.0</td><td class="benchmarkresult">82.8</td><td class="benchmarkresult">76.5</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<16> copy{str_with_len_N};/32<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">24.1</td><td class="benchmarkresult">24.5</td><td class="benchmarkresult">88.0</td><td class="benchmarkresult">85.5</td><td class="benchmarkresult">79.5</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<16> copy{str_with_len_N};/64<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">25.6</td><td class="benchmarkresult">25.9</td><td class="benchmarkresult">84.8</td><td class="benchmarkresult">85.1</td><td class="benchmarkresult">82.9</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<16> copy{str_with_len_N};/128<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">27.3</td><td class="benchmarkresult">26.5</td><td class="benchmarkresult">85.1</td><td class="benchmarkresult">89.8</td><td class="benchmarkresult">83.0</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<16> copy{str_with_len_N};/256<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">27.6</td><td class="benchmarkresult">29.6</td><td class="benchmarkresult">88.2</td><td class="benchmarkresult">655</td><td class="benchmarkresult">133</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<16> copy{str_with_len_N};/512<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">30.4</td><td class="benchmarkresult">30.9</td><td class="benchmarkresult">89.4</td><td class="benchmarkresult">92.5</td><td class="benchmarkresult">130</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<16> copy{str_with_len_N};/1024<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">70.0</td><td class="benchmarkresult">71.7</td><td class="benchmarkresult">101</td><td class="benchmarkresult">101</td><td class="benchmarkresult">111</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<16> copy{str_with_len_N};/2048<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">74.5</td><td class="benchmarkresult">74.3</td><td class="benchmarkresult">131</td><td class="benchmarkresult">132</td><td class="benchmarkresult">122</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<16> copy{str_with_len_N};/4096<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">90.9</td><td class="benchmarkresult">93.3</td><td class="benchmarkresult">194</td><td class="benchmarkresult">196</td><td class="benchmarkresult">167</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> copy{str_with_len_N};/15<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">5.14</td><td class="benchmarkresult">4.93</td><td class="benchmarkresult">4.94</td><td class="benchmarkresult">8.62</td><td class="benchmarkresult">17.9</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> copy{str_with_len_N};/16<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">4.86</td><td class="benchmarkresult">4.97</td><td class="benchmarkresult">5.36</td><td class="benchmarkresult">8.94</td><td class="benchmarkresult">18.5</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> copy{str_with_len_N};/23<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">4.91</td><td class="benchmarkresult">4.94</td><td class="benchmarkresult">5.05</td><td class="benchmarkresult">8.67</td><td class="benchmarkresult">18.6</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> copy{str_with_len_N};/24<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">4.99</td><td class="benchmarkresult">4.90</td><td class="benchmarkresult">4.83</td><td class="benchmarkresult">8.44</td><td class="benchmarkresult">18.8</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> copy{str_with_len_N};/32<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">4.58</td><td class="benchmarkresult">5.03</td><td class="benchmarkresult">7.94</td><td class="benchmarkresult">12.0</td><td class="benchmarkresult">25.0</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> copy{str_with_len_N};/64<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">6.06</td><td class="benchmarkresult">6.12</td><td class="benchmarkresult">7.92</td><td class="benchmarkresult">12.1</td><td class="benchmarkresult">21.2</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> copy{str_with_len_N};/128<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">6.44</td><td class="benchmarkresult">7.87</td><td class="benchmarkresult">8.26</td><td class="benchmarkresult">12.3</td><td class="benchmarkresult">22.3</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> copy{str_with_len_N};/256<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">8.00</td><td class="benchmarkresult">8.70</td><td class="benchmarkresult">9.31</td><td class="benchmarkresult">13.2</td><td class="benchmarkresult">24.0</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> copy{str_with_len_N};/512<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Даже 512 символов копируются быстрее, чем
|
||
одна аллокация или атомарный инкремент.</span></span></td><td class="benchmarkresult">10.7</td><td class="benchmarkresult">10.6</td><td class="benchmarkresult">10.9</td><td class="benchmarkresult">14.6</td><td class="benchmarkresult">26.8</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> copy{str_with_len_N};/1024<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">А дальше уже как у всех</span></span></td><td class="benchmarkresult">69.8</td><td class="benchmarkresult">71.4</td><td class="benchmarkresult">99.0</td><td class="benchmarkresult">98.2</td><td class="benchmarkresult">113</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> copy{str_with_len_N};/2048<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">73.4</td><td class="benchmarkresult">77.5</td><td class="benchmarkresult">131</td><td class="benchmarkresult">131</td><td class="benchmarkresult">129</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> copy{str_with_len_N};/4096<span class="tooltiptext code">template<typename T>
|
||
void CopyDynString(benchmark::State& state) {
|
||
T x(state.range(0), 'a');
|
||
for (auto _: state) {
|
||
T copy{x};
|
||
benchmark::DoNotOptimize(copy);
|
||
benchmark::DoNotOptimize(x);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">90.8</td><td class="benchmarkresult">93.4</td><td class="benchmarkresult">191</td><td class="benchmarkresult">195</td><td class="benchmarkresult">169</td></tr>
|
||
</tbody></table></div><script>bench_sets['Copy not literal Str with N symbols'] = {id:'bs7', tests:[
|
||
{name:'std::string copy{str_with_len_N};/15',data:[4.90,5.07,1.86,4.45,97.2]},
|
||
{name:'std::string copy{str_with_len_N};/16',data:[23.1,23.7,81.6,94.0,94.6]},
|
||
{name:'std::string copy{str_with_len_N};/23',data:[23.2,23.9,79.8,94.8,91.6]},
|
||
{name:'std::string copy{str_with_len_N};/24',data:[22.3,24.9,80.5,97.7,94.5]},
|
||
{name:'std::string copy{str_with_len_N};/32',data:[22.2,22.6,86.2,95.8,97.0]},
|
||
{name:'std::string copy{str_with_len_N};/64',data:[22.6,22.9,79.3,94.1,98.1]},
|
||
{name:'std::string copy{str_with_len_N};/128',data:[26.2,24.2,85.0,103,103]},
|
||
{name:'std::string copy{str_with_len_N};/256',data:[27.3,25.5,84.4,105,161]},
|
||
{name:'std::string copy{str_with_len_N};/512',data:[28.3,29.2,86.6,97.1,151]},
|
||
{name:'std::string copy{str_with_len_N};/1024',data:[39.6,37.2,95.3,99.1,131]},
|
||
{name:'std::string copy{str_with_len_N};/2048',data:[81.3,81.5,127,140,148]},
|
||
{name:'std::string copy{str_with_len_N};/4096',data:[117,118,176,187,185]},
|
||
{name:'stringa copy{str_with_len_N};/15',data:[1.13,1.13,1.34,4.03,5.19]},
|
||
{name:'stringa copy{str_with_len_N};/16',data:[1.12,1.14,1.35,4.09,10.0]},
|
||
{name:'stringa copy{str_with_len_N};/23',data:[1.11,1.20,1.35,4.06,9.97]},
|
||
{name:'stringa copy{str_with_len_N};/24',data:[16.6,16.3,15.8,18.7,10.1]},
|
||
{name:'stringa copy{str_with_len_N};/32',data:[16.2,16.2,15.8,18.6,10.0]},
|
||
{name:'stringa copy{str_with_len_N};/64',data:[16.0,16.2,16.0,18.9,9.95]},
|
||
{name:'stringa copy{str_with_len_N};/128',data:[16.2,16.3,15.8,18.4,9.93]},
|
||
{name:'stringa copy{str_with_len_N};/256',data:[16.0,16.2,15.8,18.6,9.95]},
|
||
{name:'stringa copy{str_with_len_N};/512',data:[16.0,16.1,16.0,19.5,10.0]},
|
||
{name:'stringa copy{str_with_len_N};/1024',data:[16.4,16.5,15.9,18.3,9.92]},
|
||
{name:'stringa copy{str_with_len_N};/2048',data:[16.1,16.3,16.0,18.5,10.0]},
|
||
{name:'stringa copy{str_with_len_N};/4096',data:[16.1,16.2,15.9,18.9,10.1]},
|
||
{name:'lstringa<16> copy{str_with_len_N};/15',data:[5.08,4.88,4.96,7.85,17.2]},
|
||
{name:'lstringa<16> copy{str_with_len_N};/16',data:[4.97,4.89,4.87,8.07,17.0]},
|
||
{name:'lstringa<16> copy{str_with_len_N};/23',data:[4.90,5.01,4.98,7.94,77.8]},
|
||
{name:'lstringa<16> copy{str_with_len_N};/24',data:[24.2,25.0,84.0,82.8,76.5]},
|
||
{name:'lstringa<16> copy{str_with_len_N};/32',data:[24.1,24.5,88.0,85.5,79.5]},
|
||
{name:'lstringa<16> copy{str_with_len_N};/64',data:[25.6,25.9,84.8,85.1,82.9]},
|
||
{name:'lstringa<16> copy{str_with_len_N};/128',data:[27.3,26.5,85.1,89.8,83.0]},
|
||
{name:'lstringa<16> copy{str_with_len_N};/256',data:[27.6,29.6,88.2,655,133]},
|
||
{name:'lstringa<16> copy{str_with_len_N};/512',data:[30.4,30.9,89.4,92.5,130]},
|
||
{name:'lstringa<16> copy{str_with_len_N};/1024',data:[70.0,71.7,101,101,111]},
|
||
{name:'lstringa<16> copy{str_with_len_N};/2048',data:[74.5,74.3,131,132,122]},
|
||
{name:'lstringa<16> copy{str_with_len_N};/4096',data:[90.9,93.3,194,196,167]},
|
||
{name:'lstringa<512> copy{str_with_len_N};/15',data:[5.14,4.93,4.94,8.62,17.9]},
|
||
{name:'lstringa<512> copy{str_with_len_N};/16',data:[4.86,4.97,5.36,8.94,18.5]},
|
||
{name:'lstringa<512> copy{str_with_len_N};/23',data:[4.91,4.94,5.05,8.67,18.6]},
|
||
{name:'lstringa<512> copy{str_with_len_N};/24',data:[4.99,4.90,4.83,8.44,18.8]},
|
||
{name:'lstringa<512> copy{str_with_len_N};/32',data:[4.58,5.03,7.94,12.0,25.0]},
|
||
{name:'lstringa<512> copy{str_with_len_N};/64',data:[6.06,6.12,7.92,12.1,21.2]},
|
||
{name:'lstringa<512> copy{str_with_len_N};/128',data:[6.44,7.87,8.26,12.3,22.3]},
|
||
{name:'lstringa<512> copy{str_with_len_N};/256',data:[8.00,8.70,9.31,13.2,24.0]},
|
||
{name:'lstringa<512> copy{str_with_len_N};/512',data:[10.7,10.6,10.9,14.6,26.8]},
|
||
{name:'lstringa<512> copy{str_with_len_N};/1024',data:[69.8,71.4,99.0,98.2,113]},
|
||
{name:'lstringa<512> copy{str_with_len_N};/2048',data:[73.4,77.5,131,131,129]},
|
||
{name:'lstringa<512> copy{str_with_len_N};/4096',data:[90.8,93.4,191,195,169]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs8"><h4>Convert to int '1234567'</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string s = "123456789"; int res = std::strtol(s.c_str(), 0, 10);<span class="tooltiptext code">void ToIntStr10(benchmark::State& state, const std::string& s, int c) {
|
||
for (auto _: state) {
|
||
int res = std::strtol(s.c_str(), nullptr, 10);
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">В simstr для конвертации в число достаточно куска строки,
|
||
нет нужды в null терминированности. Ближайший аналог такого
|
||
поведения "std::from_chars", но он к сожалению очень ограничен
|
||
по возможностям. Здесь я попытался произвести тесты, близкие по
|
||
логике к работе std::from_chars</span></span></td><td class="benchmarkresult">27.5</td><td class="benchmarkresult">27.0</td><td class="benchmarkresult">31.7</td><td class="benchmarkresult">32.4</td><td class="benchmarkresult">204</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string_view s = "123456789"; std::from_chars(s.data(), s.data() + s.size(), res, 10);<span class="tooltiptext code">void ToIntFromChars10(benchmark::State& state, const std::string_view& s, int c) {
|
||
for (auto _: state) {
|
||
int res = 0;
|
||
std::from_chars(s.data(), s.data() + s.size(), res, 10);
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">from_chars требует точного указания основания счисления,
|
||
не допускает знаков плюс, пробелов, префиксов 0x и т.п.</span></span></td><td class="benchmarkresult">15.8</td><td class="benchmarkresult">12.3</td><td class="benchmarkresult">13.9</td><td class="benchmarkresult">15.0</td><td class="benchmarkresult">65.9</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa s = "123456789"; int res = s.to_int<int, true, 10, false><span class="tooltiptext code">template<typename T>
|
||
void ToIntSimStr10(benchmark::State& state, T t, int c) {
|
||
for (auto _: state) {
|
||
int res = t. template to_int<int, true, 10, false, false>().value;
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
benchmark::DoNotOptimize(t);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Здесь для to_int заданы такие же ограничения - проверять переполнение,
|
||
десятичная система, без лидирующих пробелов и знака плюс</span></span></td><td class="benchmarkresult">12.8</td><td class="benchmarkresult">8.38</td><td class="benchmarkresult">14.3</td><td class="benchmarkresult">15.3</td><td class="benchmarkresult">58.9</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">ssa s = "123456789"; int res = s.to_int<int, true, 10, false><span class="tooltiptext code">template<typename T>
|
||
void ToIntSimStr10(benchmark::State& state, T t, int c) {
|
||
for (auto _: state) {
|
||
int res = t. template to_int<int, true, 10, false, false>().value;
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
benchmark::DoNotOptimize(t);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">12.5</td><td class="benchmarkresult">8.48</td><td class="benchmarkresult">13.0</td><td class="benchmarkresult">16.2</td><td class="benchmarkresult">54.2</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<20> s = "123456789"; int res = s.to_int<int, true, 10, false><span class="tooltiptext code">template<typename T>
|
||
void ToIntSimStr10(benchmark::State& state, T t, int c) {
|
||
for (auto _: state) {
|
||
int res = t. template to_int<int, true, 10, false, false>().value;
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
benchmark::DoNotOptimize(t);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">12.5</td><td class="benchmarkresult">8.36</td><td class="benchmarkresult">13.4</td><td class="benchmarkresult">15.9</td><td class="benchmarkresult">54.1</td></tr>
|
||
</tbody></table></div><script>bench_sets['Convert to int \'1234567\''] = {id:'bs8', tests:[
|
||
{name:'std::string s = "123456789"; int res = std::strtol(s.c_str(), 0, 10);',data:[27.5,27.0,31.7,32.4,204]},
|
||
{name:'std::string_view s = "123456789"; std::from_chars(s.data(), s.data() + s.size(), res, 10);',data:[15.8,12.3,13.9,15.0,65.9]},
|
||
{name:'stringa s = "123456789"; int res = s.to_int<int, true, 10, false>',data:[12.8,8.38,14.3,15.3,58.9]},
|
||
{name:'ssa s = "123456789"; int res = s.to_int<int, true, 10, false>',data:[12.5,8.48,13.0,16.2,54.2]},
|
||
{name:'lstringa<20> s = "123456789"; int res = s.to_int<int, true, 10, false>',data:[12.5,8.36,13.4,15.9,54.1]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs9"><h4>Convert to unsigned 'abcDef'</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string s = "abcDef"; int res = std::strtol(s.c_str(), 0, 16);<span class="tooltiptext code">void ToIntStr16(benchmark::State& state, const std::string& s, int c) {
|
||
for (auto _: state) {
|
||
int res = std::strtol(s.c_str(), nullptr, 16);
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Всё то же, только для 16ричной системы</span></span></td><td class="benchmarkresult">23.9</td><td class="benchmarkresult">24.3</td><td class="benchmarkresult">34.5</td><td class="benchmarkresult">35.7</td><td class="benchmarkresult">158</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string_view s = "abcDef"; std::from_chars(s.data(), s.data() + s.size(), res, 16);<span class="tooltiptext code">void ToIntFromChars16(benchmark::State& state, const std::string_view& s, int c) {
|
||
for (auto _: state) {
|
||
int res = 0;
|
||
std::from_chars(s.data(), s.data() + s.size(), res, 16);
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">10.0</td><td class="benchmarkresult">15.0</td><td class="benchmarkresult">8.49</td><td class="benchmarkresult">9.90</td><td class="benchmarkresult">85.4</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa s = "abcDef"; int res = s.to_int<int, true, 16, false><span class="tooltiptext code">template<typename T>
|
||
void ToIntSimStr16(benchmark::State& state, T t, int c) {
|
||
for (auto _: state) {
|
||
int res = t. template to_int<int, true, 16, false, false>().value;
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
benchmark::DoNotOptimize(t);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">12.9</td><td class="benchmarkresult">8.57</td><td class="benchmarkresult">12.3</td><td class="benchmarkresult">14.6</td><td class="benchmarkresult">50.4</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">ssa s = "abcDef"; int res = s.to_int<int, true, 16, false><span class="tooltiptext code">template<typename T>
|
||
void ToIntSimStr16(benchmark::State& state, T t, int c) {
|
||
for (auto _: state) {
|
||
int res = t. template to_int<int, true, 16, false, false>().value;
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
benchmark::DoNotOptimize(t);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">12.5</td><td class="benchmarkresult">7.90</td><td class="benchmarkresult">12.0</td><td class="benchmarkresult">14.0</td><td class="benchmarkresult">47.5</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<20> s = "abcDef"; int res = s.to_int<int, true, 16, false><span class="tooltiptext code">template<typename T>
|
||
void ToIntSimStr16(benchmark::State& state, T t, int c) {
|
||
for (auto _: state) {
|
||
int res = t. template to_int<int, true, 16, false, false>().value;
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
benchmark::DoNotOptimize(t);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">12.7</td><td class="benchmarkresult">7.94</td><td class="benchmarkresult">11.8</td><td class="benchmarkresult">13.9</td><td class="benchmarkresult">47.2</td></tr>
|
||
</tbody></table></div><script>bench_sets['Convert to unsigned \'abcDef\''] = {id:'bs9', tests:[
|
||
{name:'std::string s = "abcDef"; int res = std::strtol(s.c_str(), 0, 16);',data:[23.9,24.3,34.5,35.7,158]},
|
||
{name:'std::string_view s = "abcDef"; std::from_chars(s.data(), s.data() + s.size(), res, 16);',data:[10.0,15.0,8.49,9.90,85.4]},
|
||
{name:'stringa s = "abcDef"; int res = s.to_int<int, true, 16, false>',data:[12.9,8.57,12.3,14.6,50.4]},
|
||
{name:'ssa s = "abcDef"; int res = s.to_int<int, true, 16, false>',data:[12.5,7.90,12.0,14.0,47.5]},
|
||
{name:'lstringa<20> s = "abcDef"; int res = s.to_int<int, true, 16, false>',data:[12.7,7.94,11.8,13.9,47.2]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs10"><h4>Convert to int ' 1234567'</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string s = " 123456789"; int res = std::strtol(s.c_str(), 0, 0);<span class="tooltiptext code">void ToIntStr0(benchmark::State& state, const std::string& s, int c) {
|
||
for (auto _: state) {
|
||
int res = std::strtol(s.c_str(), nullptr, 0);
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">А здесь уже парсинг произвольного числа.</span></span></td><td class="benchmarkresult">28.9</td><td class="benchmarkresult">28.7</td><td class="benchmarkresult">44.1</td><td class="benchmarkresult">47.2</td><td class="benchmarkresult">226</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa s = " 123456789"; int res = s.to_int<int>; // Check overflow<span class="tooltiptext code">template<typename T>
|
||
void ToIntSimStr0(benchmark::State& state, T t, int c) {
|
||
for (auto _: state) {
|
||
int res = t. template to_int<int>().value;
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
benchmark::DoNotOptimize(t);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">18.8</td><td class="benchmarkresult">15.7</td><td class="benchmarkresult">17.2</td><td class="benchmarkresult">20.0</td><td class="benchmarkresult">80.3</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">ssa s = " 123456789"; int res = s.to_int<int, false>; // No check overflow<span class="tooltiptext code">void ToIntNoOverflow(benchmark::State& state, ssa t, int c) {
|
||
for (auto _: state) {
|
||
int res = t.to_int<int, false>().value;
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
benchmark::DoNotOptimize(t);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">16.1</td><td class="benchmarkresult">10.9</td><td class="benchmarkresult">16.6</td><td class="benchmarkresult">18.5</td><td class="benchmarkresult">53.0</td></tr>
|
||
</tbody></table></div><script>bench_sets['Convert to int \' 1234567\''] = {id:'bs10', tests:[
|
||
{name:'std::string s = " 123456789"; int res = std::strtol(s.c_str(), 0, 0);',data:[28.9,28.7,44.1,47.2,226]},
|
||
{name:'stringa s = " 123456789"; int res = s.to_int<int>; // Check overflow',data:[18.8,15.7,17.2,20.0,80.3]},
|
||
{name:'ssa s = " 123456789"; int res = s.to_int<int, false>; // No check overflow',data:[16.1,10.9,16.6,18.5,53.0]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs11"><h4>Convert to double '1234.567e10'</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string s = "1234.567e10"; double res = std::strtod(s.c_str(), nullptr);<span class="tooltiptext code">void ToDoubleStr(benchmark::State& state, const std::string& s, double c) {
|
||
for (auto _: state) {
|
||
char* ptr = nullptr;
|
||
double res = std::strtod(s.c_str(), &ptr);
|
||
if (ptr == s.c_str()) {
|
||
state.SkipWithError("not equal");
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">65.0</td><td class="benchmarkresult">65.0</td><td class="benchmarkresult">103</td><td class="benchmarkresult">106</td><td class="benchmarkresult">460</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string_view s = "1234.567e10"; std::from_chars(s.data(), s.data() + s.size(), res);<span class="tooltiptext code">void ToDoubleFromChars(benchmark::State& state, const std::string_view& s, double c) {
|
||
for (auto _: state) {
|
||
double res = 0;
|
||
if (std::from_chars(s.data(), s.data() + s.size(), res).ec != std::errc{}) {
|
||
state.SkipWithError("not equal");
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">24.2</td><td class="benchmarkresult">23.9</td><td class="benchmarkresult">62.8</td><td class="benchmarkresult">85.6</td><td class="benchmarkresult">294</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">ssa s = "1234.567e10"; double res = *s.to_double()<span class="tooltiptext code">template<typename T>
|
||
void ToDoubleSimStr(benchmark::State& state, T t, double c) {
|
||
for (auto _: state) {
|
||
auto r = t.template to_double<false>();
|
||
if (!r) {
|
||
state.SkipWithError("not equal");
|
||
}
|
||
double res = *r;
|
||
#ifdef CHECK_RESULT
|
||
if (res != c) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
benchmark::DoNotOptimize(t);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">26.1</td><td class="benchmarkresult">24.3</td><td class="benchmarkresult">35.7</td><td class="benchmarkresult">37.7</td><td class="benchmarkresult">105</td></tr>
|
||
</tbody></table></div><script>bench_sets['Convert to double \'1234.567e10\''] = {id:'bs11', tests:[
|
||
{name:'std::string s = "1234.567e10"; double res = std::strtod(s.c_str(), nullptr);',data:[65.0,65.0,103,106,460]},
|
||
{name:'std::string_view s = "1234.567e10"; std::from_chars(s.data(), s.data() + s.size(), res);',data:[24.2,23.9,62.8,85.6,294]},
|
||
{name:'ssa s = "1234.567e10"; double res = *s.to_double()',data:[26.1,24.3,35.7,37.7,105]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs12"><h4>Append const literal of 16 bytes 64 times, 1024 total length</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::stringstream str; ... str << "abbaabbaabbaabba";<span class="tooltiptext code">void AppendStreamConstLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
std::string result;
|
||
std::stringstream str;
|
||
for (size_t c = 0; c < 64; c++) {
|
||
str << TEXT_16;
|
||
}
|
||
result = str.str();
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(str);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1403</td><td class="benchmarkresult">1513</td><td class="benchmarkresult">4774</td><td class="benchmarkresult">5830</td><td class="benchmarkresult">11819</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string str; ... str += "abbaabbaabbaabba";<span class="tooltiptext code">void AppendStdStringConstLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
std::string result;
|
||
for (size_t c = 0; c < 64; c++) {
|
||
result += TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">359</td><td class="benchmarkresult">346</td><td class="benchmarkresult">1084</td><td class="benchmarkresult">1313</td><td class="benchmarkresult">1174</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<8> str; ... str += "abbaabbaabbaabba";<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstringConstLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 64; c++) {
|
||
result += TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">337</td><td class="benchmarkresult">371</td><td class="benchmarkresult">767</td><td class="benchmarkresult">973</td><td class="benchmarkresult">1294</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<128> str; ... str += "abbaabbaabbaabba";<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstringConstLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 64; c++) {
|
||
result += TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Чем больше внутренний буфер, тем меньше раз требуется
|
||
аллокация, тем быстрее результат.</span></span></td><td class="benchmarkresult">242</td><td class="benchmarkresult">264</td><td class="benchmarkresult">391</td><td class="benchmarkresult">541</td><td class="benchmarkresult">900</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> str; ... str += "abbaabbaabbaabba";<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstringConstLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 64; c++) {
|
||
result += TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">227</td><td class="benchmarkresult">239</td><td class="benchmarkresult">246</td><td class="benchmarkresult">365</td><td class="benchmarkresult">637</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<1024> str; ... str += "abbaabbaabbaabba";<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstringConstLiteral(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 64; c++) {
|
||
result += TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">138</td><td class="benchmarkresult">141</td><td class="benchmarkresult">154</td><td class="benchmarkresult">254</td><td class="benchmarkresult">501</td></tr>
|
||
</tbody></table></div><script>bench_sets['Append const literal of 16 bytes 64 times, 1024 total length'] = {id:'bs12', tests:[
|
||
{name:'std::stringstream str; ... str << "abbaabbaabbaabba";',data:[1403,1513,4774,5830,11819]},
|
||
{name:'std::string str; ... str += "abbaabbaabbaabba";',data:[359,346,1084,1313,1174]},
|
||
{name:'lstringa<8> str; ... str += "abbaabbaabbaabba";',data:[337,371,767,973,1294]},
|
||
{name:'lstringa<128> str; ... str += "abbaabbaabbaabba";',data:[242,264,391,541,900]},
|
||
{name:'lstringa<512> str; ... str += "abbaabbaabbaabba";',data:[227,239,246,365,637]},
|
||
{name:'lstringa<1024> str; ... str += "abbaabbaabbaabba";',data:[138,141,154,254,501]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs13"><h4>Append string of 16 bytes and const literal of 16 bytes 32 times, 1024 total length</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::stringstream str; ... str << str_var << "abbaabbaabbaabba";<span class="tooltiptext code">void AppendStreamStrConstLiteral(benchmark::State& state) {
|
||
std::string s1 = TEXT_16;
|
||
for (auto _: state) {
|
||
std::string result;
|
||
std::stringstream s;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
s << s1 << TEXT_16;
|
||
}
|
||
result = s.str();
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(s1);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1403</td><td class="benchmarkresult">1456</td><td class="benchmarkresult">4816</td><td class="benchmarkresult">5571</td><td class="benchmarkresult">11807</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string str; ... str += str_var + "abbaabbaabbaabba";<span class="tooltiptext code">void AppendStdStrStrConstLiteral(benchmark::State& state) {
|
||
std::string p1 = TEXT_16;
|
||
for (auto _: state) {
|
||
std::string result;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
result += p1 + TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(p1);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1296</td><td class="benchmarkresult">1276</td><td class="benchmarkresult">3968</td><td class="benchmarkresult">4182</td><td class="benchmarkresult">4085</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<8> str; ... str += str_var + "abbaabbaabbaabba";<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstringStrConstLiteral(benchmark::State& state) {
|
||
stringa p1 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
result += p1 + TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(p1);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">431</td><td class="benchmarkresult">420</td><td class="benchmarkresult">796</td><td class="benchmarkresult">827</td><td class="benchmarkresult">1439</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<128> str; ... str += str_var + "abbaabbaabbaabba";<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstringStrConstLiteral(benchmark::State& state) {
|
||
stringa p1 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
result += p1 + TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(p1);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">326</td><td class="benchmarkresult">355</td><td class="benchmarkresult">492</td><td class="benchmarkresult">542</td><td class="benchmarkresult">1179</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> str; ... str += str_var + "abbaabbaabbaabba";<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstringStrConstLiteral(benchmark::State& state) {
|
||
stringa p1 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
result += p1 + TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(p1);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">312</td><td class="benchmarkresult">310</td><td class="benchmarkresult">315</td><td class="benchmarkresult">381</td><td class="benchmarkresult">934</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<1024> str; ... str += str_var + "abbaabbaabbaabba";<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstringStrConstLiteral(benchmark::State& state) {
|
||
stringa p1 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
result += p1 + TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(p1);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">253</td><td class="benchmarkresult">253</td><td class="benchmarkresult">216</td><td class="benchmarkresult">271</td><td class="benchmarkresult">734</td></tr>
|
||
</tbody></table></div><script>bench_sets['Append string of 16 bytes and const literal of 16 bytes 32 times, 1024 total length'] = {id:'bs13', tests:[
|
||
{name:'std::stringstream str; ... str << str_var << "abbaabbaabbaabba";',data:[1403,1456,4816,5571,11807]},
|
||
{name:'std::string str; ... str += str_var + "abbaabbaabbaabba";',data:[1296,1276,3968,4182,4085]},
|
||
{name:'lstringa<8> str; ... str += str_var + "abbaabbaabbaabba";',data:[431,420,796,827,1439]},
|
||
{name:'lstringa<128> str; ... str += str_var + "abbaabbaabbaabba";',data:[326,355,492,542,1179]},
|
||
{name:'lstringa<512> str; ... str += str_var + "abbaabbaabbaabba";',data:[312,310,315,381,934]},
|
||
{name:'lstringa<1024> str; ... str += str_var + "abbaabbaabbaabba";',data:[253,253,216,271,734]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs14"><h4>Append string of 16 bytes and const literal of 16 bytes 2048 times, 65536 total length</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::stringstream str; ... str << str_var << "abbaabbaabbaabba"; 2048 times<span class="tooltiptext code">void AppendStreamStrConstLiteralBig(benchmark::State& state) {
|
||
std::string s1 = TEXT_16;
|
||
for (auto _: state) {
|
||
std::string result;
|
||
std::stringstream s;
|
||
for (size_t c = 0; c < 2048; c++) {
|
||
s << s1 << TEXT_16;
|
||
}
|
||
result = s.str();
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024 * 64) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(s1);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">125727</td><td class="benchmarkresult">132670</td><td class="benchmarkresult">219773</td><td class="benchmarkresult">284627</td><td class="benchmarkresult">609176</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string str; ... str += str_var + "abbaabbaabbaabba"; 2048 times<span class="tooltiptext code">void AppendStdStrStrConstLiteralBig(benchmark::State& state) {
|
||
std::string p1 = TEXT_16;
|
||
for (auto _: state) {
|
||
std::string result;
|
||
for (size_t c = 0; c < 2048; c++) {
|
||
result += p1 + TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024 * 64) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(p1);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">77160</td><td class="benchmarkresult">74369</td><td class="benchmarkresult">193770</td><td class="benchmarkresult">193928</td><td class="benchmarkresult">207760</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<8> str; ... str += str_var + "abbaabbaabbaabba"; 2048 times<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstringStrConstLiteralBig(benchmark::State& state) {
|
||
stringa p1 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 2048; c++) {
|
||
result += p1 + TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024 * 64) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(p1);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">52479</td><td class="benchmarkresult">55191</td><td class="benchmarkresult">19446</td><td class="benchmarkresult">23525</td><td class="benchmarkresult">53812</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<128> str; ... str += str_var + "abbaabbaabbaabba"; 2048 times<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstringStrConstLiteralBig(benchmark::State& state) {
|
||
stringa p1 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 2048; c++) {
|
||
result += p1 + TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024 * 64) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(p1);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">28389</td><td class="benchmarkresult">28835</td><td class="benchmarkresult">19410</td><td class="benchmarkresult">22444</td><td class="benchmarkresult">51889</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> str; ... str += str_var + "abbaabbaabbaabba"; 2048 times<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstringStrConstLiteralBig(benchmark::State& state) {
|
||
stringa p1 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 2048; c++) {
|
||
result += p1 + TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024 * 64) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(p1);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">18137</td><td class="benchmarkresult">19500</td><td class="benchmarkresult">18772</td><td class="benchmarkresult">22848</td><td class="benchmarkresult">50113</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<1024> str; ... str += str_var + "abbaabbaabbaabba"; 2048 times<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstringStrConstLiteralBig(benchmark::State& state) {
|
||
stringa p1 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 2048; c++) {
|
||
result += p1 + TEXT_16;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024 * 64) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(p1);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">15503</td><td class="benchmarkresult">18108</td><td class="benchmarkresult">18557</td><td class="benchmarkresult">21680</td><td class="benchmarkresult">52780</td></tr>
|
||
</tbody></table></div><script>bench_sets['Append string of 16 bytes and const literal of 16 bytes 2048 times, 65536 total length'] = {id:'bs14', tests:[
|
||
{name:'std::stringstream str; ... str << str_var << "abbaabbaabbaabba"; 2048 times',data:[125727,132670,219773,284627,609176]},
|
||
{name:'std::string str; ... str += str_var + "abbaabbaabbaabba"; 2048 times',data:[77160,74369,193770,193928,207760]},
|
||
{name:'lstringa<8> str; ... str += str_var + "abbaabbaabbaabba"; 2048 times',data:[52479,55191,19446,23525,53812]},
|
||
{name:'lstringa<128> str; ... str += str_var + "abbaabbaabbaabba"; 2048 times',data:[28389,28835,19410,22444,51889]},
|
||
{name:'lstringa<512> str; ... str += str_var + "abbaabbaabbaabba"; 2048 times',data:[18137,19500,18772,22848,50113]},
|
||
{name:'lstringa<1024> str; ... str += str_var + "abbaabbaabbaabba"; 2048 times',data:[15503,18108,18557,21680,52780]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs15"><h4>Append 2 string of 16 bytes 32 times, 1024 total length</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::stringstream str; ... str << str_var1 << str_var2;<span class="tooltiptext code">void AppendStream2String(benchmark::State& state) {
|
||
std::string s1 = TEXT_16;
|
||
std::string s2 = TEXT_16;
|
||
for (auto _: state) {
|
||
std::string result;
|
||
std::stringstream s;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
s << s1 << s2;
|
||
}
|
||
result = s.str();
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(s1);
|
||
benchmark::DoNotOptimize(s2);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1369</td><td class="benchmarkresult">1425</td><td class="benchmarkresult">4503</td><td class="benchmarkresult">5453</td><td class="benchmarkresult">11836</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string str; ... str += str_var1 + str_var2;<span class="tooltiptext code">void AppendStdStr2String(benchmark::State& state) {
|
||
std::string s1 = TEXT_16;
|
||
std::string s2 = TEXT_16;
|
||
|
||
for (auto _: state) {
|
||
std::string result;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
result += s1 + s2;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.size() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(s1);
|
||
benchmark::DoNotOptimize(s2);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1396</td><td class="benchmarkresult">1392</td><td class="benchmarkresult">4062</td><td class="benchmarkresult">4415</td><td class="benchmarkresult">4507</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<16> str; ... str += str_var1 + str_var2;<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstring2String(benchmark::State& state) {
|
||
stra s1 = TEXT_16;
|
||
stra s2 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
result += s1 + s2;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(s1);
|
||
benchmark::DoNotOptimize(s2);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">523</td><td class="benchmarkresult">630</td><td class="benchmarkresult">842</td><td class="benchmarkresult">959</td><td class="benchmarkresult">1657</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<128> str; ... str += str_var1 + str_var2;<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstring2String(benchmark::State& state) {
|
||
stra s1 = TEXT_16;
|
||
stra s2 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
result += s1 + s2;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(s1);
|
||
benchmark::DoNotOptimize(s2);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">419</td><td class="benchmarkresult">534</td><td class="benchmarkresult">546</td><td class="benchmarkresult">656</td><td class="benchmarkresult">1413</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<512> str; ... str += str_var1 + str_var2;<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstring2String(benchmark::State& state) {
|
||
stra s1 = TEXT_16;
|
||
stra s2 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
result += s1 + s2;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(s1);
|
||
benchmark::DoNotOptimize(s2);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">395</td><td class="benchmarkresult">470</td><td class="benchmarkresult">416</td><td class="benchmarkresult">484</td><td class="benchmarkresult">1088</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<1024> str; ... str += str_var1 + str_var2;<span class="tooltiptext code">template<unsigned N>
|
||
void AppendLstring2String(benchmark::State& state) {
|
||
stra s1 = TEXT_16;
|
||
stra s2 = TEXT_16;
|
||
for (auto _: state) {
|
||
lstringa<N> result;
|
||
for (size_t c = 0; c < 32; c++) {
|
||
result += s1 + s2;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result.length() != 1024) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(s1);
|
||
benchmark::DoNotOptimize(s2);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">311</td><td class="benchmarkresult">434</td><td class="benchmarkresult">311</td><td class="benchmarkresult">388</td><td class="benchmarkresult">977</td></tr>
|
||
</tbody></table></div><script>bench_sets['Append 2 string of 16 bytes 32 times, 1024 total length'] = {id:'bs15', tests:[
|
||
{name:'std::stringstream str; ... str << str_var1 << str_var2;',data:[1369,1425,4503,5453,11836]},
|
||
{name:'std::string str; ... str += str_var1 + str_var2;',data:[1396,1392,4062,4415,4507]},
|
||
{name:'lstringa<16> str; ... str += str_var1 + str_var2;',data:[523,630,842,959,1657]},
|
||
{name:'lstringa<128> str; ... str += str_var1 + str_var2;',data:[419,534,546,656,1413]},
|
||
{name:'lstringa<512> str; ... str += str_var1 + str_var2;',data:[395,470,416,484,1088]},
|
||
{name:'lstringa<1024> str; ... str += str_var1 + str_var2;',data:[311,434,311,388,977]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs16"><h4>Append text, number, text</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::stringstream str; str << "test = " << k << " times";<span class="tooltiptext code">void AppendStreamStrNumStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
std::stringstream t;
|
||
t << "test = " << k << " times";
|
||
std::string result = t.str();
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">3149</td><td class="benchmarkresult">3106</td><td class="benchmarkresult">10976</td><td class="benchmarkresult">12174</td><td class="benchmarkresult">19450</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string str = "test = " + std::to_string(k) + " times";<span class="tooltiptext code">void AppendStdStringStrNumStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
std::string result = "test = " + std::to_string(k) + " times";
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">482</td><td class="benchmarkresult">448</td><td class="benchmarkresult">1131</td><td class="benchmarkresult">1244</td><td class="benchmarkresult">3261</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">char buf[100]; sprintf(buf, "test = %u times", k); std::string str = buf;<span class="tooltiptext code">void AppendSprintfStrNumStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
char buf[100];
|
||
std::sprintf(buf, "test = %u times", k);
|
||
std::string result = buf;
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1416</td><td class="benchmarkresult">1526</td><td class="benchmarkresult">2941</td><td class="benchmarkresult">2886</td><td class="benchmarkresult">7677</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string str = std::format("test = {} times", k);<span class="tooltiptext code">void AppendFormatStrNumStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
std::string result = std::format("test = {} times", k);
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1134</td><td class="benchmarkresult">1271</td><td class="benchmarkresult">2082</td><td class="benchmarkresult">2480</td><td class="benchmarkresult">4200</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<8> str; str.format("test = {} times", k);<span class="tooltiptext code">template<typename T>
|
||
void AppendSimStrStrNumStrF(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
T result;
|
||
result.format("test = {} times", k);
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">В simstr format с первого раза не помещается в такую строку без аллокации.</span></span></td><td class="benchmarkresult">1390</td><td class="benchmarkresult">1674</td><td class="benchmarkresult">2137</td><td class="benchmarkresult">2641</td><td class="benchmarkresult">6598</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<32> str; str.format("test = {} times", k);<span class="tooltiptext code">template<typename T>
|
||
void AppendSimStrStrNumStrF(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
T result;
|
||
result.format("test = {} times", k);
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">А в такую помещается. Используйте сразу буфера подходящего размера.</span></span></td><td class="benchmarkresult">963</td><td class="benchmarkresult">1138</td><td class="benchmarkresult">1004</td><td class="benchmarkresult">1551</td><td class="benchmarkresult">4632</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<8> str = "test = " + k + " times";<span class="tooltiptext code">template<typename T>
|
||
void AppendSimStrStrNumStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
T result = "test = "_ss + k + " times";
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Результат не помещается в SSO, возникает аллокация.</span></span></td><td class="benchmarkresult">290</td><td class="benchmarkresult">317</td><td class="benchmarkresult">830</td><td class="benchmarkresult">911</td><td class="benchmarkresult">1342</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">lstringa<32> str = "test = " + k + " times";<span class="tooltiptext code">template<typename T>
|
||
void AppendSimStrStrNumStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
T result = "test = "_ss + k + " times";
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">А здесь и ниже - результат укладывается в SSO.
|
||
Ещё раз - используйте сразу буфера подходящего размера.</span></span></td><td class="benchmarkresult">157</td><td class="benchmarkresult">154</td><td class="benchmarkresult">158</td><td class="benchmarkresult">195</td><td class="benchmarkresult">614</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">stringa str = "test = " + k + " times";<span class="tooltiptext code">template<typename T>
|
||
void AppendSimStrStrNumStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
for (unsigned k = 1; k <= 1'000'000'000; k *= 10) {
|
||
T result = "test = "_ss + k + " times";
|
||
#ifdef CHECK_RESULT
|
||
if (!result.starts_with("test = ") || !result.ends_with(" times")) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(k);
|
||
}
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Под WASM размер SSO 15 символов, что явно не хватает для размещения
|
||
результата, отсюда и такое время.</span></span></td><td class="benchmarkresult">149</td><td class="benchmarkresult">170</td><td class="benchmarkresult">158</td><td class="benchmarkresult">247</td><td class="benchmarkresult">1303</td></tr>
|
||
</tbody></table></div><script>bench_sets['Append text, number, text'] = {id:'bs16', tests:[
|
||
{name:'std::stringstream str; str << "test = " << k << " times";',data:[3149,3106,10976,12174,19450]},
|
||
{name:'std::string str = "test = " + std::to_string(k) + " times";',data:[482,448,1131,1244,3261]},
|
||
{name:'char buf[100]; sprintf(buf, "test = %u times", k); std::string str = buf;',data:[1416,1526,2941,2886,7677]},
|
||
{name:'std::string str = std::format("test = {} times", k);',data:[1134,1271,2082,2480,4200]},
|
||
{name:'lstringa<8> str; str.format("test = {} times", k);',data:[1390,1674,2137,2641,6598]},
|
||
{name:'lstringa<32> str; str.format("test = {} times", k);',data:[963,1138,1004,1551,4632]},
|
||
{name:'lstringa<8> str = "test = " + k + " times";',data:[290,317,830,911,1342]},
|
||
{name:'lstringa<32> str = "test = " + k + " times";',data:[157,154,158,195,614]},
|
||
{name:'stringa str = "test = " + k + " times";',data:[149,170,158,247,1303]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs17"><h4>Split text and convert to int</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::string::find + substr + std::strtol<span class="tooltiptext code">void SplitConvertIntStdString(benchmark::State& state) {
|
||
std::string numbers = NUMBER_LIST;
|
||
for (auto _: state) {
|
||
int total = 0;
|
||
for (size_t start = 0; start < numbers.length(); ) {
|
||
int delim = numbers.find("-!-", start);
|
||
if (delim == std::string::npos) {
|
||
delim = numbers.size();
|
||
}
|
||
std::string part = numbers.substr(start, delim - start);
|
||
total += std::strtol(part.c_str(), nullptr, 0);
|
||
start = delim + 3;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (total != 218) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(total);
|
||
benchmark::DoNotOptimize(numbers);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">276</td><td class="benchmarkresult">273</td><td class="benchmarkresult">558</td><td class="benchmarkresult">571</td><td class="benchmarkresult">1414</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">ssa::splitter + ssa::as_int<span class="tooltiptext code">void SplitConvertIntSimStr(benchmark::State& state) {
|
||
stra numbers = NUMBER_LIST;
|
||
for (auto _: state) {
|
||
int total = 0;
|
||
for (auto splitter = numbers.splitter("-!-"); !splitter.is_done();) {
|
||
total += splitter.next().as_int<int>();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (total != 218) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(total);
|
||
benchmark::DoNotOptimize(numbers);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">154</td><td class="benchmarkresult">137</td><td class="benchmarkresult">171</td><td class="benchmarkresult">311</td><td class="benchmarkresult">670</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">ssa::splitf + functor<span class="tooltiptext code">void SplitConvertIntSplitf(benchmark::State& state) {
|
||
stra numbers = NUMBER_LIST;
|
||
for (auto _: state) {
|
||
int total = 0;
|
||
numbers.splitf<void>("-!-", [&](ssa& part){total += part.as_int<int>();});
|
||
#ifdef CHECK_RESULT
|
||
if (total != 218) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(total);
|
||
benchmark::DoNotOptimize(numbers);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">214</td><td class="benchmarkresult">130</td><td class="benchmarkresult">190</td><td class="benchmarkresult">220</td><td class="benchmarkresult">939</td></tr>
|
||
</tbody></table></div><script>bench_sets['Split text and convert to int'] = {id:'bs17', tests:[
|
||
{name:'std::string::find + substr + std::strtol',data:[276,273,558,571,1414]},
|
||
{name:'ssa::splitter + ssa::as_int',data:[154,137,171,311,670]},
|
||
{name:'ssa::splitf + functor',data:[214,130,190,220,939]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs18"><h4>Replace symbols in text ~400 symbols</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">Naive (and wrong) replace symbols with std::string find + replace<span class="tooltiptext code">void ReplaceSymbolsStdStringNaiveWrong(benchmark::State& state) {
|
||
std::string_view source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
;
|
||
std::vector<std::pair<u8s, std::string_view>> repl = {
|
||
{'&', "&amp;"},
|
||
{'-', ""},
|
||
{'<', "&lt;"},
|
||
{'>', "&gt;"},
|
||
{'\'', "&#39;"},
|
||
{'\"', "&quot;"}
|
||
};
|
||
|
||
auto repl_all = [](std::string& str, char s, std::string_view repl) {
|
||
size_t start_pos = 0;
|
||
while((start_pos = str.find(s, start_pos)) != std::string::npos) {
|
||
str.replace(start_pos, 1, repl);
|
||
start_pos += repl.length();
|
||
}
|
||
};
|
||
for (auto _: state) {
|
||
std::string result{source};
|
||
for (const auto& r : repl) {
|
||
repl_all(result, r.first, r.second);
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Это наивная реализация, которая неверно отработает на
|
||
таких заменах, как 'a'->'b' и 'b'->'a'. Но если замены не конфликтуют,
|
||
то работает быстро.</span></span></td><td class="benchmarkresult">852</td><td class="benchmarkresult">851</td><td class="benchmarkresult">1171</td><td class="benchmarkresult">1258</td><td class="benchmarkresult">6175</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace symbols with std::string find_first_of + replace<span class="tooltiptext code">void ReplaceSymbolsStdStringNaiveRight(benchmark::State& state) {
|
||
std::string_view source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
;
|
||
std::vector<std::pair<u8s, std::string_view>> repl = {
|
||
{'-', ""},
|
||
{'<', "&lt;"},
|
||
{'>', "&gt;"},
|
||
{'\'', "&#39;"},
|
||
{'\"', "&quot;"},
|
||
{'&', "&amp;"},
|
||
};
|
||
|
||
for (auto _: state) {
|
||
std::string result{source};
|
||
std::string pattern;
|
||
for (const auto& r : repl) {
|
||
pattern += r.first;
|
||
}
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find_first_of(pattern, start_pos)) != std::string::npos) {
|
||
size_t idx = pattern.find(result[start_pos]);
|
||
result.replace(start_pos, 1, repl[idx].second);
|
||
start_pos += repl[idx].second.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Дальше уже правильные реализации, не зависящие от конфликтующих замен.</span></span></td><td class="benchmarkresult">2510</td><td class="benchmarkresult">2496</td><td class="benchmarkresult">2063</td><td class="benchmarkresult">2344</td><td class="benchmarkresult">10124</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace symbols with std::string_view find_first_of + copy<span class="tooltiptext code">void ReplaceSymbolsStdString(benchmark::State& state) {
|
||
std::string_view source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
;
|
||
|
||
const std::string_view repl_from = "-<>'\"&";
|
||
const std::string_view repl_to[] = {"", "&lt;", "&gt;", "&#39;", "&quot;", "&amp;"};
|
||
|
||
for (auto _: state) {
|
||
std::string result;
|
||
|
||
for (size_t start = 0; start < source.size();) {
|
||
size_t idx = source.find_first_of(repl_from, start);
|
||
if (idx == std::string::npos) {
|
||
result += source.substr(start);
|
||
break;
|
||
}
|
||
if (idx > start) {
|
||
result += source.substr(start, idx - start);
|
||
}
|
||
size_t what = repl_from.find(source[idx]);
|
||
result += repl_to[what];
|
||
|
||
start = idx + 1;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1110</td><td class="benchmarkresult">973</td><td class="benchmarkresult">2410</td><td class="benchmarkresult">2606</td><td class="benchmarkresult">5505</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace runtime symbols with string expressions and without remembering all search results<span class="tooltiptext code">template<bool UseVector>
|
||
void ReplaceSymbolsDynPatternSimStr(benchmark::State& state) {
|
||
stra source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
;
|
||
|
||
std::vector<std::pair<u8s, ssa>> repl = {
|
||
{'-', ""},
|
||
{'<', "&lt;"},
|
||
{'>', "&gt;"},
|
||
{'\'', "&#39;"},
|
||
{'\"', "&quot;"},
|
||
{'&', "&amp;"},
|
||
};
|
||
|
||
for (auto _: state) {
|
||
stringa result = expr_replace_symbols<u8s, UseVector>{source, repl};
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1235</td><td class="benchmarkresult">1508</td><td class="benchmarkresult">1441</td><td class="benchmarkresult">1524</td><td class="benchmarkresult">5599</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace runtime symbols with simstr and memorization of all search results<span class="tooltiptext code">template<bool UseVector>
|
||
void ReplaceSymbolsDynPatternSimStr(benchmark::State& state) {
|
||
stra source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
;
|
||
|
||
std::vector<std::pair<u8s, ssa>> repl = {
|
||
{'-', ""},
|
||
{'<', "&lt;"},
|
||
{'>', "&gt;"},
|
||
{'\'', "&#39;"},
|
||
{'\"', "&quot;"},
|
||
{'&', "&amp;"},
|
||
};
|
||
|
||
for (auto _: state) {
|
||
stringa result = expr_replace_symbols<u8s, UseVector>{source, repl};
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1069</td><td class="benchmarkresult">1172</td><td class="benchmarkresult">1396</td><td class="benchmarkresult">1405</td><td class="benchmarkresult">5123</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace const symbols with string expressions and without remembering all search results<span class="tooltiptext code">template<bool UseVector>
|
||
void ReplaceSymbolsCons2PatternSimStr(benchmark::State& state) {
|
||
stra source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
;
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl_const_symbols<UseVector>(source,
|
||
'-', "",
|
||
'<', "&lt;",
|
||
'>', "&gt;",
|
||
'\'', "&#39;",
|
||
'\"', "&quot;",
|
||
'&', "&amp;"
|
||
);
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1084</td><td class="benchmarkresult">1253</td><td class="benchmarkresult">1209</td><td class="benchmarkresult">1288</td><td class="benchmarkresult">4773</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace const symbols with string expressions and memorization of all search results<span class="tooltiptext code">template<bool UseVector>
|
||
void ReplaceSymbolsCons2PatternSimStr(benchmark::State& state) {
|
||
stra source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
" ksjd-fksjd \"dkjfs-jkhdf dfj ' kdkd \"dkfdkfkdjf"
|
||
;
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl_const_symbols<UseVector>(source,
|
||
'-', "",
|
||
'<', "&lt;",
|
||
'>', "&gt;",
|
||
'\'', "&#39;",
|
||
'\"', "&quot;",
|
||
'&', "&amp;"
|
||
);
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
" ksjdfksjd &quot;dkjfsjkhdf dfj &#39; kdkd &quot;dkfdkfkdjf"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">862</td><td class="benchmarkresult">874</td><td class="benchmarkresult">1206</td><td class="benchmarkresult">1198</td><td class="benchmarkresult">4477</td></tr>
|
||
</tbody></table></div><script>bench_sets['Replace symbols in text ~400 symbols'] = {id:'bs18', tests:[
|
||
{name:'Naive (and wrong) replace symbols with std::string find + replace',data:[852,851,1171,1258,6175]},
|
||
{name:'replace symbols with std::string find_first_of + replace',data:[2510,2496,2063,2344,10124]},
|
||
{name:'replace symbols with std::string_view find_first_of + copy',data:[1110,973,2410,2606,5505]},
|
||
{name:'replace runtime symbols with string expressions and without remembering all search results',data:[1235,1508,1441,1524,5599]},
|
||
{name:'replace runtime symbols with simstr and memorization of all search results',data:[1069,1172,1396,1405,5123]},
|
||
{name:'replace const symbols with string expressions and without remembering all search results',data:[1084,1253,1209,1288,4773]},
|
||
{name:'replace const symbols with string expressions and memorization of all search results',data:[862,874,1206,1198,4477]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs19"><h4>Replace symbols in text ~40 symbols</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">Short Naive (and wrong) replace symbols with std::string find + replace<span class="tooltiptext code">void ShortReplaceSymbolsStdStringNaiveWrong(benchmark::State& state) {
|
||
std::string_view source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
;
|
||
std::vector<std::pair<u8s, std::string_view>> repl = {
|
||
{'&', "&amp;"},
|
||
{'-', ""},
|
||
{'<', "&lt;"},
|
||
{'>', "&gt;"},
|
||
{'\'', "&#39;"},
|
||
{'\"', "&quot;"}
|
||
};
|
||
|
||
auto repl_all = [](std::string& str, char s, std::string_view repl) {
|
||
size_t start_pos = 0;
|
||
while((start_pos = str.find(s, start_pos)) != std::string::npos) {
|
||
str.replace(start_pos, 1, repl);
|
||
start_pos += repl.length();
|
||
}
|
||
};
|
||
for (auto _: state) {
|
||
std::string result{source};
|
||
for (const auto& r : repl) {
|
||
repl_all(result, r.first, r.second);
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">170</td><td class="benchmarkresult">161</td><td class="benchmarkresult">331</td><td class="benchmarkresult">346</td><td class="benchmarkresult">827</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">Short replace symbols with std::string find_first_of + replace<span class="tooltiptext code">void ShortReplaceSymbolsStdStringNaiveRight(benchmark::State& state) {
|
||
std::string_view source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
;
|
||
std::vector<std::pair<u8s, std::string_view>> repl = {
|
||
{'-', ""},
|
||
{'<', "&lt;"},
|
||
{'>', "&gt;"},
|
||
{'\'', "&#39;"},
|
||
{'\"', "&quot;"},
|
||
{'&', "&amp;"},
|
||
};
|
||
|
||
for (auto _: state) {
|
||
std::string result{source};
|
||
std::string pattern;
|
||
for (const auto& r : repl) {
|
||
pattern += r.first;
|
||
}
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find_first_of(pattern, start_pos)) != std::string::npos) {
|
||
size_t idx = pattern.find(result[start_pos]);
|
||
result.replace(start_pos, 1, repl[idx].second);
|
||
start_pos += repl[idx].second.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">310</td><td class="benchmarkresult">321</td><td class="benchmarkresult">375</td><td class="benchmarkresult">435</td><td class="benchmarkresult">1187</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">Short replace symbols with std::string_view find_first_of + copy<span class="tooltiptext code">void ShortReplaceSymbolsStdString(benchmark::State& state) {
|
||
std::string_view source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
;
|
||
|
||
const std::string_view repl_from = "-<>'\"&";
|
||
const std::string_view repl_to[] = {"", "&lt;", "&gt;", "&#39;", "&quot;", "&amp;"};
|
||
|
||
for (auto _: state) {
|
||
std::string result;
|
||
|
||
for (size_t start = 0; start < source.size();) {
|
||
size_t idx = source.find_first_of(repl_from, start);
|
||
if (idx == std::string::npos) {
|
||
result += source.substr(start);
|
||
break;
|
||
}
|
||
if (idx > start) {
|
||
result += source.substr(start, idx - start);
|
||
}
|
||
size_t what = repl_from.find_first_of(source[idx]);
|
||
result += repl_to[what];
|
||
|
||
start = idx + 1;
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">165</td><td class="benchmarkresult">155</td><td class="benchmarkresult">329</td><td class="benchmarkresult">381</td><td class="benchmarkresult">694</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">Short replace runtime symbols with string expressions and without remembering all search results<span class="tooltiptext code">template<bool UseVector>
|
||
void ShortReplaceSymbolsDynPatternSimStr(benchmark::State& state) {
|
||
stra source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
;
|
||
|
||
std::vector<std::pair<u8s, ssa>> repl = {
|
||
{'-', ""},
|
||
{'<', "&lt;"},
|
||
{'>', "&gt;"},
|
||
{'\'', "&#39;"},
|
||
{'\"', "&quot;"},
|
||
{'&', "&amp;"},
|
||
};
|
||
|
||
for (auto _: state) {
|
||
stringa result = expr_replace_symbols<u8s, UseVector>{source, repl};
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">167</td><td class="benchmarkresult">192</td><td class="benchmarkresult">256</td><td class="benchmarkresult">277</td><td class="benchmarkresult">583</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">Short replace runtime symbols with simstr and memorization of all search results<span class="tooltiptext code">template<bool UseVector>
|
||
void ShortReplaceSymbolsDynPatternSimStr(benchmark::State& state) {
|
||
stra source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
;
|
||
|
||
std::vector<std::pair<u8s, ssa>> repl = {
|
||
{'-', ""},
|
||
{'<', "&lt;"},
|
||
{'>', "&gt;"},
|
||
{'\'', "&#39;"},
|
||
{'\"', "&quot;"},
|
||
{'&', "&amp;"},
|
||
};
|
||
|
||
for (auto _: state) {
|
||
stringa result = expr_replace_symbols<u8s, UseVector>{source, repl};
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">176</td><td class="benchmarkresult">190</td><td class="benchmarkresult">369</td><td class="benchmarkresult">374</td><td class="benchmarkresult">669</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">Short replace const symbols with string expressions and without remembering all search results<span class="tooltiptext code">template<bool UseVector>
|
||
void ShortReplaceSymbolsCons2PatternSimStr(benchmark::State& state) {
|
||
stra source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
;
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl_const_symbols<UseVector>(source,
|
||
'-', "",
|
||
'<', "&lt;",
|
||
'>', "&gt;",
|
||
'\'', "&#39;",
|
||
'\"', "&quot;",
|
||
'&', "&amp;"
|
||
);
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">142</td><td class="benchmarkresult">159</td><td class="benchmarkresult">223</td><td class="benchmarkresult">252</td><td class="benchmarkresult">440</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">Short replace const symbols with string expressions and memorization of all search results<span class="tooltiptext code">template<bool UseVector>
|
||
void ShortReplaceSymbolsCons2PatternSimStr(benchmark::State& state) {
|
||
stra source =
|
||
"abcdefg124 < jhsfjsh sjdfsh jfhjd && jdjdj >"
|
||
;
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl_const_symbols<UseVector>(source,
|
||
'-', "",
|
||
'<', "&lt;",
|
||
'>', "&gt;",
|
||
'\'', "&#39;",
|
||
'\"', "&quot;",
|
||
'&', "&amp;"
|
||
);
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result
|
||
!=
|
||
"abcdefg124 &lt; jhsfjsh sjdfsh jfhjd &amp;&amp; jdjdj &gt;"
|
||
) {
|
||
state.SkipWithError("not equal");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">157</td><td class="benchmarkresult">149</td><td class="benchmarkresult">310</td><td class="benchmarkresult">342</td><td class="benchmarkresult">512</td></tr>
|
||
</tbody></table></div><script>bench_sets['Replace symbols in text ~40 symbols'] = {id:'bs19', tests:[
|
||
{name:'Short Naive (and wrong) replace symbols with std::string find + replace',data:[170,161,331,346,827]},
|
||
{name:'Short replace symbols with std::string find_first_of + replace',data:[310,321,375,435,1187]},
|
||
{name:'Short replace symbols with std::string_view find_first_of + copy',data:[165,155,329,381,694]},
|
||
{name:'Short replace runtime symbols with string expressions and without remembering all search results',data:[167,192,256,277,583]},
|
||
{name:'Short replace runtime symbols with simstr and memorization of all search results',data:[176,190,369,374,669]},
|
||
{name:'Short replace const symbols with string expressions and without remembering all search results',data:[142,159,223,252,440]},
|
||
{name:'Short replace const symbols with string expressions and memorization of all search results',data:[157,149,310,342,512]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs20"><h4>Replace All Str To Longer Size</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- in std::string|64<span class="tooltiptext code">template<size_t Long>
|
||
void ReplaceAllLongerStdString(benchmark::State& state) {
|
||
std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
std::string_view sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
std::string_view pattern = "bb";
|
||
std::string_view repl = "----";
|
||
|
||
std::string big_source, big_sample;
|
||
for (int i = 0; i < Long; i++) {
|
||
big_source += source;
|
||
big_sample += sample;
|
||
}
|
||
|
||
for (auto _: state) {
|
||
std::string result{big_source};
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find(pattern, start_pos)) != std::string::npos) {
|
||
result.replace(start_pos, pattern.length(), repl);
|
||
start_pos += repl.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result != big_sample) {
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">164</td><td class="benchmarkresult">174</td><td class="benchmarkresult">236</td><td class="benchmarkresult">248</td><td class="benchmarkresult">759</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- in std::string|256<span class="tooltiptext code">template<size_t Long>
|
||
void ReplaceAllLongerStdString(benchmark::State& state) {
|
||
std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
std::string_view sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
std::string_view pattern = "bb";
|
||
std::string_view repl = "----";
|
||
|
||
std::string big_source, big_sample;
|
||
for (int i = 0; i < Long; i++) {
|
||
big_source += source;
|
||
big_sample += sample;
|
||
}
|
||
|
||
for (auto _: state) {
|
||
std::string result{big_source};
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find(pattern, start_pos)) != std::string::npos) {
|
||
result.replace(start_pos, pattern.length(), repl);
|
||
start_pos += repl.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result != big_sample) {
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">531</td><td class="benchmarkresult">511</td><td class="benchmarkresult">780</td><td class="benchmarkresult">807</td><td class="benchmarkresult">2371</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- in std::string|512<span class="tooltiptext code">template<size_t Long>
|
||
void ReplaceAllLongerStdString(benchmark::State& state) {
|
||
std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
std::string_view sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
std::string_view pattern = "bb";
|
||
std::string_view repl = "----";
|
||
|
||
std::string big_source, big_sample;
|
||
for (int i = 0; i < Long; i++) {
|
||
big_source += source;
|
||
big_sample += sample;
|
||
}
|
||
|
||
for (auto _: state) {
|
||
std::string result{big_source};
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find(pattern, start_pos)) != std::string::npos) {
|
||
result.replace(start_pos, pattern.length(), repl);
|
||
start_pos += repl.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result != big_sample) {
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1217</td><td class="benchmarkresult">1180</td><td class="benchmarkresult">1449</td><td class="benchmarkresult">1551</td><td class="benchmarkresult">4397</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- in std::string|1024<span class="tooltiptext code">template<size_t Long>
|
||
void ReplaceAllLongerStdString(benchmark::State& state) {
|
||
std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
std::string_view sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
std::string_view pattern = "bb";
|
||
std::string_view repl = "----";
|
||
|
||
std::string big_source, big_sample;
|
||
for (int i = 0; i < Long; i++) {
|
||
big_source += source;
|
||
big_sample += sample;
|
||
}
|
||
|
||
for (auto _: state) {
|
||
std::string result{big_source};
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find(pattern, start_pos)) != std::string::npos) {
|
||
result.replace(start_pos, pattern.length(), repl);
|
||
start_pos += repl.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result != big_sample) {
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">2374</td><td class="benchmarkresult">2244</td><td class="benchmarkresult">3239</td><td class="benchmarkresult">3622</td><td class="benchmarkresult">8983</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- in std::string|2048<span class="tooltiptext code">template<size_t Long>
|
||
void ReplaceAllLongerStdString(benchmark::State& state) {
|
||
std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
std::string_view sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
std::string_view pattern = "bb";
|
||
std::string_view repl = "----";
|
||
|
||
std::string big_source, big_sample;
|
||
for (int i = 0; i < Long; i++) {
|
||
big_source += source;
|
||
big_sample += sample;
|
||
}
|
||
|
||
for (auto _: state) {
|
||
std::string result{big_source};
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find(pattern, start_pos)) != std::string::npos) {
|
||
result.replace(start_pos, pattern.length(), repl);
|
||
start_pos += repl.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result != big_sample) {
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">5735</td><td class="benchmarkresult">6009</td><td class="benchmarkresult">8127</td><td class="benchmarkresult">8251</td><td class="benchmarkresult">20059</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- in lstringa<8>|64<span class="tooltiptext code">template<size_t N, size_t Count>
|
||
void ReplaceAllLongerSimString(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
lstringa<N> result = big_source;
|
||
result.replace("bb", "----");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">145</td><td class="benchmarkresult">154</td><td class="benchmarkresult">336</td><td class="benchmarkresult">331</td><td class="benchmarkresult">734</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- in lstringa<8>|256<span class="tooltiptext code">template<size_t N, size_t Count>
|
||
void ReplaceAllLongerSimString(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
lstringa<N> result = big_source;
|
||
result.replace("bb", "----");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">435</td><td class="benchmarkresult">459</td><td class="benchmarkresult">659</td><td class="benchmarkresult">685</td><td class="benchmarkresult">2096</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- in lstringa<8>|512<span class="tooltiptext code">template<size_t N, size_t Count>
|
||
void ReplaceAllLongerSimString(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
lstringa<N> result = big_source;
|
||
result.replace("bb", "----");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">825</td><td class="benchmarkresult">850</td><td class="benchmarkresult">1091</td><td class="benchmarkresult">1198</td><td class="benchmarkresult">3770</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- in lstringa<8>|1024<span class="tooltiptext code">template<size_t N, size_t Count>
|
||
void ReplaceAllLongerSimString(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
lstringa<N> result = big_source;
|
||
result.replace("bb", "----");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1713</td><td class="benchmarkresult">1775</td><td class="benchmarkresult">1937</td><td class="benchmarkresult">2107</td><td class="benchmarkresult">7288</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- in lstringa<8>|2048<span class="tooltiptext code">template<size_t N, size_t Count>
|
||
void ReplaceAllLongerSimString(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
lstringa<N> result = big_source;
|
||
result.replace("bb", "----");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">3055</td><td class="benchmarkresult">3322</td><td class="benchmarkresult">3647</td><td class="benchmarkresult">4065</td><td class="benchmarkresult">13342</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- by init stringa|64<span class="tooltiptext code">template<size_t Count>
|
||
void ReplaceAllLongerSimStringExpr(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl(big_source.to_str(), "bb", "----");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">117</td><td class="benchmarkresult">124</td><td class="benchmarkresult">212</td><td class="benchmarkresult">230</td><td class="benchmarkresult">498</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- by init stringa|256<span class="tooltiptext code">template<size_t Count>
|
||
void ReplaceAllLongerSimStringExpr(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl(big_source.to_str(), "bb", "----");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">398</td><td class="benchmarkresult">483</td><td class="benchmarkresult">559</td><td class="benchmarkresult">582</td><td class="benchmarkresult">1896</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- by init stringa|512<span class="tooltiptext code">template<size_t Count>
|
||
void ReplaceAllLongerSimStringExpr(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl(big_source.to_str(), "bb", "----");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">803</td><td class="benchmarkresult">888</td><td class="benchmarkresult">1035</td><td class="benchmarkresult">1007</td><td class="benchmarkresult">3611</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- by init stringa|1024<span class="tooltiptext code">template<size_t Count>
|
||
void ReplaceAllLongerSimStringExpr(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl(big_source.to_str(), "bb", "----");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1624</td><td class="benchmarkresult">1787</td><td class="benchmarkresult">1850</td><td class="benchmarkresult">1913</td><td class="benchmarkresult">6933</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to ---- by init stringa|2048<span class="tooltiptext code">template<size_t Count>
|
||
void ReplaceAllLongerSimStringExpr(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa----baaaaaaaa--------aaaaabaaaaaaaaaaaaaaaaaaaaa----a";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl(big_source.to_str(), "bb", "----");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">3156</td><td class="benchmarkresult">3741</td><td class="benchmarkresult">3423</td><td class="benchmarkresult">3605</td><td class="benchmarkresult">13812</td></tr>
|
||
</tbody></table></div><script>bench_sets['Replace All Str To Longer Size'] = {id:'bs20', tests:[
|
||
{name:'replace bb to ---- in std::string|64',data:[164,174,236,248,759]},
|
||
{name:'replace bb to ---- in std::string|256',data:[531,511,780,807,2371]},
|
||
{name:'replace bb to ---- in std::string|512',data:[1217,1180,1449,1551,4397]},
|
||
{name:'replace bb to ---- in std::string|1024',data:[2374,2244,3239,3622,8983]},
|
||
{name:'replace bb to ---- in std::string|2048',data:[5735,6009,8127,8251,20059]},
|
||
{name:'replace bb to ---- in lstringa<8>|64',data:[145,154,336,331,734]},
|
||
{name:'replace bb to ---- in lstringa<8>|256',data:[435,459,659,685,2096]},
|
||
{name:'replace bb to ---- in lstringa<8>|512',data:[825,850,1091,1198,3770]},
|
||
{name:'replace bb to ---- in lstringa<8>|1024',data:[1713,1775,1937,2107,7288]},
|
||
{name:'replace bb to ---- in lstringa<8>|2048',data:[3055,3322,3647,4065,13342]},
|
||
{name:'replace bb to ---- by init stringa|64',data:[117,124,212,230,498]},
|
||
{name:'replace bb to ---- by init stringa|256',data:[398,483,559,582,1896]},
|
||
{name:'replace bb to ---- by init stringa|512',data:[803,888,1035,1007,3611]},
|
||
{name:'replace bb to ---- by init stringa|1024',data:[1624,1787,1850,1913,6933]},
|
||
{name:'replace bb to ---- by init stringa|2048',data:[3156,3741,3423,3605,13812]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs21"><h4>Replace All Str To Same Size</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- in std::string|64<span class="tooltiptext code">template<size_t Long>
|
||
void ReplaceAllEqualStdString(benchmark::State& state) {
|
||
std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
std::string_view sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
std::string_view pattern = "bb";
|
||
std::string_view repl = "--";
|
||
|
||
std::string big_source, big_sample;
|
||
for (int i = 0; i < Long; i++) {
|
||
big_source += source;
|
||
big_sample += sample;
|
||
}
|
||
|
||
for (auto _: state) {
|
||
std::string result{big_source};
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find(pattern, start_pos)) != std::string::npos) {
|
||
result.replace(start_pos, pattern.length(), repl);
|
||
start_pos += repl.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result != big_sample) {
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">119</td><td class="benchmarkresult">118</td><td class="benchmarkresult">192</td><td class="benchmarkresult">206</td><td class="benchmarkresult">545</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- in std::string|256<span class="tooltiptext code">template<size_t Long>
|
||
void ReplaceAllEqualStdString(benchmark::State& state) {
|
||
std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
std::string_view sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
std::string_view pattern = "bb";
|
||
std::string_view repl = "--";
|
||
|
||
std::string big_source, big_sample;
|
||
for (int i = 0; i < Long; i++) {
|
||
big_source += source;
|
||
big_sample += sample;
|
||
}
|
||
|
||
for (auto _: state) {
|
||
std::string result{big_source};
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find(pattern, start_pos)) != std::string::npos) {
|
||
result.replace(start_pos, pattern.length(), repl);
|
||
start_pos += repl.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result != big_sample) {
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">415</td><td class="benchmarkresult">370</td><td class="benchmarkresult">495</td><td class="benchmarkresult">533</td><td class="benchmarkresult">1885</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- in std::string|512<span class="tooltiptext code">template<size_t Long>
|
||
void ReplaceAllEqualStdString(benchmark::State& state) {
|
||
std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
std::string_view sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
std::string_view pattern = "bb";
|
||
std::string_view repl = "--";
|
||
|
||
std::string big_source, big_sample;
|
||
for (int i = 0; i < Long; i++) {
|
||
big_source += source;
|
||
big_sample += sample;
|
||
}
|
||
|
||
for (auto _: state) {
|
||
std::string result{big_source};
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find(pattern, start_pos)) != std::string::npos) {
|
||
result.replace(start_pos, pattern.length(), repl);
|
||
start_pos += repl.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result != big_sample) {
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">783</td><td class="benchmarkresult">739</td><td class="benchmarkresult">854</td><td class="benchmarkresult">968</td><td class="benchmarkresult">3368</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- in std::string|1024<span class="tooltiptext code">template<size_t Long>
|
||
void ReplaceAllEqualStdString(benchmark::State& state) {
|
||
std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
std::string_view sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
std::string_view pattern = "bb";
|
||
std::string_view repl = "--";
|
||
|
||
std::string big_source, big_sample;
|
||
for (int i = 0; i < Long; i++) {
|
||
big_source += source;
|
||
big_sample += sample;
|
||
}
|
||
|
||
for (auto _: state) {
|
||
std::string result{big_source};
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find(pattern, start_pos)) != std::string::npos) {
|
||
result.replace(start_pos, pattern.length(), repl);
|
||
start_pos += repl.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result != big_sample) {
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1499</td><td class="benchmarkresult">1423</td><td class="benchmarkresult">1670</td><td class="benchmarkresult">1840</td><td class="benchmarkresult">6925</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- in std::string|2048<span class="tooltiptext code">template<size_t Long>
|
||
void ReplaceAllEqualStdString(benchmark::State& state) {
|
||
std::string_view source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
std::string_view sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
std::string_view pattern = "bb";
|
||
std::string_view repl = "--";
|
||
|
||
std::string big_source, big_sample;
|
||
for (int i = 0; i < Long; i++) {
|
||
big_source += source;
|
||
big_sample += sample;
|
||
}
|
||
|
||
for (auto _: state) {
|
||
std::string result{big_source};
|
||
size_t start_pos = 0;
|
||
while((start_pos = result.find(pattern, start_pos)) != std::string::npos) {
|
||
result.replace(start_pos, pattern.length(), repl);
|
||
start_pos += repl.length();
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (result != big_sample) {
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">2960</td><td class="benchmarkresult">2898</td><td class="benchmarkresult">3178</td><td class="benchmarkresult">3641</td><td class="benchmarkresult">13051</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- in lstringa<8>|64<span class="tooltiptext code">template<size_t N, size_t Long>
|
||
void ReplaceAllEqualSimString(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
lstringa<2048> big_source{Long, source}, big_sample{Long, sample};
|
||
|
||
for (auto _: state) {
|
||
lstringa<N> result = big_source;
|
||
result.replace("bb", "--");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">101</td><td class="benchmarkresult">99.1</td><td class="benchmarkresult">192</td><td class="benchmarkresult">200</td><td class="benchmarkresult">483</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- in lstringa<8>|256<span class="tooltiptext code">template<size_t N, size_t Long>
|
||
void ReplaceAllEqualSimString(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
lstringa<2048> big_source{Long, source}, big_sample{Long, sample};
|
||
|
||
for (auto _: state) {
|
||
lstringa<N> result = big_source;
|
||
result.replace("bb", "--");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">326</td><td class="benchmarkresult">301</td><td class="benchmarkresult">446</td><td class="benchmarkresult">475</td><td class="benchmarkresult">1542</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- in lstringa<8>|512<span class="tooltiptext code">template<size_t N, size_t Long>
|
||
void ReplaceAllEqualSimString(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
lstringa<2048> big_source{Long, source}, big_sample{Long, sample};
|
||
|
||
for (auto _: state) {
|
||
lstringa<N> result = big_source;
|
||
result.replace("bb", "--");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">569</td><td class="benchmarkresult">566</td><td class="benchmarkresult">789</td><td class="benchmarkresult">816</td><td class="benchmarkresult">2827</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- in lstringa<8>|1024<span class="tooltiptext code">template<size_t N, size_t Long>
|
||
void ReplaceAllEqualSimString(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
lstringa<2048> big_source{Long, source}, big_sample{Long, sample};
|
||
|
||
for (auto _: state) {
|
||
lstringa<N> result = big_source;
|
||
result.replace("bb", "--");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1128</td><td class="benchmarkresult">1104</td><td class="benchmarkresult">1526</td><td class="benchmarkresult">1508</td><td class="benchmarkresult">5568</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- in lstringa<8>|2048<span class="tooltiptext code">template<size_t N, size_t Long>
|
||
void ReplaceAllEqualSimString(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
lstringa<2048> big_source{Long, source}, big_sample{Long, sample};
|
||
|
||
for (auto _: state) {
|
||
lstringa<N> result = big_source;
|
||
result.replace("bb", "--");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">2155</td><td class="benchmarkresult">2088</td><td class="benchmarkresult">2820</td><td class="benchmarkresult">2969</td><td class="benchmarkresult">10863</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- by init stringa|64<span class="tooltiptext code">template<size_t Count>
|
||
void ReplaceAllEqualSimStringExpr(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
ssa pattern = "bb";
|
||
ssa repl = "--";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl(big_source.to_str(), "bb", "--");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">86.9</td><td class="benchmarkresult">99.6</td><td class="benchmarkresult">162</td><td class="benchmarkresult">192</td><td class="benchmarkresult">363</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- by init stringa|256<span class="tooltiptext code">template<size_t Count>
|
||
void ReplaceAllEqualSimStringExpr(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
ssa pattern = "bb";
|
||
ssa repl = "--";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl(big_source.to_str(), "bb", "--");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">232</td><td class="benchmarkresult">274</td><td class="benchmarkresult">354</td><td class="benchmarkresult">392</td><td class="benchmarkresult">1249</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- by init stringa|512<span class="tooltiptext code">template<size_t Count>
|
||
void ReplaceAllEqualSimStringExpr(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
ssa pattern = "bb";
|
||
ssa repl = "--";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl(big_source.to_str(), "bb", "--");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">441</td><td class="benchmarkresult">527</td><td class="benchmarkresult">600</td><td class="benchmarkresult">660</td><td class="benchmarkresult">2243</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- by init stringa|1024<span class="tooltiptext code">template<size_t Count>
|
||
void ReplaceAllEqualSimStringExpr(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
ssa pattern = "bb";
|
||
ssa repl = "--";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl(big_source.to_str(), "bb", "--");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">883</td><td class="benchmarkresult">1029</td><td class="benchmarkresult">1079</td><td class="benchmarkresult">1196</td><td class="benchmarkresult">4204</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">replace bb to -- by init stringa|2048<span class="tooltiptext code">template<size_t Count>
|
||
void ReplaceAllEqualSimStringExpr(benchmark::State& state) {
|
||
ssa source = "aaaaaaaaaaaaaaaaaaabbbaaaaaaaabbbbaaaaabaaaaaaaaaaaaaaaaaaaaabba";
|
||
ssa sample = "aaaaaaaaaaaaaaaaaaa--baaaaaaaa----aaaaabaaaaaaaaaaaaaaaaaaaaa--a";
|
||
ssa pattern = "bb";
|
||
ssa repl = "--";
|
||
|
||
lstringa<2048> big_source{Count, source}, big_sample{Count, sample};
|
||
|
||
for (auto _: state) {
|
||
stringa result = e_repl(big_source.to_str(), "bb", "--");
|
||
|
||
#ifdef CHECK_RESULT
|
||
if (result.to_str() != big_sample) {
|
||
std::cout << result.length() << ": " << result << "\n\n" << big_sample.length() << ": " << big_sample << "\n\n";
|
||
state.SkipWithError("error in replace");
|
||
break;
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(result);
|
||
benchmark::DoNotOptimize(source);
|
||
benchmark::DoNotOptimize(pattern);
|
||
benchmark::DoNotOptimize(repl);
|
||
}
|
||
}</span></span></td><td></td><td class="benchmarkresult">1670</td><td class="benchmarkresult">2041</td><td class="benchmarkresult">2067</td><td class="benchmarkresult">2432</td><td class="benchmarkresult">8206</td></tr>
|
||
</tbody></table></div><script>bench_sets['Replace All Str To Same Size'] = {id:'bs21', tests:[
|
||
{name:'replace bb to -- in std::string|64',data:[119,118,192,206,545]},
|
||
{name:'replace bb to -- in std::string|256',data:[415,370,495,533,1885]},
|
||
{name:'replace bb to -- in std::string|512',data:[783,739,854,968,3368]},
|
||
{name:'replace bb to -- in std::string|1024',data:[1499,1423,1670,1840,6925]},
|
||
{name:'replace bb to -- in std::string|2048',data:[2960,2898,3178,3641,13051]},
|
||
{name:'replace bb to -- in lstringa<8>|64',data:[101,99.1,192,200,483]},
|
||
{name:'replace bb to -- in lstringa<8>|256',data:[326,301,446,475,1542]},
|
||
{name:'replace bb to -- in lstringa<8>|512',data:[569,566,789,816,2827]},
|
||
{name:'replace bb to -- in lstringa<8>|1024',data:[1128,1104,1526,1508,5568]},
|
||
{name:'replace bb to -- in lstringa<8>|2048',data:[2155,2088,2820,2969,10863]},
|
||
{name:'replace bb to -- by init stringa|64',data:[86.9,99.6,162,192,363]},
|
||
{name:'replace bb to -- by init stringa|256',data:[232,274,354,392,1249]},
|
||
{name:'replace bb to -- by init stringa|512',data:[441,527,600,660,2243]},
|
||
{name:'replace bb to -- by init stringa|1024',data:[883,1029,1079,1196,4204]},
|
||
{name:'replace bb to -- by init stringa|2048',data:[1670,2041,2067,2432,8206]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs22"><h4>Hash Map insert and find</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">hashStrMapA<size_t> emplace & find stringa;<span class="tooltiptext code">void HashMapSimStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
hashStrMapA<size_t> store;
|
||
for (size_t idx = 0; idx < bs_sim.size(); idx++) {
|
||
store.try_emplace(bs_sim[idx], idx);
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (store.size() != bs_sim.size()) {
|
||
state.SkipWithError("bad inserts");
|
||
}
|
||
#endif
|
||
for (size_t idx = 0; idx < bs_sim.size(); idx++) {
|
||
auto find = store.find(bs_sim[idx]);
|
||
size_t res = find->second;
|
||
#ifdef CHECK_RESULT
|
||
if (res != idx) {
|
||
state.SkipWithError("bad find");
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Вставляем в hashStrMapA 10000 stringa длиной от 30 до 50
|
||
символов, а потом ищем их в ней</span></span></td><td class="benchmarkresult">3565051</td><td class="benchmarkresult">3720924</td><td class="benchmarkresult">3852886</td><td class="benchmarkresult">4270225</td><td class="benchmarkresult">5371717</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::unordered_map<std::string, size_t> emplace & find std::string;<span class="tooltiptext code">void HashMapStdStr(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
std::unordered_map<std::string, size_t> store;
|
||
for (size_t idx = 0; idx < bs_std.size(); idx++) {
|
||
store.try_emplace(bs_std[idx], idx);
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (store.size() != bs_std.size()) {
|
||
state.SkipWithError("bad inserts");
|
||
}
|
||
#endif
|
||
for (size_t idx = 0; idx < bs_std.size(); idx++) {
|
||
auto find = store.find(bs_std[idx]);
|
||
size_t res = find->second;
|
||
#ifdef CHECK_RESULT
|
||
if (res != idx) {
|
||
state.SkipWithError("bad find");
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">То же самое c std::string и std::unordered_map</span></span></td><td class="benchmarkresult">3504581</td><td class="benchmarkresult">3624563</td><td class="benchmarkresult">5329837</td><td class="benchmarkresult">5385050</td><td class="benchmarkresult">5883527</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">hashStrMapA<size_t> emplace & find ssa;<span class="tooltiptext code">void HashMapSimSsa(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
hashStrMapA<size_t> store;
|
||
for (size_t idx = 0; idx < bs_sim.size(); idx++) {
|
||
store.emplace(bs_sim[idx], idx);
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (store.size() != bs_sim.size()) {
|
||
state.SkipWithError("bad inserts");
|
||
}
|
||
#endif
|
||
for (size_t idx = 0; idx < bs_sim.size(); idx++) {
|
||
ssa key = bs_sim[idx];
|
||
auto find = store.find(key);
|
||
size_t res = find->second;
|
||
#ifdef CHECK_RESULT
|
||
if (res != idx) {
|
||
state.SkipWithError("bad find");
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Теперь вставляем stringa, а ищем ssa</span></span></td><td class="benchmarkresult">3648733</td><td class="benchmarkresult">3730268</td><td class="benchmarkresult">3511046</td><td class="benchmarkresult">3953790</td><td class="benchmarkresult">5376097</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">std::unordered_map<std::string, size_t> emplace & find std::string_view;<span class="tooltiptext code">void HashMapStdStrView(benchmark::State& state) {
|
||
for (auto _: state) {
|
||
std::unordered_map<std::string, size_t> store;
|
||
for (size_t idx = 0; idx < bs_std.size(); idx++) {
|
||
store.emplace(bs_std[idx], idx);
|
||
}
|
||
#ifdef CHECK_RESULT
|
||
if (store.size() != bs_std.size()) {
|
||
state.SkipWithError("bad inserts");
|
||
}
|
||
#endif
|
||
for (size_t idx = 0; idx < bs_std.size(); idx++) {
|
||
std::string_view key = bs_std[idx];
|
||
auto find = store.find(std::string{key});
|
||
size_t res = find->second;
|
||
#ifdef CHECK_RESULT
|
||
if (res != idx) {
|
||
state.SkipWithError("bad find");
|
||
}
|
||
#endif
|
||
benchmark::DoNotOptimize(res);
|
||
}
|
||
}
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Вставляем std::string, а ищем std::string_view</span></span></td><td class="benchmarkresult">4252438</td><td class="benchmarkresult">4036697</td><td class="benchmarkresult">6336347</td><td class="benchmarkresult">6874509</td><td class="benchmarkresult">6884220</td></tr>
|
||
</tbody></table></div><script>bench_sets['Hash Map insert and find'] = {id:'bs22', tests:[
|
||
{name:'hashStrMapA<size_t> emplace & find stringa;',data:[3565051,3720924,3852886,4270225,5371717]},
|
||
{name:'std::unordered_map<std::string, size_t> emplace & find std::string;',data:[3504581,3624563,5329837,5385050,5883527]},
|
||
{name:'hashStrMapA<size_t> emplace & find ssa;',data:[3648733,3730268,3511046,3953790,5376097]},
|
||
{name:'std::unordered_map<std::string, size_t> emplace & find std::string_view;',data:[4252438,4036697,6336347,6874509,6884220]}
|
||
]}</script>
|
||
|
||
<div class="benchset" id="bs23"><h4>Build Full Func Name</h4>
|
||
<table><thead><tr><th>Benchmark name</th><th width="5%">Comment</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), Clang-21</th><th width="8%">Xeon E5-2682 v4, Ubuntu 22 (WSL), GCC-13</th><th width="8%">Xeon E5-2682 v4, Windows 10, Clang-19</th><th width="8%">Xeon E5-2682 v4, Windows 10, MSVC-19</th><th width="8%">Xeon E5-2682 v4, WASM Chrome, Clang-21</th></tr></thead><tbody>
|
||
<tr><td class="benchmarkname"><span class="tooltip">Build func full name std::string;<span class="tooltiptext code">std::string build_full_name_std() const {
|
||
std::string str{has_ret_type_resolver ? "any"sv : type_names_sv[(unsigned)ret_type]};
|
||
str += " ";
|
||
str += std_name;
|
||
str += "(";
|
||
|
||
bool add_comma = false;
|
||
|
||
for (const auto& param : params) {
|
||
if (add_comma) {
|
||
str += ", ";
|
||
}
|
||
if (param.optional) {
|
||
str += "[";
|
||
}
|
||
param.allowed_types.to_stdstr(str);
|
||
if (param.optional) {
|
||
str += "]";
|
||
}
|
||
add_comma = true;
|
||
}
|
||
if (unlim_params) {
|
||
if (add_comma) {
|
||
str += ", ";
|
||
}
|
||
str += "...";
|
||
}
|
||
str += ")";
|
||
//std::cout << "Len=" << str.length() << ", Cap=" << str.capacity() << "\n";
|
||
return str;
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Обыденная задача, подобные часто могут встретится в работе:
|
||
По неким данным сгенерировать текст. В этом случае по данным
|
||
о неких функциях сформировать их полное имя с типами параметров и
|
||
возвращаемого значения. Алгоритм на std::string.</span></span></td><td class="benchmarkresult">733</td><td class="benchmarkresult">1031</td><td class="benchmarkresult">1581</td><td class="benchmarkresult">1651</td><td class="benchmarkresult">4861</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">Build func full name std::string 1;<span class="tooltiptext code">std::string build_full_name_std1() const {
|
||
std::string str{has_ret_type_resolver ? "any"sv : type_names_sv[(unsigned)ret_type]};
|
||
str += " " + std_name + "(";
|
||
|
||
bool add_comma = false;
|
||
|
||
for (const auto& param : params) {
|
||
if (add_comma) {
|
||
str += ", ";
|
||
}
|
||
if (param.optional) {
|
||
str += "[";
|
||
}
|
||
param.allowed_types.to_stdstr(str);
|
||
if (param.optional) {
|
||
str += "]";
|
||
}
|
||
add_comma = true;
|
||
}
|
||
if (unlim_params) {
|
||
if (add_comma) {
|
||
str += ", ";
|
||
}
|
||
str += "...";
|
||
}
|
||
str += ")";
|
||
//std::cout << "Len=" << str.length() << ", Cap=" << str.capacity() << "\n";
|
||
return str;
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Почти тот же алгоритм, но несколько последовательных
|
||
+= к строке заменены на одно += + + +.</span></span></td><td class="benchmarkresult">829</td><td class="benchmarkresult">999</td><td class="benchmarkresult">1654</td><td class="benchmarkresult">1706</td><td class="benchmarkresult">5220</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">Build func full name std::stream;<span class="tooltiptext code">std::string build_full_name_stream() const {
|
||
std::ostringstream str;
|
||
if (has_ret_type_resolver) {
|
||
str << "any";
|
||
} else {
|
||
str << type_names_sv[(unsigned)ret_type];
|
||
}
|
||
str << " " << std_name << "(";
|
||
|
||
bool add_comma = false;
|
||
|
||
for (const auto& param : params) {
|
||
if (add_comma) {
|
||
str << ", ";
|
||
}
|
||
if (param.optional) {
|
||
str << "[";
|
||
}
|
||
param.allowed_types.to_stream(str);
|
||
if (param.optional) {
|
||
str << "]";
|
||
}
|
||
add_comma = true;
|
||
}
|
||
if (unlim_params) {
|
||
if (add_comma) {
|
||
str << ", ";
|
||
}
|
||
str << "...";
|
||
}
|
||
str << ")";
|
||
return str.str();
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Строим имя функции через std::ostringstream и <<</span></span></td><td class="benchmarkresult">2554</td><td class="benchmarkresult">2626</td><td class="benchmarkresult">8195</td><td class="benchmarkresult">9950</td><td class="benchmarkresult">16474</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">Build func full name stringa;<span class="tooltiptext code">stringa build_full_name() const {
|
||
lstringa<512> str = e_choice(has_ret_type_resolver, "any", type_names[(unsigned)ret_type]) + " " + name + "(";
|
||
|
||
bool add_comma = false;
|
||
|
||
for (const auto& param : params) {
|
||
str += e_if(add_comma, ", ") + e_if(param.optional, "[");
|
||
param.allowed_types.to_simstr(str);
|
||
if (param.optional) {
|
||
str += "]";
|
||
}
|
||
add_comma = true;
|
||
}
|
||
return str + e_if(unlim_params, e_if(add_comma, ", ") + "...") + ")";
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Реализация на simstr строках и строковых выражениях.
|
||
Инфа о параметрах добавляется в текущую строку</span></span></td><td class="benchmarkresult">525</td><td class="benchmarkresult">602</td><td class="benchmarkresult">859</td><td class="benchmarkresult">948</td><td class="benchmarkresult">2853</td></tr>
|
||
<tr><td class="benchmarkname"><span class="tooltip">Build func full name stringa 1;<span class="tooltiptext code">stringa build_full_name1() const {
|
||
lstringa<512> str = e_choice(has_ret_type_resolver, "any", type_names[(unsigned)ret_type]) + " " + name + "(";
|
||
|
||
bool add_comma = false;
|
||
|
||
for (const auto& param : params) {
|
||
str += e_if(add_comma, ", ") + e_if(param.optional, "[") + param.allowed_types.get_simstr() + e_if(param.optional, "]");
|
||
add_comma = true;
|
||
}
|
||
return str + e_if(unlim_params, e_if(add_comma, ", ") + "...") + ")";
|
||
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Реализация на simstr строках и строковых выражениях.
|
||
Инфа о параметрах добавляется во временную строку, а потом
|
||
разом добавляется в текущую строку. Позволяет операции в цикле
|
||
записать в одну строку, но чуть проигрывает по времени выполнения.</span></span></td><td class="benchmarkresult">672</td><td class="benchmarkresult">674</td><td class="benchmarkresult">1015</td><td class="benchmarkresult">1108</td><td class="benchmarkresult">3292</td></tr>
|
||
</tbody></table></div><script>bench_sets['Build Full Func Name'] = {id:'bs23', tests:[
|
||
{name:'Build func full name std::string;',data:[733,1031,1581,1651,4861]},
|
||
{name:'Build func full name std::string 1;',data:[829,999,1654,1706,5220]},
|
||
{name:'Build func full name std::stream;',data:[2554,2626,8195,9950,16474]},
|
||
{name:'Build func full name stringa;',data:[525,602,859,948,2853]},
|
||
{name:'Build func full name stringa 1;',data:[672,674,1015,1108,3292]}
|
||
]}</script></body></html> |