<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Roundtrip to Shanghai via Tokyo</title>
	<atom:link href="http://kohei.us/feed/" rel="self" type="application/rss+xml" />
	<link>http://kohei.us</link>
	<description>Kohei Yoshida's Webspace</description>
	<lastBuildDate>Fri, 09 Jul 2010 12:20:09 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>OOo module dependencies</title>
		<link>http://kohei.us/2010/07/07/ooo-module-dependencies/</link>
		<comments>http://kohei.us/2010/07/07/ooo-module-dependencies/#comments</comments>
		<pubDate>Wed, 07 Jul 2010 23:56:00 +0000</pubDate>
		<dc:creator>Kohei Yoshida</dc:creator>
				<category><![CDATA[]]></category>
		<category><![CDATA[openoffice.org]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tool]]></category>

		<guid isPermaLink="false">http://kohei.us/?p=808</guid>
		<description><![CDATA[Below is a graphical representation of OOo&#8217;s module dependencies as of DEV300 milestone 84 generated via graphviz.  Click on the image to get the whole picture.

You can find the python script I wrote to generate this nice picture here.
]]></description>
			<content:encoded><![CDATA[<p>Below is a graphical representation of OOo&#8217;s module dependencies as of DEV300 milestone 84 generated via <a href="http://www.graphviz.org/">graphviz</a>.  Click on the image to get the whole picture.</p>
<p><a href="http://kohei.us/wp-content/uploads/2010/07/ooo-modules.png"><img src="http://kohei.us/wp-content/uploads/2010/07/ooo-modules-thumb.png" alt="ooo-modules-thumb" title="ooo-modules-thumb" width="400" height="264" class="alignnone size-full wp-image-812" /></a></p>
<p>You can find the python script I wrote to generate this nice picture <a href="http://cgit.freedesktop.org/ooo-build/ooo-build/tree/bin/check-deps.py">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://kohei.us/2010/07/07/ooo-module-dependencies/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Strace equivalent for Windows</title>
		<link>http://kohei.us/2010/06/25/strace-equivalent-for-windows/</link>
		<comments>http://kohei.us/2010/06/25/strace-equivalent-for-windows/#comments</comments>
		<pubDate>Fri, 25 Jun 2010 20:45:36 +0000</pubDate>
		<dc:creator>Kohei Yoshida</dc:creator>
				<category><![CDATA[]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[tool]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://kohei.us/?p=801</guid>
		<description><![CDATA[While searching for a debug tool equivalent of strace that runs on Windows, I&#8217;ve come across Process Monitor.  This appears to work well for me.  For anyone in search of strace equivalent on Windows, give this one a try.
I&#8217;ve also tried StraceNT, but this one was not very reliable as it tends to [...]]]></description>
			<content:encoded><![CDATA[<p>While searching for a debug tool equivalent of <a href="http://en.wikipedia.org/wiki/Strace">strace</a> that runs on Windows, I&#8217;ve come across <a href="http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx">Process Monitor</a>.  This appears to work well for me.  For anyone in search of strace equivalent on Windows, give this one a try.</p>
<p>I&#8217;ve also tried <a href="http://www.intellectualheaven.com/default.asp?BH=projects&#038;H=strace.htm">StraceNT</a>, but this one was not very reliable as it tends to crash the traced process almost every time.</p>
<p>An equally useful tool for debugging on Windows is <a href="http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx">DebugView</a>, which captures output from the <a href="http://msdn.microsoft.com/en-us/library/aa363362%28VS.85%29.aspx">OutputDebugString</a> calls.</p>
]]></content:encoded>
			<wfw:commentRss>http://kohei.us/2010/06/25/strace-equivalent-for-windows/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Ixion &#8211; threaded formula calculation library</title>
		<link>http://kohei.us/2010/06/21/ixion-threaded-formula-calculation-library/</link>
		<comments>http://kohei.us/2010/06/21/ixion-threaded-formula-calculation-library/#comments</comments>
		<pubDate>Tue, 22 Jun 2010 01:06:42 +0000</pubDate>
		<dc:creator>Kohei Yoshida</dc:creator>
				<category><![CDATA[]]></category>
		<category><![CDATA[algorithm]]></category>
		<category><![CDATA[formula]]></category>
		<category><![CDATA[hack week]]></category>
		<category><![CDATA[ixion]]></category>
		<category><![CDATA[novell]]></category>
		<category><![CDATA[thread]]></category>

		<guid isPermaLink="false">http://kohei.us/?p=750</guid>
		<description><![CDATA[I spent my entire last week on my personal project, by taking advantage of Novell&#8217;s HackWeek.  Officially, HackWeek took place two weeks ago, but because I had to travel that week I postponed mine till the following week.
Ixion is the project I worked on as part of my HackWeek.  This project is an [...]]]></description>
			<content:encoded><![CDATA[<p>I spent my entire last week on my personal project, by taking advantage of Novell&#8217;s HackWeek.  Officially, HackWeek took place two weeks ago, but because I had to travel that week I postponed mine till the following week.</p>
<p><a href="http://gitorious.org/ixion">Ixion</a> is the project I worked on as part of my HackWeek.  This project is an experimental effort to develop a stand-alone library that supports parallel computation of formula expressions using threads.  I&#8217;d been working on this on and off in my spare time, but when the opportunity came along to spend one week of my paid time on any project of my choice (personal or otherwise), I didn&#8217;t hesitate to pick Ixion.</p>
<h3>Overview</h3>
<p>So, what&#8217;s Ixion?  Ixion aims to provide a library for calculating the results of formula expressions stored in multiple named targets, or &#8220;cells&#8221;. The cells can be referenced from each other, and the library takes care of resolving their dependencies automatically upon calculation. The caller can run the calculation routine either in a single-threaded mode, or a multi-threaded mode. The library also supports re-calculation where the contents of one or more cells have been modified since the last calculation, and a partial calculation of only the affected cells gets performed.  It is written entirely in C++, and makes extensive use of the <a href="http://boost.org">boost library</a> to achieve portability across different platforms.  It has currently been tested to build on Linux and Windows.</p>
<p>The goal is to eventually bring this library up to the level where it can serve as a full-featured calculation engine for spreadsheet applications.  But right now, this project remains as an experimental, proof-of-concept project to help me understand what is required to build a threaded calculation engine capable of performing all sorts of tasks required in a typical spreadsheet app.</p>
<p>I consider this project a library project; however, building this project only creates a single stand-alone console application at the moment.  I plan to separate it into a shared library and a front-end executable in the future, to allow external apps to dynamically link to it.</p>
<h3>How it works</h3>
<p>Building this project creates an executable called <code>ixion-parser</code>.  Running it with a <code>-h</code> option displays the following help content:</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">Usage: ixion-parser [options] FILE1 FILE2 ...
&nbsp;
The FILE must contain the definitions of cells according to the cell definition rule.
&nbsp;
Allowed options:
  -h [ --help ]         print this help.
  -t [ --thread ] arg   specify the number of threads to use for calculation.  
                        Note that the number specified by this option 
                        corresponds with the number of calculation threads i.e.
                        those child threads that perform cell interpretations. 
                        The main thread does not perform any calculations; 
                        instead, it creates a new child thread to manage the 
                        calculation threads, the number of which is specified 
                        by the arg.  Therefore, the total number of threads 
                        used by this program will be arg + 2.</pre></div></div>

<p>The parser expects one or more cell definition files as arguments.  A cell definition file may look like this:</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">%mode init
A1=1
A2=A1+10
A3=A2+A1*30
A4=(10+20)*A2
A5=A1-A2+A3*A4
A6=A1+A3
A7=A7
A8=10/0
A9=A8
%calc
%mode result
A1=1
A2=11
A3=41
A4=330
A5=13520
A6=42
A7=#REF!
A8=#DIV/0!
A9=#DIV/0!
%check
%mode edit
A6=A1+A2
%recalc
%mode result
A1=1
A2=11
A3=41
A4=330
A5=13520
A6=12
A7=#REF!
A8=#DIV/0!
A9=#DIV/0!
%check
%mode edit
A1=10
%recalc</pre></div></div>

<p>I hope the format of the cell definition rule is straightforward.  The definitions are read from top down.  I used the so-called A1 notation to name target cells, but it doesn&#8217;t have to be that way.  You can use any naming scheme to name target cells as long as the lexer recognizes them as names.  Also, the format supports a command construct; a line beginning with a &#8216;%&#8217; is considered a command.  Several commands are currently available.  For instance the <strong>mode</strong> command lets you switch input modes.  The parser currently supports three input modes:</p>
<ul>
<li><strong>init</strong> &#8211; initialize cells with specified contents.</li>
<li><strong>result</strong> &#8211; pick up expected results for cells, for verification.</li>
<li><strong>edit</strong> &#8211; modify cell contents.</li>
</ul>
<p>In addition to the <strong>mode</strong> command, the following commands are also supported:</p>
<ul>
<li><strong>calc</strong> &#8211; perform full calculation, by resetting the cached results of all involved cells.</li>
<li><strong>recalc</strong> &#8211; perform partial re-calculation of modified cells and cells that reference modified cells, either directly or indirectly.</li>
<li><strong>check</strong> &#8211; verify the calculation results.</li>
</ul>
<p>Given all this, let&#8217;s see what happens when you run the parser with the above cell definition file.</p>

<div class="wp_syntax"><div class="code"><pre class="txt" style="font-family:monospace;">./ixion-parser -t 4 test/01-simple-arithmetic.txt 
Using 4 threads
Number of CPUS: 4
---------------------------------------------------------
parsing test/01-simple-arithmetic.txt
---------------------------------------------------------
A1: 1
A1: result = 1
---------------------------------------------------------
A2: A1+10
A2: result = 11
---------------------------------------------------------
A3: A2+A1*30
A3: result = 41
---------------------------------------------------------
A4: (10+20)*A2
A4: result = 330
---------------------------------------------------------
A5: A1-A2+A3*A4
A5: result = 13520
---------------------------------------------------------
A8: 10/0
result = #DIV/0!
---------------------------------------------------------
A6: A1+A3
A6: result = 42
---------------------------------------------------------
A9: 
result = #DIV/0!
---------------------------------------------------------
A7: result = #REF!
---------------------------------------------------------
checking results
---------------------------------------------------------
A2 : 11
A8 : #DIV/0!
A3 : 41
A9 : #DIV/0!
A4 : 330
A5 : 13520
A6 : 42
A7 : #REF!
A1 : 1
---------------------------------------------------------
recalculating
---------------------------------------------------------
A6: A1+A2
A6: result = 12
---------------------------------------------------------
checking results
---------------------------------------------------------
A2 : 11
A8 : #DIV/0!
A3 : 41
A9 : #DIV/0!
A4 : 330
A5 : 13520
A6 : 12
A7 : #REF!
A1 : 1
---------------------------------------------------------
recalculating
---------------------------------------------------------
A1: 10
A1: result = 10
---------------------------------------------------------
A2: A1+10
A2: result = 20
---------------------------------------------------------
A3: A2+A1*30
A3: result = 320
---------------------------------------------------------
A4: (10+20)*A2
A4: result = 600
---------------------------------------------------------
A5: A1-A2+A3*A4
A5: result = 191990
---------------------------------------------------------
A6: A1+A2
A6: result = 30
---------------------------------------------------------
(duration: 0.00113601 sec)
---------------------------------------------------------</pre></div></div>

<p>Notice that at the beginning of the output, it displays the number of threads being used, and the number of &#8220;CPU&#8221;s it detected.  Here, the &#8220;CPU&#8221; may refer to the number of physical CPUs, the number of cores, or the number of hyper-threading units.  I&#8217;m well aware that I need to use a different term for this other than &#8220;CPU&#8221;, but anyways&#8230;  The number of child threads to use to perform calculation can be specified at run-time via <code>-t</code> option.  When running without the <code>-t</code> option, the parser will run in a single-threaded mode.  Now, let me go over what the above output means.</p>
<p>The first calculation performed is a full calculation.  Since no cells have been calculated yet, we need to calculate results for all defined cells.  This is followed by a verification of the initial calculation.  After this, we modify cell A6, and perform partial re-calculation.  Since no other cells depend on the result of cell A6, the re-calc only calculates A6.</p>
<p>Now, the third calculation is also a partial re-calculation following the modification of cell A1.  This time, because several other cells <em>do</em> depend on the result of A1, those cells also need to be re-calculated.  The end result is that cells A1, A2, A3, A4, A5 and A6 all get re-calculated.</p>
<h3>Under the hood</h3>
<h4>Cell dependency resolution</h4>
<p><a href="http://kohei.us/wp-content/uploads/2010/06/cell-dependency-graph.png"><img src="http://kohei.us/wp-content/uploads/2010/06/cell-dependency-graph-300x222.png" alt="cell-dependency-graph" title="cell-dependency-graph" width="300" height="222" class="alignright size-medium wp-image-766" /></a><br />
There are several technical aspects of the implementation of this library I&#8217;d like to cover.  The first is cell dependency resolution.  I use a well-known algorithm called <a href="http://en.wikipedia.org/wiki/Topological_sorting">topological sort</a> to sort cells in order of dependency so that cells can be calculated one by one without being blocked by the calculation of precedent cells.  Topological sort is typically used to manage scheduling of tasks that are inter-dependent with each other, and it was a perfect one to use to resolve cell dependencies.  This algorithm is a by-product of <a href="http://en.wikipedia.org/wiki/Depth-first_search">depth first search</a> of <a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph">directed acyclic graph (DAG)</a>, and is well-documented.  A quick google search should give you tons of pseudo code examples of this algorithm.  This algorithm work well both for full calculation and partial re-calculation routines.</p>
<h4>Managing threaded calculation</h4>
<p>The heart of this project is to implement parallel evaluation of formula expressions, which has been my number 1 goal from the get-go.  This is also the reason why I put my focus on designing the threaded calculation engine as my initial goal before I start putting my focus into other areas.  Programming with threads was also very new to me, so I took extra care to ensure that I understand what I&#8217;m doing, and I&#8217;m designing it correctly.  Also, designing a framework that uses multiple threads can easily get out-of-hand and out-of-control when it&#8217;s overdone.  So, I made an extra effort to limit the area where multiple threads are used while keeping the rest of the code single-threaded, in order to keep the code simple and maintainable.</p>
<p>As I soon realized, even knowing the basics of programming with threads, you are not immune to falling into many pitfalls that may arise during the actual designing and debugging of concurrent code.  You have to go extra miles ensuring that access to thread-global data are synchronized, and that one thread waits for another thread in case threads must be executed in certain order.  These things may sound like common sense and probably are in every thread programming text book, but in reality they are very easy to overlook, especially to those who have not had substantial exposure to concurrency before.  Parallelism seemed that <em>un</em>-orthodox to conventional minds like myself.  Having said all that, once you go through enough pain dealing with concurrency, it does become less painful after a while.  Your mind can simply adjust to &#8220;thinking in parallel&#8221;.</p>
<p>Back to the topic.  I&#8217;ve picked the following pattern to manage threaded calculation.</p>
<p><a href="http://kohei.us/wp-content/uploads/2010/06/thread-design.png"><img src="http://kohei.us/wp-content/uploads/2010/06/thread-design-300x271.png" alt="thread-design" title="thread-design" width="300" height="271" class="alignnone size-medium wp-image-781" /></a></p>
<p>First, the <strong>main thread</strong> creates a new thread whose job is to manage cell queues, that is, receiving queues from the main thread and assigning them to idle threads to perform calculation.  It is also responsible for keeping track of which threads are idle and ready to take on a cell assignment.  Let&#8217;s call this thread a <strong>queue manager thread</strong>.  When the queue manager thread is created, it spawns a specified number of child threads, and waits until they are all ready.  These child threads are the ones that perform cell calculation, and we call them <strong>calc threads</strong>.</p>
<p>Each calc thread registers itself as an idle thread upon creation, then sleeps until the queue manager thread assigns it a cell to calculate and signals it to wake up.  Once awake, it calculates the cell, registers itself as an idle thread once again and goes back to sleep.  This cycle continues until the queue manager thread sends a termination request to it, after which it breaks out of the cycle and reaches the end of its execution path to terminate.</p>
<p>The role of the queue manager thread is to receive cell calculation requests from the main thread and pass them on to idle calc threads.  It keeps doing it until it receives a termination request from the main thread.  Once receiving the termination request from the main thread, it sends all the remaining cells in queue to the calc threads to finish up, then sends termination requests to the calc threads and wait until all of them terminate.</p>
<p>Thanks to the cells being sorted in topological order, the process of putting a cell in queue and having a calc thread perform calculation is entirely asynchronous.  The only exception is that when referencing another cell during calculation, the result of that referenced cell may not be available at the time of the value query due to concurrency.  In such cases, the calculating thread needs to block its execution until the result of the referenced cell becomes available.  When running in a single-threaded mode, on the other hand, the result of a referenced cell is guaranteed to be available as long as cells are calculated in topological order and contain no circular references.</p>
<h3>What I accomplished during HackWeek</h3>
<p>During HackWeek, I was able to accomplish quite a few things.  Before the HackWeek, the threaded calculation framework was not even there; the parser was only able to reliably perform calculation in a single-threaded mode.  I had some test code to design the threaded queue management framework, but that code had yet to be integrated into the main formula interpreter code.  A lot of work was still needed, but thanks to having an entire week devoted for this, I was able to </p>
<ul>
<li>port the test threaded queue manager framework code into the formula interpreter code,</li>
<li>adopt the circular dependency detection code for the new threaded calculation framework, </li>
<li>test the new framework to squeeze lots of kinks out,</li>
<li>put some performance optimization in the cell definition parser and the formula lexer code,</li>
<li>implement result verification framework, and</li>
<li>implement partial re-calculation.</li>
</ul>
<p>Had I had to do all this in my spare time alone, it would have easily taken months.  So, I&#8217;m very thankful for the event, and I look forward to having another opportunity like this in hopefully not-so-distant future.</p>
<h3>What lies ahead</h3>
<p>So, what lies ahead for <a href="http://gitorious.org/ixion">Ixion</a>?  You may ask.  There are quite a few things to get done.  Let me start first by saying that, this library is far from providing all the features that a typical spreadsheet application needs.  So, there are still lots of work needed to make it even usable.  Moreover, I&#8217;m not even sure whether this library will become usable enough for real-world spreadsheet use, or it will simply end up being just another interesting proof-of-concept.  My hope is of course to see this library evolve into maturity, but at the same time I&#8217;m also aware that it would be hard to advance this project with only my scarce spare time to spend in.</p>
<p>With that said, here are some outstanding issues that I plan on addressing as time permits.</p>
<ul>
<li>Add support for literal strings, and support textural formula results in addition to numerical results.</li>
<li>Add support for empty cells. Empty cells are those cells that are not defined in the model definition file but can still be referenced. Currently, referencing a cell that is not defined causes a reference error.</li>
<li>Add support for cell ranges.  This implies that I need to make cell instances addressable by 3-dimensional coordinates rather than by pointer values.</li>
<li>Split the code into two parts: a shared library and an executable.</li>
<li>Use autoconf to make the build process configurable.</li>
<li>Make the expression parser feature-complete.</li>
<li>Implement more functions.  Currently only MAX and MIN are implemented.</li>
<li>Support for localized numbers.</li>
<li>Lots and lots more.</li>
</ul>
<h3>Conclusion</h3>
<p>This concludes my HackWeek report.  Thank you very much, ladies and gentlemen.</p>
]]></content:encoded>
			<wfw:commentRss>http://kohei.us/2010/06/21/ixion-threaded-formula-calculation-library/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>mdds 0.3.0 released!</title>
		<link>http://kohei.us/2010/05/05/mdds-0-3-0-released/</link>
		<comments>http://kohei.us/2010/05/05/mdds-0-3-0-released/#comments</comments>
		<pubDate>Thu, 06 May 2010 00:20:49 +0000</pubDate>
		<dc:creator>Kohei Yoshida</dc:creator>
				<category><![CDATA[]]></category>
		<category><![CDATA[mdds]]></category>

		<guid isPermaLink="false">http://kohei.us/?p=738</guid>
		<description><![CDATA[I&#8217;m happy to announce the release of version 0.3.0 of Multi-Dimensional Data Structure, or mdds for short.  This is a C++ library, and is a collection of various data structures designed to efficiently store and query multi-dimensional data for various filtering criteria.  Different structures are optimized for different query needs.
This library is a [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m happy to announce the release of version 0.3.0 of <a href="http://code.google.com/p/multidimalgorithm/">Multi-Dimensional Data Structure</a>, or mdds for short.  This is a C++ library, and is a collection of various data structures designed to efficiently store and query multi-dimensional data for various filtering criteria.  Different structures are optimized for different query needs.</p>
<p>This library is a source-code only library.  It&#8217;s designed to be header-only meaning that the user program does not need to link to any additional shared library in order to use these data structures.  The data structures are all available as C++ templates.</p>
<p>I have briefly touched on the motivation behind starting this project when I previously <a href="http://kohei.us/2010/02/20/increasing-calcs-row-limit-to-1-million/">talked about my effort to increase Calc&#8217;s row limit</a>, the effort of which eventually led to the creation of Flat segment tree, one of the structures included in this library.</p>
<h3>What this release contains</h3>
<p>This version contains the following four data structures:</p>
<ul>
<li>Segment tree</li>
<li>Flat segment tree</li>
<li>Rectangle set</li>
<li>Point quad tree</li>
</ul>
<p>I will not go into the details of each of these data structures in this post, but I will probably do a follow-up post explaining the strengths of each structure, and details of how they are structured internally, how the query works etc.  The <a href="http://code.google.com/p/multidimalgorithm/">project home page</a> provides a brief (yes, very brief!) overview of these data structures for the curious-minded.</p>
<h3>Installation</h3>
<p>I&#8217;ve created a package for the SUSE family of Linux distributions, via <a href="https://build.opensuse.org/">openSUSE Build Service (OBS)</a>.  There is also a link to 1-Click Install from the <a href="http://code.google.com/p/multidimalgorithm/">project home page</a>.</p>
<p>For non-SUSE users, please install it directly from the generic source package available from <a href="http://multidimalgorithm.googlecode.com/files/mdds_0.3.0.tar.bz2">here</a>, but first I must apologize for not providing the familiar configure, make, make install installation option yet.  That&#8217;s one of the things I&#8217;d like to work on in future releases.  For now, please install the library manually by</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">tar</span> xvf mdds_0.3.0.tar.bz2
<span style="color: #7a0874; font-weight: bold;">cd</span> mdds_0.3.0
<span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">cp</span> <span style="color: #660033;">-R</span> inc<span style="color: #000000; font-weight: bold;">/</span>mdds <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>include<span style="color: #000000; font-weight: bold;">/</span></pre></div></div>

<h3>How to use these data structures</h3>
<p>I&#8217;ve provided some example source code under the example directory which should serve as a quick tutorial on how to use these structures.  For more details of the API, please refer to their respective header file.  As time permits, I will work on providing documentation for this library.</p>
<h3>Lastly&#8230;</h3>
<p>Comments and feedback are very much appreciated!  Thank you very much, ladies and gentlemen. :-)</p>
]]></content:encoded>
			<wfw:commentRss>http://kohei.us/2010/05/05/mdds-0-3-0-released/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fetching tarball before the build</title>
		<link>http://kohei.us/2010/04/29/fetching-tarball-before-the-build/</link>
		<comments>http://kohei.us/2010/04/29/fetching-tarball-before-the-build/#comments</comments>
		<pubDate>Thu, 29 Apr 2010 15:11:49 +0000</pubDate>
		<dc:creator>Kohei Yoshida</dc:creator>
				<category><![CDATA[]]></category>
		<category><![CDATA[openoffice.org]]></category>

		<guid isPermaLink="false">http://kohei.us/?p=733</guid>
		<description><![CDATA[I just rebased one of my upstream child work spaces to milestone 77 (DEV300_m77), and noticed my build breaking all over the place due to missing patches for external libraries.  After some digging, here is the step I was missing.

./fetch_tarballs.sh ooo.lst

which apparently downloads a whole bunch of external source packages from http://hg.services.openoffice.org/binaries that the [...]]]></description>
			<content:encoded><![CDATA[<p>I just rebased one of my upstream child work spaces to milestone 77 (DEV300_m77), and noticed my build breaking all over the place due to missing patches for external libraries.  After some digging, here is the step I was missing.</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">.<span style="color: #000000; font-weight: bold;">/</span>fetch_tarballs.sh ooo.lst</pre></div></div>

<p>which apparently downloads a whole bunch of external source packages from <a href="http://hg.services.openoffice.org/binaries">http://hg.services.openoffice.org/binaries</a> that the build depends on, and places them into their respective location within the source tree.  After this was done, my build proceeded normally.</p>
]]></content:encoded>
			<wfw:commentRss>http://kohei.us/2010/04/29/fetching-tarball-before-the-build/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>STL container performance on data insertion</title>
		<link>http://kohei.us/2010/03/31/stl-container-performance-on-data-insertion/</link>
		<comments>http://kohei.us/2010/03/31/stl-container-performance-on-data-insertion/#comments</comments>
		<pubDate>Thu, 01 Apr 2010 01:12:55 +0000</pubDate>
		<dc:creator>Kohei Yoshida</dc:creator>
				<category><![CDATA[]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[code snippet]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[stl]]></category>

		<guid isPermaLink="false">http://kohei.us/?p=718</guid>
		<description><![CDATA[I just ran a quick analysis on the performance of various STL containers on simple data insertion.  The result was not exactly what I expected so I&#8217;d like to share it with you.
What was performed was sequential insertions of 50,000,000 (50 million) unique pointer values into various STL containers, either by push_back or insert, [...]]]></description>
			<content:encoded><![CDATA[<p>I just ran a quick analysis on the performance of various STL containers on simple data insertion.  The result was not exactly what I expected so I&#8217;d like to share it with you.</p>
<p>What was performed was sequential insertions of 50,000,000 (50 million) unique pointer values into various STL containers, either by push_back or insert, depending on which method is supported by the container.  I ran the test on openSUSE 11.2, with g++ 4.4.1, with the compiler options of <strong>-std=c++0x -Os -g</strong>.  The -std=c++0x flag is necessary in order to use std::unordered_set.</p>
<p>Anyway, here is the result I observed:</p>
<p><img src="http://kohei.us/wp-content/uploads/2010/03/stl-perf.png" alt="stl-perf" title="stl-perf" width="633" height="351" class="alignnone size-full wp-image-719" /></p>
<p>I was fully aware of the set containers being slower than list and vector on insertion, due to the internal structure of set being more elaborate than those of list or vector, and this test confirms my knowledge.  However, I was not aware of such wide gap between list and vector.  Also, the difference between unreserved and reserved vector was not as wide as I would have expected.  (For the sake of completeness, a reserved vector is an instance of vector whose internal array size is pre-allocated in advance in order to avoid re-allocation.)  My belief has always been that reserving vector in advance improves performance on data insertion, which it does, but I was expecting a wider gap between the two.  So, the result I see here is a bit unexpected.</p>
<p>In case you want to re-run this test on your own environment, here is the code I used to measure the containers&#8217; performance:</p>

<div class="wp_syntax"><div class="code"><pre class="cpp" style="font-family:monospace;"><span style="color: #339900;">#include &lt;vector&gt;</span>
<span style="color: #339900;">#include &lt;unordered_set&gt;</span>
<span style="color: #339900;">#include &lt;set&gt;</span>
<span style="color: #339900;">#include &lt;list&gt;</span>
&nbsp;
<span style="color: #339900;">#include &lt;stdio.h&gt;</span>
<span style="color: #339900;">#include &lt;string&gt;</span>
<span style="color: #339900;">#include &lt;sys/time.h&gt;</span>
&nbsp;
<span style="color: #0000ff;">using</span> <span style="color: #0000ff;">namespace</span> std<span style="color: #008080;">;</span>
&nbsp;
<span style="color: #0000ff;">namespace</span> <span style="color: #008000;">&#123;</span>
&nbsp;
<span style="color: #0000ff;">class</span> StackPrinter
<span style="color: #008000;">&#123;</span>
<span style="color: #0000ff;">public</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">explicit</span> StackPrinter<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">const</span> <span style="color: #0000ff;">char</span><span style="color: #000040;">*</span> msg<span style="color: #008000;">&#41;</span> <span style="color: #008080;">:</span>
        msMsg<span style="color: #008000;">&#40;</span>msg<span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000dd;">fprintf</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">stdout</span>, <span style="color: #FF0000;">&quot;%s: --begin<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, msMsg.<span style="color: #007788;">c_str</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        mfStartTime <span style="color: #000080;">=</span> getTime<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    ~StackPrinter<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">double</span> fEndTime <span style="color: #000080;">=</span> getTime<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000dd;">fprintf</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">stdout</span>, <span style="color: #FF0000;">&quot;%s: --end (duration: %g sec)<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, msMsg.<span style="color: #007788;">c_str</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, <span style="color: #008000;">&#40;</span>fEndTime<span style="color: #000040;">-</span>mfStartTime<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">void</span> printTime<span style="color: #008000;">&#40;</span><span style="color: #0000ff;">int</span> line<span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span>
    <span style="color: #008000;">&#123;</span>
        <span style="color: #0000ff;">double</span> fEndTime <span style="color: #000080;">=</span> getTime<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000dd;">fprintf</span><span style="color: #008000;">&#40;</span><span style="color: #0000ff;">stdout</span>, <span style="color: #FF0000;">&quot;%s: --(%d) (duration: %g sec)<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, msMsg.<span style="color: #007788;">c_str</span><span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>, line, <span style="color: #008000;">&#40;</span>fEndTime<span style="color: #000040;">-</span>mfStartTime<span style="color: #008000;">&#41;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">private</span><span style="color: #008080;">:</span>
    <span style="color: #0000ff;">double</span> getTime<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span> <span style="color: #0000ff;">const</span>
    <span style="color: #008000;">&#123;</span>
        timeval tv<span style="color: #008080;">;</span>
        gettimeofday<span style="color: #008000;">&#40;</span><span style="color: #000040;">&amp;</span>tv, <span style="color: #0000ff;">NULL</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">return</span> tv.<span style="color: #007788;">tv_sec</span> <span style="color: #000040;">+</span> tv.<span style="color: #007788;">tv_usec</span> <span style="color: #000040;">/</span> <span style="color:#800080;">1000000.0</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #008080;">::</span><span style="color: #007788;">std</span><span style="color: #008080;">::</span><span style="color: #007788;">string</span> msMsg<span style="color: #008080;">;</span>
    <span style="color: #0000ff;">double</span> mfStartTime<span style="color: #008080;">;</span>
<span style="color: #008000;">&#125;</span><span style="color: #008080;">;</span>
&nbsp;
<span style="color: #008000;">&#125;</span>
&nbsp;
<span style="color: #0000ff;">int</span> main<span style="color: #008000;">&#40;</span><span style="color: #008000;">&#41;</span>
<span style="color: #008000;">&#123;</span>
    <span style="color: #0000ff;">size_t</span> store_size <span style="color: #000080;">=</span> <span style="color: #0000dd;">50000000</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#123;</span>
        StackPrinter __stack_printer__<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;vector non-reserved&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        string<span style="color: #000040;">*</span> ptr <span style="color: #000080;">=</span> <span style="color: #208080;">0x00000000</span><span style="color: #008080;">;</span>
        vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span><span style="color: #000080;">&gt;</span> store<span style="color: #008080;">;</span>
        <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">size_t</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> store_size<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span>
            store.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>ptr<span style="color: #000040;">++</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #008000;">&#123;</span>
        StackPrinter __stack_printer__<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;vector reserved&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        string<span style="color: #000040;">*</span> ptr <span style="color: #000080;">=</span> <span style="color: #208080;">0x00000000</span><span style="color: #008080;">;</span>
        vector<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span><span style="color: #000080;">&gt;</span> store<span style="color: #008080;">;</span>
        store.<span style="color: #007788;">reserve</span><span style="color: #008000;">&#40;</span>store_size<span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">size_t</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> store_size<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span>
            store.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>ptr<span style="color: #000040;">++</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #008000;">&#123;</span>
        StackPrinter __stack_printer__<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;list&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        string<span style="color: #000040;">*</span> ptr <span style="color: #000080;">=</span> <span style="color: #208080;">0x00000000</span><span style="color: #008080;">;</span>
        list<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span><span style="color: #000080;">&gt;</span> store<span style="color: #008080;">;</span>
        <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">size_t</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> store_size<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span>
            store.<span style="color: #007788;">push_back</span><span style="color: #008000;">&#40;</span>ptr<span style="color: #000040;">++</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #008000;">&#123;</span>
        StackPrinter __stack_printer__<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;set&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        string<span style="color: #000040;">*</span> ptr <span style="color: #000080;">=</span> <span style="color: #208080;">0x00000000</span><span style="color: #008080;">;</span>
        set<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span><span style="color: #000080;">&gt;</span> store<span style="color: #008080;">;</span>   
        <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">size_t</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> store_size<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span>
            store.<span style="color: #007788;">insert</span><span style="color: #008000;">&#40;</span>ptr<span style="color: #000040;">++</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
&nbsp;
    <span style="color: #008000;">&#123;</span>
        StackPrinter __stack_printer__<span style="color: #008000;">&#40;</span><span style="color: #FF0000;">&quot;unordered set&quot;</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
        string<span style="color: #000040;">*</span> ptr <span style="color: #000080;">=</span> <span style="color: #208080;">0x00000000</span><span style="color: #008080;">;</span>
        unordered_set<span style="color: #000080;">&lt;</span><span style="color: #0000ff;">void</span><span style="color: #000040;">*</span><span style="color: #000080;">&gt;</span> store<span style="color: #008080;">;</span>
        <span style="color: #0000ff;">for</span> <span style="color: #008000;">&#40;</span><span style="color: #0000ff;">size_t</span> i <span style="color: #000080;">=</span> <span style="color: #0000dd;">0</span><span style="color: #008080;">;</span> i <span style="color: #000080;">&lt;</span> store_size<span style="color: #008080;">;</span> <span style="color: #000040;">++</span>i<span style="color: #008000;">&#41;</span>
            store.<span style="color: #007788;">insert</span><span style="color: #008000;">&#40;</span>ptr<span style="color: #000040;">++</span><span style="color: #008000;">&#41;</span><span style="color: #008080;">;</span>
    <span style="color: #008000;">&#125;</span>
<span style="color: #008000;">&#125;</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://kohei.us/2010/03/31/stl-container-performance-on-data-insertion/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>The book has arrived!</title>
		<link>http://kohei.us/2010/03/22/the-book-has-arrived/</link>
		<comments>http://kohei.us/2010/03/22/the-book-has-arrived/#comments</comments>
		<pubDate>Mon, 22 Mar 2010 19:58:22 +0000</pubDate>
		<dc:creator>Kohei Yoshida</dc:creator>
				<category><![CDATA[]]></category>
		<category><![CDATA[book]]></category>
		<category><![CDATA[unix]]></category>

		<guid isPermaLink="false">http://kohei.us/?p=703</guid>
		<description><![CDATA[
This is the 2nd edition of the classic Advanced Programming in the UNIX Environment book.  I&#8217;m a happy owner of the 1st edition, and ever since the 2nd edition was published I had the urge to go ahead and order a copy.  I had been fighting off that urge, but last week I [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://kohei.us/wp-content/uploads/2010/03/the-unix-book.jpg"><img src="http://kohei.us/wp-content/uploads/2010/03/the-unix-book-224x300.jpg" alt="the-unix-book" title="the-unix-book" width="224" height="300" class="alignnone size-medium wp-image-707" /></a></p>
<p>This is the 2nd edition of the classic Advanced Programming in the UNIX Environment book.  I&#8217;m a happy owner of the 1st edition, and ever since the 2nd edition was published I had the urge to go ahead and order a copy.  I had been fighting off that urge, but last week I had finally given up fighting and decided to place an order.</p>
<p>The 1st edition truly opened up my eyes on the power of UNIX programming.  Like the 1st edition, I am looking forward to discovering what this book offers, and how the UNIX system (most notably Linux) has evolved since the 1st edition was published.</p>
]]></content:encoded>
			<wfw:commentRss>http://kohei.us/2010/03/22/the-book-has-arrived/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mso-dumper now packaged in OBS</title>
		<link>http://kohei.us/2010/03/20/mso-dumper-now-packaged-in-obs/</link>
		<comments>http://kohei.us/2010/03/20/mso-dumper-now-packaged-in-obs/#comments</comments>
		<pubDate>Sun, 21 Mar 2010 03:06:23 +0000</pubDate>
		<dc:creator>Kohei Yoshida</dc:creator>
				<category><![CDATA[]]></category>
		<category><![CDATA[calc]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[filter]]></category>
		<category><![CDATA[mso-dumper]]></category>
		<category><![CDATA[power point]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tool]]></category>

		<guid isPermaLink="false">http://kohei.us/?p=699</guid>
		<description><![CDATA[I&#8217;m happy to announce that the mso-dumper tool is now packaged in the openSUSE build service under my home repository.  This tool is written in Python, and allows you to dump the contents of MS Office documents stored in the BIFF-structured binary file format in a more human readable fashion.  It is an [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m happy to announce that the mso-dumper tool is now <a href="http://download.opensuse.org/repositories/home:/kohei_yoshida/">packaged in the openSUSE build service under my home repository</a>.  This tool is written in Python, and allows you to dump the contents of MS Office documents stored in the BIFF-structured binary file format in a more human readable fashion.  It is an indispensable tool when dealing with importing from and/or exporting to the Office documents.  Right now, only Excel and Power Point formats are supported.</p>
<p>This package provides two new commands <code>xls-dump</code> and <code>ppt-dump</code>.  If you wish to dump the content of an Excel document, all you have to do is</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">xls-dump .<span style="color: #000000; font-weight: bold;">/</span>path<span style="color: #000000; font-weight: bold;">/</span>to<span style="color: #000000; font-weight: bold;">/</span>mydoc.xls</pre></div></div>

<p>and it dumps its content to standard output.  What the output looks like depends on what&#8217;s stored with the document, but it will look something like this:</p>
<pre>
...
0085h: =============================================================
0085h: BOUNDSHEET - Sheet Information (0085h)
0085h:   size = 14
0085h: -------------------------------------------------------------
0085h: B4 09 00 00 00 00 06 00 53 68 65 65 74 31
0085h: -------------------------------------------------------------
0085h: BOF position in this stream: 2484
0085h: sheet name: Sheet1
0085h: hidden state: visible
0085h: sheet type: worksheet or dialog sheet

008Ch: =============================================================
008Ch: COUNTRY - Default Country and WIN.INI Country (008Ch)
008Ch:   size = 4
008Ch: -------------------------------------------------------------
008Ch: 01 00 01 00 

00EBh: =============================================================
00EBh: MSODRAWINGGROUP - Microsoft Office Drawing Group (00EBh)
00EBh:   size = 90
00EBh: -------------------------------------------------------------
00EBh: 0F 00 00 F0 52 00 00 00 00 00 06 F0 18 00 00 00
00EBh: 02 04 00 00 02 00 00 00 02 00 00 00 01 00 00 00
00EBh: 01 00 00 00 02 00 00 00 33 00 0B F0 12 00 00 00
00EBh: BF 00 08 00 08 00 81 01 09 00 00 08 C0 01 40 00
00EBh: 00 08 40 00 1E F1 10 00 00 00 0D 00 00 08 0C 00
00EBh: 00 08 17 00 00 08 F7 00 00 10 

00FCh: =============================================================
00FCh: SST - Shared String Table (00FCh)
00FCh:   size = 8
00FCh: -------------------------------------------------------------
00FCh: 00 00 00 00 00 00 00 00
00FCh: -------------------------------------------------------------
00FCh: total number of references: 0
00FCh: total number of unique strings: 0
...
</pre>
<p>I have originally written this tool to deal with the Excel import and export part of Calc&#8217;s development, and continue to develop it further.  <a href="http://blog.thebehrens.net/">Thorsten Behrens</a> has later joined forces and <a href="http://blog.thebehrens.net/2009/01/08/python-binary-ppt-fun/">added support for the Power Point format</a>.  Right now, I&#8217;m working on adding an XML output format option to make it easier to compare outputs, which is important for regression testing.</p>
]]></content:encoded>
			<wfw:commentRss>http://kohei.us/2010/03/20/mso-dumper-now-packaged-in-obs/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Increasing Calc&#8217;s row limit to 1 million</title>
		<link>http://kohei.us/2010/02/20/increasing-calcs-row-limit-to-1-million/</link>
		<comments>http://kohei.us/2010/02/20/increasing-calcs-row-limit-to-1-million/#comments</comments>
		<pubDate>Sat, 20 Feb 2010 05:21:39 +0000</pubDate>
		<dc:creator>Kohei Yoshida</dc:creator>
				<category><![CDATA[]]></category>
		<category><![CDATA[algorithm]]></category>
		<category><![CDATA[calc]]></category>
		<category><![CDATA[go-oo]]></category>
		<category><![CDATA[openoffice.org]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[row limit]]></category>

		<guid isPermaLink="false">http://kohei.us/?p=668</guid>
		<description><![CDATA[Introduction
With the child work space (CWS) koheirowlimitperf being marked ready for QA, I believe this is a good time to talk about the change that the CWS will bring once it gets integrated.
The role of this CWS is to upstream various pieces of performance optimization from Go-OO, that arose from the increase of the row [...]]]></description>
			<content:encoded><![CDATA[<h2>Introduction</h2>
<p>With the child work space (CWS) <a href="http://eis.services.openoffice.org/EIS2/cws.ShowCWS?Path=DEV300/koheirowlimitperf">koheirowlimitperf</a> being marked ready for QA, I believe this is a good time to talk about the change that the CWS will bring once it gets integrated.</p>
<p>The role of this CWS is to upstream various pieces of performance optimization from <a href="http://go-oo.org/">Go-OO</a>, that arose from the increase of the row limit from 65536 (64 thousand rows) to 1048576 (1 million rows).  However, the upstream build will not see the increase of the row limit itself yet, as the upstream developers still consider that move premature due to two outstanding issues that are show stoppers for them.  I&#8217;ll talk more about those issues later.</p>
<p>What this CWS <em>does</em> change is the storage of row attributes to 1) improve performance of querying the attributes, and to 2) make extra information available that can be used to make the algorithm of various bits of operations more efficient.  The CWS also makes several other changes in order to improve performance in general, though not related to the change in the row attribute storage.</p>
<h2>Limitation of the old attribute storage</h2>
<p>Before I talk about how the row attributes are stored in the new storage, I&#8217;d like to talk about the limitation of the old attribute storage, and why it was not adequate when the row limit was raised to 1 million rows.  Also, in this article, I&#8217;ll only talk about row attribute storage, but the same argument also applies to the column attribute storage as well.<br />
The old attribute container was designed to store several different attributes altogether, namely, </p>
<ul>
<li>hidden state, </li>
<li>filtered state, </li>
<li>automatic page break position, </li>
<li>manual page break position, and </li>
<li>whether or not a row has a manual height.</li>
</ul>
<p>They were stored per range, not per individual row or column, so that if a range of rows had identical set of attribute values over the entire range, that attribute set would be stored as a single record.  Searching for the value of an attribute for an arbitrary row was performed linearly from the first record since the core of the container itself was simply just an array.</p>
<p>There were primarily two problems with this storage scheme that made the container non-scalable.  First, the attributes stored together in this container had different distribution patterns, which caused over-partitioning of the container and unnecessarily slowed down the queries of <em>all</em> stored attributes.</p>
<p>For instance, the hidden and filtered attributes are distributed in a very similar manner, but the manual height attribute is not necessarily distributed in a manner similar to these attributes.  Because of this, storing that together with the hidden and filtered attributes unnecessarily increased the partition count, which in turn would slow down the query speed of <em>all three attributes</em>.</p>
<p>Even more problematic was the automatic page break attributes; because the automatic page breaks always need to be set for the entire sheet, increasing the row limit significantly raised the partition count.  On top of that, the page breaks themselves are actually single-row attributes; it made little sense to store them in a container that was range-based.</p>
<p>This over-partitioning problem led to the second problem; when the container was over-partitioned, querying for an attribute value would become very slow due to the linear search algorithm used in the query, and this algorithm scales with the number of partitions.  Because row attributes are used extensively in many areas of Calc&#8217;s operations, and often times in loops, the degradation of its lookup performance caused all sorts of interesting performance problems when the row limit was raised to 1 million.</p>
<h2>New way of storing row attributes</h2>
<h3>Separation of row attributes</h3>
<p>The first step in speeding up storage and lookup of row attributes is to separate them into own containers, to avoid the storage of one attribute affecting the storage of another.  It was natural to use a range-based container to store the hidden, filtered and the manual height attributes, since these attributes typically span over many consecutive rows.  The page break positions, on the other hand,  should be stored as point values as opposed to range values since they rarely occur in ranges and they are always set to individual rows.</p>
<p>I picked STL&#8217;s std::set container to store the automatic and manual page break positions (they are stored separately in two set containers).  That <em>alone</em> resulted in significantly speeding up the sheet pagination performance, whose performance previously suffered due to the poor storage speed of the old container.  Later on I improved the pagination performance even further by modifying the pagination algorithm itself, but more on that later.</p>
<p>For the hidden and filtered attributes, I picked a data structure that I call the <em>flat segment tree</em>, which I designed and implemented specifically for this purpose.  Row heights are also stored in the flat segment tree.</p>
<h3>Flat segment tree</h3>
<p>I named this data structure &#8220;flat segment tree&#8221; because it is a modified version of a data structure known as the <a href="http://en.wikipedia.org/wiki/Segment_tree">segment tree</a>, and unlike the original segment tree which supports storage of overlapping ranges, my version only stores non-overlapping ranges, hence the name &#8220;flat&#8221;.  The structure of the flat segment tree largely resembles that of the original segment tree; it consists of a balanced binary tree with its leaf nodes storing the values while its non-leaf nodes storing auxiliary data used only for querying purposes.  The leaf nodes are doubly-linked, allowing them a quick access to their neighboring nodes.  Since ranges never overlap with each other in this data structure, one leaf node represents the end of a preceding range and the start of the range that follows.  Last but not least, this data structure is a template, and allows you to specify the types of both key and value.</p>
<p><a href="http://kohei.us/wp-content/uploads/2010/02/flat-segment-tree-lookup.png"><img src="http://kohei.us/wp-content/uploads/2010/02/flat-segment-tree-lookup-300x143.png" alt="flat-segment-tree-lookup" title="flat-segment-tree-lookup" width="300" height="143" class="alignleft size-medium wp-image-686" /></a></p>
<p>There are three advantages of using this data structure: 1) compactness of storage since only the range boundaries are stored as nodes, 2) reasonably fast lookup thanks to its tree structure, and 3) a single query of a stored value also returns the lower and upper boundary positions of that range <em>with no additional overhead</em>.  The last point is very important which I will explain later in the next section.</p>
<p>As an additional rule, the flat segment tree guarantees that <em>the values of adjacent ranges are always different</em>.  There is no exception to this rule, so you can take advantage of this when you use this structure in your code.</p>
<p>Also, please do keep in mind that, while the lookup of a value is reasonably fast, it is not without an overhead.  So, you are discouraged to perform, say, lookup for every single row when you are iterating through a series of rows in a loop.  Instead, do make use of the range boundary info judiciously to skip ahead in such situation.</p>
<p>This data structure is distributed independently of the OOo code base, licensed under MIT/X11.  You can find the source code at <a href="http://code.google.com/p/multidimalgorithm/">http://code.google.com/p/multidimalgorithm/</a>.  That project includes other data structures than the flat segment tree; however, only the flat segment tree is currently usable by 3rd party programs; the implementations of other structures are still in an experimental stage, and need to be properly templetized before becoming usable in general.  Even the flat segment tree is largely undocumented.  This is intentional since the API is still not entirely frozen and is subject to change in future versions.  You have been warned.</p>
<h3>Loop count reduction</h3>
<p>Aside from the aforementioned improvement associated with the row attribute storage, I also worked on improving various algorithms used throughout Calc&#8217;s core, by taking advantage of one feature of the new data structure.<br />
<a href="http://kohei.us/wp-content/uploads/2010/02/loop-for-each-row.png"><img src="http://kohei.us/wp-content/uploads/2010/02/loop-for-each-row.png" alt="loop-for-each-row" title="loop-for-each-row" width="380" height="112" class="alignright size-full wp-image-679" /></a><br />
As I mentioned earlier, the flat segment tree returns the lower and upper boundary positions of the range as part of a normal value query.  You can make use of this extra piece of information to significantly reduce the number of loops in an algorithm that loops through a wide row range.  Put it another way, since you already know the attribute value associated with that range, and you also know the start and end positions of that range, you don&#8217;t need to query the value for every single row position within that range, thus reducing the number of iterations in the loop.  And the reduction of the loop count means the reduction of the time required to complete that operation, resulting in a better performance.</p>
<p>That&#8217;s the gist of the performance improvement work I did in various parts of Calc, though there were slight variations depending on which part of Calc&#8217;s code I worked on.  In summary, the following areas received significant performance improvement:</p>
<ul>
<li>Sheet pagination, which consisted of loops in which numerous calls are made to query row&#8217;s hidden states and row height values.</li>
<li>Print preview, mostly due to the improvement of the pagination performance.</li>
<li>Calculation of drawing object&#8217;s vertical position</li>
</ul>
<p>I&#8217;m sure there are other areas where the performance still needs improvement.  As this is an on-going effort, we will work on resolving any other outstanding issues as we discover them.</p>
<h2>Other related work</h2>
<p>In addition to the re-work of the row attribute storage and the performance improvement involving the row attribute queries, I&#8217;ve also made other changes to improve performance and ensure that Calc&#8217;s basic usability is not sacrificed.</p>
<h3>Removal of redundant pagination</h3>
<p>Prior to my row limit increase work, Calc would re-calculate page break positions again and again even when no changes were made to the document that would alter page break positions, such as changing row heights, filtering rows, inserting manual page breaks, and so on.  Because the pagination operation became much more expensive after the row limit increase, I have decided to remove this redundancy so that the re-pagination is done <em>only when necessary</em>.  This change especially made huge impact in print preview performance, since (for whatever reason) Calc was performing full pagination every time you move the mouse cursor within the preview pane, even when the movement was only by one pixel!  Removal of such redundant re-pagination has brought sanity back to the print preview experience.</p>
<h3>Efficient zoom level calculation</h3>
<p>The row limit increase also caused the performance degradation of calculating the correct zoom size to fit the document within specified page size.  Calc does this when you specify your document to &#8220;fit within n pages wide and y pages tall&#8221; or &#8220;fit to n pages in total&#8221;.  The root cause was again in the degraded performance in pagination.  This time, however, I could not use the trick of &#8220;performing pagination only once&#8221;, because we do need to perform full pagination continuously at different zoom levels in order to find a correct zoom level.</p>
<p>The solution I employed was to reduce the number of re-pagination by using the <a href="http://en.wikipedia.org/wiki/Bisection_method">bisection method</a> to arrive at the correct zoom level.  The old code worked like this:</p>
<ol>
<li>Initialize the zoom level to 100%, and perform full pagination.</li>
<li>If that doesn&#8217;t fit the required page size, decrement the zoom level by 1%, and perform full pagination once again.</li>
<li>If that doesn&#8217;t fit, decrement the zoom level by 1%, and try again.</li>
<li>Continue this until the correct zoom level is reached.</li>
</ol>
<p>Of course, if the correct zoom level is far below the initial value of 100%, this algorithm is not very efficient.  If the desired zoom level is 35%, for example, Calc would need to perform full pagination 66 times.  Switching to the bisection method here reduced the full pagination count roughly down to the neighborhood of 5 or 6.  At the time I worked on this, each full pagination took about 1 second.  So the reduction of pagination count from 66 to 5 roughly translated to the reduction of the zoom level calculation from 1 minute to 5 seconds.  Suffice it to say that this made a big difference.</p>
<p>Even better news is that the performance of this operation is much faster today, thanks to the improvement I made in the pagination performance in general.</p>
<h3>Calculation of autofill marker position</h3>
<p><a href="http://kohei.us/wp-content/uploads/2010/02/autofill.png"><img src="http://kohei.us/wp-content/uploads/2010/02/autofill-300x151.png" alt="autofill" title="autofill" width="300" height="151" class="alignright size-medium wp-image-675" /></a><br />
When making a selection, Calc puts the little square at the lower-right corner of the selection.  That&#8217;s called an autofill marker, and it&#8217;s there to let you drag selection to fill values.</p>
<p>Interestingly, calculating its position (especially its vertical position) turned out to be a very slow operation when the marker was positioned close to the bottom of the sheet.  Worse is the fact that Calc calculated its position even when it was outside the visible area.  The slowdown caused by this was apparent especially when making column selection.  Because selecting columns always places the autofill marker at the last row of the sheet, increasing the row limit made that process sluggish.  The solution was to simply detect whether the autofill marker is outside the visible area, and if it is, skip calculating its position (since there is no point calculating its position if we don&#8217;t need to display it).  That made the process of column selection back to normal again.</p>
<p>However, the sluggishness of making selection can still manifest itself under the right (wrong?) condition even with this change.  We still need to speed up the calculation of its vertical position, by improving the calculation algorithm itself.</p>
<h2>Show stoppers for the upstream build</h2>
<p>I sat down and briefly discussed with Niklas Nebel and Eike Rathke, Sun&#8217;s Calc co-leads, when we met during last year&#8217;s OOoCon in Orvieto, about the possibility of increasing the row limit in the upstream version of Calc.  During our discussion, I was told that, in addition to the general performance issues most of which I&#8217;ve already resolved, we will need to resolve at least two more outstanding issues before they can set the row limit to 1 million in the upstream build.</p>
<p>First, we need to improve the performance of the formula calculation and the value change propagation mechanism (that we call &#8220;broadcasting&#8221;).  The existing implementation is still tuned for the grid size of 65536 rows; we need to re-tune that for 1 million rows and to ensure that the performance will not suffer after the row limit increase.</p>
<p><a href="http://kohei.us/wp-content/uploads/2010/02/cell-note-misplaced.png"><img src="http://kohei.us/wp-content/uploads/2010/02/cell-note-misplaced-300x290.png" alt="cell-note-misplaced" title="cell-note-misplaced" width="300" height="290" class="alignleft size-medium wp-image-677" /></a></p>
<p>Second, we need to resolve the incorrect positioning of drawing objects at higher row positions.  This one is somewhat tricky, since the drawing objects are drawn entirely independent of the sheet grid, and the coerce resolution of the drawing layer causes the vertical position of a drawing object to deviate from its intended position.  Generally speaking, the higher the row position the more deviation results.  With the maximum of 65536 rows, however, it was not such a big issue since the amount of deviation was barely noticeable even at the highest row position.  But because the problem becomes much more noticeable with 1 million rows, this needs to be addressed somehow.</p>
<h2>Going forward&#8230;</h2>
<p>Going forward, I will continue to hunt for the remaining performance issues, and squash them one by one.  The major ones should all be resolved by now, so what&#8217;s remaining should be some corner case issues, performance-wise.  As for the two outstanding issues I mentioned in the previous section, we will have to take a good look at them at some point.  Whether or not they are really show stoppers is somewhat subject to personal view point, but they are real issues needing resolution, for sure, no matter what their perceived severity is.</p>
<p>Also, as of this writing, the manual row size attribute is still stored in the old, array-based container.  It will probably make sense to migrate that to the flat segment tree, so that we can eliminate the old container once and for all, and have a fresh start with the new container.  Having said that, doing so would require another round of refactoring of non-trivial scale, it should be conducted with care and proper testing.</p>
<p>The ODS export filter still needs re-work.  Currently, all row attributes which are now stored separately, are temporarily merged back into the old array-based container before exporting the document to ODS.  The reason is that the ODS export filter code still expects the partitioning behavior of the old container during the export of row styles.  In order to fully embrace the new storage of row attributes, that code needs to be adjusted to work with the new storage scheme.  Again, this will require a non-trivial amount of code change, thus should be conducted with care.</p>
<p>Calculation of vertical position of various objects, such as the autofill marker can still use some algorithmic improvement.  We can make them more efficient by taking advantage of the flat segment tree in a way similar to how the pagination algorithm was made more efficient.</p>
<h2>Conclusion</h2>
<p>This concludes my write-up on the current status of Calc&#8217;s row limit increase work.  I hope I&#8217;ve made it clear that work is underway toward making that happen without degrading Calc&#8217;s basic usability.  As a matter of fact, the row limit has already been increased to 1 million in some variants of OOo, such as <a href="http://go-oo.org/">Go-OO</a>.  I believe we&#8217;ll be able to increase the row limit in the upstream version in the not-so-distant future as long as we keep working at the remaining issues.</p>
<p>That&#8217;s all I have to say for now.  Thank you very much, ladies and gentlemen.</p>
]]></content:encoded>
			<wfw:commentRss>http://kohei.us/2010/02/20/increasing-calcs-row-limit-to-1-million/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Inserting current date and time in one step</title>
		<link>http://kohei.us/2010/02/16/inserting-current-date-in-one-step/</link>
		<comments>http://kohei.us/2010/02/16/inserting-current-date-in-one-step/#comments</comments>
		<pubDate>Tue, 16 Feb 2010 21:39:26 +0000</pubDate>
		<dc:creator>Kohei Yoshida</dc:creator>
				<category><![CDATA[]]></category>
		<category><![CDATA[calc]]></category>
		<category><![CDATA[feature]]></category>
		<category><![CDATA[go-oo]]></category>
		<category><![CDATA[openoffice.org]]></category>

		<guid isPermaLink="false">http://kohei.us/?p=655</guid>
		<description><![CDATA[
Here is another simple feature that may come in handy.
With the change I just checked into ooo-build master, you can now insert current date and time with just one key stroke.  By default, Ctrl+; (semicolon) is bound to current date, while Ctrl+Shift+; is bound to current time.  But these key bindings are configurable [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://kohei.us/wp-content/uploads/2010/02/current-date-time.png"><img src="http://kohei.us/wp-content/uploads/2010/02/current-date-time-300x182.png" alt="current-date-time" title="current-date-time" width="300" height="182" class="alignright size-medium wp-image-657" /></a><br />
Here is another simple feature that may come in handy.</p>
<p>With the change I just checked into ooo-build master, <em>you can now insert current date and time with just one key stroke</em>.  By default, <strong>Ctrl+; (semicolon)</strong> is bound to current date, while <strong>Ctrl+Shift+;</strong> is bound to current time.  But these key bindings are configurable in case you don&#8217;t like these default bindings.</p>
]]></content:encoded>
			<wfw:commentRss>http://kohei.us/2010/02/16/inserting-current-date-in-one-step/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
