Blog Closed

This blog has moved to Github. This page will not be updated and is not open for comments. Please go to the new site for updated content.
Showing posts with label YAPC. Show all posts
Showing posts with label YAPC. Show all posts

Wednesday, June 24, 2009

YAPC: L1 Recap

On request, I have been asked to summarize some of the discussions we had about L1 at YAPC. We talked about L1 as a small group on Sunday during the PVMW unconference (Myself, cotto, particle plus two others), and again as a slightly larger group at Lulu's restaurant for Tuesday lunch (Myself, chromatic, pmichaud, particle, cotto, jhorwitz and three others). I will try, as well as I am able, to summarize what we discussed both times. I'm going to post most of this post also to the Parrot wiki so more then just my readers here will have access to it.

Microprocessor analogy

When you look at modern microprocessors, you see these complex instruction sets like x86. In traditional machine code, each bit in a machine code opcode travels down wires and acts as control signals to the actual circuit hardware. The problem with this is that the opcode structure becomes intimately tied to the architecture of the hardware: If you change one, you need to change the other (because different bits now need to travel down different wires to different circuits), and then things built on top break: Your assemblers now need to output new machine code, your pre-existing binary executables are no longer valid, etc.

In addition to this, some machine code words are very complex. x86 has hundreds of operations, and each operation can use a large number of addressing modes. Combine these together and you get hundreds, maybe millions of permutations. A single op, depending on the types of the sources and the destinations can have a number of distinct behaviors. add ax, bx is pretty far different from add [ax], bx, which is different from add ax, [bx], etc. Having to decide what behaviors to activate for each opcode from a large set of opcodes is hard to do.

Reasons for L1

Consider the idea now of converting those "high-level" machine code words into "low-level" microcode where each microcode operation is small, simple, atomic, and fast. Because each of these lower level instructions is more simple and atomic, they are easier to use in automated translation and with JIT.

Right now we have a lot of our critical code paths are written in C, and a lot of them are written in PIR. It's immensely expensive moving data between PIR registers and the C system stack to call functions in each language, and we are incurring that cost very frequently. In addition, we lose out on lots of opportunities because of the boundary between the two: We cannot easily optimize, we cannot easily inline functions, we cannot easily profile (we can typically profile C or profile PIR, not both at once), etc.

L1 is an abstraction that allows us to insert a new abstraction layer into Parrot to help reduce algorithmic complexity on the global level and give us more opportunities for optimization then we have in the PIR/C combination so far. Other projects like TraceMonkey are using cool optimization techniques such as polymorphic inline caching (which Parrot has a basic and messy implemenation of now, which has been deprecated), trace-based JIT, and context threading. These optimizations together are producing some stunning benchmark results for leading-edge javascript interpreters.

What L1 will look like

So the question invariably arises, what will L1 look like to the average programmer? Will it look like some grizzled assembly language? Will we be forced to reimplement large swaths of Parrot in some freaky home-brewed assembly? The answer, I think we are all pleased to consider now, is no. We have skills and background and tools for programming language design and we have several existing parsers for languages that we could utilize. One specific example of things that we could do, as mentioned by pmichaud, is to write core PMC types in NQP. It would have to have some extensions to allow direct register addressing, definition of vtables, and definition of attributes which may be references to arbitrary C data structures. Also, it would have to have a new backend which outputs L1 bytecode instead of PIR->PBC as PCT normally does now. We also have a new language in development by Austin Hastings called "Close", which is a very low-level language based on C that will eventually have all the capability of PIR (and therefore L1), but with familiar C-like syntax.

What this means is that there won't be a human-editable form of L1 bytecode, because we can write it in NQP, Close, or even other high-level languages which currently run on Parrot (although we will want to find one with a small runtime, or even a variant with no runtime). The short answer: L1 looks like any language we want it to look like (but probably Perl6-like in NQP or C-like in Close).

Next Steps

So what are the next steps? Well, pmichaud suggests that a good way forward is to actually start prototyping some key core PMC types in NQP now, so we can get a feel for what syntax and semantics we will actually want and need. Once we know what our needs are, we can start modifying NQP to support our new syntax for dealing with these things.

With the synatx requirements set, we can then modify the NQP parser to output normal C for now, and eventually redo the backend to output L1 instead.

chromatic suggests that with our current plug-in architecture we could create a library of L1 dynops, and create an NQP backend to target those. Once we have core PMCs as written in NQP executing only on L1 dynops, we can start the rest of the conversion process.

Here is a quick checklist:
  1. Write core PMC types in NQP, making careful note of what syntax we need to add to support all existing operations. Good candidates for this prototyping would be Integer, ResizablePMCArray, and Hash (which is soon to be renamed to AssociativePMCArray).
  2. Write existing PIR opcodes in NQP, making careful note of what syntax we need to add to support existing operations.
  3. Write a dynop lib for L1 ops
  4. Modify the NQP compiler to have all the necessary syntax from steps #1 and #2, and to output only those L1 opcodes created in step #3.
  5. Modify IMCC (or PIRC, depending on time frame) to output L1 or PBC, depending on some kind of switch
  6. Move L1 opcodes into the core instead of being a dynoplib.
  7. Make the final switch. All ops and PMCs get compiled from NQP into L1 during the normal build process (possibly using a bootstrapping step)
  8. Optimize like rabid ferrets.

Monday, June 22, 2009

IO work at YAPC.

