forked from qt-creator/qt-creator
SmallString is a very simple utf8 string class. It's purpose is performance. It uses a short string opimization which provides 31 bytes of heap free memory to save a 30 bytes long string plus null terminator. If the string gets larger heap is allocated. The grow strategy is 1.5 to improve reuse of allocated memory. It uses optionally constexpr to provide string literals. Change-Id: I7757fb51abfeca200d074cbfce2f1d99edc0ecb0 Reviewed-by: Tobias Hunger <tobias.hunger@theqtcompany.com>
360 lines
10 KiB
C++
360 lines
10 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
** Contact: http://www.qt.io/licensing
|
|
**
|
|
** This file is part of Qt Creator.
|
|
**
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms and
|
|
** conditions see http://www.qt.io/terms-conditions. For further information
|
|
** use the contact form at http://www.qt.io/contact-us.
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
** following information to ensure the GNU Lesser General Public License
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** In addition, as a special exception, The Qt Company gives you certain additional
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include <benchmark/benchmark.h>
|
|
|
|
#include <QByteArray>
|
|
|
|
#include <utils/smallstringvector.h>
|
|
|
|
#ifndef __cpp_constexpr
|
|
#define constexpr
|
|
#endif
|
|
|
|
namespace {
|
|
|
|
Utils::SmallStringView createText(int size)
|
|
{
|
|
auto text = new char[size + 1];
|
|
std::fill(text, text + size, 'x');
|
|
text[size] = 0;
|
|
|
|
return Utils::SmallStringView(text, size);
|
|
}
|
|
|
|
void CreateSmallStringLiteral(benchmark::State& state) {
|
|
while (state.KeepRunning())
|
|
constexpr auto string = Utils::SmallStringLiteral("very very very long long long text");
|
|
}
|
|
BENCHMARK(CreateSmallStringLiteral);
|
|
|
|
void CreateNullSmallString(benchmark::State& state) {
|
|
while (state.KeepRunning())
|
|
auto string = Utils::SmallString();
|
|
}
|
|
BENCHMARK(CreateNullSmallString);
|
|
|
|
void CreateSmallStringFromLiteral(benchmark::State& state) {
|
|
while (state.KeepRunning())
|
|
auto string = Utils::SmallString("very very very long long long text");
|
|
}
|
|
BENCHMARK(CreateSmallStringFromLiteral);
|
|
|
|
void CreateSmallString(benchmark::State& state) {
|
|
auto text = createText(state.range_x());
|
|
|
|
while (state.KeepRunning())
|
|
auto string = Utils::SmallString(text.data(), state.range_x());
|
|
}
|
|
BENCHMARK(CreateSmallString)->Range(0, 1024);
|
|
|
|
void CreateQByteArray(benchmark::State& state) {
|
|
auto text = createText(state.range_x());
|
|
|
|
while (state.KeepRunning())
|
|
QByteArray foo(text.data(), state.range_x());
|
|
}
|
|
BENCHMARK(CreateQByteArray)->Range(0, 1024);
|
|
|
|
void CreateQString(benchmark::State& state) {
|
|
auto text = createText(state.range_x());
|
|
|
|
while (state.KeepRunning())
|
|
auto string = QString::fromUtf8(text.data(), state.range_x());
|
|
}
|
|
BENCHMARK(CreateQString)->Range(0, 1024);
|
|
|
|
void SmallStringAppend(benchmark::State& state) {
|
|
auto text = createText(state.range_y());
|
|
|
|
while (state.KeepRunning()) {
|
|
auto string = Utils::SmallString();
|
|
for (int i = 0; i < state.range_x(); ++i)
|
|
string.append(text);
|
|
}
|
|
}
|
|
BENCHMARK(SmallStringAppend)->RangePair(1, 64, 1, 4096);
|
|
|
|
void QByteArrayAppend(benchmark::State& state) {
|
|
auto text = createText(state.range_y());
|
|
|
|
while (state.KeepRunning()) {
|
|
auto string = QByteArray();
|
|
for (int i = 0; i < state.range_x(); ++i)
|
|
string.append(text.data(), text.size());
|
|
}
|
|
}
|
|
BENCHMARK(QByteArrayAppend)->RangePair(1, 64, 1, 4096);
|
|
|
|
void CompareCString(benchmark::State& state) {
|
|
Utils::SmallString text("myFunctionIsQuiteLong");
|
|
|
|
while (state.KeepRunning())
|
|
benchmark::DoNotOptimize(text == "staticMetaObject");
|
|
}
|
|
BENCHMARK(CompareCString);
|
|
|
|
void CompareString(benchmark::State& state) {
|
|
Utils::SmallString text("myFunctionIsQuiteLong");
|
|
|
|
while (state.KeepRunning())
|
|
benchmark::DoNotOptimize(text == Utils::SmallString("staticMetaObject"));
|
|
}
|
|
BENCHMARK(CompareString);
|
|
|
|
void CompareStringView(benchmark::State& state) {
|
|
Utils::SmallString text("myFunctionIsQuiteLong");
|
|
|
|
while (state.KeepRunning())
|
|
benchmark::DoNotOptimize(text == Utils::SmallStringView("staticMetaObject"));
|
|
}
|
|
BENCHMARK(CompareStringView);
|
|
|
|
void CompareCStringPointer(benchmark::State& state) {
|
|
Utils::SmallString text("myFunctionIsQuiteLong");
|
|
const char *cStringText = "staticMetaObject";
|
|
|
|
while (state.KeepRunning())
|
|
benchmark::DoNotOptimize(text == cStringText);
|
|
}
|
|
BENCHMARK(CompareCStringPointer);
|
|
|
|
void StartsWith(benchmark::State& state) {
|
|
Utils::SmallString text("myFunctionIsQuiteLong");
|
|
|
|
while (state.KeepRunning())
|
|
benchmark::DoNotOptimize(text.startsWith("qt_"));
|
|
}
|
|
BENCHMARK(StartsWith);
|
|
|
|
void ShortSize(benchmark::State& state) {
|
|
Utils::SmallString text("myFunctionIsQuiteLong");
|
|
|
|
while (state.KeepRunning())
|
|
benchmark::DoNotOptimize(text.size());
|
|
}
|
|
BENCHMARK(ShortSize);
|
|
|
|
void LongSize(benchmark::State& state) {
|
|
Utils::SmallString text("myFunctionIsQuiteLong");
|
|
|
|
while (state.KeepRunning())
|
|
benchmark::DoNotOptimize(text.size());
|
|
}
|
|
BENCHMARK(LongSize);
|
|
|
|
void Size(benchmark::State& state) {
|
|
Utils::SmallString text("myFunctionIsMUCHMUCHMUCHMUCHMUCHLonger");
|
|
|
|
while (state.KeepRunning())
|
|
benchmark::DoNotOptimize(text.size());
|
|
}
|
|
BENCHMARK(LongSize);
|
|
|
|
void generateRandomString(char *data, const int length)
|
|
{
|
|
static const char alphaNumericData[] =
|
|
"0123456789"
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
"abcdefghijklmnopqrstuvwxyz";
|
|
|
|
for (int i = 0; i < length; ++i) {
|
|
data[i] = alphaNumericData[std::rand() % (sizeof(alphaNumericData) - 1)];
|
|
}
|
|
}
|
|
|
|
uint entryCount=100000;
|
|
|
|
QByteArray generateRandomQByteArray()
|
|
{
|
|
QByteArray text;
|
|
text.resize(20);
|
|
|
|
generateRandomString(text.data(), text.size());
|
|
|
|
return text;
|
|
}
|
|
|
|
void Collection_CreateQByteArrays(benchmark::State& state)
|
|
{
|
|
while (state.KeepRunning()) {
|
|
QVector<QByteArray> values;
|
|
values.reserve(entryCount);
|
|
|
|
for (int i = 0; i < entryCount; i++)
|
|
values.append(generateRandomQByteArray());
|
|
}
|
|
}
|
|
BENCHMARK(Collection_CreateQByteArrays);
|
|
|
|
void Collection_SortQByteArrays(benchmark::State& state)
|
|
{
|
|
while (state.KeepRunning()) {
|
|
state.PauseTiming();
|
|
|
|
QVector<QByteArray> values;
|
|
values.reserve(entryCount);
|
|
|
|
for (int i = 0; i < entryCount; i++)
|
|
values.append(generateRandomQByteArray());
|
|
|
|
state.ResumeTiming();
|
|
|
|
std::sort(values.begin(), values.end());
|
|
}
|
|
}
|
|
BENCHMARK(Collection_SortQByteArrays);
|
|
|
|
void Collection_FilterQByteArrays(benchmark::State& state)
|
|
{
|
|
while (state.KeepRunning()) {
|
|
state.PauseTiming();
|
|
|
|
QVector<QByteArray> values;
|
|
values.reserve(entryCount);
|
|
QVector<QByteArray> filteredValues;
|
|
filteredValues.reserve(entryCount);
|
|
|
|
for (int i = 0; i < entryCount; i++)
|
|
values.append(generateRandomQByteArray());
|
|
|
|
auto startsWithA = [] (const QByteArray &byteArray) {
|
|
return byteArray.startsWith('a');
|
|
};
|
|
|
|
state.ResumeTiming();
|
|
|
|
std::copy_if(std::make_move_iterator(values.begin()),
|
|
std::make_move_iterator(values.end()),
|
|
std::back_inserter(filteredValues),
|
|
startsWithA);
|
|
}
|
|
}
|
|
BENCHMARK(Collection_FilterQByteArrays);
|
|
|
|
Utils::SmallString generateRandomSmallString(int size = 20)
|
|
{
|
|
Utils::SmallString text;
|
|
text.resize(size);
|
|
|
|
generateRandomString(text.data(), text.size());
|
|
|
|
return text;
|
|
}
|
|
|
|
void Collection_CreateSmallStrings(benchmark::State& state)
|
|
{
|
|
while (state.KeepRunning()) {
|
|
Utils::SmallStringVector values;
|
|
values.reserve(entryCount);
|
|
|
|
for (int i = 0; i < entryCount; i++)
|
|
values.push_back(generateRandomSmallString());
|
|
}
|
|
}
|
|
BENCHMARK(Collection_CreateSmallStrings);
|
|
|
|
void Collection_SortSmallStrings(benchmark::State& state)
|
|
{
|
|
while (state.KeepRunning()) {
|
|
state.PauseTiming();
|
|
|
|
Utils::SmallStringVector values;
|
|
values.reserve(entryCount);
|
|
|
|
for (int i = 0; i < entryCount; i++)
|
|
values.push_back(generateRandomSmallString());
|
|
|
|
state.ResumeTiming();
|
|
|
|
std::sort(values.begin(), values.end());
|
|
}
|
|
}
|
|
BENCHMARK(Collection_SortSmallStrings);
|
|
|
|
void Collection_FilterSmallStrings(benchmark::State& state)
|
|
{
|
|
while (state.KeepRunning()) {
|
|
state.PauseTiming();
|
|
|
|
Utils::SmallStringVector values;
|
|
values.reserve(entryCount);
|
|
Utils::SmallStringVector filteredValues;
|
|
filteredValues.reserve(entryCount);
|
|
|
|
for (int i = 0; i < entryCount; i++)
|
|
values.push_back(generateRandomSmallString());
|
|
|
|
auto startsWithA = [] (const Utils::SmallString &byteArray) {
|
|
return byteArray.startsWith('a');
|
|
};
|
|
|
|
state.ResumeTiming();
|
|
|
|
std::copy_if(std::make_move_iterator(values.begin()),
|
|
std::make_move_iterator(values.end()),
|
|
std::back_inserter(filteredValues),
|
|
startsWithA);
|
|
}
|
|
}
|
|
BENCHMARK(Collection_FilterSmallStrings);
|
|
|
|
void IterateOver(benchmark::State& state) {
|
|
Utils::SmallString text = generateRandomSmallString(30);
|
|
auto begin = std::next(text.begin(), state.range_x());
|
|
auto end = std::next(text.begin(), state.range_y());
|
|
|
|
while (state.KeepRunning()) {
|
|
std::for_each(begin, end, [] (char x) {
|
|
benchmark::DoNotOptimize(x);
|
|
});
|
|
}
|
|
}
|
|
BENCHMARK(IterateOver)->ArgPair(0, 8)
|
|
->ArgPair(8, 16)
|
|
->ArgPair(16, 24)
|
|
->ArgPair(24, 31)
|
|
->ArgPair(0, 8)
|
|
->ArgPair(0, 16)
|
|
->ArgPair(0, 24)
|
|
->ArgPair(0, 31);
|
|
|
|
|
|
//void StringLiteralSize(benchmark::State& state) {
|
|
// constexpr Utils::SmallStringLiteral text("myFunctionIsQuiteLong");
|
|
|
|
// while (state.KeepRunning()) {
|
|
// constexpr auto size = text.size(); // internal compile error
|
|
// benchmark::DoNotOptimize(size);
|
|
// }
|
|
//}
|
|
//BENCHMARK(StringLiteralSize);
|
|
}
|