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 GSOC. Show all posts
Showing posts with label GSOC. Show all posts

Saturday, August 21, 2010

GSoC Threads: Chandon's Results

The pencil's down date for the 2010 GSoC program has come and gone, and now we're starting the process of sorting through the rubble and seeing what all got accomplished this summer. I have been purposefully trying not to provide too many of my own status updates for Chandon's project this summer, instead wanting him to post his own updates as he went without me getting in the way. It's his project after all, and I wanted him to get all the credit for all the good work he was doing.

The project is now over, and he's posted a nice final review of what he managed to accomplish this summer. While it isn't everything that he mentioned in his proposal, it still is quite a nice step in the right direction and a lot of the necessary framework is now available to bring threading to Parrot in a real and usable way.

So what did he manage to do? In his branch there is now a more-or-less working implementation of green threads, which means Parrot is getting onto the same level of capability as modern Python or Ruby implementations. You can schedule multiple independent tasks to run and, while they cannot run truly in parallel on separate OS threads or even on multiple processor cores, you can get the illusion of concurrency. It also gives you the ability to run multiple tasks together without having to explicitly schedule them one after the other, or having to manually switch back and forth between them. In a later post I may go into some detail about how this all works, and how it can be used by programs.

This is a pretty significant step forward, and once a few of the final nits get worked out I think we will be able to merge this into Parrot trunk and start making use of the new functionality immediately. However, green threads is only one half of the promised "hybrid threads" that Chandon's proposal hoped to achieve. The other half is the ability to run Parrot code in true parallel on separate OS threads. This was the larger part of the project and definitely the more difficult piece. Today I would like to talk a little bit about why it didn't get done, and maybe motivate some people to look into help completing the work as we move forward.


Let's take a look at a small snippet of normal object-oriented code:

foo.bar();
foo.bar();

Extremely simple, we have an object "foo" and we are calling the "bar" method on it. In a very naive staticly-typed language this would be a simple operation. The compiler would determine the type of foo, calculate the location of the bar routine in memory and would simply call that address twice. This would be extremely fast to execute too, which everybody likes. This would basically be converted to this low-level pseudo-code:

call bar(foo)
call bar(foo)

Now let's move up to a slightly more complicated example: a statically-typed language which allows subclassing and method overriding. Now, the compiler doesn't necessarily know which function in memory corresponds to "foo.bar()", since foo could be of type Foo, or of type FooSubclass, or even FooSubSubclass, and the location of the appropriate bar function would change with each different type. However, for each type, the value of bar does not change. It can be overridden by subclasses, but it cannot be changed for the class itself. Now, the compiler needs to ask foo to get the appropriate method first:

method _bar = get_method(typeof(foo), "bar")
call _bar(foo)
call _bar(foo)

Assuming foo does not change type inside the call to _bar, this code works just fine. Next let's look at a more complicated example still, the case of a dynamic language like Perl or Python. In these languages the class MyFooClass is an object of type Class, and foo is an object of type MyFooClass. Also bar is not a compiled-in constant property of the Class, but is instead a mutable property of it. Inside the call to bar, maybe we change the definition of bar itself inside the class object. Likewise, the definition of routines like "find_method" inside Class can change. Accounting for all this dynamicism,  our code changes to look like this:

class fooclass = find_class(foo)
method _get_method = find_method(fooclass, "bar")
call _bar(foo)
class fooclass = find_class(foo)
method _get_method = find_method(fooclass, "bar")


call _bar(foo)

Keep in mind that everything can change inside each call to bar. We can:

  • Modify the inheritance hierachy of MyFooClass to add or remove parent classes
  • Add or remove methods in MyFooClass, and any item in it's inheritance hierarchy
  • Add or remove methods on the object foo itself (like in javascript where foo.bar = function() {...})
  • Change the class of foo
