Okay. Let's continue. Up next, we have Javier Martinez, who at some point had reason to write
the GCC plug-in for something that he will tell us, I guess. And then, eventually, contribute
that this implementation upstream into GCC trunk without the plug-in infrastructure.
Please go ahead.
Thank you. That's here.
Hi, everyone. I'm really, really cool. It's a full room. My name is Javier. I'm a C++ developer
at the RW working on low latency C++. Before that, I did computer science at Cambridge
and electrical engineering and nothing else. So, I'm into like low-level performance
kind of things. Also, compilers. There is someone here. I've spent most of my compilers
hacking time on no camel, not C or GCC or anything like that. But I do have the
tiniest of contributions to GCC, which was part of my internship with RW, which is the
topic of today. So, kind of the whole thesis behind this is that most code is called in
an application. So, if you see this code, there is, you know, a testing at some point
there is zero. If it is, it looks like it's going to turn exception otherwise, it's fine
returns. And, you know, to the compiler, heuristics, this is, you know, the exception
through in path is, is clearly a very cold code kind of case. You know, it's an early return
from a function, it's checking in and zero. It's returning an extra, it's throwing an exception
if it's all of the cases. So, I guess, if you, if you were the compiler, and this is kind
of funny to ask here, because a bunch of you are the compiler. But if you were the compiler
and you were to think about what you can do with, you know, that some code is called,
you can, you can reorganize your, your bunches for better prediction. At some point, with
20 and 40, you could even have some hints for the CPU, that is not the case anymore. But
you can at least make the likely case, a fall through or a closer branch than the likely
case. You can also optimize for a size. And, in my opinion, well, for my case, most importantly,
what you see here is you can try to keep the cold functions, well, you are not taking
for the linker, as you see with a clone called, and you try to keep them together. And
they are here is that, you know, all of your cold stuff is like far away, and it's not
messing with your instruction cache when you run your hot code. So, we wanted to do this,
the hint to tell the compiler that something is called is that you've called, it works
on functions. And for my case, it didn't feel like the right granularity to express the
the cold, because, well, I don't want to spray it on every single function or a thousand
functions. And at the component level, I can express the size, but I couldn't express
the cold hint. So, we thought about writing a plugin, the mental model behind the
plugin should be simple, like a pre-processor path that just, you know, you annotate a class
being called, and it is goes through a refunction and marks it as called. So, the way you write
plugins in, in GCC, is that you tell the compiler which points at compilation in your
interest zone. There's 27 such points, it actually gets multiplex into more points, because you
can specify concrete optimization passes that you want to aim for. And then when you hit
that point, the compiler just gives you a handle, and you can look at new data. So, if you
need to do this, you basically open that file or documentation, and one of these points is,
you know, after finishing parsing a type. So, you know, it seems to fit my, my use case.
And as you see, just in a couple lines, you get this pointer to GCC data, and it's a three,
everything is a three in the IR. And, you know, simple enough, you can access the, if the three
is a type, you can, like a union or a struct, or a class. You can iterate the type fields,
if the type field is a function declaration, you know, sure enough, you just add the attribute.
So, as you see, you can get something like this going in just about 30 lines of code, and it's
mostly boilerplate, which is really nice if you're new to it. And then the question is whether,
well, if you want to go from a plugin to an entry patch, it's like, how difficult is this?
Well, the good thing is that the data structure from the written phrase interfaces are all mostly
just the same. So, in my case, kind of my main problem was just finding the right point at which
to do the work that I was doing in the plugin anyways. So, you start browsing code.
I remember there was something called class, a typical class, sounds great. You look at their
header comment, thanks great. And then one of the functions says, well, this is going into
our class and we check in the members and maybe adding some implicitly defined, implicitly declared
special members. So, I thought this was the right place to add it, and surely at the very,
very out of this function, I do exactly the same kind of loop that I do before, just with a few more
safety checks. You have to think about what happens if you're marking a class called that has
function that is already marked, hot kind of thing. But yeah, that does it. It was a really,
really simple transition from the parallel into the entry patch. Sure, there's a couple of surprises.
I think for me, the main pitfall is that these says, it adds any implicitly declared functions,
in reality, there's a few lazily inserted implicitly, there are functions. There is a second
code path that has to repeat that loop. But other than that, you know, very simple straightforward,
then the whole patch is about a hundred lines of code if you remove some documentation changes and
tests. So, yeah, I didn't teach you how to write plugins, but hopefully I thought you that is kind
of a nice introduction to the topic. So, I wrote a workshop that I guess I'll place the link on
matrix later that guides you through writing your first plugin. So, it's a custom attribute,
a static analysis path that is loops of the names of functions, and some instrumentation to
basically call a login function. And this is all like packed in the exercise of writing an aspect,
oriented C++, toy language, which I think is, you know, SQL exercise. But yeah, that's it. Thank you.
Thank you.
I guess if we have any questions.
What's the code simplified on your slide where you added the code attribute or is it the original code?
No, it's definitely simplified, but you're talking about this code.
Yeah, because I was wondering whether it really makes sense to put that idea if I got forward
inside the name.
Right. So, the question was whether this code is simplified. It is simplified to some extent.
This is indeed hoisted out. It's probably a couple more cases. I mean, this does not fully
represent the exact code because I also had to check again if there was attributes already present.
And perhaps something that I found surprising about this one is that this is additive. So you don't
have to, you know, this is a list in GCC. So you don't have to look at all of the past attributes,
and then concatenate the list and then pass it. This is a word of the existing attributes.
So yeah, it's not exactly the same code. Close enough.
Other than hard and cold, what can you apply to an entire class?
We don't do this. Like this part is only for cold and hot. You could do, I could see size.
I mean, what size you can do with pragmars? You can do the always inline kind of thing that is
a common one. I guess you could start big infotivates in counterbanks. Maybe visibility.
Okay, any more questions? Thank you again.