Thinking Small is a two-day training course with programming examples taught by Patrice Roy. It is offered online from 09:00 to 17:00 MDT on Saturday, October 30th and and Sunday October, 31st, 2021 (immediately after the conference).
Maybe you are someone who, at least on occasion, needs to think small when coding:
- You write programs that need to fit in limited memory, or that are big to the point where available memory becomes a problem
- You care about speed and the way your code and your data fit in cache
- When your projects near their shipping deadline, you and your team are scrambling for the last few remaining bytes available
- You work in the kind of industry where, once the code’s ready to ship, more space in persistent storage or in memory means additional resources to make the product more enticing
Today, with code, small often (not always, of course) means fast. For that reason, this course, titled Thinking Small, seeks to bring its audience techniques that will help write programs that lead to smaller and faster binaries (sometimes one, sometimes the other, ideally both) using standard C++.
In order to benefit from this class, you will need:
- To be familiar with “modern” C++, the word “modern” being taken in the sense of “C++11 and later”. You don’t need to be an expert, but having used such things as lambdas and constexpr beforehand will make the class material feel less… alien
- To have a laptop with a compiler that supports C++17. We will strive to limit ourselves to portable C++ code, but we will consider C++17 to be portable since all major compilers support it today… and because there’s so much to enjoy in today’s language!
- To be willing to do in-class exercises, and to discuss tricks and techniques with your instructor and colleagues in a friendly manner. In such training sessions, part of the experience comes from meeting other interested (and interesting!) individuals, and sharing knowledge and tricks
If you come from another language than C++, make sure to inform Patrice such that he can better accompany you in your in-class experience.
The target audience is intermediate-level developers who:
- Are familiar with modern C++, meaning C++11 and more in this case, without necessarily being experts
- Work in resource-constrained application domains
- Want to get a better understanding of how standard C++ as it exists today can help you meet these constraints
Junior developers can benefit from this course if they want to develop skills appropriate to the target application domain. Developers coming to C++ from another language might find the course surprisingly useful due to the (potentially radical) differences between the object model of C++ and these other languages. More advanced developers might also enjoy this course if looking for a greater familiarity with modern C++ and its usefulness in their daily tasks. Make sure to examine the Selected Approach and Expected Contents sections below to ensure you make the right choice for your needs.
By concentrating on standard C++, this course will avoid most compiler-specific and operating system-specific techniques that one can use to achieve smaller or faster code. For that reason, if you are looking for a better knowledge of such tricks (compiler intrinsics, inline assembly, compiler options, specific system calls, etc.), this course might not be what you want. Finally, if you are working in an application domain where there are abundant resources and one can always add hardware to fix problems, you might be wondering what this course is about at all; this doesn’t mean you would not enjoy it, but keeping an open mind would be particularly important.
This course will address concurrency issues on occasion, and will use templates quite frequently. Familiarity with concurrent programming, while not necessary, will help participants benefit more from the experience, and familiarity with templates is recommended.
Since the class will involve problem-solving exercises, participants must bring their laptops (or equivalent development tool) and at least one recent C++ compiler of their choice; compilers that support C++ 17 are obviously preferable given the subject matter. As mentioned previously, we will strive to constrain ourselves to standard C++ only, and will avoid non-portable or platform-specific code as much as possible.
Note that, since there is a variety of target compilers for the target application domains, and that not all of them support all modern C++ features one could hope for, we will sometimes cover techniques to work around these missing features or emulate them.
The format for this course will be a combination of lecture-style presentation of features and tricks and exercise solving. We will typically start with a concrete problem to solve, and a minimal objective to achieve, and work towards reaching that objective for some short time. A presentation of potential solutions will follow, accompanied by a discussion where participants’ input is encouraged.
Topics covered in this course include:
- How we will measure execution time
- brief overview of lambdas, variadics, move semantics and perfect forwarding
- Brief overview of CPU caches and their impact on program speed
- false sharing, cost of concurrent read and write memory accesses, impact of unpredictable memory accesses, relation to size of objects, relation to memory layout, etc.
- what the standard library provides to help one portably benefit from cache size, particularly since C++17
- Object size and layout basics:
- sizeof, alignof, alignas
- composite objects
- we will look at both what is guaranteed by the standard and what is not (sometimes, we take things done by a specific compiler vendor as standard even if it is not)
- Simple but sometimes dirty tricks to reduce object size: member variable ordering, strong enumerations, bitfields (with all the problems they bring), unions
- Impact (or lack thereof) of generic programming on program size, and how to reduce such costs.
- Low-level memory management:
- placement new
- writing arenas
- allocators (and how the rules have changed between versions of the language)
- stack allocation
- rules for object lifetime and avoiding undefined behavior when playing tricks with it
- The small object optimization:
- what it is, how it is useful, and how it can be implemented
- concrete examples (string, function, writing your own compact delegate)
- Some (potentially) compact standard containers and utilities, including bitset and the useful-but-unfortunately-named vector<bool>, as well as recent utilities such as optional and variant.
- Other tricks to make things small and fast: interruptible tasks, turning arrays-of-structs into structs-of-arrays, when to use reinterpret_cast, when to use constexpr, etc.
Patrice Roy has been playing with C++, either professionally, for pleasure or (most of the time) both for over 20 years. After a few years doing R&D and working on military flight simulators, he moved on to academics and has been teaching computer science since 1998. Since 2005, he’s been involved more specifically in helping graduate students and professionals from the fields of real-time systems and game programming develop the skills they need to face today’s challenges.
He’s been a participating member in the ISO C++ Standards Committee since late 2014 and has been involved with the ISO Programming Language Vulnerabilities since late 2015. He has five kids, and his wife ensures their house is home to a continuously changing numbers of cats, dogs and other animals.