Let's bring this back to the idea of threading before I go too far off topic. Every time we call a method, or attempt to access a field on an object, we need to look those up in the associated Class object first. Those Class objects need to be global, because all code on all threads need to be able to lookup methods on any object, because we can pass objects between threads and we need to be able to work with them.

If classes are global, and need to be accessible from multiple threads, we inevitably run into the idea of contention: If one thread is changing the definition of foo.bar() at the same time that another thread is attempting to look it up, the thread doing the reading may end up with incomplete, corrupted, or incorrect information.

Global data is the enemy of good multithreading. Global data is a necessity for highly dynamic object systems like those supported by Parrot. Ergo, multithreading on Parrot is hard.


Look at all the global data in Parrot: there's the interpreter object itself, the packfiles, the list of Classes (and the methods/properties that they contain), the list of Namespaces (and the global values they contain), the context graph (and the contents of all registers in those contexts), the opcode table and the MMD signature cache. This is a hell of a lot of globally-available data, and we're going to need to find a sane way to limit corruptive concurrent access to these things. Not only that, but if we have to lock every single access to a global value, which means we need to obtain a lock every time we want to do a method call, our performance is going to be terrible.

By convention I think we can all agree that things like the opcode table should really not be modified when we have multiple threads running. But it's harder to make such a convention that class/method definitions should be treated as constant when multiple threads are running.

What we can do to alleviate some of the performance problems is to create short-term caches for things like Classes and Methods in local threads, with the understanding that without explicit synchronization, the exact ordering of read/write operations between threads cannot be guaranteed and can be scheduled for maximum benefit. If the relative execution times of two operations on separate threads cannot be guaranteed, then it makes no difference to functionality for the user whether those operations happen at random times with respect to each other and whether Parrot manually orders them to improve caching.

Think about it this way: We have two threads, one is writing a global value and one is reading it. These threads are operating in true parallel on two separate processor cores. If we run this program a million times, sometimes the read will randomly occur before the write, sometimes the write will occur before the read, and sometimes they will happen at the exact same moment and cause corruption. Depending on a simple matter of random timing, we could get three very different results from our program. Now, if Parrot implements a heuristic that if a write and a read happen within a very short period of time, Parrot will manually order them so that the read occurs before the write. And, if the read always happens before the write, maybe we don't read at all, but instead use a cached version. Then, only when the write has complete, we update the cache.

Another thing to think about is that we could disallow direct lookups of data in global variables, and give each thread a local copy of global values. Considering the principal I mentioned above, we can be a little bit liberal with the way we handle writes and reads. If a thread modifies its copy of a Class, those changes could be propagated to a global reference copy at a convenient time, and then propagated down to the local copies later, only when it's convenient to do so. Remember, if things are happening at random times compared to each other, it makes no substantive difference to the thread whether it's copy of a global variable is exactly up-to-date or whether it's a little bit lagged behind. That is, the reading thread doesn't know whether the writing thread had a legitimate delay before writing, or whether Parrot manually scheduled the write at a different time.

To get a complete Hybrid Threads implementation in Parrot like what Chandon was envisioning, we are going to have a few steps to take:
  1. We have to break the Interpreter structure up into two parts: One which is truly global and contains data which all threads need, and one which is local for each thread and contains data that the thread needs. The local interpreter may contain a cache or a mirror of data in the global interpreter.
  2. We need to come up with a good sane scheme (which will likely consist of both technical solutions and programmer conventions) to manage access to global values
  3. We need to come up with a good sane scheme for sharing values between threads.Creating a local variable and passing a reference to it to another thread essentially turns it into a global variable and opens up problems with contention. We need a good way to manage this without slowing everything down.
All of these problems are solvable, and if we put forward a concerted effort we could have a decent hybrid threading system in Parrot within the next few months. We almost have a complete working Green Threads system ready to merge now, and hopefully that will be enough for our users while we get the rest of the details of the hybrid system worked out and implemented.

Friday, April 9, 2010

GSoC: The Contenders

