mirror of https://github.com/orefkov/simstr.git
3770 lines
224 KiB
HTML
3770 lines
224 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.49, 0.86, 0.76</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.00, 0.00, 0.00</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 2518.87 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 2497.21 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">Chrome 136.0.7103.114 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.13</td><td class="benchmarkresult">1.19</td><td class="benchmarkresult">1.12</td><td class="benchmarkresult">2.59</td><td class="benchmarkresult">3.47</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.372</td><td class="benchmarkresult">0.759</td><td class="benchmarkresult">0.377</td><td class="benchmarkresult">1.86</td><td class="benchmarkresult">3.68</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.375</td><td class="benchmarkresult">0.185</td><td class="benchmarkresult">0.367</td><td class="benchmarkresult">1.84</td><td class="benchmarkresult">2.14</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.757</td><td class="benchmarkresult">0.759</td><td class="benchmarkresult">0.751</td><td class="benchmarkresult">2.22</td><td class="benchmarkresult">3.66</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.16</td><td class="benchmarkresult">1.11</td><td class="benchmarkresult">1.14</td><td class="benchmarkresult">2.62</td><td class="benchmarkresult">3.10</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.14</td><td class="benchmarkresult">1.13</td><td class="benchmarkresult">1.15</td><td class="benchmarkresult">2.60</td><td class="benchmarkresult">3.10</td></tr>
|
|||
|
|
</tbody></table></div><script>bench_sets['Create Empty Str'] = {id:'bs1', tests:[
|
|||
|
|
{name:'std::string e;',data:[1.13,1.19,1.12,2.59,3.47]},
|
|||
|
|
{name:'std::string_view e;',data:[0.372,0.759,0.377,1.86,3.68]},
|
|||
|
|
{name:'ssa e;',data:[0.375,0.185,0.367,1.84,2.14]},
|
|||
|
|
{name:'stringa e;',data:[0.757,0.759,0.751,2.22,3.66]},
|
|||
|
|
{name:'lstringa<20> e;',data:[1.16,1.11,1.14,2.62,3.10]},
|
|||
|
|
{name:'lstringa<40> e;',data:[1.14,1.13,1.15,2.60,3.10]}
|
|||
|
|
]}</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.88</td><td class="benchmarkresult">1.88</td><td class="benchmarkresult">1.85</td><td class="benchmarkresult">2.61</td><td class="benchmarkresult">4.95</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.746</td><td class="benchmarkresult">0.757</td><td class="benchmarkresult">0.740</td><td class="benchmarkresult">1.83</td><td class="benchmarkresult">2.22</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.377</td><td class="benchmarkresult">0.746</td><td class="benchmarkresult">0.371</td><td class="benchmarkresult">1.84</td><td class="benchmarkresult">2.18</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.12</td><td class="benchmarkresult">1.12</td><td class="benchmarkresult">1.12</td><td class="benchmarkresult">2.60</td><td class="benchmarkresult">4.69</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.89</td><td class="benchmarkresult">1.87</td><td class="benchmarkresult">1.84</td><td class="benchmarkresult">2.25</td><td class="benchmarkresult">6.54</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.90</td><td class="benchmarkresult">1.91</td><td class="benchmarkresult">1.87</td><td class="benchmarkresult">2.63</td><td class="benchmarkresult">4.02</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.88,1.88,1.85,2.61,4.95]},
|
|||
|
|
{name:'std::string_view e = "Test text";',data:[0.746,0.757,0.740,1.83,2.22]},
|
|||
|
|
{name:'ssa e = "Test text";',data:[0.377,0.746,0.371,1.84,2.18]},
|
|||
|
|
{name:'stringa e = "Test text";',data:[1.12,1.12,1.12,2.60,4.69]},
|
|||
|
|
{name:'lstringa<20> e = "Test text";',data:[1.89,1.87,1.84,2.25,6.54]},
|
|||
|
|
{name:'lstringa<40> e = "Test text";',data:[1.90,1.91,1.87,2.63,4.02]}
|
|||
|
|
]}</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">19.5</td><td class="benchmarkresult">18.7</td><td class="benchmarkresult">78.0</td><td class="benchmarkresult">74.8</td><td class="benchmarkresult">56.3</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.758</td><td class="benchmarkresult">0.751</td><td class="benchmarkresult">0.739</td><td class="benchmarkresult">1.84</td><td class="benchmarkresult">5.05</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.376</td><td class="benchmarkresult">0.754</td><td class="benchmarkresult">0.369</td><td class="benchmarkresult">1.85</td><td class="benchmarkresult">2.18</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.13</td><td class="benchmarkresult">1.11</td><td class="benchmarkresult">2.92</td><td class="benchmarkresult">5.33</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">20.5</td><td class="benchmarkresult">19.6</td><td class="benchmarkresult">82.0</td><td class="benchmarkresult">76.7</td><td class="benchmarkresult">59.7</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">1.90</td><td class="benchmarkresult">2.59</td><td class="benchmarkresult">1.85</td><td class="benchmarkresult">3.01</td><td class="benchmarkresult">6.28</td></tr>
|
|||
|
|
</tbody></table></div><script>bench_sets['Create Str from long literal (30 symbols)'] = {id:'bs3', tests:[
|
|||
|
|
{name:'std::string e = "123456789012345678901234567890";',data:[19.5,18.7,78.0,74.8,56.3]},
|
|||
|
|
{name:'std::string_view e = "123456789012345678901234567890";',data:[0.758,0.751,0.739,1.84,5.05]},
|
|||
|
|
{name:'ssa e = "123456789012345678901234567890";',data:[0.376,0.754,0.369,1.85,2.18]},
|
|||
|
|
{name:'stringa e = "123456789012345678901234567890";',data:[1.13,1.13,1.11,2.92,5.33]},
|
|||
|
|
{name:'lstringa<20> e = "123456789012345678901234567890";',data:[20.5,19.6,82.0,76.7,59.7]},
|
|||
|
|
{name:'lstringa<40> e = "123456789012345678901234567890";',data:[1.90,2.59,1.85,3.01,6.28]}
|
|||
|
|
]}</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">5.73</td><td class="benchmarkresult">4.91</td><td class="benchmarkresult">1.87</td><td class="benchmarkresult">5.16</td><td class="benchmarkresult">5.67</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.381</td><td class="benchmarkresult">0.377</td><td class="benchmarkresult">0.376</td><td class="benchmarkresult">3.74</td><td class="benchmarkresult">5.04</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.378</td><td class="benchmarkresult">0.377</td><td class="benchmarkresult">3.75</td><td class="benchmarkresult">5.02</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.12</td><td class="benchmarkresult">1.14</td><td class="benchmarkresult">1.32</td><td class="benchmarkresult">4.07</td><td class="benchmarkresult">4.81</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">5.00</td><td class="benchmarkresult">4.84</td><td class="benchmarkresult">5.23</td><td class="benchmarkresult">8.64</td><td class="benchmarkresult">15.8</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.62</td><td class="benchmarkresult">4.60</td><td class="benchmarkresult">5.24</td><td class="benchmarkresult">8.46</td><td class="benchmarkresult">15.7</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:[5.73,4.91,1.87,5.16,5.67]},
|
|||
|
|
{name:'std::string_view e = "Test text"; auto c{e};',data:[0.381,0.377,0.376,3.74,5.04]},
|
|||
|
|
{name:'ssa e = "Test text"; auto c{e};',data:[0.376,0.378,0.377,3.75,5.02]},
|
|||
|
|
{name:'stringa e = "Test text"; auto c{e};',data:[1.12,1.14,1.32,4.07,4.81]},
|
|||
|
|
{name:'lstringa<20> e = "Test text"; auto c{e};',data:[5.00,4.84,5.23,8.64,15.8]},
|
|||
|
|
{name:'lstringa<40> e = "Test text"; auto c{e};',data:[4.62,4.60,5.24,8.46,15.7]}
|
|||
|
|
]}</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.8</td><td class="benchmarkresult">24.2</td><td class="benchmarkresult">78.2</td><td class="benchmarkresult">76.3</td><td class="benchmarkresult">116</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.763</td><td class="benchmarkresult">0.746</td><td class="benchmarkresult">0.741</td><td class="benchmarkresult">1.84</td><td class="benchmarkresult">5.04</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.744</td><td class="benchmarkresult">0.372</td><td class="benchmarkresult">1.87</td><td class="benchmarkresult">2.20</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.14</td><td class="benchmarkresult">1.13</td><td class="benchmarkresult">1.89</td><td class="benchmarkresult">2.97</td><td class="benchmarkresult">5.36</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.2</td><td class="benchmarkresult">24.4</td><td class="benchmarkresult">79.0</td><td class="benchmarkresult">82.0</td><td class="benchmarkresult">67.1</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">4.68</td><td class="benchmarkresult">5.62</td><td class="benchmarkresult">4.95</td><td class="benchmarkresult">7.05</td><td class="benchmarkresult">15.5</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.8,24.2,78.2,76.3,116]},
|
|||
|
|
{name:'std::string_view e = "123456789012345678901234567890"; auto c{e};',data:[0.763,0.746,0.741,1.84,5.04]},
|
|||
|
|
{name:'ssa e = "123456789012345678901234567890"; auto c{e};',data:[0.373,0.744,0.372,1.87,2.20]},
|
|||
|
|
{name:'stringa e = "123456789012345678901234567890"; auto c{e};',data:[1.14,1.13,1.89,2.97,5.36]},
|
|||
|
|
{name:'lstringa<20> e = "123456789012345678901234567890"; auto c{e};',data:[20.2,24.4,79.0,82.0,67.1]},
|
|||
|
|
{name:'lstringa<40> e = "123456789012345678901234567890"; auto c{e};',data:[4.68,5.62,4.95,7.05,15.5]}
|
|||
|
|
]}</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">7.73</td><td class="benchmarkresult">7.11</td><td class="benchmarkresult">39.5</td><td class="benchmarkresult">42.5</td><td class="benchmarkresult">141</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.25</td><td class="benchmarkresult">6.43</td><td class="benchmarkresult">39.1</td><td class="benchmarkresult">41.5</td><td class="benchmarkresult">134</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.91</td><td class="benchmarkresult">6.47</td><td class="benchmarkresult">18.2</td><td class="benchmarkresult">21.1</td><td class="benchmarkresult">101</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">8.10</td><td class="benchmarkresult">6.83</td><td class="benchmarkresult">18.8</td><td class="benchmarkresult">32.2</td><td class="benchmarkresult">102</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.91</td><td class="benchmarkresult">6.88</td><td class="benchmarkresult">18.2</td><td class="benchmarkresult">21.3</td><td class="benchmarkresult">100</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.92</td><td class="benchmarkresult">6.80</td><td class="benchmarkresult">17.8</td><td class="benchmarkresult">21.6</td><td class="benchmarkresult">102</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:[7.73,7.11,39.5,42.5,141]},
|
|||
|
|
{name:'std::string_view::find;',data:[7.25,6.43,39.1,41.5,134]},
|
|||
|
|
{name:'ssa::find;',data:[6.91,6.47,18.2,21.1,101]},
|
|||
|
|
{name:'stringa::find;',data:[8.10,6.83,18.8,32.2,102]},
|
|||
|
|
{name:'lstringa<20>::find;',data:[6.91,6.88,18.2,21.3,100]},
|
|||
|
|
{name:'lstringa<40>::find;',data:[6.92,6.80,17.8,21.6,102]}
|
|||
|
|
]}</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">5.87</td><td class="benchmarkresult">7.34</td><td class="benchmarkresult">1.85</td><td class="benchmarkresult">5.18</td><td class="benchmarkresult">117</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.5</td><td class="benchmarkresult">24.8</td><td class="benchmarkresult">80.4</td><td class="benchmarkresult">84.9</td><td class="benchmarkresult">120</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.6</td><td class="benchmarkresult">25.3</td><td class="benchmarkresult">81.2</td><td class="benchmarkresult">85.1</td><td class="benchmarkresult">119</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">23.7</td><td class="benchmarkresult">24.6</td><td class="benchmarkresult">80.9</td><td class="benchmarkresult">83.1</td><td class="benchmarkresult">120</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">23.1</td><td class="benchmarkresult">23.9</td><td class="benchmarkresult">85.9</td><td class="benchmarkresult">89.1</td><td class="benchmarkresult">124</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">23.1</td><td class="benchmarkresult">24.1</td><td class="benchmarkresult">87.1</td><td class="benchmarkresult">89.7</td><td class="benchmarkresult">125</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">25.4</td><td class="benchmarkresult">26.1</td><td class="benchmarkresult">90.3</td><td class="benchmarkresult">89.0</td><td class="benchmarkresult">122</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">25.5</td><td class="benchmarkresult">26.6</td><td class="benchmarkresult">87.8</td><td class="benchmarkresult">91.5</td><td class="benchmarkresult">146</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">30.4</td><td class="benchmarkresult">30.8</td><td class="benchmarkresult">90.4</td><td class="benchmarkresult">93.8</td><td class="benchmarkresult">163</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.0</td><td class="benchmarkresult">41.2</td><td class="benchmarkresult">95.5</td><td class="benchmarkresult">99.5</td><td class="benchmarkresult">148</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">111</td><td class="benchmarkresult">111</td><td class="benchmarkresult">130</td><td class="benchmarkresult">132</td><td class="benchmarkresult">165</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">142</td><td class="benchmarkresult">139</td><td class="benchmarkresult">186</td><td class="benchmarkresult">181</td><td class="benchmarkresult">204</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.11</td><td class="benchmarkresult">1.31</td><td class="benchmarkresult">4.15</td><td class="benchmarkresult">4.84</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.12</td><td class="benchmarkresult">1.31</td><td class="benchmarkresult">4.11</td><td class="benchmarkresult">10.3</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.12</td><td class="benchmarkresult">1.11</td><td class="benchmarkresult">1.30</td><td class="benchmarkresult">4.13</td><td class="benchmarkresult">10.1</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.3</td><td class="benchmarkresult">16.2</td><td class="benchmarkresult">16.1</td><td class="benchmarkresult">18.7</td><td class="benchmarkresult">10.2</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.4</td><td class="benchmarkresult">16.2</td><td class="benchmarkresult">16.3</td><td class="benchmarkresult">18.6</td><td class="benchmarkresult">10.2</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.3</td><td class="benchmarkresult">16.8</td><td class="benchmarkresult">16.0</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};/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.6</td><td class="benchmarkresult">16.3</td><td class="benchmarkresult">16.1</td><td class="benchmarkresult">18.6</td><td class="benchmarkresult">10.1</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.3</td><td class="benchmarkresult">16.3</td><td class="benchmarkresult">16.0</td><td class="benchmarkresult">18.6</td><td class="benchmarkresult">10.1</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.3</td><td class="benchmarkresult">16.4</td><td class="benchmarkresult">16.0</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};/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.3</td><td class="benchmarkresult">16.2</td><td class="benchmarkresult">16.0</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};/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.4</td><td class="benchmarkresult">16.2</td><td class="benchmarkresult">16.0</td><td class="benchmarkresult">18.8</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.3</td><td class="benchmarkresult">16.2</td><td class="benchmarkresult">16.0</td><td class="benchmarkresult">18.5</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.11</td><td class="benchmarkresult">4.87</td><td class="benchmarkresult">4.85</td><td class="benchmarkresult">8.67</td><td class="benchmarkresult">15.7</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">5.12</td><td class="benchmarkresult">4.83</td><td class="benchmarkresult">4.83</td><td class="benchmarkresult">8.61</td><td class="benchmarkresult">16.1</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">5.20</td><td class="benchmarkresult">4.90</td><td class="benchmarkresult">4.89</td><td class="benchmarkresult">8.58</td><td class="benchmarkresult">75.4</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.3</td><td class="benchmarkresult">25.0</td><td class="benchmarkresult">83.5</td><td class="benchmarkresult">80.5</td><td class="benchmarkresult">76.2</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">23.9</td><td class="benchmarkresult">25.0</td><td class="benchmarkresult">85.8</td><td class="benchmarkresult">83.1</td><td class="benchmarkresult">82.1</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.8</td><td class="benchmarkresult">25.9</td><td class="benchmarkresult">81.4</td><td class="benchmarkresult">83.1</td><td class="benchmarkresult">78.1</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">26.3</td><td class="benchmarkresult">27.0</td><td class="benchmarkresult">84.3</td><td class="benchmarkresult">86.5</td><td class="benchmarkresult">79.2</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.7</td><td class="benchmarkresult">28.3</td><td class="benchmarkresult">85.1</td><td class="benchmarkresult">89.8</td><td class="benchmarkresult">103</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.6</td><td class="benchmarkresult">30.7</td><td class="benchmarkresult">89.0</td><td class="benchmarkresult">90.8</td><td class="benchmarkresult">121</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">85.9</td><td class="benchmarkresult">83.7</td><td class="benchmarkresult">99.5</td><td class="benchmarkresult">101</td><td class="benchmarkresult">107</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">99.2</td><td class="benchmarkresult">97.7</td><td class="benchmarkresult">132</td><td class="benchmarkresult">131</td><td class="benchmarkresult">123</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">118</td><td class="benchmarkresult">116</td><td class="benchmarkresult">195</td><td class="benchmarkresult">192</td><td class="benchmarkresult">160</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">4.96</td><td class="benchmarkresult">4.99</td><td class="benchmarkresult">5.57</td><td class="benchmarkresult">8.47</td><td class="benchmarkresult">15.3</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.95</td><td class="benchmarkresult">4.89</td><td class="benchmarkresult">5.69</td><td class="benchmarkresult">8.59</td><td class="benchmarkresult">15.1</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.89</td><td class="benchmarkresult">5.60</td><td class="benchmarkresult">8.48</td><td class="benchmarkresult">15.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.92</td><td class="benchmarkresult">4.85</td><td class="benchmarkresult">5.59</td><td class="benchmarkresult">8.60</td><td class="benchmarkresult">15.3</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.61</td><td class="benchmarkresult">4.52</td><td class="benchmarkresult">8.48</td><td class="benchmarkresult">11.7</td><td class="benchmarkresult">17.2</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.14</td><td class="benchmarkresult">6.15</td><td class="benchmarkresult">8.74</td><td class="benchmarkresult">11.6</td><td class="benchmarkresult">18.3</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.50</td><td class="benchmarkresult">6.59</td><td class="benchmarkresult">8.99</td><td class="benchmarkresult">11.9</td><td class="benchmarkresult">19.1</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.19</td><td class="benchmarkresult">8.29</td><td class="benchmarkresult">10.1</td><td class="benchmarkresult">13.0</td><td class="benchmarkresult">32.3</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.4</td><td class="benchmarkresult">10.6</td><td class="benchmarkresult">11.8</td><td class="benchmarkresult">14.6</td><td class="benchmarkresult">33.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">87.0</td><td class="benchmarkresult">89.0</td><td class="benchmarkresult">99.4</td><td class="benchmarkresult">101</td><td class="benchmarkresult">106</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">103</td><td class="benchmarkresult">101</td><td class="benchmarkresult">133</td><td class="benchmarkresult">130</td><td class="benchmarkresult">119</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">118</td><td class="benchmarkresult">115</td><td class="benchmarkresult">196</td><td class="benchmarkresult">192</td><td class="benchmarkresult">162</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:[5.87,7.34,1.85,5.18,117]},
|
|||
|
|
{name:'std::string copy{str_with_len_N};/16',data:[23.5,24.8,80.4,84.9,120]},
|
|||
|
|
{name:'std::string copy{str_with_len_N};/23',data:[23.6,25.3,81.2,85.1,119]},
|
|||
|
|
{name:'std::string copy{str_with_len_N};/24',data:[23.7,24.6,80.9,83.1,120]},
|
|||
|
|
{name:'std::string copy{str_with_len_N};/32',data:[23.1,23.9,85.9,89.1,124]},
|
|||
|
|
{name:'std::string copy{str_with_len_N};/64',data:[23.1,24.1,87.1,89.7,125]},
|
|||
|
|
{name:'std::string copy{str_with_len_N};/128',data:[25.4,26.1,90.3,89.0,122]},
|
|||
|
|
{name:'std::string copy{str_with_len_N};/256',data:[25.5,26.6,87.8,91.5,146]},
|
|||
|
|
{name:'std::string copy{str_with_len_N};/512',data:[30.4,30.8,90.4,93.8,163]},
|
|||
|
|
{name:'std::string copy{str_with_len_N};/1024',data:[39.0,41.2,95.5,99.5,148]},
|
|||
|
|
{name:'std::string copy{str_with_len_N};/2048',data:[111,111,130,132,165]},
|
|||
|
|
{name:'std::string copy{str_with_len_N};/4096',data:[142,139,186,181,204]},
|
|||
|
|
{name:'stringa copy{str_with_len_N};/15',data:[1.13,1.11,1.31,4.15,4.84]},
|
|||
|
|
{name:'stringa copy{str_with_len_N};/16',data:[1.12,1.12,1.31,4.11,10.3]},
|
|||
|
|
{name:'stringa copy{str_with_len_N};/23',data:[1.12,1.11,1.30,4.13,10.1]},
|
|||
|
|
{name:'stringa copy{str_with_len_N};/24',data:[16.3,16.2,16.1,18.7,10.2]},
|
|||
|
|
{name:'stringa copy{str_with_len_N};/32',data:[16.4,16.2,16.3,18.6,10.2]},
|
|||
|
|
{name:'stringa copy{str_with_len_N};/64',data:[16.3,16.8,16.0,18.6,10.0]},
|
|||
|
|
{name:'stringa copy{str_with_len_N};/128',data:[16.6,16.3,16.1,18.6,10.1]},
|
|||
|
|
{name:'stringa copy{str_with_len_N};/256',data:[16.3,16.3,16.0,18.6,10.1]},
|
|||
|
|
{name:'stringa copy{str_with_len_N};/512',data:[16.3,16.4,16.0,18.7,10.1]},
|
|||
|
|
{name:'stringa copy{str_with_len_N};/1024',data:[16.3,16.2,16.0,18.6,10.0]},
|
|||
|
|
{name:'stringa copy{str_with_len_N};/2048',data:[16.4,16.2,16.0,18.8,10.0]},
|
|||
|
|
{name:'stringa copy{str_with_len_N};/4096',data:[16.3,16.2,16.0,18.5,10.1]},
|
|||
|
|
{name:'lstringa<16> copy{str_with_len_N};/15',data:[5.11,4.87,4.85,8.67,15.7]},
|
|||
|
|
{name:'lstringa<16> copy{str_with_len_N};/16',data:[5.12,4.83,4.83,8.61,16.1]},
|
|||
|
|
{name:'lstringa<16> copy{str_with_len_N};/23',data:[5.20,4.90,4.89,8.58,75.4]},
|
|||
|
|
{name:'lstringa<16> copy{str_with_len_N};/24',data:[24.3,25.0,83.5,80.5,76.2]},
|
|||
|
|
{name:'lstringa<16> copy{str_with_len_N};/32',data:[23.9,25.0,85.8,83.1,82.1]},
|
|||
|
|
{name:'lstringa<16> copy{str_with_len_N};/64',data:[25.8,25.9,81.4,83.1,78.1]},
|
|||
|
|
{name:'lstringa<16> copy{str_with_len_N};/128',data:[26.3,27.0,84.3,86.5,79.2]},
|
|||
|
|
{name:'lstringa<16> copy{str_with_len_N};/256',data:[27.7,28.3,85.1,89.8,103]},
|
|||
|
|
{name:'lstringa<16> copy{str_with_len_N};/512',data:[30.6,30.7,89.0,90.8,121]},
|
|||
|
|
{name:'lstringa<16> copy{str_with_len_N};/1024',data:[85.9,83.7,99.5,101,107]},
|
|||
|
|
{name:'lstringa<16> copy{str_with_len_N};/2048',data:[99.2,97.7,132,131,123]},
|
|||
|
|
{name:'lstringa<16> copy{str_with_len_N};/4096',data:[118,116,195,192,160]},
|
|||
|
|
{name:'lstringa<512> copy{str_with_len_N};/15',data:[4.96,4.99,5.57,8.47,15.3]},
|
|||
|
|
{name:'lstringa<512> copy{str_with_len_N};/16',data:[4.95,4.89,5.69,8.59,15.1]},
|
|||
|
|
{name:'lstringa<512> copy{str_with_len_N};/23',data:[4.91,4.89,5.60,8.48,15.6]},
|
|||
|
|
{name:'lstringa<512> copy{str_with_len_N};/24',data:[4.92,4.85,5.59,8.60,15.3]},
|
|||
|
|
{name:'lstringa<512> copy{str_with_len_N};/32',data:[4.61,4.52,8.48,11.7,17.2]},
|
|||
|
|
{name:'lstringa<512> copy{str_with_len_N};/64',data:[6.14,6.15,8.74,11.6,18.3]},
|
|||
|
|
{name:'lstringa<512> copy{str_with_len_N};/128',data:[6.50,6.59,8.99,11.9,19.1]},
|
|||
|
|
{name:'lstringa<512> copy{str_with_len_N};/256',data:[8.19,8.29,10.1,13.0,32.3]},
|
|||
|
|
{name:'lstringa<512> copy{str_with_len_N};/512',data:[10.4,10.6,11.8,14.6,33.8]},
|
|||
|
|
{name:'lstringa<512> copy{str_with_len_N};/1024',data:[87.0,89.0,99.4,101,106]},
|
|||
|
|
{name:'lstringa<512> copy{str_with_len_N};/2048',data:[103,101,133,130,119]},
|
|||
|
|
{name:'lstringa<512> copy{str_with_len_N};/4096',data:[118,115,196,192,162]}
|
|||
|
|
]}</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);
|
|||
|
|
benchmark::DoNotOptimize(s);
|
|||
|
|
}
|
|||
|
|
}</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.3</td><td class="benchmarkresult">32.5</td><td class="benchmarkresult">33.7</td><td class="benchmarkresult">205</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) {
|
|||
|
|
#ifdef __EMSCRIPTEN__
|
|||
|
|
state.SkipWithError("not implemented");
|
|||
|
|
#else
|
|||
|
|
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);
|
|||
|
|
benchmark::DoNotOptimize(s);
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">from_chars требует точного указания основания счисления,
|
|||
|
|
не допускает знаков плюс, пробелов, префиксов 0x и т.п.</span></span></td><td class="benchmarkresult">15.2</td><td class="benchmarkresult">12.4</td><td class="benchmarkresult">13.8</td><td class="benchmarkresult">17.9</td><td class="benchmarkresult">Not impl</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 = std::get<0>(t. template to_int<int, true, 10, false, false>());
|
|||
|
|
#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">13.7</td><td class="benchmarkresult">7.92</td><td class="benchmarkresult">13.3</td><td class="benchmarkresult">15.4</td><td class="benchmarkresult">55.2</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 = std::get<0>(t. template to_int<int, true, 10, false, false>());
|
|||
|
|
#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">13.2</td><td class="benchmarkresult">7.73</td><td class="benchmarkresult">13.0</td><td class="benchmarkresult">15.1</td><td class="benchmarkresult">51.0</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 = std::get<0>(t. template to_int<int, true, 10, false, false>());
|
|||
|
|
#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.8</td><td class="benchmarkresult">7.73</td><td class="benchmarkresult">13.2</td><td class="benchmarkresult">14.9</td><td class="benchmarkresult">52.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.3,32.5,33.7,205]},
|
|||
|
|
{name:'std::string_view s = "123456789"; std::from_chars(s.data(), s.data() + s.size(), res, 10);',data:[15.2,12.4,13.8,17.9,NaN]},
|
|||
|
|
{name:'stringa s = "123456789"; int res = s.to_int<int, true, 10, false>',data:[13.7,7.92,13.3,15.4,55.2]},
|
|||
|
|
{name:'ssa s = "123456789"; int res = s.to_int<int, true, 10, false>',data:[13.2,7.73,13.0,15.1,51.0]},
|
|||
|
|
{name:'lstringa<20> s = "123456789"; int res = s.to_int<int, true, 10, false>',data:[12.8,7.73,13.2,14.9,52.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);
|
|||
|
|
benchmark::DoNotOptimize(s);
|
|||
|
|
}
|
|||
|
|
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">Всё то же, только для 16ричной системы</span></span></td><td class="benchmarkresult">24.2</td><td class="benchmarkresult">24.0</td><td class="benchmarkresult">34.4</td><td class="benchmarkresult">36.1</td><td class="benchmarkresult">149</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) {
|
|||
|
|
#ifdef __EMSCRIPTEN__
|
|||
|
|
state.SkipWithError("not implemented");
|
|||
|
|
#else
|
|||
|
|
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);
|
|||
|
|
benchmark::DoNotOptimize(s);
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
}</span></span></td><td></td><td class="benchmarkresult">9.80</td><td class="benchmarkresult">14.8</td><td class="benchmarkresult">8.29</td><td class="benchmarkresult">10.1</td><td class="benchmarkresult">Not impl</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 = std::get<0>(t. template to_int<int, true, 16, false, false>());
|
|||
|
|
#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">11.8</td><td class="benchmarkresult">7.55</td><td class="benchmarkresult">11.4</td><td class="benchmarkresult">13.8</td><td class="benchmarkresult">51.8</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 = std::get<0>(t. template to_int<int, true, 16, false, false>());
|
|||
|
|
#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">11.6</td><td class="benchmarkresult">8.28</td><td class="benchmarkresult">10.8</td><td class="benchmarkresult">12.8</td><td class="benchmarkresult">50.0</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 = std::get<0>(t. template to_int<int, true, 16, false, false>());
|
|||
|
|
#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">11.5</td><td class="benchmarkresult">8.16</td><td class="benchmarkresult">11.2</td><td class="benchmarkresult">12.8</td><td class="benchmarkresult">51.4</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:[24.2,24.0,34.4,36.1,149]},
|
|||
|
|
{name:'std::string_view s = "abcDef"; std::from_chars(s.data(), s.data() + s.size(), res, 16);',data:[9.80,14.8,8.29,10.1,NaN]},
|
|||
|
|
{name:'stringa s = "abcDef"; int res = s.to_int<int, true, 16, false>',data:[11.8,7.55,11.4,13.8,51.8]},
|
|||
|
|
{name:'ssa s = "abcDef"; int res = s.to_int<int, true, 16, false>',data:[11.6,8.28,10.8,12.8,50.0]},
|
|||
|
|
{name:'lstringa<20> s = "abcDef"; int res = s.to_int<int, true, 16, false>',data:[11.5,8.16,11.2,12.8,51.4]}
|
|||
|
|
]}</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);
|
|||
|
|
benchmark::DoNotOptimize(s);
|
|||
|
|
}
|
|||
|
|
}</span></span></td><td><span class="tooltip info"> >> <span class="tooltiptext">А здесь уже парсинг произвольного числа.</span></span></td><td class="benchmarkresult">29.1</td><td class="benchmarkresult">29.1</td><td class="benchmarkresult">44.2</td><td class="benchmarkresult">48.8</td><td class="benchmarkresult">216</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 = std::get<0>(t. template to_int<int>());
|
|||
|
|
#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">22.1</td><td class="benchmarkresult">16.7</td><td class="benchmarkresult">18.8</td><td class="benchmarkresult">22.4</td><td class="benchmarkresult">74.8</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 = std::get<0>(t.to_int<int, false>());
|
|||
|
|
#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">15.8</td><td class="benchmarkresult">14.6</td><td class="benchmarkresult">15.9</td><td class="benchmarkresult">19.0</td><td class="benchmarkresult">51.3</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:[29.1,29.1,44.2,48.8,216]},
|
|||
|
|
{name:'stringa s = " 123456789"; int res = s.to_int<int>; // Check overflow',data:[22.1,16.7,18.8,22.4,74.8]},
|
|||
|
|
{name:'ssa s = " 123456789"; int res = s.to_int<int, false>; // No check overflow',data:[15.8,14.6,15.9,19.0,51.3]}
|
|||
|
|
]}</script>
|
|||
|
|
|
|||
|
|
<div class="benchset" id="bs11"><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">1384</td><td class="benchmarkresult">1439</td><td class="benchmarkresult">7392</td><td class="benchmarkresult">5758</td><td class="benchmarkresult">11603</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">368</td><td class="benchmarkresult">369</td><td class="benchmarkresult">1068</td><td class="benchmarkresult">1327</td><td class="benchmarkresult">1138</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">370</td><td class="benchmarkresult">372</td><td class="benchmarkresult">757</td><td class="benchmarkresult">972</td><td class="benchmarkresult">1204</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">254</td><td class="benchmarkresult">258</td><td class="benchmarkresult">403</td><td class="benchmarkresult">539</td><td class="benchmarkresult">873</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">232</td><td class="benchmarkresult">241</td><td class="benchmarkresult">229</td><td class="benchmarkresult">371</td><td class="benchmarkresult">640</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">140</td><td class="benchmarkresult">140</td><td class="benchmarkresult">139</td><td class="benchmarkresult">235</td><td class="benchmarkresult">498</td></tr>
|
|||
|
|
</tbody></table></div><script>bench_sets['Append const literal of 16 bytes 64 times, 1024 total length'] = {id:'bs11', tests:[
|
|||
|
|
{name:'std::stringstream str; ... str << "abbaabbaabbaabba";',data:[1384,1439,7392,5758,11603]},
|
|||
|
|
{name:'std::string str; ... str += "abbaabbaabbaabba";',data:[368,369,1068,1327,1138]},
|
|||
|
|
{name:'lstringa<8> str; ... str += "abbaabbaabbaabba";',data:[370,372,757,972,1204]},
|
|||
|
|
{name:'lstringa<128> str; ... str += "abbaabbaabbaabba";',data:[254,258,403,539,873]},
|
|||
|
|
{name:'lstringa<512> str; ... str += "abbaabbaabbaabba";',data:[232,241,229,371,640]},
|
|||
|
|
{name:'lstringa<1024> str; ... str += "abbaabbaabbaabba";',data:[140,140,139,235,498]}
|
|||
|
|
]}</script>
|
|||
|
|
|
|||
|
|
<div class="benchset" id="bs12"><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">1390</td><td class="benchmarkresult">1399</td><td class="benchmarkresult">6632</td><td class="benchmarkresult">5986</td><td class="benchmarkresult">11698</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">1298</td><td class="benchmarkresult">1343</td><td class="benchmarkresult">3901</td><td class="benchmarkresult">3929</td><td class="benchmarkresult">4015</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">425</td><td class="benchmarkresult">429</td><td class="benchmarkresult">763</td><td class="benchmarkresult">849</td><td class="benchmarkresult">1435</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">367</td><td class="benchmarkresult">361</td><td class="benchmarkresult">481</td><td class="benchmarkresult">550</td><td class="benchmarkresult">1128</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">323</td><td class="benchmarkresult">316</td><td class="benchmarkresult">306</td><td class="benchmarkresult">388</td><td class="benchmarkresult">858</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">241</td><td class="benchmarkresult">256</td><td class="benchmarkresult">214</td><td class="benchmarkresult">271</td><td class="benchmarkresult">730</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:'bs12', tests:[
|
|||
|
|
{name:'std::stringstream str; ... str << str_var << "abbaabbaabbaabba";',data:[1390,1399,6632,5986,11698]},
|
|||
|
|
{name:'std::string str; ... str += str_var + "abbaabbaabbaabba";',data:[1298,1343,3901,3929,4015]},
|
|||
|
|
{name:'lstringa<8> str; ... str += str_var + "abbaabbaabbaabba";',data:[425,429,763,849,1435]},
|
|||
|
|
{name:'lstringa<128> str; ... str += str_var + "abbaabbaabbaabba";',data:[367,361,481,550,1128]},
|
|||
|
|
{name:'lstringa<512> str; ... str += str_var + "abbaabbaabbaabba";',data:[323,316,306,388,858]},
|
|||
|
|
{name:'lstringa<1024> str; ... str += str_var + "abbaabbaabbaabba";',data:[241,256,214,271,730]}
|
|||
|
|
]}</script>
|
|||
|
|
|
|||
|
|
<div class="benchset" id="bs13"><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">73908</td><td class="benchmarkresult">74700</td><td class="benchmarkresult">361900</td><td class="benchmarkresult">285644</td><td class="benchmarkresult">581542</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">77722</td><td class="benchmarkresult">72474</td><td class="benchmarkresult">199378</td><td class="benchmarkresult">194551</td><td class="benchmarkresult">207680</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">21112</td><td class="benchmarkresult">19642</td><td class="benchmarkresult">19852</td><td class="benchmarkresult">23615</td><td class="benchmarkresult">52577</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">16124</td><td class="benchmarkresult">17774</td><td class="benchmarkresult">18215</td><td class="benchmarkresult">22280</td><td class="benchmarkresult">49889</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">16129</td><td class="benchmarkresult">17565</td><td class="benchmarkresult">17973</td><td class="benchmarkresult">22335</td><td class="benchmarkresult">50097</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">16145</td><td class="benchmarkresult">18274</td><td class="benchmarkresult">17891</td><td class="benchmarkresult">21663</td><td class="benchmarkresult">49930</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:'bs13', tests:[
|
|||
|
|
{name:'std::stringstream str; ... str << str_var << "abbaabbaabbaabba"; 2048 times',data:[73908,74700,361900,285644,581542]},
|
|||
|
|
{name:'std::string str; ... str += str_var + "abbaabbaabbaabba"; 2048 times',data:[77722,72474,199378,194551,207680]},
|
|||
|
|
{name:'lstringa<8> str; ... str += str_var + "abbaabbaabbaabba"; 2048 times',data:[21112,19642,19852,23615,52577]},
|
|||
|
|
{name:'lstringa<128> str; ... str += str_var + "abbaabbaabbaabba"; 2048 times',data:[16124,17774,18215,22280,49889]},
|
|||
|
|
{name:'lstringa<512> str; ... str += str_var + "abbaabbaabbaabba"; 2048 times',data:[16129,17565,17973,22335,50097]},
|
|||
|
|
{name:'lstringa<1024> str; ... str += str_var + "abbaabbaabbaabba"; 2048 times',data:[16145,18274,17891,21663,49930]}
|
|||
|
|
]}</script>
|
|||
|
|
|
|||
|
|
<div class="benchset" id="bs14"><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">1393</td><td class="benchmarkresult">1400</td><td class="benchmarkresult">6383</td><td class="benchmarkresult">5491</td><td class="benchmarkresult">11739</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">1412</td><td class="benchmarkresult">1342</td><td class="benchmarkresult">3986</td><td class="benchmarkresult">3997</td><td class="benchmarkresult">4587</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">513</td><td class="benchmarkresult">598</td><td class="benchmarkresult">859</td><td class="benchmarkresult">958</td><td class="benchmarkresult">1593</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">443</td><td class="benchmarkresult">500</td><td class="benchmarkresult">569</td><td class="benchmarkresult">664</td><td class="benchmarkresult">1343</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">462</td><td class="benchmarkresult">403</td><td class="benchmarkresult">483</td><td class="benchmarkresult">1057</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">312</td><td class="benchmarkresult">431</td><td class="benchmarkresult">314</td><td class="benchmarkresult">381</td><td class="benchmarkresult">929</td></tr>
|
|||
|
|
</tbody></table></div><script>bench_sets['Append 2 string of 16 bytes 32 times, 1024 total length'] = {id:'bs14', tests:[
|
|||
|
|
{name:'std::stringstream str; ... str << str_var1 << str_var2;',data:[1393,1400,6383,5491,11739]},
|
|||
|
|
{name:'std::string str; ... str += str_var1 + str_var2;',data:[1412,1342,3986,3997,4587]},
|
|||
|
|
{name:'lstringa<16> str; ... str += str_var1 + str_var2;',data:[513,598,859,958,1593]},
|
|||
|
|
{name:'lstringa<128> str; ... str += str_var1 + str_var2;',data:[443,500,569,664,1343]},
|
|||
|
|
{name:'lstringa<512> str; ... str += str_var1 + str_var2;',data:[395,462,403,483,1057]},
|
|||
|
|
{name:'lstringa<1024> str; ... str += str_var1 + str_var2;',data:[312,431,314,381,929]}
|
|||
|
|
]}</script>
|
|||
|
|
|
|||
|
|
<div class="benchset" id="bs15"><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">3133</td><td class="benchmarkresult">3419</td><td class="benchmarkresult">11663</td><td class="benchmarkresult">11615</td><td class="benchmarkresult">19990</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">486</td><td class="benchmarkresult">451</td><td class="benchmarkresult">1114</td><td class="benchmarkresult">1260</td><td class="benchmarkresult">3781</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">1424</td><td class="benchmarkresult">1509</td><td class="benchmarkresult">2906</td><td class="benchmarkresult">2855</td><td class="benchmarkresult">8018</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">1184</td><td class="benchmarkresult">1286</td><td class="benchmarkresult">1950</td><td class="benchmarkresult">2420</td><td class="benchmarkresult">5058</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">1412</td><td class="benchmarkresult">1618</td><td class="benchmarkresult">2112</td><td class="benchmarkresult">2609</td><td class="benchmarkresult">7141</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">997</td><td class="benchmarkresult">1132</td><td class="benchmarkresult">1029</td><td class="benchmarkresult">1549</td><td class="benchmarkresult">5041</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">323</td><td class="benchmarkresult">316</td><td class="benchmarkresult">823</td><td class="benchmarkresult">949</td><td class="benchmarkresult">1865</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">162</td><td class="benchmarkresult">160</td><td class="benchmarkresult">191</td><td class="benchmarkresult">1202</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">152</td><td class="benchmarkresult">174</td><td class="benchmarkresult">156</td><td class="benchmarkresult">241</td><td class="benchmarkresult">1715</td></tr>
|
|||
|
|
</tbody></table></div><script>bench_sets['Append text, number, text'] = {id:'bs15', tests:[
|
|||
|
|
{name:'std::stringstream str; str << "test = " << k << " times";',data:[3133,3419,11663,11615,19990]},
|
|||
|
|
{name:'std::string str = "test = " + std::to_string(k) + " times";',data:[486,451,1114,1260,3781]},
|
|||
|
|
{name:'char buf[100]; sprintf(buf, "test = %u times", k); std::string str = buf;',data:[1424,1509,2906,2855,8018]},
|
|||
|
|
{name:'std::string str = std::format("test = {} times", k);',data:[1184,1286,1950,2420,5058]},
|
|||
|
|
{name:'lstringa<8> str; str.format("test = {} times", k);',data:[1412,1618,2112,2609,7141]},
|
|||
|
|
{name:'lstringa<32> str; str.format("test = {} times", k);',data:[997,1132,1029,1549,5041]},
|
|||
|
|
{name:'lstringa<8> str = "test = " + k + " times";',data:[323,316,823,949,1865]},
|
|||
|
|
{name:'lstringa<32> str = "test = " + k + " times";',data:[157,162,160,191,1202]},
|
|||
|
|
{name:'stringa str = "test = " + k + " times";',data:[152,174,156,241,1715]}
|
|||
|
|
]}</script>
|
|||
|
|
|
|||
|
|
<div class="benchset" id="bs16"><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">268</td><td class="benchmarkresult">285</td><td class="benchmarkresult">576</td><td class="benchmarkresult">555</td><td class="benchmarkresult">1618</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">161</td><td class="benchmarkresult">139</td><td class="benchmarkresult">173</td><td class="benchmarkresult">289</td><td class="benchmarkresult">655</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">180</td><td class="benchmarkresult">153</td><td class="benchmarkresult">188</td><td class="benchmarkresult">207</td><td class="benchmarkresult">899</td></tr>
|
|||
|
|
</tbody></table></div><script>bench_sets['Split text and convert to int'] = {id:'bs16', tests:[
|
|||
|
|
{name:'std::string::find + substr + std::strtol',data:[268,285,576,555,1618]},
|
|||
|
|
{name:'ssa::splitter + ssa::as_int',data:[161,139,173,289,655]},
|
|||
|
|
{name:'ssa::splitf + functor',data:[180,153,188,207,899]}
|
|||
|
|
]}</script>
|
|||
|
|
|
|||
|
|
<div class="benchset" id="bs17"><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">859</td><td class="benchmarkresult">867</td><td class="benchmarkresult">1153</td><td class="benchmarkresult">1303</td><td class="benchmarkresult">6193</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">2541</td><td class="benchmarkresult">2597</td><td class="benchmarkresult">2073</td><td class="benchmarkresult">2205</td><td class="benchmarkresult">9978</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);
|
|||
|
|
benchmark::DoNotOptimize(repl_from);
|
|||
|
|
benchmark::DoNotOptimize(repl_to);
|
|||
|
|
}
|
|||
|
|
}</span></span></td><td></td><td class="benchmarkresult">2719</td><td class="benchmarkresult">2671</td><td class="benchmarkresult">2441</td><td class="benchmarkresult">2625</td><td class="benchmarkresult">10198</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">1253</td><td class="benchmarkresult">1543</td><td class="benchmarkresult">1386</td><td class="benchmarkresult">1555</td><td class="benchmarkresult">5706</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">1026</td><td class="benchmarkresult">1181</td><td class="benchmarkresult">1373</td><td class="benchmarkresult">1382</td><td class="benchmarkresult">5029</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">1150</td><td class="benchmarkresult">1265</td><td class="benchmarkresult">1213</td><td class="benchmarkresult">1277</td><td class="benchmarkresult">4946</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">897</td><td class="benchmarkresult">866</td><td class="benchmarkresult">1228</td><td class="benchmarkresult">1266</td><td class="benchmarkresult">4198</td></tr>
|
|||
|
|
</tbody></table></div><script>bench_sets['Replace symbols in text ~400 symbols'] = {id:'bs17', tests:[
|
|||
|
|
{name:'Naive (and wrong) replace symbols with std::string find + replace',data:[859,867,1153,1303,6193]},
|
|||
|
|
{name:'replace symbols with std::string find_first_of + replace',data:[2541,2597,2073,2205,9978]},
|
|||
|
|
{name:'replace symbols with std::string_view find_first_of + copy',data:[2719,2671,2441,2625,10198]},
|
|||
|
|
{name:'replace runtime symbols with string expressions and without remembering all search results',data:[1253,1543,1386,1555,5706]},
|
|||
|
|
{name:'replace runtime symbols with simstr and memorization of all search results',data:[1026,1181,1373,1382,5029]},
|
|||
|
|
{name:'replace const symbols with string expressions and without remembering all search results',data:[1150,1265,1213,1277,4946]},
|
|||
|
|
{name:'replace const symbols with string expressions and memorization of all search results',data:[897,866,1228,1266,4198]}
|
|||
|
|
]}</script>
|
|||
|
|
|
|||
|
|
<div class="benchset" id="bs18"><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">165</td><td class="benchmarkresult">170</td><td class="benchmarkresult">321</td><td class="benchmarkresult">329</td><td class="benchmarkresult">1016</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">312</td><td class="benchmarkresult">348</td><td class="benchmarkresult">378</td><td class="benchmarkresult">429</td><td class="benchmarkresult">1431</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);
|
|||
|
|
benchmark::DoNotOptimize(repl_from);
|
|||
|
|
benchmark::DoNotOptimize(repl_to);
|
|||
|
|
}
|
|||
|
|
}</span></span></td><td></td><td class="benchmarkresult">338</td><td class="benchmarkresult">322</td><td class="benchmarkresult">342</td><td class="benchmarkresult">363</td><td class="benchmarkresult">1417</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">165</td><td class="benchmarkresult">198</td><td class="benchmarkresult">251</td><td class="benchmarkresult">279</td><td class="benchmarkresult">795</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">188</td><td class="benchmarkresult">192</td><td class="benchmarkresult">347</td><td class="benchmarkresult">389</td><td class="benchmarkresult">847</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">146</td><td class="benchmarkresult">165</td><td class="benchmarkresult">218</td><td class="benchmarkresult">248</td><td class="benchmarkresult">626</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">150</td><td class="benchmarkresult">153</td><td class="benchmarkresult">301</td><td class="benchmarkresult">354</td><td class="benchmarkresult">706</td></tr>
|
|||
|
|
</tbody></table></div><script>bench_sets['Replace symbols in text ~40 symbols'] = {id:'bs18', tests:[
|
|||
|
|
{name:'Short Naive (and wrong) replace symbols with std::string find + replace',data:[165,170,321,329,1016]},
|
|||
|
|
{name:'Short replace symbols with std::string find_first_of + replace',data:[312,348,378,429,1431]},
|
|||
|
|
{name:'Short replace symbols with std::string_view find_first_of + copy',data:[338,322,342,363,1417]},
|
|||
|
|
{name:'Short replace runtime symbols with string expressions and without remembering all search results',data:[165,198,251,279,795]},
|
|||
|
|
{name:'Short replace runtime symbols with simstr and memorization of all search results',data:[188,192,347,389,847]},
|
|||
|
|
{name:'Short replace const symbols with string expressions and without remembering all search results',data:[146,165,218,248,626]},
|
|||
|
|
{name:'Short replace const symbols with string expressions and memorization of all search results',data:[150,153,301,354,706]}
|
|||
|
|
]}</script>
|
|||
|
|
|
|||
|
|
<div class="benchset" id="bs19"><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">161</td><td class="benchmarkresult">162</td><td class="benchmarkresult">238</td><td class="benchmarkresult">245</td><td class="benchmarkresult">832</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">541</td><td class="benchmarkresult">493</td><td class="benchmarkresult">779</td><td class="benchmarkresult">852</td><td class="benchmarkresult">2559</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">1075</td><td class="benchmarkresult">993</td><td class="benchmarkresult">1450</td><td class="benchmarkresult">1534</td><td class="benchmarkresult">4466</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">2344</td><td class="benchmarkresult">2333</td><td class="benchmarkresult">3246</td><td class="benchmarkresult">3381</td><td class="benchmarkresult">8916</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">6366</td><td class="benchmarkresult">6359</td><td class="benchmarkresult">8153</td><td class="benchmarkresult">8081</td><td class="benchmarkresult">19324</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">167</td><td class="benchmarkresult">343</td><td class="benchmarkresult">349</td><td class="benchmarkresult">749</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">438</td><td class="benchmarkresult">495</td><td class="benchmarkresult">645</td><td class="benchmarkresult">702</td><td class="benchmarkresult">2053</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">824</td><td class="benchmarkresult">922</td><td class="benchmarkresult">1080</td><td class="benchmarkresult">1187</td><td class="benchmarkresult">3754</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">1662</td><td class="benchmarkresult">1862</td><td class="benchmarkresult">1916</td><td class="benchmarkresult">2087</td><td class="benchmarkresult">6775</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">3108</td><td class="benchmarkresult">3551</td><td class="benchmarkresult">3650</td><td class="benchmarkresult">4039</td><td class="benchmarkresult">13478</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">116</td><td class="benchmarkresult">121</td><td class="benchmarkresult">216</td><td class="benchmarkresult">230</td><td class="benchmarkresult">503</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">389</td><td class="benchmarkresult">444</td><td class="benchmarkresult">548</td><td class="benchmarkresult">573</td><td class="benchmarkresult">1848</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">797</td><td class="benchmarkresult">827</td><td class="benchmarkresult">941</td><td class="benchmarkresult">1009</td><td class="benchmarkresult">3537</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">1629</td><td class="benchmarkresult">1637</td><td class="benchmarkresult">1775</td><td class="benchmarkresult">1988</td><td class="benchmarkresult">6923</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">3125</td><td class="benchmarkresult">3280</td><td class="benchmarkresult">3478</td><td class="benchmarkresult">3790</td><td class="benchmarkresult">13739</td></tr>
|
|||
|
|
</tbody></table></div><script>bench_sets['Replace All Str To Longer Size'] = {id:'bs19', tests:[
|
|||
|
|
{name:'replace bb to ---- in std::string|64',data:[161,162,238,245,832]},
|
|||
|
|
{name:'replace bb to ---- in std::string|256',data:[541,493,779,852,2559]},
|
|||
|
|
{name:'replace bb to ---- in std::string|512',data:[1075,993,1450,1534,4466]},
|
|||
|
|
{name:'replace bb to ---- in std::string|1024',data:[2344,2333,3246,3381,8916]},
|
|||
|
|
{name:'replace bb to ---- in std::string|2048',data:[6366,6359,8153,8081,19324]},
|
|||
|
|
{name:'replace bb to ---- in lstringa<8>|64',data:[145,167,343,349,749]},
|
|||
|
|
{name:'replace bb to ---- in lstringa<8>|256',data:[438,495,645,702,2053]},
|
|||
|
|
{name:'replace bb to ---- in lstringa<8>|512',data:[824,922,1080,1187,3754]},
|
|||
|
|
{name:'replace bb to ---- in lstringa<8>|1024',data:[1662,1862,1916,2087,6775]},
|
|||
|
|
{name:'replace bb to ---- in lstringa<8>|2048',data:[3108,3551,3650,4039,13478]},
|
|||
|
|
{name:'replace bb to ---- by init stringa|64',data:[116,121,216,230,503]},
|
|||
|
|
{name:'replace bb to ---- by init stringa|256',data:[389,444,548,573,1848]},
|
|||
|
|
{name:'replace bb to ---- by init stringa|512',data:[797,827,941,1009,3537]},
|
|||
|
|
{name:'replace bb to ---- by init stringa|1024',data:[1629,1637,1775,1988,6923]},
|
|||
|
|
{name:'replace bb to ---- by init stringa|2048',data:[3125,3280,3478,3790,13739]}
|
|||
|
|
]}</script>
|
|||
|
|
|
|||
|
|
<div class="benchset" id="bs20"><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">129</td><td class="benchmarkresult">125</td><td class="benchmarkresult">196</td><td class="benchmarkresult">218</td><td class="benchmarkresult">570</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">404</td><td class="benchmarkresult">405</td><td class="benchmarkresult">503</td><td class="benchmarkresult">539</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">815</td><td class="benchmarkresult">780</td><td class="benchmarkresult">864</td><td class="benchmarkresult">979</td><td class="benchmarkresult">3523</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">1489</td><td class="benchmarkresult">1446</td><td class="benchmarkresult">1700</td><td class="benchmarkresult">1885</td><td class="benchmarkresult">6916</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">3100</td><td class="benchmarkresult">3138</td><td class="benchmarkresult">3239</td><td class="benchmarkresult">3576</td><td class="benchmarkresult">13510</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">103</td><td class="benchmarkresult">192</td><td class="benchmarkresult">202</td><td class="benchmarkresult">482</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">302</td><td class="benchmarkresult">301</td><td class="benchmarkresult">452</td><td class="benchmarkresult">470</td><td class="benchmarkresult">1565</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">579</td><td class="benchmarkresult">548</td><td class="benchmarkresult">797</td><td class="benchmarkresult">816</td><td class="benchmarkresult">2921</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">1181</td><td class="benchmarkresult">1112</td><td class="benchmarkresult">1444</td><td class="benchmarkresult">1515</td><td class="benchmarkresult">5594</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">2181</td><td class="benchmarkresult">2105</td><td class="benchmarkresult">2839</td><td class="benchmarkresult">2909</td><td class="benchmarkresult">10928</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">82.9</td><td class="benchmarkresult">91.4</td><td class="benchmarkresult">167</td><td class="benchmarkresult">183</td><td class="benchmarkresult">366</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">219</td><td class="benchmarkresult">261</td><td class="benchmarkresult">352</td><td class="benchmarkresult">392</td><td class="benchmarkresult">1224</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">447</td><td class="benchmarkresult">485</td><td class="benchmarkresult">598</td><td class="benchmarkresult">668</td><td class="benchmarkresult">2221</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">880</td><td class="benchmarkresult">984</td><td class="benchmarkresult">1082</td><td class="benchmarkresult">1201</td><td class="benchmarkresult">4235</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">1654</td><td class="benchmarkresult">1862</td><td class="benchmarkresult">1963</td><td class="benchmarkresult">2295</td><td class="benchmarkresult">8496</td></tr>
|
|||
|
|
</tbody></table></div><script>bench_sets['Replace All Str To Same Size'] = {id:'bs20', tests:[
|
|||
|
|
{name:'replace bb to -- in std::string|64',data:[129,125,196,218,570]},
|
|||
|
|
{name:'replace bb to -- in std::string|256',data:[404,405,503,539,1885]},
|
|||
|
|
{name:'replace bb to -- in std::string|512',data:[815,780,864,979,3523]},
|
|||
|
|
{name:'replace bb to -- in std::string|1024',data:[1489,1446,1700,1885,6916]},
|
|||
|
|
{name:'replace bb to -- in std::string|2048',data:[3100,3138,3239,3576,13510]},
|
|||
|
|
{name:'replace bb to -- in lstringa<8>|64',data:[101,103,192,202,482]},
|
|||
|
|
{name:'replace bb to -- in lstringa<8>|256',data:[302,301,452,470,1565]},
|
|||
|
|
{name:'replace bb to -- in lstringa<8>|512',data:[579,548,797,816,2921]},
|
|||
|
|
{name:'replace bb to -- in lstringa<8>|1024',data:[1181,1112,1444,1515,5594]},
|
|||
|
|
{name:'replace bb to -- in lstringa<8>|2048',data:[2181,2105,2839,2909,10928]},
|
|||
|
|
{name:'replace bb to -- by init stringa|64',data:[82.9,91.4,167,183,366]},
|
|||
|
|
{name:'replace bb to -- by init stringa|256',data:[219,261,352,392,1224]},
|
|||
|
|
{name:'replace bb to -- by init stringa|512',data:[447,485,598,668,2221]},
|
|||
|
|
{name:'replace bb to -- by init stringa|1024',data:[880,984,1082,1201,4235]},
|
|||
|
|
{name:'replace bb to -- by init stringa|2048',data:[1654,1862,1963,2295,8496]}
|
|||
|
|
]}</script>
|
|||
|
|
|
|||
|
|
<div class="benchset" id="bs21"><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">3718900</td><td class="benchmarkresult">3769704</td><td class="benchmarkresult">4144900</td><td class="benchmarkresult">4237335</td><td class="benchmarkresult">5327536</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">3691442</td><td class="benchmarkresult">3652417</td><td class="benchmarkresult">5984962</td><td class="benchmarkresult">5468019</td><td class="benchmarkresult">6172235</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">3719844</td><td class="benchmarkresult">3800957</td><td class="benchmarkresult">3983708</td><td class="benchmarkresult">3990921</td><td class="benchmarkresult">5318092</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">4115786</td><td class="benchmarkresult">4103196</td><td class="benchmarkresult">7030276</td><td class="benchmarkresult">6304651</td><td class="benchmarkresult">7002408</td></tr>
|
|||
|
|
</tbody></table></div><script>bench_sets['Hash Map insert and find'] = {id:'bs21', tests:[
|
|||
|
|
{name:'hashStrMapA<size_t> emplace & find stringa;',data:[3718900,3769704,4144900,4237335,5327536]},
|
|||
|
|
{name:'std::unordered_map<std::string, size_t> emplace & find std::string;',data:[3691442,3652417,5984962,5468019,6172235]},
|
|||
|
|
{name:'hashStrMapA<size_t> emplace & find ssa;',data:[3719844,3800957,3983708,3990921,5318092]},
|
|||
|
|
{name:'std::unordered_map<std::string, size_t> emplace & find std::string_view;',data:[4115786,4103196,7030276,6304651,7002408]}
|
|||
|
|
]}</script>
|
|||
|
|
|
|||
|
|
<div class="benchset" id="bs22"><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">949</td><td class="benchmarkresult">1588</td><td class="benchmarkresult">1660</td><td class="benchmarkresult">5576</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">837</td><td class="benchmarkresult">1025</td><td class="benchmarkresult">1648</td><td class="benchmarkresult">1747</td><td class="benchmarkresult">5877</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">2608</td><td class="benchmarkresult">2654</td><td class="benchmarkresult">10979</td><td class="benchmarkresult">9942</td><td class="benchmarkresult">16604</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">512</td><td class="benchmarkresult">500</td><td class="benchmarkresult">847</td><td class="benchmarkresult">891</td><td class="benchmarkresult">2780</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">657</td><td class="benchmarkresult">716</td><td class="benchmarkresult">1003</td><td class="benchmarkresult">1007</td><td class="benchmarkresult">3249</td></tr>
|
|||
|
|
</tbody></table></div><script>bench_sets['Build Full Func Name'] = {id:'bs22', tests:[
|
|||
|
|
{name:'Build func full name std::string;',data:[733,949,1588,1660,5576]},
|
|||
|
|
{name:'Build func full name std::string 1;',data:[837,1025,1648,1747,5877]},
|
|||
|
|
{name:'Build func full name std::stream;',data:[2608,2654,10979,9942,16604]},
|
|||
|
|
{name:'Build func full name stringa;',data:[512,500,847,891,2780]},
|
|||
|
|
{name:'Build func full name stringa 1;',data:[657,716,1003,1007,3249]}
|
|||
|
|
]}</script></body></html>
|