Exceptions in Predicates

Today, I finished going through the simple mistakes that Bill had found in my thesis. There still are a lot of comments to address; he really gave me a lot of feedback. Thanks, Bill!

One comment that was particularly important was the question: “What happens if an exception is thrown in a predicate?” I never thought of that. Up until now, the exception would unwind the stack and terminate the program. That’s probably not what the programmer wants, though; generally, I designed the predicate checks to be as invisible as possible.

An exception in a predicate should be treated as an error, but it’s a particular kind of error: An error in the code that is there to check the behavior of the program! What I did this afternoon was add a try { ... } catch(Throwable t) { ... } block around every predicate check. If an exception is thrown, then a different log method is invoked. The exception is noted but consumed, and program execution continues.

Share
Posted in Concurrent Unit Testing, MS Thesis | Leave a comment

Print This Post Print This Post  

Timing an Interpreter in Java

The last two days I’ve helped Walid with one of his projects. He argues that staged interpreters, i.e. interpreters in which some of the work is done before runtime, drastically outperform simple interpreters, and has strong evidence for this claim. However, some people have been saying that the advantages of staging disappear when the interpreter is optimized using a JIT compiler. Walid asked me to help him show that his claims are true by writing an interpreter in Java and timing programs interpreted by it and programs that correspond to the staged versions.

While this is conceivably possible that JIT compilers make staging unnecessary, anyone who has written an interpreter with today’s compilers knows that the optimizations a JIT compiler can make are on a far lower level of reasoning. Up until about eight years ago, when I was still involved in game development, I wrote assembly code by hand and often won against the compiler; nowadays, I don’t bother with assembly. On the small scale, at the assembly language level, compilers typically outperform anything I could write by hand. But compilers still cannot prevent me from computing something in a profoundly stupid way; it’ll just be a slick, optimized profoundly stupid way. Compilers have not made optimization by humans obsolete, they have only raised the level at which humans need to think.

The program wasn’t hard to write; it was probably easier than the interpreters written in COMP 311. Since we wanted the Java interpreter to correspond as closely as possible to an OCaml interpreter that Walid had already used for timing, some structures were a little bit peculiar.

The resulting program also feels like a weird blend of object-oriented, functional, and procedural programming, but I was gunning for similarity and simplicity. For example, everything is contained in one big file, with nested classes of course. Many helper functions are static, but since I don’t think I’ll extend and override them, making them dynamic and having to use an instance seemed unnecessary. Finally, I used arrays; I initially wrote a version with a functional first-rest-style list and a visitor pattern, which allowed me to imitate the OCaml match more closely, but I decided creating the lists was too verbose and could actually be seen as “non-traditional Java style” and used to dismiss the timings.

Right now, I believe the interpreter is very close to standard Java usage, and even though I didn’t profile or try to optimize it, I don’t think there is a lot of bloat. The only thing that may be non-standard is the environment: I build a chain of function objects using anonymous inner classes that check for the variable name and return a value if it matches or recur if it doesn’t. Traditional Java programmers would probably have used a java.util.Stack.

Anyway, I need to get back to thinking about schedule generation and to making corrections to my thesis. I just noticed that many of my references (apparently all journal articles) are missing the title of the article; they only have the title of the journal. I guess I’m doing something wrong with bibtex.

Share
Posted in Concurrent Unit Testing, MS Thesis, Research | Leave a comment

Print This Post Print This Post  

Topological Sort

Following Corky’s suggestion, I’ve been trying to view the whole thing more as a graph problem than a combinatorics problem. I still think generating permutations would be the most efficient way, but I can’t figure out how to limit the generator to just legal schedules: If I just generate all permutations, I might schedule a thread before it has been forked, or after it has been joined and is therefore presumed dead.

Just approaching it as a graph search problem, e.g. depth-first, doesn’t seem to be enough, though, because we’re not interested in just ONE way to cover the graph, we’re interested in ALL ways to cover the graph. So I’m still trying to combine graph algorithms with permutations.

One way that I might to is collapse the graph as much as possible, i.e. remove consecutive nodes with just one inbound and one outbound arrow. Then I could run a topological sort to figure out in which order the forks and joins need to happen.

Maybe from that I can even figure out which threads I need to schedule concurrently.

Of course, on the other hand, I can still generate all possible permutations and then remove the permutations that violate scheduling protocols.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Expensive Textbooks

I really need to use the library more, textbooks are just so cripplingly expensive, and since the topics they deal with usually aren’t all that central to my research, I wouldn’t look at them very often anyway. I just have a little bit of a “book fetish”; I like to own books.

Here’s the book I would like to look at now: “Graphical Enumeration”, by Frank Harary and Edgar M. Palmer. It’s the most expensive book I’ve come across so far: At $295, it costs more than a dollar a page.

The worst pricey book experience I’ve had was due to the Rice course RELI 101: The professor decided to change books the semester I took it, so I couldn’t buy a used book. The new book was a special-print book that didn’t even have an ISBN. I think it cost about $120, I had no real interest in it, and because of the way it was written — it as an epistemology without any interpretation — I didn’t understand it at all. At the end of the semester, the prof decided the experiment had failed so he switched back to the old book, so I couldn’t even sell my copy.

Share
Posted in Concurrent Unit Testing, Ramblings | Leave a comment

Print This Post Print This Post  

Ahead of Time Announcement: From July 26 to July 31 I’m Gone!

Diana had booked us flights for Comic-Con. I rarely read comics, but I’m sure this could be exciting for me too! And the main thing is that Diana and I get away for a while, and I’m also looking forward to meeting Diana’s Brother and his wife. I haven’t been in California since 1999. It’s been a while.

I’ll probably bring my MacBook, though.

Share
Posted in Uncategorized | Leave a comment

Print This Post Print This Post  

Paperful Writing

The last three or four days I’ve done most of my reasoning on my trusted old hardcover checker lined notebooks. It’s somehow still easier to erase your mistakes there, and to draw arrows from one point to another.

I came up with many wrong models, but I think I’m getting closer. I’m scanning my pencil drawings to help my bad memory, though.

