I'd like to thank you all for coming today to listen about my project. This is Ocelot, this Ruby compiler I've been trying to write. Ocelot is a preliminary name, and it's also a preliminary implementation, meaning in spite of how much work I put into it. I'm sorry. Ocelot is a preliminary name, and it's also a preliminary implementation, which means that in spite of how much work I put into it, it's still not very far along. But I've gotten through the difficult parts, I think, and so some exciting stuff should start happening soon. Now, my goal with this project is to have an efficient implementation of Ruby while supporting the full semantics of the language. Now, those goals aren't entirely compatible because Ruby just isn't that way, but it's surprising how little actually has to be given up in order to have efficiency. So, oh, and I should say, probably speaking, Ocelot is not a compiler, but a Ruby to C translator, which is not, in my opinion, a true compiler. But it should still be pretty fast regardless. So, before we talk about Ruby, let's talk a little bit about an efficient language. Here's some C code. This is a Fibonacci calculator. Now, C is efficient because the compiler knows what the types of things are. So, for instance, when it comes time for the compiler to omit the instruction for this minus operator here, it knows that the types of its operands are integers, and so it can omit the integer version of the minus instruction instead of some polymorphic instruction sequence that switches off depending on the runtime type of the operands, choosing a float or an integer or a char minus. Likewise, with this plus instruction, the compiler can see that the return value of the Fib method is an int, so it omits the integer version of the plus instruction. And even more than that, when it comes time to omit the call site for these Fib calls here and here, the compiler can see where the target of those calls is, and this is recursive so the target is the same method, but being able to see where the target of the calls are means that the compiler can do things like inlining or tail recursion elimination, that kind of thing. And most of this would be true even if C were a polymorphic language, even if you were allowed to have multiple versions of Fib, you could still have all these nice optimizations. So now here's a Ruby version of the same algorithm. Ruby is several orders of magnitude slower than C when running this code. And the major difference between these two is, you know, aside from syntactical differences, is that Ruby has no type declarations for anything. So it's very difficult for a compiler to get a grip on what the types of things are going to be at runtime. You know, in this code we'd normally expect N to be an int, but according to the semantics of the language N could be an array, it could be a string, it could be anything. So, and because of that it makes it very difficult for the compiler to generate efficient call sites and the calls are everywhere in Ruby. You know, it's not just these Fibs here, all of these operators minus, plus, less than or equal, those are all calls and those are all pretty slow. So writing a compiler for Ruby is something I wanted to do for a very long time and it's something I more or less gave up on a number of years ago. It just seemed too hard to solve that problem.  But then there was a breakthrough. Now, in Ruby we have this tradition of writing tests. Ruby's the most test heavy language that I've ever encountered. And so here's an example test for the Fib method. Now, notice something very interesting about this test. The arguments to Fib and the test are all integers. Likewise, the returns of Fib are all integers. So what if you had the compiler run the unit test for the code that is compiling and then extract type definite, the types of the expressions as they go flying past and use those pragmatically as a kind of type declaration, right? I call this type induction. Type induction is to be contrasted with a camel-style type inference, where the compiler sees what methods are being used on a specific variable and infers a type declaration for that variable that has all of those methods in it. I should also mention I didn't invent this idea. There's two other people who seem to have independently come up with the same idea and told me about it. Those two people are Rich Moran and Josh Sesser. Both of them are at the conference, but I don't see them in the room today. I did come up with this name type induction, however. Okay, so now I've been using this word type, which is kind of a controversial religious word in Ruby. It's been the cause of flame wars in the past. Now, even though it's such a dangerous term, I think it's actually the appropriate one, but I should spend a few moments to give a definition of what is a type in Ruby. I think I can come up with a definition that's both one that we can all agree on and one that's useful for writing compilers. So what is a type? Now, here's some wrong answers. Some people, for instance, say Ruby has no types. Now, while there are no type declarations, it is not true that Ruby values have no types. You might say that classes are the types. That's a closer approach to the definition at any rate. And it's true enough in a static language, but it's leaving out an important aspect of the way Ruby works, which is singleton classes. In Ruby, you can change the behavior of an object at runtime, and that changes its singleton class. So maybe these singleton classes are the types. It's closer yet, but it's still not quite right. That's actually, I believe, a correct definition of types. However, the problem is it's really not very useful. Singleton classes are too numerous. Every object which has singleton classes has a unique singleton class. So potentially a program that's using singleton classes can have very, very many types, or an infinite number even. And that's too many to deal with statically. So here's a good definition of type. Type is class plus decorators. So when an object is born, its type is its class. They're the same. But over its lifetime, it may get decorated with these modifications to its behavior like here. And the class that it's born with plus the list of decorators that are applied to it over its lifetime together define the type of a value. Here's another definition of type. This is probably even better than the last one because it results in fewer types overall. Type is the object set of name to method body mappings, which is to say it's a hash of method names to method implementations. This is the most exact definition. I think it really captures the essence of what a type is. And it is equivalent to this definition, although it's not a one-to-one mapping. That's to say that there may be multiple paths through the graph of decorators to a single unique set of method name to method body mappings. Now, type inductance is very powerful. It's the key insight for this project. But it does have some problems. I want to cover how we're going to address those problems. One is the issue of coverage. So here's the Fibonacci code I showed before. But I could have written it like this. That is, I could have made a weaker test. Now, in this version, I'm only passing 0 and 1 to Fib. And that will mean that this first line of Fib is the only one that gets executed. And never is even hit. So as a result, the type inducer, when it's examining Fib, will never get a chance to see what the types of the expressions in the second line are. They won't have any information about them. So clearly, in order to be able to type induce your program, you first have to have pretty much complete code coverage. But code coverage isn't the only type of coverage. Now, let's imagine we have this situation. We have these three animal classes. And they each have a call method, which corresponds to the sound the animal makes.  And the zoo also has a sound that it makes. When all the animals in the zoo make their call at once, we have a cacophony. And then there's a test over here for the cacophony method. But there's a problem with this test, right? I forgot to put a bird into the zoo when I created it. So as a result, when the type inducer will never see, in this line, never see that the variable animal could have the type of bird. There isn't a code coverage issue here. All the expressions in cacophony are being covered. But there is a lack of what I call type coverage. Now, another problem with, yes? Because I think I would think that a zoo cacophony would be any sort of animal would be able to receive a call. Would this sort of compile be able to understand that? That wouldn't really help by itself. The ancestor is just sort of a way of initializing the class when Eufford has created it. So another problem with type induction is mocks.  And so at runtime, they're polluting the information that the type inducer is able to obtain. They cause the type inducer to believe that some of your expressions will have types that aren't actually possible at runtime. Even worse, it could be a sign that your tests aren't exercising all of the types that all of your expressions could have. And so again, you'd have a lack of proper type coverage. So I don't use mocks. In general, I personally dislike mocks and for the same reason that the compiler dislikes mocks, they divorce your tests from reality. Use of a mock means you're exercising your code in an artificial environment which doesn't correspond to the actual runtime. In a few circumstances, they may be justified in order to interact with something external, like a server or a piece of hardware. Kind of have to have a mock then. But even if you do that, you should also have another test which exercises that code using the actual real type that could actually... Question? Yeah. What about like the fact that if you use no mocks, any failure in your code can cover the whole code base because it's going all the way through where many times you want to isolate your code for certain types of tests, say unit tests. Only that area of the code is actually responsible for these things. You don't see a benefit from mocking in that case? Well, mocks can be nice to kind of narrow down the range of code that's being executed. I can see the advantage of that. What I'm trying to say is if you do use your mock, make sure that you also have some kind of integration type test which is not using the mocks which is actually testing the whole stack with the real types that are going to be present at runtime. I don't want to forbid people from using mocks. It's a very popular thing to do. It's not going to be a disaster but you do need to make sure you get complete type coverage. And I'll be talking about some of the other ways of dealing with missing type coverage. I've talked about typing induction, some of its problems. I'll be talking about this a little more but first let's explore some of the C code that the compiler is actually going to generate. Keep in mind these examples that I'm giving are pseudocode, reality as usual is more complicated than this but it'll give you the idea of what's going to go on. So what happens, for instance, when the compiler sees a call site? Here's a call site that I snipped out of that example I gave earlier. What should that look like and see? This is one possibility. This is what C++ does. C++ adds a hidden field to every object which they call the vtable. Here I'm calling it the class. That's the name that's used by MRI internally. Now it's a kind of deceptive name because we know class and type aren't the same thing necessarily but that's the standard terminology for Ruby. And then hanging off of this vtable or class there'll be a table of pointers to actual method implementations and so at runtime the compiler dereferences the object reference to find the class and then dereferences a pointer in the table in the class table to find the actual method implementation and then jumps to that. This is an okay way to do it. C++ does this a lot. It's not very slow but there's another way. Instead of jumping through a pointer you could switch off of the class field and when it has a type known to the compiler actually jump straight to the implementation of the method for that type.  Why do you want to do that? There are some pretty good reasons for doing it this way. One is that avoiding the indirect call means you avoid the pipeline install that those calls usually cause. A direct call even if you have several branches proceeding it is going to be predicted by the processor better and as a result it's going to be a little faster. Another advantage to this technique is that it enables inlining. When you know exactly which method you're going to call it's relatively straightforward for the compiler to just inline the implementations of those methods directly in the appropriate switch branch. Whereas with this version it's hard to see how the compiler is going to inline it all without converting it to this first. Again this isn't my idea I stole this out of a paper on small Eiffel which is the open source Eiffel compiler. Let's see. Both compilers and processors benefit from having explicit knowledge of what the targets of your call sites are going to be. There's something interesting going on in the default case down here. The default case corresponds to the case where the compiler didn't know what the type at runtime is. At a type at runtime is encountered that the compiler didn't expect. That indicates a gap in type coverage. Now one thing you could do at this point is you could just raise an exception. Something happened I didn't expect. Sorry. But there would be a problem with that because then your compiler would be introducing bugs into your program that weren't present in the interpreted version. It's much, much better not to do that if it's at all possible. What I've got here is an RB Fun Call for those of you who aren't familiar with writing C extensions or with Ruby internals. That's the way that Ruby itself handles method calls internally. This RB Fun Call function. And it's every bit as slow as a normal method call in Ruby. In fact, it's probably a little bit slower. But it works. And it preserves the full semantics of the original code. Now the other thing going on in the switch statement is I've got this warning. Remember, going into the default case means that you have a lack of type coverage. And as good testers, that's something you ought to want to know about. You ought to be looking at these warnings and using them as clues as to how to write better tests. Which means the next time the compiler runs it will have more information and it will better be able to compile your program. Now one problem with these warnings or another thing you can do with these is the compiler can actually use these directly as input. So on a subsequent recompile of the same code, it can actually see where there was a type that wasn't expected the first time and generate the correct code the second time and you get, again, a better compile. That's a somewhat weaker technique than actually fixing your tests because that information quickly becomes stale whereas your tests presumably don't. But either way, it's a good idea. Now let me try to talk as briefly as possible about object representation. Here's an example of Ruby class and obviously it has three instance variables, Fubar and Baz. I was just going to be represented in C. This is what the interpreter does. Every object, every Ruby object is represented by one of these R object things. And R object has three fields in it and it has a flag field. It has the class that we talked about before and it has this IVAR table which is a hash where the instance variables are kept. This works but there's a little bit better way. Since we can tell fairly clearly what the instance variables in the class are, why not just inline them directly into the appropriate structure. That way, access to those instance variables will be done basically as an array dereference instead of as a hash lookup. That's both faster and it uses less memory. I think Ruby 1.9 already does something like this. I'm not sure of the details. It may be limited in some way. And then when it comes to bindings, we have much the same issue. It's relatively easy to analyze a method for the set of local variables and use in it. And you can use that to create a custom stack frame for each method which contains the local variables and use in that method. As well as a hash table. In both of these cases, you keep the hash table and that's used as sort of a backup for the case where the variable is used dynamically but not statically which you couldn't otherwise detect. Other than polymorphic dynamic method calls, let's talk about some of the other issues that a compiler is going to run into because there are a number of them. Ruby has these singleton methods singleton classes, it has modules you can extend your objects by and all of these present more or less the same problem which is that you're changing the type of a value at runtime. How is that going to be done in C? C doesn't allow you to change types of things really. C types don't even really exist at runtime in the same way they do in Ruby. But remember, the type of a Ruby object is stored in this class field here and there's no reason you couldn't just change that as necessary in order to make it the value that it needs to be. The object's type is really just an aspect of its state and the boundary between the type and state is, if you really think about it, it's not that firm of a thing. There's no reason why the type can't be mutable just like the state is, even though most static languages don't really support that. Okay, so what about method missing? Here's another difficult feature in a dynamic language, it's hard to support statically. The problem with this is it makes the flow of control pretty hard to follow. A compiler can never know when an innocent looking method call is actually going to end up calling that the missing instead. And in a program that's using method, I should add that if it were not for this one feature, we probably would have had a compiler a number of years ago based on a camel-style type inference. Method missing inhibits that. But it's a useful feature and it's used in all kinds of neat things. So we want to be able to support it. Now let's go back and look at this example method call I showed before. Now what if we allow the type of the receiver to be a delegate instead at this point which responds to most methods with its method missing call? Once the compiler figures out that a call to method missing is possible for a specific type at a particular call site, it can just generate the call to method missing at that point. You do have to pass an extra parameter for the method name. But it really type induction handles this problem quite beautifully. You also have to make sure that you've got complete coverage of your types over the call sites where method missing can be called. But it's really in contrast to type inference which just falls apart completely in this case. We can handle this really with no problems. And then there's eval. Some people call this evil and there's a good reason for that. This really makes writing a compiler hell. You just can't tell what's going to happen when there's an eval. There could be arbitrary side effects inside the eval. You know, you can't tell what the argument to eval is going to be in the general case.  It takes a string at runtime and interprets it. How are you going to compile that? But it turns out that most calls to eval are actually static. Which is to say that there's only ever one argument that's really possible or maybe a fairly narrow range of arguments. So if you can figure out what that one argument is, you can deal with that. Discovering that statically is kind of difficult. In fact, it's impossible in a lot of cases. But we can use the same trick as we did with type induction. That is, you can run the unit test, see what argument was passed to eval in the unit test, and just assume that at runtime it's going to be the same argument. So in other words, calls to eval will turn into something like this. You check to see if the argument was the expected one. If it was, you just inline that code directly at that point. Notice there's no eval call left in this code now. There's also no quotes around this code that had been quoted before, or in a string at any rate. Now the other thing going on here also, we've got this else clause, right? The correct thing for me to do at this point, if the argument wasn't an expected one, would be just to fall back to the interpreter's version of eval and use that. I actually think that failing at this point is going to be a better thing to do. If there's a, if the call to eval has an unexpected argument that indicates one of two things, either you didn't have proper eval coverage in your tests, which is something you want to know about, or possibly user input is able to influence the call to an eval. That latter is considered a bad thing usually, although it's useful in some programs. Every eval call is a potential code injection attack, so having a tool which can eliminate those attacks entirely is probably a good idea. And expecting your tests to have complete eval coverage is not that extreme of a requirement. That's something your tests really should do. Okay, so this magic way of predicting what the calls to eval are going to be, that's something I call eval prescience. So, overall, the process of using a compiler works something like this. You use type induction and eval prescience to narrow down the actual range of dynamic behavior in your program. The compiler then uses the information gathered in those stages to produce a static version of your program. But the information gathered is only really as good as your tests. And most tests, even tests for Ruby projects, really aren't complete enough. So the runtime also emits log statements telling you whether your gaps in your test coverage and you should use those log statements to make your tests more complete, which makes more information available from the compiler in the next cycle. Probably three or four times through a cycle like this and you'll have pretty complete tests which describe the behavior of your program pretty well. So we can deal with the lack of type coverage and coverage in general in four different ways. One, there's a fallback to the interpreter when something unexpected happens. Two, we have this virtuous circle which is hopefully causing you to continuously improve the test coverage unless the information available to the compiler. Three, we have the warnings emitted by the runtime which can be used directly by the compiler as input and type hints to optimize subsequent recompiles. And then there's a fourth secret technique which I believe to be the most powerful, but I'm not going to tell you about that yet. Okay, now let's talk about the really hard stuff. I said that, for instance, most calls to eval are static. Well, there are dynamic calls to eval. For instance, in this program. Does anyone recognize this program? Who said REPL? Right. This is what LIST calls a REPL that stands for redeval print loop. Basically, this is a very simple version of IRD. It's taking input from the user and evaling it. So no matter how much you test this code, you're never going to cover all the possible inputs to eval. It's pretty well hopeless. So this is a case that's basically incompilable. But it's impossible to compile it completely. However, it is possible to compile it to something that ends up calling eval in this inner loop here. And for that matter, who really needs IRB to be faster than it is right now? Now, there are other interesting cases for this kind of thing. For instance, if you were writing a spreadsheet in Ruby, and the natural thing to do would be to use Ruby as the cell formula language. In that case, again, you've got user input being passed to eval. So things will be happening at runtime that weren't predictable. So probably, I think that there'll be some kind of hint that you can give the compiler to tell it that those few places where there is a really genuinely dynamic call to eval, this one's a dynamic eval, and so it'll know how to handle it a little bit differently. I don't know a lot about just-in-time compiling. It's not the approach that I prefer. It could be done. If what you're doing, if the output of the compiler is C, then adjusting time compiler means that you're going to be running the C compiler in the background, and it's not really optimized for compile speed that way in the way like-it's not optimized for the way a Java jet compiler is. So it may not be a real good idea. Yes, here. Now, one thing that you might want to do, for instance, is have a sort of background compiler that runs in a separate process. It gathers the warnings emitted by default cases and then uses that to, you know, be like every 10 minutes, recompile your program as long as it continues to be warnings. Something like that for a very long-running process like most Rails apps would probably be a pretty good thing.  That's not really a jet. But, you know, overall this technique is more or less the same thing as what goes on in a jet compiler. It's just a little slower. It's slower in the cycle, the feedback cycle is slower. So you first run the tests in one process and you gather information about your program there and then you use the information to do the compile and that's a whole-you quickly get to basically static version of your program which has pretty static behavior. Unlike in Java where you're constantly running inside of the virtual machine and you basically don't have any control over when the compiler is running and when there might be extra work to be done, although Java does a pretty good job of hiding that. Okay, so there's another important case to consider. The dynamic typing version of the dynamic val problem. See, in this program I've got, let's say, 20 modules and they're being mixed in to an object in random order. That adds up to 20 factorial different possible types. That's probably more than the number of atoms in the universe. So there's no way you're ever going to be able to exercise this program enough to enumerate all of the types. Nor will there ever be enough memory to store all of those types. So this program, again, is incompilable. On the other hand, this is really rare. I've never seen or heard of code that actually does this. Has anybody ever written any code that does something? Paul raises his hand. Something like that. Okay, but in any given program, you're usually loading in the same order, right? You can be specified in a configuration file or something like that. Yes, that's true. Good question. That depends on whether the method actually has a call to super in it or not. If there's no call to super, then you're not chaining the methods up and the order is much less important and the actual number of types is approachable again. To go back to Paul's point, I think that somehow... Well, to handle that kind of case, you would need to have the config file basically be part of the inputs of the compiler. And that could get a little tricky. All right, so that's the end. I want to thank you all for coming and listening to me. Here's some information about me, my email address and my blog. I hesitate to put the blog up there because I haven't updated it in a long time. There's not much on there anyway. There's also this mailing list, which I started for discussing this in similar topics. And I want to add that I'm actively looking for collaborators and people who want to help me with this or maybe there's somebody out there who'd like to sponsor me for doing this work. And in the about five minutes remaining, open the floor up to questions. How does code which is dependent on other libraries work? Do the libraries... Would you use some type of library loading? Like the libraries would have to be compiled as well? Because I'm trying to think, if the libraries weren't compiled, would you need to test for the libraries to be run for all the types or to determine all the types for the libraries as well? Yeah, basically the libraries have to be compiled as well. And the libraries have to have tests. Which, again, are part of the compile process. Separately, if you have a library, you have a compiled version that then your client program would load the compiled version of the library, or which compile it all as one big unit. You probably could do it separately, but it's better to have, for a dynamic language, to have all of the source code available to the compiler so that it can get a complete picture of what's going on. It's called whole program compilation. Wouldn't, if you did compile the libraries beforehand using this compiler to be used to commit to those? Couldn't you ship some sort of summary of the types in addition to the actual compile code that this compiler used to know what sort of types that libraries can spit out that are in the compiled library? Yes, you could. But the compiler really wants to be able to see other things that are going on inside of the external source code as well. You know, to be able to do something, if you want to be able to like inline, for instance, calls the things in your compiler, you have to have that source code available. So what's the state of the compiler and how are you testing its performance? At this point, I have type induction almost finished. So it's really not very far along. So the next thing to do is to start actually generating C code from parse trees. That's, I think, going to be fairly easy. And as far as testing performance, well, you know, you run some code through it and see how fast it is compared to other implementations. There is a project called Ruby Benchmark Suite out there for benchmarking Ruby implementations and operations that they do. Or you could benchmark Ruby spec, or you could benchmark Rails. There's lots of possible things. Yes? So you're linking in the Ruby interpreter as well, such that potentially if there's code you depend on that they can't make a file or whatever, you can still deal with that. Yes. Yes. It's just slow. Yes. I'm linking in the Ruby interpreter, the C code for the Ruby interpreter and with your executable also. If you can guarantee that there aren't going to be any cause to a vowel and that you have good type coverage, you could potentially leave the interpreter out. Probably that's not a real good idea, but it might be an attractive option for some people. Was there another question over here? Yeah. Why restrict your type induction to only come from tests? Why not come from other parts of the program, especially if you have a couple of programs that you can do some sort of data analysis for? Well, that's a good question, and you don't need to. In fact, what you really need is just to exercise the code in some way, and you want to do that exercise in some way that in the end of the day there's going to be no persisting side effects. So tests fulfill all those conditions, but depending on your application there may be a variety of other things you can do that also can be used. How about handling when a dynamic code calls in words from the compiled code, say it sets an instance variable that does or doesn't exist in your class? Well, so as far as just calling code from the dynamic side to the static side, that would go through an RB fun call, which would be slow. The instance variables, basically each class will have to have a different implementation of instance variable get and set, which knows how to get to those records in the statically allocated records in the class of structure. Yes. When you start, you mentioned that you're putting, instead of having 90 tables, directly variables in there, right? Yes. So what happens when you start going dynamically instance variable set in that table and say, where did you set up? Well, this is going to be a custom version of instance variable set for each method, for each class. So when you call instance variable set it will call a specific version rather than a generic version that the interpreter has. I see people coming in, so I think that's the end of my time. Thank you all very much.


