Skip to content

Commit

Permalink
QByteArray: use new assign() in operator=(const char *)
Browse files Browse the repository at this point in the history
operator=(~) and assign(~) share similar names but, until now, have not
shared the same functionality. This patch introduces the usage of
QByteArray::assign() within the non-sharing assignment operator to
effectively boost efficiency by reusing the available capacity.

Since these assignment operators are frequently used in many places,
both within Qt and non-Qt code, this patch comes with benchmarks.

The preview of the benchmark results are compared with this patch and
before this patch. The findings indicate a slight enhancement in
performance associated with the assignment operator. Despite the results
displaying only a minor improvement, progress has been made. Therefore
use assign(QByteArrayView) as replacement.

(x86_64-little_endian-lp64 shared (dynamic) release build (O3); by
gcc 13.2.1, endeavouros ; 13th Gen Intel(R) Core(TM) i9-13900K

benchmarks executed with -perf -iterations 1000000

  * The last value at the EOL represent the string size.

QByteArray &operator=(const char *ch) (current)
  65    cycles/iter; 317  instructions/iter; 16.0 nsec/iter (5)
  71.7  cycles/iter; 383  instructions/iter; 13.0 nsec/iter (10)
  59.8  cycles/iter; 318  instructions/iter; 10.9 nsec/iter (20)
  70.8  cycles/iter; 340  instructions/iter; 12.9 nsec/iter (50)
  80.2  cycles/iter; 419  instructions/iter; 14.6 nsec/iter (100)
  164.2 cycles/iter; 899  instructions/iter; 29.9 nsec/iter (500)
  260.5 cycles/iter; 1522 instructions/iter; 45.6 nsec/iter (1'000)

QByteArray &operator=(const char *ch) (before)
  66.8  cycles/iter; 317  instructions/iter; 16.9 nsec/iter (5)
  76.5  cycles/iter; 383  instructions/iter; 13.9 nsec/iter (10)
  63.7  cycles/iter; 318  instructions/iter; 11.6 nsec/iter (20)
  71.6  cycles/iter; 344  instructions/iter; 13.0 nsec/iter (50)
  77.5  cycles/iter; 419  instructions/iter; 14.1 nsec/iter (100)
  143.4 cycles/iter; 893  instructions/iter; 26.1 nsec/iter (500)
  270.8 cycles/iter; 1516 instructions/iter; 48.2 nsec/iter (1'000)

Task-number: QTBUG-106201
Change-Id: I0745c33f0f61f1d844a60960cc55f565320d5945
Reviewed-by: Thiago Macieira <[email protected]>
  • Loading branch information
Dennis Oberst committed Aug 11, 2023
1 parent 70835a9 commit 3c38efb
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 8 deletions.
9 changes: 1 addition & 8 deletions src/corelib/text/qbytearray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1342,14 +1342,7 @@ QByteArray &QByteArray::operator=(const char *str)
} else if (!*str) {
d = DataPointer::fromRawData(&_empty, 0);
} else {
const qsizetype len = qsizetype(strlen(str));
const auto capacityAtEnd = d->allocatedCapacity() - d.freeSpaceAtBegin();
if (d->needsDetach() || len > capacityAtEnd
|| (len < size() && len < (capacityAtEnd >> 1)))
// ### inefficient! reallocData() does copy the old data and we then overwrite it in the next line
reallocData(len, QArrayData::KeepSize);
memcpy(d.data(), str, len + 1); // include null terminator
d.size = len;
assign(str);
}
return *this;
}
Expand Down
35 changes: 35 additions & 0 deletions tests/benchmarks/corelib/text/qbytearray/tst_bench_qbytearray.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ private slots:

void toPercentEncoding_data();
void toPercentEncoding();

void operator_assign_char();
void operator_assign_char_data();
};

void tst_QByteArray::initTestCase()
Expand Down Expand Up @@ -353,6 +356,38 @@ void tst_QByteArray::toPercentEncoding()
QTEST(encoded, "expected");
}

void tst_QByteArray::operator_assign_char()
{
QFETCH(QByteArray, data);
QString str(data.size(), Qt::Uninitialized);

const char *tdata = data.constData();
QBENCHMARK {
str.operator=(tdata);
}
}

void tst_QByteArray::operator_assign_char_data()
{
QTest::addColumn<QByteArray>("data");

QByteArray data;
data.fill('a', 5);
QTest::newRow("length: 5") << data;
data.fill('b', 10);
QTest::newRow("length: 10") << data;
data.fill('c', 20);
QTest::newRow("length: 20") << data;
data.fill('d', 50);
QTest::newRow("length: 50") << data;
data.fill('e', 100);
QTest::newRow("length: 100") << data;
data.fill('f', 500);
QTest::newRow("length: 500") << data;
data.fill('g', 1'000);
QTest::newRow("length: 1'000") << data;
}

QTEST_MAIN(tst_QByteArray)

#include "tst_bench_qbytearray.moc"

0 comments on commit 3c38efb

Please sign in to comment.