Next, let me show you this, giving an update on incremental LTO support in GCC.
So what can we run to the top, incremental LTO is the main patches of incremental LTO is finally
abstain into GCC, so it will be in the next version, so what does that actually mean?
First, let's start with explaining the basic explanation of LTO.
Standard completion is done in parallel, we just compile individuals or sources directly into LTO
and then link them together.
The problem with it's nice, simple, fast.
The problem with that is that if we have some function in first source one, for example,
the source two doesn't know anything about the contents of the two, so we can
document and do optimizations based on that.
So that's why we do link time optimizations, which at another part,
inside the linking process, the linker calls our plugin, which does the first part,
is similar to the internal comparison, which just don't produce the instructions,
but we people use the individual representation as a form of GCC, which we then,
which then goes into the whole plugin analysis, which doesn't do the optimizations themselves,
but it makes the decisions and then partitions that will be done in the local transformations.
In this example, the function foo is propagated and the whole plugin analysis decides that
the partition one will create the instructions for the foo, and the part two will be given a copy of the foo
of the function foo, so it can be, for example, in line into something else.
This is nice, it creates faster and smaller binaries, but it's a major problem that it's slow.
For example, when I compile on my machine, the whole plugin analysis, which is single for
it, it takes for this four seconds, and the local transformation part took 200 for this
seconds on 16 threads. So this is a problem, especially if we are making some small changes,
for example, that if we wanted to change the foo, which normally we just so using make files,
and we recompile just that one file and use the previous results of the other files,
but we cannot, and it results that the compilation is faster just several seconds,
but the whole plugin analysis is a bit problematic because it can influence any part that flows.
So we cannot do just something naive based on timestamps.
So what incremental audio does is that it adds some cache for a local transformation.
So if it, so it compares the produce partitions, and if it finds partition that was already in our cache,
it just returns the payloads ourselves, and we can save time instead of doing the hard part.
This is a nice idea, but it's useless if we don't actually reproduce the two same partitions.
And if foo is always part of the foo, it's always part of the foo, it's always part of the gateway into all partitions,
and change, for example, even just one byte, we cannot at least do naive comparison between those partitions.
So the major part of the incremental audio project was figuring out where the partitions diverge and how we can avoid it.
There are two major categories, the first one, what I call global counters, which essentially,
but I give the example of the lines of code lines, which essentially counts how many lines are there before it.
So the problematic part is that if we add some new line at the start of the file, a very single line after that is the number is incremented by one.
So even if the function foo is identical, the line numbers are not.
If we propagate the numbers, for example, for warnings, errors, then we don't have the exact same partitions and we cannot, and we cannot just find it in the cache.
So specifically, line numbers are good as an example, because they are easy to understand, but problematic to solve, because these line numbers actually have meaning to the user.
So we cannot just, but in other examples, in other instances of these counters, we don't actually care about the specific numbers,
but we care just about some of their properties. So for example, whether they are unique or whether they have some specific ordering.
So we can replace that with something that has those properties, but does not depend on exact numbers that are before it.
The second category is that we often propagate information that is actually unused in the given file condition.
For example, in this case, we have function foo that we call from two places with arguments two and three.
In the position of constant propagation, realizes that the function is called just with those two arguments, and gives to the function information that it's called just with those two arguments, so that it can be better optimised with this knowledge.
But if we create foo copy that is intended to be in line, we already know, or at least we can find better, better limits what those arguments actually can be at that place that it's in line into.
So that information is actually used in that second partition where it will be in line, so we can just, we can in those cases just delete that information because we don't use it anyway.
And the most problematic part, this was the example where we have some debug function that is used in many places and takes argument as line, the line again is problematic because the function is used almost everywhere, so it's in line to almost everywhere.
So if we change just one line before some of those debug function, it's propagated into almost a very partition and it was one of the ones we proposed.
So those are categories, and now, how does it look currently in GCC-15, so those are currently my somewhat of benchmark compiling compiler.
These are all patches from from drunk that they're actually used, so those are what I use as a representative of some small change.
So I have two values for debugging for and without debugging for I originally hope that I would manage to do to obtain a patch for debugging for, but it will be probably in the next version.
Currently there is a, so how to read this graph is for example in this first example of the debugging for via compiler for the five partitions of those to 128, so we do roughly only one part of work that we would have to do our device.
So this saved time on all the time that we would otherwise spend in the local transformations.
So in future, most of the defense, debugging for debugging for and default debugging for shouldn't be there.
There I have already some patching, the jobs have some problems that we have to, they add some additional information that we didn't, later I have to delete the linker, so we have to add some linker support to remove that extra information.
I've identified most of the divergence is so probably in future versions it will be better, but I cannot predict that.
So what I do are relevant facts, the main flag that you have that you need to use is audio in the command to which points to the directory that will be used, in which the cache will be stored.
The directory must already exist and it's phylog, it has phylog, so you can use it in parallel, so you can use it in your existing built system, it doesn't matter that there are multiple gc instances that will access the cache.
And the second two flags are a bit optimizations that they will result in the faulty argumental results in identifying the binary if it is used or it is not, but to other other flags will partition partition, partition the symbols differently.
The faulty partition cache should keep symbols only more together from one partition, so it is, it's beneficial for the, for the case with debugging for, I haven't measured that much difference with faulty debugging for.
So it's good for now, but I'm sure it will be necessary in the future.
And the second parameter is a number of partition, so if you have flagged project, it might be better to increase the number of partition.
So first off, you can parallelize it better, and second, if there is one partition that has one divergence, if you split it into 26, 2056, 2056, those will be two partitions and the dimensions will be only in one of those, so there will be also less work with that.
So thank you for for attention, and are there any questions?
Okay, yes, we could produce the dot of files with a link time optimization, is it a totally different format, or is it just extra information?
It's still outfile, but it doesn't have the contents, actually, it's just contains the simple.
There is possible to contain both the input and both, both instructions, but those, those are not in fact faulty, but those, I am, I am to use the dimension anymore.
Yeah, do you think that would be in the future any possibility of this in the default when using it?
I'm, well, but definitely, you have, well, the question was for the, it will be a little bit can be default in future.
The problem is that you have to specify the very, it's the cache actually.
You could, but if you, if you use the cache from multiple projects, then it will, there's some on it, how big the cache can be, so to not waste the, the space space, and if you see it from multiple projects, you will just replace the cache from one project with another and that will not be useful.
I have a question for, with normal thing, for programs that need to patch the object files, like, when you don't use the other are some programs that they need to patch object files before they get linked.
I did, for example, it does that, and so with LTO, some people are starting to think about using linker plugin, the default linker plugin that the linker supports, to actually intercept the object result from LTO, the LTO linker plugin, before the linker actually links it.
That's the only way, right? So this new schema, would that be as if possible, or not anymore.
So the question is, but we can still intercept the results of this caching, before it's linked together, before it's found.
No, my question is, with normal LTO, there is a point in the linking process, where the linker actually has all the object files, which has been processed by the LTO plugin.
Yeah, I think I understand it, but I don't know how to explain it in a second.
So from the point of the linker, it shouldn't be any different.
Okay, so even if it's incremental at some point, the linker in one single run will get all the objects.
I mean, the linker gets the objects, gives them to our LTO vapor, and then gets back another farce.
And inside of the LTO vapor, it's implemented the cache. So from the point of the linker, it's nothing is different.
The linker is not incremental, just the LTO compilation.
Okay, which is what actually a partition is?
Very cute.
Uh, it essentially is, we want to parallelize our work, so we separate it into multiple parts, which are similar to standard compulsion,
because otherwise, we would have to do all the optimizations in single-ferred, which would be slow.
We also have that option, but I don't think it's used anymore, it was the original LTO.
It's related to the incremental LTO, it doesn't exist.
No, it exists already in the standard LTO, because we use the partition so we can parallelize over them.
I'm sorry, I'm sorry.
Uh, we all have the time.
Thank you.