Ne vzveč sem tukaj občin, da bi se pošličilo. Ciao, tudi. Mi je Marco Crivelaro, prinsipul in genir v zonu. Čakaj sem spetnja vzveč in spetnja, skupajte s tukaj zonu v 2017. In vzveč je inčen zvokal, tukaj v 2020. Vzveč se počičal, da sem vzveč v zvoku. Remember, the zone is a name. So before we dive deep into the subject of the agenda I would like to tell you about what the zone is, then give a bit of history in how we got to use backstage and then we will look into some technical and cultural learnings and I'm hoping to give you some suggestions on the way. So what is the zone? Beside a funny name. The zone is a global life OTT plafor, je tukaj v 11 krajci, z kvalitvom vratu, ki je Italija Serija, German Bundesliga in Spanišlja Liga, in je tukaj v nekaj 180 krajci, z globa vratu, ki je UFA Women Champions League in Boxing Matchroom. Dazone inginering je pravda organizacija, ki je zazone plafor vratu. Toči se od 7 mili inženečnih začali iz svoj 70 njev, z kodinimi vseh njev. Svečne inženečnih je tudi platform način, da se vse vseh vseh njev poslutijo in težkje njev začali inženečnje inženečnje. Čakaj, zelo se različno izgleda. Nelj na povsem na našem, While implementing the micro-service-based architecture of the zone, we found ourselves multiple times in trouble while trying to answer in questions such as, which team owns a specific service, what's the scope of such a service, where can we find the code. We did a new work to find the documentation, monitoring, so a lot of questions, and we realized that we needed to build a service directory to answer all of these questions. So, one evening, a colleague of mine and I were having a beer in Seattle, and he came with the idea of storing all of this information together where the code lived. And this is how the zone manifest came to be. The zone manifest is a YAML metadata file that every engineering team in the zone is required to store in their GitHub repository. And it contains information such as the owner of the repository, which services are deployed from such a repository, dependencies of these services, links to Rambooks, Dashboard, SLOs, and many more informations. So, we built the foundation that the zone manifest. The SRE team has built an API around it, and we started to build tooling around it, but we never got to the point where we worked on the service directory that we wanted to work on the beginning. So, welcome backstage. And this is really the first learning that we have, and it is that it's very likely that the problem that you have has already been solved by someone else. When we first heard about backstage, listening to a podcast, we were amazed by the fact that it had all the features that we were looking for, if not more. So, it would have been silly for us to not try and use it. So, we started the work of implementing backstage internally in March 2021, and we officially launched it October last year, so we are looking at one year of learnings. So, now let's look at some technical learnings. First of all, how do you start? Well, as for most of the things, the best thing that you can do is start small and then build piece by piece. Backstage has a very large quantity of plugins, which keeps growing. This isn't necessarily a bad thing, but sometimes it could be overwhelming, especially at the beginning. Start with what matters the most and then build from there. When we started implementing backstage at the zone, we made the mistake of trying to implement all possible plugins that we could think of, because we wanted to show all the engineering teams how cool backstage could have been. But that had the result of raising even more questions rather than answering them. So, we made a step back and we focused on the software catalog, then we introduced tech docs and only recently we started looking at the scaffolder. You also want to use what you know and keep it simple. Backstage is pretty flexible and you don't necessarily have to run it in a Kubernetes cluster, although we are at KubeCon, so I shouldn't say that. You can use what you know. For instance, in the zone, we deploy our services in AWS ECS Fargate, so we decided to do the same with backstage and use what we already know. We are building a single container image that serves both the front and the back end via an AWS application load balancer. We are offloading the authentication to the application load balancer, which is connected to Azure Active Directory using OpenID Connect and we store into the database RDS Postgres. So, pretty simple. Also, don't be afraid to get your hands dirty. Backstage has a lot of features. We all know that, but sometimes you need to do something that may not be already available in backstage. To give you an example, we use Ashikov Volt to store our secrets and of course we wanted to use the same for backstage, but we couldn't find anything, so we built a native API that could have allowed us to do that, especially while running on ECS Fargate. So we built a wrapper around backstage, which is started as the container starts, fetches the secrets from Volt, populace the configuration for backstage and then it starts the backstage process. And this has proven to be very effective for us because since we deployed it, we never had to change it again while backstage was evolving. Sometimes, though, getting your hands dirty could be painful. An example for that is how we had to handle the authentication. As I mentioned earlier, we are using AWS load balancer to handle the authentication and as we started to use backstage, there was already an API in place to handle the authentication via the application load balancer, but there was no documentation. So we reached out to the community of maintainers, and we found a solution running a dummy sign-in component on the front-end and handling the identity creation at the back-end side. But as backstage was evolving, as its API was evolving, we had to touch that code multiple times because it was breaking our pipeline, but it eventually got much better and we are now using a native proxy sign-in page to handle that, and as we started to use that code, we never had to touch it again, so great job there. We also love external integrations. We think that they are really powerful. External integrations allow you to consume APIs or other sources that you already have in place. We don't necessarily have to use catalogue info format to populate your catalogue, and we are using those to populate our catalogue. We have an API around the manifest, it's called the manifest API, and we use it to ingest components, an API, into backstage. We also have another internal API called the identity API, and we consume it to produce users and groups. But the power of external integration aren't just that you can ingest what you already have in place. You can build automations around them. An example of the automation that we put in place is how we, for instance, emit a custom tag whenever we identify that an entity has SLO defined. So we are creating that tag, so it's easier to filter the entities that already have an SLO in place. We haven't built a plugin to displace the SLO. And also another automation is how we automate the annotation that enables tech docs on the front end. In the zone, we are publishing our tech docs to an AWS-free bucket, and the engineering teams are already required to maintain a GitHub action workflow to publish the tech docs. And we didn't want to ask them to also remember to go into the manifest and add an annotation there so that the front end could enable the link to tech docs. So we decided to use at the external integration level we are checking if the tech docs exist on the Azure bucket, if it's there, then we emit the annotation, otherwise we don't. So the only thing that the engineering teams needs to remember is they need to use a workflow to publish them. External integrations have allowed us to implement another principle that we wanted to adopt since the very beginning, which is not letting backstage becoming our single source of truth. Backstage is more like an aggregator for us. We ingest entities from GitHub, manifest API that I mentioned earlier, identity API, and other APIs that we will have in the futures. There is no entity that is only owned by backstage. We don't register entities directly in backstage. We configure them to be ingested. And this allows us to rebuild backstage from an empty state, and we will know that it will be repopulated with the data that we had in place before. Much easier to do a disaster recovery. We should also strive to strive and implement real friction onboarding. Automate as much as you can, and when you cannot automate it, provide copy and paste examples to the engineers so that it's easy for them to configure whatever is missing. As we started backstage, as we launched backstage, all the engineering teams already found their services in their software catalog, and for the aspects that were not configured, we were providing them a config example that they could copy and paste. And a good example for that, again, is how we are hinting them how to populate tech docs. If we identify that the tech docs are not available, we provide them a snippet of code that they can copy and paste into their GitHub workflow to publish tech docs. If they don't know what tech docs is, we provide a link to the documentation that we maintain explaining how to populate tech docs and how good they are. You should also strive to stay on top of it. Since it is very easy to get started with backstage, it's also easy to forget to maintain it and let it run. And as with many products, beside losing the latest features you will find a lot of friction when you try to upgrade it. So our recommendation is to try and stay up to date with the monthly release. Since the introduction of the upgrade helper it's much easier to do that, but sometimes you will need to be ready to dig into the changelog or even to the code, especially if you have customized some aspects of backstage. Definitely stay in touch with the community. The community session is a great way of knowing what's coming up and reach out to the community of maintainers and adopters in Discord. They are really helpful there. So we see some technical learnings, quick cultural learnings, and then we all go for a beer. For us backstage is a tool that can... We see backstage as a tool that can influence our engineering culture We think it could become a driver of innovation and creativity, so it must be easy to contribute to it and be contribution internal and to the upstream open source. But it wasn't really easy to contribute to the internal instance of backstage, especially at the beginning. As I mentioned earlier, we use Vault to manage our secrets and not all the engineering teams have access to our vault namespace, so the moment they were cloning in the GitHub repository, they couldn't start backstage. So we have created a couple of scripts, make file targets that would allow them to set up backstage, whether they had access to the secrets or not. So if you are a member of the DX team, you can configure backstage with the access to secrets. What it will do for you, it will create a configuration file that makes use of the identity API and the manifest API using the secrets that you have involved, and then you can run it and populate the catalog as if it were in production. If you're not an engineer in the X team and you don't have access to those secrets, you can configure backstage without access to secrets, and it will populate the catalog... Sorry, it will populate the configuration with pointing backstage to some manifest files in the GitHub repositories, so the only secret that you need is your GitHub token to populate some example of the catalog. As we made it easier to contribute to backstage, we saw a first great contribution coming from the internal engineering community, a contribution that is very helpful for us in the zone, and it's called the TV target plugin. The TV target plugin has been contributed by an engineer working in the living room domain, a domain that we at the X team don't know very well, and it contains information for the packages that can be installed on the TV targets, such as Android, Apple TV and whatnot. It contains information such as the countries in which the application is available, minutes viewed per month for that type of application, how the application is packaged, which features are available, it even allows you to add it feature flags, many additional information that somebody in the DX team would have not come up with because we don't know the domain, so it is key that you enable engineers working on other domains to contribute to backstage because they know what they need, they know what is very... what's important to them and so what would make useful backstage to them. You also need to be prepared to make your voice heard and engage with your internal engineering organization. It's incredible, but even after a year that we launched backstage internally, we still hear from people that they haven't heard that backstage was around. Oh, it would be nice to have a service that tells us who owns a specific service. Well, we have it, it's backstage. Haven't you heard about it? So, yeah, and we are trying to be in touch with them continuously. We are writing, we have an internal blog platform and we are posting there, we post their new features announcements, every time we add a new feature to our internal instance, we are posting there, we are hosting demos for teams, we are shouting out for contribution opportunities so whenever we hear from people or from engineers that they have something that they would work on and that might be done in backstage, we try to hint them to go and contribute to our internal instance of backstage and we also try to attend the townhouse that our company has just to spread the word that backstage is around. And I like to close with a result of the first learning and it is that it's likely that someone else would benefit from the solution that you build. So, give back. And there are multiple ways in which you can contribute back to backstage open source. You can go to GitHub issues and find a good first issue, contribute with bug fixes, documentation as well is a good way to contribute, tutorial. In the zone we have contributed a tutorial to enable AWS application load balancer authentication and also with plugins. In the zone we have created a few plugins. One is the GitHub pull request board that us in DX and other engineering teams in the zone are using during their stand-ups to see what are the pull requests that they have opened, what are the statuses. We have contributed with a similar plugin but for GitHub issues because at the moment we have introduced tech docs and we allowed people to comment on tech docs by opening a GitHub issue, we realized nobody was looking at the GitHub issues so we created this plugin so it's there in backstage. And since it was mentioned earlier soon we will also have a plugin to do neuralic analytic using the analytics API. And also another great way to contribute is to give talks like I'm doing and with that I'd like to thank you for listening to me and it was a great pleasure. Thank you, Marco. Thank you. I can take questions. Yeah. Even at the beer. Again, you make me run. Thank you, Marco. Really interesting, as usual. I know that one of the most recurring questions is tips and lesson learned from real adopters. This is the focus of your presentation and a lot of presentation. Would you mind to share some tips that some suggest what not to do with backstage or lesson learned that you suggest not to repeat or to avoid in your experience, of course. If you have some. Yeah, well, I mentioned trying to get every plugin as much as you can because that is just making you lose the focus so definitely something that you don't want to do not doing in backstage. It's another question. Okay, sorry. So let me change another if I can. I mean, if you would be, because now you have experience, if you would be able to think about one missing feature of backstage, what you would like to see as next or what you would like to see as different. I mean, something different, easier, not done or whatever you'd like to choose for, does own yourself, the developer and the team that you're working on. So I love data and one thing that I would like to see is more data, especially on the back-end side of things. So being able to monitor how back-end is working, latencies and whatever, errors, all of that, if that could become easier, that would be great. And observability as well. We also added, just because we are working on the scaffolder now, did a small contribution that would allow us to see who is creating, who is running the scaffolder, just because it is changing something in our GitHub repository so we need to know that. So all of those kind of details on the back-end level is what I'd love to see. We talked a lot about analytics and data collection and data consumption. I'm curious about analytics and how we solve backstage usage itself. What do we know about users, about their patterns, about their habits? Because we mentioned a little bit, that some teams are using backstage during their stand-ups, during onboarding of new team members. Another extremum is that some people tell that they use backstage for everything. So what kind of groups of users are you identified with what data you're collecting and any thoughts on that? Yeah. As we launched backstage, we were a bit blind on how it was used and then we introduced Google Analytics. So what we see backstage being used is that TV target plug-in is used very frequently because it's something specific to what we do at the zone. The engineers that are using it, now we have even people from the product team that are using it. So probably something that not only the engineers need is something that would make it is what is used most frequently. Then I can see the pull request plug-in because it's a lot of team using it. And then the catalog, it really depends because we have, I think, we are around 2,000 entities right now and you have the granularity that they are browsing. So, yeah. The documentation as well is something that is really valuable, especially as more teams are migrating to tech docs because until backstage, really, until we launched backstage, all the documentation was hosted in Confluence and now teams are slowly but surely migrating into backstage. So that is getting a lot of attention now. I hope that answered the question. OK. Thank you so much. Marko. Thank you.


