 Okay, so the next speaker here will be Mark Besby. Mark is a long time open BST developer, and he's in charge, of course, of the port system, which he rewrote and brought it to the shape that it is today. So please, Mark. Thank you. So today I'm going to talk about something apparently completely different, except it's not, because obviously it's related to building stuff, again. And well, it's quite a big challenge to talk about that, because it's work that I've been doing for a long time, something over 10 years by now. And like Martin did say yesterday, there are lots of dragons here. Very much so. Oh yeah. Who's fun is that? Is that mine? Oh yeah, quite possibly. No, it's in the other pocket. No, where is it? It's gone. Oh yeah. Yeah, that's it. It goes. Sorry about that. So I'm going to, is it still working, right? Yeah. Start with an example to give you an idea of how many dragons were in there. I hope that everybody knows at least some mech. So for instance, you've got here a fragment of a mech file which starts with a .suffix.is line, which is supposed to tell you what you're going to do when you meet .cfile, for instance. And then you get a rule, which is actually a suffix rule since you got the suffixes already defined here. And then you say that you want to generate an object file from a C file. And of course it works because you have those suffixes. Then you decide that you don't want any more suffixes. So after this line precisely, the b.o is not going to do anything because it doesn't know about the .c2.o translation. And then what's really funny about mech is that if you put that line again, what's going to happen on the .c.o file? Is it going to be generated from the C file or is it not? Three questions. Does anybody know? It's okay. It's actually going to work. Surprisingly enough, you can define some suffixes rule with some suffixes existing. Then you can wipe the suffixes, but it only says that okay, for now the suffixes don't work, but if later you instead the suffixes, then it works again. And it has to be that way. If you change that, you are going to break lots of mech files. Everything is like that, basically. So it's complete minefield. Just to say that you don't have to work in the kernel to break things. You can also very well break things in user land. So like I said, I began this 10 years ago. Right now I should say that some things are obvious, but they were not so when I started. So I'm going to start with a chunk of pieces of stuff that doesn't make any sense. And hopefully, by the end, you will be as confused as I am. To start with, while I got tricked by this guy in MTO into playing with mech, it's obviously not my code. It's crappy code, actually. It's not even Unix code. The mech we have in OpenBSD, which is basically what's also in that BSD, is coming from some experimental operating system called Sprite, which was supposed to be distributed. And you have lots of tendrils about that everywhere. It's mostly a student project. Well, fairly good student project, but still it's definitely not prediction code at the start when I started with it. What you know also is that these days, if you want to build anything on a system, you have to have some kind of mech. Like Beth says this morning, Esconcise crap and most everything else is not very good compared to mech, so you have to work with it. It's supposed to be more or less standard, but it's not very standard. Yeah, I put this line in yesterday. It's mission critical. You have to have a mech that works, a boot as well as your shell. Choose the right one. Please. My initial goal was just to make things faster. If you have to look at the specification, you're going to go crazy. It's a little less crazy than it was 10 years ago, but still it's bad. And there are some things we try a bit more specified, but more fun than not. You will see that new features are just stuff that comes from GMECH as usual. Well, basically you take anything that's on Linux these days, and they have a huge influence over POSIX, so you won't find any of our influence, and we have to fight this, obviously. We have to get people from all the BSD projects inside POSIX somehow and say, hey, we exist. Don't just copy Linux. That's completely stupid. And at the time, 10 years ago, Parallel was something which was, okay, it could be a nice feature, but it's not supposed to be working. Of course, but that time we did not have that many SMP systems, and especially not on OpenBSD. I did not have a plan. I started looking at some changes. My initial goal was just to make things faster, to put things into perspective. At the time I started, the Amiga port system just took seven seconds to start doing anything. You went to any port in the port street, and you typed make, and you waited for seven seconds, and then something happened. Usually it crashed, but it went on to one second. Yeah. How much time they are at the end? Actually, I'm cheating there, because the work I did on make is about halfway responsible for making things faster. The rest was changing the port street so that it went sane, more or less. So let's look at the internal. At first sight, you will think that make is mostly working with character strings, but actually it's not quite. More specifically, it's not the right data structure, because you've got lots of constraints inside make which looks like this, and you have to parse them, you have to read them, and you have to expand sucks on them. So if you have usual C strings, you're going to spend all your time copying stuff around, or doing what make was doing, which was even more stupid, which was to say, okay, here, I have the start of this variable. I'm going to look until the end. I'm going to change this character, this brace into a zero, so that this looks like a character string. Then I'm going to do something with this variable value. Then I'm going to put the brace back, completely crazy. Especially if you want to debug things because you can't even make a distinction between strings which are read only, and stuff that is modified all over the place, which is completely crazy. So the thing that I started with was to change that, to actually handle a string as intervals, because most of the time, you're going to have a buffer in make, and you're going to want to play with that buffer between this position and that position, and this is really the natural structure to deal with character strings inside make. There's also a shing table, which is something that I introduced fairly along, and looking at the way make did not manage memory, actually. So how bad was the code? For instance, one of the first problems I tried to solve was to look at how make was building new strings, choosing a simple, growable buffer where you add characters, and when you finish, you put a zero at the end, and you do a copy of part of the buffer that you want, and there were actually two zeros at the end of the strings. So I said, okay, let's remove one. Bam, cordump, obviously. So you look through the code, you find one bug, you fix it, and you recompile, and bam, cordump again. There are at least two bugs involved in that, and most of the code was like that. You would look at something, find something insane inside the makes code, fix it, and you realize that something else was relying on that specific behavior. If you've seen Tedu's work on OpenSSL, for instance, it will remind you of something because it's exactly the same issue, exactly the same kind of crappy code. To talk about something more fun, I actually introduced some hashing techniques inside of make to make it faster afterwards. You've got to realize how bad of a research project this was at first, because there was exactly no structure to look for variable names or for target names inside makes. 10 years ago, it was only a set of lists. So you take this normal make file, like stuff that's generated by I make, for instance, which has about 500 variables, 500 targets, and each time you want to get any value of any variable, you have to walk through that list to find it. It's going to be slow, right? I designed OpenAshing to be useful all for it make, and looking at things that managed to find seven places inside of make, which needed some actual data structure to look up names, at least. I even introduced a new one, number eight, maybe we'll talk about that if we have the time. And it's going to be widely successful, at least in OpenBSD, since it's also using M4RT sort, mandoc, and signify, as you know. How does it look? Well, it was designed specifically for make to be fast, so there's mostly no internal memory allocation, if you want to allocate stuff, you have to design it directly into your data structure. So for instance, you're not going to say, I want a new hash table, you say, you have your data structure in memory, and you're going to initialize it directly. You give it an hint of how many variables you're going to store in it, like a power of two usually. And the fourth parameter to hash in it is just to tell it how to allocate memory when it actually needs to. And then you do everything by hand. So for instance, for hashing a data structure, you're actually going to do the hashing part yourself, so you can specialize it, plug it with something else. Then you're going to look into your data structure to find the exact slots where whatever you want to do is going to end. And once you have that slot, you can say that, okay, there is something there already, so I found it. Or if it's not the right one, I have to replace it with something else. But if you didn't find something and you want to insert a new data structure, you don't have to look again, you already did. So that gains a lot actually. That's actually a lot faster to specify looking up for a given slot and then deciding whether you want to insert, whether you want to find your data structure in certain new one or remove a long one. Also, there's this point which is specific to make, which actually, if you look at how we make files, become loaded with actual variables. You've got those magic variables like dollar target, for instance, or you have those special rules like funny, like posix, that's a joke actually. And having the hash value available here means that you can actually build it directly inside your parser. You can take your target name, hash it, and you put it inside the C-switch so that you can figure out, okay, this is already a variable I know. I don't need to create a special entry for it. The next point that I did work on was memory allocation. At that point, you had lists and yeah, well, it was lists, basically. Retail and see, but still lists. Every single data structure inside of make was allocating at least two pieces of memory. You are putting things, for instance, this is a geno, it's actually the internal representation of a target inside of make. And we were allocating a new one each time, duplicating the name of a target. It was on-stored inside the same data structure. And every target had maybe 10 lists and each of those lists was just a pointer to an external data structure, right? So I spent some time working on this. I remembered that I also know some other programming languages like C++ where they have this nice notion that allocating memory and initializing a data structure are some completely different beasts and you don't have to do both at the same time. And by applying this, which was really boring work, but necessary, which was basically changing all of makes source code to just replace constructors with initialization functions. I managed to change the previous code into something that looked like this. So you have exactly one allocation, one memory allocation per target instead of 12 or so. And looking at the end result for Jeep Wroth, for instance, showed me that I managed to divide the number of memory allocation by more than 10. Which was obviously something which made things much faster, as you can guess. So we're probably something like six or seven years ago and while I had just tickled the monster and it didn't bite too hard, so I decided to dive in a little further. And at which point I had an actual image of make, which is more or less the reality, which is that you have lots of small modules which are supposed to do one thing and do one thing well. But some people have looked at those modules and decided that they wanted to add some features that means that some module is talking directly to something else and bypassing some mechanism to do something tricky which probably made sense at the time. But in the end, everything is untangled and nothing works. And I don't want to frighten you too much but that's still the case today. There are still some areas where we haven't fixed everything. And I'm 100% certain that the other projects, so NetBSD and FreeBSD these days are both using BMECH which is a descendant of the same project, have the same issues. So how to proceed? Well, you have to refactor that, as usual, going through one module, trying to understand it, trying not to disturb whatever's going on in the other modules until you can manage to grasp the intricacies and progress beyond that. To give you some actual needs, is the very simplified version of what's in Sidemake. You have variables. That's probably the senus module. It's very complicated but it's mostly self-contained. So it means that if you are going to touch variables, you're not going to break anything else, hopefully. Targets. So yeah, basically that's your initial list of targets. There are some issues in there because it has to support some mechanism which are only used by IMECH, like the double-double-colon rules, which is something completely insane but that you have to support. The parser, which was a bit insane because it was calling each module in turn to try to decide what to do with whatever line and manage more or less to tame it and make it a bit faster. Cone, which was misnamed because it actually deals with every dot BSD command. So that includes conditionals, but that also includes and for loops. So you have to break it up and try to make it center. It's not quite finished yet, but not really important. Things that should work, do work these days. Suffix is online. That one is definitely not finished yet because there are lots of callbacks all over the place from the other module, like the job engine that tries to decide when you try to build something, whether you can apply some suffix rule or not. And since you are able to look in several different places, several different directories, especially on BSD-MECH, since you have this object-gear construct, but also on other MECH, since you have some kind of VPAP mechanism, you're never quite sure what's going to happen until you actually reach the point where you actually want to build your target. Maybe you will discover that you have some new dependencies that you didn't know existed. Can be funny. Compat, the reliable old sequential engine, Job, the new parallel engine which wasn't working 10 years ago and which is still a bit clunky and there's still this problem where we actually have two engines, which is not a good idea. At some point, we want to merge those. Directory caching, yet another place to put open ashing, and trivial stuff like string construction in buffer and non-trivial stuff, but that's so mostly unused that it can break and nobody will notice. The stuff that's supposed to handle achieves directly inside MECH. More or less works, but nobody uses it anyway. What? You have to have it if you want to be posix. So this is what I said, basically. There are some baby dragons in the very small parts that I started with and once we decided you weren't burnt too badly, you can go on to fight bigger dragons and get singed, obviously. Let's talk a little bit more about variables because yeah, this is a baby dragon but it's already complicated enough because if you look at the rule for MECH, you actually have four different kinds of variables at least because what you put in the MECH file will be overridden by stuff that you pass on the command line, but you also have a switch in MECH which means that stuff on the environment will override both of them and then you have dynamic variables, stuff that is only defined within the context of one rule like dollar target for instance and which can be tricky to do because suffixes might happen much later than you would like and in some cases you have to revaluate your lines to be sure you get the right values for a variable. Obviously this initially meant that things went very slow because you had to look up variables at least those four places to be sure you had the right value so I managed to make it down to at least at most two lookups. There's one global list and one list per target and usually when you find things in the global list that should be in the local list you're very unhappy about it and that's a bug, like for instance if you find a definition of your target of the dot target variable in the MECH file it's not a good idea, it should be automatic. Plus laziness which is again a good and a bad idea because you have the laziness explained in the POSIX rules and then you have the BSD extensions which means that some stuff are expanded early and some stuff is expanded light and can be completely crazy but it's not really a problem inside MECH it's more of a problem when you want to use it if you have to maintain any part of a BSD MECH file just run away, just don't do it. It's crazy. Like I said, variable expansion is complicated. I found a bug a few months ago which is related to dynamic variables. There are some features that we didn't have that I managed to add thanks to my work on variables recursive variables which means basically a variable which contains another variable as part of its name so that you can specialize stuff for instance for a given architecture. C flags depending on the given file it's very easy to do as well. Thanks to that. There's something that we had to do to implement FAKE in the port street which is basically to pass everything that was passed on the command line down to SUBMEX and then SUBMEX and then SUBMEX all the way down to turtles. So that for instance this year would work. I think that finally in MBSD realized that they had to do this as well but it took them a long time. And just to say something nice about them as well we borrowed some features like very extended followups which is an awesome idea because then you can do stuff like that say that you have a list which is actually composed of a pair of stuff like a link and a file and you can create a rule that will link every main page to its source just in one simple line of MAKE file. If you're used to make one simple line of MAKE file. Where am I? Oh cool. So like I said we have some basic stuff and when we have some not such basic stuff like taking the lowercase part of a variable for instance and for loops and conditionals and stuff like that. This is something where we came first more or less. By this I mean that by the time I started working on MAKE we had more or less the same modifiers as NetBSD. FreeBSD didn't have anything more or less. And we started adding new stuff like lowercase for instance a few years before NetBSD decided to do their own stuff and obviously in completely incompatible ways to what we were doing. So why fuck them? Or if you want more reasonably you can take our source and look at the modifiers code which is very clean. And if you don't like our modifiers and you want to have something else it's very easy to do. We just don't see the need for us but it's very easy to port that to any other BSD if you want to have OLL or something like that set of variable modifiers that they took from whatever projects. I don't remember the name. You can do that. It's very easy. The interesting part is that at that point ParallelMAKE wasn't working. So by that point you're probably thinking why did that come to see this guy? He said that he was going to talk about ParallelMAKE and he hasn't said anything about that so far. There was the science student project part which is that the guy who wrote this make thought that putting all commands under a target into one single shell was a good idea which is obviously going to break almost every make file in existence because they expect everything online a make file to be run by a distinct shell won't work otherwise. There was also a fact that this ParallelStuff wasn't working so he put more debug stuff in it so if you try to run a make file in Parallel at that point while it won't work because it will display a shit lot of stuff and since some commands expect to have some result produced by make and reuse it later well that won't work. And there was a lot of code that wasn't used it wasn't VMS but it was Sprite and there was a lot of code that was supposed to let you run jobs over machines distantly using whatever interface what we don't have at all. So at that point I decided I wanted ParallelMAKE to work so the first thing I did was remove extra shell execution every line in the target should have its own shell it won't work otherwise. Remove extra display, leave it into a debug mode but not keep it for anything and get rid of all the noise because remote was just noise it was just stuff that was making the code almost impossible to read and definitely impossible to change. So this gave us first version of ParallelMAKE that worked basically there was still remains of one shell per target part which is that the job handler was forking a job manager which would be running each line for a separate shell and then running the last line advancing us okay everything went okay, you have your target it's done. This had one major problem which is that output comes out garbled because you are going to run several jobs in Parallel and you're going to see every job manager saying hey I'm going to execute this at the same time and you get fragments of lines or stuff horrible stuff all through it. So I did something I shouldn't have I did some extra structure to try to gain control of the situation which is that basically at that point the main make process used to have a pipe to each job manager and to select whatever it wanted to display at that time. So if you have some knowledge of concurrent programming it's basically a completely unfair scheduler because I want once I have some output from a given job to give it a chance to output as much as it can before I switch to the next job. So yeah basically you just try to bug a scheduler into works. And at this point it worked for the kernel we managed to build our first kernel with make minus g4 I think and no issues. I needed to add lots of dependencies and boom it worked for the source tree as well. The main issue with the source tree was that Parallel make was completely interested of course since it didn't used to work so people used to forget dependencies all over the place and if you try to build things in Parallel instead of second show obviously you're going to say oh wait I should have built this before that so I have to write it down so that it works. This is as stupid as it goes. This was the easy part because then you have to look at the cases where it doesn't work and you have to realize that you're not even halfway there there are still lots of issues to fix. Is the list of the three most important issues that we have that we had, sorry. First one is that pipe means that you don't have any standard input. So that's the difference between a compact make because in sequential make you can have one command which is going to ask the user do you want to continue or something like that? It will block make for a while but it will work. If you have your Parallel job handler which is actually redirecting a studio from each command and getting it into make that means that those commands no longer get what they need in terms of user input. So some stuff doesn't quite work. More serious is that naturally inside of normal way to build unique stuff you have some rules that will create several files. The simplest example I expect that your familiar with it is using YAC since usually you will create a C source file and a header H file. So at that point we did some MacGyver and just did the same thing that the GCC guys did which is to put a timestamp to serialize the build of those files. I'd hope that we did not forget any. And the last problem which is actually the most serious one is that actually Mac doesn't understand the file system. So if you have two targets say dot slash A and A for Mac there are different targets but on your file system usually they have the same file. If that doesn't scare you it should but we'll come back to that in a few minutes. At which point I was probably confident enough to try to decide that I wanted to document things. Which was also a big part of taming the beast because the documentation we had was horrible and not matching any standards at all. So first you document how things work then you look at POSIX then you realize you don't even use the right vocabulary so that people coming from outside won't understand what you're talking about. So you change every term until you more or less match what POSIX says. And there's also very big ongoing work which is that you have to decide which extensions you want to keep because they're actually useful and maintainable and working and not a problem to port to elsewhere and which part you want to get rid of because it's complete crap. And this is actually very difficult. I think that this is a point where NetBSD is actually losing because they're keeping way too much stuff which is unmentionable in the long term. Guilty. This is something that we don't do yet that we should do. And we should have a mode that enables us to say, okay, this part of make is standard and warning you are using some stuff that won't work elsewhere. And this is the best story basically because if the people who are writing bash scripts did have the flag to make sure they don't use bash extensions then they wouldn't be into such a mess where you have to have bash on your system because suddenly half the shell scripts won't work. You have the same issues we've made. It's less of an issue, some ish because it's only used by developers usually but it's still a nightmare. Well, Theo isn't there because it's actually his optimization. If you start looking at recursive make files you quite well know that if you're going to use parallel make you're going to have some combinatorial explosion because at the first level you've got four jobs then second level is 16 jobs and 64 jobs and you don't usually go that much further because your machine has exploded. Other systems like Numek for instance use a kind of token system but it's actually a little brittle for two reasons. One, you could decide to use a socket or something but where are you going to put it? You don't know actually when you're using make which file system is whiteable, which one is not and so if you have for instance some temporary file system or some network file system you can possibly not put a socket on it and have it working. So you have to have some very strong constraints if you actually want to use a socket to communicate between processes. You could decide to use file descriptor but that actually doesn't work. Well, it works but people like Marquette Ennis for instance said nah, it's not standard it shouldn't work, it won't work because you're not passing a file descriptor directly from a make process to the next make process but you have a shell in between and the shell is allowed to do whatever it wants with any file descriptor you pass it besides standard input, standard output and standard error. So the heuristic was very simple. It's just that you look deeper at whatever you're going to execute and hey if you noticed that you have something which is also invoking make or something that looks like make you decide hey I'm a recursive make file so I'm going to block there which means that I'm going to start my four jobs as usual but once I'm running this one I'm not going to start anything else until we'll see it's finished and that's good enough actually in practice. If that sounds familiar to the people working in Portsland it's exactly the same optimization that we put as DPB per lab. We're going to start stuff which is potentially expensive and we're going to block on starting anything else until we're sure that part is done. Sorry I'm going a bit fast because I want to go to the juicy part. The pipe issue, the solution came from something else entirely. Basically I just wanted to get better messages with a line number and stuff like that and if you have just a job manager that runs in every line in a target building you don't have good error messages because the job manager is just going to say oh something fucked up and you don't know where it went wrong. So I replaced the job manager with a job automaton instead of having one manager which is responsible for forking a lot of stuff have make proper which is forking everything by hand and each manager just keeps track of where it's at at which line it is inside a given job. The nice thing is that once you do that you realize you no longer need to have a pipe because you're no longer printing stuff from within the job manager but from make itself. So you have complete lines. Of course the comments you're going to fork are maybe going to display some stuff. Now it's not that often and it doesn't really matter. It works just fine. So no longer any problem with pipes. Since I don't link become an issue if you don't know about this I'm just going to alert you that this stuff doesn't work. You can't fork jobs and use wait and expect to get signals at the same time because wait won't be interrupted by signals. So it's as simple as that. If you have your make which is building lots of stuff and you want to interrupt it and you do things that way then you may have to wait for a long time. The idea is that you're going to do something funky with signals. Well, basically you no longer wait for jobs but instead you're going to pause until you get a signal and in order to get jobs you just put empty under for sick child so that whenever one of your children dies then you get a signal which you ignore but at least you get out of the loop. More or less. Side notes while bat is on there so it doesn't really matter. This one is probably the most important. People did say that using one single shell was good because you were forking less processes. Instead of that we can do another optimization. We don't necessarily have to run a shell for each command. Especially if you don't have any shell wildcards in the command. And we already scan the command through. We already look to see if we see a keyword like make. So if we just have a simple command, no shell. So it's even faster. And maybe I will do that but it would make sense to optimize the simple constructs which come up all the time where you change to a given directory and run some command. You could just directly do CHDR inside make and run the command that would work. As far as multiple targets I have to credit David Dolant. I think, if I remember correctly. He told me that when you see something like that it used to be a shortcut to say that both targets have the same dependencies and same commands but in recent POSIX declaration it actually means that you are, you might be building and be together. In order to be sure you have to do some heuristics. Always the same one. You are going to look if you're referencing the target in the command you're executing. In which case you have some speed commands. You're actually reusing the same rule to build a NB separately. But if you don't refer to the target it's very likely that you're building everything at the same time. And so you just lock one target while you're building the other one so that you don't try to build both at the same time. Notice that it's just a heuristic and if you're wrong it's not really a problem because if you tie some targets which are actually generated separately. Ah, they are not parallel. And that's it. That's the only issue you're going to run into. Okay, I just have time to talk about that which is the only issue that we have left these days. Why is it an issue? It's because when you're running Sec&Shall make it doesn't really matter because you can rely on the file system. Basically you're going to take one rule, evaluate it, build the target which is called A for instance. And then you look again at the file system and if you see a rule which refers to dot slash A. Okay, you look at the file system, you have the file and you have the right timestamps so you don't have to rebuild anything. But if you're trying to do stuff in parallel you don't necessarily know that both targets refer to the same file and you might try to build them both at the same time and it's going to go completely crazy. And even worse with VPF and even worse with suffixes. The first hint I got that there was a big issue with that is when I tried to build recent auto-conf because they rely on this. If you build any recent auto-conf with a separate object directory it will break with our Mac completely and it's not a Mac file issue. It's that problem. It's definitely that it tries to build a file in a given directory and refers to it as if it were in another directory and it has to be the same file and it doesn't know anything about it. It's very complicated. I had a partial solution which is basically to look at the file names and once you have the same file names you try to decide based on the full path whether it's the same file or not. And this works. You can actually figure out which files are supposed to be the same file. But you can't simply put a rule inside of Mac saying that okay, those targets are the same. You are going to tie them forever because then you're going to create loops inside your dependency tree. Basically, you can build loops inside the Mac file. It's perfectly normal. As long as you only take a tree part and you try to build it. And if you do those equivalents without thinking you're definitely going to create loops that Mac is going to notice and it's going to be awfully confused about it. And this doesn't work. And nobody in BSD land has a solution for this as far as I know yet. So the next step will be to go into the worst part of Mac which is the Parallel Job Builder and take it out entirely because I think that the sequential builder is better. The only thing that needs to be done is instead of building things to put stuff that's supposed to be built inside a queue and to iterate on that. And very often to look at those equivalence targets to make sure that what you've built is actually what you need and that you have everything in sync. And they should work, hopefully. So maybe see you in two years and tell you whether it worked or not. I think that's about the state of what we're doing right now. Yeah, some publicity for some other projects. If you want to have a build system that's sane you should really consider Ninja. As far as I know, it's make-don't-write. It's completely different. The syntax has nothing to do with Mac but almost every problem that you noticed if you played a lot with Mac like recursive Macs, automatically generating dependencies for header files, it's handled correctly by Ninja. The guy who did this has, well, 20 years of insight. He thought really hard about how Mac should work and he did something that does actually work. So please look at it. Don't go to S-Cons. Don't go to C-Mac to give to whatever. Definitely not to GNU-Mac. If you want to do something new, start with Ninja. Ah, I'm almost on time, I think. Yeah, any questions? No, I wait for the mic. In the example for the AB dependency rule change, that looks a lot like the Yak rule. They're using before, so what does make-do now when it sees that rule with Yak? For now, you explicitly have to put this dependency for things to work, which means that you can't rely on the auto-generated suffix rules for Yak but if you explicitly write that Yak rule, it will work. So this is still a bit tricky. You can't just use whatever is designed by POSIX for now because it will only say that to transform a Yak file into a C file, you have Veshul and it doesn't say anything about the header file. You still have to put extra dependency for things to work. This is what we did and as far as I know, we haven't had any races inside the Yak generated stuff for at least one year, so probably works. Actually, two questions. If, have you tried running make with different J values and see how the jobs are distributed among the processors? Yeah. Are they used in a proper way? Can make help that or is it just a kernel scheduler that's crappy? Oh, the kernel scheduler is definitely crappy. Yes, I know that, but can make help with that handicapped, of whom he has? Yeah, I should, but... I was just curious how the distribution looks. The thing I've noticed is that you have a crappy laptop like this 2-core CPU. You usually use a make-managed G4, for instance, because it's better than make-managed G2. That's some overhead that I don't understand anything about. If you really look at how much time you spend, most of the time it's not going to be a problem with make proper, but mostly with recursive make files. That requires that you redesign things to not be recursive at all, and you also spend a lot of time in configure street, for instance. But it's one exception in our source tree, which is bin hotels, which is completely crazy, but you've got all that stuff running in parallel and perfectly using make to build things very fast. But if you look at the most crapiest example we have, which is Xenocara, you will lose completely with make-managed G4, because you spend about half the time running configurals and compressing fonts, which are mostly sequential stuff. There's only one target running at one given time. If you look at it more closely, it's also one reason to have DPB and try to use it for possibly source constructs. Yeah, there isn't verse where you want to yell at me. Because make only deals properly with something which is fairly local. If you have one single directory with lots of source files, sure, you can parallelize it and it will work. But if you have things over several directories and people have already written make files that are separate for each directory, it won't be so good. It should also be possible to replace what we have in the tree in order to build several programs at once. In some cases, like very simple stuff, like LS or shmold or stuff like that, where you have the same options and where you have one source file per directory, you could say, okay, I want to build everything at once in parallel mode and it should possibly work. But there are some other dragons, most of all, TO, because if you start looking at the .mk file and try changing them, usually you're going to break something else. So it's complicated. So my second question was, if you look, is it always worth it to parallelize make in a project? I mean, the time it takes to calculate the dependencies and weight on the objects that need to be built might take more time than actually doing it sequentially. No, if you have one single directory and one single make instance, it's usually going to be worth it. It's going to be a problem if you have several directories, obviously, or if you have the time, if you start from scratch, I'd recommend that you write one single make file and that you reach over into whatever source directory you need and at least you get a chance to get all dependencies right because having make running over several directories and having several make files, it's going to be expensive because you are going to rescind the file system several times and also you're going to have some sequential bottlenecks all over the place. That's actually this anecdotal stuff about Ninja, which is that CMEK can be coerced to use Ninja as a backend and if you start doing that, you will break things because people usually don't supply all interdependencies between directory and Ninja is so much more efficient than CMEK at finding them out that you will find races that you weren't even aware existed, but it's definitely worth it. You just have to learn how to read dependencies, sprinkle a few of them around and it would usually go much faster. For instance, the biggest instance we had was Chromium because Chromium used to build using CMEK and GMEK and now it's, no, sorry, not CMEK, Jeep and GMEK and now it's using Ninja as a backend as a result, the build time has been more than half. Yeah, it was spending half the time just running GMEK rules at at least 50% CPU per GMEK. What the fuck? Thank you, that's perfect. One question is, let's thank our speaker.