The GSoC applications deadline came and went today at 19:00 UTC, and we have received quite an impressive crop of proposals from prospective students. I don't know how many slots Google will give to the Perl Foundation, and of those I don't know how many will be devoted to Parrot. However, even if only a few of the proposals we received get final approval it will be a great year for Parrot. Some students did submit multiple applications, and at least one student that I am aware of also submitted applications to other organizations, so even under the best circumstances we won't be getting all of the projects below approved and started.

Anyway, I would like to briefly describe the proposals we have received. I can't go into too much detail because we're entering a period of feedback and revisions, but I can give the gist of what has been proposed.

GMP Bindings for Parrot - Robert Kuo

Robert, better known on IRC by the handle "bubaflub" has been a Parrot contributor for a while now. He has submitted two proposals to Parrot, both of which look quite interesting. His first proposal, proper bindings for the venerable GMP library, is related closely to some of the rantings and ravings I've made previously on this very blog.

There are two premises behind this project:
  1. The BigInt and BigNum libraries don't really belong in the Parrot core distribution
  2. The GMP library has a large amount of power and utility that these two PMC types don't even begin to expose
Another big benefit here is that GMP bindings can be quite intensive for a new runtime, so if they are done properly in Parrot they could be made immediately available to all languages running on Parrot for free.

A PAST Optimization Framework for Parrot - Tyler Curtis

Tyler, "tcurtis" on IRC, is a Parrot newcomer. He originally showed some interest in my Immutable Strings project idea, but has since been steered in the direction of adding an optimization framework for PAST. Personally I'm happy he made the switch.

This is another project that I've discussed at length on my blog, and I'm very happy somebody has taken up the challenge of it. A robust and extendable optimization framework would allow other people to quickly and easily write new optimizations. The framework is much more important in this regard than any individual optimization is. Of course, the proposal is also sort of open-ended: Once the framework is in place, Tyler can devote his energy to adding new optimization stages to it from an endless list of possibilities. For this reason, this is one of those projects where we won't be asking "when will he finish?" , but instead we will ask "how much will he complete before time is up?".

The real power here is adding the optimization framework to PAST, which many (though not all!) of our compiler projects use. In this way, optimizations added once can be immediately used by several compilers. Write once, make faster everywhere. It's quite a compelling project for the performance-weary among us, and it looks like chromatic is quite keen to mentor this one if it gets accepted.

Hybrid Threads for Parrot - Nat Tuck

Threads are another huge issue in Parrot. Our current threading system, while technically "existing" is so messy, bug-ridden, and  lousy as to be essentially unusable by our various projects. I've said on a number of occasions that Parrot can't really call itself "Production Ready" as our 2.0 release tagline was supposed to be until it has the scalability and performance improvements that a robust threading system provides.

Nat Tuck, "Chandon" on IRC, was another person originally interested in Immutable Strings, but has since submitted his application to revamp the threading system in Parrot. It's hard for me to say any other project has the same potential for reward, but it's also hard to say that any other project matches this one in terms of complexity. It's ambitious, to say the least.

Threads are an extremely esoteric area of infrastructure development, similar to GC. When they work, they just work and nobody even thinks about them. Your software just "scales" the way people need it to. Plus, anybody can write threading code, but it can be extremely difficult to do it correctly. That's why Parrot getting it's part right is of utmost importance.

Nat's general idea is to use a small number of OS threads to host a large number of discrete tasks and virtual "green" threads transparently. He's also looking into fixing some of the bugs in cloning interpreters that stymie the current threading system and would make implementation of the new system more difficult.

Improvements to the NCI System and LLVM Stack Frame Builder - John Harrison

John Harrison, also known as IRC regular "ash_", has submitted an interesting and extremely pertinent project proposal for an improved NCI system. The title mentions LLVM specifically, but he's also looking at variants using libFFI. He wants to build a pluggable system with multiple available dynamic frame-builders, and Ahead-Of-Time compliation of frames to save runtime effort.