Under the St. Lucia Proposed Cannabis Industry, license cultivation, transportation, importation, manufacturing and retail of cannabis and cannabis products will be for medicinal and industrial purposes. This message is brought to you by the St. Lucia Cannabis Task Force.


Hey everybody, what's going on? I am Greg Sussman and these are your MLB picks tonight from Megan Nunez. What's happening, Megan? Not a whole lot. What's happening with you? Not much, ready to win some money betting on baseball this afternoon and into this evening. And we begin in Detroit, where the White Sox are taking on the Tigers. White Sox is their slight favorite. Mine is 132 over at the Fangirl Sportsbook and you are buying Dylan and Cease. We're taking on Matt Boyd and the Tigers this afternoon. Yeah, I'm gonna go ahead and take Cease. It's a great young arm and he has this White Sox lineup behind him that has just been mashing. Boyd on the other hand hasn't been so great for the Tigers. Last time he started it against Pittsburgh, I think they put up seven on him and this White Sox lineup is way better than that Pittsburgh lineup. So go ahead and give me Cease and this White Sox lineup. Two young pitchers and yet it's Cease that's pitching better as Megan noted rather than Matt Boyd. A lot of people came in this season very, very high on. Today we're gonna take advantage of that hype and we're gonna go the other way. We're gonna go Chicago White Sox and Dylan Cease. Up next, we head to Colorado where last week you'd absolutely destroy that first five under with the Rockies today. Well, we're not messing around there. We're just taking the Rockies on the money line. Rockies are facing off against the Diamondbacks, age Luke Weaver taking on, sends a tell up from Colorado. Rockies are minus 112 at Coors Field this afternoon. So first thing I noticed was a mismatch here. Sinsatella, he has been great only giving up, I think, two runs where Weaver has been the definition of erratic. Usually, as you said, I'm a first five under girl here but because of Weaver being so erratic I'm gonna have to take the Rockies to win the full game because you never know what you're gonna get. You never know what you're gonna get at Coors Field and Antonio Sinsatella has pitched well as Luke Weaver a bit erratic all over the place. Again, you wouldn't necessarily think this, right? If you Weaver the pitcher that you imagine pitching better than Sinsatella, that's not the case right now. So let's take advantage. We'll go to Sinsatella minus 112 with the Colorado Rockies today. Moving on to the Angels and the Athletics is Chris Bassett going on against Griffin canning of the Los Angeles Angels. You're going with the Oakland A's here. Both teams are minus 108 right now at the Fanville Sportsbook. Chris Bassett's your guy with Oakland. Why is that? Okay, so the A's were on absolute fire coming into the series with the Angels. It's been a little deflated as they've lost the two games but Bassett last time he faced the Angels was able to get through with no runs whereas canning last time he pitched against the A's gave up three. So while there's not a big difference there I just don't think the A's are going to get swept here today. I think that Bassett gets it done on the bump and I just like the A's money line here. The idea is that the A's like Megan said they're not going to get swept. Griffin canning pitched fine last week after Chris Bassett these two teams seeing each other quite a bit just like every team in the majors are and the A's too hot to get swept. So that's why Chris Bassett's going to lead the way for Oakland. We're not done with the Angels and the Athletics because this number of nine the run total today over at the Angels Sportsbook it's too high for you do you think? Yeah, I'm going to go ahead and take the full game under that's again because if I'll listen to my breakdown of the A's and the Angels money line we have two great pitchers in Bassett and Canning. That full game that both of these pitchers played last game was three to zero final score. So I'm thinking that I can definitely keep it under the nine today. Last time both Bassett and Griffin Canning pitched the number way under nine we're hoping we get more of the same for that today only the A's bats don't come alive too too much this afternoon. In one of the games of the day we get to the Cubs and the Cleveland Indians Kyle Hendricks on the mound against Carlos Carrasco for Cleveland like we said it is a good one out there in Cleveland this afternoon and you're going with the slight underdog Chicago Cubs with Kyle Hendricks. Carrasco's pitched well what makes you lean toward the Cubbies? Okay, so I don't usually like going against Carrasco I really like him as a pitcher and as a guy but the Cubbies lineup has been on fire and arguably the hottest in major league baseball. Look, they came off a five day layoff and put up seven runs yesterday to get the win. I think that Hendricks is going to be capable of holding an underperforming Indians lineup and I don't see why the Cubbies are underdogs here today so I'm rolling with my Cubs. No care in the world for Carlos Carrasco even though he's your boy and you're used to going with him today the Cubs lineup just too lethal to go against what Kyle Hendricks is bringing it's a banking on Carlos Carrasco Kyle Hendricks and the Cubs the way to go this afternoon. One last bet and this one's late at night we talked a lot about the afternoon games the 940s start tonight on the East Coast for the Los Angeles Dodgers and the San Diego Padres. Dodgers Tony Gosselin on the mound against San Diego's Zach Davies. The Padres are a bit of an underdog here that doesn't scare you. So it's dangerous but I am taking the Padres here to sweep the Dodgers. I just think that Zach Davies on the mound the last time he faced off against the Dodgers he only allowed one run. I think that the Padres lineup with Patees and Machado I think that they can get hot and I think they are hot and I think that they stay hot. I like the Padres being plus money here and I like them to sweep a over I don't wanna say overvalued but an over bet Dodgers team. When it came to the A's you didn't think they were gonna get swept. Today you're going with the Dodgers and you swept out of Dodger Stadium with the San Diego Padres who are very hot with the bat so the Man in Machado grants slam. Last night Fernando Tatees won the Hottest Henderson Baseball. Megan believes they keep it going tonight against Gonsil in the Dodgers. Padres are the underdog bet to make. There you have it. Those are the picks for tonight. I feel good Megan. You ready to rock? I'm ready. Not to mention we didn't bring up. I went five and two last week or five and one last week on the show. So let's make some money this week as well. Five and one last week. There's not much higher we can go. You win a lot of money when you're five and one. We're shooting for six and oh today. That's why you gotta watch this on the hurry up. Tomorrow, it's time Becky will join me as we take a look at the NBA. For Megan Nunez, I'm Greg Sosman. Thanks so much for watching. We'll see you tomorrow. Enjoy the games and we'll see you next time. Right here on the Fandil Hurry Up.