In the last few days I also fixed (or at least patched) a bug in DrJava: When Java 6 was being used to run DrJava and tools.jar was not on the class path, the wrong tools.jar was picked. The code to find the right tools.jar file was recently refactored, and large pieces of my code, mainly code to look inside the tools.jar to find the exact version and a dialog box that exactly explained the problem with mismatched JVM/tools.jar versions, were commented out. The code looks a lot nicer now, but the refactoring was buggy.

I think this might have been a step ahead for the developer but a step backward for the user.

Share
Posted in Concurrent Unit Testing, DrJava | Leave a comment

Print This Post Print This Post  

Independence Day

Happy July 4th, everyone, whatever that means. Somehow, contrary to my previous plans, I again ended up at home, alone, by myself. But I really don’t mind. This way, I can listen to my music (for grilling typically some kind of classic rock, like “The Who” or “The Rolling Stones”), eat my food (burgers and a NY strip today), drink my beeer (Becks for sentimental reasons) and just really relax. And I can have my notebook out on my balcony with the food and the beer and the music without feeling bad about it.

But this way, I can also digitize Bill’s comments on my thesis and see if I can even read them all. But now it’s food time.

And after that, I’m going to do the most patriotic German-American thing possible on Independence Day: watch “Independence Day” ;)

Share
Posted in Concurrent Unit Testing, MS Thesis, Uncategorized | Leave a comment

Print This Post Print This Post  

Need join Synchronization Point

I just wrote a test program, basically something like the A-B-C program in the previous post, and recorded the schedule with debugging information. An interesting part is this:

// give ForkJoinTest$B (a Runnable) instance unique object ID -478
0 8           0 sample.schedule.ForkJoinTest$B.
0 6           0 sample.schedule.ForkJoinTest$B.
0 7        -478 sample.schedule.ForkJoinTest$B.

// give Thread instance unique object ID -479
0 8           0 java.lang.Thread.
0 6           0 java.lang.Thread.
0 7        -479 java.lang.Thread.

// give thread unique thread ID 9
0 11           0 java.lang.Thread.
0 9           0 java.lang.Thread.
0 10           9 java.lang.Thread.
...
// increment thread and object IDs
0 3    13249998 java.lang.Thread.nextThreadNum
0 1    13249998 java.lang.Thread.nextThreadNum
0 2    13249998 java.lang.Thread.nextThreadNum
0 3    13249998 java.lang.Thread.nextThreadID
0 1    13249998 java.lang.Thread.nextThreadID
0 2    13249998 java.lang.Thread.nextThreadID

// start thread with unique object ID -479
0 3        -479 java.lang.Thread.start
0 1        -479 java.lang.Thread.start

9 4           0 java.lang.Thread.start()
// user thread with id 9 started; 2 remaining
...
0 2        -479 java.lang.Thread.start

Using the 0 10 9 synchronization point, I can tell that an instance a thread with thread ID 10 has been created. Later, the 0 3 -479 tells me that the thread with object ID -479 is being started. Right after that, there is the first synchronization point in then newly started thread, 9 4 0, a special synchronization point that I insert. I can treat anything before that point as prefix where thread 9 should not be scheduled.

I should make it easier to correlate thread ID 9 and object ID -479, although I think the object ID may not strictly be necessary; the 9 4 0 specifically marks Thread.start. I also definitely need a special synchronization point for Thread.join. Right now, the log does not indicate what thread is being joined (dying), only which one is doing the joining (waiting):

9 3          -1 java.lang.Thread.join
9 1          -1 java.lang.Thread.join
9 2          -1 java.lang.Thread.join

The part of the schedule above also illustrates the three-point nature of synchronized blocks right now. I added the TRYMONITORENTER synchronization point (3) so the scheduler can halt before the monitorenter opcode is executed, potentially blocking the thread, and to allow the deadlock monitor to detect cycles before they actually occur. However, as Corky has already pointed out once, splitting up TRYMONITORENTER and MONITORENTER in the schedule is problematic. If I have two threads that both try to lock the same object, a naive schedule generator could easily generate the following schedule:

0 1        -100 ThreadA.run // thread 0 locks object
0 3        -100 ThreadA.run // thread 0 tries to lock object

The sequence MONITORENTERTRYMONITORENTER just doesn’t make sense; acquiring the lock implies trying to acquire it. This suggests that as part of the schedule, I should omit TRYMONITORENTER. (@About an hour after I had gone to sleep, I realized that the above is utter garbage, of course, since the synchronization points within a thread are not permuted; therefore, a MONITORENTER never occurs before the TRYMONITORENTER.@) Furthermore, even splitting up a synchronized block into MONITORENTER and MONITOREXIT has its problems. Again, a naive scheduler might generate the following invalid schedule in which both threads 0 and 9 hold the lock at the same time.

0 1        -100 ThreadA.run // thread 0 locks object
9 1        -100 ThreadB.run // thread 9 locks object
...
0 2        -100 ThreadA.run // thread 0 unlocks object
9 2        -100 ThreadB.run // thread 9 unlocks object

For a monent I thought that releasing a lock wasn’t such an important operation after all and that I could just let the thread that released the lock continue, but that’s not true. The scheduler should afford the other thread the opportunity to execute, but not always; whether that happens or not is part of the schedule and therefore needs to be stored in the schedule. My schedule generator should ideally not generate schedules like the above, but in the worst case, the schedule above is behaviorally identical with a schedule that just makes thread 9 wait until thread 0 has released the lock:

0 1        -100 ThreadA.run // thread 0 locks object
...
0 2        -100 ThreadA.run // thread 0 unlocks object
9 1        -100 ThreadB.run // thread 9 locks object
...
9 2        -100 ThreadB.run // thread 9 unlocks object

The problem are the ellipses in this example… There might be a great number of synchronization points between the points where thread 0 acquires and releases the lock, and if I don’t eliminate schedules with invalid concurrent lock ownership, then the number of generated schedules is unnecessarily increased.

