Tuesday, 28 February 2017

A Simple Text Editor


A parallel world has many doors,
With lots to explore and lots to find.
Knock knock and thee shall ask for more,
With fork and join, to blow your mind.

Enough with the theatricals? Yes, I understand.

So, for my second adventure in the parallel world, I set out to inspect parallelism in Java. Don't worry - this is not going to be the nine hundred and ninety ninth post that you are reading, explaining Java's incredible journey from threads to executor service! Contrarily, this is about my experience in putting the same into use.

I found this cute, simple text editor written in Java on GitHub, that I thought had some scope for improvement. It had most of the features of a typical text editor, except for scroll pane (which I thought was pretty necessary). After sufficient twiddling, I happened to notice that it had no "find all" feature and there was my light-bulb moment - implementing a parallel search for a word in a document.


Implementing a parallel search for a word in a document

If you think about it, it is piece of cake - You have some jumbo text, in which you have to find the occurrence of a word. All you java lovers are probably wondering why all this hue and cry for a simple String.indexOf() function call. Well, I was also in agreement till I discovered that the indexOf function is, in reality, implemented as O(mn) algorithm.  (If you are fortunate enough to have not come across this notation, you can either refer here or take my word for "We can do better".)

A simple parallel approach to the same problem is to divide the search among threads i.e break up the jumbo text into smaller chunks and make each thread return occurrences of the search string. But wait, what if the word is spread across the chunks? Yes, we have to handle that case separately.

A screenshot of the find all implementation
All said and done, with a few lines of code, this new feature was added to the text editor. It seemed to perform pretty well with a running time of 2 milliseconds for 237 occurrences in a text of about 20000 characters (using the same old O(mn) algorithm). However, there was no significant change in the performance when the number of threads was increased.

Hope you liked this short simple post on Java parallelism. Look forward to more in the upcoming posts. Till such time, happy coding in a parallel world.😊

P.S. All relevant code will be available here.


Sunday, 29 January 2017

The Page Rank Mystery

I kick-started my quest for some long slow code, out there, lost in the GitHub world, waiting to be rescued by some parallel programmer, who'd walk by, and wave his magic openmp wand and change the world. Eventually I discovered that hunting for "slow code" is a wild goose chase; it makes much more sense to look for "interesting code". Voila-algorithm implementations!

So I stumbled upon this repository implementing the infamous page rank algorithm. Much to my disappointment, it was very well-written in Greek. The readme directed me to this useful link: How Google Finds Your Needle in the Web's Haystack, that explained the latent ugly math of the algorithm. Henceforth, I dived into the C++ code to get a clearer picture of what is happening.

The code was surprisingly very fast for large inputs (about 1.2 seconds for 100000 vertices). This is probably because of the extensive use of library functions that are assuredly compiler friendly. An extremely useful lesson: When you write code, exploit the language library as much as you can! Nevertheless, when I looked at 0.65 seconds response time on Google search results page, I hoped that there might be some scope for improvement. 


A quick examination of the code from the perspective of a profiler yields obvious results : that the page rank computation is essentially the bottleneck.  I suppressed my instincts to instantly use the #pragma mantra and played around with the serial code. For instance, it might have caught your eye that the current element of the H vector is computed in each and every iteration!

But wait! Aren't computations involving double data types expensive? Loss of precision? It depends on the representation? Either way, why would I want to compute it every single time? Can't I just compute once and store it in an array? Isn't that more cache friendly?

Yes. I had the same set of questions on my mind. As it turns out, I could not have been more wrong. The computation, though expensive, is conditional. For a sparse matrix, pre-computing values in an array would hardly make any difference; in fact, pray that it does not add more overhead. This led me to my second lesson: Don't always blame the expensive computation.

Parallelizing the computations on the rows using good old openmp reduced the running time by 0.2 seconds (16% speedup). Frankly, I was balked. Ouch! Expectations hurt. I welcome any comments on your speculation of the reason. 

Moving on, my next move was to address the smaller elephant in the room - the file input. Reading a huge file line by line seems highly inefficient for several reasons such as increase in number of system calls and therefore increased interrupts, the file pointer has to be moved more frequently etc...

So, what is the most efficient way to read a file? Perhaps read the entire file into a string and then parse the string. I tested the same with a sample file and realized that this was indeed the case.
Hurrah! Our page rank algorithm got 0.15 s faster!


Summing up, I believe that the optimization is still "work in progress". But that is for another time in another post. Till such time, happy coding in a parallel world. 😊

P.S: All the relevant code and readme files will be available in my gitHub account.