Posts

Showing posts with the label Optimization

Excessive Collection Locking

As soon as you step into writing multithreaded code, you will need to work with collections in a thread-safe manner. While Delphi provides some basic thread-safe collections for its own use in the RTL and visual frameworks, those are usually not enough. So you will either end up using some third-party thread-safe collection library, or you will be insipired to roll out your own. Making thread-safe collections is not a very complicated task, but if you are not careful, you can easily end up using locking patterns which will look fine at first glance, but can cause excessive locking when used. You will get thread safety, but running at a snail's pace. Considering that modern computers are powerful enough, such code can still run at an acceptable speed, and you might not even notice that you are burning CPU cycles in vain. Thread-safe Collection To implement any thread-safe collection, you will need a lock. While there are many different lock types we can use based on particular n...

Are generics slow?

Image
In the TCoffeeAndCode session about "Code Profiling, Optimization, Performance, and Memory Leaks", it has been mentioned that generics are slow. However, no specific details were given, and this topic deserves to be explained in more detail before people start indiscriminately removing generics from their codebases, hoping to gain some speed. You can watch the session replay at: https://www.youtube.com/watch?v=hCFZv0I9TUk (minute 56) How generics work In order to understand how generics can impact speed, we need to know how generics work under the hood and why they are useful. The simplest way to explain generics is to imagine you have some particular code you need to run on different types. And to achieve that, you copy-paste the code and replace one type with another and nothing else. This is how generics work in C++, where they are not called generics, but templates. Instead of you having to copy-paste code and replace types, the compiler does that for you. Generic c...

Optimizing ARC - weakness of [weak]

In Delphi, the [weak] attribute is used to break strong reference cycles between reference counted object instances. It can be used with the ARC compiler on both object and interface references, and with the classic compiler for interface references. Weak interface references were introduced in Delphi 10.1 Berlin. Now, there is a teeny-weeny problem with the [weak] attribute. It denotes a zeroing weak reference that will be zeroed (niled) when the object it points to is no longer valid. In order to do that, the compiler has to track such objects at runtime and that introduces some overhead. If you are tracking many such references, that can introduce a significant performance loss. Not all weak references that serve the purpose of breaking reference cycles need to be zeroed out. If you can guarantee that a [weak] reference will never outlive the object it points to, all that tracking and zeroing is useless. To avoid a performance penalty in such cases, you can use the [unsafe] ...

Optimizing ARC the hard way

One of the potentially unnecessary ARC triggers is passing a reference counted entity as a parameter. Depending on the parameter's declaration, the compiler might insert transient reference counting code in the prologue and epilogue of the called procedure (function, method). Parameters passed with the default (value) semantics will trigger the reference counting mechanism. On the other hand, parameters passed as references - declared as var , const , [ref] , [weak] or [unsafe] - will not trigger the reference counting mechanism while entering and exiting the procedure. There is nothing new here. Delphi COW copy-on-write strings are reference counted, and passing strings as const parameters is a commonly used optimization pattern. The same principle applies not only to strings, but also to all other reference counted entities, like dynamic arrays, variants, interface references, anonymous method references, and additionally object references on Delphi ARC compilers. Why t...

Optimizing ARC with unsafe references

Image
ARC recognizes two types of references: strong and weak . Strong references are ones that participate in the reference counting mechanism, and weak references are references that do not participate in reference counting. While there is more than one way of achieving weak references, the ones that conceptually fit into ARC memory management are zeroing weak references. Zeroing weak references are niled (set to zero) when the object instance they point to is destroyed. A combination of strong and zeroing weak references leaves no room for invalid pointers. At all times, you will be dealing with references that are either nil or point to a valid object instance. Sounds perfect, doesn't it? Well, at least in theory. In practice, just like reference counting itself adds some small amount of overhead, zeroing weak references add some more. In order to zero out weak references after the object instance they point to is destroyed, the application has to track them at runtime and tha...