I also believed at first that my strategy to assign object IDs had a bug. My intention was to assign unique object IDs to direct subclasses of Object, but it seemed like the same instance was assigned both object IDs -478 and -479, and I assumed that -479 was residing in a shadowed field in the Thread class, and -478 in a field in the ForkJoinTest$B class that extended Thread. However, I made a mistake in interpreting the log: ForkJoinTest$B does not extend Thread but instead just implements a Runnable, so we do have two separate objects.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Multiple Joins

The task of generating only valid schedules is really more complex than I thought. As stated in the previous post, not scheduling a thread before it is started is pretty easy, I’ll just have to watch the THREADSTART synchronization point. But I also do not want to schedule a thread’s blocks interleaved with blocks of other threads that occur after a join. For example, I don’t want to let the following program

{ A1 fork B; A2 }
{ B1; B2 join A; B3 }

generate this schedule:

A1 fork B; B1; B2 join A; A2; B3

I naturally want to keep all of A’s blocks before the B2 join A. It gets more complicated if there are several joins:

{ A1 fork B; A2 fork C; A3 }
{ B1; B2 join A; B3 }
{ C1; C2; C3 join A; C4 }

Here, I have to keep all of A’s blocks before the B2 join A and before the C3 join A, or conversely stated: B2 join A; B3 may not execute until after thread A is dead, but B1, C1 and C2 may.

It is not hard to detect invalid schedules after they have been generated, for example, the schedule

A1 fork B; A2 fork C; B1; C1; C2; C3 join A; C4; B2 join A; B3

is invalid. It respects thread B’s requirement to join with A, but it doesn’t respect that of thread C. If I only want to generate valid schedules, it seems like this is a whole lot more complicated than some kind of permutations of execution opportunities for threads. Maybe I should, at least for the first cut, generate invalid schedules like the one above and then in a second stage reject them?

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

Fork/Join

After I started implementing the schedule generator about a week ago, mainly because I wanted to program something again, I realized that it’s not as easy as I thought: Even the scheme that Justin and I worked out when he reviewed my thesis may generate invalid schedules.

The central realization we had back then, and which probably has been clear to most everyone anyway, including me a while ago before I forgot again, was that we need to consider permutations of critical blocks, but the blocks within a thread do not move; they always stay in the same order. If a thread executes the code {A1; A2}, then this is never going to turn into {A2; A1}. Therefore, what we’re actually permuting are opportunities for threads to execute the next block, whichever that may be.

As an example, if we have two threads A and B that fall apart into the critical blocks {A1; A2} and {B1; B2; B3}, respectively, we have to execute the following ten schedules:

A1; A2; B1; B2; B3
A1; B1; A2; B2; B3
A1; B1; B2; A2; B3
A1; B1; B2; B3; A2
B1; A1; A2; B2; B3
B1; A1; B2; A2; B3
B1; A1; B2; B3; A2
B1; B2; A1; A2; B3
B1; B2; A1; B3; A2
B1; B2; B3; A1; A2

The number 10 makes sense since we’re first choosing all the possible combinations of two out of the total of five blocks assigned to thread A, and then all the possible combinations of three blocks out of the remainder of three blocks assigned to thread B (not really a “choice” anymore, since B just gets the leftovers):

{5 \choose 2} {3 \choose 3}=\frac{5!}{2!(5-2)!} \cdot \frac{3!}{3!(3-3)!}=<br />
\frac{120}{12} \cdot \frac{6}{6}=10

I was almost done with support code to write a scheduler that creates these kinds of lists when I realized that I can’t really come up with a Java program in which all of these schedules were valid. In most Java programs, or at least in the idealized ones I’m considering now, program execution starts with just the main thread; the main thread may then spawn other threads. We could therefore have the threads A and B with the blocks {A1 fork B; A2} and {B1; B2; B3}, respectively, where fork B marks the point thread B is started, or inversely, the point before which thread B did not execute. The point at which thread B is started is not an critical block itself but rather the critical point that delineates the blocks A1 and A2.

If we now examine the list of schedules above and consider the inverse meaning of the fork point, we realize that the following six schedules are invalid since they schedule parts of thread B before it has been started:

B1; A1 fork B; A2; B2; B3
B1; A1 fork B; B2; A2; B3
B1; A1 fork B; B2; B3; A2
B1; B2; A1 fork B; A2; B3
B1; B2; A1 fork B; B3; A2
B1; B2; B3; A1 fork B; A2

To obtain the valid set of schedules, we can consider {A1 fork B} a prefix of all schedules which we do not have to permute, and only deal with the remaining four blocks (for clarity, I showed the prefix only in the first schedule):

A1 fork B; A2; B1; B2; B3
           B1; A2; B2; B3
           B1; B2; A2; B3
           B1; B2; B3; A2

Now we just have four schedules left, as predicted by the product of s-combinations: 1 \cdot \left({4 \choose 1} {3 \choose 3} \, \right) = 4.

Ok, good. What if one thread waits for another thread to die, i.e. there’s a join point as with the blocks {A1 fork B; A2} and {B1; B2 join A; B3} for threads A and B, where join A marks the point at which thread A waits for thread B to die, or more interestingly, the point after which thread A does not execute anymore. Therefore, the following schedules are all invalid, because part of A executes after the join point:

A1 fork B; B1; B2 join A; A2; B3
           B1; B2 join A; B3; A2

We have to consider {A1 fork B} a prefix and {B2 join A; B3} a suffix of all schedules and only permute for the remaining two slots, yielding only two valid schedules: 1 \cdot \left({2 \choose 1} {1 \choose 1} \, \right) \cdot 1 = 2.

A1 fork B; A2; B1; B2 join A; B3
           B1; A2;

Looks like a relatively simple task now; once a prefix or suffix have been determined, we recursively process the middle part. There are a few problems, though:

  • I need to know which thread gets forked and joined. Unique thread IDs give me that information.
  • Java may have join() calls with timeouts, interruptions from interrupt() calls, and even spurious wake-ups.
  • Java programs do not have to conform to a fork-join model.

I’ll have to think about how much the lack of a fork-join model impacts schedule generation. Forks definitely exist, so I can avoid scheduling a thread before it is running, but what should I do about the end of threads? If there is no join point, then they can be scheduled at any time, of course, but if there is a join point, then they probably should not be scheduled after it, although Java makes a join() almost meaningless. Maybe the default should be treating a join() as real join point, and optionally making it… meaningless.