So, hi again. My name is Mansi Naware, and I work at Intel's NN-15 graphics kernel driver team. I've been on that team for about two and a half years, and today I'm going to talk about actually my very first project on the team which was DisplayPort Compliance. From the user's point of view, yes, it meant fixing the black screens with DisplayPort, which maybe it happened just now. I don't know. I shouldn't have because I have the latest kernel with the fixes. So, has anybody else experienced this before with the DisplayPort or Mini DisplayPort just a black screen? Okay. So, good. So, I guess you can relate to the problem that I'm talking about here. When I joined the team, there were almost I think 97 percent of the free desktop bugs that we had on the display side were because of the black screens or the hot plug issues and connect multiple monitors, and there's just no display. So, the goal of my project was to make the DisplayPort driver DP compliant and upstream the solution. So, let's start with the basics. So, what happens when you connect a DP cable? So, you have the DP source on one end, which is your PC and the DP monitor on the other end. So, when you connect it with the DisplayPort cable, the first thing that happens is the hot plug detect signal that the sync device sends to the source device. It's just a interrupt signal saying, hey, there's a new connection. After that, the source is going to initiate the DisplayPort configuration data register read rights, through which it's going to start reading the capability supported by the monitor. It will know the resolution supported, the link parameters that are supported by the sync device. Once it has negotiated these parameters between the source and the sync device, then it's ready to encode the data and start sending it on the actual cable. The very first thing that happens when you connect the DisplayPort cable is this negotiation sequence between the source and the sync device, which is called as the DisplayPort link training. So, yeah, the first signal is the hot plug detect signal, then the source will start the link training. First, it has to go through the clock recovery sequence, where it sends the known training data patterns to lock the clocking information on the DisplayPort receiver end. Then it's going to send another known training pattern sequence, but this time it's going to send it with the known skew between the two lanes. So, this data is used on the other end to find out the inter-lane alignment and get the mapping of how the data symbols are sent between the two lanes on the DisplayPort cable. After these two sequences succeed, the source and the sync device kind of lock a particular link rate and lane count and then they can start sending the data at that specific link rate and lane count. We say that the link is ready and that's when it will start sending the data and you see the display on the monitor. So, what was our plan for testing the DisplayPort compliance? So, the plan was to use the third-party device DPR-120, which is certified by VESA to run the exhaustive test suite, the compliance test suite, which makes sure that the driver is compliant with the specification. So, it basically acts as a reference sync device. You connect the device under test, the laptop to the DisplayPort input of DPR-120, and the DPR-120 is going to say, okay, display this specific data pattern at this resolution, and the laptop will start sending the data, DPR-120 taps the information on the DisplayPort cable, and it's going to compare that with the CRC values reference data patterns, and if it matches then, yes, it passes the test. So, a lot of these tests here try to verify that link training is going to pass in different scenarios. Like for example, if the first phase of clock recovery fails, then the DPR-120 actually is going to try to induce that failure and see if the device can recover from that and still send the data after the specified number of retries specified by the DisplayPort spec. So, the goal was to run all these tests and make sure that the driver was actually passing all those link training tests and it was able to recover from the failures. So, going back to the basics, so what was the existing state of the atomic kernel mode setting? So, what does it do when you connect the DisplayPort cable? The user space is going to form the list of parameters, the properties and send that to the kernel. Then the first step that the kernel does is forms the state of the device, it forms the state for the different DRM mode objects depending on the requested mode. This is the atomic check phase and in this phase, it's going to try and validate the mode that is being requested. So, in this phase, it will, let's say, get the 4K mode and it's going to see whether that mode is going to be supported by the hardware, by the available clock, by the link parameters of the DisplayPort cable. If it can actually support that resolution, then it will go to the commit phase. In this phase, it's going to take all the data and write it to the hardware registers. Since this is the phase where it does all the writes or the hardware update, this is where the link training is going to happen because it has to actually send the data symbols. That's when you're going to start seeing the display on the monitor. So, I thought, okay, the atomic mode setting is validating the state in the atomic check phase and it's then going to write everything to the hardware. So, because it's already validated, it should actually work and everything should just work fine. So, I thought, okay, yes, it's all problem is solved, but did we actually fix the black screens at this point? So, yeah, I ran the test suite and yes, sure that when DPR 120 tried to introduce the link training failures, the driver was not able to recover from the link training failures and it was just a black screen. So, let's see what the problem was. So, just a simple scenario again, you have the sync device connected to the source device. It sends the hot plug detect signal. Let's say it requests this mode at 60 hertz. So, the first phase is going to be the kernel is going to do, set up the CRTC, set up the pipe for specific configuration. It will start with the optimum link rate and lane count at this point and see if that supports the requested mode and configure the pipe for that specific link rate and lane count, but it hasn't actually sent any symbols on the cable. So, it hasn't validated whether it's going to be able to send those symbols on the cable if it's going to work or not. That's going to happen in the commit phase where it actually sends those training pattern symbols and it goes through clock recovery and channel equalization. What happens if at that point the link training fails, and that's when you see a black screen. So, the existing state of the driver at that time, it would just get a black screen and the D-message logs would just say, okay, error, link training failed. But there was literally no information going back to the user space or the kernel wasn't doing anything to recover from this mode failure, and that's when we were getting those black screens. So, what did we do? How was this fixed in the driver to actually be able to recover from such failures which happened only at the last stage of the atomic kernel mode setting? So, we were here, it requested a specific mode and let's say, first it tried to link train at the maximum link rate and lane count for 5.4 gigabits per second and four lanes and that failed. So, once that failed, so we introduced a new property for the DRM connector, which would indicate the status of that specific link. So, at that point, the kernel knows that link training failed at 5.4 gigabits per second, four lanes. So, it's going to immediately fall back to the next lower values of the link rate, which is HBR which is 2.7 gigabits per second and four lanes. So, first it will go down, fall back the link rate and try again and it keeps doing that until basically the link training succeeds. So, it falls back and at the same time, it's going to set the link status property to bad and then send the U event a notification to the user space saying that, okay, something went wrong in the configuration and that specific requested mode did not work. So, at that point, user space retries the mode set. It retries the mode set at the same resolution first, but then it might happen that because we fell back to the lower link rate and lane count values, it might prune the mode. So, at that point, the user space has to get the connector information again, get the new modes and then try the mode set at the next available, next lower resolution. So, at this time, the kernel gets the mode set request, it's going to go through the same phases, but now this time it's training at the lower values and the link training is hopefully going to succeed and we get a successful mode. So, this actually happens for all the combinations, it does for the link rates all the way to RBR, 1.62 gigabits per second. If that doesn't succeed then it starts reducing the lane count and it goes all the way to one lane. So, it basically tries all the combinations and keeps reducing the resolution until it can show something on the screen which is, even if it's really small resolution, it's better than the black screen. So, why was this needed? So, the basic loophole here in the atomic kernel mode setting was that the failure is always an option and it was assumed that the atomic commit phase will always pass and the mode was always guaranteed at that point. But with link training when we are dealing with the actual hardware it guarantees the requested mode. Yes, but at that point it's only checking against the GPU parameters, but not the actual physical cable. So, link training can still fail and the atomic commit can still fail. So, we do need to handle this case. So, this link training failure is asynchronous, because the link might be working and ready in your transmitting symbols, but it can fail at some point when it's up and running, displaying something. So, you need a way to asynchronously send some notification to the user space at any time. It detects that the link is not working correctly. Also, it helps because atomic allows the non-blocking commits. So, what that means is it's going to do the mode set and return the control to the user space, but we don't know whether the atomic commit has completed. So, the user space still doesn't know if it has successfully been able to display something and the atomic commit phase is successful. So, in that case, also we need some way to asynchronously notify this to the user space. So, this is how we basically tested the entire stack and made sure that the newly introduced property and the way of handling the atomic failures was actually validated through the entire stack, and the whole stack was able to recover from this mode set failure. So, we use the DPR-120 device to induce those failures in the link training. So, first it sends the long pulse, it requests a specific mode. The kernel at that point is going to validate the mode link train at a certain rate. Once it fails, it's going to fall back, set the link status property to bad and send the U event. At that time, we did make changes to both the XF86 Video Intel and the mode setting driver to actually handle this newly introduced property. So, it keeps looking at the link status property, and as soon as it sees that it's bad, then at that time it's going to try, it's going to request a new mode set at the same resolution. But like I said, that resolution might actually get pruned because now the link parameters have changed, and it might not support that same resolution. So, it sends the XRandar event up to the desktop environment, and Martin actually wrote this app AutoRandar to constantly listen to those Randar events, and so every time it gets that event, it's going to reprobe the connector, get the mode information, and then redo the mode set at the next available resolution. So, this was the way we were able to test it across the stack. All the changes are upstreamed for i9-15 as well as the X server, but I still need to connect with the GNOME KDE folks to do these changes in the desktop environment because otherwise the whole stack is not going to be compliant at this time. I also wrote a tool. It's upstreamed in the Intel GPU tools. Well, GPU tools now. So, it's a DP compliance tool for fully automating this compliance testing. It does need having DPR-120 connected to the DUT, but after that it just gets the test request, handles the test request from the DPR-120 runs the entire suite, and it's going to keep the log of what tests are passed and what failed. So, that was a good way for us to do our pre-merge and post-merge testing at this point. But one of the future steps for us is to move this whole testing infrastructure to the open-source hardware, Google's chameleon board. With that, the idea is we will be able to test it with lot more corner cases, with different types of external displays. So, we will replace the DPR-120 with Google chameleon board. We would have to move the entire compliance test suite onto the chameleon board, which is going to be a big effort because it has to be certified by Vesa to say that, okay, this is a reliable test suite that you can run and say that the driver is DisplayPort compliant. Then eventually, the goal is, once we are able to move everything to the chameleon boards, we can have that as part of our CI system, so that for every laptop with a DisplayPort, we have this connected and we always run the compliance suite. So, anything that any patch that gets submitted, it will run against the suite and we'll make sure that it's not breaking the link training. So, that's all I had and this was definitely not a one-man project. I wouldn't have been able to finish this without help from the community, from reviews from everyone. So, yeah, thanks to everyone for reviews and suggestions. Thank you. Any questions? So, what Linux versions do you talk about here for 15? So, what version does it have to fix? Oh, so it's in the 4.12 and X server, yeah. Yeah, it's in the 4.12 and X server, yeah. What's the real answer of this? So, it is not there on Valend, so that's one of the goals to actually scale the solution to Valend and even on Android Surface Linger. So, because until then, this property is going to be there, but if the user space does not look at the property and does not handle it, then it's still going to basically fail at that time. So, yeah, I'm trying to reach out to other user space communities and help out to scale this feature. So, yeah. So far, we have just ordered the Google Chameleon Boards. We have the budget for that, right? Yeah. Yes. So, but no resources are allocated to that. So, yeah, it's going to take a while, but we will work on that in 2018. Again, I would need help from the community. I know, Leutpal from Red Hat, she's done a lot of work with testing DPMST and other corner cases with hot plugs using the Chameleon Boards. So, I'm going to reach out to her and, yeah. Yeah. Anybody can order it. It's, I think it's, and replacing that, the DPR 120 with Chameleon Boards is way cheaper because DPR 120, the licensing fees are like ridiculous $5,000 or something. So, we definitely want to, so we definitely can't have more than two DPR 120s. So, with DPR 120, there's a no way, there's no way we can integrate that with CI. So, we would need a solution on Chameleon Boards. DPR 1.2 and 1.3, we haven't tested DPR 1.4 yet. So, DPR 120, they have added new tests for DPR 1.4 support or they are adding, but we haven't ran that compliance test we did. Yes. Yeah. For the newer platforms too. Okay. Thank you.


