CppCast - Kvasir
Episode Date: November 9, 2016Rob and Jason are joined by Odin Holmes to talk about developing for Embedded Microcontrollers with C++ and the Kvasir library. Odin Holmes has been programming bare metal embedded systems for... 15+ years and as any honest nerd admits most of that time was spent debugging his stupid mistakes. With the advent of the 100x speed up of template metaprogramming provided by C++11 his current mission began: teach the compiler to find his stupid mistakes at compile time so he has more free time for even more template metaprogramming. Odin Holmes is the author of the Kvasir.io library, a DSL which wraps bare metal special function register interactions allowing full static checking and a considerable efficiency gain over common practice. He is also active in building and refining the tools need for this task such as the brigand MPL library, a replacement candidate for boost.parameter and a better public API for boost.MSM-lite. News Compiler Explorer's embedded view A peek into the WebAssembly Browser preview WebAssembly Browser Preview Cling on Ubuntu on Windows Odin Holmes @odinthenerd Odin Holmes on GitHub Odin Holmes' Blog Links Kvasir Meeting C++ Lightning Talks - Odin Holmes - Modern special function register abstraction Brigand Embedded C++ Conference in Bochum Sponsor JetBrains
Transcript
Discussion (0)
This episode of CppCast is sponsored by JetBrains, maker of excellent C++ developer tools,
including CLion, ReSharper for C++, and AppCode.
Start your free evaluation today at jetbrains.com slash cppcast dash cpp.
And by Meeting C++, the leading European C++ event for everyone in the programming community.
Meeting C++ offers five tracks with seven sessions and two
great keynotes. This year, the conference is on the 18th and 19th of November in Berlin.
Episode 78 of CPP cast with guest Odin Holmes recorded November 3rd, 2016. In this episode, we discuss WebAssembly coming to your browsers.
Then we talk to Odin Holmes.
Odin talks to us about developing for microcontrollers in his Kvasir library. Welcome to episode 78 of CppCast, the only podcast for C++ developers by C++ developers.
I'm your host, Rob Irving, joined by my co-host, Jason Turner.
Jason, how are you doing today?
I'm doing all right, Rob. How about you?
Doing pretty good.
We're doing a little bit of time travel this week, right?
Yeah.
We'll be recording today, releasing it sometime next week and uh
because i'll be out of town and i gotta say i kind of wish we could be actually time traveling
right now because then we could skip ahead to uh november 9th or 10th when the election's over
that's about all i'm willing to say about politics i don't want to alienate anyone but uh i'm looking
forward to it being over i i will i i will say that i have
not met a single person who is excited about this election yeah so i think everyone's ready for it
to be over yeah pretty much okay well at the top very episode i'd like to read a piece of feedback
uh we got one here today from iran who writes in from israel it says been listening to various
programming related podcasts for a while but yours is just unbelievably spot on my interest from Iran who writes in from Israel. It says, I've been listening to various programming-related podcasts
for a while, but yours is just unbelievably spot-on my interest.
Keep on with the great work. To contribute my share,
I'd like to suggest a topic, Dynamic Binary Instrumentation
and Optimization. The most prominent tool
I'm aware of is Intel PIN, which provides an API
that allows monitoring various types of commands at runtime
as well as modifying the program in memory.
This provides a relatively short path in profiling executables
and optimizing them accordingly without access to the source code.
PIN isn't alone in this field, of course.
Some compilers offer PGO, FileGrind, or use similar techniques,
but it's unique in being a platform for tool development.
I believe the ability to dynamically interact with an executable can be mind-opening
and writing dedicated tools can provide new insights
into what your programs are really doing at runtime.
While this is not a C++-specific topic,
it may suit your audience.
So that's definitely not something I'm familiar with,
Intel PIM, but I know Intel puts out
a bunch of really interesting tools for programmers.
Yeah, I've never heard about that at all.
But it definitely might be a topic we could cover on the show.
We'll have to see if we can look into that a little bit more.
We had someone else from Intel on, right?
Talking about hardening of executables?
Yes.
Yes, we did have someone from Intel on a while ago.
But yeah, Euron, thank you for the suggestion.
It's definitely something that could be interesting.
We'd love to hear your thoughts about the show
as well. You can always reach out to us on
Facebook, Twitter, or email us
at feedback.cvpcast.com.
And don't forget to leave us a review on iTunes.
Joining us today is
Odin Holmes. Odin has been
programming bare metal embedded systems
for 15 plus years, and as any
honest nerd admits, most of that time was spent
debugging his stupid mistakes.
With the advent of the 100x speedup
of template metaprogramming provided by
C++11, his current mission began
teach the compiler to find his stupid mistakes
at compile time, so he has more free
time for even more template metaprogramming.
Odin is the author of the
Kvasir.io library, a DSL
which wraps bare metal special function register interactions, allowing full static checking and a considerable efficiency gain over common practice.
He's also active in building and refining the tools needed for this task, such as the Brigand MPL library, our placement candidate for Boost Parameter, and a better public API for Boost MSM Lite.
Odin, welcome to the show.
Hi, guys.
Thanks for joining us.
Yeah, it's a pleasure.
I'm curious how you got started in embedded systems,
if you've been doing that for over 15 years now.
Oh, Assembler.
I think like pretty much anyone at that point.
Back then, you couldn't really get a c compiler even for uh most chips okay so when what did you
start programming with then i guess what was your first uh experience programming uh pick pick uh
um processors uh that was your first experience overall um yeah well, I did a little bit of like, C for dummies and C++ for dummies. And I was like, super isolated as a nerd as a kid, because I grew up like among hippies and suddenly programming like I somehow was hung up on parameters being positional.
That took me like two weeks to figure out that it wasn't like they were matching names.
They were just matching positions and types.
So like if you're super isolated, yeah.
And so I got more into electronic design.
I'm actually a half-decent electronic engineer.
And then I came back to programming, yeah, programming picks
because I needed some processing power in my electronic design.
Interesting.
I did nothing but pick assembler for years.
And then at some point, the systems I was making got
pretty complex and I got a really hard to find bug like my my ring buffer was
being corrupted and usually was being corrupted in an area that wasn't
actually being used and so it's like a super seldom bug and it took me like
three weeks to find it not a friend of mine helping me trying to find it and then you know he had this offhand comment like if you'd
used a real programming language that wouldn't have happened and yeah it kind of stuck with me
i didn't really act on it for you know another year or two and i had gotten into some you know
windows programming in c++ so i basically leapfrogged c in my whole development um went
straight from uh assembler to uh c++ uh i mean i i somehow do things the hard way a lot of the time
like my my second c++ book was uh modern c++ by andre alexandrescu which i had to read like
five times before i understood anything. I imagine.
But it kind of like my feeling for how people write programs was like I thought,
oh, I'm doing things like the normal way by making things policy-based.
Yeah, and it wasn't until three years ago that I really started being active in any kind of C++ user group stuff and noticed that, oh, I'm kind of the oddball out.
That's interesting. I think it might be the first person we've had who got started on microcontrollers oh yeah um i i mean there are a lot of people that got started on
microcontrollers but i think very few of them have switched to c++ and hence are not on your show
i mean i'd imagine actually your last guest dan sacks i imagine he probably started on
microcontrollers you know probably far before i was born but uh yeah he might be a candidate for
that title maybe i mean he probably started on machines
that were less powerful than today's microcontrollers,
but put it that way.
Almost certainly, yes.
Yeah, plenty of people on here have started on 8-bit systems, yeah.
Okay, well, Odin, we have a couple news articles to discuss,
and then we'll start talking to you more about C++ on microcontrollers, okay?
Sure.
Okay, so this first one, Jason, maybe you can talk about this, is an update on Matt
Godbolt's blog about some new features in Compiler Explorer.
Yeah, so the Compiler Explorer, he's been doing a ton of UI updates lately.
I showed some of them in my talk at CppCon, but his most recent update is that you can
now do embedded Compiler explorer views on your own
web page so if you have a code snippet and you want to show how this compiles to assembly you
can just put some javascript in your web page get an embedded view and that does seem like uh
i mean we've looked at plenty of recent blog posts that have been referencing uh gcc godbolt
so he's just making gonna make it a lot easier because people have been like embedded just
putting the links because you can embed all the code in the link, I think.
Yes.
But now you'll be able to just embed it to Vue. That's awesome.
Yeah, with, I guess, the compiler selection, whatever, that you want to demo to.
I haven't played with it enough to see how it works.
If you have multiple compilers and you want to do that embedded, it seems like it would start to get crowded quickly.
Right. Definitely a great new feature.
Okay, next up up we actually have
two articles one from windows and microsoft edge team and one from mozilla the firefox team and
they're talking about the web assembly going into a browser preview state so it's kind of hard to
believe that they've done this much work so fast that they're getting to the point where we can actually try it out in our browsers.
I think it's on the Mozilla side, they're saying it's available now,
and if you just turn on a certain flag to enable WebAssembly,
you can go ahead and run with it.
Yeah, it's astounding just how much effort this is being put into these systems,
and the performance that they're starting to get is pretty crazy.
Yeah, they do have a little graph here on the Mozilla page comparing throughput of ASM.js and WebAssembly.
And ASM.js, it's already showing pretty impressive performance, but WebAssembly is maybe about 10 or 20% faster.
Right.
Anything you wanted to mention on this one, Odin?
No, it's not really my neck of the woods,
but anything closer to native is welcome in my mind.
Yeah, absolutely.
So we had JF on here talking about this, right?
Yeah, and it's been like a year since we found him on.
That's what I was just wondering. July 9th.
And that was right after it was first announced. And this Mozilla
article is saying they're expecting the
WebAssembly to be, the design spec to be finished
and to kind of go live in March next year.
So that's a lot of work in just under two years.
Yeah.
And, you know, I just still have such a hard time wrapping my mind around the fact
that if you compile C++ to JavaScript,
it's like orders of magnitude faster than running native JavaScript.
Yeah.
Yeah, it's pretty crazy.
Okay.
This next one is actually a YouTube video
from a former guest, Dimitri Nustruk,
and it's Kling on Ubuntu on Windows,
which is pretty crazy to wrap your mind around.
Basically, Windows 10 recently added an Ubuntu subsystem?
Yes.
Yeah.
Have you played around with that at all, Jason?
I haven't, but the people that I know who have say it's pretty sweet.
It works pretty well.
Yeah, I think I have it enabled,
but I haven't actually gone and tried to mess around with it at all.
But yeah, if you're a developer on Windows,
you can now turn on Ubuntu and get the full bash shell
and everything else you would want.
And because of this, we can now get cling on Windows pretty easily. And Dimitri has this
video where he's just walking people through how to get cling set up on Windows and how to
play around with it. Yeah, I still personally haven't found a use case for cling. But I'm
always in favor of more tools on more platforms yeah absolutely okay
well uh odin let's start talking to you about microcontrollers um to start off maybe tell us
what kind of hardware you work with well a lot of stuff in my day job uh um you know spanning from 6k a ram to 256k a ram uh mostly arm cortex you know we have some legacy
stuff but every all new designs are uh arm cortex uh you know m034 because i mean they're essentially
as cheap as another microcontroller and they're as powerful as my first pc was so yeah a bit less
ram but uh you know as far as processor power so if we can dig
in just a little bit by legacy what do you refer to oh the the pics uh we actually have some
products that have been around for 12 years now um and it's actually quite interesting we come up
with a lot of uh memory management stuff to try and get new features into these old picks that
have you know maybe uh 300 bytes of ram and so yeah i mean uh you can get pretty far away from
the classic uh stack and heap model if you uh if you adapt that very much to your own uh design 300 bytes is pretty limiting yeah yeah
um yeah but i i wouldn't suggest it if you like having free time
yeah no it's i mean we have a lot of them in the field so it's kind of a curse
uh um but uh yeah it's a lot more fun to work on the new ones where we can use real C++.
So then you say ARM Cortex, which I'm not terribly familiar with the ARM family line.
What does that give you?
What's the lowest-end ARM that you use?
The lowest-end ARM is the Cortex-M0, and you can get it, you know, they start at about 48 megahertz with 6K RAM, and usually have a lot of peripherals on the board, though.
Like, they'll have a USB, you know, CAN bus, several UARTs, comparators, op amps, analog digital converters, all that stuff on one chip.
A lot of times they even have the oscillator on chip.
So for, you know, 50 cents or maybe 60 cents,
you can already get a fully functioning processor.
And maybe it's a little more than a dollar
if you want USB connectivity.
But that's like a whole system on chip, basically.
Like the RAM's on there, flash the rams on their flashes on their crystals
on there and yeah I mean there there there's not really much of a market in my eyes for anything
below cortex I mean I'm pretty sure people will come up with a lot of stuff but for for anything
that needs to connect to any modern systems, Cortex is the way to go.
So it's a 32-bit arm.
You can use GDC with it, whatever.
Yeah, it's the same Thumbtube instruction set
as the bigger arms.
I mean, some of the stuff is implemented differently.
Like, I don't know, compare and swap will fail
if there's any interrupt,
because as soon as you don't have multiple cores, it could only be an interrupt.
And so they just hardware it.
Even if that memory isn't being touched, it just says,
ah, it was touched if there was any interrupt in between.
So it is a little bit different than the big ones.
But for the most part, it's probably not a whole lot different
developing for these tiny chips than it is for the more mainstream stuff. part, it's probably not a whole lot different developing
for these tiny chips than it is for the
more mainstream stuff.
From a core standpoint,
from a RAM and other
resources standpoint, it is very different.
Okay. Do you want to
tell us a little bit about the open source
library you work on, Kvasir?
Am I pronouncing that right?
Well, I think it's probably debatable
it was it was a norse god uh we figured you know since the loki library was a norse god we we'd
name our uh and it's uh i guess if with a bit of stretch of the imagination it was the god of
innovation right kvasir so uh that's why we named it that and it was one of the only norse gods that
didn't have like special characters in the name which which would have been hard. But yeah, Kvasir is basically what grew out of that seed that a friend of mine planted in my brain that you should just use language tools to not be able to make those kinds of mistakes. And so, uh, with, uh, what we've done so far, um, is been to, uh,
abstract, you know, add a layer of abstraction around any interaction with, uh, special function
registers, which is where you're actually talking directly to the hardware, right? So, you know,
configurations of things, interrupt status flags, that kind of stuff. Because that's where a lot of the bugs come from.
I mean, first of all, you have to market volatile and nobody understands volatile very well, including like even compiler implementers.
I mean, going back to Matt Godbolt's awesome tool, if you play around with the volatile keyword, I'm sure you'll find some stuff that it's doing wrong
in even modern GCC.
So if it's something that's iffy,
then it's a good idea to wrap it, right?
Because then you have one place to adapt
to compilers doing weird stuff.
The problem is that volatile takes away
a whole lot of the compiler's ability to optimize things, especially it's a blunt tool. but allow reordering in another place, like in one use of the variable in one context
and in another context you want to do it differently,
you mark that variable volatile,
and so it won't be reordered.
And reordering on these tiny chips
actually adds a lot more performance than you would think
because addresses are 32-bit,
but instructions are 16.
So to actually add,
to actually load a full address takes like three instructions.
But you do also have a load with offset.
So if you can reorder things to where they're next to each other,
as far as an address space,
then you can save a lot of loads,
a lot of address loading.
Interesting.
So, yeah, you know, I don't want to get too deep into the weeds.
I know this is, you know, outside the domain of probably most of the listeners.
But what we did was to make constexpr global variables, which are basically just empty structs. But we put all the knowledge that we have about this bit field that this global variable is representing,
we put all of that into the template parameters.
And so you can pass these things in sort of a C-like syntax to functions that are also templated,
and they can work on this template information
and then pass whatever result they have back.
And so you can do like a big, lazy, evaluated chain of stuff.
And then at the end of the chain, you can do optimizations at compile time using template
metaprogramming and then generate the most efficient, most safe code you could.
And then you can, you know, like you can't write to a read-only bit fields
or read-only bits.
You can make other rules like, you know,
you have, for example, some bits that get cleared
when you read the register.
So you can force the user to write read and clear
rather than read because you have this information.
You can get this information from the same source as the debugger gets its information,
ARM standardized like hardware description files, which we put through a Python script
and generate these global variables with all this information in there.
So yeah, essentially we've taken a whole category of potential errors that the user
can make out of, I mean, it won't compile, right?
It's not something you'd see at runtime.
It'll happen at compile time and you won't ship it.
And the odd side effect that we found, which we didn't actually initially expect, is that we can do much better optimizations than somebody writing C can.
I mean, they could, theoretically, but no one could be able to read the code, and so they don't, right? is that we can do much better optimizations than somebody writing C can.
I mean, they could, theoretically, but no one could be able to read the code, and so they don't, right?
Plus, if, you know, if me and my team of super nerds that look at this stuff all day come up with some stuff,
then we can put it in there and it benefits everybody,
even if you don't know how, you know, the special functions of this particular chip work, right. It's, you know, encapsulated expertise. So, uh, yeah, we've
been porting some, uh, libraries from chip vendors or from, uh, arms embed to use our stuff.
And sometimes like the flash footprint shrinks almost an order of magnitude. Wow.
Yeah.
I mean, one of the things that is probably the biggest, biggest bang for your buck is initialization.
Because actually with these chips, a lot of the code is initialization.
You can set up the hardware to work the way it's supposed to.
And after that, you're just pushing data around.
Right. and after that you're just pushing data around, right? So a lot of the modules are organized in a way that they have like power clock register
is common for all the modules.
And you'd be touching that in the initialization
of every module, just changing one or two bits, right?
But we can take lazy evaluation to extreme
and just save the initialization in a compile time readable format and then do initialization all at once, doing optimizations across all of this information.
So we can take, you know, GPIO, pin multiplexing, power clock registers, stuff like that, and sort it to where it's all next to each
other and then merge it together into one operation rather than a bunch of them.
So from the programmer's perspective, they're writing like, I don't know,
10 or 15 statements saying, I need to set up all these different hardware flags.
And you say, that's great. I'll merge that into basically two writes to two different
registers and be done with it. Yeah, yeah.
Where they're usually doing like load address, read, modify, write, because they don't want to affect the other bits that are in the register.
They just want to affect their little bit field.
And so, you know, once we can prove that we're touching all the bit fields, then we can just
write rather than read, modify, write.
And we don't have to load the
address 16 times, we just have to load it once, right? So the first one costs about the same as
it usually would, and all the rest are free, right? Okay. Plus, we're also benefiting from
load with offset more often, because we sorted things by address, right? And actually, that sorting was what got me into my work with the
Bridge End Library, because I had originally written my own replacement for BoostMPL,
because BoostMPL is just super slow, right? They're using linked lists rather than
battery-addict templates. They're using a lot of macro stuff that was built to squeeze every last drop out of a compiler that was made five, ten years ago.
So, yeah, I made my own replacement for that.
And then I found that BridgeEnd was actually faster at some stuff and way more famous than me, obviously.
So I decided, why don't I backport everything I know into that?
And, you know, we can collaborate because I hate it when like, there's 50 different projects,
because there's 50 different people interested in the field, right? Why don't they all work together?
So yeah, that when I joined BridgeAnd, we could sort maybe, you know, 100 things. And now it's
like several thousand in less time. So yeah, we did a lot of work there.
You're saying and sorting at compile time, right?
At compile time.
Yeah.
Like a list of a thousand types you can sort, you know, in a fraction of a second.
It's it's it's I mean, some things literally are three orders of magnitude faster than they were on a five-year-old desktop with a five-year-old library and a five-year-old compiler, right?
I mean, okay, maybe if you're comparing today's compiler compiling that old code, it might not be three orders of magnitude.
But yeah, I don't think people realize how much faster template metaprogramming has gotten just over the last two years.
So can you maybe give us a taste of how you're able to speed up the template metaprogramming
that much?
Sure, sure.
Well, variadic templates are, in most algorithms, on order of magnitude in and of themselves,
right?
We don't have to do linked lists of types.
We can have a vector equivalent of types, right?
Right.
And then on top of that,
we can also do what's called fast tracking,
where if we're iterating through a list of types,
rather than taking one off, doing something with it, and then
taking the next off, taking the next off. I mean, maybe we're looking for a type at a certain index,
right? Well, the algorithm for that would be, you know, take the list, drop the first one,
you know, take it out of the list, and then count how many you took out. And then the front of the
list at that point is your index, right? That's, you know, functional programming, probably weird for non-functional programmers, but yeah, that's
how you do it. But, you know, with fast track, you could say, well, I'm going to check if the
amount that I want to take off is, you know, say more than 16. And if it is, well, I'll just take
16 off, right? So we, you know, you can build up these, you know, usually power of two fast tracks
where you're taking off a lot of types in one operation rather than one type each time.
It was, I think, originally developed by the Bridgend authors.
At least that's where it was popularized.
And it was originally to get around max instantiation depth issues, right? Because the compiler will complain if you have a template
that's got a nesting depth of more than,
depending on the compiler, something around 256, right?
Right.
So if you bite off more than one every iteration,
every nesting call,
then it's kind of like a trampoline
if there are some functional programmers listening.
But yeah, it allows you to do more instantiation depth.
But it's also way faster.
Another thing was there were some ambiguities
in the format of the boost MPL meta lambdas and that needed to be resolved using Svine,
which is actually super slow.
And so we changed the meta lambda format to where it was, you know, not contents dependent or not data dependent.
And that sped it up quite a bit.
That was actually
mostly my contribution uh and very recently um we found another way uh or uh to to speed things up
because you know the the problem with uh template algorithms is you're instantiating a type for every operation that you do,
right? You know, I'm a, I'm some type and I derive from this, you know, the same type,
but without one element or something similar, right? So we're every, every step in, in, um,
the instantiation of the templates gets remembered by the compiler.
And another thing that slows it down is the way we make decisions,
at least classically, is through template specialization.
And that's pattern matching on a lot of types, right?
And so that's potentially slow. And so what I came up with is that I named the metamonad pattern, which basically uses an alias, which is a member of a templated struct.
Because with aliases, we don't actually create types, right?
It's just an alias to that type.
So we don't create a type.
Problem is we can't make decisions, right?
Because we have no alias specialization.
But if you set it up so that a constexpr function
decides which struct is next in the chain,
and that struct has a nested alias
that actually does the operation
that the constex of function is selected,
then you can write algorithms in a kind of a really weird way because you don't have like multiple parameters.
You just have one list because it's an alias and you have no specialization.
But you can get by with creating a whole lot less types.
And because of that, you can make some know, make some algorithms, uh, another
order of magnitude faster. Interesting. Have you by any chance written up an article or have any
examples on this that maybe we could share in the link notes? Well, there's my, uh, my Metaporky
blog. Um, I think I sent you the link. Uh, if you would, uh, add that the last couple of blog posts
have been around about this.
I really should have actually written more.
That's kind of a chronic problem with me.
I always have way too much to do.
The Quasi library as well is actually pretty poorly documented.
We actually use it in our contract development stuff.
And I have explained it to some people doing consulting work and there actually
are some other people using it but yeah I think you know before before it's it's
compatible with the masses we need to document it some more but internally
I've been adding a lot of people to the closet development team I think I
tweeted a couple of days ago, we're probably the only
embedded company where a hardcore template metaprogramming course is
part of onboarding. Yeah, we've been
trying to add people to the project because that's just
register abstraction. We can take this much, much further.
We can take this much, much further. We can abstract
different peripherals in flexible ways using
policy-based class design. We can
use some of the knowledge that we have about creative memory management
to speed things up and save RAM.
One of the big uh the big uh differences between our field and say classic uh you know desktop apps is that we are so ram
constrained uh yeah i mean classically people think of okay this object doesn't live forever
plus globals are evil. And on the other
hand, it's not, you know, its lifetime isn't connected to the stack. So we'll put it on the
heap, right? But if you have to prove that there is no peep fragmentation scenario where your device
will crash, then you have to add a, you know, a heap fragmentation penalty is what we call it of often,
you know, several X on top of what your, what your usual heap use would be. So if you can
connect, you know, if you can, if you can organize object lifetimes in other ways,
like with state local storage, for example,
or, you know, making them protected, mockable, but still essentially globals, right? If you make them like static members of template functions, well, I can, you know, swap out the template
function by using specialization, so it's mockable. And okay, it is a global, but not everyone can access it because you
could make private, right?
So looking at other object lifetimes in order to get rid of the heap is usually a huge RAM
savings.
And it makes you a lot more deterministic.
I mean, the value of deterministic behavior, again, is something that's very misunderstood outside of usually, you know, they don't like theoretically prove anything.
And there are usually little, you know, hardware in the loop tests, integration tests, whatever.
If it works once, then okay, yay, right?
And but if you have non-deterministic behavior, then there's probably a chance that it won't work some of the time. And so, yeah,
a lot of, a lot of our, uh, um, a lot of what, uh, um, of our intellectual property back in the
beginning of, uh, auto intern, the company I run, um, was knowing the timing requirements for,
uh, control units in cars because they're not deterministic, right? If you know that
they have a window between, I don't know, 1.6 milliseconds and two milliseconds, where they
will guarantee to answer you, and then from zero to five, you probably will get an answer,
then it's actually quite hard to figure out that you only have that small window,
it will always answer, right? and as far as i've heard from
other people like kuka robots and even modern stuff i mean the auto industry is pretty pretty uh
uh pretty old in the way they do things but you even like industrial robots have the same problem
where uh it's poorly documented and poorly known what their timing requirements are and a lot of
that comes from schedulers in the heap
because those are the only two real non-deterministic things, right?
I mean, you have in any given point in your system explicit state,
which is, okay, you know, what state am I in?
Am I initialized?
Whatever.
And you also have like implicit state.
You know, how is my heap fragmented?
What's the phase shift of my scheduler switching through different tasks? And, you know, if you put those two together, if you were to try and exhaustively test all scenarios, the exhaustive test would state, you know, not use a schedule, use some
run to completion kernel, use, uh, other memory management, not the heap, then, uh, you have,
uh, um, yeah, you have, you have many, many, many, many, uh, scenarios that suddenly cannot
happen anymore, right? Like the, you know, the, the possibility of, uh, control paths is decreased by several orders of magnitude.
And therefore, race conditions, timing dependent stuff either becomes very often or very, very seldom, both of which are good, right?
I mean, if the bug is so seldom that no one's ever going to see it, that's good.
And if it's quite often, then you're going to see it.
And so your customer won't, right?
Right. So I'm curious what lessons you think maybe regular application developers could learn
from this. I mean, it seems like doing more work at compile time is better for everyone.
Yeah. Well, I think we're kind of at an interesting state where, I mean, you know,
Alex Andreescu taught us how to do policy-based class design a long time ago.
The problem is you have to write really ugly types, right?
In, you know, in any field in C++, I think we have the ability, again, to use more policy-based class design because we can use auto or we can use concept-based polymorphism to wrap whatever ungodly type we created
in a wrapper that people can talk about, right?
And, you know, we can create factory functions that build these,
you know, obviously templated factory functions,
but the user doesn't have to know,
that build these policy-based classes.
And, you know, we can add a lot of flexibility
without it having to be runtime flexibility.
I mean, like a simple example,
if you use standard function, right?
If you give it a small function object,
it will put that on the stack, right?
It has like a small object optimization.
But I can't say how big that is, right?
I mean, usually it'd be like,
if my object is smaller than three pointers then it'll go on the stack as far as i know that's like the clang
and gcc but that might be outdated i haven't worked in that field for a while but i mean you
you could be maybe for for multi-plating reasons you don't want to use the heap right because the
heap is again you know at least in most systems just some global instance with a lock around it
right yeah and so you don't want to do that so so you maybe you have function objects that are at least in most systems, just some global instance with a lock around it, right?
Yeah.
And so you don't want to do that.
So maybe you have function objects that are the size of four pointers and want to put
them on the stack.
Well, you can't do that.
You'd have to go into the library and change how the standard library is implemented.
We could theoretically make an extra parameter that you could put into your standard functions uh that would
decide what that size is and give have it defaulted so nobody ever plays with it doesn't know that
it's there right um i mean it's it's kind of terrible that the classic examples of policy
based class design is allocators because allocators are just written in the wrong way. It kind of gives the whole idea a bad name, but that's, you know,
that was, that predates, uh, Alagazandrescu, um,
at least talking about it. Uh, but yeah,
that's one of the early policy-based class design, uh, implementations.
I'd like to interrupt the discussion for just a moment to bring you a word
from our sponsors.
ReSharper C++ makes Visual Studio a much better IDE for C++ developers.
It provides on-the-fly code analysis,
quick fixes, powerful search and navigation,
smart code completion, automated refactorings,
a wide variety of code generation options,
and a host of other features
to help increase your everyday productivity.
Code refactorings for C++ help change your code safely,
while context actions
let you switch between alternative syntax constructs and serve as shortcuts to code
generation actions. With ReSharper C++, you can instantly jump to any file, type, or type member
in solution. You can search for usages of any code and get a clear view of all found usages
with grouping and preview options. Visit jb.gg slash cppcast-rcpp
to learn more and download your free 30-day evaluation.
Bringing it back to embedded development
and C++ a little bit,
I'm curious, as someone in the industry,
what do you see as the trend?
Do you see a lot of C++ being used?
Uh, no. Um, I mean, I, I, I heard, uh, I, you know, I listened to the last, uh, um, cast with,
uh, uh, um, Dan Sachs and, you know, he was, he was saying, yeah, well, it's pretty easy to
migrate to C++. And there are a lot of, you know, myths about the, you know,
performance myths out there. And yeah, he is right to a certain extent. It is quite easy to just
use a C++ compiler and compile your C code. But those performance myths, I mean, there are
performance traps out there, right? Like if you turn on exceptions, for example,
then there's the so-called emergency buffer of usually like 40 kilobytes of RAM or something
where the exception objects go.
Like if you throw one out of memory,
that object that you're throwing has to go somewhere.
And if you're out of memory, it can't go on the heap, right?
So there's the so-called emergency buffer.
And the compilers are getting better about taking it out
if no one throws exceptions anywhere.
But as soon as you use something like standard vector,
well, it could potentially throw.
And so the compiler is usually not smart enough to say,
well, in none of your scenarios are you indexing out of range
or something like that,
right? So, I mean, if you got a chip with 6K of RAM and you need a 40K emergency buffer, well,
there's no way that's going to work, right? I mean, even if you have a chip with 64K of RAM,
well, you blew more than half your RAM just on this emergency buffer that nobody's using.
So, I mean, there are performance traps.
There are workarounds to all of them, essentially.
But, yeah, I mean, I do some consulting work, and I often come into companies where there's the embedded guys and there's the, you know, application developers.
Sorry, that was a German word.
Application developers. Sorry, that was a German word. Application developers.
And there's kind of this feeling by the application developers,
those guys should just use C++.
I've heard it can be done.
And then we can use, like, we can share code, right?
And it's not quite that easy because, okay, sharing code. Well, the application developer, even if they do, I mean, you can turn off interrupts, and then it's just undefined behavior if you ever throw one. And then you can be like really meticulous about never doing anything that would throw one. But still, if you use like a standard vector for say, can packets, right? Can packet is, you know, zero to eight data bytes payload, right?
Okay.
If I were to do a memory pool of CAN packets, then I would probably add, like, you know,
an index into that pool as in which packet I am and probably add, you know, that as sort
of intrusive linked list pointer to the next packet in a queue, say, right?
If I want a queue of canned packets.
And then I'd have another byte or maybe some bits of another byte say, okay, how many bytes are there in my canned pack?
So I'm basically adding, you know, two bytes to make it 10.
And then I can do intrus you know, the equivalent in, say, a standard deck of vectors, right, I've like doubled or maybe even tripled my RAM overhead because a vector is always three pointers, three pointers are always 32 bits, and so on and so forth.
So, yeah, I mean, there are, you can't just use standard library stuff in these really small chips.
You can use a lot of the concepts.
I mean, I'm actually doing a talk at Meeting C++ in a couple of weeks or two weeks now.
I have to finish.
Anyway, on Ranges version 3, which sadly didn't get into the standard, but that's actually something we can use
because it's just a concept essentially, right?
It has no dictated implementation,
whereas the way vector is written,
it's kind of a dictated implementation.
Yeah, so most of the standard library is out,
which means it is a different C++ than you're used
to in desktop development. At the same time, it is a powerful toolbox. So basically, what we're
trying to do with Quasir is to make a standard library or a standard framework or at least a good framework for embedded people using
the modern C++ tools. So you said a lot of the standard libraries out. I guess maybe to clarify,
or maybe my opinion would be you're saying a lot of the standard containers, but there's no reason
why you couldn't still use things like the algorithms. Is that correct uh no you you could use uh uh the algorithms yes okay um
i mean the way it's done now i mean even like okay two iterators right and they have to be
the same type so i have to have some state deciding which ones begin and end right right
uh it's still not quite as efficient as it could be but i mean mean, we may be, you know, nitpicking there, but, but we, we will be able to do that better with ranges, right? If I have, if I, if I want to model my
serial port as an output range, um, that output range object doesn't even have to have any state,
right? Uh, you know, if you write to it, then, uh, it goes into the FIFO buffer hardware register, which is not part of the object,
right?
And if I want to know if it's at end, well, I check the hardware flag.
I can't do that with iterators because, you know, first of all, which one's which, right?
Which is the begin, which is the end.
If they're the same type, you have to have at least some state.
Right.
Okay.
Okay.
Jason, do you have any other questions
today um well i am just moderately curious you said you do uh consulting work yeah have you
gotten and and you are clearly are using advanced c++ techniques yeah yeah do you ever get pushback
from the clients when you go in and be like well i'm going to show you how to use all these template
metaprogramming and you need to update your compiler to the latest gcc like do they care um yeah well i actually kind
of anticipate that i don't i don't go usually go in and teach them uh the the newest stuff
because uh i mean if they don't have a developer in-house that uh you know understands this stuff
i'm not sure that quasier's to the the point where you will never get an error.
I mean, it will be at some point, but especially other techniques that we use on the contract development and our products that we do ourselves.
As soon as they don't have somebody that understands the library, you can only hand them a finished library, like a tried and true library.
And so usually what I do is I give them probably some of the same advice that Dan Sachs would give them.
Okay, here's how you would abstract hardware registers as local variables in a class that are private and then you can do modifying functions and it's not quite
as efficient and it's not quite as uh statically checked uh but it's definitely still better than
than c right i mean even you know function overloading right i mean as a c++ programmer
you don't realize like how bad it is like Like, yeah, functional or, or, or being able
to make your own types. Right. I mean, okay. I have a packet ID. I have a protocol ID. I want
to not be able to switch them around accidentally. Right. It, you know, if I have a function that
takes six ins, then I mean, there's nothing intuitive about that. I have to read two pages
of documentation before I can give that thing data. right? But if I have a function that takes, you know, a packet ID, a protocol ID, I don't know,
a length, a XY coordinates, whatever, then I know where which parameter goes where, and I know what
to call it with, right? Without, I mean, the documentation's in the code, and because it's in the code, the compiler can actually read it, right?
I mean, we tend to overlook, like, with all the hype around Industry 4.0 and Internet of Things and all this stuff that's a Twitter account called the Internet of Shit, which is – will give you a very, very good impression of where industry is on this kind of thing, right?
I mean the need is there and the potential is there.
Like you could make things way more efficient.
You could make things way better, way nicer.
And a lot of this is in industry, like, you know,
factories. If I walk down the street into the next factory, there's probably no technology in there
that was invented after my birth. And I have some gray beard hair, right? I mean, this is, yeah.
And, but the reason is, I mean, you know, my Windows 95 crashed all the time, but then somebody came up with unit
testing and my Windows XP didn't crash that often, right? There have been advances and many, many,
many advances since, you know, the 80s when most of the embedded coding style, I mean, where it
comes from. Like if you look in current embedded code,
you'll usually see the variable before the for loop, right?
Like compilers have been able to deal with that
since before I was born.
But that's still kind of the way people code.
It's kind of the sleeping beauty syndrome
or whatever you call it, right?
And that means either the systems are built
on just this big pyramid of, you know,
guess and pray type decisions, where somebody said, Oh, well, I tested it, and it worked. Well,
are you sure it will always work? Well, I'm going to figure that out, right? Or, or you have things
like, you know, autopilot, you know, flight control software, cars, ABS systems, or whatever.
And I don't think people realize how many man hours go into really simple things.
I mean, I think, for example, Siemens is one of the biggest employers of programmers in
the world.
And oh, what do they do for software?
Well, they have 100
guys working on this thing that turns a switch on and off very, very reliably, right? And so when I
hear people talk about, you know, these Internet of Things, Internet of Industry 4.0, and the like,
either we're going to see, you know, dynamic programming language, like, you know, my light fixture will run a Java stack and probably use more energy than my light.
Um, or we're going to see things that break all the time.
Uh, or we're going to have to, you know, increase the amount of programmers that we have a hundred fold, which is obviously not going to happen. So, you know,
the only, the only other way out is to increase, you know, improve the way we write code, right?
Right.
Write things in a way that we have way more program productivity, that we have, you know,
less potential for errors. And this has happened in all the other fields, right? It's just,
it hasn't really in embedded because things
need to be super flexible to be viable in the embedded field and, you know, less than in other
fields. And we haven't really, I mean, before C++11, the stuff that we're doing now would be
super ugly. It wouldn't look like as if it were C, right? It would be full of angle brackets and stuff
and nobody would use it.
But, you know, as a C++11,
we have the potential of actually doing this.
And I mean, I'm not sure it's just C++11.
With Rust, you could do it pretty well as well.
But yeah, I mean, I think also that, you know,
the payoff, the potential payoff is huge, right?
I mean, if I look at, I don't know, from a government standpoint, right, from an environmentalist standpoint, I mentioned earlier I grew up among hippies, right?
If they want to save, you know, say X amount of energy, then they'll go insulate some government building for, you know, $6 million, right?
And then if you look, okay okay how much energy did they save well
that's kind of equivalent to the standby current of all the microwaves in bohol where i live right
uh how much would it cost to make those microwaves not use that standby current um you know probably
in parts something like 50 grand i mean the parts don't cost anything really, but the
development overhead would be much higher. You'd need smart, you need to add some amount of
intelligence to that microwave power supply. And that's prohibitively expensive because of the way
embedded systems are developed. But, you know, with that $6 million of the government spend
insulating their building, we could easily develop a library that would not only make it so that it's no longer prohibitively expensive to add intelligence to the microwave power supply but to the other several billion embedded devices. I mean, you could get, you know, many organors of magnitude more bang for your buck than things that are somehow understandable, like insulating buildings.
And, you know, from the economic standpoint, insulating the building is probably a loss, right?
Because the cost of insulation is probably more than the cost of electricity that they're saving, right? But if you were to lower the cost of developing embedded systems by orders of magnitude,
that would create a huge amount of economic growth.
I mean, I don't really understand as a whole why environmentalists, philanthropists,
or the government don't invest
money in native languages. Because, you know, if I can, if I can stop, if I can move code
to native code, just as a general way of explaining it, right? If, if there's less
servers out there that run Java stacks and rest light fixtures out there that run Java stacks, it's not really that expensive.
I mean, look at the budget of the standard committee.
It's peanuts, right?
Look at, you know, the standard library implementations.
I mean, that's like a couple of guys, right?
And, you know, because of that, there's a lot less Java on servers, right?
And people, or in the embedded field, like people say, okay, well, that's just, you know, three watts in standby.
That's not really a problem, right?
That's like three, four bucks a year on electricity.
But there's a lot of microwaves out there, and it'd be pretty easy to make that not happen, right?
Yeah.
It'd be way, way, way more
than a lot of these, you know,
government pet projects.
Yeah, where they, I mean,
pander to some, I don't know,
corn farmers or something.
And, or, you know, here in Germany, the biofuel subsidies are insane.
Whereas, you know, most, most, most environmentalists will say, well, you know, on balance, it's
probably zero sum effect on the, on the environment, because, you know, not only do they make biofuels
out of corn grown in Germany, they also make biofuels out of oil palms in, you know not only do they make biofuels out of corn grown in germany they
also make biofuels out of oil palms and you know some other country where they cut down rainforest
to plant the oil palms right but with software it's like it doesn't cost anything but man hours
in the right place right nobody wants to build infrastructure i mean nobody wants to build
infrastructure in other fields too, right? Like,
you know, telecom, telecommunications, the government has to go in and reorganize things
every decade or so, so that somebody actually updates things, right? But, but people understand
that that's important. People understand that like, I'm not going to build my road and then
you build your road, right? We cooperate on things, but not in software usually, and not in interfacing between things.
Yeah.
Did I mention I grew up among hippies?
It went off in the weeds a little bit there.
It definitely seems like, I think the answer to the question is
there aren't enough politicians who understand software at all.
Yes, yes, yes, very much.
I mean, it's not only politicians.
Like, even it's many universities.
They're, like, they have a software department,
but there's still nobody that really understands software.
I mean, there are obviously, you know, it's a mixed bag.
There are some that are very good.
But I think generally people in power don't really understand software
because most people understand software, you know,
want to be left alone, program stuff, and you'll want to be involved in some ego battles to get some
political position but yeah we're definitely off in the weeds at this point
well where can um people find you online odin and uh get more information about Kvasir? Kvasir.io
simple enough
if they want
current stuff I try and
feed Twitter
now and then
and what I do
do is try and
talk at
user groups
conferences and whatever.
That actually seems to be the
format that I like to
present stuff the best in.
Some of them are
recorded and can be found online
over the next couple of weeks.
Actually, a lot more of those recordings
will be generated. It's up to
the organizers when they actually
get onto YouTube.
If you're interested, It's up to the organizers when they actually get onto YouTube. But right.
Yeah.
Or I mean, if you're interested, I mean, I'm very approachable.
Just yell at me on Twitter or something like that.
Yeah.
OK.
OK.
Thank you so much for your time today.
Yeah, it was fun.
Thanks for joining us.
Yeah.
Thanks so much for listening in as we chat about C++++ I'd love to hear what you think of the podcast
please let me know if we're discussing the stuff you're interested in
or if you have a suggestion for a topic I'd love to hear about that too
you can email all your thoughts to feedback at cppcast.com
I'd also appreciate if you like CppCast on Facebook
and follow CppCast on Twitter
you can also follow me at Rob W. Irving and Jason
at Leftkiss on Twitter. And of course, you can find all that info and the show notes on the
podcast website at cppcast.com. Theme music for this episode is provided by podcastthemes.com.