I also have to consider whether I can create a connection between wait() and notify()/notifyAll() calls similar to the fork-join model, although that would not only require unique thread IDs, but also unique object IDs.

Share
Posted in Concurrent Unit Testing, MS Thesis | Leave a comment

Print This Post Print This Post  

Shrinkage

It’s likely no one noticed, but my thesis actually shrunk by about 53 pages. I applied a LaTeX formatting template that James had given me by Corky’s request. This template has smaller, more book-like line spacing, which probably violates the Rice formatting requirements, but Corky says all his students’ theses in the past have used it and got accepted. I also single-spaced the listings, which is allowed by Rice but which I had missed. The result is a thesis that is much more readable. It’s strange: My intuition told me whitespace contributes to easy readability, but true double-spacing was obviously too much and distracting. And double-spaced listings were just plain horrible.

I haven’t started a rewrite, even though I’ve discovered a few mistakes and clumsily worded parts myself, because I was still waiting for a bit more stylistic feedback from my committee members. I know Corky is almost completely through, so I’ll probably get his written feedback on Tuesday. Bill sent me an email today and said that he’ll probably put the review copy in my mailbox. I’ll check tomorrow, and then over the weekend probably do some editing.

It’s getting progressively more difficult to work on the “Master’s part” of my research, though: It was difficult to start writing after I had finished most of the coding, because it felt like “the work was done”. After I had finished the first rough draft of my thesis, it was difficult to start working on the presentation because “people could just read my thesis if they wanted to know something”. Now that I’ve done the presentation and defended, it feels like — at least in general — my work has been accepted, so why do I need to make changes? I realize, though, that the written thesis will be the most lasting evidence of my work, so I should strive to make it clear and concise. Corky’s advice to pay particular attention to the introduction is good, since that will be the part that is read most often. I think now, after a few weeks, I also have the necessary distance to recognize bad parts of my thesis and change them. I’ve done four proof-readings after I finished writing, but I was still too attached to my original writing.

I’ve also experimented a bit with integrating JUnit 4 with DrJava. I tried to create a “blended” junit.jar that contains the new interface from JUnit 4.x, but also the old 3.8.2 classes. This blended library works within DrJava if the programs run by the user use the old interface, but I’m still having problems with the new API. First of all, I had to look at all class files now, not just those that extend junit.framework.TestCase. Second, apparently the text output format of JUnit 4.x is different, so the part of DrJava that parses the output has to be rewritten. Third, some changes with respect to the TestCaseClassLoader will probably have to be made. I couldn’t reach a satisfactory conclusion yet, because I don’t quite understand what the expected output format is and how I can get the equivalent information with JUnit 4.x. It is encouraging, though, that a blended junit.jar seems possible. I believe this will be much easier than including both jar files and switching between them.

I’ve also finally added more backup support to my TeraStation RAID device. Now, my webserver contents get mirrored to the RAID device once a week using rsync, and if I want to, I can copy any changes to my MacBook’s local web server with a simple script that also uses rsync. I’ve found, to my surprise, that rsync is incredibly fast once the first synchronization has been made. In a similar fashion, I also mirror the Perforce repository, both in its original form and as tar.gz backups. Since rsync allows file-by-file mirroring (although they can be gzipped), I may convert my other backups to rsync as well. It would make recovery much easier than with Microsoft’s proprietary backup format.

I also started programming some schedule generation code using permutations, but I’ve realized it’s a bit more complicated than I originally thought. I also want to limit the schedules so that threads don’t appear before they are started.

Share
Posted in Concurrent Unit Testing, DrJava, MS Thesis, Uncategorized | Leave a comment

Print This Post Print This Post  

Cron-ically Wrong [sic!]

So it turns out there was yet another mistake in my crontabbed update scripts: They were also started on other computers I logged in. That by itself is wasteful, but not catastrophic; some of the computers didn’t run Linux on x86s, though, but Solaris on Sparcs. Every once in a while I’d get a differently formatted cron error email that complained about something not working. It took me a while to understand that this was a Sparc machine. Now I’m just running them on finland, which is an Intel Linux box.

I just went to get some random stuff from Target, letter sorters, drywall sealer, an extension cord, and carpet cleaner, among other things. What I didn’t find was some manual way to unclog the bathtub drain. Drano is ineffective and I can’t find any wire hangers; I must have used them all. The problem with both my bathtub drain and the toilet is that both empty not down, but towards the back, probably because the floors were built so close together.

The letter sorters don’t look good but will hopefully help (they already bend under the load), They now implement a primitive system of sorting the papers I’m working with: Bottom stack is “read papers, not very important”; the second stack is “not read, not directly applicable”; the third is “read and important”; and the top stack has directly to do with my thesis. Before this reorganization, I had so many papers floating around, I even forgot I had some. The extension cord has a switch to reboot both my DSL router and my Gigabit switch; lately I’ve seen lots of problems with that, and resetting those two devices so far does the trick.

I also looked at new thermostats, but they had only one that didn’t give me enough information. I think I may buy a newer, digital, programmable model from the same manufacturer though; they are cheap, $20 shipped, and during the day when I’m gone I can automatically power down the AC. Now that I know the current circuit board almost by heart, replacing the 70s-style rotary dial thermostat should be easy.

Then I looked at the fans at Target. There are big fans and small fans; tower fans and box fans. Most of them are measured in inches of diameter. This is something that has puzzled me for a long time, for about as long as I’ve had my own apartment and I’ve considered buying a fan: People only care about a fan’s size, but not about the power consumption, the noise and the airflow, even though to me those seem to be the most important characteristics of a fan. Who cares if it’s the size of a dime but needs its own nuclear battery and sounds like an airport?

I actually opened two tower fans up, a 30″ and a 40″. Nowhere did it mention anything besides “3 speeds”, the inches, and that the bigger one had a remote control. I guess it lets you select among three different but all unspecified amounts of airflow. I just can’t buy a fan like that. I think this is one of the weird traits were my Europeanness still shows. I also looked for multimeters. No surprise that they didn’t have a device to measure potential, current and resistance… Measure what? Can I supersize that?