Hello, welcome everybody, in our talk about the wise ways in open source compliance, taxonomy and the tools of open source compliance. Let us introduce ourselves. My name is Greg Etchatari and I'm working as a senior open source specialist in the Nokia Open Source Program Office, and my colleague here is... Yeah, I'm Jan Jorell, I'm a student at Alta University, and I worked this summer as a summer trainee at the Nokia Open Source Program Office also. And in this talk we will discuss a bit of a taxonomy of the open source compliance check, because we think that it's very important that we have a well defined set of actions, what we are doing in the compliance check, and we will cover a bit which tools are covering which part of this process. But let's start from the really beginning. So what is the target of open source compliance check? The target of open source compliance check is to follow the license obligations of the used open source software in a product, which means that we have to know what is the list of open source software used in the product. We have to know what is the license of these open source software components, and we have to know what are the different obligations in these licenses, and we have to act according to them. So for this, the first step is to get the list of open source software, what is used in the product, which is creating the so-called bill of material. And the very difficult part of this is to get all the dependencies and all the dependencies of dependencies. I will discuss this a bit later. And then there is a second step, which is basically a decision to decide if the usage of the open source component in the given product is okay or not. Different companies have different policies on the usage of open source based on their internal business processes, but still a decision has to be made if the open source component can be used or not. And then the third check is to fulfill the obligations of the license or licenses. So let's see these in detail. So the first step is to get the list of the used open source components and their licenses. And this is a very complex step to create this full so-called bill of material. And I collected all the steps which are needed for let's say a full analysis, and for each of them I describe a bit what do I mean on them. So the first step is do a container content resolution, which means that if we are using containers and container images, we need to unpack the content of these containers. So we are able to analyze the content of the container images, which means that we have to get access to all files stored in the container images. There is an interesting fact about container images that they are using these layers in the file system. So in theory it's possible to have hidden content in the container images and some tools are discovering these hidden files, some tools do not discover these hidden files. But still we need this step to unpack the containers. And then we need to resolve the dependencies and this can happen in two levels. There is a level what I call the operating system level package dependency, which means that we use the tools what the operating systems are using. So we are using RPMs, EPT, EU, whatever the operating system has. So these tools to discover what packages are installed to the product, what we would like to ship. The other layer of the dependency resolving is the technology level package dependency resolving, which means that we use language specific tools like P or NPM or GoDep or something like that to discover what kind of dependencies the given source code what we are producing are using. So for example in case of Golang, this is the discovery of all the included Go modules and all the transient dependencies of all these Go modules. But still until this step we just or only have the list of the open source components, we do not have the source code of these or we do not have any information about the license or the copyright information of these. So we need to get the source code to run a full analysis. And for this we need the source code downloader, which basically downloads based on this information get from these different sources, it downloads the source code of the open source components. And then there is a need to scan for the copyrights and license information. So it's a tool which goes through the source code and the text licenses and copyrights information. This step can be bypassed by a different step, which is the online license checking. So there are or actually there is a database called clearly defined, which is accessible by everybody online. And this contains the license and copyright information of different open source components. So instead of scanning, it is possible to get these information from clearly defined. And there is also another optional step, which is the binary analyzer. So it can happen that we do not have access to the source code of the different components in the product. So in this case, binary analysis is needed when we analyze the binary artifact of a build process. And there's a last step that is a need for what is called forensic school analysis, which means that we scan the source code again for different code snipplets copied from other places, like from other or from any other open source projects or from stack overflow places like that. So all of these steps are needed to get the full list of open source components, their licenses and their copyright information. But then in step two, which is a bit more simple, we need to make a decision if the usage of the open source project is okay or not. And for this, we need basically two steps. So first of all, we need the software structural analyzer, which means that we need to be able to get information about how the open source software is communicating with other parts of the software. Because some licenses have different obligations for open source software statically linked to other software or dynamically linked. So that depends on these architectural decisions. And we need to analyze that structure. And then we need basically a policy engine, which makes a decision based on all of this information. And then the next and last step is to fulfill the obligations. So for these, we need basically two things. We need an obligation database, which means that we need information about what license have what obligations and practically how to fulfill these. And then we need some kind of a compliance bundle, which fulfills the obligations. This can be like, I don't know, list of the copyright holders in the documentation or including the license tax documentation or packaging code for distribution. These kinds of things. All of these steps can happen in different phases and different places in a build pipeline. So in the first case, this is happening in a totally distributed way. So each of the builds execute these steps in the scope of the specific build. And I represented compliance and legal experts here with this small figure. These information is injected somehow to the software artifacts as part of the code tree or something like that, which is like in the context of the given build pipeline. And every step is executed there and all the decisions are made based on these policies, which are basically part of the source code. The other architecture possibility is to do everything in a centralized manner, meaning that there is a centralized set of tools, which execute all of these steps. And the build pipeline just feeds information to these centralized tools and get basically a decision and the compliance bundle at the end of the handling of the compliance. And the legal and compliance persons are interacting with these centralized tools. And that is, of course, a hybrid way when some parts of this process like the compositionalizes is done as a part of the pipeline and other ways are done like the decision making and the bundle generation are done in the centralized tools. And in Nokia, we are using this third hybrid solution, so all products are doing the compositionalizes themselves based on the specific technologies that they are using, and they are uploading all the data to a centralized tool, and legal and compliance colleagues are doing their work, interacting with the centralized tool and the centralized tool is providing a result to the build pipeline and the compliance bundle. So we are using this hybrid way. Of course, it's possible to do any combinations like having only the decision in a centralized place and moving down the bundle generation to the pipeline. It's up to the decision of each company. Okay, that was the part of the paperwork, and let's hear about the actual tools, which are covering these steps. Yeah, okay, so I will talk a bit about some different compliance tools that we tested mostly during the summer and a bit what the features they bring and if they're actually any good views. Okay, but before I talk about that, I want to briefly mention some things that we looked at when selecting which tools we were going to investigate. So firstly, we wanted them to be open source, and secondly, we wanted them to be installable within a reasonable amount of time, so maybe like a couple of days max. Okay, let's dive into the tools. So the first tool that we tested was the OSS review toolkit or ORT for short, and it's an open source tool developed by HEAR Technologies, and it's a toolkit consisting of different sub-tools. So it has an analyzer tool, which can do this dependency analysis and based on source code find all the dependencies, and it works by using different technology specific package managers. So for example, if it's a Node.js project, it will use NPM to figure out all the dependencies. And yeah, then it also has a downloader tool, which uses the analyzer results to download the source code for each of the dependencies. And it's quite sophisticated, it can use also different version control tools like it to clone specific like versions of the software. And then there's the scanner tool, which does this static scanning of all the source code, and for this by default it's using the scan code toolkit, which is another static license and copyright analyzer. And so yeah, it uses that to scan all of the components and figure out or find the licenses and copyright notices. And after this, there's an evaluator tool, which can look at the scan results and apply some custom rules to basically decide if it's okay to use the software. So it has to be implemented in a Kotlin based domain specific language, so you can write the scripts that specify these rules. So for example, you could disallow using some copy left licenses or something like that. There's the reporter tool, which can generate reports in good looking human readable formats, for example HTML and PDF and so on. And yeah, each of these tools like depend on the previous one for input files, so they can be running this kind of pipeline way. And yeah, I think I didn't mention it's a CLI tool, so it can be running in scripts or on some CI CD services or whatever. Okay, up next is Turn, which is a tool developed by VMware, which is focused on container analysis and finding the bill of materials for container images. And it works, it's like a dynamic analysis, so it works by mounting the different layers of the image and then running some shell scripts inside of them to find out the installed packages. And yeah, it can also use as extensions this scan code toolkit for static analysis of all the files in the container and also this CVE binary tool for vulnerability scanning, so it can detect if there's some package that has known vulnerability. And yeah, it generates reports in different formats like HTML and also SPDX. Okay, the next tool is licensed, it's a tool developed by GitHub and it's quite similar to the ORT in its features, so it can do dependency analysis based on source code. And also using these different technology specific package managers. But it can't download the source code, so but instead it has a feature to fetch the licenses for each dependency. And based on that, you can write in a config file a list of allowed licenses and so it can check against that list if there are any licenses that are not allowed and then it can generate some reports for each component of the project in this notice format. Okay, up next is this FOSA CLI, which is very similar to licensed I think in its features. So it can also do in a similar way this dependency analysis, but unfortunately that's the only feature that or the rest of the features require you to set up an API key with FOSA.com. So you have to sign up to their services. So yeah, the dependency analysis part is like the only part that can be run without the setup, but it has features to check for also license policy violations on FOSA.com and also generate reports and things like that. Okay, up next is FOSOLOGY, which is a Linux foundation project, which it's mainly focused on scanning and reviewing, so it can't do this dependency analysis, but you can upload software to their database using this web UI. And it has two different license and copyright scanners, which try to complement each other. And then based on the results you can do some manual clearing or reviewing, so you can look at all the licenses found and even correct if there's something that you think is wrong. And yeah, so it's a web UI, but the web UI looks a bit outdated in my opinion. And finally it can generate reports in different formats. Okay, up next is software 360 antenna, which is a tool developed by Eclipse. And it can do dependency analysis using this Maven dependency tree. Or firstly, I can mention that it can be like installed as a Maven or a Gradle plugin. So if you're using Maven or Gradle, you can use it as a plugin, so that's quite neat. You can include it like in a build step. Okay, but anyway, so it can do dependency analysis using this Maven dependency tree analyzer, but that's primarily for Java projects. So if it's another type of project, you can feed it ORT analyzer results instead. And it can do download source code and licenses using this Maven artifact resolver. But again, that's primarily for Java projects. But if it's another type of project, you can use the ORT downloader. It's like included, so you can use that to download the source code. And it can check for forbidden licenses also as configured in your config file. And it can generate reports in different formats like most of the other tools. But it can also be integrated into the Eclipse software 360 platform, which is an open source software catalog app. So you can view later your results there in like a web interface and things like that. Okay. Yeah, the last tool that we looked at was this Go Licenses tool, which is a tool developed by Google, which is it can detect dependencies for Go projects. But no, we noticed that it doesn't detect versions, so that's a bit of a downside. And it has a feature to collect all the artifacts needed for license compliance. So it can figure out the licenses of all the dependencies. And based on those, it can collect the license text and copyright notices and even source code for licenses that require it. And collect all of that into a single folder. So that's quite neat. And it can also check for forbidden licenses according to Google's license classifier and generate CSV reports. Okay, finally, I've made this comparison table to kind of compare all of the tools. So up top we have the tools and some steps in compliance. So yeah, from this we can see that there's no tool that can perform all of these steps perfectly. And some are of course overlapping in their features, but yeah. And with this, we reached the end of our presentation. Thank you for listening to us. And if you have any questions, please use the conference platform to contact to us or you can just use your or contact information. With this we would like to thank you and have a nice conference.


