[Development] How qAsConst and qExchange lead to qNN

Volker Hilsheimer volker.hilsheimer at qt.io
Mon Nov 14 19:00:27 CET 2022



> On 14 Nov 2022, at 18:30, Marc Mutz via Development <development at qt-project.org> wrote:
> 
> Hi Ulf,
> 
> On 14.11.22 17:37, Ulf Hermann via Development wrote:
>> Hi Marc,
>> 
>>> On 11.11.22 09:35, Ulf Hermann via Development wrote:
>>>> There is an undeniable benefit of _offering_ QSpan, QStringView, and
>>>> generator APIs in a few relevant cases:
>>>> 
>>>> 1. Users want to pass a "foreign" container to a Qt function that
>>>> doesn't only store it as QList or QString. It might merely iterate it or
>>>> store it as something else.
>>> 
>>> The assumption that there's a problem only for "foreign containers" is
>>> incorrect: Take the native Qt container QString as an example. See
>>> assembly in my QAnyStringView blog post:
>>> https://www.qt.io/blog/qstringview-diaries-qanystringview You have this
>>> problem as soon as you pass constant data, which is a common enough
>>> use-case to warrant optimizing for.
>> 
>> My point is the "doesn't only store it as QList or QString" and 
>> "foreign" is in quotes quite on purpose. Maybe that wasn't clear enough, 
>> though.
>> 
>> So, if the method immediately converts whatever it gets to QList or 
>> QString, then there is no point in passing it a span or view.
> 
> My point is that there _is_. Citing my blog post:

[…]

> It matters whether the QString/QList creation is in front of or behind 
> the ABI boundary. The size of the tst_qsettings executable for Clang 
> builds went down by >10% when the API was switched over to 
> QAnyStringView, without any changes to the test code itself (and 
> QAnyStringView hasn't even got the size/tag swap that Thiago pointed out 
> and that would make it require less gargantuan immediate values):
> https://codereview.qt-project.org/c/qt/qtbase/+/353688
> 
> Sure, the sequence of assembler instructions is the same, but improved 
> code locality means it'll also execute a bit faster. Also, if we can 
> condense user code by 10% without changes to their code, then some users 
> may have an easier time right-sizing their embedded hardware, e.g.
> 
> 
> Finally, to give you the very big picture: we have a duty to avoid 
> inflicting such egregiously inefficient code on the world. This bloat 
> needs to be stored: on disk, in RAM, in cache. At each of these levels, 
> the extra storage causes some pJ extra energy use, billions of times 
> over, causing corresponding CO2 emissions.
> 
> The German government has started dealing out the well-known "blue 
> angel" certificates for software now. Customers will eventually demand 
> our help in getting the energy use of their software down so they can be 
> certified.
> 
> We can, of course, ostrich on. But Qt is in a unique position, as a C++ 
> native UI framework, to assist users in meeting climate goals. Think 
> about it: Would projects that prefer programmer productivity over 
> resource use inflict C++ on their programmers? Won't such projects 
> rather (continue to) use Java and HTML, shipping applications with a 
> bundled chromium to run a few HTML/JS apps in GiBs of memory instead of 
> MiBs (hello, MS Teams!)? To me, it sounds more logical that projects 
> that inflict C++ on their developers would be those projects that need 
> to meet resource usage goals (because of right-sizing of embedded 
> hardware or because they want to get certified as energy-efficient). And 
> all this talk about convenience trumping efficiency is going to raise 
> eyebrows in such projects.
> 
> Let's make C++ easy to use, for sure. But, sorry, using spans isn't 
> difficult. Don't confuse familiarity with simplicity.
> 


Hey Marc,


Today, the vast majority of client code already has an owning container that gets passed around by copy or as const references. In Qt, we usually store data in the implementation in QList and QString. A test case that artificially creates a ton of QString instances perhaps rather falls into the small and isolated use case that doesn’t translate very well into real applications.

There are most certainly classes where it’d be good if we could replace that implementation with e.g. a std::pmr::vector with an optimised allocator. And then being stuck with a QList API forces both us and client code to construct suboptimal data structures. And there are APIs where replacing the QString version with QAnyStringView makes perfect sense (such as all remaining fromString factory functions).

But that we either replace all, or none of our APIs with something taking a view or a span are perhaps not the only outcomes of this conversation.

Can we focus on the cases with the biggest wins, like you already did with QRegion, QSettings, and QObject::setObjectName? What APIs in Qt that take a QString are usually called with a string literal in real applications, rather than with an already created QString object (that is in turn the result of user input or reading from some storage)? What was the outcome of the QObject::setObjectName change for e.g. Qt Creator?

What would a QSpan-returning implementation of e.g. QObject::findChildren or QItemSelectionModel::selectedIndexes look like? Is that even feasible without using coroutines?


Volker




More information about the Development mailing list