Trusted Software Excellence across Desktop and Embedded
Take a glance at the areas of expertise where KDAB excels ranging from swift troubleshooting, ongoing consulting and training to multi-year, large-scale software development projects.
Find out why customers from innovative industries rely on our extensive expertise, including Medical, Biotech, Science, Renewable Energy, Transportation, Mobility, Aviation, Automation, Electronics, Agriculture and Defense.
High-quality Embedded Engineering across the Stack
To successfully develop an embedded device that meets your expectations regarding quality, budget and time to market, all parts of the project need to fit perfectly together.
Learn more about KDAB's expertise in embedded software development.
Where the capabilities of modern mobile devices or web browsers fall short, KDAB engineers help you expertly architect and build high-functioning desktop and workstation applications.
Extensible, Safety-compliant Software for the Medical Sector
Create intelligent, patient-focused medical software and devices and stay ahead with technology that adapts to your needs.
KDAB offers you expertise in developing a broad spectrum of clinical and home-healthcare devices, including but not limited to, internal imaging systems, robotic surgery devices, ventilators and non-invasive monitoring systems.
Building digital dashboards and cockpits with fluid animations and gesture-controlled touchscreens is a big challenge.
In over two decades of developing intricate UI solutions for cars, trucks, tractors, scooters, ships, airplanes and more, the KDAB team has gained market leading expertise in this realm.
Build on Advanced Expertise when creating Modern UIs
KDAB assists you in the creation of user-friendly interfaces designed specifically for industrial process control, manufacturing, and fabrication.
Our specialties encompass the custom design and development of HMIs, enabling product accessibility from embedded systems, remote desktops, and mobile devices on the move.
Legacy software is a growing but often ignored problem across all industries. KDAB helps you elevate your aging code base to meet the dynamic needs of the future.
Whether you want to migrate from an old to a modern GUI toolkit, update to a more recent version, or modernize your code base, you can rely on over 25 years of modernization experience.
KDAB offers a wide range of services to address your software needs including consulting, development, workshops and training tailored to your requirements.
Our expertise spans cross-platform desktop, embedded and 3D application development, using the proven technologies for the job.
When working with KDAB, the first-ever Qt consultancy, you benefit from a deep understanding of Qt internals, that allows us to provide effective solutions, irrespective of the depth or scale of your Qt project.
Qt Services include developing applications, building runtimes, mixing native and web technologies, solving performance issues, and porting problems.
KDAB helps create commercial, scientific or industrial desktop applications from scratch, or update its code or framework to benefit from modern features.
Discover clean, efficient solutions that precisely meet your requirements.
Boost your team's programming skills with in-depth, constantly updated, hands-on training courses delivered by active software engineers who love to teach and share their knowledge.
Our courses cover Modern C++, Qt/QML, Rust, 3D programming, Debugging, Profiling and more.
The collective expertise of KDAB's engineering team is at your disposal to help you choose the software stack for your project or master domain-specific challenges.
Our particular focus is on software technologies you use for cross-platform applications or for embedded devices.
Since 1999, KDAB has been the largest independent Qt consultancy worldwide and today is a Qt Platinum partner. Our experts can help you with any aspect of software development with Qt and QML.
KDAB specializes in Modern C++ development, with a focus on desktop applications, GUI, embedded software, and operating systems.
Our experts are industry-recognized contributors and trainers, leveraging C++'s power and relevance across these domains to deliver high-quality software solutions.
KDAB can guide you incorporating Rust into your project, from as overlapping element to your existing C++ codebase to a complete replacement of your legacy code.
Unique Expertise for Desktop and Embedded Platforms
Whether you are using Linux, Windows, MacOS, Android, iOS or real-time OS, KDAB helps you create performance optimized applications on your preferred platform.
If you are planning to create projects with Slint, a lightweight alternative to standard GUI frameworks especially on low-end hardware, you can rely on the expertise of KDAB being one of the earliest adopters and official service partner of Slint.
KDAB has deep expertise in embedded systems, which coupled with Flutter proficiency, allows us to provide comprehensive support throughout the software development lifecycle.
Our engineers are constantly contributing to the Flutter ecosystem, for example by developing flutter-pi, one of the most used embedders.
KDAB invests significant time in exploring new software technologies to maintain its position as software authority. Benefit from this research and incorporate it eventually into your own project.
Start here to browse information on the KDAB website(s) and take advantage of useful developer resources like blogs, publications and videos about Qt, C++, Rust, 3D technologies like OpenGL and Vulkan, the KDAB developer tools and more.
The KDAB Youtube channel has become a go-to source for developers looking for high-quality tutorial and information material around software development with Qt/QML, C++, Rust and other technologies.
Click to navigate the all KDAB videos directly on this website.
In over 25 years KDAB has served hundreds of customers from various industries, many of them having become long-term customers who value our unique expertise and dedication.
Learn more about KDAB as a company, understand why we are considered a trusted partner by many and explore project examples in which we have proven to be the right supplier.
The KDAB Group is a globally recognized provider for software consulting, development and training, specializing in embedded devices and complex cross-platform desktop applications.
Read more about the history, the values, the team and the founder of the company.
When working with KDAB you can expect quality software and the desired business outcomes thanks to decades of experience gathered in hundreds of projects of different sizes in various industries.
Have a look at selected examples where KDAB has helped customers to succeed with their projects.
KDAB is committed to developing high-quality and high-performance software, and helping other developers deliver to the same high standards.
We create software with pride to improve your engineering and your business, making your products more resilient and maintainable with better performance.
KDAB has been the first certified Qt consulting and software development company in the world, and continues to deliver quality processes that meet or exceed the highest expectations.
In KDAB we value practical software development experience and skills higher than academic degrees. We strive to ensure equal treatment of all our employees regardless of age, ethnicity, gender, sexual orientation, nationality.
Interested? Read more about working at KDAB and how to apply for a job in software engineering or business administration.
This blog post is part of an ongoing series about the internals of the QML engine.
In the last blog post, we covered how bindings in the QML engine work. In this post, we'll examine the different kind of bindings. Some of this content is already covered by my DevDays talk QtQuick Under the Hood. In addition to that, there will be new content in this post as well.
Each binding like this one is actually a JavaScript function which is evaluated at runtime by the v8 engine. The result of the evaluation is the return value of the function, which is then assigned to the text property. v8 doesn't know about Qt's objects and properties, when encountering objects like parent or properties like width it asks the context wrapper and the object wrapper in QML to resolve them. These wrappers remember which properties were accessed while a binding was evaluated, and can therefore automatically connect to the changed signal (e.g. widthChanged()) of each property and connect it to a slot that re-evaluates the binding.
With the way bindings work now freshly in mind again, let's move on and have a look at the different binding types.
Binding Types
In the last post, I stated that each binding is represented by an instance of the QQmlBinding class. That was actually a lie-to-children. Having a full-blown QQmlBinding instance for each binding would be much to costly - there are hundreds if not thousands of bindings in a typical QML application, therefore a binding needs to be lightweight. In addition, each binding is compiled separately when loading a QML file, so there is a lot of overhead by invoking the v8 compiler many times during loading.
QV8Bindings
To resolve the large overhead of QQmlBinding, there is another binding class, confusingly named QV8Bindings. QV8Bindings is a collection of all bindings in a QML file, using an array of the much more lightweight QV8Bindings::Binding structure. The QML devs have gone to great lengths of minimizing the memory usage of this structure - they even exploit the fact that the last 2 bits of a pointer are unused because of alignment, and use that unused space to store flags (a common enough pattern that QML has a special-purpose class QFlagPointer for this). As a result, a QV8Bindings::Binding is only 64 bytes large.
The big advantage of QV8Bindings compared to QQmlBinding is that it compiles all bindings together, so only one v8 compiler invocation is needed. In QQmlCompiler::completeComponentBuild(), you can see that when compiling a QML file, all binding functions are concatenated together into one big JavaScript program, and stored in QQmlCompiledData (a structure that contains all kind of compiled data for each QML file). When the QML file is first instantiated, the v8 program is compiled, which happens in QV8Bindings::QV8Bindings(). The compiled program is then also stored in QQmlCompiledData and the original source is discarded. When instantiating the same QML file another time, the QML engine re-uses the QQmlCompiledData from before and does not need to compile the bindings program again. This is not the case with QQmlBinding, which need to be compiled each time a QML file is instantiated. To sum up: Since QV8Bindings packs together all bindings of the same QML file, it uses much less memory for each individual binding and can compile all bindings together in one go.
So, where does that leave us QQmlBinding, why does this class even exist? In some cases, bindings are non-shareable, for example because they use closures or eval(). In this case, each binding function requires a different context, and can therefore not be compiled together with the other bindings that share the same context. Therefore, in these special and rare cases, a binding will get its own QQmlBinding instance instead. The decision on what binding type is used happens when compiling the QML file, in QQmlCompiler::completeComponentBuild(). There, a SharedBindingTester is used to check which bindings will be part of QV8Bindings and which will become their own QQmlBinding. SharedBindingTester is visitor for the JS AST. If you look at the code, you'll see that the SharedBindingTester also tests whether a binding is safe, which is used to avoid evaluating bindings multiple times when instantiating a QML file, which is best described in the commit message for this optimization.
To keep things in the QML code simple, both QQmlBinding and QV8Bindings::Binding inherit from QQmlAbstractBinding.
QV4Bindings
If you have looked at the QML engine code a bit, you will probably have noticed the class QV4Bindings, which is also a subclass of QQmlAbstractBinding. Yet another binding type? What is this one about? Like QV8Bindings, this is a collection of bindings of a QML file. Unlike QV8Bindings, QV4Bindings stores only so-called optimized bindings, also wrongly and confusingly called compiled bindings. Some bindings can be optimized, in which case they will be part of QV4Bindings, some bindings can not, and will be part of QV8Bindings. So what is this optimization? v4 bindings are not evaluated by the v8 engine. Instead, v4 bindings are compiled to bytecode, and run through a bytecode interpreter. This bytecode compiler and interpreter can not deal with all JavaScript expressions, simply because ahead-of-time compilation of JavaScript is impossible for all cases.
But why bytecode? After all, the v8 engine compiles to machine code, isn't that faster than a bytecode interpreter? Turns out it isn't: the v8 engine has quite a bit of overhead when invoking it and when it needs to call out to the QML engine to resolve objects and properties. In addition, the v8 engine sometimes recompiles a function on the fly, with more optimizations, when it is called multiple times. All of this is too much overhead for the QML usecase, which typically are a lot of one-line binding functions. As a result of a benchmark I did for my DevDays talk I basically let the QML engine evaluate a binding a few hundred times. The binding was a simple one which the v4 compiler could deal with. To compare that to using the v8 engine, I used the environment variable QML_DISABLE_OPTIMIZER=1 to disable v4 bindings altogether.
As you can see, the v4 bytecode engine is indeed faster than v8 for this particular usecase.
Internally, v4 is a register machine. Much like a CPU, it has registers to store temporary values. Unlike a CPU, it does not load and store values from memory - instead it loads and stores values from QObject properties. Using the environment variable QML_BINDINGS_DUMP=1, let's have a look at a simple binding:
As you can see, the properties width and height are loaded into register 0 and 1, then these registers are multiplied together, and the result stored in the text property (which happens to be property number 42 in the QQuickText class). The instruction FetchAndSubscribe not only loads a property, but also subscribes to its changed signal, which is needed for automatic binding updates to work. In the above "assembler" code, you can also see another advantage: The v4 compiler resolve objects and properties at compile-time, and stores the property index in the bytecode. Thus, at runtime, no name lookup is needed, the properties can be accessed directly by index. Contrast that to the v8 engine, which calls out to QML object and context wrappers to resolve object and property names, which of course is much more overhead. The disadvantage is that the v4 engine can not deal with dynamic objects, for example those exported from C++ via setContextProperty(). A binding containing such a dynamic object will be part of QV8Bindings.
Summary of Binding Types
To sum up, there are 3 binding types, all inheriting from QQmlAbstractBinding:
QV4Bindings::Binding
QV8Bindings::Binding
QQmlBinding
v4 bindings are fastest as they use a custom bytecode engine. Both QV8Bindings and QQmlBinding use the v8 JS engine for evaluation, however QV8Bindings packs together all bindings to compile them all in one go, and QQmlBindings are compiled individually and on each QML component instantiation.
Here is a (nonsensical) example with all binding types:
Using QML_COMPILER_DUMP=1, you'll see the QML compiler uses STORE_COMPILED_BINDING two times, STORE_V8_BINDING once and STORE_BINDING once as well.
STORE_BINDING is for QQmlBinding, it is used for font.pointSize, as that binding uses eval() and can therefore not be shared.
The bindings for anchors.centerIn and text are both v4 bindings (STORE_COMPILED_BINDING instruction, QV4Bindings::Binding class).
Finally, font.wordSpacing is an ordinary QV8Bindings::Binding (STORE_V8_BINDING instruction). The v4 bytecode compiler and interpreter is smart enough to deal with the tenary operator, but the complement operator is not yet implemented, therefore the QML compiler chose to use v8 bindings instead.
The QML Profiler in Qt Creator actually shows which bindings are evaluated by v4, and which by v8: Check out the 'Type' section in the Events pane.
4 - Feb - 2013
Simon
Thanks Thomas for the informative posts. It is very useful stuff for some bindings related stuff I'm working on at the moment.
I do have to say that a lot of this optimisation stuff in QML strikes me as being massive overkill and "micro-optimisations" at best. I don't see how shaving a few bytes off here and there in the QML binding classes and then adding more complexity really makes any sense. For example, the client company's logo in their real world QML app is likely to consume way more RAM than any micro-optimisations in the QML bindings are saving. And no one thinks twice about adding a logo to their app if they need one. Sometimes C++ developers lose sight of the bigger picture when they are worrying about a few bytes all the time.
30 - Aug - 2013
Kuba
I'd presume that those optimizations are done as a result of benchmarking on real devices. What you imply is that the developers are doing all this work with no purpose - I'd better had some strong arguments to back that up, if I was implying it myself. Remember that sometimes reducing memory consumption is not about memory consumption at all, but about cache utilization. It can make things faster even if the memory savings are immaterial.
What I see a lot in QML implementation in Qt is that every optimization taken in isolation yields a small improvement, "not worth it" you might say. Yet QML, initially, was suffering from performance death by a thousand cuts. Nothing by itself was too big of a performance killer. It wasn't possible to fix it without addressing each and every of those thousand cuts individually.
Getting rid of V8 and multiple copies of the same data will be significant. I'm sure it will reduce not only the data memory footprint, but also the executable memory footprint.
4 - Feb - 2013
Milian Wolff
Simon, that statement is really a great oversimplification. If you can save a few bytes per object it doesn't sound much. But when you keep the law of large numbers in mind, then this will sum up to considerable savings. Especially on embedded hardware that might be the difference - especially if you want to use that memory for shiny graphic images.
Furthermore, making items smaller means more items can be stored in the CPU cache thus leading to immense performance benefits in many cases.
5 - Feb - 2013
Dalius
Thank you for writing this. It is really good to understand what happens behind the scene sometimes.
5 - Feb - 2013
Simon
Milian, in a general sense what you say is correct, but we are talking about this specific case of QML bindings and saving a few bytes for objects in the order maybe maximum a thousand instances, adds up to KBs, not MBs or GB.s It is tiny, just minuscule in 2013 where people are running around with smartphones in their hands which now pack GBs of RAM by default.
What I want to see is more empirical work, i.e. measurements and testing, on real applications which put into proper context just how big these perceived problems are. These is no point is optimising memory or speed when is only accounts for <1% of the application's usage.
Where are the numbers? and what is the real context?
6 - Mar - 2013
Christian Feldbacher
Hi Thomas, thanks for your post - it's a joy reading the QML Engine Internals series!
I had a similar discussion on the qt-project forums about QML binding performance, it might be a good additional information of this post for everybody interested: https://qt-project.org/forums/viewthread/22664/
Cheers, Chris
6 - Mar - 2013
Thomas McGuire
Thanks, that is a very informative link, nice to see some more details from Chris Adams there :)
8 Comments
4 - Feb - 2013
Kai Koehne
The QML Profiler in Qt Creator actually shows which bindings are evaluated by v4, and which by v8: Check out the 'Type' section in the Events pane.
4 - Feb - 2013
Simon
Thanks Thomas for the informative posts. It is very useful stuff for some bindings related stuff I'm working on at the moment.
I do have to say that a lot of this optimisation stuff in QML strikes me as being massive overkill and "micro-optimisations" at best. I don't see how shaving a few bytes off here and there in the QML binding classes and then adding more complexity really makes any sense. For example, the client company's logo in their real world QML app is likely to consume way more RAM than any micro-optimisations in the QML bindings are saving. And no one thinks twice about adding a logo to their app if they need one. Sometimes C++ developers lose sight of the bigger picture when they are worrying about a few bytes all the time.
30 - Aug - 2013
Kuba
I'd presume that those optimizations are done as a result of benchmarking on real devices. What you imply is that the developers are doing all this work with no purpose - I'd better had some strong arguments to back that up, if I was implying it myself. Remember that sometimes reducing memory consumption is not about memory consumption at all, but about cache utilization. It can make things faster even if the memory savings are immaterial.
What I see a lot in QML implementation in Qt is that every optimization taken in isolation yields a small improvement, "not worth it" you might say. Yet QML, initially, was suffering from performance death by a thousand cuts. Nothing by itself was too big of a performance killer. It wasn't possible to fix it without addressing each and every of those thousand cuts individually.
Getting rid of V8 and multiple copies of the same data will be significant. I'm sure it will reduce not only the data memory footprint, but also the executable memory footprint.
4 - Feb - 2013
Milian Wolff
Simon, that statement is really a great oversimplification. If you can save a few bytes per object it doesn't sound much. But when you keep the law of large numbers in mind, then this will sum up to considerable savings. Especially on embedded hardware that might be the difference - especially if you want to use that memory for shiny graphic images.
Furthermore, making items smaller means more items can be stored in the CPU cache thus leading to immense performance benefits in many cases.
5 - Feb - 2013
Dalius
Thank you for writing this. It is really good to understand what happens behind the scene sometimes.
5 - Feb - 2013
Simon
Milian, in a general sense what you say is correct, but we are talking about this specific case of QML bindings and saving a few bytes for objects in the order maybe maximum a thousand instances, adds up to KBs, not MBs or GB.s It is tiny, just minuscule in 2013 where people are running around with smartphones in their hands which now pack GBs of RAM by default.
What I want to see is more empirical work, i.e. measurements and testing, on real applications which put into proper context just how big these perceived problems are. These is no point is optimising memory or speed when is only accounts for <1% of the application's usage.
Where are the numbers? and what is the real context?
6 - Mar - 2013
Christian Feldbacher
Hi Thomas, thanks for your post - it's a joy reading the QML Engine Internals series!
I had a similar discussion on the qt-project forums about QML binding performance, it might be a good additional information of this post for everybody interested: https://qt-project.org/forums/viewthread/22664/
Cheers, Chris
6 - Mar - 2013
Thomas McGuire
Thanks, that is a very informative link, nice to see some more details from Chris Adams there :)