In the name of Allah, the beneficent, the merciful, respected viewers, brothers and sisters in Islam, may the peace and blessings of Allah SWT be upon you. Today we will continue our discussion regarding women in Islamic history. Today we will discuss the life of Sayyidina Zaynab AS and the many honorable traits she possessed that have made her what Allah SWT had intended for her to be known by, and that is one of the greatest female role models to have ever been created. In one of the holiest households to have ever been created, Sayyidina Zaynab AS received enough of the knowledge and powerful traits so that she was able to follow in her mother and grandmother's holy footsteps into becoming one of the world's most powerful female figures. Being the daughter of the commander of the faithful, Imam Ali AS and Fatima al-Zahra AS, Sayyidina Zaynab AS was known as an exemplary woman of great ability, intelligence, knowledge, insight, courage and preservatives. And she used to have these holy traits to perform her divine duties to the best of her ability. If one were to closely look at the individuals who were present within the life of Sayyid Zaynab AS, one would clearly notice that out of the five holy members shown a brilliant start and it was through the traits in which she possessed, Sayyid Zaynab AS was able to manifest such great a fortitude in Karbala. Out of all of the remarkable holy female role models Allah SWT created and set out for us to learn from, Sayyid Zaynab AS is recognized the most for her great courage and never-ending patience in which she portrayed throughout her holy life. In order for one to truly understand what Sayyid Zaynab portrayed within her individuality, one must be familiar with whom she had inherited these characteristics from. Her mother Sayyid Zaynab AS was the greatest role model for the world in its entirety as she was infallible in her mind and spoke only the truth as well as infallible in her heart which had no place except for good and infallible in her life which was driven by the spiritual values that neared her to Allah. As for the traits of patience and courage we witness in Sayyid Zaynab AS, this is seen in her mother AS as she revealed her knowledge and courage after delivering her famous and holy speeches in the Prophet's Mosque defending the religion of Islam and what was rightfully hers. Following in her mother's footsteps, Sayyid Zaynab AS revealed her patience and courage as her life had always been laden with hardships and devastating losses. When Sayyid Zaynab was first born, Jibrail descended and told the Prophet peace be upon him, O messenger of Allah, from early on in life this girl will remain entangled in tribulations and trials in this world. First she will face your separation from this world, thereafter she will bemoan the loss of her mother, then her father and then her brother Hassan. After all this she will be confronted with the trials of the land of Karbala and the tribulations of that lonely desert as a result of which her hair will turn gray and her back will be bent. These powerful and devastating words were not new news to the Ahlul Bayt AS as they were all aware of the hardship Sayyid Zaynab AS was meant to face. However, it is very clear that the courage, patience and perseverance that Sayyid Zaynab portrayed on the Day of Ashura and after as she went along patiently spreading the true Hussaini message is one of the greatest and most remarkable stands to have ever taken place in history. On the Holy Day of Ashura, the amount of devastation the Ahlul Bayt AS faced cannot be put into words. The virgility of what Sayyid Zaynab AS had to witness before her eyes in terms of having everyone she loved be martyred and the most inhumane ways before her eyes is one of the most heartbreaking events to ever take place. After Imam Hussain, his family members and companions were killed. Sayyid Zaynab AS was left to protect and fight for the children. The woman and Imam Sajjar AS was very ill at the time. Yazid's army burned the tents of Imam Hussain's family and stole all of their belongings, leaving the women and children in fear and terrorized before taking them as captives to Kufa and then Damascus. This is when Sayyid Zaynab AS' role came into place as she took on the mission of reviving the Hussaini revolution after the enemies attempted to silence it and heroically defended the household's rights and did not permit the enemies to take advantage of what took place on the plains of Karbala. When Sayyid Zaynab AS, the women and children arrived in Kufa, they saw that the people were rejoicing and celebrating the shameful acts of Yazid as they were brainwashed to think that Imam Hussain AS was one of the ones who was wrong. This is when Sayyid Zaynab AS delivered her unforgettable speech which shook the city in its entirety. The sermon she delivered was so powerful it converted the glorious show of victory into a mournful ceremony where the evils of the governor, bin Yazid, were revealed. Where the evils of the governor, Ibn Ziyad, were revealed. The sermon caused for the delighted happy faces to sat in and many even began to cry. As a matter of fact, her elegant speech even boosted people's anger for the governor. In her sermon, she courageously stated, even though there was a risk on her holy life, praise to Allah and may the blessing of Allah be upon Muhammad in his progeny. O people of Kufa, you are hypocrites and deceitful. You feign to be sorry for the death of my brother and his companions. May you always shed tears. I find nothing in you but flattery, evil acts and thoughts, pride and in spite and ill will. By Allah subhanahu wa ta'ala, you deserve lasting sorrow instead of joy.  This powerful saying enlightened the minds of many living in Kufa, causing them to go against the enemies of the Prophet Muhammad. The one who was your sole refuge in the case of adversity.  This powerful saying enlightened the minds of many living in Kufa, causing them to go against the enemies and avenge for the martyr of Imam Hussein and his household, which was something Yazid feared. Sayyid Zaynab alaihi wa sallam revealed her courage as she stood like a mountain before Benziyad in Kufa already knowing that she could be killed and whatever ever plot you can, blazes are waiting for you and the hereafter. You'll be accountable to Allah subhanate ala for your atrocities. This was not only a way to reveal the inequality and inhumanity of Yazid at the time, but it was also a series of lessons for the world and its entirety to learn that standing for what is right comes with sacrifices. It is a way for us to realize what had been given up for the sake of the true religion of Islam, and shows us that no matter what we decide to sacrifice comes nothing compared to what the Ahlul Bayt alaihi sallam endured. Sayyid Zaynab stands continues as she and the holy family of the Imam Hussein are taking captive to Damascus to the place of Yazid. Once again, Sayyid Zaynab alaihi sallam delivered another sermon, once again revealing the oppression that Ahlul Bayt alaihi sallam were put through. This beautiful and elegant sermon teaches us what it truly means to love and sacrifice for the religion of Islam. This is seen when Sayyid Zaynab says, what I saw was beautiful. It was martyrdom. Although it was difficult, it was in the way of God and it was done for preserving Islam. It was the creation of an epic in the history so that the Islamic ummah knows what it should do and how it should move forward and stand firm. The brave and courageous stands of Sayyid Zaynab are many and one cannot possibly put the effect they had on history. Although Sayyid Zaynab alaihi sallam is known for the courage and perseverance, one also learns many other beautiful things from this holy figure. In narrating all of her mothers and fathers' traits, Sayyid Zaynab alaihi sallam portrays the ultimate role model for women to follow. She was known to be the caring and loyal wife and mother and raised her children the same way she was raised and the results of the holy upbringing is clearly seen as her four sons were martyrdom with Imam Hussain alaihi sallam on the day of Ashura. The short analysis of the character of Sayyid Zaynab alaihi sallam are not only very little but extremely humble compared to what she deserves. Being a member of the holiest family to have ever been created, Sayyid Zaynab alaihi sallam is not only a role model to women but to the world and its entirety. Though her stands, knowledge, eloquence, patience, and perseverance, Sayyid Zaynab alaihi sallam reveals that being a woman does not limit what one can do. Through her holy life, Sayyid Zaynab made it clear that defending the religion of Islam and revealing the truth is something that comes with great sacrifices and is one of the greatest things one can do. Thank you for tuning in and we hope to see you next time.