Your New Mental Model of constexpr - Jason Turner - CppCon 2021
Вставка
- Опубліковано 19 гру 2024
- cppcon.org/
github.com/Cpp...
---
In my experience as a trainer, UA-camr, and speaker, I find that many people have a mistaken impression of what constexpr is and for what it is suited. I see people over-complicate constexpr by conflating it with meta programming and template-related topics. Students will often fail to recognize where and when constexpr could be used. Experts will get concerned about the "contract" you are making with the user of your library by marking functions as constexpr.
In this talk, I will present a mental model for how you should consider constexpr. I will explain what constexpr is (less mechanically and more metaphorically), give practical applications for constexpr, and help you figure out where constexpr fits into your application or library.
In the most straightforward sense, constexpr is moving work from runtime to compile-time. This mental model that I will present will ask, "what work would you rather do at compile-time?" We will find this answer by looking at constexpr as a continuum. On one end of the continuum is the use case of moving a runtime fixed-size vector into a compile-time fixed-size constexpr array, and on the far end is executing your entire program at compile-time and simply outputting the results at runtime.
---
Jason Turner
Host of C++Weekly / jasonturner-lefticus , Co-host of CppCast cppcast.com, Co-creator and maintainer of the embedded scripting language for C++, ChaiScript chaiscript.com, and author and curator of the forkable coding standards document cppbestpractice....
I'm available for contracting and onsite training.
---
Videos Filmed & Edited by Bash Films: www.BashFilms.com
UA-cam Channel Managed by Digital Medium Ltd events.digital...
*--*
In the end using constexpr (if at all applicable) or not boils down to a basic standard software engineering questions : do you trade memory for speed. I mention this because the compile time generated data tables may be bigger then the runtime code needed to generate those tables and this might be an issue on smaller systems.
Can you give me some guidance, when I can read more about this topic of memory usage of constexpr?
@@kamilziemian995 constexpr is evaluated at compile time, meaning there is NO overhead both for speed and space. However, if you need to store nontrivial value, such as a string, some collection of data, that you might need to allocate more memory than actually needed in order to evaluate at compile time.
Pep said that this kind of tradeoff might cause problems for constraint environment, since it mostly likely inflates the input data as constexpr results (but I 70% disagree), and you are not able to release (technically you should not) the memory allocated by constexpr.
That is a bit naive/too simple and general. Often not really true... Your "may" in that sentence is very very important.
Constexpr can give both speed and save memory at the same time. Preprocessing data into more compact representation is also possible. Like, let's say you inline a text file and parse it. Like, a json file often/always takes less data in a binary representation than in it's text form. Especially if you also consider that the parsing itself will likely take up memory and have the raw text in memory at the same time for some proportion of the time. Which you don't need when it is preparsed. Just as an example. Of course you can parse it into your own binary file in a separate step and load that at runtime too, but that has limits as well, and does still takes extra memory while loading.
Or very commonly, const hash strings. The hash takes less data than the string.
And in most cases I would actually claim that the constexpr takes about the same data before and after, but there are cases where it takes more and cases where it takes less. But as always, making general claims is in general not good.
They may be bigger, but OTOH the font generation and scaling code example would need quite a bit of extra memory to create all those fonts at runtime just for the algorithm to work, while the generated data will be simply sitting in the data segment waiting to be simply extracted from mapped memory thus conserving the memory required too.
Great talk. I always enjoy Jason's presentations, but I'm still waiting for constexpr Doom :-p
oh wow, didn't read the complete title before - hey, it's again jason turner
Wow, thank you very much for this presentation! I sense this is very very important for the performance limited embedded systems and their optimizations!
Glad it was helpful!
constexpr example I did:
for a given time interval, with a given clock speed, find the best fitting clock divider/top count value for the timer of an Atmel chip (Arduino) and into just 6 instructions to fill the 3 register bytes used.
Sounds like you need a python script.
I always enjoy your constexpr talks Jason. It makes me reconsider what work could reasonably be done at compile time in my work. I've been pushing to constexpr more over the last year or so. Also I got the Back to the Future joke. :)
Great to hear!
29:00 also you don't always want to have everything possible at compile time. When working on bigger projects compiles might take hours and heavy use of constexpr and templates do add to that and make debugging more annoying. Also this can effectively DOS your build server. And i these cases where there is no real time performance requirement or any other hard run time performance requirements I think it can make sense to also do things at runtime, even though they would be possible at compile time.
Also as jason mentioned: compile time computation often produces a bigger binary, because it has to store the computation results somehow (can also make the binary smaller, so this is not a rule). But if you have a storage medium limitation, you sometimes have to generate things at runtime. I think the game KKrieger is an amazing and extreme example of this.
So it is always a question of what you value most. And C++ always is about giving the user the option/power. So having the compiler decide what should be constexpr would go against one principle of C++ that make many people love the language so much.
Yesss, new Jason talk! I was looking forward to this the whole year
Thank you Jason and cppcon for this! Everytime I watch one of Jason's talk, I start with skepticism, because the headline doesn't appeal much and the beginning sounds like old news, but then I keep watching because it's cppcon, it means more than that and I know better about Jason, so I wait for the moment in his talk where I'll flip and go like "ok now we're talking", then it comes, time to share! At that point I start sending links to colleagues and friends, and we start discussing about the real deal that this talk is about, and we start deconstructing the bits and pieces of what has just been presented to us, just so we can come to the same conclusions by our own, and appreciate even more all the outcomes of it, and that's is the really cool part. Thank you Jason and everyone involved for allowing us to grow and contribute through what you share to the community, much appreciated!
Wow. You do have a great positive way of turning things. I guess if you watch a light bulb long enough you'd discover more that the light emitting! Core message of a presentation must come clear and without a need for that wow moment patiently!!
This talk was very hard to follow, but I glad that I did it.
I'm writing a toy database engine and I'm trying to do as much as I can at compile time. I've been at it off an on for more than two years, almost have a working proof of concept now, and I have very little runtime code. You can do a lot at compile time if you design for it from scratch, and the most difficult problem I've had was serializing and de-serializing (because de-serialization from storage happens at runtime by definition, yet it must produce compile-time-constant results so that further processing of the results can happen at compile time again). Had to redesign this part three times to avoid insane compiler recursion depth and code bloat.
WOOH! YEAH BABY! THAT'S WHO I'VE BEEN WAITING FOR, CONSTEXPR IS WHAT IT'S ALL ABOUT.
In my experience, an audience that doesn't have a question doesn't usually mean they're an expert in the topic at hand, but rather that they haven't understood anywhere near enough to even consider considering questions.
My favorite part of every cppcon: constexpr
I think constexpr is about dealing with static information. Static information is information that is known at compile time. If initial information, data is static we can process it as much as we want in compile time. So like presentation here, many resource is known at compile time already, we can process it as much as we want(of course there might be limitation in current C++, but it is not about fundamental limitation). On the other hand, dynamic information, which is information that is created in runtime(like user input data), can not be handled in constexpr context. Trade off might be memory space and compile time.
Jason, great presenter as always. Thanks also for your UA-cam channel!
I was experimenting with some VERY simple constexpr trials, just to see practically how a function marked constexpr might be evaluated at compile time.
Here is the very first lines I had written:
```
constexpr int summ(const int& val) {
return val + 1;
}
int main()
{
constexpr int val = 1;
auto res = summ(val);
return res;
}
```
Well, I noticed that this works fine using GCC (i.e. mov DWORD PTR [rbp-4], 2 ).
On the other hand, if using CLANG (even trunk), it does make an explicit call to summ().
EDIT: I found out that CLANG does work by changing the line "auto res = summ(val);" to "constexpr auto res = summ(val);"
Why then does GCC work even without the constexpr keyword in front of "auto res = summ(val);" ?
GCC moves it to compile time even without the constexpr keyword because it can do that as an optimization without changing the behavior of the program. Compilers may do a lot they don't need to do to speed up the runtime of programs, especially at higher optimization levels. If you write a for loop that sums up all numbers between 1-100, GCC will most likely just compute that at compile time because it can. Or if you write a function that sums all numbers between 1 to an integer parameter n using a for loop, it might just replace that with the formula n(n+1)/2.
This can be annoying, and it's the whole reason consteval keyword was added. As Jason mentioned, a constexpr function function is one that might be executed at compile time, but it's not required to.
I remember writing a font scaler in GW-BASIC on a Tandy 1000 back in the early 1990s that scaled up the CGA font in roughly the same way that Jason's approximation of hq2x ends up doing. I believe the actual hq2x algorithm, however, is more sophisticated, since it deals with color. I was only working with 1bpp CGA font bitmaps.
And the result looked pretty much identical to the smoothed font in Jason's preso. It was a fun blast from the past for me. 😀
And in case anyone wonders, I'm referring to the _original_ Tandy 1000, with no suffix letters. I had an add-in card to take it from 128K to 640K. It was like a "Super PCjr" in many ways.
This talk has inspired me to code the presentation slide! I have written an article with the title "Code Your Presentation Slides as an Executable Program" on Medium.
I both love and hate constexpr. As a game modder, I don't want any of a game evaluated at compile time and hidden from me, but as a game modder, I want as much of my own code not adding performance overhead at runtime :)
Excellent talk, Jason!
So basically I can have my game engine run during compile time. Pretty sure that would be a really bad use of this but I get the point.
Handy if I want to say generate some table, data, patterns, expression handlers, or other code that I didn't want to have to do every-time the program starts.
Fun talk, but what's the "old" mental model of constexpr then? I thought that constexpr was always about doing things at compile time.
Jason Turner is some kind of C++ superman. And constexpert.
I wonder why would I not want the compiler to constexpr everything by default? Is it for backwards compatibility to avoid having things written in an old way optimized out?
I don't think compatibility is that much of a concern. You can just emit a function and have the linker then deal with it in case it isn't used by someone. If it's static or inline and nobody tries to take a pointer to it in a given module then it doesn't even need to be emitted. Compilers are fundamentally capable and sometimes optimise out both loops (including timing ones, there are ways to deal with that though - 'volatile' or 'asm'), and function invocations.
Problem one is that trying to evaluate EVERY possible expression at compile time can be spectacularly slow, given the compilers don't all have a compiler available to them at compile time, which, i know, sounds absurd, but they often output either just an intermediate representation that ends up getting compiled by the linker - another program - or assembly, and needs to be assembled and THEN linked by an external process, what you want is specifically a JIT, and they don't generally have one at hand, so they will end up interpreting it from the slow AST. If they were to have a JIT available (LLVM, maybe DMC), then guessing whether JIT is actually faster is another difficulty.
Problem two is that this can cause an increase or loss of precise control over binary size, while C++ targets everything from ATTiny12 to an Epyc or Xeon and a lot of weird things in between. Obviously you don't get STL on an ATTiny but as far as compiler/language features, they're all there! Output of a constexpr can be of arbitrary size.
The font at 00:08 made me misread the word Mental.
1:54 summary of constexpr
7:26 "i'm'n a room full of constexperts" oh loll, nice play
9:41 [equivalent to] a macro: #define
26:17 will that talk be linked when it will be released?
Love it!
Jason running PPT on C64.
At least according to the fonts.
But content is key! 👍🏻👍🏻👍🏻
PS.: i swear, I wrote this after seeing his first „slide“
Not full powerpoint, of course :D
I found I spent too much energy trying to read the slides with that font.
such good talk, thank you Jason
Need 47:47 in HD
Does anybody have the link for the presentation he talked about at 51:28?
I was interested in that one too. I believe it's this one: ua-cam.com/video/OcyAmlTZfgg/v-deo.html
How're the slides made? I'm a fan of the text editor style.
How to say you didn't watch the presentation - without saying you didn't watch it.
23:36
This was a really fun and entertaining talk. I think compile time regular expression compilation is quite possibly *the* most clever use of constexpr I have ever seen. That being said, though, despite his compile time ARM emulator being possibly just for fun, I do have to wonder at what point are you, the programmer, treating compile-time *as* runtime, and whether or not that makes it worth it to even use constexpr in the first place if you are treating compile-time as runtime.
Once I wrote C which changed some complicated algorithm code initialisation with debug into generating the actual C for storing the data in run time tables and then simply including that in itself if it wasn't in source generation mode. I had been diff-ing output to ensure correctness so it was a small step.
This made run time far simpler using known correct results from debugged prior runs and proved actually much faster than mmap-ing the pre-calculated data from file which was slightly harder to implement, while the C gen code made it self-documenting. It was modifiable too, as if including generated code was off, then the build tables & code generation would be run instead.
An advantage was compile time was accelerated too 😊😊
I can imagine it would have caused gray hairs if managers had heard of any plan to do that, while I did it as an experiment having had the insight and had it working in one afternoon because it was so simple.
In this case it was natural evolution of the program as I developed it, like cache-ing results and freezing in the analysis that lead to algorithmic improvement. So really you could sometimes feedback runtime into compile time too, with some very interesting trade offs. 🤔🤔
To me constexpr feels like the next "auto" (local variable marker) and "register." The compilers will eventually get smart enough to figure it on their own.
Did you just replace ppt with c++ console. cool. Guess ppt is overrated. Love the font and slide transitions
I'd like to see the code for that.
we can do petscii. Ho ho I know where this is going, you're gonna say that the whole slide is constexpr, right ?
Font scaling example is cool.
46:55 this feels like memoization :)
This guy perfectly exemplifies the overzealous "clever" C++ programmer. I have a hammer so everything looks like a nail. Or in this case I have a sledge hammer and I want to hang a picture on a wall.
The only place that excessive use of constexpr to move compute to compile is on a program that gets loaded up and then discarded over and over and over. Anything you can compile can be done at program load. On a long running process do you really care if it takes a few extra seconds to start up?
Maybe it makes slightly more sense if you compile on a 128 core monster to be run on some ancient anemic hardware, but how often does that really apply.
This is "I've got a solution to a problem" virtually no one is asking for.
There are plenty of programs that get loaded and then discarded quickly, like most command-line utilities
@@n0ame1u1Yeah, but none of them need constexpr. Most of the stuff you would use constexpr for was traditionally done translating a small dsl into C or C++ and then including that code. Those DSLs were usually more readable for their scenarios than constexpr is.
He talks at normal speed if you want the video at 1.5x. 1.75x is doable although it's a little fast. Had to slow down for the Q&A though.
Far too many :
This works only for small (academical) programs,
but does not work for very, very big programs,
because:
if you don't know the type, it's very hard to make safe changes.
nice
Thanks
The podium looks like a toilet tank...
Of all the hard to read fonts that exist, this is one of the most unreadable. Comis Sans would be a world of improvement in this case honestly.