<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6787189684621789552</id><updated>2021-04-07T09:23:31.537+01:00</updated><category term="Life"/><category term="Linux"/><category term="Software Development"/><category term="Vim"/><category term="Ruby"/><category term="Java"/><category term="JVM"/><category term="Postgres"/><category term="Gdb"/><title type='text'>Vincent Liu</title><subtitle type='html'>Sitzfleisch</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default?alt=atom&amp;redirect=false'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default?alt=atom&amp;start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>157</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-1204574726856224986</id><published>2017-12-27T01:43:00.001+00:00</published><updated>2017-12-27T01:47:03.329+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Life"/><title type='text'>Nobody blogs anymore, and Heroku limitations</title><content type='html'>Looking at the previous date stamp, you&#39;d have noticed that it has been ages since I&#39;ve written anything on this blog. But in this day and age, who does &#39;blogging&#39; anymore? I&#39;d be surprised if any of my old-timer friends are checking if there&#39;s any updates to this page, and/or be still subscribed to any feeds related to it (if the feed readers are still surviving themselves!)&lt;br /&gt;&lt;br /&gt;I&#39;ve moved the blog to Heroku+git a while ago, and while it has also has been stagnant, in the last month, it seems like someone/something has been pinging the site pretty hard that caused all my dyno hours to be used up, bringing it down for the remainder of December. Whoever the ddos&#39;er is, well *you win* &lt;i&gt;[not like it matters anyhow]&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Makes me wonder if my move to Heroku was really warranted, thinking that it is easier to post code-related snippets (and it still is), but at least with blogger, there&#39;s no risk of the site being shut down just because someone exceeded the 550 hours of use.&lt;br /&gt;&lt;br /&gt;At least there&#39;s a choice :)&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/1204574726856224986/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2017/12/nobody-blogs-anymore-and-heroku.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/1204574726856224986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/1204574726856224986'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2017/12/nobody-blogs-anymore-and-heroku.html' title='Nobody blogs anymore, and Heroku limitations'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-6225380816315153331</id><published>2013-02-10T23:06:00.000+00:00</published><updated>2013-02-10T23:06:34.186+00:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Vim"/><title type='text'>Getting YouCompleteMe to work in RHEL 6 (or Fedora)</title><content type='html'>&lt;b id=&quot;internal-source-marker_0.9820069067645818&quot; style=&quot;font-weight: normal;&quot;&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;No matter what IDE I use, so far I still give up and go back to vim. However, Eclipse is quite missed for it’s autocomplete facility. The recent announcement on Hacker News gave me a glimpse of hope with &lt;/span&gt;&lt;a href=&quot;http://valloric.github.com/YouCompleteMe/&quot;&gt;&lt;span style=&quot;color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;YouCompleteMe&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;, as with &lt;/span&gt;&lt;a href=&quot;http://www.vim.org/scripts/script.php?script_id=3302&quot;&gt;&lt;span style=&quot;color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;clang complete&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; a while ago, but even sleeker.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;But YouCompleteMe uses a number of really new dependencies, which RHEL6, being an old snapshot of Linux, is a bad target candidate since these dependencies are not easily satisfied. Perhaps stopping short of paid support, it’s unlikely that these packages will be made up-to-date. Not being a cheap-ass here, but since I really don’t like waiting, I’ll just have to roll-my-own :-)&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Amazingly these dependencies are so new that even vim needs to be rebuilt due to the recently introduced python extensions, so there’s no avoiding some serious source compiling here!&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Before we start, let me impart some words of advice. Firstly, even if you are gutsy enough to build your own binaries, &lt;/span&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;never try to reinvent the wheel and build from pristine sources&lt;/span&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;! &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Secondly, installing software through package managers (eg. RPMs, .debs) are always superior to “sudo make install”. It ensures you’ll never have lingering dependencies, or wrong versions of libraries that got wrongly linked because the installed script overwrote the default.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;For Redhat based OSes, since the guys at Fedora has already done the hard work of building up-to-date packages, applying patches and cleanups for you, it’ll be the best bet to avoid pain from compilation errors, or hours spent in debugging other people’s code.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Pull a copy of the vim.spec file from &lt;/span&gt;&lt;a href=&quot;https://fedoraproject.org/wiki/Releases/Rawhide?rd=Rawhide&quot;&gt;&lt;span style=&quot;color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Fedora Rawhide&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; and re-adapt it to your liking before building an RPM. Obviously, F19 (as this time of writing) has diverged since RHEL6 got snapshotted, so a little &lt;/span&gt;&lt;a href=&quot;https://bitbucket.org/vincentliu/rhel6-vim/commits/226d2024e6f1352c61adee137e00faae63a283ca&quot;&gt;&lt;span style=&quot;color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;patch&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; and backporting is unavoidable.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Then, there’s the issue of Clang, which is recommended to be version 3.2. Even Fedora Rawhide at the moment only supports 3.1, so I was rather surprised about such a new dependency that YouCompleteMe requires. Still it’s not a problem, just a little more hacking on &lt;/span&gt;&lt;a href=&quot;https://bitbucket.org/vincentliu/rhel6-llvm/commits/3e686b0e8ea8edbd27c7766bb0566f44802b520d&quot;&gt;&lt;span style=&quot;color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;llvm.spec&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; font-weight: bold; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Note:&lt;/span&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; my Clang 3.2 build fails a single regression test during building, so I’ve disabled regression testing to allow the RPM to be built. While it may be ok for some other software, but regression test failures on your compiler is a BAD thing, especially if you’re going to build the entire OS from scratch. But since we’re only using it as an annotation tool, I’m going to let it slide.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;If building those 2 things hasn’t deterred you yet, you’ll still need to deal with the last headache of building a newer version of &lt;/span&gt;&lt;a href=&quot;http://bitbucket.org/vincentliu/rhel6-cmake&quot;&gt;&lt;span style=&quot;color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;CMake&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;, as a dependency that YouCompleteMe require in order to compile the final ycm_core.so library. &lt;/span&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; font-style: italic; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;[ But why? :-( ]&lt;/span&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;Anyway, for people who want to skip the pain of building it yourself, you can get my pre-built &lt;/span&gt;&lt;a href=&quot;http://bit.ly/ycm_core&quot;&gt;&lt;span style=&quot;color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;ycm_core.so&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; and all my vim/llvm RPM dependencies from my &lt;/span&gt;&lt;a href=&quot;http://bit.ly/RHEL6-RPM&quot;&gt;&lt;span style=&quot;color: #1155cc; font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt;RPM repo&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot;font-family: Arial; font-size: 15px; vertical-align: baseline; white-space: pre-wrap;&quot;&gt; (if you trust my work ;-) and save yourself some compiling hassles. They probably will work on Fedora as well, since dependencies are usually forward-compatible, but YMMV. Have fun!&lt;/span&gt;&lt;/b&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/6225380816315153331/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2013/02/getting-youcompleteme-to-work-in-rhel-6.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/6225380816315153331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/6225380816315153331'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2013/02/getting-youcompleteme-to-work-in-rhel-6.html' title='Getting YouCompleteMe to work in RHEL 6 (or Fedora)'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-1059593468196904073</id><published>2012-09-14T06:00:00.000+01:00</published><updated>2012-09-14T06:00:00.998+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Software Development"/><title type='text'>Have you ever reused code?</title><content type='html'>The term &#39;Code Reuse&#39; feels like a software developer&#39;s cliche that had since fallen into the list with other unfashionable tech lexicons. Nevertheless the terminology still lingers on like a bad smell, never fully ready to die off. These days, code reuse feels more like the definition of a myth - a story everybody has heard of, but nobody has witnessed.&lt;br /&gt;&lt;br /&gt;If you are ever geeky enough to have raised code reuse as a conversation piece, you&#39;ll probably notice that almost everybody have something good to say about it, from a vague feel-good feeling about how good a thing it is, to how it may have profoundly changed a person&#39;s life (ok, I exaggerated about this one). If you had to ask anybody for 5 good examples, I&#39;m sure you&#39;ll be hard pressed to find anybody with a sensible answer. How about we start with yourself: when was the last time you&#39;ve reused your own code in a meaningful, substantive way?&lt;br /&gt;&lt;br /&gt;These days, the only visible code reuse I know of, is only when I rely on code from a software library - often an external library written by somebody else. Be it a data structure, a fancy graphical widget, or complex mathematical computations, there is probably a library out there which will cater to your need. Writing from scratch is something you never seem to do anymore.&lt;br /&gt;&lt;br /&gt;But relying on software libraries is just not &lt;span style=&quot;font-style: italic;&quot;&gt;my&lt;/span&gt; romanticised version of code reuse, the one where the object-oriented programming paradigm had so promised so long ago. Remember the textbook claims on writing your own well-abstracted objects, and how you&#39;ll be rewarded in reusing them for all perpetuity? Personally, that lofty promise has certainly fallen short of my expectations from when I was a starry-eyed kid coding in OOP for the first time, to the more experienced software developer today.&lt;br /&gt;&lt;br /&gt;So what went wrong? Nothing actually.&lt;br /&gt;&lt;br /&gt;Code that has well-defined purposes, inputs and outputs, which are so often used, are easily defined and hence usually gets &#39;factorised&#39; into code libraries. These libraries get battle-tested by many other developers over time, ironing out any residual kinks, as well as any lingering bugs. Over time, a well-used library makes more compelling sense to use than to roll your own, since it minimises the risk and uncertainty from newly introduced code.&lt;br /&gt;&lt;br /&gt;So whatever&#39;s that&#39;s left for you to work on, are likely new and unique issues you are solving, making it naturally unfactorisable. And if certain portions of code do become apparent enough for you to find a commonality, that&#39;s perhaps when you&#39;ll refactor your own code to reuse these commonalities, although I suspect the possibility of such situations are getting less likely. Maybe like me, you&#39;re feeling a little cheated as well.&lt;br /&gt;&lt;br /&gt;Code reuse today is just an euphemism of relying on other people&#39;s code - well, it is still reuse, just not your own code, not unless you happen to be a software library writer. But chances are, you are usually not.&lt;br /&gt;&lt;br /&gt;I might as well go one step further and declare that we never reuse our own code anymore - as a corollary to the famous &lt;a href=&quot;http://en.wikipedia.org/wiki/Parkinson%27s_Law_of_Triviality&quot;&gt;Bikeshed Problem&lt;/a&gt;. Not all of us will gain sufficient experience in building our own nuclear reactor (or more efficient data structures and algorithms), so what&#39;s left remaining is only to focus on the colour of the bikeshed (or button placements within a HTML form) because that&#39;s the only thing that&#39;s left to do when other people have done all the heavy lifting for you. And that&#39;s how it &lt;span style=&quot;font-style: italic;&quot;&gt;should&lt;/span&gt; be, after all, didn&#39;t they tell us not to reinvent the wheel?&lt;br /&gt;&lt;br /&gt;It&#39;s why any boy and his dog today can write an application with some knowledge of HTML, CSS and Javascript -  nobody needs to know how to code a rasteriser for transforming vectors into pixels, write their own graphics routines so that they can display a button, input, or to write their own binary search tree in order to use a hashmap, since they don&#39;t have to - the first principles of software systems are all conveniently abstracted into libraries, frameworks, and easy APIs that they can use.&lt;br /&gt;&lt;br /&gt;It is not a bad thing, but it is also to no wonder why any arts major can simply write a web application and proclaim themselves to be a software developer these days. While I wouldn&#39;t mind them doing a webpage for me, I won&#39;t go as far to trust a lay-coder on anything that&#39;s of any&amp;nbsp;algorithmic complexity.&lt;br /&gt;&lt;br /&gt;On the flip side, it&#39;s never been better to be a software developer; we are more productive from the assortment of libraries that are at our disposal, from the myriad software frameworks to numerous tools that we utilise today - all of which has allowed us to write software systems that would be difficult in the past, a relative breeze today.&lt;br /&gt;&lt;br /&gt;As software development goes these days, we are indeed standing on the shoulders of giants.&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/1059593468196904073/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2012/09/have-you-ever-reused-code.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/1059593468196904073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/1059593468196904073'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2012/09/have-you-ever-reused-code.html' title='Have you ever reused code?'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-3576922166955957982</id><published>2012-09-07T06:00:00.000+01:00</published><updated>2012-09-07T06:00:09.577+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Vim"/><title type='text'>Vim: When Copy and Paste doesn&#39;t work ...</title><content type='html'>I used to remember that copying and pasting to the clipboard used to work a long while ago, but I just couldn&#39;t remember what &lt;i&gt;exactly &lt;/i&gt;did I do in order to get it to work. That were the days where I was still bothered enough to tweak things to get it running - these days I just want to get things to work, which many will arguably retort that what I&#39;m asking for is&amp;nbsp;&lt;i&gt;impossible&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;While Linux may be perceived as still a much less-accessible OS compared to the ones that you have to pay for, it actually works pretty well once you&#39;ve gone past the learning curve. But from time-to-time, you can still be surprised with what you don&#39;t know. It can feel like a hassle sometimes, but on the flip-side, learning new things is what makes using it fun. (Sure many may disagree on that too - and if you are one of them, I&#39;ll save you the torture; shut your brain down and go back to surf your Facepage instead ;p)&lt;br /&gt;&lt;br /&gt;I remembered about having to recompile vim from dog years ago, and started to look at what&#39;s missing in the standard &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;vim-enhanced&lt;/span&gt; package; lo-and-behold, the version flag shows the following:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;$ /usr/bin/vim --version&lt;br /&gt;VIM - Vi IMproved 7.3 (2010 Aug 15, compiled Nov 16 2010 17:05:25)&lt;br /&gt;Included patches: 1-56&lt;br /&gt;Modified by &lt;bugzilla@redhat.com&gt;&lt;br /&gt;Compiled by &lt;bugzilla@redhat.com&gt;&lt;br /&gt;Huge version without GUI.  Features included (+) or not (-):&lt;br /&gt;+arabic +autocmd -balloon_eval -browse ++builtin_terms +byte_offset +cindent &lt;br /&gt;-clientserver -clipboard +cmdline_compl +cmdline_hist +cmdline_info +comments &lt;br /&gt;+conceal +cryptv +cscope +cursorbind +cursorshape +dialog_con +diff +digraphs &lt;br /&gt;-dnd -ebcdic +emacs_tags +eval +ex_extra +extra_search +farsi +file_in_path &lt;br /&gt;+find_in_path +float +folding -footer +fork() +gettext -hangul_input +iconv &lt;br /&gt;+insert_expand +jumplist +keymap +langmap +libcall +linebreak +lispindent &lt;br /&gt;+listcmds +localmap -lua +menu +mksession +modify_fname +mouse -mouseshape &lt;br /&gt;+mouse_dec +mouse_gpm -mouse_jsbterm +mouse_netterm -mouse_sysmouse &lt;br /&gt;+mouse_xterm +multi_byte +multi_lang -mzscheme +netbeans_intg -osfiletype &lt;br /&gt;+path_extra +perl +persistent_undo +postscript +printer +profile +python &lt;br /&gt;-python3 +quickfix +reltime +rightleft +ruby +scrollbind +signs +smartindent &lt;br /&gt;-sniff +startuptime +statusline -sun_workshop +syntax +tag_binary &lt;br /&gt;+tag_old_static -tag_any_white -tcl +terminfo +termresponse +textobjects +title&lt;br /&gt; -toolbar +user_commands +vertsplit +virtualedit +visual +visualextra +viminfo &lt;br /&gt;+vreplace +wildignore +wildmenu +windows +writebackup -X11 -xfontset -xim -xsmp&lt;br /&gt; &lt;b&gt;-xterm_clipboard&lt;/b&gt; -xterm_save &lt;br /&gt;   system vimrc file: &quot;/etc/vimrc&quot;&lt;br /&gt;     user vimrc file: &quot;$HOME/.vimrc&quot;&lt;br /&gt;      user exrc file: &quot;$HOME/.exrc&quot;&lt;br /&gt;  fall-back for $VIM: &quot;/etc&quot;&lt;br /&gt; f-b for $VIMRUNTIME: &quot;/usr/share/vim/vim73&quot;&lt;br /&gt;Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H     -O2 -g -pipe -Wall  -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64  -D_FORTIFY_SOURCE=1     &lt;br /&gt;Linking: gcc   -L.  -rdynamic -Wl,-export-dynamic  -Wl,--enable-new-dtags -Wl,-rpath,/usr/lib64/perl5/CORE   -L/usr/local/lib -Wl,--as-needed -o vim       -lm -lnsl  -lselinux  -lncurses -lacl -lattr -lgpm -ldl    -Wl,--enable-new-dtags -Wl,-rpath,/usr/lib64/perl5/CORE  -fstack-protector  -L/usr/lib64/perl5/CORE -lperl -lresolv -lnsl -ldl -lm -lcrypt -lutil -lpthread -lc -L/usr/lib64/python2.7/config -lpython2.7 -lpthread -ldl -lutil -lm -Xlinker -export-dynamic   -lruby -lpthread -lrt -ldl -lcrypt -lm   &lt;br /&gt;&lt;/bugzilla@redhat.com&gt;&lt;/bugzilla@redhat.com&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The compiler flag &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;xterm_clipboard&lt;/span&gt; isn&#39;t compiled with standard text mode vim, that was the main reason that I had to recompile vim in the past!&lt;br /&gt;&lt;br /&gt;But these days, I&#39;m lazy. I much rather not have to recompile and maintain my own packages if I have to, and it turns out that I&#39;m in luck - a bit of digging showed that the &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;vim-X11&lt;/span&gt; package contains &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;vimx&lt;/span&gt;, a version of vim that has the&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt; xterm_clipboard&lt;/span&gt; flag enabled. Happy days!&lt;br /&gt;&lt;br /&gt;So just do:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;$ sudo yum install vim-X11&lt;br /&gt;$ alias vim=$(which vimx)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The alias command just makes it easier given I&#39;m so used to typing vim than vimx, so that I don&#39;t have to undo my habit :)&lt;br /&gt;&lt;br /&gt;So how do you make use of the clipboard? Let say you have mouse mode on (set mouse=a), and selected some text using your mouse; in order to send it to the clipboard, do&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&quot;+y&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note that the quote isn&#39;t a typo. To paste from the clipboard into vim, do:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&quot;+p&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt; Bonus trick. You can make your selection in normal mode automatically be sent to the x11 clipboard by making this configuration:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;set go+=a&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt; Have fun! :D&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/3576922166955957982/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2012/09/vim-when-copy-and-paste-doesnt-work.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/3576922166955957982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/3576922166955957982'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2012/09/vim-when-copy-and-paste-doesnt-work.html' title='Vim: When Copy and Paste doesn&#39;t work ...'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-1918318083311397817</id><published>2012-08-31T06:00:00.001+01:00</published><updated>2012-08-31T06:00:00.306+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><title type='text'>Adding extra jar files to Ant path in Fedora/RHEL</title><content type='html'>&lt;br /&gt;The default RPM packaged version of &#39;Ant&#39; that comes with Fedora/JPackage doesn&#39;t doesn&#39;t respect the $ANT_HOME environment variable the same way as if you have downloaded and installed it directly from Apache itself.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;These days, having a little more to do with J2EE work as they are good sample applications for testing our JVM, I&#39;m having to pick up various build tools that I don&#39;t normally use, like Apache Ivy and Maven. Ivy works as an additional jar to supercharge Ant&#39;s capabilities, and hence a post as a self reminder. There are essentially 2 ways of accomplishing the task:&lt;br /&gt;&lt;br /&gt;1) Put &quot;ivy.jar&quot; into our custom development distro by default into /usr/share/ant/lib. This is a nice option for all developers, since we won&#39;t need to do anything extra for it to work. But it isn&#39;t tracked by package management (ie not an RPM), and neither should developers put in the file into /usr/share/ant/lib just because we have local superuser rights, since management of these issues should be done by the sysadmin, automatically if possible.&lt;br /&gt;&lt;br /&gt;2) Workaround this situation by having a local override of the Ant configuration. Create the following directory structure in your $HOME/.ant directory, eg.&lt;br /&gt;&lt;br /&gt; &lt;pre&gt;&lt;br /&gt;&lt;br /&gt;[vincentliu@workstation08 ~]$ tree $HOME/.ant&lt;br /&gt;/home/vincentliu/.ant&lt;br /&gt;|-- ant.conf&lt;br /&gt;`-- lib&lt;br /&gt;     `-- ivy.jar&lt;/pre&gt; &lt;br /&gt;&lt;br /&gt;In the ant.conf file, have the following lines: &lt;br /&gt;&lt;br /&gt; &lt;pre&gt;&lt;br /&gt;&lt;br /&gt;[vincentliu@workstation08 ~]$ cat $HOME/.ant/ant.conf&lt;br /&gt;# Need to override the existing $ANT_HOME path that JPackage customized&lt;br /&gt;# to add in the ivy package as part of Ant&#39;s classlib&lt;br /&gt;CLASSPATH=$HOME/.ant/lib/ivy.jar&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Copy the ivy.jar file into $HOME/.ant/lib directory. And these changes will allow you to compile use Apache Ivy natively without littering multiple copies of it per project.&amp;nbsp;&lt;/div&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/1918318083311397817/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2012/08/adding-extra-jar-files-to-ant-path-in.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/1918318083311397817'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/1918318083311397817'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2012/08/adding-extra-jar-files-to-ant-path-in.html' title='Adding extra jar files to Ant path in Fedora/RHEL'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-6888026491667310519</id><published>2012-08-24T06:00:00.000+01:00</published><updated>2012-08-24T06:00:09.476+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Software Development"/><title type='text'>Google Drive does not work if your network is slow</title><content type='html'>&lt;br /&gt;I solely use Google Docs, erm Drive, for working with documents these days.&amp;nbsp;While it&#39;s named &quot;Drive&quot; now, I&#39;ll refer it as the old incarnation &quot;Docs&quot; as it&#39;s&amp;nbsp;the document editor that I&#39;m about to rant here.&lt;br /&gt;&lt;br /&gt;Google Docs as an editor, is simple to use, and is very accessible - there is&amp;nbsp;no need to install any specific software for it, all you need to do is to open&amp;nbsp;it up through the web browser. But the best thing I like about it, is that I&amp;nbsp;can edit the document without a care and not have to worry about saving the&amp;nbsp;document somewhere so that I can resume editing elsewhere later. Everything is&amp;nbsp;available as long as I have access to the Internet.&lt;br /&gt;&lt;br /&gt;Now, that&#39;s all fine and dandy, except if you have a &quot;slow&quot; connection. And when&amp;nbsp;I say &quot;slow&quot;, I don&#39;t mean the archaic 56kbps speeds back in the heyday where&amp;nbsp;people still dial-up a modem connected to a copper phone line. Slow in Google&#39;s&amp;nbsp;context, apparently meant anything at mobile broadband speeds (@1mbps).&lt;br /&gt;&lt;br /&gt;Google Docs had been working fine, prior to the fairly recently change they&#39;ve&amp;nbsp;introduced the &quot;we&#39;ll save as you type&quot; feature. The old Google Docs&amp;nbsp;wasn&#39;t that bandwidth hungry since saving the document was in coarser time blocks&amp;nbsp;instead of the consistent synching that they are doing now.&lt;br /&gt;&lt;br /&gt;With the recent changes, Google Docs appear to either suck up more bandwidth, or&amp;nbsp;have lower latency requirements that my humble mobile broadband dongle does&amp;nbsp;not appear to satisfy anymore. For whatever I type in, after 2 minutes working&amp;nbsp;into the document, Google Docs will just hang at &quot;Saving...&quot; and then produce&amp;nbsp;this screen:&lt;br /&gt;&lt;br /&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-esB5MUjHEkU/UDANRzcDaKI/AAAAAAAAAV8/TC6xeI3zwHA/s1600/Google+Docs+Suck.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;185&quot; src=&quot;http://2.bp.blogspot.com/-esB5MUjHEkU/UDANRzcDaKI/AAAAAAAAAV8/TC6xeI3zwHA/s320/Google+Docs+Suck.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;This error is consistently reproducible, and it&#39;s not even a complex document&amp;nbsp;we&#39;re talking about here - it&#39;s essentially a text file editable by vim that I&amp;nbsp;copy and paste into sometimes. I don&#39;t get how Google gets this so wrong - we&#39;re&amp;nbsp;talking about a document editor for a simple file, for god&#39;s sake, what kind of&amp;nbsp;network requirements do you need in order to make it work?!&lt;br /&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/6888026491667310519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2012/08/google-drive-does-not-work-if-your.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/6888026491667310519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/6888026491667310519'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2012/08/google-drive-does-not-work-if-your.html' title='Google Drive does not work if your network is slow'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-esB5MUjHEkU/UDANRzcDaKI/AAAAAAAAAV8/TC6xeI3zwHA/s72-c/Google+Docs+Suck.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-6239549830730744424</id><published>2012-03-17T22:04:00.000+00:00</published><updated>2012-09-01T12:31:13.555+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Life"/><title type='text'>Happy St. Patricks!</title><content type='html'>It&#39;s been busy, but I haven&#39;t forgotten.  Shout out to all my friends:  Work has been busy, but life is chugging along.  Will need to catch up with everyone soon.  Till then, remember your friend in the Emerald Isle :D&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/6239549830730744424/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2012/03/happy-st-patricks.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/6239549830730744424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/6239549830730744424'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2012/03/happy-st-patricks.html' title='Happy St. Patricks!'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-5152155577621567760</id><published>2011-07-11T00:26:00.011+01:00</published><updated>2012-04-22T19:16:51.364+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Software Development"/><title type='text'>The x86_64 Calling Convention</title><content type='html'>&lt;br /&gt;I suppose I can consider myself an &#39;old-school&#39; developer now; even though I have been reading the &lt;a href=&quot;http://www.x86-64.org/documentation/abi.pdf&quot;&gt;AMD64 ABI&lt;/a&gt; documentation, I still haven&#39;t fully absorbed it into my head yet, which is evidenced by the recent two situations I had today where &lt;a href=&quot;http://blog.vinceliu.com/2007/09/do-not-rtfm.html&quot;&gt;RTFM&lt;/a&gt;-ing would have had saved me hours of GDB debugging pain.&lt;br /&gt;&lt;br /&gt;I have been coding some assembly instructions to make C-calls at runtime to a debugging routine, but the call seems to always ends up mysteriously trampling the JIT-ed routines, making the VM take unexpected execution paths and causing some unlikely assertions to be fired.&lt;br /&gt;&lt;br /&gt;The situation is confounded by a number of issues:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;the code generated is dynamic, and therefore there are no debugging symbols associated with them compared to code typically generated by the assembler/compiler;&lt;/li&gt;&lt;li&gt;there are different types of call-frames for a given method; 1 for a pre-compiled stub, 1 for a frame that&#39;s crossed-over from JIT-ed code to native code, and 1 for the JIT-ed code itself;&lt;/li&gt;&lt;li&gt;when the eventual assertion does manifest, the code is already far away in the rabbit-hole from where the original problem manifested. And because some of the JIT-ed code actually makes a &quot;JMP&quot;, unlike a &quot;CALL&quot;, you can&#39;t actually figure out where the code originated from, since %rip is never saved on the call stack.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;While situations 1 and 2 make debugging difficult by having the need to keep a lot of contextual information in order to figure out what&#39;s going on, situation 3 is just impossible to debug if the bug is non-deterministic in nature. For example, each compiled method in the VM generates a small assembly stub that replaces the actual code to be executed; when the stub gets executed for the first time, it triggers of the JIT compiler at runtime to compile the real method from its intermediate representation. The compiled method then replaces the stub, hence subsequent invocations will simply call the already JIT-generated method, thereby executing at native-speed, like just as you would get on compiled code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To optimise on space, the stubs are made as small as possible (~20 bytes), and the common execution body shared by all stubs is factored into a common block. All stubs will eventually perform a global &quot;JMP&quot; instruction to this common block. In order to faciliate communication, all shared data between the stub and the common code block is passed on the thread stack, where the common offset to the method handle is agreed upon.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;While the design is elegant, it is also impossible to debug when it breaks; the non-deterministic-ness of the bug seems to surface from time-to-time, where it seems to suggest that the thread stack got corrupted or that it&#39;s not passing the method handle correctly. Even when GDB is left running, by the time the assertion triggers, it&#39;s already past the fact, and therefore it is unable to trace back to the originating path.&lt;br /&gt;&lt;br /&gt;I thought it might be a good idea to inject some debugging calls to trace the execution and stack pointer at runtime, so that I can figure out which stub was last called and the stack height when the call was made; the two information combined should give me sufficient hints on where the problem might lie.&amp;nbsp;However, my injected code has introduced two other issues that I had overlooked, which brings me back into the discussion of the x86_64 ABI again; if you ever wanted to template any assembly instructions into your code that relies on an external library call, do keep these 2 points from the ABI specification in mind:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Save ALL caller-saves registers, not just only the ones that you are using.&lt;/li&gt;&lt;li&gt;(§3.2.2) The end of the input argument area shall be aligned on a 16 (32, if __m256 is&amp;nbsp;passed on stack) byte boundary. In other words, the value (%rsp + 8) is always&amp;nbsp;a multiple of 16 (32) when control is transferred to the function entry point. The&amp;nbsp;stack pointer, %rsp, always points to the end of the latest allocated stack frame.&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;I have to say that I&#39;ve dismissed (1) since I&#39;ve gotten use to the style of only documenting and saving the registers that was used; the convention was something that I had picked up from Peter Norton&#39;s 1992 book, &quot;Assembly Language for the PC&quot;. For those who don&#39;t know, he&#39;s the &quot;Norton&quot; that Symantec&#39;s Norton Antivirus is named after. I still have the out-of-print book on my desk as a keepsake; it reminds me of the the memories of reading it and scribbling code on a piece of paper at my local library. Remarkably, that was how I learnt assembly, since I didn&#39;t have a computer back then. Thumbing through the book today, I still have an incredible respect for Peter&#39;s coding&amp;nbsp;prowess. He had a way of organising his procedures so elegantly such that each of them all fitted perfectly together from chapter to chapter.&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;http://ecx.images-amazon.com/images/I/51VltHvdjbL._SL500_AA300_.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://ecx.images-amazon.com/images/I/51VltHvdjbL._SL500_AA300_.jpg&quot; style=&quot;cursor: move;&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Sorry, got sidetracked. So yes, point (1) - to save ALL registers; this is necessary because all caller-saved registers can actually be occupied by the JIT routines as input arguments to the callee; while this typically means the 6 defined registers (%rdi, %rsi, %rdx, %rcx, %r8, %r9) for general input (see&amp;nbsp;§3.2.3), other registers can also be trashed upon a call return, so as a rule-of-thumb save everything, except the callee-saved registers (%rbx, %rbp, %r12 to %r15), which&amp;nbsp;are guaranteed to be preserved.&lt;br /&gt;&lt;br /&gt;Point (2) - I haven&#39;t observed a reproducible side effect from this; however the failure points between adhering to it and not actually causes a visible difference in the JIT-ed code&#39;s path; therefore there is a need to be on the side of caution. I seem to have observed that some memory faults from not following this directive, but I can&#39;t ascertain this for a fact yet.&lt;br /&gt;&lt;br /&gt;Finally, a self-inflicted bug that I&#39;d like to remind myself of; remember make sure to deduct from %rsp if any memory has been written onto the thread stack; otherwise any function calls may unknowingly overwrite it!&lt;br /&gt;&lt;br /&gt;For all the trouble with debugging that I&#39;ve gotten myself into, there is at least a silver-lining to it; I had made the problem deterministic, or if it isn&#39;t the same problem, it was a similar class of problem that I can consistently reproduce to analyse its behaviour and learn from the mistakes I have been making. Because of the determinism, I was able to use &lt;a href=&quot;http://blog.vinceliu.com/2009/09/gdb-70-is-out.html&quot;&gt;GDB&#39;s reversible debugging&lt;/a&gt; feature to record the execution from the stub to the common code to gain a better understanding of how the generated code actually works. It&#39;s a really nifty feature, and I&#39;m glad to have it as my first useful case of applied reversible debugging in practice.&lt;/div&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/5152155577621567760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2011/07/x8664-calling-convention.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/5152155577621567760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/5152155577621567760'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2011/07/x8664-calling-convention.html' title='The x86_64 Calling Convention'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-7577759317839379105</id><published>2011-06-04T18:30:00.008+01:00</published><updated>2012-09-01T12:20:38.541+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Software Development"/><title type='text'>Page Faults</title><content type='html'>While going through some code emitted by a Just-In-Time compiler (JIT), I’ve encountered a curious piece of code which suggested that if access to the process&#39; utilisable stack space isn’t done incrementally, it will cause an “access violation”.&lt;br /&gt;&lt;br /&gt;Normally, I wouldn’t have bothered with the problem. But in this case, the JIT-ed code makes uninitialised reads to the process stack, causing valgrind to generate a huge amount of spurious warnings in its log. This makes it difficult to sieve through relevant details, and makes it impossible to generate a static suppression for because the JIT-ed code&#39;s call frames are dynamically generated and arbitrary in nature.&lt;br /&gt;&lt;br /&gt;I didn’t see what’s wrong with touching memory that&#39;s already accessible by the application, so I didn’t really grok what the “access violation” exactly implies. A little sleuthing is required, so I wrote a little code to test out the “access violation”:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#.equ INCREMENT, 0x1000&lt;br /&gt;.equ INCREMENT, 0x1800&lt;br /&gt;&lt;br /&gt;.section .text&lt;br /&gt;&lt;br /&gt;FORMAT_STR:&lt;br /&gt; .string &quot;%d\n&quot;&lt;br /&gt;&lt;br /&gt;.globl _start&lt;br /&gt;_start:&lt;br /&gt; push %rbp&lt;br /&gt; movq %rsp, %rbp&lt;br /&gt;&lt;br /&gt; # loop and keep touching stack space&lt;br /&gt; movq $640, %rcx&lt;br /&gt; movq $-0x1000, %rbx&lt;br /&gt;again:&lt;br /&gt; movq (%rbp, %rbx), %rax&lt;br /&gt; subq $INCREMENT, %rbx&lt;br /&gt;&lt;br /&gt; movq %rbx, %r12   # use callee-save to prevent push to stack   &lt;br /&gt; movq %rbx, %rsi&lt;br /&gt; movq $FORMAT_STR, %rdi&lt;br /&gt; movq $0, %rax&lt;br /&gt; call printf       # but call pushes to stack too :(&lt;br /&gt; movq %r12, %rbx&lt;br /&gt; loop again&lt;br /&gt;&lt;br /&gt; movq $1, %rbx&lt;br /&gt; movq $1, %rax&lt;br /&gt; int $0x80&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note the commented code at the first line; this represents the original page size boundary in which the JIT emitted that’s causing the offending uninitialised memory access; if the size isn’t extended, the code will segmentation fault at around the 8MB mark. The corresponds to what ‘ulimit -s’ reports on the OS.&lt;br /&gt;&lt;br /&gt;However, if the size gets incremented to 0x1800 bytes for example, the code will segmentation fault way much earlier, at around the 140k mark, which puzzled me. Looking at ‘dmesg’ shows something interesting:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[806331.042666] incremental[28910]: segfault at 7fff983ad8a8 ip 0000000000400256 sp 00007fff983cf8a8 error 4 in incremental[400000+1000]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I’m surprised that the kernel actually reports this error, so I started searching for the error string on Google code search. The likely matches came from &lt;a href=&quot;http://www.google.com/codesearch/p?hl=en#bXCwqadbOuY/winsup/cygwin/exceptions.cc&amp;amp;q=%22segfault%20at%22%20%22error%20%25d%22&amp;amp;sa=N&amp;amp;cd=3&amp;amp;ct=rc&amp;amp;l=679&quot;&gt;cygwin&lt;/a&gt; which does mention “access violation” and &lt;a href=&quot;http://www.google.com/codesearch/p?hl=en#HTrPUplLEaU/Research/SRG/netos/xen/downloads/xen-3.0.1-src.tgz%7CI_J3heDqS9U/xen-3.0.1/linux-2.6-xen-sparse/arch/xen/i386/mm/fault.c&amp;amp;q=%22error_code%20%7C=%204%22&amp;amp;l=301&quot;&gt;xen-source&lt;/a&gt; where it indicates a &lt;a href=&quot;http://en.wikipedia.org/wiki/Page_fault&quot;&gt;page fault&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Reading through the definition suggests that I’m causing a hard page fault, but I wanted to make sure that the error code 4 is exactly meaning this. Some cursory research led me to a pretty helpful &lt;a href=&quot;http://www.cs.nmsu.edu/~pfeiffer/classes/474/notes/linux-page-fault.html&quot;&gt;CS page explaining page faults&lt;/a&gt;, with excerpts from Linux 1.0’s sources; scanning through it which showed that &quot;error 4&quot; means that the error comes from user space (as opposed to kernel space).&lt;br /&gt;&lt;br /&gt;The code also indicates that if an allocation exceeds the OS page size, the kernel is free to abort the program, which explains the error. Further research also led me to the getpagesize() system call, which verified that the page size for Linux is set at 4KB.&lt;br /&gt;&lt;br /&gt;So mystery solved. I suppose the next thing I can do, is to make a nasty hack in the JIT to make spurious writes instead of reads instead; that should get rid of all the valgrind false positives, but I can’t say it’s the most elegant way of resolving the issue.&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/7577759317839379105/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2011/06/while-going-through-some-code-emitted.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/7577759317839379105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/7577759317839379105'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2011/06/while-going-through-some-code-emitted.html' title='Page Faults'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-3157000718249659436</id><published>2011-04-17T00:29:00.006+01:00</published><updated>2011-04-17T01:07:36.969+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><title type='text'>The Future of Linux UI Scares Me</title><content type='html'>I don’t think I have mentioned that I moved from Ubuntu to Fedora. Two years ago.&lt;br /&gt;&lt;br /&gt;Why has this to do with the state of the Linux desktop? I’d say at least somewhat to do with it. When I last switched from Gentoo to Ubuntu, it was due to the eventual frustration with the incessant amount of tinkering I had to do in order to get things work.&lt;br /&gt;&lt;br /&gt;Most people would have jumped the bandwagon and moved to the newer, and trendy MacOSX. But you know what? What most Linux windows manager have is the “focus follows mouse” feature, which is the most Zen-like simplicity that no other non-unix OSes have. That was why I swapped to Ubuntu, which was the new poster-boy for the “Linux that Just Works”.&lt;br /&gt;&lt;br /&gt;The charm however, did not last. “apt-get” was the loveliest feature that I embraced, and it was great that Ubuntu finally fast-tracked Debian to bring forth the most bleeding edge of software packages, albeit with a higher defect rate than the rock solid Debian. Even so, the defect rate in Ubuntu wasn’t something that I perceptively noticed. Not until it came to development tools.&lt;br /&gt;&lt;br /&gt;Fedora is the undisputed leader for being the distro by the developers, for the developers. Ubuntu is great, but only when you don’t have to tinker under the hood. If you are, then be prepared for pain. Badly configured packages like GDB, with debugger instability and crashes, and badly placed debugging symbols for packages made it hard to treat Ubuntu as a serious development environment.&lt;br /&gt;&lt;br /&gt;It so happened that my company was relocating, and as part of the transition, it was just a good time to think about the software infrastructure that we were using, and to set things up correctly. It was also fortuitous that at the same time, we had hired a very capable sysadmin who is an expert on Redhat based distros, so the decision was to maintain one and one (free) distribution only - Fedora.&lt;br /&gt;&lt;br /&gt;I have to say it has been a good choice; personally, I think the QA behind Fedora is very solid generally, and especially in developer tools. But what I thought had been a good choice was that Fedora stuck to the original Gnome desktop where everything was simple, like Windows 98 simple. No, it isn’t a pun; older desktop environments did get it correct, like how OS/2, Windows XP and the KDE 3.x did. They just worked.&lt;br /&gt;&lt;br /&gt;There is nothing wrong with the existing paradigm of having an app-menu selector, a taskbar, and a widget area for notifications, plus a few bells and whistles here and there. But Ubuntu decided that it wasn’t good enough; “No, we’ve got to look like Apple”, Mark Shuttleworth says. Then he starts tinkering with the menu icons, switching it from the right hand side to the left.&lt;br /&gt;&lt;br /&gt;I’m glad that I’ve left Ubuntu before then; I&#39;m sure he must have realised that getting about 80% of the desktop users to make a context switch of a long-established habit won&#39;t be pleasant. It’s like telling a heroine addict that going cold-turkey is a piece of cake. Bad analogy? But you get the point.&lt;br /&gt;&lt;br /&gt;Then Mark decides that a singular change isn’t enough, “I have an idea, let’s revamp the whole desktop altogether!” And this is how the Unity interface came about. Still, that’s ok. Ubuntu is Mark’s baby, he’s entitled to drive the design of his distro any way he likes.&lt;br /&gt;&lt;br /&gt;I don’t really have much to say about Unity, since I’ve never used it. I don’t think I will anyway; it looks too different to what I have come to be very comfortable with as a desktop environment. But it is not just that I ain&#39;t adventurous; field reports from users who had tried it just didn’t look encouraging.&lt;br /&gt;&lt;br /&gt;However, the bad news is, Gnome 3 will start shipping the new Gnome-shell interface, which appears to have taken a leaf from Unity&#39;s design. It means that Gnome will be the last major window manager to jump the shark. Well so long Gnome, it’s fun while it lasted.&lt;br /&gt;&lt;br /&gt;Fedora 15 will be shipping with Gnome 3. The thought of upgrading makes me shudder. Will I be productive with it, or will I be &quot;enjoying&quot; my time in discovering what new features the new UI will bring? Unfortunately, I don’t understand what all that fuss about, competing to reinvent the desktop. I’ll just get a Mac instead*.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;*Oh wait, that’s a joke. Don’t get too upset, my Mac fanboy friends. I’ll show you my new shiny Xfce-compiz desktop, or my zen-like fluxbox windows manager. Trust me, you’ll love it.&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/3157000718249659436/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2011/04/future-of-linux-ui-scares-me.html#comment-form' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/3157000718249659436'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/3157000718249659436'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2011/04/future-of-linux-ui-scares-me.html' title='The Future of Linux UI Scares Me'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-600205810371348655</id><published>2011-04-02T21:37:00.005+01:00</published><updated>2012-09-01T12:30:10.534+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Software Development"/><title type='text'>No Technical Support Provided</title><content type='html'>Readers,&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you&#39;re came here through the links from my other blog posts, please take time to read what I have to say.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The solutions to the problems I solve, are large done to &quot;scratch my own itch&quot;. I like to share these solutions through my blog with the hope that it&#39;ll be useful to others facing the same issues. However, I have a pretty intense full-time job in my own company, which leaves me very little time to be providing any specific guidance in any related problems that you may face.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You may want to comment on the blog post, and hopefully, some good Samaritans may give out more wisdom or advice. Or you may be the one who&#39;s giving help to others, and good on you if that&#39;s the case. That is what community spirit is all about.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Unfortunately, I cannot be here to provide technical support for you and if I don&#39;t have further insight or time to the problems you have, you are largely on your own.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thank you for understanding.&lt;/div&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/600205810371348655/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2011/04/no-technical-support-provided.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/600205810371348655'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/600205810371348655'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2011/04/no-technical-support-provided.html' title='No Technical Support Provided'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-3382151403895667802</id><published>2011-03-31T21:31:00.003+01:00</published><updated>2011-03-31T22:54:08.924+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Life"/><title type='text'>Finding the inclination to write</title><content type='html'>I&#39;m still here; yes, I have been very quiet.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Mostly because I&#39;m busy with things. Work mainly. Some aspects I do not enjoy, but it is still fun when it comes to the technical bits. Enjoying those!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Off work, life consists of quite a bit of physical training, something I have come to enjoy too. That is complementary to another habit of mine: sleep. I&#39;m sleeping sufficiently early to wake up for exercise these days. That is a luxury for most people. Ask yourself, when is the last time you have had a good sleep? People are usually so sleep deprived these days, which is sad, &lt;a href=&quot;http://dailycontributor.com/research-says-less-sleep-causes-depression/10139/&quot;&gt;literally&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It does mean I sacrifice other material enjoyments in life; TV watching, net surfing or out having a few late night drinks with friends. I don&#39;t miss them much, perhaps just a little bit on the socialising. But there&#39;s no point in hanging out late in this &lt;a href=&quot;http://en.wikipedia.org/wiki/Ireland&quot;&gt;country&lt;/a&gt;; people tend to go overboard with their drinks - there&#39;ll hardly be any sensibilities left for meaningful interactions after late ... but I think a lot of people here will digress!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Life is coasting along. It does feel a little aimless sometimes. But then again, what is there to be aiming for? Does it matter whether if you have not done the gazillon things that you wanted to do? In the long run, we are all dead anyway. Maybe that&#39;s not enough, for we need that epitaph to survive us?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Well right now, it is enough.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For myself, keep writing. For my friends, keep in touch.&lt;/div&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/3382151403895667802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2011/03/finding-inclination-to-write.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/3382151403895667802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/3382151403895667802'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2011/03/finding-inclination-to-write.html' title='Finding the inclination to write'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-7831779082753802835</id><published>2010-06-05T23:29:00.003+01:00</published><updated>2012-09-01T12:20:38.545+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JVM"/><category scheme="http://www.blogger.com/atom/ns#" term="Software Development"/><title type='text'>Why a volatile is different in C/C++ and Java</title><content type='html'>The &lt;span style=&quot;font-family:courier new;&quot;&gt;volatile&lt;/span&gt; keyword is highly subjective to the  language and the platform it is implemented on. While Java provides a  consistent behaviour of &lt;span style=&quot;font-family:courier new;&quot;&gt;volatile&lt;/span&gt; across  all architectures, this is not the case for languages that are directly  compiled into the native machine platform, such as in the case of C/C++.  Let&#39;s try to understand why this is the case.&lt;br /&gt;&lt;br /&gt;Let &lt;img alt=&quot;a,  b&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a%2C%20b&quot; style=&quot;vertical-align: middle;&quot; /&gt; be member of a set of program actions &lt;img alt=&quot;P&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=P&quot; style=&quot;vertical-align: middle;&quot; /&gt;, and &lt;img alt=&quot;v_{n} (a)&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=v_%7Bn%7D%20%28a%29&quot; style=&quot;vertical-align: middle;&quot; /&gt; be function that applies the  volatility requirement to an action, where the subscript &lt;img alt=&quot;_n&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=_n&quot; style=&quot;vertical-align: middle;&quot; /&gt; denotes the &lt;img alt=&quot;_n&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=_n&quot; style=&quot;vertical-align: middle;&quot; /&gt;-th iteration in which a volatile  action is applied, and &lt;img alt=&quot;\rightarrow&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%5Crightarrow&quot; style=&quot;vertical-align: middle;&quot; /&gt; be the precedes operator, which is  explained &lt;a href=&quot;http://blog.vinceliu.com/2010/05/concurrency-vs-multi-threading.html&quot; id=&quot;n4qr&quot; title=&quot;previously&quot;&gt;previously&lt;/a&gt;. For all program actions,  the following rules holds:&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;margin-left: 40px;&quot;&gt;&lt;img alt=&quot;v_n(a) \rightarrow v_{n+1}(a)&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=v_n%28a%29%20%5Crightarrow%20v_%7Bn%2B1%7D%28a%29&quot; style=&quot;vertical-align: middle;&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img alt=&quot;a \rightarrow v_n(b)  \Rightarrow a \rightarrow v_{n+i}(b)&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a%20%5Crightarrow%20v_n%28b%29%20%5CRightarrow%20a%20%5Crightarrow%20v_%7Bn%2Bi%7D%28b%29&quot; style=&quot;vertical-align: middle;&quot; /&gt;   &lt;img alt=&quot;where&quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=where&quot; style=&quot;vertical-align: middle;&quot; /&gt; &lt;img alt=&quot; i \in \mathbb{N}&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%20i%20%5Cin%20%5Cmathbb%7BN%7D&quot; style=&quot;vertical-align: middle;&quot; /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Rule 1 says that all  volatile functions enforce a total order, where the function &lt;img alt=&quot;v_{n} (a)&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=v_%7Bn%7D%20%28a%29&quot; style=&quot;vertical-align: middle;&quot; /&gt; always precedes &lt;img alt=&quot;v_{n+1} (a)&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=v_%7Bn%2B1%7D%20%28a%29&quot; style=&quot;vertical-align: middle;&quot; /&gt;, where rule 2 says that if an action  &lt;img alt=&quot;a&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a&quot; style=&quot;vertical-align: middle;&quot; /&gt; precedes a volatile function on an  action &lt;img alt=&quot;b&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt; on the &lt;img alt=&quot;_n&quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=_n&quot; style=&quot;vertical-align: middle;&quot; /&gt;-th iteration, then the action &lt;img alt=&quot;a&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a&quot; style=&quot;vertical-align: middle;&quot; /&gt; must necessarily precede all  subsequent volatile functions applied to &lt;img alt=&quot;b&quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt;.&lt;br /&gt;&lt;br /&gt;This is a very strong memory  requirement in Java, in fact it is much stronger than compared to C/C++.  The C/C++ language specification has no such restriction on memory  ordering, and leaves it to the compiler implementation to decide how  non-volatile actions are ordered around volatile actions.&lt;br /&gt;&lt;br /&gt;Let&#39;s  consider how the these rules affect program execution with a simple code  sample:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;int a = 0;&lt;br /&gt;int b = 0;&lt;br /&gt;volatile int count = 0;&lt;br /&gt;&lt;br /&gt;a  = 1;&lt;br /&gt;count = 1;&lt;br /&gt;b = 2;&lt;br /&gt;count = 2;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In C/C++, the &lt;span style=&quot;font-family:courier new;&quot;&gt;volatile&lt;/span&gt; keyword only guarantees that the  count variable cannot be reordered against each other, ie. if &lt;span style=&quot;font-family:courier new;&quot;&gt;count == 2&lt;/span&gt;, then &lt;span style=&quot;font-family:courier new;&quot;&gt;count  = 1&lt;/span&gt; must necessarily precede it. However, there is neither a  guarantee that &lt;span style=&quot;font-family:courier new;&quot;&gt;a == 1,&lt;/span&gt; nor that &lt;span style=&quot;font-family:courier new;&quot;&gt;b == 2&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;In Java, given the stronger  guarantee defined above, then if &lt;span style=&quot;font-family:courier new;&quot;&gt;count == 1&lt;/span&gt;,  then the assertion &lt;span style=&quot;font-family:courier new;&quot;&gt;a == 1&lt;/span&gt; must be true.  Similarly, if &lt;span style=&quot;font-family:courier new;&quot;&gt;count == 2&lt;/span&gt; then assertion  that &lt;span style=&quot;font-family:courier new;&quot;&gt;a == 1 &amp;amp;&amp;amp; b == 2&lt;/span&gt; must be  true. This is what is means by the strict memory guarantee that Java  offers that C/C++ does not.&lt;br /&gt;&lt;br /&gt;However this does not mean that  C/C++ will not behave the same way Java does. Whether if it does so  depends on (1) whether if the compiler performs any code reordering that  may be in a surprising order, but legit order, and (2) whether if the  underlying machine architecture upholds the same strict memory order,  provided that the compiler does not perform any surprising code  reordering.&lt;br /&gt;&lt;br /&gt;For instance, compiling code on &lt;span style=&quot;font-family:courier new;&quot;&gt;gcc&lt;/span&gt; with &lt;span style=&quot;font-family:courier new;&quot;&gt;-O0&lt;/span&gt; set on all x86  platforms will conform to (and is stricter than) Java&#39;s memory model,  but other architectures such as the PowerPC, Alpha, Itanium all uphold a  weaker memory model which can exhibit surprising program behaviours  that a programmer may not expect. &lt;i&gt;Caveat Lector&lt;/i&gt;!&lt;br /&gt;&lt;br /&gt;Anyhow,  if you are interested in more memory model consistency rules, you might  want to watch Intel&#39;s explanation of the x86 memory model where the  nuances of memory ordering is explained in good detail. Enjoy!&lt;br /&gt;&lt;br /&gt;&lt;object width=&quot;480&quot; height=&quot;385&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/WUfvvFD5tAA&amp;amp;hl=en_US&amp;amp;fs=1&amp;amp;&quot;&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;embed src=&quot;http://www.youtube.com/v/WUfvvFD5tAA&amp;amp;hl=en_US&amp;amp;fs=1&amp;amp;&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;480&quot; height=&quot;385&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/7831779082753802835/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2010/06/why-volatile-is-different-in-cc-and.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/7831779082753802835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/7831779082753802835'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2010/06/why-volatile-is-different-in-cc-and.html' title='Why a volatile is different in C/C++ and Java'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-6588375422201725053</id><published>2010-06-05T22:17:00.002+01:00</published><updated>2010-06-05T22:17:00.152+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><title type='text'>Java Hatred Is A Disease</title><content type='html'>When it comes to critising programming languages, Java seems to take the top spot for being the baddest. This is widely seen on the InterTubes, like &lt;a href=&quot;http://news.ycombinator.com/item?id=285066&quot;&gt;here&lt;/a&gt;, and &lt;a href=&quot;http://www.reddit.com/r/programming/comments/utqb/ask_reddit_why_do_so_many_reddit_users_hate_java&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;But does a &#39;bad&#39; language mean that it&#39;ll die a relatively quick death?&lt;br /&gt;&lt;br /&gt;To find out, let&#39;s take a look at the etymology of an older computer language, C. C has been a systems programming language that has been around the last 40 years. The last revision to the C standard was 10 years ago, and even without moving with the times, the language is still going strong - last I heard, it is still the language of choice for 40% of Open Source developers.&lt;br /&gt;&lt;br /&gt;Does that mean that people have stopped complaining about pointers, easy-to-write buffer overflow errors, memory leaks, having to declare all variables up front before code, etc, etc, and other quirks about the language?&lt;br /&gt;&lt;br /&gt;I suspect not. So why still C?&lt;br /&gt;&lt;br /&gt;Simple - it works. And I suspect the same can be said with Java.&lt;br /&gt;&lt;br /&gt;Furthermore, it&#39;s silly to argue about Java&#39;s merits and drawbacks, because that&#39;s really missing the forest for the trees. While the most visible part about Java is the undoubtedly the language, but the true technology of &lt;a href=&quot;http://blog.vinceliu.com/2009/07/java-is-not-jvm.html&quot;&gt;Java is not in the language, but the virtual machine itself&lt;/a&gt;. The JVM as it stands today, is a fast, abstract machine that you can plug any languages into, and is able to operate at speeds comparable to natively compiled binaries.&lt;br /&gt;&lt;br /&gt;Like most programmers, we do enjoy bitching about peculiarities of a language once in a while, but for people who hate Java with a passion, maybe you need to get your head checked. A language is merely a medium of expression; and a computer language is one specifically used to express program behaviour. Normally, the choices are either to learn it well and avoid the pitfalls, or find a better medium of expression.&lt;br /&gt;&lt;br /&gt;So seriously, if you don&#39;t like Java, there &lt;span style=&quot;font-style: italic;&quot;&gt;is&lt;/span&gt; a cure. Stop. Using. It.&lt;br /&gt;&lt;br /&gt;I&#39;ll let you in on a secret to programming languages; there are only two types of languages in this world - languages that people complain about, and languages that nobody uses (&lt;a href=&quot;http://www2.research.att.com/%7Ebs/&quot;&gt;Stroustrup&lt;/a&gt; said so). So in an obtuse manner, the vast majority of people who criticises about Java are only reaffirming its popularity.&lt;br /&gt;&lt;br /&gt;Which is precisely why I can&#39;t see Java going the way of dinosaurs. Raving incessantly against it, ironically only helps boost its reputation, albeit in a weird, backhanded-kind of way.&lt;span style=&quot;font-weight: bold;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/6588375422201725053/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2010/06/java-hatred-is-disease.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/6588375422201725053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/6588375422201725053'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2010/06/java-hatred-is-disease.html' title='Java Hatred Is A Disease'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-987598393465716983</id><published>2010-05-29T23:16:00.001+01:00</published><updated>2012-09-01T12:45:54.356+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JVM"/><title type='text'>Word Tearing</title><content type='html'>... Or why you are not guaranteed a coherent  value when you are reading longs and doubles in Java.&lt;br /&gt;&lt;br /&gt;How is that  possible?&lt;br /&gt;&lt;br /&gt;This mainly due to a language compromise to deal with  &#39;legacy&#39; 32-bit CPU systems, where a 64-bit value memory action is  divided into two 32-bit memory actions, which is mainly done for historical efficiency reasons (Refer to &lt;a href=&quot;http://java.sun.com/docs/books/jls/second_edition/html/memory.doc.html#28733&quot; id=&quot;xfa1&quot; title=&quot;17.4&quot;&gt;17.4&lt;/a&gt; of the Java Language Specification for an explicit answer to why). But note that &lt;gdoc:callout calloutclosed=&quot;false&quot; calloutmarkerid=&quot;fhsy&quot; calloutshowfull=&quot;true&quot; callouttype=&quot;footnote&quot; class=&quot;google_footnote writely-callout writely-callout-data&quot; id=&quot;kj:w&quot; name=&quot;gdoccallout&quot;&gt;this is not a problem if you are using native 64-bit  architectures.&lt;/gdoc:callout&gt;&lt;marker class=&quot;writely-footnote-marker&quot; id=&quot;fhsy&quot; style=&quot;display: inline-block;&quot;&gt;&lt;/marker&gt;&lt;br /&gt;&lt;br /&gt;So how does  this translate to a possible problem?&lt;br /&gt;&lt;br /&gt;Lets try to simplify this  problem by illustrating the same scenario as having a 2-bit value memory action being split into two 1-bit  memory action. So assuming that we have a memory location &lt;i&gt;m&lt;/i&gt;  which looks something like this:&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;http://docs.google.com/drawings/image?w=119&amp;amp;h=119&amp;amp;ac=1&amp;amp;id=sQ8fQk-jEWlmROMb5geiV8w&amp;amp;rev=23&quot; /&gt;&lt;br /&gt;&lt;br /&gt;From  the diagram &lt;i&gt;m&lt;/i&gt; is logically separated into to two 1-bit locations  &lt;i&gt;m[0]&lt;/i&gt; and &lt;i&gt;m[1]&lt;/i&gt;. Let&#39;s assume that &lt;i&gt;m&lt;/i&gt; starts off with  &lt;span style=&quot;font-family: courier new;&quot;&gt;00&lt;/span&gt;&lt;i style=&quot;font-family: courier new;&quot;&gt;&lt;sub&gt;&lt;span style=&quot;font-size: 78%;&quot;&gt;b&lt;/span&gt;&lt;/sub&gt;&lt;/i&gt; as its initial value.  Then &lt;i&gt;m&lt;/i&gt; looks like this:&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;http://docs.google.com/drawings/image?w=119&amp;amp;h=119&amp;amp;ac=1&amp;amp;id=styM2uQRMjBazZLBfFdRftw&amp;amp;rev=4&quot; /&gt;&lt;br /&gt;&lt;br /&gt;Now  suppose that we have 2 CPUs concurrently executing the following code:&lt;br /&gt;&lt;br /&gt;&lt;table border=&quot;1&quot; bordercolor=&quot;#000000&quot; cellpadding=&quot;3&quot; cellspacing=&quot;0&quot; id=&quot;is1j&quot; style=&quot;height: 59px; width: 210px;&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;CPU1&lt;/b&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;CPU2&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;R(m)&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;W(m=&lt;span style=&quot;font-family: courier new;&quot;&gt;11&lt;/span&gt;&lt;i style=&quot;font-family: courier new;&quot;&gt;&lt;span style=&quot;font-size: 78%;&quot;&gt;&lt;sub&gt;b&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;R(m)  is a function that reads the value of &lt;i&gt;m&lt;/i&gt;, while W(m) is a  function that sets the value to &lt;i&gt;m&lt;/i&gt;. In the case of our example, &lt;b&gt;CPU1  &lt;/b&gt;is reading the value of &lt;i&gt;m&lt;/i&gt; while &lt;b&gt;CPU2&lt;/b&gt; is writing the  binary value 11&lt;i&gt;&lt;span style=&quot;font-size: 78%;&quot;&gt;&lt;sub&gt;b&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt; in to &lt;i&gt;m&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Logically  if atomicity is enforced, then the only possible value that can be  observed at any given time is either &lt;span style=&quot;font-family: courier new;&quot;&gt;00&lt;/span&gt;&lt;i style=&quot;font-family: courier new;&quot;&gt;&lt;span style=&quot;font-size: 78%;&quot;&gt;&lt;sub&gt;b&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;  or &lt;span style=&quot;font-family: courier new;&quot;&gt;11&lt;/span&gt;&lt;i style=&quot;font-family: courier new;&quot;&gt;&lt;span style=&quot;font-size: 78%;&quot;&gt;&lt;sub&gt;b&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;. But in the case of  longs and doubles, the specification explicitly mentions that no  guarantees of atomicity is enforced.&lt;br /&gt;&lt;br /&gt;Hence it is possible to  timeslice memory updates in the following order:&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;http://docs.google.com/drawings/image?w=402&amp;amp;h=402&amp;amp;ac=1&amp;amp;id=sAAIYuarU9JETk2tnidV0RA&amp;amp;rev=72&quot; /&gt;&lt;br /&gt;&lt;br /&gt;As  &lt;b&gt;CPU2&lt;/b&gt;&#39;s execution is timesliced between the execution of &lt;b&gt;CPU1&lt;/b&gt;,  this results in R(m) return the value of &lt;span style=&quot;font-family: courier new;&quot;&gt;01&lt;/span&gt;&lt;i style=&quot;font-family: courier new;&quot;&gt;&lt;span style=&quot;font-size: 78%;&quot;&gt;&lt;sub&gt;b&lt;/sub&gt;&lt;/span&gt;&lt;/i&gt;,  which is a transient value, but it is not a proper value to be  observed.&lt;br /&gt;&lt;br /&gt;It can be said that that &lt;b&gt;CPU1&lt;/b&gt; happens to be  reading at the right place but at a &lt;i&gt;wrong&lt;/i&gt; time. The &lt;i&gt;volatile&lt;/i&gt;  keyword in Java will resolve this problem, by virtue of the fact that  it does not allow reordering of &lt;i&gt;read&lt;/i&gt; and &lt;i&gt;write&lt;/i&gt; actions,  and hence by implictly disallowing read &lt;i&gt;in-between&lt;/i&gt; write actions  and vice-versa.&lt;br /&gt;&lt;br /&gt;This has the effect of making read and write  actions appear atomic, not that the read and write actions are  implicitly atomic themselves. For a better understanding of what I mean by atomic, see my explanation on &lt;a href=&quot;http://blog.vinceliu.com/2010/05/difference-between-atomic-and-volatile.html&quot;&gt;the difference between Atomic and Volatile&lt;/a&gt;.&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/987598393465716983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2010/05/word-tearing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/987598393465716983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/987598393465716983'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2010/05/word-tearing.html' title='Word Tearing'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-580417723388761433</id><published>2010-05-22T23:29:00.000+01:00</published><updated>2012-09-01T12:31:45.745+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Software Development"/><title type='text'>Google Docs&#39;s Equation Editor does not Create Permalink Images</title><content type='html'>I initially thought I could get away with it by linking Latex images for my  equations directly from Google Docs to Blogger, but it seems that the  image URLs are not permalinks, causing the images in my blog posts to be  missing after a while.&lt;br /&gt;&lt;br /&gt;Wordpress has a plugin to support this  directly, but there&#39;s a nary of solution for Blogger.&lt;br /&gt;&lt;br /&gt;Still  trying to look for possible workarounds to this problem. Hopefully it&#39;s  not one that involves manually copying and linking the images directly.  :(&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/580417723388761433/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2010/05/google-docss-equation-editor-does-not.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/580417723388761433'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/580417723388761433'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2010/05/google-docss-equation-editor-does-not.html' title='Google Docs&#39;s Equation Editor does not Create Permalink Images'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-7851908947540957333</id><published>2010-05-15T07:59:00.001+01:00</published><updated>2012-09-01T12:20:38.547+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Software Development"/><title type='text'>Difference between Atomic and Volatile?</title><content type='html'>There seems to be a  tendency for people to confuse an atomic action with a volatile memory  access. This is quite natural, since they exhibit similar properties  and makes it hard for people to distinguish between the two.&lt;br /&gt;&lt;br /&gt;So  what is the common property between an atomic action and a volatile  memory? They both exhibit the property of total ordering. Let&#39;s assume  for &lt;img alt=&quot;\forall a, b, c \in A&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%5Cforall%20a%2C%20b%2C%20c%20%5Cin%20A&quot; style=&quot;vertical-align: middle;&quot; /&gt; where &lt;img alt=&quot;A&quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=A&quot; style=&quot;vertical-align: middle;&quot; /&gt; is the set of possible actions a  program can execute, and &lt;img alt=&quot;a \rightarrow b&quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a%20%5Crightarrow%20b&quot; style=&quot;vertical-align: middle;&quot; /&gt; denotes that an action &lt;img alt=&quot;a&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a&quot; style=&quot;vertical-align: middle;&quot; /&gt; precedes action &lt;img alt=&quot;b&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt;, then the property of total order  means:&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;margin-left: 40px;&quot;&gt;&lt;img alt=&quot;a \rightarrow b  \wedge b \rightarrow a \Rightarrow a = b&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a%20%5Crightarrow%20b%20%5Cwedge%20b%20%5Crightarrow%20a%20%5CRightarrow%20a%20%3D%20b&quot; style=&quot;vertical-align: middle;&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img alt=&quot;a \rightarrow b , b  \rightarrow c \Rightarrow a \rightarrow c&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a%20%5Crightarrow%20b%20%2C%20b%20%5Crightarrow%20c%20%5CRightarrow%20a%20%5Crightarrow%20c&quot; style=&quot;vertical-align: middle;&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img alt=&quot;a \rightarrow b \vee b  \rightarrow a&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a%20%5Crightarrow%20b%20%5Cvee%20b%20%5Crightarrow%20a&quot; style=&quot;vertical-align: middle;&quot; /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Literally, the set of  rules mean (1) that for any action &lt;img alt=&quot;a&quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a&quot; style=&quot;vertical-align: middle;&quot; /&gt; that precedes &lt;img alt=&quot;b&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt; and any action &lt;img alt=&quot;b&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt; that precedes &lt;img alt=&quot;a&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a&quot; style=&quot;vertical-align: middle;&quot; /&gt;, then the action &lt;img alt=&quot;a&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a&quot; style=&quot;vertical-align: middle;&quot; /&gt; must necessarily be the same action as  &lt;img alt=&quot;b&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt;. (2) If &lt;img alt=&quot;a&quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a&quot; style=&quot;vertical-align: middle;&quot; /&gt; precedes &lt;img alt=&quot;b&quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt;, and &lt;img alt=&quot;b&quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt; precedes &lt;img alt=&quot;c&quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=c&quot; style=&quot;vertical-align: middle;&quot; /&gt;, then &lt;img alt=&quot;a&quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a&quot; style=&quot;vertical-align: middle;&quot; /&gt; must precede &lt;img alt=&quot;c&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=c&quot; style=&quot;vertical-align: middle;&quot; /&gt;. (3) &lt;img alt=&quot;a&quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a&quot; style=&quot;vertical-align: middle;&quot; /&gt; must precede &lt;img alt=&quot;b&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt; or &lt;img alt=&quot;b&quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt; must precede &lt;img alt=&quot;a&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a&quot; style=&quot;vertical-align: middle;&quot; /&gt;. These are just some mathematical (or  convoluted) formalisms of saying any action is guaranteed to be in  sequential order.&lt;br /&gt;&lt;br /&gt;But that&#39;s where the similarity ends.&lt;br /&gt;&lt;br /&gt;An  atomic action is literally what it means: an action that is  indivisible. Volatile memory only provides a guarantee of sequential  order, but offers no guarantee that an interleaving of actions cannot  occur. For an illustration, lets take a look at the following code:&lt;br /&gt;&lt;br /&gt;a  = 0;&lt;br /&gt;a++;&lt;br /&gt;&lt;br /&gt;Assume that &#39;a&#39; is a volatile variable. From the  code, we naturally think that the increment operator (++) will  atomically increment the value of &#39;a&#39; to 1, but this assumption is  slightly faulty:&lt;br /&gt;&lt;br /&gt;[a] = 0;&lt;br /&gt;r0 = [a];&lt;br /&gt;r0 = r0 + 1;&lt;br /&gt;[a] =  r0;&lt;br /&gt;&lt;br /&gt;The square brackets between [a] denotes a value gotten from  memory, while r0 represents a register in which the addition operation  actually occurs. An increment operation is actually a &lt;i&gt;composite&lt;/i&gt;  action, composed of a &lt;i&gt;read&lt;/i&gt;, then a &lt;i&gt;write&lt;/i&gt; action. (By the  way, it is implied that register actions are atomic, despite being a &lt;i&gt;composite&lt;/i&gt;  action. This is because an operation within a register cannot be  directly observed).&lt;br /&gt;&lt;br /&gt;So increment is a &lt;i&gt;composite&lt;/i&gt; action,  compared to being an &lt;i&gt;atomic&lt;/i&gt; action, what&#39;s the harm? Lets go  through the same example, but with 2 concurrent processors executing  simultaneously:&lt;br /&gt;&lt;br /&gt;&lt;table id=&quot;kg5j&quot; border=&quot;1&quot; bordercolor=&quot;#000000&quot; width=&quot;229&quot; cellpadding=&quot;3&quot; cellspacing=&quot;0&quot; height=&quot;53&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;CPU1&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;CPU2&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;a++;&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;a++;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Lets assume that a is  initially 0 to start. Given that iff the actions from CPU1 and CPU2 are  both &lt;i&gt;volatile&lt;/i&gt; and &lt;i&gt;atomic&lt;/i&gt;, then the only possible  transition value that can be seen after execution can only be 2.&lt;br /&gt;&lt;br /&gt;However,  if the actions from CPU1 and CPU2 are only &lt;i&gt;volatile&lt;/i&gt;, then the  actions can translate to this:&lt;br /&gt;&lt;br /&gt;&lt;table id=&quot;m7.y&quot; border=&quot;1&quot; bordercolor=&quot;#000000&quot; width=&quot;229&quot; cellpadding=&quot;3&quot; cellspacing=&quot;0&quot; height=&quot;53&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;CPU1&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;CPU2&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;r0 = a;&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;r1 = a;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;r0 = r0 + 1;&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;r1= r1 + 1&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;a = r0;&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;a = r1&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;For all the possible &lt;a href=&quot;http://blog.vinceliu.com/2010/05/concurrency-vs-multi-threading.html&quot;&gt;decompositions of &lt;img alt=&quot;C&quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=C&quot; style=&quot;vertical-align: middle;&quot; /&gt; into uniprocessor-&lt;img alt=&quot;MT&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=MT&quot; style=&quot;vertical-align: middle;&quot; /&gt; interleavings&lt;/a&gt;, one can see that it is possible that both registers r0 and  r1 both read a as 0 simultaneously which causes the resultant possible values to be either 1 or 2. Clearly seeing 1 is &lt;i&gt;wrong&lt;/i&gt;, since if  the operation is atomic, then 1 cannot be a legal value at the end of  the execution.&lt;br /&gt;&lt;br /&gt;Conversely, a volatile variable &lt;i&gt;can&lt;/i&gt; be  deemed atomic. Consider the example below:&lt;br /&gt;&lt;br /&gt;&lt;table id=&quot;k:5m&quot; border=&quot;1&quot; bordercolor=&quot;#000000&quot; width=&quot;229&quot; cellpadding=&quot;3&quot; cellspacing=&quot;0&quot; height=&quot;53&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;CPU1&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;CPU2&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;a=1;&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;a=2;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;In this case, the  only possible set of terminal values are 1 or 2, which is exactly the  same as you would get for an atomic action. Therefore, a volatile memory  access is atomic iff you perform only a &lt;i&gt;read&lt;/i&gt; or &lt;i&gt;write&lt;/i&gt; action,  which are atomic in nature. But a volatile variable is no  guarantee of atomicity if a composite action is executed.&lt;br /&gt;&lt;br /&gt;Hence  the label atomic actions is a slight misnomer, because it doesn&#39;t imply  that the action is atomic, but rather it means that it guarantees a &lt;i&gt;composite  action is executed as a single atomic action&lt;/i&gt;. A well known example  of such a composite action is the &lt;a href=&quot;http://en.wikipedia.org/wiki/Compare-and-swap&quot; id=&quot;q9yv&quot; title=&quot;Compare-and-Swap&quot;&gt;Compare-and-Swap&lt;/a&gt; instruction.&lt;br /&gt;&lt;br /&gt;For  simplicity, just remember that atomicity is not a property of memory,  but a property its actions, to which a volatile memory access may or may not uphold.&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/7851908947540957333/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2010/05/difference-between-atomic-and-volatile.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/7851908947540957333'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/7851908947540957333'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2010/05/difference-between-atomic-and-volatile.html' title='Difference between Atomic and Volatile?'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-6347770039495255400</id><published>2010-05-08T00:42:00.000+01:00</published><updated>2012-09-01T12:20:38.535+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Software Development"/><title type='text'>Concurrency vs. Multi-Threading</title><content type='html'>&lt;b&gt;&lt;/b&gt;A lot of people tend to treat concurrency and multi-threading as the same thing. In many ways, they are correct given the similarities between the two. But when trying to reason program behaviour, teasing out the distinction is somewhat important. Concurrency, &lt;img alt=&quot;C&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=C&quot; style=&quot;vertical-align: middle;&quot; /&gt;, is by definition multi-threading; but multi-threading, &lt;img alt=&quot;MT&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=MT&quot; style=&quot;vertical-align: middle;&quot; /&gt;, is not necessarily concurrent.&lt;br /&gt;&lt;br /&gt;To make it clear why concurrency is not strictly multi-threading, we start off by defining what concurrency is. Let &lt;img alt=&quot;P&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=P&quot; style=&quot;vertical-align: middle;&quot; /&gt; be the set of all program actions and that &lt;img alt=&quot;A, B \subseteq P&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=A%2C%20B%20%5Csubseteq%20P&quot; style=&quot;vertical-align: middle;&quot; /&gt; and &lt;img alt=&quot;\forall a, b, c \in P&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%5Cforall%20a%2C%20b%2C%20c%20%5Cin%20P&quot; style=&quot;vertical-align: middle;&quot; /&gt;. Also, &lt;img alt=&quot;a \rightarrow b&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a%20%5Crightarrow%20b&quot; style=&quot;vertical-align: middle;&quot; /&gt; denotes that the action &lt;img alt=&quot;a&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a&quot; style=&quot;vertical-align: middle;&quot; /&gt; precedes action &lt;img alt=&quot;b&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;margin-left: 40px;&quot;&gt;&lt;img alt=&quot;A \rightarrow B \wedge B \rightarrow A \Rightarrow A = B&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=A%20%5Crightarrow%20B%20%5Cwedge%20B%20%5Crightarrow%20A%20%5CRightarrow%20A%20%3D%20B&quot; style=&quot;vertical-align: middle;&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img alt=&quot;a \rightarrow b , b \rightarrow c \Rightarrow  a \rightarrow c&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a%20%5Crightarrow%20b%20%2C%20b%20%5Crightarrow%20c%20%5CRightarrow%20%20a%20%5Crightarrow%20c&quot; style=&quot;vertical-align: middle;&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img alt=&quot;A \rightarrow A&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=A%20%5Crightarrow%20A&quot; style=&quot;vertical-align: middle;&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;The explanation is actually straightforward when expressed in plain English.&lt;br /&gt;&lt;br /&gt;The set of rules says (1) if all the actions in set &lt;img alt=&quot;A&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=A&quot; style=&quot;vertical-align: middle;&quot; /&gt; precedes all the actions in set &lt;img alt=&quot;B&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=B&quot; style=&quot;vertical-align: middle;&quot; /&gt;, and all the actions in set &lt;img alt=&quot;B&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=B&quot; style=&quot;vertical-align: middle;&quot; /&gt; precedes all the actions in set &lt;img alt=&quot;A&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=A&quot; style=&quot;vertical-align: middle;&quot; /&gt;, then the set of actions are equivalent; (2) for any action &lt;img alt=&quot;a&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a&quot; style=&quot;vertical-align: middle;&quot; /&gt; that precedes action &lt;img alt=&quot;b&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt;, and any action &lt;img alt=&quot;b&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=b&quot; style=&quot;vertical-align: middle;&quot; /&gt; that precedes action &lt;img alt=&quot;c&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=c&quot; style=&quot;vertical-align: middle;&quot; /&gt;, then action &lt;img alt=&quot;a&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=a&quot; style=&quot;vertical-align: middle;&quot; /&gt; precedes action &lt;img alt=&quot;c&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=c&quot; style=&quot;vertical-align: middle;&quot; /&gt;. This is known as a &lt;a href=&quot;http://en.wikipedia.org/wiki/Transitive_relation&quot; id=&quot;k211&quot; title=&quot;transitive relation&quot;&gt;transitive relation&lt;/a&gt;, but note that while this transitive relation describes an action, broadly this relationship holds within &lt;i&gt;a set of actions&lt;/i&gt; as well. (3) All the set of actions in &lt;img alt=&quot;A&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=A&quot; style=&quot;vertical-align: middle;&quot; /&gt; precedes all the set of actions in &lt;img alt=&quot;A&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=A&quot; style=&quot;vertical-align: middle;&quot; /&gt;, i.e. this loosely means that if an action has happened before, then it cannot happen again, which is used to describe how program flows.&lt;br /&gt;&lt;br /&gt;To put it simply, concurrency means that for a given quantum of time, there can be one or more program actions happening simultaneously. A set of actions on a given thread T1&lt;b&gt; &lt;/b&gt;will be causally ordered by only on the thread itself, however this set of actions may or may not have an ordering relationship with the set of actions on another thread T2.&lt;br /&gt;&lt;br /&gt;Understanding what concurrency is, how is multi-threading different?&lt;br /&gt;&lt;br /&gt;Consider multi-threading on a single CPU machine. In a uni-core CPU, all actions are totally ordered, ie no two actions can happen at a single quantum of time, but this is not the case for a multi-core (concurrent) CPU. Obviously, we can easily make a multi-core CPU function like a single core CPU, but certainly not the other way around, which is why &lt;img alt=&quot;C \geq MT&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=C%20%5Cgeq%20MT&quot; style=&quot;vertical-align: middle;&quot; /&gt;.&lt;br /&gt;&lt;br /&gt;Even though most times &lt;img alt=&quot;C&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=C&quot; style=&quot;vertical-align: middle;&quot; /&gt; type programs are what we are interested in, we do usually assign an arbitary program order to these programs to make it functionally behave like a single-core &lt;img alt=&quot;MT&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=MT&quot; style=&quot;vertical-align: middle;&quot; /&gt; program, which is much easier to reason with. You see these &lt;img alt=&quot;C&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=C&quot; style=&quot;vertical-align: middle;&quot; /&gt; to totally ordered &lt;img alt=&quot;MT&quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=MT&quot; style=&quot;vertical-align: middle;&quot; /&gt; conversions from time to time, such as in my discussion of the &lt;a href=&quot;http://blog.vinceliu.com/2010/05/implementation-of-volatile-in-jvm.html&quot; id=&quot;as63&quot; title=&quot;Implementation of Volatile in the JVM&quot;&gt;Implementation of Volatile in the JVM&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;To put it simply, threading is a way of describing program actions for concurrent programs, and sequential programs can also be reasoned in the context of threads, but not the other way round. For a simple illustration, consider the following program:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class MyLock {&lt;br /&gt;  private volatile int thread_id;&lt;br /&gt;  public void lock ( )&lt;br /&gt;  {&lt;br /&gt;     int my_id = Thread.getID ( );&lt;br /&gt;     thread_id = my_id;&lt;br /&gt;     while ( thread_id == my_id ) { } // wait loop&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The code is multi-threaded; assume that there are 2 threads executing at the moment, and with thread T1, T2 returning IDs of 1, 2 correspondingly.&lt;br /&gt;&lt;br /&gt;There is an interesting property with this piece of code - if the threads are &lt;i&gt;concurrent&lt;/i&gt;, then eventually the &lt;span style=&quot;font-family:courier new;&quot;&gt;thread_id&lt;/span&gt; value will change, and the code can never halt (and the threads will be &lt;i&gt;fairly-scheduled&lt;/i&gt; as an interesting side effect). But if the threads are &lt;i&gt;sequential&lt;/i&gt;, then one thread will enter the &lt;span style=&quot;font-family:courier new;&quot;&gt;lock ( )&lt;/span&gt; code, and halts the processor in a wait loop.&lt;br /&gt;&lt;br /&gt;For those who may be interested, the code in this example is a part of an implementation of &lt;a href=&quot;http://en.wikipedia.org/wiki/Peterson%27s_algorithm&quot; id=&quot;p2zr&quot; title=&quot;Peterson&#39;s algorithm&quot;&gt;Peterson&#39;s algorithm&lt;/a&gt;, and a simple and poignant example to show how concurrent programs can be different from multi-threading ones.&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/6347770039495255400/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2010/05/concurrency-vs-multi-threading.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/6347770039495255400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/6347770039495255400'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2010/05/concurrency-vs-multi-threading.html' title='Concurrency vs. Multi-Threading'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-1003724897073187370</id><published>2010-05-03T18:49:00.011+01:00</published><updated>2010-06-06T00:23:25.454+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JVM"/><title type='text'>The Implementation of Volatile in the JVM</title><content type='html'>Scanning through the code between the JVM bytecode interpreter and the JIT compiler, I was perplexed to why an interpreter does not care to  differentiate between a volatile memory field access to a non-volatile  one, while a JIT actually emits special code to deal with it.&lt;br /&gt;&lt;br /&gt;But  after thinking though a while, I realise why this actually makes sense.  Before we find out why an interpreter does not need to care about  volatile semantics, we need to first understand the idea of causality,  and then understand what the &lt;span style=&quot;font-family:courier new;&quot;&gt;volatile&lt;/span&gt;  keyword is for.&lt;br /&gt;&lt;br /&gt;Lets start off with a very simple snippet of code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;a = 1&lt;br /&gt;v1 = a&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We expect &lt;code&gt;v1&lt;/code&gt; to have &lt;code&gt;1&lt;/code&gt; because we put &lt;code&gt;1&lt;/code&gt; into &lt;code&gt;a&lt;/code&gt;, and then &lt;code&gt;a&lt;/code&gt; into &lt;code&gt;v1&lt;/code&gt;. The assignment of &lt;code&gt;a = 1&lt;/code&gt; necessarily orders before the operation of &lt;code&gt;v1 = a&lt;/code&gt;. This necessity is  termed as &#39;causal order&#39;. Subsequently we use the notation a = 1 &lt;img alt=&quot;\rightarrow &quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%5Crightarrow%20&quot; style=&quot;vertical-align: middle;&quot; /&gt; v1 = a to imply this causal ordering.&lt;br /&gt;&lt;br /&gt;For illustration, we can show that not all program executions need to follow causal order:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;a = 1&lt;br /&gt;b = 2&lt;br /&gt;v1 = a&lt;br /&gt;v2 =  b&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Assuming that &lt;code&gt;v1&lt;/code&gt; and &lt;code&gt;v2&lt;/code&gt; needs to be assigned the value of &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; eventually, then there is a causal order such that the execution of the statement &lt;code&gt;a = 1&lt;/code&gt; &lt;img alt=&quot;\rightarrow &quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%5Crightarrow%20&quot; style=&quot;vertical-align: middle;&quot; /&gt; &lt;code&gt;v1 = a&lt;/code&gt;, and a causal order of &lt;code&gt;b = 2&lt;/code&gt; &lt;img alt=&quot;\rightarrow &quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%5Crightarrow%20&quot; style=&quot;vertical-align: middle;&quot; /&gt; &lt;code&gt;v2 = b&lt;/code&gt;. However there is no such  requirement needed between the statement of &lt;code&gt;a = 1&lt;/code&gt; and &lt;code&gt;b = 2&lt;/code&gt;. In fact, if  we swapped the order around, the program will continue to execute fine:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;b = 2&lt;br /&gt;a = 1&lt;br /&gt;v1 = a&lt;br /&gt;v2 = b&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;As long as we don&#39;t  break causal ordering, executions that has no causal order requirements have an  interesting property of &lt;i&gt;parallelism&lt;/i&gt;. We are able to break the  such programs into separate parts and execute them in parallel and still be  able to satisfy program requisites:&lt;br /&gt;&lt;br /&gt;&lt;table id=&quot;j_gx&quot; border=&quot;1&quot; bordercolor=&quot;#000000&quot; width=&quot;201&quot; cellpadding=&quot;3&quot; cellspacing=&quot;0&quot; height=&quot;73&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;CPU1&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;CPU2&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;a = 1&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;b = 2&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;v1 = a&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;v2 = b&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;But with  multi-processors, we can violate program determinism quite easily if we are not careful. Consider the following example:&lt;br /&gt;&lt;br /&gt;&lt;table id=&quot;ibud&quot; border=&quot;1&quot; bordercolor=&quot;#000000&quot; width=&quot;201&quot; cellpadding=&quot;3&quot; cellspacing=&quot;0&quot; height=&quot;73&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;CPU1&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;CPU2&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;a = 1&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;a = 2&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;v1 = a&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;In the absence of any  ordering restrictions, we term the execution as &lt;i&gt;concurrent&lt;/i&gt;; it is  legal for the value of &lt;code&gt;v1&lt;/code&gt; to be either &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;2&lt;/code&gt;. In practice this value  most likely be 1 because of cache locality, but this is not a guarantee.  Even though executions between CPU1 and CPU2 can happen at exactly the  same quantum, we treat such concurrent executions as if they are a  special case of interleaving; either CPU1&#39;s executions always happen  slightly before CPU2&#39;s executions, or CPU2&#39;s executions always happen  slightly before CPU1&#39;s executions. &lt;i&gt;&lt;b&gt;Corollary:&lt;/b&gt;&lt;/i&gt; CPU1&#39;s and  CPU2&#39;s executions never happen simultaneously, hence can be considered  to be functionally equivalent to a multi-threaded application. This  resulting execution is known to have a &lt;a href=&quot;http://en.wikipedia.org/wiki/Partially_ordered_set&quot;&gt;partial-ordering&lt;/a&gt;, ie, the  execution between CPU1 and CPU2 can be interleaved in any possible  permutations.&lt;br /&gt;&lt;br /&gt;For compiled languages like C/C++, there is no  implicit notion of concurrency; this is also true for a just-in-time  compiler within Java. No notion of concurrency is fine and dandy on a  1-CPU machine architecture, but not so on a multi-processor system or in  a language that has a notion of threads. Let&#39;s understand why by  first examining a simple single-threaded code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;a = 1&lt;br /&gt;a  = 2&lt;br /&gt;v1 = a&lt;br /&gt;v2 = a&lt;br /&gt;if ( v1 == v2 ) {&lt;br /&gt; v3 = true&lt;br /&gt;}&lt;br /&gt;return v3&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If causal order is upheld,  then naturally &lt;code&gt;a = 1&lt;/code&gt; &lt;img alt=&quot;\rightarrow &quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%5Crightarrow%20&quot; style=&quot;vertical-align: middle;&quot; /&gt; &lt;code&gt;a = 2&lt;/code&gt; &lt;img alt=&quot;\Rightarrow &quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%5CRightarrow%20&quot; style=&quot;vertical-align: middle;&quot; /&gt; &lt;code&gt;v1 == v2 == a == 2&lt;/code&gt;. On a  single-threaded execution that is causally ordered, the resulting  execution is also &lt;a href=&quot;http://en.wikipedia.org/wiki/Total_order&quot;&gt;totally ordered&lt;/a&gt;. Hence, an optimizing compiler may  say, &quot;hey, why don&#39;t I skip all the steps and assign &lt;code&gt;v3 = true&lt;/code&gt; directly,  since &lt;code&gt;v1 == v2&lt;/code&gt; always holds?&quot;. In the end, the compiler generates the  code that looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;v3 = true;&lt;br /&gt;return v3; // or  simply &quot;return true;&quot;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now consider a similar, but multi-threaded  code:&lt;br /&gt;&lt;br /&gt;&lt;table id=&quot;piw9&quot; border=&quot;1&quot; bordercolor=&quot;#000000&quot; width=&quot;308&quot; cellpadding=&quot;3&quot; cellspacing=&quot;0&quot; height=&quot;217&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;T1&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;T2&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;a = 1&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;a = 0&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;v1 = a&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;a = 2&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;v2 = a&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;if ( v1 == v2 )&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;{&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;   v3 = true&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;}&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;return v3&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Notice that both threads &lt;b&gt;T1&lt;/b&gt;  and &lt;b&gt;T2&lt;/b&gt; still follows causal order. For &lt;b&gt;T1&lt;/b&gt;, &lt;code&gt;a = 1&lt;/code&gt; &lt;img alt=&quot;\rightarrow &quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%5Crightarrow%20&quot; style=&quot;vertical-align: middle;&quot; /&gt; &lt;code&gt;v1 = a&lt;/code&gt; &lt;img alt=&quot;\rightarrow &quot; class=&quot;ee_img tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%5Crightarrow%20&quot; style=&quot;vertical-align: middle;&quot; /&gt; &lt;code&gt;v2 = a&lt;/code&gt;, hence implies that &lt;code&gt;v1 == v2 ==  1&lt;/code&gt;. On &lt;b&gt;T2&lt;/b&gt;, &lt;code&gt;a = 0&lt;/code&gt; &lt;img alt=&quot;\rightarrow &quot; class=&quot;ee_img  tr_noresize&quot; eeimg=&quot;1&quot; src=&quot;https://www.google.com/chart?cht=tx&amp;amp;chf=bg,s,FFFFFF00&amp;amp;chco=000000&amp;amp;chl=%5Crightarrow%20&quot; style=&quot;vertical-align: middle;&quot; /&gt; &lt;code&gt;a = 2&lt;/code&gt; is shown as a trivial case of  causal order. However, there is no total ordering enforced among the execution between the two threads.&lt;br /&gt;&lt;br /&gt;For a given compiler, it is  very difficult to be able to reason the ordering of execution across a  number of threads, given each thread&#39;s execution sequence is normally  examined in isolation. The reason for this limitation is simple: in  order for a compiler to be able to optimise for causality safety, it  needs to examine all executions across all threads; however it is  theoretically possible for the number of threads to be (1) dynamically  generated; (2) the number of threads generated to be unbounded and therefore  infeasible to make such an analysis.&lt;br /&gt;&lt;br /&gt;Usually the compiler will  optimise on the assumption that causality safety is assumed, where the  onus is on the programmer to indicate otherwise through the &lt;span style=&quot;font-family:courier new;&quot;&gt;volatile &lt;/span&gt;keyword.&lt;br /&gt;&lt;br /&gt;In the absence of the  &lt;span style=&quot;font-family:courier new;&quot;&gt;volatile&lt;/span&gt; keyword, the compiler is free  to assume the following optimisation:&lt;br /&gt;&lt;br /&gt;&lt;table id=&quot;j.ty&quot; border=&quot;1&quot; bordercolor=&quot;#000000&quot; width=&quot;654&quot; cellpadding=&quot;3&quot; cellspacing=&quot;0&quot; height=&quot;73&quot;&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;T1&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;b&gt;T2&lt;/b&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;v3 = true&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;// does nothing, since a  is unused&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;50%&quot;&gt;return v3; // or simply  &quot;return true&quot;;&lt;br /&gt;&lt;/td&gt;&lt;td width=&quot;50%&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Therefore,  the &lt;span style=&quot;font-family:courier new;&quot;&gt;volatile&lt;/span&gt; keyword means for &lt;i&gt;all  accesses of a, always emit the code for the accesses&lt;/i&gt;. By doing so,  it retains the code&#39;s original execution and hence execution coherency.&lt;br /&gt;&lt;br /&gt;This  is also why the volatile semantics within an interpreter is always  upheld.&lt;br /&gt;&lt;br /&gt;As an interpreter always execute instructions line-by-line,  therefore no inferences and optimisations actually occurs compared to  compiled code. Thus the interpreter needs not enforce the volatile  mechanic, so as long as the underlying machine architecture adheres to  program causality.&lt;br /&gt;&lt;br /&gt;And this behaviour should be safe  on machine architectures like the x86, but on esoteric machine  architectures that performs instruction reordering, eg. Alpha and  Itanium, the interpreter may require some additional memory fencing  instructions to ensure that volatile semantics are upheld.&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/1003724897073187370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2010/05/implementation-of-volatile-in-jvm.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/1003724897073187370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/1003724897073187370'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2010/05/implementation-of-volatile-in-jvm.html' title='The Implementation of Volatile in the JVM'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-5380450306065486908</id><published>2010-04-24T18:30:00.002+01:00</published><updated>2010-05-08T23:14:19.112+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Software Development"/><title type='text'>Code Reviews</title><content type='html'>Ever since I&#39;ve read the book &quot;&lt;a href=&quot;http://smartbear.com/codecollab-code-review-book.php&quot;&gt;Best Kept Secrets of Peer Code Review&lt;/a&gt;&quot; a couple of years ago, I was cottoned onto the idea that code reviews are good things to have. The book cites many successful examples, like Cisco and other successful corporations, and surely they must be doing something right that is worth emulating?&lt;br /&gt;&lt;br /&gt;When I first mentioned about my plan for a code review, one of the first things I wanted to know from the team was to find out their own experiences with the process. Among the various discussions we&#39;ve had, one recurring topic that keeps getting cited as an issue for a code review is the lack of domain knowledge, or the &#39;&lt;a href=&quot;http://en.wikipedia.org/wiki/Parkinson%27s_Law_of_Triviality&quot;&gt;Bikeshed Problem&lt;/a&gt;&#39;, as one of my colleagues puts it.&lt;br /&gt;&lt;br /&gt;And he tells it like this: if you have a large development team, it&#39;s likely that the person assigned to review your code may not have sufficient domain knowledge to critique on the changes you&#39;ve made. However, when you&#39;re told that your job is to &#39;find fault&#39; with others, chances are, you will find them. &lt;br /&gt;&lt;br /&gt;The lack of domain knowledge can hinder the process, not help it. It is plausible to believe that the only problems that you&#39;ll be able to spot are only the easiest ones - things like formatting, code convention and spelling. At the end of the process, you&#39;re most likely made not much improvement to the code, irritated your fellow colleague with trivialities, and wasted your own time.&lt;br /&gt;&lt;br /&gt;He has a valid point.&lt;br /&gt;&lt;br /&gt;Code reviews are meant as a process for locating defects, not a process of bickering over changes and causing friction among fellow developers. And even with the best of intentions, it is sometimes inevitable that frictions can occur within a code review process, given a code review is a task that relies on one&#39;s communication skill, and not solely a technical one.&lt;br /&gt;&lt;br /&gt;But if a code review process can turn terribly wrong, does that mean it is be better than having no code review at all?&lt;br /&gt;&lt;br /&gt;I don&#39;t believe so. Since we know that there bad ways of conducting a code review, we will assiduously avoid them. If we find something that works for us, we keep them. And we&#39;ll continually refine this process until it becomes a natural, unawkward and effective routine.&lt;br /&gt;&lt;br /&gt;So far, even after months, this process remains as a &#39;work-in-progress&#39;, although there are a few emergent behaviours that are becoming clearer:&lt;br /&gt;&lt;br /&gt;1) A code review process should not be all about spelling, formatting and comments about non-adherence to convention.  if one is irked by spelling and formatting, then the reviewer should take the liberty of fixing it himself; they are not proper critique for a code review;&lt;br /&gt;&lt;br /&gt;2) Code reviews are assigned to people in a random fashion, irrespective of how familiar the reviewer is with the domain of the code. This is to mitigate what we call a &#39;hit by a bus&#39; problem, where if a developer is the sole person who understands the code gets hit by the bus, then it becomes difficult for someone else to take over the code. (Not to mention that we&#39;ll be very sad about losing a colleague too.) Besides the purpose of risk mitigation, the reviewer gets an opportunity to ask questions and further his own understanding of a different subsystem of the software;&lt;br /&gt;&lt;br /&gt;3) The &#39;eject&#39; button. Sometimes, the code can be too far off for a reviewer to understand without going deep into understand the design, architecture and nuances of the problem. If it is time consuming or difficult to review the code effectively, the code will be reassigned to somebody else who has better a domain knowledge understanding. And it works in our situation because our team works loosely in pairs, and at times even perform pair programming when dealing with larger and more intractable problems.&lt;br /&gt;&lt;br /&gt;But I have no doubt about the merits of a code review process, although we should remember that part of the impact of a code review is a psychological one: people learn to code better through this process because of the behaviourial impetuses that drives them to work better. Because we&#39;re talking about people&#39;s pride, fear and ego here, there is absolutely a need to temper the process to factor any sensitivities involved.&lt;br /&gt;&lt;br /&gt;The most important lesson I&#39;ve learnt about a code review is that whenever it is a process that involves individuals, you&#39;ll always have to find your own right balance in conducting the whole process. Find out what works for you by basing your decisions on the nature of the software project and the team that you have - so don&#39;t be foolhardy to believe that all code reviews are the same, and there can be a &#39;one size fits all&#39; solution.&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/5380450306065486908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2009/08/code-reviews.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/5380450306065486908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/5380450306065486908'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2009/08/code-reviews.html' title='Code Reviews'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-5932980486639426008</id><published>2010-04-19T22:25:00.000+01:00</published><updated>2010-04-20T21:00:49.636+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Life"/><title type='text'>A Little Less Efficiency and a Little More Humanity</title><content type='html'>Singapore is a country that prides itself on its efficiency.&lt;br /&gt;&lt;br /&gt;The country is efficient. Not as efficient as the Japanese, but not as polite either.&lt;br /&gt;&lt;br /&gt;When things are not running smoothly, people whinge, threaten and complain.&lt;br /&gt;&lt;br /&gt;Nevertheless, efficiency is expected of when I was growing up in Singapore.&lt;br /&gt;&lt;br /&gt;And I never knew how refreshing the lack of efficiency can be. Until today.&lt;br /&gt;&lt;br /&gt;It was the usual train I catch to work each day, and I was running late.&lt;br /&gt;&lt;br /&gt;Chasing after the train as it was leaving the station. &lt;br /&gt;&lt;br /&gt;I was not alone. There were a few other people, all running behind me, all hoping to catch it too.&lt;br /&gt;&lt;br /&gt;We paused as the train slowly inched away from us.&lt;br /&gt;&lt;br /&gt;And then it stopped.&lt;br /&gt;&lt;br /&gt;The train driver had waited. Just for a few of us.&lt;br /&gt;&lt;br /&gt;Nevermind it was off-schedule.&lt;br /&gt;&lt;br /&gt;It was a beautiful illustration of humanity above efficiency.&lt;br /&gt;&lt;br /&gt;As I made my way to the seat on the aisle, it left me to wonder, &quot;Singapore, isn&#39;t it possible to just have a little less efficiency and a little more humanity?&quot;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/5932980486639426008/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2010/04/little-less-efficiency-and-little-more.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/5932980486639426008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/5932980486639426008'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2010/04/little-less-efficiency-and-little-more.html' title='A Little Less Efficiency and a Little More Humanity'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-1908423124682726438</id><published>2010-01-31T16:22:00.000+00:00</published><updated>2012-09-01T12:30:10.509+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Software Development"/><title type='text'>Calorie Counting Dinner</title><content type='html'>Calorie counting is a futile exercise. Can you imagine yourself to be meticulously noting down every single thing you put into your mouth throughout the day? Even if you are able to count Calories with the accuracy of an accounting auditor, you will still never get exact numbers. Our food just do not come in standard calibrated units that happily lend itself to exact, precise calculations. Therefore is there any merit in such an exercise at all?&lt;br /&gt;&lt;br /&gt;The science behind the Glycemic Index tells us that food is not digested at a uniform rate, and by similar reasoning, it is not unlikely that not all food is absorbed uniformly too. So even if &#39;a Calorie is a Calorie&#39; seducively sounds like a single reducible truth, we are doing ourselves a disservice if we believe that food can be cut down to a single number alone. While I won&#39;t argue against having a rough ballpark number to work with, there should be some sensibility on not relying on it too specifically.&lt;br /&gt;&lt;br /&gt;To the avid hard-core Calorie counters out there, let me satisfy you a little with my own Calorie counting exercise. Here is a snapped picture of what I normally have for dinner:&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;http://3.bp.blogspot.com/_lSk990LIlbk/S2Wuq0t4HdI/AAAAAAAAAP8/kStZzt9WGvg/s1600-h/P1030903.JPG&quot;&gt;&lt;img style=&quot;margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;&quot; src=&quot;http://3.bp.blogspot.com/_lSk990LIlbk/S2Wuq0t4HdI/AAAAAAAAAP8/kStZzt9WGvg/s400/P1030903.JPG&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5432940576221175250&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;All the food is cooked in a steamer, seasoned with some salt, plus pepper on the trout that I was having. There are no cooking oil or any other added ingredients to what you are seeing, so what you see is what you get. I&#39;ll go through the breakdown of what was in my dinner:&lt;br /&gt;&lt;br /&gt;Onion, whole&lt;br /&gt;Beetroot, whole&lt;br /&gt;Carrot, 1 stick&lt;br /&gt;Sweet potato, 1/2&lt;br /&gt;Asparagus, 8 tips&lt;br /&gt;Coriander, 2 sprigs&lt;br /&gt;Leek, 5 slices (not visible, under trout)&lt;br /&gt;Rainbow Trout, 250gm&lt;br /&gt;&lt;br /&gt;Let&#39;s try to calculate the total Calorie intake. It will not be accurate, but I&#39;ll give higher numbers on all my estimates just for argument:&lt;br /&gt;&lt;br /&gt;Onion (94gm) - 41 Calories&lt;br /&gt;Beetroot (87gm) - 37 Calories&lt;br /&gt;Carrot (61gm) - 25 Calories&lt;br /&gt;Sweet Potato (84gm) - 72 Calories&lt;br /&gt;Aspragus (120gm) - 26 Calories&lt;br /&gt;Leek (26gm) - 15 Calories&lt;br /&gt;Rainbow Trout (250gm) - 387 Calories&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Total Calorie Intake:&lt;/span&gt; 603 Calories&lt;br /&gt;&lt;br /&gt;That&#39;s typical dinner, and sometimes with an additional fruit or cheese as dessert after. That is usually all for dinner, and I do not consume any more after I cleaned up my kitchen. If I make a simplistic projection of these numbers to a full day (x3 for breakfast, lunch and dinner), then I&#39;m consuming less Calories than the standard daily requirement! So if the standard is to be believed, then by definition I must be starving!&lt;br /&gt;&lt;br /&gt;Our environment is a complex one, and our bodies are miraculous complex organisms that have to deal with this complexity. We have many bodily functions that regulate themselves autonomously without conscious thought or control, and our body constantly adjusts itself based on the feedback it receives; we feel sleepy when we are tired, our bodies ache and stop us from hurting ourselves when we over-tax it, we get thirsty when we are dehydrated. Shouldn&#39;t that mean it is naturally correct that we eat only when we are hungry?&lt;br /&gt;&lt;br /&gt;There is no reason not to trust our bodies to do the right thing. If I am not feeling hungry from my food intake, then my body is telling me that I am not in energy deficit. And I trust that my body is right. Who do you believe, your body or the standard conventional wisdom out there?&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/1908423124682726438/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2010/01/calorie-counting-dinner.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/1908423124682726438'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/1908423124682726438'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2010/01/calorie-counting-dinner.html' title='Calorie Counting Dinner'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_lSk990LIlbk/S2Wuq0t4HdI/AAAAAAAAAP8/kStZzt9WGvg/s72-c/P1030903.JPG" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-9023136570636165792</id><published>2010-01-23T15:47:00.001+00:00</published><updated>2012-09-01T12:34:52.235+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Life"/><category scheme="http://www.blogger.com/atom/ns#" term="Software Development"/><title type='text'>Food and the meaning in life</title><content type='html'>I have not been writing for a while, you may have noted. What have I been doing with my free time?&lt;br /&gt;&lt;br /&gt;These days I have been researching on a number of quite arbitrary and seemingly unfocused things, but even with all that arbitrariness, it still has much to do with my philosophising on life. If there is one notable aspect that has consumed my more of time these days, it will have to do with researching about nutrition. So how is that to do with philosophy? If you think about how much food actually affects your quality of life, then the answer is &lt;span style=&quot;font-style: italic;&quot;&gt;&#39;a lot&#39;&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Food has always been an on-and-off topic between colleagues and friends, and it is still surprisingly a subject area that I can&#39;t seem to be able to form an objective opinion upon. There is a bewildering number of conflicting literature on the science of food, and nobody, not even medical specialists, seem to be able to come to an agreement of what actually is good for you. What we have out there today is mainly unquestioned conventional wisdom, versus various splinter food cultures with their advocates and strong opinions to boot.&lt;br /&gt;&lt;br /&gt;One aspect of food nutrition that I am interested in has been the topic of weight loss. For those who know me, you will be challenging on why this would even be my subject of interest, given that I have no personal stake in dealing with any weight issues. True, but I have always been curious to why I&#39;m a perpetual a non-gainer no matter what I eat, while others seem to put on weight on even the most minuscule of calorie intake.&lt;br /&gt;&lt;br /&gt;Sometimes people blame it on genetics. It makes sense from an evolutionary aspect since some people are more efficient at storing extra energy than others, given that food supply was inconsistent in the past. It would have been beneficial for humans to store surplus energy, but I have my doubts that this is the key reason, given that the obesity problem has only surfaced within the last century - I&#39;m willing to bet my money that it&#39;s more likely that the problem comes from the composition of our food itself.&lt;br /&gt;&lt;br /&gt;Recently, one of my colleagues had completed his weight-loss regime. He had been going on a low carbohydrate diet, coupled with a sachet of weight loss formula, which he had good results in losing around 10lbs (4.5kg) within 3 months. The talk about a &#39;low carb&#39; diet became a talking point as it reminded me of the Atkins diet that had been associated with a reputation of varying between effective and crazily faddish.&lt;br /&gt;&lt;br /&gt;Given my current interest in food nutrition, I decided to offer some interesting, counter-intuitive opinions on his diet. Basically, I told him that his &#39;low carb&#39; diet was essentially a &#39;high fat&#39; one! Obviously he didn&#39;t seem happy with my explanation, since it flies in the face of conventional wisdom - you gain weight consuming fat, not lose it. My explanation was relatively simple, if not immediately obvious.&lt;br /&gt;&lt;br /&gt;There are only 3 categories of energy sources we derive from food, carbohydrates, proteins and fats. It is not possible for someone to sustain himself purely from a protein only diet, as he would have suffered from a condition called &#39;rabbit starvation&#39;. Proteins at high amounts is essentially toxic, aside one symptom that protein poisoning will have caused is ravenous, insatiable hunger. If that were the case, it would have been impossible for him to diet, since it is not an issue that can be subdued by willpower alone. Dieting in such condition is as futile as trying to stop yourself from breathing. Unless he&#39;s starving himself literally, his only viable energy replacement would have to be coming from fats.&lt;br /&gt;&lt;br /&gt;I have no idea what he was eating during the diet period (hardly anything from my observation), but it was obviously likely that in the absence of any energy input through food consumption, his body would naturally utilise its fat reserves, causing him to lose weight. But I believe that weight loss through dieting is orthogonal to the real problem of keeping it off permanently. You do get quick and good results during short dieting binges, but it is equally likely that you&#39;ll regain it back as quickly as you have taken it away.&lt;br /&gt;&lt;br /&gt;This is because the urge to over consume on your food has not decreased. It has been shown that &lt;a href=&quot;http://www.eurekalert.org/pub_releases/2009-09/mu-rda092409.php&quot;&gt;willpower is a limited resource&lt;/a&gt;, and when you go on a diet, you are essentially pushing your willpower to overcome your urges given by your brain to consume (more) food. A diet is hardly anything natural or sustainable if you can only maintain it for a limited of time. Eventually your willpower will break down, and you&#39;ll go back to your normal eating habits again, so whatever loss you are seeing will be temporary.&lt;br /&gt;&lt;br /&gt;The impetus to tackle weight gain is really to be addressing the real issue behind the problem over-consumption. The current science of blaming fats as a bogeyman to tackling the real problem, like any dismayal science, really isn&#39;t helping. It willfully ignores that fact that any food you eat will cause you to become fat when consumed in excess - it is just restating the laws of thermodynamics. Not besides the fact that I&#39;ve seen plenty chubby friends despite being on a low fat diet for perpetuity. &lt;br /&gt;&lt;br /&gt;I&#39;ve recently watched this video titled, &quot;Sugar: a bitter truth&quot;, by Professor Robert H. Lustig which has strengthened this belief. He labels sugar as the key cause of obesity, and presents a clear cut explanation of how sugar intake increases appetite:&lt;br /&gt;&lt;br /&gt;&lt;object height=&quot;344&quot; width=&quot;425&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://www.youtube.com/v/dBnniua6-oM&amp;hl=en_US&amp;fs=1&amp;rel=0&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot;&gt;&lt;/param&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;/param&gt;&lt;embed src=&quot;http://www.youtube.com/v/dBnniua6-oM&amp;hl=en_US&amp;fs=1&amp;rel=0&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;344&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;Generally when a doctor puts his neck out against conventional wisdom, he is either convinced he is right or a crackpot out for fame and notoriety. I can only suggest to do your own research and make your own conclusions. There are good literature out there to suggest that obesity isn&#39;t the result of a high fat diet, but a high sugar one. Some might nitpick that it&#39;s very specifically high fructose, I don&#39;t disagree, but do remember that sucrose (table sugar) is one part glucose and one part fructose.&lt;br /&gt;&lt;br /&gt;Sugar isn&#39;t categorically the culprit for obesity, but if it is a cause for driving your up brain signals to consume, then it stands to reason that an increased sugar intake will lead to over-consumption. And if willpower is expendable, the only sustainable way to ensure a permanent weight loss is to cut down on sugar intake.&lt;br /&gt;&lt;br /&gt;I suggested to my colleague that the easiest solution to weight loss is to simply stop consuming all forms of added sugar. He was aghast.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;&quot;If I can&#39;t have my lollipops and cookies, what would be the meaning in life? I much rather be fat and lose a few years of my life than to stop eating sugar at all.&quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Which means to say that sometimes the most obvious solutions aren&#39;t always the easiest.&lt;br /&gt;&lt;br /&gt;Isn&#39;t it remarkable that seemingly trivial things like food choices can be difficult when you have to make conscious, rational choices? Now isn&#39;t that worth philosophising about? Food for thought anyone? :)&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/9023136570636165792/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2010/01/food-and-meaning-in-life.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/9023136570636165792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/9023136570636165792'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2010/01/food-and-meaning-in-life.html' title='Food and the meaning in life'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-4092424210767523797</id><published>2009-11-28T17:19:00.002+00:00</published><updated>2010-04-25T01:24:03.741+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ruby"/><title type='text'>Compiling Ruby 1.9 for Mac OSX 10.4</title><content type='html'>This article contains specifics for installing Ruby on PowerPC MacOSX 10.4. Newer Intel Macs with &amp;gt; 10.4 OS has more updated dependencies and probably do not require the instructions described here; you shouldn&#39;t need to compile from source in that case as well - there are one-click installers for binaries for Ruby 1.9 on the Internet, look for it.&lt;br /&gt;&lt;br /&gt;On 10.4 PPC, the default version of Ruby is 1.8.2. This version is now old for some of the ruby plugins to be installed, specifically rubygems 1.3.5 in my case. I won&#39;t go into the reasons here on not going for older versions of rubygems (Read &lt;a href=&quot;http://blog.vinceliu.com/2009/01/ways-of-solving-slow-gem-install.html&quot;&gt;here&lt;/a&gt; if you are really interested why), but since an upgrade of Ruby is warranted, instead of upgrading to the latest 1.8.x series, it might be worthwhile to try out the new features from the 1.9.x series instead.&lt;br /&gt;&lt;br /&gt;In order to recompile ruby, you&#39;ll need &lt;a href=&quot;http://developer.apple.com/technology/xcode.html&quot;&gt;Xcode&lt;/a&gt; from Apple. That will install the SDK for developing on Apple&#39;s MacOS, but more importantly, it contains the &lt;code&gt;gcc&lt;/code&gt; part of the GNU toolchain required for compilation.&lt;br /&gt;&lt;br /&gt;However the GNU toolchain is incomplete at this stage; we&#39;ll require at the minimum GNU &lt;code&gt;m4&lt;/code&gt;, &lt;code&gt;autoconf&lt;/code&gt; and &lt;code&gt;automake&lt;/code&gt; to complete the chain of dependencies Ruby needs.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Not Using Darwin Port/Fink&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I&#39;m going to compile these things from source directly without any package management system, and for a good reason; 3rd party MacOS package management systems are usually more trouble than it&#39;s worth, either having longer compilation time from spurious dependencies, compilation breakages due to improperly configured parameters or missing specific compiler flags that you&#39;ll end up having to fix by hand anyway.&lt;br /&gt;&lt;br /&gt;That said, don&#39;t be put off by the exercise of compiling from scratch. It is not difficult, and you&#39;ll get to learn a thing or two about the internals of your OS. &lt;br /&gt;&lt;br /&gt;Open up your terminal, and &lt;code&gt;sudo&lt;/code&gt; into &lt;code&gt;root&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Tigershark:~ vince$ sudo -i&lt;br /&gt;Password:&lt;br /&gt;Tigershark:~ root#&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In order to separate your newly compiled stuffs from your existing binaries, I recommend you create a separate directory under the &lt;code&gt;&#39;/&#39;&lt;/code&gt; directory so that they will be cleanly partitioned. I&#39;m using the directory &lt;code&gt;&#39;/lfs&#39;&lt;/code&gt; in my example here, as a tribute to the &lt;a href=&quot;http://www.linuxfromscratch.org/&quot;&gt;Linux from Scratch&lt;/a&gt; project, where I got my derivative knowledge from. Feel free to choose your own directory names though.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Tigershark:~ root# export LFS=/lfs&lt;br /&gt;Tigershark:~ root# echo &quot;export PATH=$LFS/bin:$PATH&quot; &amp;gt;&amp;gt; /Users/YOURUSERNAME/.profile&lt;br /&gt;Tigershark:~ root# export PATH=$LFS/bin:$PATH&lt;br /&gt;Tigershark:~ root# mkdir -p $LFS/src&lt;br /&gt;Tigershark:~ root# cd $LFS/src&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The code above creates the &lt;code&gt;/lfs&lt;/code&gt; directory, and the &lt;code&gt;&#39;/lfs/src&#39;&lt;/code&gt; directory as well. It also sets up the PATH environment to firstly look in &lt;code&gt;&#39;/lfs/bin&#39;&lt;/code&gt; before it searches all other paths. This is necessary so that you&#39;ll be using your new binaries instead of the old system binaries. The same change is added into your user&#39;s &lt;code&gt;.profile&lt;/code&gt; file so that Terminal will know to look for the new binaries in the future when it starts up.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Installing m4&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Tigershark:/ root# cd $LFS/src&lt;br /&gt;Tigershark:/lfs/src root# curl http://ftp.gnu.org/gnu/m4/m4-1.4.9.tar.gz &amp;gt; m4-1.4.9.tar.gz&lt;br /&gt;Tigershark:/lfs/src root# tar -zxvf m4-1.4.9.tar.gz&lt;br /&gt;Tigershark:/lfs/src root# cd m4-1.4.9&lt;br /&gt;Tigershark:/lfs/src/m4-1.4.9 root# ./configure --prefix=$LFS&lt;br /&gt;Tigershark:/lfs/src/m4-1.4.9 root# make &amp;&amp; make check&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Make sure that the test results come up without any errors. When the test results are satisfied, install it.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Tigershark:/lfs/src/m4-1.4.9 root# make install&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Installing autoconf&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Tigershark:/ root# cd $LFS/src&lt;br /&gt;Tigershark:/lfs/src root# curl http://ftp.gnu.org/gnu/autoconf/autoconf-2.65.tar.gz &amp;gt; autoconf-2.65.tar.gz&lt;br /&gt;Tigershark:/lfs/src root# tar -zxvf autoconf-2.65.tar.gz&lt;br /&gt;Tigershark:/lfs/src root# cd autoconf-2.65&lt;br /&gt;Tigershark:/lfs/src/autoconf-2.65 root# ./configure --prefix=$LFS&lt;br /&gt;Tigershark:/lfs/src/autoconf-2.65 root# make &amp;&amp; make check&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Make sure that the test results come up without any errors. When the test results are satisfied, install it.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Tigershark:/lfs/src/autoconf-2.65 root# make install&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Installing automake&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Tigershark:/ root# cd $LFS/src&lt;br /&gt;Tigershark:/lfs/src root# curl http://ftp.gnu.org/gnu/automake/automake-1.9.6 &amp;gt; automake-1.9.6.tar.gz&lt;br /&gt;Tigershark:/lfs/src root# tar -zxvf automake-1.9.6.tar.gz&lt;br /&gt;Tigershark:/lfs/src root# cd automake-1.9.6&lt;br /&gt;Tigershark:/lfs/src/automake-1.9.6 root# ./configure --prefix=$LFS&lt;br /&gt;Tigershark:/lfs/src/automake-1.9.6 root# make &amp;&amp; make check&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Make sure that the test results come up without any errors. When the test results are satisfied, install it.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Tigershark:/lfs/src/automake-1.9.6 root# make install&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Additional Step: Upgrading libreadline&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Apple&#39;s implementation of the &lt;code&gt;readline&lt;/code&gt; library has missing symbols in which Ruby (or more accurately, &lt;code&gt;irb&lt;/code&gt;) requires in order to retrieve command line history. If you do not use &lt;code&gt;irb&lt;/code&gt; (which I doubt, unless you never require testing some code you&#39;re uncertain of), you may skip compiling this. But I recommend you do :)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Tigershark:/ root# cd $LFS/src&lt;br /&gt;Tigershark:/lfs/src root# curl http://ftp.gnu.org/gnu/readline/readline-6.0.tar.gz &amp;gt; readline-6.0.tar.gz&lt;br /&gt;Tigershark:/lfs/src root# tar -zxvf readline-6.0.tar.gz&lt;br /&gt;Tigershark:/lfs/src root# cd readline-6.0&lt;br /&gt;&lt;br /&gt;Tigershark:/lfs/src/readline-6.0 root# curl http://ftp.gnu.org/gnu/readline/readline-6.0-patches/readline60-001 &amp;gt; readline60-001&lt;br /&gt;Tigershark:/lfs/src/readline-6.0 root# curl http://ftp.gnu.org/gnu/readline/readline-6.0-patches/readline60-002 &amp;gt; readline60-002&lt;br /&gt;Tigershark:/lfs/src/readline-6.0 root# curl http://ftp.gnu.org/gnu/readline/readline-6.0-patches/readline60-003 &amp;gt; readline60-003&lt;br /&gt;Tigershark:/lfs/src/readline-6.0 root# curl http://ftp.gnu.org/gnu/readline/readline-6.0-patches/readline60-004 &amp;gt; readline60-004&lt;br /&gt;Tigershark:/lfs/src/readline-6.0 root# patch -p0 &lt; readline60-001&lt;br /&gt;Tigershark:/lfs/src/readline-6.0 root# patch -p0 &lt; readline60-002&lt;br /&gt;Tigershark:/lfs/src/readline-6.0 root# patch -p0 &lt; readline60-003&lt;br /&gt;Tigershark:/lfs/src/readline-6.0 root# patch -p0 &lt; readline60-004&lt;br /&gt;&lt;br /&gt;Tigershark:/lfs/src/readline-6.0 root# ./configure --libdir=/usr/local/lib&lt;br /&gt;Tigershark:/lfs/src/readline-6.0 root# make &amp;&amp; make check&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The instructions also contains the additional patches that was released since libreadline 6.0. Make sure you follow those additional instructions to apply the patches correspondingly. &lt;br /&gt;&lt;br /&gt;Also, note that the &lt;code&gt;./configure&lt;/code&gt; parameter has changed. In this case, we are installing a library, so the path to install to is different. We are installing it to &lt;code&gt;&#39;/usr/local/lib&#39;&lt;/code&gt;, which will make sure that we won&#39;t conflict with the original &lt;code&gt;libreadline&lt;/code&gt; in &lt;code&gt;&#39;/usr/lib&#39;&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight:bold;&quot;&gt;Finally, make Ruby!&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Tigershark:/ root# cd $LFS/src&lt;br /&gt;Tigershark:/lfs/src root# curl ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p243.tar.gz &amp;gt; ruby-1.9.1-p243.tar.gz&lt;br /&gt;Tigershark:/lfs/src root# tar -zxvf ruby-1.9.1-p243.tar.gz&lt;br /&gt;Tigershark:/lfs/src root# cd ruby-1.9.1-p243&lt;br /&gt;Tigershark:/lfs/src/ruby-1.9.1-p243 root# ./configure --prefix=$LFS LDFLAGS=-L/usr/local/lib&lt;br /&gt;Tigershark:/lfs/src/ruby-1.9.1-p243 root# make &amp;&amp; make install&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Note the additional parameter &lt;code&gt;&#39;LDFLAGS=-L/usr/local/lib&#39;&lt;/code&gt; that we pass to &lt;code&gt;&#39;./configure&#39;&lt;/code&gt;. This is required so that when ruby gets compiled, it&#39;ll first search &lt;code&gt;&#39;/usr/local/lib&#39;&lt;/code&gt; for it&#39;s library dependencies before looking at its system default paths. Because we have our new &lt;code&gt;&#39;libreadline&#39;&lt;/code&gt; installed, this makes sure that Ruby is compiled with our newer library instead of the system one. &lt;br /&gt;&lt;br /&gt;Congratulations! Once you&#39;ve reached here, you have your new shiny Ruby 1.9 interpreter to play with! To check:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Tigershark:/ root# which ruby&lt;br /&gt;/lfs/bin/ruby&lt;br /&gt;Tigershark:/ root# ruby --version&lt;br /&gt;ruby 1.9.1p243 (2009-07-16 revision 24175) [powerpc-darwin8.11.0]&lt;br /&gt;&lt;/pre&gt;&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/4092424210767523797/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2009/11/compiling-ruby-19-from-scratch-for-mac.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/4092424210767523797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/4092424210767523797'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2009/11/compiling-ruby-19-from-scratch-for-mac.html' title='Compiling Ruby 1.9 for Mac OSX 10.4'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6787189684621789552.post-1416452307747350246</id><published>2009-10-01T23:57:00.000+01:00</published><updated>2009-10-01T23:57:14.291+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Software Development"/><title type='text'>Why you should Blame your Tools, sometimes.</title><content type='html'>As software developers, we would all wish to have 3rd party libraries that works magically immediately after installation. While this is to be expected and holds true for popular and widely used libraries, people do tend to forget that it is still more of a rule of thumb than an iron-cast fact.&lt;br /&gt;&lt;br /&gt;Like the urban myth goes, &quot;a good workman never blames his tools&quot;, this mindset is so ingrained in the software development culture, that it is always bad form to assume that bug may reside in a library rather than in your code. After all, it is more likely that you are the offending culprit, given it is less likely a widely used code base will make a mistake when compared to code just seen by you alone. But with everything statistical, there is always a chance that an outlier event can happen.&lt;br /&gt;&lt;br /&gt;And it did for me. &lt;br /&gt;&lt;br /&gt;Internally, we rely on log4cxx as our logging library, which a peculiar bug seems to only be triggered upon the termination of our application. After spending more than 2 days of debugging, the error seemed to have consistently been at the line where the logger object is being accessed. And like all true developers, I bit my lip and kept soldiering on, reading through my own code, checking the same lines over and over again, trying to see if I had missed defining a variable, or if I had forgotten to allocate memory for it. Naturally, after while of doing so, I began to start questioning my personal sanity rather than the lines of code I&#39;ve written, amid this &#39;impossibility&#39; that the error could actually be from the library.&lt;br /&gt;&lt;br /&gt;And then I popped.&lt;br /&gt;&lt;br /&gt;I turned over to my colleague and mentioned to him that the code kept failing on the logging line. The team had known that I&#39;ve been stuck on this problem for the last day. Even as I started, I could see the mild derision on his face, &quot;it can&#39;t be the library. Maybe gdb is not showing what actually is going on.&quot;&lt;br /&gt;&lt;br /&gt;So on and on the circle I went. Then someone else suggested using valgrind.&lt;br /&gt;&lt;br /&gt;Since I was running out of options, I didn&#39;t see any harm trying. At most I&#39;ll waste an hour more to the day I&#39;ve already wasted, anyway.&lt;br /&gt;&lt;br /&gt;Valgrind didn&#39;t really show anything more different to what gdb was showing. Basically saying the same thing - that log4cxx is accessing an invalid memory location. Given I wasn&#39;t an expert on valgrind, I got someone else to come over and discussed what we were seeing on the stack trace.&lt;br /&gt;&lt;br /&gt;No luck still.&lt;br /&gt;&lt;br /&gt;It&#39;s gone past the point of frustration, into the point of desperation that I decided to just fucking comment out the offending statement and see if the problem goes away.&lt;br /&gt;&lt;br /&gt;After recompling and re-running the application 30+ times without the bug re-surfacing, I was very certain to point at the logger library being the culprit. But of course if I did, I couldn&#39;t definitively prove it, and worse, I had no workaround; the entire code base is reliant on it for logging, and to take it away would mean a major re-engineering exercise.&lt;br /&gt;&lt;br /&gt;Sometimes talking to others help. Sometimes they offer a difference in perspective, and other times, they may have caught something you hadn&#39;t.&lt;br /&gt;&lt;br /&gt;Given that we had multiple threads that were still operating when a shutdown signal is received, I thought maybe it&#39;ll be worth trying to stop those threads safely before the termination signal is processed - since it&#39;s likely that some portions or memory may be freed while the threads are still utilising them. But I was just shooting wildly - it was a very long shot, given how the threading interactions were designed, it was difficult to believe that it could have been the problem. But trying something is better than doing nothing.&lt;br /&gt;&lt;br /&gt;So I sat down with another colleague of mine, and talked him through what I wanted to do, and invariably the discussion lead to another where we talked about the valgrind backtrace that I had generated, which showed memory destruction caused by exit(). After a bit of theorising back and forth about the behaviour, and on how I&#39;d would write a quick hack to test my hypothesis, my colleague decided to do a ubiquity search on &#39;&lt;a href=&quot;http://www.google.ie/search?q=log4cxx+exit+crash&quot;&gt;log4cxx exit crash&lt;/a&gt;^H^H^H^H&#39;, which then our eyes popped when we saw the preview result before it changed into something else that he was meaning to type.&lt;br /&gt;&lt;br /&gt;&quot;Go back again&quot;, I said excitedly. He was already as excited as I was, so there wasn&#39;t really the need for any prompting.&lt;br /&gt;&lt;br /&gt;It turns out that there is a known problem in log4cxx found months ago, and someone had even posted a patch on it already. But here&#39;s the thing about software: unless you are willing to roll your own fixes, be prepared to wait for a long time before someone eventually fixes it. And even if someone did fix it, the upstream maintainer will still take a while before committing it into the main trunk. Or even worse, he may just choose to ignore it. And yes it does happen - ask &lt;a href=&quot;http://en.wikipedia.org/wiki/Ulrich_Drepper&quot;&gt;Ulrich Drepper&lt;/a&gt;. :P&lt;br /&gt;&lt;br /&gt;On how to fix it, and package it up nicely for use, I&#39;ll write about that in a later post, for now I want to share an invaluable lesson when it comes to software development, which also equally applies in life: while established conventions are more often right than wrong, it never hurts to question them just in case they aren&#39;t. It may not be okay to blame your tools all the time, but it sometimes worth to know when to call a shoddy spade when you see one.&lt;div class=&quot;blogger-post-footer&quot;&gt;&lt;script type=&quot;text/javascript&quot;&gt;&lt;!-- google_ad_client = &quot;pub-7827109100899293&quot;;google_ad_width = 468;google_ad_height = 60;google_ad_format = &quot;468x60_as&quot;;google_ad_type = &quot;text_image&quot;;google_ad_channel = &quot;&quot;;google_color_border = &quot;FFFFFF&quot;;google_color_bg = &quot;FFFFFF&quot;;google_color_link = &quot;0000FF&quot;;google_color_text = &quot;000000&quot;;google_color_url = &quot;008000&quot;;google_ui_features = &quot;rc:6&quot;;//--&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://pagead2.googlesyndication.com/pagead/show_ads.js&quot;&gt;&lt;/script&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.vinceliu.com/feeds/1416452307747350246/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://blog.vinceliu.com/2009/10/why-you-should-blame-your-tools.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/1416452307747350246'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6787189684621789552/posts/default/1416452307747350246'/><link rel='alternate' type='text/html' href='http://blog.vinceliu.com/2009/10/why-you-should-blame-your-tools.html' title='Why you should Blame your Tools, sometimes.'/><author><name>Unknown</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>