The sysadmin heritage of Perl has really been shining through here at YAPC, a lot of our newcomers are really interested in process management and interprocess communication topics. Unfortunately, this seems to be an area where Parrot is particullarly weak. Luckily I managed to get a pretty good idea of the kinds of things that the workshop attendies are interested in, and even picked up a few good ideas about implementation. We had an "unconference" yesterday which is so awesome I would like to do it again some time. Earlier this morning I talked to a group of interested parties about the state of Parrot's GC, and may have found a volunteer to help implement the concurrent GC core I've been planning. I also did a little bit of talking about L1 to introduce the idea to people who haven't been following my blog (everybody on the planet besides myself). I'm just finishing up a session about IPC now, and have heard a lot about the things that people want, and heard lots of cool ideas about how to implement them.

I've been doing a lot of hacking on the io_cleanups branch, which I started two days ago. It was started with the goal of cleaning up the IO system a little bit and better integrating Sockets and Pipes. It's gone a little bit beyond that now, and I'm getting pretty close to having a cool result to share. I posted a patch to the IRC chatroom in hopes Infinoid would work his magic and tell me what I'm doing wrong. What I need to do is hunker down with the debugger and see where my stuff isn't working correctly, I just haven't been able to focus on it for long enough because of the festivities. I'm sure the problem has to do with my mishandling of the buffering code somewhere.

The gist of the work in the branch is this: The IO system should sanely handle all it's PMC types (FileHandle, Socket, Pipe, StringHandle), and handle them in a way such that they are subclassable from PIR. Currently we don't even have a separate Pipe type in trunk yet. Infinoid sent me a patch to add Pipes, and once I get past my current set of issues I will add it into the branch.

In order to make this all work, I changed the Handle type (which had been a mostly-useless parent type of all the IO PMCs) into a delegate type that implements all the non-subclassable attribute types that FileHandle used to use: the low-level file descriptor, the output buffer, etc. So now, FileHandle does not extend Handle, instead it has a Handle PMC as an attribute. Initially I ran into an interesting memory corruption problem where Handles were being destroyed before their parent. When FileHandle was destroyed it tried to flush it's contents to the Handle (which had already been garbage collected), and hilarity ensued. To get around that problem I moved all the buffering logic into Handle, which means any other PMC types that delegate to Handle (specifically Pipe seems like a good candidate for this) will get to have buffering for free if they want to use it. There are still some kinks to work out with this method, but once I get the implementation working it will be easier to get feedback from people.

In other YAPC news, Austin Hastings is working on a very cool C-like language compiler called Close. Basically, it's C-like syntax (curly brackets, if/else/for/while, etc). It looks to be on the same kind of level as NQP (low complexity, no runtime, good for writing PIR-level stuff that's not in PIR, etc). It really appeals to me because it's essentially a familiar syntax layer over PIR, which I find can be very tedious to write large things in as-is. He says he has a 0.1 release he's going to make public sometime soon, and I'm looking forward to that.

I talked to Patrick yesterday about my AIO plans, and he suggested I speak up about it on #perl6 to get some use-case information there. Obviously I don't want to tailor the work directly to Perl6's needs, but a flexible-enough system should satisfy them without too much wrapping and layering. Unfortunately the IO Synopses isn't entirely finalized, and there are a lot of things up in the air still. My AIO implementation, if well-enough received, could play a part in influencing that document.

Also, I MET LARRY WALL. HE WAS IN MY CAR! It was like nerd nirvana. I did, fortunately, manage to contain my school girl giggles and get us to the arrival dinner without making a complete ass of myself. Awesomeness.

So that was my Sunday at YAPC. It's now Monday morning and I'm looking forward to a full day of meeting people, watching cool presentations, and hacking hacking hacking. More blog posts to come, I'm sure.

Saturday, June 20, 2009

YAPC: Day 1

Wake up at 3am. Get in the car, drive 5 hours through the pounding rain. Get lost on CMU's godforsaken labyrinth of a campus. Finally, a local student showed me how to get to the PVM workshop (I think he had to answer the riddle of the sphinx first, I didn't see).

But here I am, and it's kicking ass. Already I've met cotto, particle, pmichaud, Util, kid51 and a whole bunch of new faces. I've seen some great presentations (all by pmichaud, I missed the earlier ones by particle) and I've gotten a lot of good hacking done already.

Infinoid was digging through the threading code and managed to plug a 62MB leak from the threading code. Spurred on by that, I made a few small cleanups to the GC and PMC reuse code, and then started getting to work on the io_cleanups branch. The task on the front burner right now is getting sockets optimized away from unnecessary PCCINVOKE calls like we did for FileHandles and StringHandles in the io_rewiring branch. I also want to get working on Pipes too. In fact, it was this pipe work that clued Infinoid in to the problems in the threading code in the first place. Hopefully we get moving forward with that soon.

So the threading system needs a lot of work, and I may push that into my task queue in the not-so-distant future. I'm sure I'm going to have to do some refactors and fixups on the road to AIO, but I will tackle that when I get there.

I'm watching cotto do some awesome work on the pmcc (the PCT-based utility to parse PMCs). I can't really help with that so I'm just an enthusiastic spectator for now.

Several of the attendees are giving Parrot and Rakudo a workout and are filing tickets and patches. I look forward to digging through some of those later, if nobody beats me to them.

A good start to the conference today, I'm looking forward to the next 3 days here.

Sunday, May 17, 2009

YAPC::NA

It's official, I'm going to YAPC::NA this year. I had been planning on it for a while, but finally this morning I managed to buy my ticket and reserve my room.

I reserved a room for Sat, Sun, and Mon nights. I'll be coming home Tuesday afternoon. I'm going to try like hell to get there by 9AM so I can make the whole PVM workshop. It will be cool to finally meet some of these people!

I'm going to be driving from Philly to Pittsburg, so in the unlikely event that somebody else wants to carpool let me know.