CppCast - Runtime Compiled C++
Episode Date: May 26, 2016Rob and Jason are joined by Doug Binks from Enkisoftware to discuss Runtime Compile C++. Doug Binks is programming the game Avoyd using Runtime Compiled C++, a technique he co-developed with i...ndustry friends; and enkiTS, a lightweight task scheduler. An experienced game developer, Doug was previously Technical Lead of the Game Architecture Initiative at Intel. He has worked in the games industry in roles ranging from the R&D development manager at Crytek to head of studio at Strangelite, as well as lead programmer. An early interest in games development was sidetracked by a doctorate in Physics at Oxford University, and two post-doctoral posts as an academic researcher in experimental nonlinear pattern formation, specializing in fluid mechanics. His fondest childhood memories are of programming games in assembly on the ZX81. News Jacksonville C++ Core Language Meeting Report Micro benchmarking libraries for C++ Doctest Andrei Alexandrescu on C++ Concepts Doug Binks @dougbinks Doug Binks Github Links Runtime Compiled C++ Rapid Development with Runtime Compiled C++ Enkisoftware
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. CppCast is also sponsored by CppCon, the annual week-long
face-to-face gathering for the entire C++ community. Get your ticket now during early bird registration until July 1st.
Episode 57 of CppCast with guest Doug Binks recorded May 25th, 2016. In this episode, we talk about micro-benchmarking
and the new unit testing library.
Then we talk to Doug Binks from Enki Software.
Doug talks to us about game development
with the runtime compiled C++.
Welcome to episode 57 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?
All right, Rob. How about you?
Doing pretty good.
We have taken two weeks off the show.
That was not originally planned.
We were planning on just taking the one week off while you were at C++ now,
but then we both wound up doing some travel.
So apologies to the listeners
who may have been missing us last week.
It feels like it's been a long time.
Two weeks feels like a very long time.
Hopefully we don't mess up too much today.
Anyway, I wanted to mention one thing,
but it comes from our feedback.
I got an email from John Kolb, and he wrote in,
I want to make certain that the fact that your co-host won not one but two Best Presentation Awards at C++ Now 2016 does not go unnoticed.
Jason's presentation, Practical Performance Practices, won both the Best Tutorial Award and the Most Useful Award.
So thank you, John, friend of the show for reaching out to
us and letting me know about that. And congratulations to you, Jason. Thanks, Rob. I didn't expect that.
Pretty awesome. Yeah, very cool. So how was the conference? That's great. As always, I highly
recommend that conference. It's a beautiful location. And it's a great opportunity to get to,
you know, more one-one time with some
of the brightest people in the entire community and who's doing the keynotes this year uh it was
one keynote and it was sean parent okay great okay well 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
at cpcast.com and don't forget to leave us a review on iTunes.
Joining us today is Doug Binks.
Doug is programming the game Avoid using runtime compiled C++,
a technique he co-developed with industry friends and Enki TS,
a lightweight task scheduler.
He's an experienced game developer.
Doug was previously technical lead of the game architecture initiative at Intel.
He's worked in the games industry in roles ranging from the R&D Development Manager at Crytek to
Head of Studio at Strangelight, as well as Lead Programmer. An early interest
in games development was sidetracked by a doctorate in physics at Oxford University
and two postdoctoral posts as an academic researcher in experimental
nonlinear pattern formation, specializing in fluid mechanics.
His fondest childhood memories
are programming games and assembly on the zx81 doug welcome to the show thanks rob thanks how are
you doing great all right uh doug how old were you when you uh recall these childhood memories
of assembly language programming on your zx81 oh it's terrible I'm trying to remember exactly when I first started. I have these early memories.
I think it must be 9 or 10 or 11, something like this.
It could have been a little bit earlier because the ZX81 was around a little bit before that.
But I think we got it after it was initially launched.
Wow.
I personally didn't touch assembly until I was 16, I believe, or 17.
That seems pretty young.
But it was an accident.
My father is an engineer,
and basically he came home with a book
which he thought would be a good introduction
to programming a computer.
I mean, it was actually programming Z80 assembly language.
And he didn't really know that we had BASIC
right there on the platform to start with.
He thought basically that was it. remember this from from what i do and that that
must be what kids do these days so that's one way to do it yeah and also back in those days games
you would you would type them in from these listings that would be in in the magazines of
the day and so a lot of those were in assembly language.
So knowing a little bit about assembly language from this book,
having these listings and then being able to change them,
you know, make your health 3,000 as an early start
and then just go from there.
You know, those are the kind of things that we would do.
Wow. Awesome.
I'm also curious, how did you go into this sidetrack
of going from game development to getting your doctorate in physics? I've always been interested in physics i was good at school um and uh when it
came to doing a degree although i'm i think sort of my primary passion i think i spent most of my
time doing was was programming the issue was i i didn't really realize that programming was
something that you did as a career or you did as a subject of study.
I thought programming was just something that you did to do other things.
Like I mostly at the time did it to write games or write some simulations or various other rendering type work.
So I didn't really realize you could go and do it at university per se.
And therefore, I thought, you know, physics is something I really enjoy.
It's one of the things I'm best at at school, so I'll go and do that.
Yeah.
And then it was a little bit of an accident when I ended up doing a work with a firm that was doing programming.
And I was working with them as a programmer, and they were going to employ me after my time at university.
But it turned out they were having a bit of a financial difficulty just towards when I was finishing up my degree.
And I had been intending to do a PhD with them. They had this capability to do a PhD
in combination with the university, but I ended up getting sidetracked and going to do another
type of PhD because of their issues. Okay. Well, we had a couple news items to go through.
Feel free to comment on any of these,
and then we'll start talking about runtime compiled C++.
Cool.
Okay, so this first article is another one from the developer Red Hat blog,
Red Hat developers blog.
And this is their Jacksonville C++ trip report.
So it's good to see their perspective on things,
their take on concepts.
Jason, was there anything you wanted to call out in this article?
The syntax for constexpr if,
that they are, I believe, has been accepted now,
which is much cleaner than the first examples that I saw.
So it's pretty cool, just if constexpr,
and then you can do compile time,
if blocks. I'm really looking forward to that. Yeah, it is much better. That was the papers
that got a lot of review, but weren't quite ready at the end of the meeting section. And it looks
like there's still some movement on the dot operator overload, which still makes me a little queasy.
Yes.
Yeah.
Those are the main things I noticed.
Okay.
The next one is a nice article about different micro-benchmarking libraries.
I haven't heard of most of these before,
but the reviewer went through HiA, Solero, Nonius, and Google Benchmark and went through some of the pros and cons of each library.
So if you're looking for a micro benchmark library, this is probably a good place to start.
And some of these libraries look pretty powerful.
He called out Nonius as being one that he thinks is probably the most
powerful and it's a header only library yeah this article really stood out to me because i'm thinking
when i'm trying to test just tiny little constructs to see which one is better than another
seems like a handy thing to play with instead of running user bin time you know a hundred times in
a row and yeah yeah it's worth noticing that it's really
difficult to input any kind of performance work these days on modern computers we uh
even had that problem with ourselves at intel the the fact that they are able to scale up their
frequencies and scale down so fast can can make repeatability a real nightmare that's right
yeah that's a good point and another thing i have here is a doc test which is a new
unit testing library and they're comparing themselves to catch which is a unit testing
library we've discussed on the show before we had the the author on a while back and uh they're
basically comparing themselves against catch and saying that they think they're uh maybe a good alternative they're
a little bit faster to compile compared to catch yeah yeah but i think it's still missing a couple
features but yeah there's some i i agree i also read that they have a pretty good to-do list it
looks like yeah but it's a it's one to keep your eye on and uh if compile time is very important
to you then maybe this is better if you're not using
every single feature that Catch has to offer.
I think the game development community, like myself,
we're always very fond of having a lightweight,
fast compile alternative
because some things do more than you need.
Right, I'm sure that's true.
And the last thing I have here
is just that Andre Alexandrescu recently spoke at the ACCU conference.
He gave a keynote, and it was titled Fastware.
And when we talked to him on the show, he talked about this book he plans on writing.
It sounds like he's still working on it, but he went over some great concepts in the talk,
and it's definitely uh worth a watch yeah if you watch the video it
sounds like he's definitely still planning on writing the book yeah i didn't get the sense
that he was necessarily actively working on it yes yeah i did uh reaffirm with him on twitter
that i am still willing to review his book as he works on it, if you would like me to.
Yeah, hopefully he takes you up on that offer.
Did you have a chance to watch this video, Doug?
No, no, no, but I'll have a look.
I always enjoy his stuff.
He has great talks.
He's always entertaining us. Yeah.
Okay, so Doug, let's start talking about Runtime Compiled C++,
and maybe you can give us an overview of it and kind of what its origins are.
Yeah, so Runtime Compiled C++ is designed so that you can change your C++ code at runtime
and then have that reflected in the program that you've got.
And for us games developers, this is really important to get rapid iteration.
And it's now an open source library on GitHub. It's been there from 2012. games developers, this is really important to get rapid iteration.
It's now an open source library on GitHub. It's been there from 2012. It uses your own compiler, so it's not a
separate compile 2 chain. It's designed to minimize compile
times for these changes, and that's where most of the work has gone within it.
It was originally started as a proof of concept that came
out of myself and another developer who was working at Crytek.
And whilst we were there, one of the things that we had experienced with working with scripting languages was that there are a number of problems.
But a primary problem that we first focused on was just that debugging between different languages is always somewhat difficult,
and especially if you don't know that language.
So being able to stay in one language as much as possible was our first focus,
and then from that we went on to performance as well,
which you natively get from having a C++ code
instead of using a scripting language, for example.
So maybe we should talk a little bit about how game developers use scripting languages
and the problem they're trying to solve there.
Right. So, I mean, there's a number of problems you can solve with scripting languages.
I mean, Jason, I presume, knows this with developing JavaScript, right?
I mean, they're useful for a lot of things.
So one of the problems that you might want to solve,
which is the one that we're trying to address, is rapid iteration.
So there the problem is you basically want to be able to change your code and to be able to see the change in your code without, one, lengthy compile, and two, having to restart your program.
That's not necessarily always possible with the scripting languages, but it's something that's usually reasonably trivial to add on to a scripting language if you can add on something like serialization. And certainly you can at least kill your scripting language state
without necessarily bringing the entire system that you've got down. So that's one thing,
the rapid iteration aspect. And that's what we primarily adjust with runtime-capable C++.
There's a couple of other things in games development where you may choose to use scripting. One area that may choose to use scripting is sandboxing. And that is that you
want to be able to have something which is not going to cause a client's program to fall over
or to be able to attack a client through code which is delivered from an untrusted third party.
I would say that this is still not necessarily something
that all scripting languages offer for certain.
And I do think that there's a lot of exposure
that you get by having any kind of scripting language
within a product where you're not giving it
the same kind of scrutiny that say JavaScript has
and all of the VMs running that.
So I'm a little bit unsure as to the huge benefit of that,
but some developers do, for example, do scripting languages so that they can offer
modification possibilities to end users. And then I think the other aspect is, which is quite an
interesting one that most developers outside of games probably aren't aware of, is that
on many console platforms, it is cheaper to ship a change to a script or data than it is to ship a change to a program.
Because of the way that the various platform holders work is that if you do a change to your program code,
this typically requires a lot more investment of their testing time to ensure that everything is working well. Whereas if you change a script,
they typically believe this is a change in data
and therefore it's not such a big problem for them.
Interesting.
Yeah, I think one aspect to that
is the concern of people being able to attack the game
to, for example, break the DRM, that sort of thing.
So that's one of the issues with a change to the code.
Just one question I always had is what kind of features of a game are in the script?
So obviously, like the graphics and everything are going to be handled by the high performance
C++, but what parts of the game are typically written in Lua or something like that?
Oh, I think this is changing quite substantially these days,
but it used to be that what I would call the logic part of the game
would be that which would be done within something like Lua.
So what that means is that you would have your entity AI
might be written in C++.
And by entity AI, I mean the underlying features
that allow something to be able to respond to inputs
and be able to develop reasoning.
But then what you would do is that you would have
the logic for this tied together with Lua.
So for example, in the CryEngine,
which I'm more familiar with than most of the others,
although I've worked with Unreal
3 and 4 and Unity. But with the CryEngine, originally the Lua simply was able to construct
some of the AI feature sets that we used. Therefore, it was there almost as a data
management tool, but you could do more with it. And then from the other logic perspective,
it's the simple if, else.
If this door is closed, then do that kind of calculations
can be done through Lua quite easily and simply.
But that's expanded quite significantly in the cryoengine.
If you look now, the code has recently gone online.
A substantial amount of game code is in Lua,
more than just little bits of logic.
Interesting. Does that have an impact in the performance of the game code is in lure more than just little bits of logic. Interesting.
And does that have like an impact in the performance of the game engine?
Or is it the kind of thing that tends to be small enough it stays out of the way?
So game code is typically not the greatest of the users of the performance of the engine themselves.
Where I think it probably does have its biggest overhead, and this is the area
where we were finding a long time back that was really hitting us on the console platforms,
is the garbage collection. So even with generational garbage collection and a lot
of optimization that's been done over the years there, this can cause stalls of milliseconds,
which is not something that you can accept in a game.
And it's unnoticeable in most other platforms or programs. But in a game engine, a few milliseconds
extra on your game time, and all of a sudden you've gone over the 16 milliseconds that you've
allotted. You're normally only a few milliseconds within that. And that means that you're going to
get a 30 millisecond frame, so you're going to
double the amount of time your frame takes, essentially.
So this isn't good.
And so, yeah, that's it.
That's the kind of thing you completely avoid with
runtime-compiled C++. And that's the kind of
thing you completely avoid with runtime-compiled C++.
It's basically all C++.
There's no difference between your...
The end product that you ship is
actually the same
compiled code
as you would do if you didn't have runtime compiled C++ almost.
There's no actual change.
And that's all compiled in the standard way with standard compiler.
The only difference is that during development time,
you're able to change that code.
So in the projects that you are working on,
where do you draw the line between what you use
for runtime compiled C++ versus scripting? Do you still use scripting? I don't use scripting at all. I have considered
it for making end user code easier to play around with. But I just come back to the fact that
runtime compiled C++ for me is a lot easier. And given that I'm making runtime compile C++ myself, I ought to try and push it
as hard as I can. I personally have almost all of my code in runtime compile C++, even the engine
code. Most of the code that isn't is there's a little bit of startup code. And then there's a few
external source code aspects that I can't quite fit into Runtime Compile C++,
and so those are in non-Runtime Compile C++ code.
Okay.
Okay, so let's dig into the specifics a little bit
about how exactly Runtime Compile C++ works.
You know, you're hooked up to a debugger
and you want to make some changes.
What happens?
So if you want to make some changes, you're hooked up to a debugger and you want to make some changes, what happens? So if you want to make some changes,
you're hooked up to a debugger. You basically just save your file. Now, what happens at that point
is we pick that up because we're monitoring the files that you registered with runtime compile
C++. And you might ask, how do you register those files. Well, when you wrote your C++ files that you wanted to be runtime compiled,
you need some objects that are derived from a base runtime compiled class.
So this is one aspect that is the primary aspect that gives you this ability to use runtime compiled C++.
But there are some advanced features that don't require you to do that.
But the number one easiest approach is to do this.
So if you drive from that base class,
those files that include those classes are monitored through a macro that registers them.
And then basically we trigger a recompiler of those files with the same compiler you use,
which we can obviously detect because that's the one that you compile the code with.
And this produces a dynamic link library on Windows
or a shared object on POSIX platforms. We load that. And then with that point, we can swap
the pointers you had to your runtime compiled drive classes with these new pointers that have
been constructed from DLL. And then you just use serialization to store and restore state between the two.
We, in between, perform some tests to make sure that the new code serialization works, etc.
And then launch your next frame. Typically, this is for games development. We're doing this in a
cyclical loop, so it's not event-style programming. It's basically, you have a loop, which is running around and around and around. And at a certain point within that game loop,
you check the compile has been loaded or not. And if it has been loaded, then you
set up this restart process. So that implies to me that the interface between the runtime
compiled things and the rest of the system must be very simple
and well defined? Yes and no, depending upon whether you're going to use some of the more
advanced parts of things that we've put in over the years. So the yes part is the easiest way to
integrate your code with the rest of the system is typically through having a set of pointers to
virtual interfaces, for example. Okay.
Or to simple structures that you're not changing.
But things that you can pass through the DLL boundary or shared object boundary,
things that you can with typical linkage do easily.
Yeah.
And then you can also link libraries.
We have a system that if you have a library,
basically we can ensure that this gets linked.
And the easiest way to do that is by having a header
that includes the header file for that library.
And then you mark that with a macro that says,
this has this library.
And then you put in where the library is.
And then basically that will get linked in at compile time.
And then there's another approach whereby you can say,
these files are runtime
compiled. The problem with this approach, though, is that it's not so easy to perverse those states.
So typically we use those for cases where you have a library for something like image loading.
I don't know whether you're aware of, there's a lot of libraries from a programmer called Sean Barrett, who's nothings on Twitter.
And he produces these libraries, which are single header file libraries.
And there are great little utilities for loading images, doing text generation of images so that you can render them.
And all of these libraries can be used very easily with Untangled File C++ through that sort of system.
And you can even change them and they will work, but they're essentially data lists themselves.
Okay.
So one thing that I'm thinking, I guess there's lots of information here that's going through my head, lots of questions.
But we've got, so when you change the code and it automatically compiles it and it loads the new object and swaps around your pointers, right?
Yeah.
So how, are you able to unload the previous running code
or do you end up with a problem where if you've been doing a runtime compiled session
for a very long time that you're starting to eat away your RAM?
So I've never had the problem that I'm eating away at my RAM, but we don't unload the previous
code. I've tried it and it does work so long as you don't need the memory. And this is obviously
the issue is that you may have allocated something from one DLL and you may not have properly serialized that out to the other
one. You may have serialized that through, for example, a pointer. Right. And that means that
it's allocated in that DLL. And if you were to unload that DLL, that would be a problem.
Okay. You'd be then referencing memory that wasn't there. So, and this is because, I mean, yeah, on Windows,
especially your DLL is allocating memory through that DLL
and not through a general pool allocator.
So there are definitely things you could do
that it can't save you from yourself, basically.
No, but this is designed for development.
We do have an error recovery mechanism built in.
So on Windows, this is through the Windows exception mechanism.
This is not C++ exceptions, but SEH exceptions.
Then basically we can catch those and stop the code that's running within that particular set of code,
which you define yourself.
So basically you can decide which sections of code all go together with an update function, for example.
And then those will all stop running until you get the next compile.
And this allows you to save your code with a correction in it, for example.
And everything's caught by the debugger as well on the first iteration through.
So you make a mistake, that gets caught by the debugger.
You'll see the problem.
If you then correct the problem and save it out, your game can then recompile that and
then keep going.
Wow.
And we use signals on POSIX, which works well on Mac OS X and works well if you're using some debuggers on Linux.
But GDB has a problem with trying to always catch the exception unless you set up the
exception filters.
So I always catch the signal.
So you need to set up GDB.
It's a bit trickier, but it does work.
So that leaves the question for me then quickly.
What debuggers does it work well with on Linux
that you don't have to set up manually?
I don't use Linux that often.
Oh, okay.
That's fine.
I think, was it LLDB?
Yeah, sorry.
I'm afraid my Linux days were mostly when I was an academic.
These days I mostly program on Windows,
and Linux is for making sure that my code works on Linux
more than actually using it seriously in anger.
In anger, okay.
In fact, I'm more of a Unix knowledge
because Linux was fairly late on for me
in terms of use of the POSIX system.
Oh.
So I know you've worked at a couple of large game studios like Crytek.
Is this technique currently being used by any large game studios that you're aware of?
Yeah, it's been used by a lot.
The actual runtime compile C++ itself as a library, I'd say less so.
Although Star Citizen, which you may have heard of it,
was the largest crowdfunded game around.
Some time back, I think it may have been past $100 million worth of crowdfunding,
but it was at least $80 million the last I remember looking.
And that was using runtime-compiled C++ for a while.
I'm not sure where they still are,
because the company that I was doing some work with, basically they're no longer working with Star Citizen as they've completed
what they've done. And I haven't talked to the Star Citizen guys in some time. And I have a
suspicion they might have moved on to a product that's in this area that was launched by a friend of mine who was working at Crytek.
And after he saw our talk when we first demoed runtime compiled C++ back in around 2012,
he implemented something in the CryEngine, which was very similar.
And then later on, he went on to found a company called EnderFinds.
And he now has a plugin called Recode, which basically turns all of this into a one-click thing for Visual Studio, which is what most games developers use most of the time these days, Visual Studio, for pretty much all platforms as the IDE.
Okay, so basically runtime compiled C++, the open source library might not be used too much, but the kind of concept is used a lot.
The concept is used a lot, yeah.
I mean, Unreal Engine 4, for example,
has something they call Hot Reload.
Now, that actually reloads the entire
what they call the game DLL.
So in Unreal 4, it switched the project
into several DLLs,
most notably the engine DLL,
but also this game DLL.
And basically, you reload all of that.
So all of the code that you write, all of that gets recompiled and reloaded.
And this can take substantially longer than runtime compile C++.
You can get sub-second iteration times with runtime compile C++.
But the Unreal Engine 4 hot reload can take, you know,
minimum I got, I think, was about seven seconds on a very small project.
And then it just goes up from there.
Wow.
So, I mean, that's still good for a read compiler.
Still good for that.
I mean, if you were, that's still pretty good.
If you were using standard compiler and you did seven seconds, then got launch on top of that,
you then got to go back to where your debug state is.
All of that is going to absorb time.
But with hot reload, you can at least, you know, you see something that's a problem, you want to change it,
you want to debug it and add extra debugging features in
because, you know, you need to debug something visually.
You can do all of that with Hot Reload.
So it is pretty good.
And I think one of the most noticeable recent games
that's using the whole technique of altering game code at runtime
is ID Software's Doom.
Oh, okay.
One of the developers, the lead rendering developer on Doom now at ID Software,
Tiago Sousa, used to work at CryEngine as well.
And he's tweeted that he was using this in-define recode by Will Winston.
And they said it saved them many, many hours of development
by being able to make a change on the fly.
I personally can't shake the feeling that it makes me nervous.
Like I wouldn't trust that it had actually loaded
the new thing that I had programmed.
Right, so first of all, it's useful to put in your own code
because you've got direct access to what's going on
to put in, this is being loaded.
So you can add some logging or even, obviously, most games are visual.
You can add a UI tweak to say, you know, this is being loaded.
Right.
And the other thing you can do is, which is quite handy,
now Visual Studio is a little better at showing this than other
IDUs that I've used, but basically when you put a breakpoint in the code and you save
that code out, your breakpoint will initially show up as being unable to break out because
that code isn't in your actual game.
But then what you'll see is that as soon as the DLL gets loaded by the game,
that actual breakpoint will turn full color
and say it's now able to break at this breakpoint.
That's a neat trick is to put a breakpoint in its initialization function for the code,
and then you see that happen,
and you just check all the states we moved over correctly, et cetera.
But, yeah, no, you definitely see it.
And, of course, it's very useful to add a little bit of, you know,
printf style, oops, sorry, cout style logging.
This is the C++ cast.
And, yeah, so, you know, you can see that, okay,
that's all worked fine.
My changes actually come through.
We don't mind.
We don't mind.
Do you mind if I dig in just a little bit on the details?
Because I'm curious how you load the new DLL.
Like, do you have to compile it with a different name?
Does the operating system care?
Do you just load the same DLL
again? No, you can't load
the same DLL again. That's one of the first
tricks that was
needed, although it's probably a pretty
simple one. But we create
tiny little DLLs
actually, so it's not
similar to what you might normally think of.
Normally you think of, you have a DLL that you
define yourself, and then that gets recompiled and reloaded. But what we do in runtime compile C++
is you actually write your code. You may even just write a single XE. And then when you make a change,
we figure out what the dependencies are. And then we only compile what dependencies you need for
that particular change into a new DLL. So not all of the code within that project,
but just the code that is necessary for that change
gets linked together into a DLL or a shared object,
and then we load that.
And we basically name that whatever we want.
It's just named as a temporary file.
These are all intended for development,
so these are all temporary file names with a random name. And so the other thing is we
keep all of them loaded and it means you have undo and redo through your code history during
development, which is really useful for a number of things. That takes, by the way, milliseconds
to go through normally, depending upon how well you've written your serialization code.
But basically the thing that I really find it useful for,
if you've done a visual change that's quite subtle,
you can flick backwards and forwards between them
with Control-Z, Control-Y, Control-Z, Control-Y.
And if you've done a performance-related change,
you can actually performance profile that
and then go back and performance profile the other
and then go forwards and backwards and forwards,
performance profiling them.
And that really helps if you've got a very subtle difference
especially with games where sometimes what you don't want is for the average performance
to be better what you sometimes want is for the worst performance to be better
so that you have a more consistent and smooth experience. And that's often difficult to pinpoint unless you can really
kind of do the same loop of gameplay and then go back and do the same loop of gameplay again.
Is there any limitation to what can be hot swapped in with runtime Compile C++? I think you said that
the class you write has to have an inheritance of this special runtime Compile C++ class. Is there any limitation to what changes you can make to that class?
In runtime compile C++, the technique that I
developed, and you've mentioned that particular technique, so long as you're
writing within this file that inherits
an object, there are absolutely no
restrictions to what you can do.
You can even
create a new runtime-compile C++
file. You have to tell the system
to add this to the file system.
I haven't got an automated way to pick up new files
as yet for that.
It would be trivial to add that in, and there
was a developer who I helped set up a system for himself.
But it's very dependent upon
individual ways of writing code
as to whether they would want to pick up an entire directory, etc.
So I haven't actually got around to doing that within the core code itself.
But yeah, there's no restriction.
You can edit data members.
You can change your virtual interface.
The one thing with changing virtual interfaces
is add your new virtual functions at the end is the one that works.
Adding a virtual function in the middle has a problem with the V table now being slightly different.
Right.
But, yeah, it basically allows you to make any change to that code.
Quite interesting as well, although you need to derive from this iObject, as I mentioned earlier, not all
code needs to. So if you're
programming in a functional way
some of your code, then that code itself
doesn't need to derive from this iObject
because it's functional code.
You just need to mark it up with some macros that I provide
and then
so long as there is one iObject
which is the
unfortunately badly named i object i should have
named it something else but um that's the base object yes yes well it was originally the whole
thing was developed as a proof of concept and unfortunately we got one of our first um uh people
uh using this code in anger straight off the bat of when we actually launched the proof of concept
and we've therefore kept all of these historical legacy issues for quite some time.
But yeah, so you can write functional code.
You include in the header so long as there's an I object to pick it up,
because that's where the macro is that sort of links everything together
and allows the rest of the system code to be able to get the interface through it.
Because your main program code, the rest of your code that you might have,
needs to have an interface into this newly compiled code.
And that has to be through a virtual interface
and therefore has to be through this iObject.
But that iObject can use all of these other functional code,
can use any other kind of code that you might want to write.
And you can, with some effort, make that runtime compilable as well without deriving from my object
i want to be clear about what we're referring to with functional code if do you mean like the
standard function wrapper in c++ 11 or do you just sorry i mean no side effects as in not using data per se. Yeah. Okay. Yeah.
As in procedural without any object data.
You can use sort of fairly standard C++ code.
The difficulty there is you've got to make sure that you serialize it correctly.
And there are some gotchas with that.
So it's a lot easier if your code is more or less data-free, let's say,
or at least that your data is kept by the runtime compiled class
and then passed into and out of the code that you change.
All right, that makes sense.
Yeah.
So what sort of effort is necessary to switch over to using runtime compiled C++,
whether you're maybe just writing everything in just pure C++ already, or if you're
using a scripting language, what kind of efforts necessary there? So I think that the best initial
comparison is that the target that we aimed at with when we first developed this, which is,
let's say you wanted to do rapid iteration in C++, sorry, you want to do rapid iteration,
and you had C++ as your main body of code and your alternatives were a scripting language or this,
then basically I would say runtime C++ is a little bit easier to integrate
than integrating a scripting engine.
If you're going to use it for writing new code,
and as you would be with a scripting engine,
you would be writing new code in that scripting language.
You wouldn't necessarily be translating all of your legacy code or your older code into that. And the same with
runtime-compiled C++. It's changing the older code to use runtime-compiled C++ is a larger
job, but adding it so that you can use new code is easier, and it's fairly trivial.
Okay.
Yeah. I mean, I have to admit, there are some scripting languages that are a lot easier to use.
I had a look at ChaiScript, and that actually has got a really simple startup.
Lua, for example, can be very easy to use.
But then comes the problem of, okay, it's working,
but there's no interface to my C++ code or my engine,
and that's where runtime compiled is a little easier to write the interfaces through to
than several things because it is C++ and a lot of headers and libraries you can just
include.
Right.
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 dash rcpp to learn more and download your free 30-day evaluation.
Another question I had was, obviously, you're a game developer and you develop this tool for the game development industry,
but do you have any examples of other application developers using these sorts of techniques?
I know that outside of game development,
I think the biggest community I know that uses
or has looked into these type of techniques
are the visualization community.
So there's people doing that kind of work
who need to get this immediate feedback.
Right.
I think other than that, right now,
no, there is one other.
I don't know whether you've heard of a software library called Juice.
Yes.
Yeah, right.
So the developer Juice, I'm terrible, I forgot his name,
but he wrote an IEE based on, I believe, a clang using this approach.
Right?
Right.
Yeah.
And there's also another big project, which is with physicists,
and that's at CERN, called Cling, which is a variant of clang,
which allows for code to be written much as you would write in, say,
if you had the Python console app.
And you can write C++ code on a console, and that will be recompiled and run as you're writing it,
which is a little bit different to the runtime compile approach,
because it's designed for not iteratively making changes, but manually just banging out lines of usually fairly simple
lines of code, I think, is what the aim is for this. You might run a library function over a
set of data. That's the kind of approach that Kling has. And I'd be quite excited to see something like that approach,
but able to be interfaced to a running program.
I think that'd be quite a good approach to take.
For most of the games developers at the moment,
the problem is that as of yet,
we don't have a fully 100% Windows SDK compliant Clang platform,
although it's coming.
And I think that will allow a lot of experimentation with LLVM.
I think already a lot of the consoles have,
obviously not Microsoft,
but the other consoles have LLVM as the basis for their components these days, I believe.
So yeah, there's quite a bit of excitement in that area.
I've got one other quick question about how the process works with using runtime compiled C++.
And I'm thinking about the normal case where you've just started your application and you haven't tried to change anything at runtime.
Do you end up with a bunch of tiny DLLs being compiled at that moment and still and loaded at runtime when your application starts
for all the things that could be swapped out? No, basically, the code runs exactly as it would do
if you didn't have runtime compile. The difference being is that yes, you have these interfaces that
are, are virtual for the runtime compile code, although you can use macros to define that out
if you don't want to have them at runtime.
But yeah, no, it's just the standard X at that point.
And we have a number of macros
that allow you to basically switch out
runtime compile C++ completely,
or there's various functions you can call just to turn it off.
But no, yeah, there's no compilation except for when you make a change if you run the demo you may see it recompiling
something at the beginning and that's because there's the the demo that comes with runtime
compile c++ actually has a console that allows you to type code in and have that compiled on the fly
and when it creates the file for the console for the first time,
that empty file gets compiled.
Okay. That makes sense.
While we have you here, I was curious if you had any current thoughts
about the state of C++ in the game development industry.
We haven't had a chance to talk to an active developer
in the game development industry yet.
Yeah, I think that the current status of c++ in the games development is probably i'd say not good and i
think part of that comes back to actually what you were saying before is that there has been
insufficient interaction probably due to games developers themselves with the c++ community and
games developers and that is beginning to improve.
There's been some good talks by games developers at various C++ conferences.
And there's now an ISO C++ group.
I believe the low latency group, I believe it's called.
Right.
Which is dealing with some of the issues that we're having.
But I would say that most game developers fall into two categories,
at least those who've worked in bigger companies,
and that is those who prefer C but are using C++
because various compilers didn't support C99 or back in the day,
and the libraries for C++ are mostly C++.
Now, say, Mike Acton from Insomniac Games, I think,
is probably the number one kind of person who talks a lot about C++ and the fact that they do it because they really want C, but this is what they've got.
And then the rest of the community, which I think is the larger part, is like C++, but carefully, with no exceptions, pretty much no templates, certainly no SDL, absolutely no boost.
That's kind of, I think, where the majority of the games development community
lies at this moment.
And when I say no SDL, no boost, I think no SDL.
You can have SDL if you're right for your tools is sort of the feeling.
I would say I use SDL a reasonable amount for containers
where I really don't care about what they are.
I just want to bang them out.
Or I'm writing some open source code,
and the container to replace it would take up more lines of code
than the open source code I have, so I will just use a vector.
But, yeah, we tend not to use STL for a number of reasons.
And I think we are a little bit of odds with the ISO C++ committee, actually.
I think that that comes down to the fact that there's a lot of stuff done for templates
and library writing of the type that we really don't use.
And we would prefer a lot more focus on, I think,
like compile times, productivity.
I think language features are really, would be important.
Co-routines, introspection slash serialization.
That's one I think that bugs me a lot.
Every time I look at a new game engine
written in C++ to use, I have to learn a new serialization system. It can be really annoying
to think, okay, I've got to write an enum, but I now need to serialize this enum in a human
readable way. Oh, brilliant. Okay. X macros. There are just so many features
that C++, for simple things,
structs, that sort of thing, should just work
with serialization and inspection, but we just
don't have that capability. And then if you
use a scripting language, it's just like, well,
obviously, there you are. After all,
the script is there at runtime, mostly.
Yeah.
Standard ABI. That would be great.
That would be a really good help.
That sort of thing where I think we need a lot more work on.
Pre-processor, would love to see better than macros and templates.
Yeah. This sort of thing, I think,
when I read all of the work that is being done on these areas,
I see it often being blocked by the issues
that we as game developers are not that interested in,
by parts of C++ like templates and the STL and exceptions
that we just don't care about
and would actually rather be removed.
So that, I think, is why there is some difficulty
with games development
in C++.
It does seem like CppCon
has been a good place for game developers
to get more involved with the rest of the C++
community, so hopefully that continues.
Yeah. I mean,
my personal viewpoint, actually,
is that I think we do need to do
a hell of a lot more work in ensuring that we
work together. And I think C++ is often labeled as being the whole kitchen sink,
but I think that's one of the reasons why it really is
a fantastic programming language,
because it tries to do so many different things
that you are able in one program to be highly performant
but highly capable.
And there's very few possibilities except
C++ and C
to some extent as well to do that.
And personally, I find C++
the easier of those two options.
Okay.
Well, where can people find more information about
you and Runtime Compile C++
online?
So for Runtime Compile C++, they can
basically go to our blog at, just check I get
this right, runtimecompilec++.blogspot.whereveryourcountryis.com.co.uk, or go to the GitHub,
which is github.com runtimecompilec++ slash runtimecompilec++. An easier approach might just be to go to my GitHub,
which is github.com slash dougbinks.
And there you'll find links to all the work that I do.
Or to my company, enki-software.com.
And on the About page there,
you'll find all of the references to the open source work I do.
And there's a dev log as well that I have
where I talk about various different open source work I do. And there's a dev log as well that I have where I talk about various different
open source and gaming
related development.
Okay, great. Cool.
Well, it's been great having you on the show today, Doug.
It's been great talking to you, Rob and Jason.
Thanks.