What this book covers
Chapter 1, About Performance, discusses performance. We’ll dissect the term itself and try to find out what users actually mean when they say that a program performs (or doesn’t perform) well. Then, we will move into the area of algorithm complexity. We’ll skip all the boring mathematics and just mention the parts relevant to programming.
Chapter 2, Profiling the Code, gives you a basic idea about measuring program performance. We will look at different ways of finding the slow (non-performant) parts of the program, from pure guesswork to measuring tools of a different sophistication, homemade and commercial.
Chapter 3, Fixing the Algorithm, examines a few practical examples where changing an algorithm can speed up a program dramatically. In the first part, we’ll look at graphical user interfaces and what we can do when a simple update to TListBox
takes too long. The second part of the chapter explores the idea of caching and presents a reusable caching class with very fast implementation.
Chapter 4, Don’t Reinvent, Reuse, admits that sometimes other people will write better code than we may do and that using a good external library is preferred to any other solution. This chapter looks at the Spring4D collections library and explains when and why you should use lists, dictionaries, sets, hashmaps, or other collection types.
Chapter 5, Fine-Tuning the Code, deals with lots of small things. Sometimes, performance lies in many small details, and this chapter shows how to use them to your advantage. We’ll check the Delphi compiler settings and see which ones affect the code speed. We’ll look at the implementation details for built-in data types and method calls. Using the correct type in the right way can mean a lot. Of course, we won’t forget about the practical side. This chapter will give examples of different optimization techniques, such as extracting common expressions, using pointers to manipulate data, and implementing parts of the solution in assembler.
Chapter 6, Memory Management, is all about memory. It starts with a discussion on strings, arrays, and how their memory is managed. After that, we will move to the memory functions exposed by Delphi. We’ll see how we can use them to manage memory. Next, we’ll cover records — how to allocate them, how to initialize them, and how to create useful dynamically allocated generic records. We’ll then move into the murky waters of memory manager implementation. I’ll sketch a very rough overview of FastMM, the default memory manager in Delphi. First, I’ll explain why FastMM is excellent, and then I’ll show when and why it may slow you down. We’ll see how to analyze memory performance problems and how to switch the memory manager to a different one. In the last part, we’ll revisit the SlowCode
program and reduce the number of memory allocations it makes.
Chapter 7, Getting Started with the Parallel World, explores the topic of parallel programming. In the introduction, I’ll talk about processes, threads, multithreading, and multitasking to establish some common ground for discussion. After that, you’ll start learning what not to do when writing parallel code. I’ll explain how a user interface must be handled from background threads and what problems are caused by sharing data between threads. Then, I’ll start fixing those problems by implementing various kinds of synchronization mechanisms and interlocked operations. We’ll also deal with the biggest problem synchronization brings to code — deadlocking. As synchronization inevitably slows a program down, I’ll explain how to achieve the highest possible speed using data duplication, aggregation, and communication. Finally, I’ll introduce two third-party libraries that contain helpful parallel functions and data structures.
Chapter 8, Working with Parallel Tools, focuses on a single topic, Delphi’s TThread
class. In the introduction, I’ll explain why I believe that TThread
is still important even in this modern age. I will explore different ways in which Tthread
-based threads can be managed in your code. After that, I’ll go through the most important TThread
methods and properties and explain what they’re good for. In the second part of the chapter, I’ll extend TThread
into something more modern and easier to use. First, I’ll add a communication channel so that are able to send messages to the thread. After that, I’ll implement a derived class designed to handle one specific usage pattern and show how this approach simplifies writing parallel code to the extreme.
Chapter 9, Exploring Parallel Practices, moves the multithreaded programming to more abstract terms. In this chapter, we’ll discuss modern multithreading concepts – tasks and patterns. We’ll look into Delphi’s own implementation, the Parallel Programming Library, and demonstrate the use of TTask
/ITask
. We’ll look at topics such as task management, exception handling, and thread pooling. After that, we’ll move on to patterns and talk about all Parallel Programming Library patterns – Join, Future, and Parallel For. We will also introduce three custom patterns — Async/Await, Join/Await, and Pipeline.
Chapter 10, More Parallel Patterns, looks into another external programming library, OmniThreadLibrary, and explores its parallel programming patterns. In this chapter, we will revisit Async/Await, Join/Await, Future, and Pipeline from the OmniThreadLibrary perspective and introduce four new patterns – Parallel Task, Background Worker, Parallel Map, and Timed Task.
Chapter 11, Using External Libraries, admits that sometimes Delphi is not enough. Sometimes, a problem is too complicated to be efficiently solved by a human. Sometimes, Pascal is just lacking speed. In such cases, we can try finding an existing library that solves our problem. In most cases, it will not support Delphi directly but will provide some kind of C or C++ interface. This chapter looks into linking with C object files and describes typical problems that you’ll encounter on the way. In the second half, we’ll present a complete example of linking to a C++ library, from writing a proxy DLL to using it in Delphi.
Chapter 12, Best Practices, wraps everything up and revisits all the important topics we explored in previous chapters. At the same time, we’ll drop in some additional tips, tricks, and techniques.