This project isn't as large or ambitious as some of the others, but in return comes higher probability that the system will be polished and thoroughly tested for robustness by the end of the summer. Massive improvements to the NCI system would also provide major benefits to projects writing library wrappers, like some of the other GSoC projects are doing.

Chance of success for this project is high, and there are clear benefits to Parrot in having this feature.


Implementing an Instrumentation Tool for Parrot VM - Muhd Khairul Syamil Hashim

This project came completely out of left field and is the only one that I never suggested on my blog ahead of time. It's also the only project proposal that came to us with working proof-of-concept code, and the results of that small example already have some of the Parrot developers imagining of all sorts of fancy long-term uses.

Muhd, "Khairul" on IRC, is planning a system of hooks and callbacks in Parrot that would allow one interpreter to attach to another interpreter at runtime and harvest information about the system as it executes. By adding the appropriate hooks and writing the correct handling routines, we could end up with all sorts of great tools, such as profilers, analyzers, debuggers, etc. And the best part is that we gain the ability to implement all these fun tools in PIR or even another HLL, not in C like some current tools use.

You don't have to think about it for long to understand the benefits of this project: Identifying code hotspots and bottlenecks, analyzing PMC usage patterns, tracking and mapping control flow, and the list goes on. We may even get to a point when we can replace Parrot's current debugging, tracing, and profiling runcores with this single tool and a variety of different PIR programs. Quite fun to think about.

NFG and Single-Representation for the Parrot VM - Daniel Arbelo Arrocha

Daniel, everbody's favorite "darbelo" from last year's GSoC fame, has proposed two projects this year. The first is an attempt to implement NFG, a new normalization form for Unicode text strings. The benefits for NFG are a perfect one-to-one mapping between a character and it's underlying representation. This in turn can lead to some significant simplifications in the code of Parrot, and some proposed speedups as well.

NFG is one of the few points in the Parrot design spec that has never even been prototyped in working code, that I am aware of. Everything else has at least been given prototype treatment, but NFG remains nowhere to be seen in the actual codebase.

Daniel's proposal is to implement NFG in a testbed so that it's performance can be compared to the current string system. If it is a benefit (and we all hope it is!) we can merge it into trunk and start a new era of strings in Parrot. If not, we can continue development on it until it becomes better, or even scrap it entirely.

Parrot on RTEMS - Daniel Arbelo Arrocha
Parrot on RTEMS - Robert Kuo

We had two submissions from prospective students with the exact same name. Both darbelo and bubflub have been inspired by dukeleto's work in the area and have proposed to work on the RTEMS port of Parrot. A major portion of this work will be improvements to the cross-compilation capability of our current configuration and build system, improvements which will have many benefits outside RTEMS. In addition, these two are proposing to help improve the operation of Parrot on RTEMS.

As far as I am aware, this submissions were both duplicated to the RTEMS people as well, so even if one of these proposals get accepted it's possible that the student will actually be working with an RTEMS mentor instead of a Parrot one.

In both cases, I think the alternate proposals for both students look a little more desirable (darbelo's NFG proposal, and bubaflub's GMP proposal), but I've never really used RTEMS so I'm probably biased. I wouldn't definitely not do any crying if one of these "Parrot on RTEMS" projects got accepted, however.

GSoC Deadline Approaching

darbelo: less than 9450 seconds to 'SOCKHOP' deadline. Everyone panic!
moritz panics 
 
 

Wednesday, April 7, 2010

GSoC Proposal Deadline: Friday

ATTENTION PROSPECTIVE GSOC STUDENTS!!

The deadline for proposals is this Friday at 19:00 UTC. Please submit your proposals soon, even if they are not complete: you will get feedback and opportunity to revise and update the proposals. If you have multiple projects and cannot decide which to submit, submit all of them and we will weed them out later.

Whatever you do, make sure to submit your applications before the deadline or you will be disqualified!!!