The fan issue is turning into a pet peeve: I’ve asked salesmen in hardware stores and written emails to manufacturers, but no one could ever tell me about a particular fan’s W, db and cc/m. Does that mean everyone here just doesn’t care how much a fan sucks or blows? But maybe the Americans have it right, actually. The temperature comfort zone is so tiny, only a small degrees, I’m sure the placebo noise of a fan already makes it colder.

Then I was on my way to get a haircut. I usually wait on a bench a little and drink some Gatorade to cool down, then comb my hair, just so I’m not all nasty and sweaty. I did the same today, but then discovered that my trusted old barber shop from nearly seven years had moved. Now it’s on the freeway, about twice as far and much more inconvenient to reach. I guess this is goodbye and back to the big chains.

Share
Posted in Ramblings, Uncategorized | Leave a comment

Print This Post Print This Post  

Everything Breaks

My surroundings seem to be in a physically flawed state. I’m feeling fine, so I don’t want to make the complaint more general, but you’ve heard the toilet story and that yesterday I enjoyed the first full day of an automatic flush toilet in 1.5 weeks.

Then, last night around 9 PM, when I came home from the office, I noticed that the fan from the air conditioner was permanently on, even though it was in the “auto” setting. I wasn’t exactly sure if any really cool air was coming out, but the moving air was definitely better than the 86 degrees Fahrenheit inside. Poor Diana.

At around midnight, finally, the air conditioner died completely. Definitely no cold air, and also no fan anymore. That reminded me of Diana’s suggestion to buy a few mobile fans, just in case we need them. We should do that. I’m pretty sure in this apartment complex, more things than just ACs and toilets are going to “crap out”. Pardon the pun. I wish I had a ceiling fan in my bedroom. I wonder if I can install it by myself.

Doing things by myself is a big pattern here: I try to fix everything myself, or at least know what is broken and what needs to be done before I call maintenance. The first time the AC died in the summer of 2004, when I had just moved in, two of the handymen here “fixed” it, but on the same day, the AC completely died, and I had to endure the weekend without AC. I always used to complain that the girl I was seeing at the time had her thermostat set too low; that weekend, I begged her to let me stay.

During both the summer of 2005 and 2006, the AC was dripping water from the unit above my bathroom onto the floor. Because the AC worked and it wasn’t too inconvenient, I preferred to put a bucket underneath to asking the repair guys to work their magic. In 2006 I decided to take a look above the cover plate. I have no idea how ACs work (besides some fuzzy thermodynamic concepts and van der Waals equation), but I noticed that what seemed to be a “reservoir” was overflowing. It was supposed to go through a PVC pipe and come out on top of my bathtub. That explained one mystery: I had always wondered what that outlet was, what would cause it to drip, and why they didn’t bypass the bathtub and connect it directly to the waste water line. Maybe they were trying to be environmentally friendly and wanted to fill the toilet with it, but did it wrong. Who knows with these guys?

Anyway, that reservoir was overflowing, but the pipe was leaky, so instead of going through the pipe, it dripped out over the reservoir and into my bathroom. When duct tape didn’t work to fix the leak, I finally called maintenance but told the man exactly what he needed to do.

Tonight the AC broke again, but in a strange way. It seemed like a bad contact, so I disassembled the control panel. I knew how the magnet and the bimetal coil work, but I had never looked at the circuit board below. Because I have left my multimeter back in Germany, I couldn’t really do much much more to find out what was going wrong than read and understand the circuit diagram and then “hot-wire” the AC by directly connecting wires. It turned out the problem was unlikely to be in the control panel.

I was about to give up, but decided to give the AC unit above the bathroom another look: I was shocked by the shabby job (must have been done in my absence or by the guy that fixed the leak): Wires were simply twisted together and right below where the water used to be dripping. I examined the wires, and found that the furnace wires had corroded and didn’t make good contact. I stropped some wire, twisted them together and insulated them much better against water. I believe all is well know.

Other things break too, because I do things too well but then forget: I had set up my nice crontab to automatically update the RiceMBS and the Concutest news if necessary. Then, just to be safe, I made a backup of the crontab listing and restored the listing whenever I booted. Later I beautified the scripts but forgot to update the backup, which got restored and therefore uglified.

Here’s my crontab right now (ignore the line breaks)

00 00,09,14,21 * * *
   /home/mgricken/bin/echo-if-failed
   /home/mgricken/public_html/research/concutest.website/news.log
   /home/mgricken/bin/update-concutest-news

05 00,09,14,21 * * *
   /home/mgricken/bin/echo-if-failed
   /home/mgricken/public_html/research/dp4mbs/current.log
   /home/mgricken/bin/update-ricembs

The two scripts update-ricembs and update-concutest-news are set up to output simply to stderr and return a non-zero value if they fail. echo-if-failed executes the script specified as 2nd argument, and if all goes well, then it just logs the output to the log file given by the 1st argument. If the script fails, however, then the output is also visible to stderr, and that means that cron will send an email notification. That way I immediately find out if one of my cron tasks has failed, but I don’t get useless emails that merely state everything went as expected.

Anyway, time to do other things.

Share
Posted in Ramblings, Uncategorized | Leave a comment

Print This Post Print This Post  

Catching Up and Organizing

After passing my defense on Thursday, I mainly did a bunch of catching up and organizing. I guess I didn’t mention it here before, but my toilet had been broken for ten days (I had to manually flush by filling the bowl with a bucket), and even though I had reported the damage to my apartment management on Friday, June 8, and they promised to special-order the part on Monday, nothing was done. This was partially my fault for not following up, but I had my defense on my mind.

The Friday after my defense I started to take care of things again and was disappointed by the management: I called in the morning and was told management would “check the work order and call me”, and I called again in the afternoon and was reassured the manager would “get right back to me”. None of the return calls materialized. On Saturday I submitted a letter of complaint in the morning and went to the office personally in the afternoon; the response I received was “this hasn’t been taken care of?” No. No, it hadn’t. Finally on Monday, a new tank was installed; the repairs took about 10 minutes. I guess the only problem was getting a tank that fits, or I could have easily done the repairs myself.

I also called my eye doctor on Friday, because I’ve been waiting for my new pair of glasses (which I mostly wear only from bed to bathroom and back) for a month and a half now. I suspect a flaw in their system, because my order of contact lenses was forgotten too.

I reorganized the download directory for the Concutest website and a semi-automatically created download page that combines all the downloads from other sections. Finally, today I submitted my first releases to SourceForge.

I find the release process on SourceForge incredibly cumbersome… someone didn’t think this through. It reminds me of my first web content management system, which allowed users to add posts and news by entering text in a web form, but pages had to be uploaded by FTP, so the whole experience was not purely web-based but a schizophrenic web-FTP hybrid. SourceForge is actually worse: It requires you to upload your submissions by FTP, then select the files from a list of files that also includes other projects’ recent submissions. For every change you make in a field, you have to push a “Submit” button, and that only saves the changes to that particular field, not all fields. I released 14 files today and, if I remember correctly, I had to push a “Submit” button 18 times. That’s just plain ridiculous. No wonder only two people currently in our research group know how to release files on SourceForge.

I’ve also automated the SourceForge Concutest news announcements. Right now I have a script that runs four times daily to exports the news and includes it on the Concutest front page. In a similar way, I’ve automated RiceMBS releases now.

I’ve also found out that Matt Barnett, a Rice and JavaPLT alumnus, is in Houston again and lives quite close to me, so I’m looking forward to getting back in touch again with him.

Share
Posted in Concurrent Unit Testing, Graduate School, Uncategorized | Leave a comment

Print This Post Print This Post  

I defended!

I haven’t written in a few days. There was a bit of chaos in my life last week, so I never got around to really gestate the subsumption post below, basing invariants on the static type and all the other things Corky and I talked about.

On Tuesday, Corky and I went over my thesis in greater depth, and we talked more about how we could extend the invariant annotation framework. On Wednesday, Corky and I emailed a few times and talked on the phone… Because today…

Today I defended my Master’s Thesis and passed.

Unfortunately, we started a bit late, and my presentation was pretty long (Diana said an hour and 50 minutes), but that was partially due to lots of comments and questions that I answered in between. I think some of these questions could perhaps have moved towards the end, but I didn’t mind. There were only very few questions at the end. I just felt bad for some of the students who had to endure such a long defense. But then again, I had brought them snacks: Cookies, mini-donuts, grapes and a veggie platter. Diana helped me set up.

Now, of course, I still have to rework my draft a bit, but it feels grrreat to have passed the defense. Here are some pictures my girlfriend and I took.

Share
Posted in Graduate School, MS Thesis | Leave a comment

Print This Post Print This Post  

Defense: A Framework for Testing Concurrent Programs

A Framework for Testing Concurrent Programs

Rice University
The Department of Computer Sciece

presents

Mathias Guenter Ricken
Master of Science Thesis Defense

A Framework for Testing Concurrent Programs

When: July 14, 2007

ABSTRACT

Incremental, test-driven development is sweeping the software industry, elevating testing from an ancillary activity to an integral part of the programming process. Unfortunately, in our recent experience developing production programs in Java, unit testing has only proven effective in assuring the reliability of code with a single thread of control; it is much less effective in concurrent programs.

To facilitate the development of concurrent programs, we are developing:

  1. An extension of the JUnit framework that actively supports the developer by treating tests that could silently ignore failures in auxiliary threads as test errors.
  2. A lightweight Java annotation language that can be used to specify and check the threading invariants of both existing and new code.
  3. A testing framework that can record and analyze the schedules of unit tests, detect deadlocks, and run the tests using modified schedules, increasing the likelihood that concurrency problems are discovered.
Share
Posted in Concurrent Unit Testing, MS Thesis, Publications | Leave a comment

Print This Post Print This Post  

Subsumption

On my bike ride back from the office, I started thinking about my earlier statement about subsumption and that the new system would lose the static guarantee that an instance of a subtype with strengthened invariant is used as a supertype. Maybe we actually can do better in some cases. The important questions are: Where does subsumption happen? What class are we compiling?

First, though, I should emphasize that static analysis of what class will be contained in a certain variable at runtime is pretty difficult. It is easy to construct a program where the runtype type depends on some condition or might even be (pseudo-)random. In those cases, some sort of sum type should be used for the variable. So even within one method or one class, a certain amount of flow analysis has to be done. With debug information, the static types of all fields, parameters and local variables should be available without having to do inference, though.

Now let’s consider what class we are compiling. If we are compiling the subclass with the strengthened invariant itself, then it is reasonable to assume that adding a new invariant may break binary compatibility, so the entire project should be recompiled, or at least re-checked (in the case of the Java API). The same should probably apply if we are compiling a superclass or subclass of the class with the strengthened invariant.

If we are compiling a class other than the subclass with the strengthened precondition, then unless subsumption happens within the class being compiled, it has to happen either during a method call to another class or after returning a value.

Does this help us? I don’t know yet. It seems like it should be possible to figure out the possible types of a variable whose method is called, at least using sum types, which may be too general. Figuring out the class of the caller is probably impossible, though, at least using incremental compilation.

I think, even after these additional considerations, I’m getting back to the point that we cannot get a static guarantee with incremental compilation, without considering the whole program.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post  

A Deadline

First off the big news: I’ve found a day and time when it seems like all my committee members are available, and a room should be available as well. Right now everything seems on track for a defense on June 14, 2007.

When I wrote the last time, I said I was finally using my TeraStation for backup purposes, as intended. Then I decided to uninstall the Dropbear SSH server and install OpenSSH, and in the process I accidentally deleted a whole lot of startup scripts; the TeraStation wouldn’t boot anymore, and I couldn’t access it using telnet, SSH or the web interface. Fortunately, putting the original firmware back on it and then redoing all my changes worked. I didn’t even lose any data, it just cost me time. Maybe I should stop messing around with it now… Otherwise I need a backup for my backup unit.

I’ve played around a bit with Corky’s idea from Tuesday, i.e. allowing stronger invariants on a method in a subclass. Let’s consider the following program, first using the system I have right now, and then using the modified system that incorporates Corky’s idea:

class A {
@Invariant1
@Invariant2
public void m() { ... }
}
class B extends A {
@Invariant3
public void m() { ... }
}
public class Test {
public static void main(String[] args) {
A a = new A();
a.m();
A a2 = new B();
a2.m();
B b = new B();
b.m();
}
}

What invariants must be satisfied for each of the three calls?

In the current system, the call to a.m() must satisfy @Invariant1 and @Invariant2; the call to a2.m() must satisfy @Invariant1 and @Invariant2 because these invariants were inherited from A.m(), and additionally, @Invariant3 must be satisfied. The exact same applies to b.m(): All three invariants must be satisfied. Because the invariant was strengthened in a subclass method by adding @Invariant3, the current system emits a subtyping warning for B.m().

In the proposed new system, the call to b.m() would be allowed because the static type B is the type at which the invariant was strengthened. More precisely, it is allowed to strengthen an invariant as long as an instance of the type at which the addition occurred, or a subtype thereof, is never used as a supertype of the type at which the invariant was strengthened: Let T be the type at which the invariant was strengthened. As long as an instance of type U, U <: T, is never used as an instance of type S, T <: S, not T = S, this strengthening is acceptable. This system seems to make sense. At first I also wondered if B.m() has to satisfy the inherited @Invariant1 and @Invariant2 at all, but I’ve realized it has to: An instance of type B, used with the static type B, could “escape” and using subsumption become an A.

The problem with this system is that it cannot provide the static guarantee that an instance of type B is never used as one of its supertypes, at least not without some kind of flow analysis that also takes into account code that is not compiled at the moment. If we wanted a static guarantee for that, so that we get the subtyping warnings in all of the cases where an instance of a subtype with strengthened invariant is used abstractly as a supertype, we would have to check that this doesn’t happen every time we compile any code, whether the code is the definition of type B itself, the code directly uses B, or the code uses something that uses B, ad infinitum.

This could be done statically, of course, but we’d have to tell the compiler or instrumentor which subtypes have strengthened invariants so it can check for violations. Maybe a data flow analysis could reveal these situations, but it would certainly be a very expensive task. If we don’t allow incremental compilation, tyhe task becomes easier, but disallowing incremental compilation runs completely counter to Java culture, and it would even rule out the use of libraries — even the Java API (rt.jar) would have to be recompiled.

Because of the loss of static information, I don’t think this should be the default system. Perhaps this system should be used dynamically and check the call sites for errors: The static analysis done by the instrumentor would emit a subtyping warning for the definition of B.m(), and then the dynamic checker would emit a warning for the call site a2.m(), but not for b.m().

This still has to ripen a little bit in my head, but I think I agree with Corky that this information should go into my thesis, even if I don’t implement it yet. These considerations are useful, I believe.

Share
Posted in Concurrent Unit Testing, Graduate School, MS Thesis, Uncategorized | Leave a comment

Print This Post Print This Post  

Land of Confusion

During the last 20 days, I haven’t written in this blog. There are reasons, although I have to admit I did not work a lot during those days.

The day after my last post, my mom arrived from Germany and spent nearly two weeks here. Fortunately, the weather was nice, not too hot and only one day of rain. We had a lot to talk about, and if you know anything about my personal life, you can imagine that this was sometimes straining. On the other hand, I enjoyed her stay more than ever this time: In the past, I’ve always had the feeling that I didn’t spend enough time with her because I still had to grade or work on my projects. This time, her visit fell into the weird period when I had mostly finished writing my thesis, but I couldn’t defend yet. So we used the time for several long walks and discussions, about important things as well as trivial things. I miss her, and I can’t wait for her to be back. She will be; I guarantee it.

As already stated, I couldn’t defend my Master’s thesis in May as planned; it was too late for graduating in May anyway, but only by a couple of weeks. Because of that, I’m not too disappointed: It would have been nice, but it wasn’t really necessary. I sent out review copies of my thesis, but unfortunately, so far I haven’t got a lot of feedback.

The only person that provided a detailed review was Justin. Thanks again, Justin, you have been a great help and wonderful friend. When talking to you about my thesis and your comments, I have realized again what an extraordinary person you are: Not only did you comment on what I had written down, you also asked questions about what I still have to do. Even though it is my task to figure things out and answer some of the difficult questions, you have gone beyond what I asked of you as a favor and have spent your time and have thought about what future problems I will face. Again, I can only marvel at your curiosity, intuition and energy. Thanks. I’ll try to repay the favors some time.

Justin helped me with two problems: First, while reading some type theory books I had loaned him, he asked a few questions about the Bottom type. In trying to answer these questions, I have realized I have a mistake in my thesis; not a major one, but I’m stating something that isn’t correct. Second, Justin helped me with the idea of schedule generation, a topic that I’ll still have to work on.

When Justin returned the review copy of my thesis, he asked questions along the lines of “Are there any values of type Bottom?”, “What does returning Bottom mean?”, and “How does returning Bottom differ from returning Unit?”. After trying to get my head straight for a few minutes, I finally explained that Bottom is a type that is a subtype of any other type. Whatever type you give me, Bottom is a subtype of it. That also means that if there were a value of type Bottom, then its type could be promoted to any other type. This is similar but more general than the relationship between the Java classes String and Object: Any value of class String can also be promoted to type Object.

Upon closer analysis, the fact that a value of type Bottom can be promoted to any other type is also the reason why there is no value of type Bottom. If that value existed, then its type could be promoted to any class, for example String or Integer, and the classes it could be promoted to need not be in a supertype-subtype relationship. Therefore, having a value of type Bottom would allow contradicting type derivations to be made.

So if there is no value of type Bottom, what good is it? The same question came to my mind when I first encountered the Unit type: If there’s only one value, what good does returning it do? It doesn’t give me any useful information, because the answer is always the same. Actually, returning unit does convey information, even though the value is always the same: Returning unit tells the caller that the subcomputation is done. It doesn’t say anything what was done in that subcomputation, but whatever it was, it terminated. And giving something the return type Unit means that it will terminate. This sets the stage for Bottom: The return type Bottom means that a subcomputation will not terminate.

So, in short, there are no values of type Bottom because having those values would lead to contradictions. Returning Bottom conveys the idea that the subcomputation will not terminate, and that’s the difference to Unit: Returning Unit doesn’t yield any useful information beyond the fact that the subcomputation terminated.

Thinking about this made me realize that I claim that the empty record of invariants is a Bottom type. This is not true, of course, since the empty record is an actual value, and Bottom doesn’t have any values. What is true, though, is that the empty record is the bottom-most value that exists in my system. That’s close, but not exactly the same, so I’ll have to correct it in my thesis. I still have to think about whether the same applies to an invariant that is impossible to fulfill: The record describing it is an actual value, so can it be a Top type? I don’t think so, because there can definitely be more than one record of invariants that are impossible to fulfill.

The other issue that Justin brought up was schedule generation: He stated that not all permutations of synchronization points correspond to a valid schedule. I remember that I realized this over two years ago already, and that I brought it up in a discussion with Corky. I suggested that we use Lamport clocks, because that’s what the earliest relevant paper that I could find did. At that time, Corky convinced me that we can find a simpler data structure that still works: We just need a series of thread IDs to replay the schedule we have chosen.

I also remember being asked a question in the same direction by John Mellor-Crummey at a poster presentation. I embarrassed myself by not being able to answer the question; I could only say that I had thought about it. That was true, but I had forgotten my answer to it.

Corky is absolutely right that a series of thread IDs is sufficient to select a particular schedule; however, this approach only shifts the work from the replay algorithm to the schedule generation algorithm. There still is no free lunch. I agree with Corky, though, that reducing the work in the scheduler while increasing the work in the schedule generator is a good idea: Schedule generation can happen offline, and as long as the code does not change, the generated schedules remain valid. The scheduler, though, will have to do its work every time the code is run, so any work that can be removed from it saves computation cycles.

If we are to use the simpler data structure, we have to make sure that we only generate valid schedules, schedules that could actually occur “in the wild”. The only thing that can happen due to nondeterministic scheduling is that a different thread than usual is executed at a certain point. This means that, while the thread that is executing may change, the order of synchronization points within a thread have to remain the same. As a concrete example, consider the try-acquired-released sequence of synchronization points that corresponds to a synchronized block: It just doesn’t make sense to move the acquired event before the try event, or the released event before the acquired event, and so on.

Justin and I also discussed how we can reduce the number of synchronization points by ignoring those that occur during the execution of a certain method. Most likely, if you exclude synchronization points in one method, you also want to exclude those that occur in methods called by the method. To determine the synchronization points that should be ignored, we need to find the first fixpoint for the set described below:

  • If the synchronization point to be excluded belongs to a structure of several of synchronization points, like the try-acquired-released sequence of a synchronized block, then the other synchronization points in that structure have to be excluded as well.
  • If a synchronization point happens in the same thread as the synchronization points to be removed and occurs after the first synchronization point in that thread’s schedule and before the last synchronization point of that thread’s schedule, then this synchronization point has to be excluded as well.

Since the first rule may add synchronization points that happen earlier or later in the same thread, applying the first rule may make it necessary to exclude additional synchronization points, as per these two rules. The set of synchronization points is the set that does not add new members to the set, i.e. the first fixpoint.

I know I had already thought about this, perhaps not as concretely, but realizing this as quickly as Justin did is simply remarkable.

Another interesting thing began to emerge today in a discussion with Corky: In some cases, it may make sense to allow a stronger invariant, and a subtyping warning should not be emitted. It all depends on the static type that is used. If the program works abstractly with a supertype, then additional invariants added in a subtype should generate a warning to tell the programmer he is no longer maintaining substitutability. However, if the program actually works with the concrete type, then the program is probably aware of the stricter invariant because the object never gets treaded abstractly, and substitutability can be discarded. I’ll still have to look at that and work out examples, but right now it seems like this makes sense and is actually possible to implement, although it will make the instrumentation global, as now different call sites may have to be treated differently, depending on the concrete type. I also have to decide whether I am going to implement this now for my Master’s thesis or whether I am just going to discuss it. Right now, I definitely prefer the latter.

I also heard today that one of my committee members will be out of town at the end of June again, so I still don’t know if I’ll actually be able to defend in June. I still have to finish my slides anyway, though, and I feel like I can defend my thesis any day, so I don’t think this is a huge problem. I may have to defend earlier than I’d really want or later than I had planned, but it will happen.

Time to go to bed. Tomorrow, I’ll have to play around with a few examples.

PS: I think I’m now finally using the network-attached storage that I bought about a month ago the way I intended. Up until yesterday, I just never had the time or nerves to change my backup scripts.

Share
Posted in Concurrent Unit Testing, Graduate School, MS Thesis, Uncategorized | Leave a comment

Print This Post Print This Post  

Unscoped If New?

One idea that I had about the global vs. scoped data annotations was to have them scoped by default, but if an object is created using new at the time of definition, then an option can be set to have the object checked globally.

I’ve now realized that that’s not such a good idea. What if you want to have an object checked, but you’ve only been given that object from some library you’re using and you don’t have the source code? Or you don’t always want to have the return value of that function checked?

So I guess it has to be possible to always select global checking. But what if no value is assigned or the variable is set to null? Then it’s going to get a whole lot more difficult to track down where that variable gets set.

The problem here stems from the fact that I’m annotating a variable, which is sort of a “static” thing (for the lack of a better word; I don’t mean Java’s static). What I want to annotate and modify, though, is an object, a dynamic thing at runtime.

There are so many open questions now. And at first, I thought this would be easy. What if the variable gets reassigned? Does the annotation at the definition site mean that all instances assigned to the variable are checked?

Without clear semantics, predicate annotations for data become a lot less attractive… even though I still think it would be cool to call a method every time an object is accessed somehow.

Share
Posted in Concurrent Unit Testing | Leave a comment

Print This Post Print This Post