<?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>Martin Ankerl</title>
	<atom:link href="http://martin.ankerl.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://martin.ankerl.com</link>
	<description>Chunky bacon!!</description>
	<lastBuildDate>Mon, 03 Jul 2017 14:03:10 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.8</generator>

<image>
	<url>http://martin.ankerl.com/wp-content/uploads/2014/06/cropped-P1070610-1-32x32.jpg</url>
	<title>Martin Ankerl</title>
	<link>http://martin.ankerl.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Essential Linux Dev Stuff</title>
		<link>http://martin.ankerl.com/2017/05/09/essential-linux-dev-stuff/</link>
		<comments>http://martin.ankerl.com/2017/05/09/essential-linux-dev-stuff/#respond</comments>
		<pubDate>Tue, 09 May 2017 06:20:30 +0000</pubDate>
		<dc:creator><![CDATA[martinus]]></dc:creator>
				<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=1727</guid>
		<description><![CDATA[I&#8217;ve recently started developing more in Linux, here is a collection of tools, tips and tricks to get the most out of the box. I&#8217;ll expand this list from time to time. Appearance Terminal &#38; Editor font: Hack Here is a test pattern I am using to evaluate fonts: [crayon-59628499ee997462961338/] This is how the pattern &#8230; <p class="link-more"><a href="http://martin.ankerl.com/2017/05/09/essential-linux-dev-stuff/" class="more-link">Continue reading<span class="screen-reader-text"> "Essential Linux Dev Stuff"</span></a></p>]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve recently started developing more in Linux, here is a collection of tools, tips and tricks to get the most out of the box. I&#8217;ll expand this list from time to time.</p>
<h1>Appearance</h1>
<h2>Terminal &amp; Editor font: Hack</h2>
<p>Here is a test pattern I am using to evaluate fonts:</p><pre class="crayon-plain-tag">o0O s5S z2Z !|l1Iij {([|})] .,;: ``''&quot;&quot; 
a@#* vVuUwW &lt;&gt;;^&deg;=-~ &ouml;&Ouml;&uuml;&Uuml;&auml;&Auml;&szlig;&micro; \/\/ 
the quick brown fox jumps over the lazy dog
THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
0123456789 &amp;-+@ for (int i=0; i&lt;j; ++i) { }</pre><p>This is how the pattern looks like with <a href="https://github.com/chrissimpkins/Hack">Hack</a>, my favourite programming font:</p>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/12/testpattern.png"><img class="aligncenter size-full wp-image-1738" src="http://martin.ankerl.com/wp-content/uploads/2016/12/testpattern.png" alt="testpattern" width="496" height="271" srcset="http://martin.ankerl.com/wp-content/uploads/2016/12/testpattern.png 496w, http://martin.ankerl.com/wp-content/uploads/2016/12/testpattern-300x164.png 300w" sizes="(max-width: 496px) 100vw, 496px" /></a></p>
<p>All characters are very distinguishable, e.g. 0 and O, 1 and l. Subpixel hinting is also excellent.</p>
<h2>colormake</h2>
<p>Simple wrapper around make to colorize its output.</p><pre class="crayon-plain-tag">sudo apt install colormake</pre><p></p>
<h2>redshift</h2>
<p>Install <tt>redshift-gtk</tt>, which is similar to <a href="https://justgetflux.com/">f.lux</a> but is more robust on my graphics card. I use this config for redshift (geoloc provider has problems). </p>
<p> In file <tt>~/.config/redshift.conf</tt>:</p>
<p></p><pre class="crayon-plain-tag">; Global settings
[redshift]
location-provider=manual
 
; Linz, Austria
[manual]
lat=48.306940
lon=14.285830</pre><p></p>
<h1>Tools</h1>
<h2>Terminator</h2>
<p>Multi-window terminal with lots of features.</p><pre class="crayon-plain-tag">sudo apt install terminator</pre><p></p>
<h2>ripgrep</h2>
<p>Extremely fast grep tool, similar to <a href="http://beyondgrep.com/">ack</a> but much faster, even faster than <a href="https://github.com/ggreer/the_silver_searcher">silver searcher</a>. It searches through my 48GB subversion folder in 1 second. Also available for Windows! See <a href="https://github.com/BurntSushi/ripgrep">here for installation instructions</a>.</p>
<p>I&#8217;ve also added some aliases in <tt>~/.bash_aliases</tt>:</p><pre class="crayon-plain-tag"># only sarch for cpp files, smart case handling.
alias rgc='rg -tcpp -S'

# only cpp, and only in test subfolders
alias rgct='rg -tcpp -g &quot;*/test/cpp/**/*&quot; -S'

# only cpp, everything but test subfolders
alias rgcnt='rg -tcpp -g \!&quot;*/test/cpp/**/*&quot; -S'</pre><p></p>
<h2>geany</h2>
<p>Replacement for <tt>gedit</tt>, for basic editing tasks. It&#8217;s not excellent but usually does the job. I&#8217;m not a vim/emacs guy.</p>
<h2>Visual Studio Code</h2>
<p>Nice and highly configurable editor, also great in Linux. Just open a directory and you are ready to go. <a href="https://code.visualstudio.com">Get it here</a>. Essential extensions are:</p>
<ul>
<li><a href="https://marketplace.visualstudio.com/items?itemName=spywhere.guides">Guides</a> &#8211; An extension for more guide lines</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=robertohuertasm.vscode-icons">vscode-icons</a> &#8211; Icons for Visual Studio Code</li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=dracula-theme.theme-dracula">Dracula Syntax Theme</a> &#8211; A dark theme for many editors, shells, and more.</li>
</ul>
<p>There are many others, but these are the bare minimum I use.</p>
<h2>glances</h2>
<p><a href="http://nicolargo.github.io/glances/">Glances</a> gives a fantastic overview of what&#8217;s going on in the system. Using you can see at a glance if e.g. your memory, disk space, swap is running out. The version you&#8217;ll get with <tt>apt</tt> is unfortunately quite outdate, so I am installing it with pip (see the homepage).</p>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/12/glances-1.png"><img class="aligncenter size-full wp-image-1743" src="http://martin.ankerl.com/wp-content/uploads/2016/12/glances-1.png" alt="glances" width="812" height="453" srcset="http://martin.ankerl.com/wp-content/uploads/2016/12/glances-1.png 812w, http://martin.ankerl.com/wp-content/uploads/2016/12/glances-1-300x167.png 300w, http://martin.ankerl.com/wp-content/uploads/2016/12/glances-1-768x428.png 768w" sizes="(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px" /></a></p>
<h1>Useful Time Savers</h1>
<h2>Clear Terminal buffer</h2>
<p>In <tt>~/.bash_aliases</tt>, put this:</p><pre class="crayon-plain-tag">alias cls='printf &quot;\033c&quot;'</pre><p>While Ctrl+L just clears the screen, <tt>cls</tt> will now clear the whole buffer. Convenient for a large build job and you want to scroll up to find something without scrolling too far.</p>
<h2>Sleep Until</h2>
<p>I use this ruby script to sleep until a given time. It&#8217;s in ruby so I can also easily use it in Windows:</p><pre class="crayon-plain-tag">#!/usr/bin/ruby

# sudo gem install chronic
require 'chronic'

exit(0) if ARGV.empty?


t = Chronic.parse(ARGV.join(" "))
now = Time.now
t += 60*60*24 if t < now
delaySeconds = t - now
puts "Sleeping #{delaySeconds.to_i} seconds until #{t.rfc2822}"
sleep(delaySeconds)</pre><p></p>
<p>I use this to schedule builds, so that when I arrive at the office everything is already built with the latest version so I can start working right away.</p><pre class="crayon-plain-tag">$ sleepuntil monday &amp;&amp; svn up &amp;&amp; make -j4 build
Sleeping 71605 seconds until Tue, 6 Dec 2016 03:00:00 +0100</pre><p></p>
<h2>bash prompt with runtime and errorcode</h2>
<p>See my <a href="http://martin.ankerl.com/2016/11/04/linux-bash-prompt/">Linux Bash Prompt</a> post. It&#8217;s awesome.</p>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/11/Screenshot_2016-11-07_06-24-23.png"><img class="aligncenter size-full wp-image-1717" src="http://martin.ankerl.com/wp-content/uploads/2016/11/Screenshot_2016-11-07_06-24-23.png" alt="screenshot_2016-11-07_06-24-23" width="579" height="272" srcset="http://martin.ankerl.com/wp-content/uploads/2016/11/Screenshot_2016-11-07_06-24-23.png 579w, http://martin.ankerl.com/wp-content/uploads/2016/11/Screenshot_2016-11-07_06-24-23-300x141.png 300w" sizes="(max-width: 579px) 100vw, 579px" /></a></p>
<h1>Optimizations</h1>
<h2>ccache</h2>
<p>Use ccache, and use it on an SSD disk. Here are my settings from <tt>~/.ccache/ccache.conf</tt>:</p><pre class="crayon-plain-tag">max_size = 16G
compression = true
compression_level = 1</pre><p>I&#8217;m using this for a huge C++ project where I build debug, release both in 32bit and 64bit, so a large ccache helps. Using <tt>compression_level</tt> is only a very minor slowdown, but practically increases cache size by a factor of 3-5 or so.</p>
<h2>Use <tt>tmpfs</tt> for <tt>/tmp</tt></h2>
<p>Much faster compilation. Add this to <tt>/etc/fstab</tt>:</p>
<p></p><pre class="crayon-plain-tag">tmpfs	/tmp	tmpfs	mode=1777,nosuid,nodev	0	0</pre><p> </p>
<h2>Compressed RAM</h2>
<p>Especially in virtual machines or low-end machines where memory is constrained, zram provides memory compression.</p>
<p></p><pre class="crayon-plain-tag">sudo apt install zram-config</pre><p> </p>
<p>Reboot your machine, and everything is well configured. For more information, see</p>
<ul>
<li><a href="https://www.kernel.org/doc/Documentation/blockdev/zram.txt">zram: Compressed RAM based block devices</a>
<li><a href="https://events.linuxfoundation.org/sites/events/files/slides/tmc_sjennings_linuxcon2013.pdf">Transparent Memory Compression in Linux (2013)</a></li>
</ul>
<h1>Disk Cleanup</h1>
<h2>Remove libreoffice</h2>
<p></p><pre class="crayon-plain-tag">sudo apt remove --purge libreoffice*
sudo apt clean
sudo apt autoremove</pre><p></p>
<h2>Remove old Kernels</h2>
<p></p><pre class="crayon-plain-tag">sudo apt install byobu
sudo purge-old-kernels</pre><p> </p>
<p>Source: <a href="http://ubuntuhandbook.org/index.php/2016/05/remove-old-kernels-ubuntu-16-04/">How to Easily Remove Old Kernels in Ubuntu 16.04</a></p>
<h1>Virtualbox</h1>
<h2>Dynamic Disk Size</h2>
<p>Don&#8217;t do it. It&#8217;s much slower. If you have to, be aware of this:</p>
<p>I&#8217;m using Linux in a Windows Host, my .vdi image is on an SSD. When using dynamic disk size, this unfortunately grows the space continuously when compiling a lot, because deleted files won&#8217;t shrink the .vdi image. But it is possible to do this with e.g. zerofree (a hazzle), or better with TRIM:</p>
<ul>
<li>In the Windows host, enable SSD and TRIM support for the image (see <a href="http://blog.glehmann.net/2015/01/20/Shrinking-VirtualBox-vdi-files/">here</a>):<br />
<pre class="crayon-plain-tag">VBoxManage storageattach ubuntu --storagectl &quot;SATA&quot; --port 0 --discard on --nonrotational on</pre></p>
<li>In Linux guest, perform TRIM, you&#8217;ll see the .vdi disk shrinking while this runs:<br />
<pre class="crayon-plain-tag">sudo fstrim -va</pre></p>
<li>Add a nightly task to crontab with <tt>sudo crontab -e</tt>, there add this line:<br />
<pre class="crayon-plain-tag">@midnight fstrim -a</pre>
</ul>
<p>I also tried to mount the image with the <tt>discard</tt> option (see <a href="https://wiki.ubuntuusers.de/SSD/TRIM/">here</a>), but it caused my Linux to hang so I disabled it again</p>
<h2>Mount shared folder</h2>
<p>Add the user to the vboxsf group:</p><pre class="crayon-plain-tag">sudo usermod -G vboxsf -a martinus</pre><p></p>
<p>Edit <tt>/etc/fstab</tt> e.g. like this:</p><pre class="crayon-plain-tag">Share_VB        /media/sf_Share_VB      vboxsf  defaults,noauto 0       0</pre><p></p>
<h2>GNOME keyring Without Password Prompt</h2>
<p>It&#8217;s unfortunate when a scheduled <tt>svn up</tt> asks for password because it has not been entered for a while. To disable the password question, do this:</p>
<ol>
<li><tt>sudo apt install seahorse</tt>
<li>Follow <a href="http://askubuntu.com/a/875">this guide</a>.
</ol>
<h2>Optimize Disk Scheduler: use <tt>noop</tt></h2>
<p>When using virtualbox, it&#8217;s best to use the <tt>noop</tt> scheduler. See <a href="https://access.redhat.com/solutions/5427">this</a>. From <a href="https://sites.google.com/site/easylinuxtipsproject/ssd">here</a>:</p>
<ol>
<li><tt>cat /sys/block/sda/queue/scheduler</tt>
<li><tt>sudo gedit /etc/default/grub</tt>
<li>Change the line <pre class="crayon-plain-tag">GRUB_CMDLINE_LINUX_DEFAULT=&quot;quiet splash&quot;</pre> into <pre class="crayon-plain-tag">GRUB_CMDLINE_LINUX_DEFAULT=&quot;elevator=noop quiet splash&quot;</pre>
<li><tt>sudo update-grub</tt>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2017/05/09/essential-linux-dev-stuff/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Visual Studio C++ 2015 Compiler Bug</title>
		<link>http://martin.ankerl.com/2017/02/28/visual-studio-c-2015-compiler-bug/</link>
		<comments>http://martin.ankerl.com/2017/02/28/visual-studio-c-2015-compiler-bug/#respond</comments>
		<pubDate>Tue, 28 Feb 2017 15:26:11 +0000</pubDate>
		<dc:creator><![CDATA[martinus]]></dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=1803</guid>
		<description><![CDATA[I think I&#8217;ve unfortunately found a compiler bug in Visual Studio 2015, all the way back to at least VS2010. Here is the code: [crayon-59628499f0041275401285/] Compile and run in 64bit, Release. This is the expected output (as with g++, clang++, or in debug): [crayon-59628499f004e635872382/] This is what I get with 64bit, Release: [crayon-59628499f0055488115281/] Also see &#8230; <p class="link-more"><a href="http://martin.ankerl.com/2017/02/28/visual-studio-c-2015-compiler-bug/" class="more-link">Continue reading<span class="screen-reader-text"> "Visual Studio C++ 2015 Compiler Bug"</span></a></p>]]></description>
				<content:encoded><![CDATA[<p>I think I&#8217;ve unfortunately found a compiler bug in Visual Studio 2015, all the way back to at least VS2010. Here is the code:</p>
<p></p><pre class="crayon-plain-tag">#include &lt;iostream&gt;
#include &lt;stdint.h&gt;

int main(int, char**) {
	for (uint32_t i = 1; i &lt; 3; ++i) {
		uint32_t a = i * 0xfbd1e995;
		uint64_t b = a;

		std::cout &lt;&lt; a &lt;&lt; " 32bit" &lt;&lt; std::endl;
		std::cout &lt;&lt; b &lt;&lt; " 64bit" &lt;&lt; std::endl;
	}
}</pre><p> </p>
<p>Compile and run in 64bit, Release. This is the expected output (as with <code>g++</code>, <code>clang++</code>, or in debug):</p>
<p></p><pre class="crayon-plain-tag">4224838037 32bit
4224838037 64bit
4154708778 32bit
4154708778 64bit</pre><p> </p>
<p>This is what I get with 64bit, Release:</p>
<p></p><pre class="crayon-plain-tag">4224838037 32bit
4224838037 64bit
4154708778 32bit
8449676074 64bit</pre><p> </p>
<p>Also see <a href="http://stackoverflow.com/q/42511458/48181">my stackoverflow post</a>. The compiler seems to optimize too much, and directly uses a 64bit number instead of making sure the 32bit value is casted to 64bit. <a href="https://connect.microsoft.com/VisualStudio/feedback/details/3125746/optimizer-uses-64bit-operation-instead-of-32bit-operation">I have already reported the bug to Microsoft</a>, and wait for feedback.</p>
]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2017/02/28/visual-studio-c-2015-compiler-bug/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linux Bash Prompt</title>
		<link>http://martin.ankerl.com/2016/11/04/linux-bash-prompt/</link>
		<comments>http://martin.ankerl.com/2016/11/04/linux-bash-prompt/#comments</comments>
		<pubDate>Fri, 04 Nov 2016 08:54:56 +0000</pubDate>
		<dc:creator><![CDATA[martinus]]></dc:creator>
				<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=1699</guid>
		<description><![CDATA[Here is my bash prompt, with the following features: Red &#10008; if the previous command has failed, otherwise a green &#10004;. Shows running time of the previous command Separate line for path and command Example Installation Add this to your .bashrc: [crayon-59628499f0609899800256/] Updates 2017-04-28: Now prints days, hours, minutes, seconds. Much better readable for long &#8230; <p class="link-more"><a href="http://martin.ankerl.com/2016/11/04/linux-bash-prompt/" class="more-link">Continue reading<span class="screen-reader-text"> "Linux Bash Prompt"</span></a></p>]]></description>
				<content:encoded><![CDATA[<p>Here is my bash prompt, with the following features:</p>
<ul>
<li>Red &#10008; if the previous command has failed, otherwise a green &#10004;.</li>
<li>Shows running time of the previous command</li>
<li>Separate line for path and command</li>
</ul>
<h1>Example</h1>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/11/Screenshot_2016-11-07_06-24-23.png"><img src="http://martin.ankerl.com/wp-content/uploads/2016/11/Screenshot_2016-11-07_06-24-23.png" alt="screenshot_2016-11-07_06-24-23" width="579" height="272" class="aligncenter size-full wp-image-1717" srcset="http://martin.ankerl.com/wp-content/uploads/2016/11/Screenshot_2016-11-07_06-24-23.png 579w, http://martin.ankerl.com/wp-content/uploads/2016/11/Screenshot_2016-11-07_06-24-23-300x141.png 300w" sizes="(max-width: 579px) 100vw, 579px" /></a></p>
<h1>Installation</h1>
<p>Add this to your <tt>.bashrc</tt>:</p>
<p></p><pre class="crayon-plain-tag">function timer_start {
  timer=${timer:-`date +%s.%3N`}
}
 
function timer_stop {
  local ELAPSED=$(bc &lt;&lt;&lt; "`date +%s.%3N` - $timer")

  local T=${ELAPSED%.*} 
  local AFTER_COMMA=${ELAPSED##*.}
  local D=$((T/60/60/24))
  local H=$((T/60/60%24))
  local M=$((T/60%60))
  local S=$((T%60))

  timer_show=
  [[ $D &gt; 0 ]] &amp;&amp; timer_show=${timer_show}$(printf '%dd ' $D)
  [[ $H &gt; 0 ]] &amp;&amp; timer_show=${timer_show}$(printf '%dh ' $H)
  [[ $M &gt; 0 ]] &amp;&amp; timer_show=${timer_show}$(printf '%dm ' $M)
  timer_show=${timer_show}$(printf "%d.${AFTER_COMMA}s" $S)
  
  unset timer
}
 
trap 'timer_start' DEBUG
PROMPT_COMMAND=timer_stop
 
PS1="\e[0m\n\[\`if [[ \$? = "0" ]]; then echo '\e[1;32m&#10004;'; else echo '\e[1;31m&#10008;' ; fi\` \e[1;32m\h\e[0m \e[1;94m\w\e[0m \e[93m\${timer_show}\e[0m\n\$ "</pre><p> </p>
<h1>Updates</h1>
<ul>
<li>2017-04-28: Now prints days, hours, minutes, seconds. Much better readable for long running tasks.
<li>2016-11-04: Initial version
</ul>
<h1>Sources</h1>
<ul>
<li><a href="http://stackoverflow.com/a/1862762/48181">How can the last command&#8217;s wall time be put in the Bash prompt?</a></li>
<li><a href="http://askubuntu.com/a/229451/14585">How to pass results of bc to a variable</a></li>
<li><a href="http://stackoverflow.com/a/103874/48181">What is your favorite Bash prompt? [closed]</a></li>
<li><a href="https://makandracards.com/makandra/1090-customize-your-bash-prompt">Customize your Bash prompt</a></li>
<li><a href="http://stackoverflow.com/a/32164707/48181">Convert seconds to hours, minutes, seconds</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2016/11/04/linux-bash-prompt/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Very Fast HashMap in C++: Benchmark Results (Part 3)</title>
		<link>http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-3/</link>
		<comments>http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-3/#comments</comments>
		<pubDate>Wed, 21 Sep 2016 10:29:17 +0000</pubDate>
		<dc:creator><![CDATA[martinus]]></dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=1655</guid>
		<description><![CDATA[Part 1: Hopscotch &#038; Robin Hood Hashing Part 2: Implementation Variants Part 3: Benchmark Results As promised in part 2 of this series, I have some interesting benchmarks of the different hash map variants. In this part I will discuss the results, and present my conclusions. Click any benchmark to get a much larger graph. &#8230; <p class="link-more"><a href="http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-3/" class="more-link">Continue reading<span class="screen-reader-text"> "Very Fast HashMap in C++: Benchmark Results (Part 3)"</span></a></p>]]></description>
				<content:encoded><![CDATA[<ul>
<li><a href="http://martin.ankerl.com/2016/09/15/very-fast-hashmap-in-c-part-1/">Part 1: Hopscotch &#038; Robin Hood Hashing</a></li>
<li><a href="http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-2/">Part 2: Implementation Variants</a></li>
<li><a href="http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-3/">Part 3: Benchmark Results</a></li>
</ul>
<hr />
<p>As promised in <a href="http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-2/">part 2</a> of this series, I have some interesting benchmarks of the different hash map variants. In this part I will discuss the results, and present my conclusions. Click any benchmark to get a much larger graph.</p>
<h1>How I Benchmark</h1>
<p>I&#8217;m inserting 100 million int -> int pairs into different hashmap variants, and every 100000 inserts I am taking measurements (insertion time, memory usage, time to lookup 1 million elements, where half of the lookups fail.). As a hash function I am using <a href="http://en.cppreference.com/w/cpp/utility/hash">std::hash</a>. My computer is an Intel i5-4670 @ 3.4 GHz, 16GB RAM, Visual Studio 2015 Update 3, 64bit.</p>
<h1>Insertion Time Benchmark</h1>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/09/all_big_insertion_time.png"><img src="http://martin.ankerl.com/wp-content/uploads/2016/09/all_insertion_time.png" alt="all_insertion_time" width="600" height="455" class="aligncenter size-full wp-image-1642" srcset="http://martin.ankerl.com/wp-content/uploads/2016/09/all_insertion_time.png 600w, http://martin.ankerl.com/wp-content/uploads/2016/09/all_insertion_time-300x228.png 300w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>In this graph the reallocations are very clearly visible. All variants are doubling the size of the internally used array when it gets full. As expected in <a href="http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-2/">part 2</a>, it can be seen that insertion time slows down when &#8220;Robin Hood with Infobyte&#8221; gets full, and also when &#8220;Robin Hood with Infobyte &#038; Fastforward&#8221; gets full. This is due to the fact that more and more data needs to be moved around so the hashmap can stay sorted.</p>
<p>Dealing with the fastforward field has a clear overhead associated with it, insertion is quite a bit slower.</p>
<p>For &#8220;Robin Hood with Infobits and Hashbit&#8221;, insertion time is very fast: mostly because the offset is limited to 16, if it would get larger the hashmap&#8217;s size is doubled. Hopscotch insertion is almost as fast, just a tad slower.</p>
<p>All variants are <em>much </em>faster than std::unordered_map. The comparison is a bit unfair, because in my implementations I do not have to support the same interface as std::unordered_map does.</p>
<h2>Memory Usage</h2>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/09/all_big_memory.png"><img src="http://martin.ankerl.com/wp-content/uploads/2016/09/all_memory.png" alt="all_memory" width="600" height="455" class="aligncenter size-full wp-image-1648" srcset="http://martin.ankerl.com/wp-content/uploads/2016/09/all_memory.png 600w, http://martin.ankerl.com/wp-content/uploads/2016/09/all_memory-300x228.png 300w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>Robin Hood with Infobyte is the most compact representation. I am resizing the map when it gets 95% full, or when an overflow occurs which is highly unlikely when using an appropriate hash function. There is just 1 byte overhead for each entry.</p>
<p>The second best representation is &#8220;Robin Hood with Infobyte &#038; Fastforward&#8221;. This has exactly the same reallocation properties as when just using the infobyte, but it uses one additional byte per bucket.</p>
<p>When limiting the maximum offset as in &#8220;Robin Hood with Infobits &#038; Hashbits&#8221;, resizes are occuring much quicker (maximum offset is 15 instead of 127), so the memory usage jumps up earlier.</p>
<p>For Hopscotch this reallocation seems to happen still a bit earlier. The overhead in my implementation is 16 bit, so the line overlaps a lot with the Infobyte &#038; Fastforward variant.</p>
<p>All my implemented variants need much less memory than std::unordered_map. While std&#8217;s implementation allocates new memory for each insert, in all my variants the memory stays constant until reallocation occurs.</p>
<h2>Lookup Time</h2>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/09/all_big_lookup_time.png"><img src="http://martin.ankerl.com/wp-content/uploads/2016/09/all_lookup_time.png" alt="all_lookup_time" width="600" height="455" class="aligncenter size-full wp-image-1646" srcset="http://martin.ankerl.com/wp-content/uploads/2016/09/all_lookup_time.png 600w, http://martin.ankerl.com/wp-content/uploads/2016/09/all_lookup_time-300x228.png 300w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>This is probably the most interesting benchmark for most use cases, and I find this graph extremely educational and interesting. </p>
<p>First, the <em>Robin Hood with Infobyte</em> variant: Lookup time starts pretty fast, but it gets slower and slower as the hashmap gets full. This is due to the longer and longer chains that needs to be traversed to find the correct element. So the highly compact format is bought with ever increasing lookup (and insertion) times. Still, lookup is almost always faster than lookup for std::unordered_map.</p>
<p>The <em>Robin Hood with Infobits &#038; Hashbits</em> variant shows the same behaviour, lookup time goes up when the hashmap gets full. This increase is capped early though due to the earlier reallocations. So faster lookup times can be bought with earlier reallocations and more memory usage.</p>
<p>To improve lookup times compared to the infobyte variant, I have introduced the fastforward byte to quickly skip directly to the elements that belong to a bucket. That&#8217;s the gray line. When the hashmap is quite empty it seems that extracting this fastforward information has quite a bit of an overhead. When implementing this variant I did not expect such a large overhead. It seems to work very well though in improving lookup time when the map gets very full, as can be seen around the 60 million elements line. Here, lookup for the variant with just the infobyte takes 0.0676 seconds, and when using fastforward byte it takes 0.0487 seconds, 38% faster. Also the lookup time is quite linear.</p>
<p>Last but not least, the Hopscotch variant. After spending quite some time tuning, this variant turned out as the fastest of all. Lookup time does not have the spiky behaviour that robin hood has, and it is extremly fast. One trick I am using is that I using that I didn&#8217;t see anywhere else mentioned, is that I shift the whole hop field and can stop the while loop as soon as the hop field is zero. So when only one element is there and it is in the first bucket, I need to check just one bit of the hopfield. When the element is <strong>not</strong> there, hopfield is zero so no bits have to be checked at all.</p>
<h1>Summary</h1>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/09/summary_big.png"><img src="http://martin.ankerl.com/wp-content/uploads/2016/09/summary.png" alt="summary" width="600" height="455" class="aligncenter size-full wp-image-1661" srcset="http://martin.ankerl.com/wp-content/uploads/2016/09/summary.png 600w, http://martin.ankerl.com/wp-content/uploads/2016/09/summary-300x228.png 300w" sizes="(max-width: 600px) 100vw, 600px" /></a><br />
I&#8217;ve summed up the average insertion time, average lookup time, and average memory usage over all the different samples. std::unordered_map is the reference with 100%. Here are my conclusions:</p>
<ul>
<li>The HopScotch implementation is the best overall for most use cases, if you have a reasonable hash function. Insertion time is just a tad slower than the fastest variant, memory usage is a bit higher than the other variants but still almost 3 times better than std::unordered_map, and lookup is blazingly fast with almost twice the speed as unordered_map. 0.0404 seconds to look up 1 million elements, or just 40.4 nanoseconds per lookup on average is not too shabby.
<li>If your hash function is bad or compactness is of utmost importance, use the <em>Robin Hood with Infobyte</em> variant.
<li>If the std interface is important, stick to std::unordered_map. While it uses lots of memory, lookup times seem to be ok and fairly consistent.
</ul>
<p>That&#8217;s my tour of hashtable implementations. You can find my code on Github at <a href="https://github.com/martinus/robin-hood-hashing">martinus/robin-hood-hashing</a>. It still needs lots of cleanup, and most importantly, the ability to remove elements&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-3/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Very Fast HashMap in C++: Implementation Variants (Part 2)</title>
		<link>http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-2/</link>
		<comments>http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-2/#respond</comments>
		<pubDate>Wed, 21 Sep 2016 09:00:58 +0000</pubDate>
		<dc:creator><![CDATA[martinus]]></dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=1624</guid>
		<description><![CDATA[Part 1: Hopscotch &#038; Robin Hood Hashing Part 2: Implementation Variants Part 3: Benchmark Results In part 1 I have discussed Hopscotch and Robin Hood Hashing table. Since then I have implemented several hashmap variants that combine some tricks from these two variants, and have some interesting results to share. Here are the variations that &#8230; <p class="link-more"><a href="http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-2/" class="more-link">Continue reading<span class="screen-reader-text"> "Very Fast HashMap in C++: Implementation Variants (Part 2)"</span></a></p>]]></description>
				<content:encoded><![CDATA[<ul>
<li><a href="http://martin.ankerl.com/2016/09/15/very-fast-hashmap-in-c-part-1/">Part 1: Hopscotch &#038; Robin Hood Hashing</a></li>
<li><a href="http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-2/">Part 2: Implementation Variants</a></li>
<li><a href="http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-3/">Part 3: Benchmark Results</a></li>
</ul>
<hr />
<p>In <a href="http://martin.ankerl.com/2016/09/15/very-fast-hashmap-in-c-part-1/">part 1</a> I have discussed <a href="https://en.wikipedia.org/wiki/Hopscotch_hashing">Hopscotch </a>and <a href="http://codecapsule.com/2013/11/11/robin-hood-hashing/">Robin Hood Hashing</a> table. Since then I have implemented several hashmap variants that combine some tricks from these two variants, and have some interesting results to share. Here are the variations that I have implemented:</p>
<h1>Robin Hood with Infobyte</h1>
<p>Robin Hood Hashing uses the hash value to calculate the position to place it, than does linear probing until it finds an empty spot to place it. While doing so it swaps out entries that have a lesser distance to its original bucket. This minimizes the maximum time a lookup takes. For a lookup, it is only necessary to lineary probe until the distance to the original bucket is larger than the current element&#8217;s distance.</p>
<p>In this &#8220;Infobyte&#8221; implementation variant, instead of storing the full 64 bit hash value I directly store the distance to the original bucket in a byte. One bit of this byte is used to mark the bucket as taken or empty. The bit layout is defined like this:</p>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/09/infobyte.png"><img src="http://martin.ankerl.com/wp-content/uploads/2016/09/infobyte.png" alt="infobyte" width="308" height="99" class="aligncenter size-full wp-image-1626" srcset="http://martin.ankerl.com/wp-content/uploads/2016/09/infobyte.png 308w, http://martin.ankerl.com/wp-content/uploads/2016/09/infobyte-300x96.png 300w" sizes="(max-width: 308px) 100vw, 308px" /></a></p>
<p>When storing four elements a, b, c, d, where a, b map to hash position 1 and c, d to hash position 2, this is how they would be stored:</p>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/09/infobyte_layout.png"><img src="http://martin.ankerl.com/wp-content/uploads/2016/09/infobyte_layout.png" alt="infobyte_layout" width="499" height="174" class="aligncenter size-full wp-image-1636" srcset="http://martin.ankerl.com/wp-content/uploads/2016/09/infobyte_layout.png 499w, http://martin.ankerl.com/wp-content/uploads/2016/09/infobyte_layout-300x105.png 300w" sizes="(max-width: 499px) 100vw, 499px" /></a></p>
<p>The advantage is that I have just 1 byte instead of 8 overhead, and linear probing is faster because I need only comparison operation on a single byte instead of calculating offsets with the hash. A byte is more than enough for the offset, since on average the distance to the the original bucket is very small. Here is the full code for lookup:</p>
<p></p><pre class="crayon-plain-tag">const Val* find(const Key&amp; key) const {
    size_t idx = _hash(key) &amp; _mask;
 
    // IS_BUCKET_TAKEN_MASK is 128 (1000 0000 in binary)
    std::uint8_t info = Traits::IS_BUCKET_TAKEN_MASK;
    while (info &lt; _info[idx]) {
        ++idx;
        ++info;
    }

    // check while info matches with the source idx
    while (info == _info[idx]) {
        if (key == _keys[idx]) {
            return _vals + idx;
        }
        ++idx;
        ++info;
    }

    // nothing found!
    return nullptr;
}</pre><p> </p>
<p>This search is very simple and straightforward, and fast.</p>
<h1>Robin Hood with Infobits &#038; Hashbits</h1>
<p>Using a full byte for the offset (actually 7 bit) is fairly large. This would allow an offset of 127, which would lead to a very long and slow linear probing. My idea then is to limit the offset to a much lower maximum number. The remaining bits of the byte can be used to store a few bits from the hash, so that we can use these few bits to reduce the number of key comparisons. Also these hashbits could be used when resizing the hashmap so we would not have to rehash all elements each time we resize. After some tuning, this is the bit layout I am using for this variant:</p>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/09/infobyte_hashbits.png"><img src="http://martin.ankerl.com/wp-content/uploads/2016/09/infobyte_hashbits.png" alt="infobyte_hashbits" width="300" height="98" class="aligncenter size-full wp-image-1630" /></a></p>
<p>The much smaller offset means that when inserting an element and the maximum offset is reached, I have to resize the hashmap. This is intentional, since very large offset would lead to slow searches. This way this hashing variant is more similar to Hopscotch. Here is the full code to lookup an element with this byte:</p>
<p></p><pre class="crayon-plain-tag">const Val* find(const Key&amp; key) const {
    auto h = _hash(key);

    // create info field: offset is bucket is taken, offset is 0, with hash info.
    std::uint8_t info = Traits::IS_BUCKET_TAKEN_MASK | ((h &gt;&gt; _level_shift) &amp; Traits::HASH_MASK);

    // calculate array position
    size_t idx = h &amp; _mask;

    // find info field
    while (info &lt; _info[idx]) {
        ++idx;
        info += Traits::OFFSET_INC;
    }

    // check while it seems we have the correct element
    while (info == _info[idx]) {
        if (key == _keys[idx]) {
            return _vals + idx;
        }
        ++idx;
        info += Traits::OFFSET_INC;
    }

    return nullptr;
}</pre><p> </p>
<p>The find code is almost exactly like in the pure Infobyte variant, except that I am or&#8217;ing 3 hash bits into the info byte, and instead of  <pre class="crayon-plain-tag">++info</pre> I am using  <pre class="crayon-plain-tag">info += Traits::OFFSET_INC</pre> where OFFSET_INC is 16 (1000b).</p>
<h1>Robin Hood with Infobyte &#038; Fastforward</h1>
<p>In the first variant of Robin Hood Hashing finding an element will be slow as the hashmap gets full, because a lot of elements need to be skipped before finding the full one. Robin hood hashing has the property that it always keeps elements that belong to the same bucket together. The infobyte introduced in the first variant basically acts as a backpointer to the bucket that element originally belongs to, and it is possible to introduce another byte that is stored at the original bucket, that acts as a forward pointer to where the first element is stored for this original bucket. </p>
<p>Using the above example where a,b maps to 1 and c,d to 2, fastforward byte looks like this:</p>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/09/infobyte_fastforward.png"><img src="http://martin.ankerl.com/wp-content/uploads/2016/09/infobyte_fastforward.png" alt="infobyte_fastforward" width="488" height="190" class="aligncenter size-full wp-image-1638" srcset="http://martin.ankerl.com/wp-content/uploads/2016/09/infobyte_fastforward.png 488w, http://martin.ankerl.com/wp-content/uploads/2016/09/infobyte_fastforward-300x117.png 300w" sizes="(max-width: 488px) 100vw, 488px" /></a></p>
<p>When looking up element c, the fastforward byte can be used to skip one element, so the  <pre class="crayon-plain-tag">while (info &lt; _info[idx]) { ... }</pre> can be replaced with the skip operation. Here is the code:</p>
<p></p><pre class="crayon-plain-tag">const Val* find(const Key&amp; key) const {
    size_t idx = _hash(key) &amp; _mask;

    const auto ff = _info[idx].fastforward;
    std::uint8_t info = Traits::IS_BUCKET_TAKEN_MASK | ff;
    idx += ff;

    // check while info matches with the source idx
    while (info == _info[idx].info) {
        if (key == _keys[idx]) {
            return _vals + idx;
        }
        ++idx;
        ++info;
    }

    // nothing found!
    return nullptr;
}</pre><p> </p>
<p>I am using a struct that contains two bytes: info field, and fastforward. Now I have two bytes overhead for each entry, but can quickly skip lots of buckets which should be especially useful when the hashmap is very full.</p>
<h1>Hopscotch</h1>
<p>Hopscotch can be seen as quite similar to the robin hood hashing with fastforward, except that it replaces the info and fastforward byte with a bitmask. With some tuning I am now using a 16 bit field, where 1 bit is used to define if the current bucket is full, and the other bits define which offsets to the current bucket are taken.</p>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/09/hopscotch_mask.png"><img src="http://martin.ankerl.com/wp-content/uploads/2016/09/hopscotch_mask.png" alt="hopscotch_mask" width="551" height="96" class="aligncenter size-full wp-image-1639" srcset="http://martin.ankerl.com/wp-content/uploads/2016/09/hopscotch_mask.png 551w, http://martin.ankerl.com/wp-content/uploads/2016/09/hopscotch_mask-300x52.png 300w" sizes="(max-width: 551px) 100vw, 551px" /></a></p>
<p>If the first bit is set, the current bucket is taken; but not nessarily by the bucket from this hop bitfield. This bit is not strictly necessary because that information is also encoded in the different hop tables, but it speeds up insertion code. With 16 bits available, this limits the hop bits to 15 though. As with &#8220;Robin Hood Hashing with Infobits &#038; Hashbits&#8221;, when the hop bits are full, the hashmap has to be resized. </p>
<h1>Benchmark Results</h2>
<p>I&#8217;m leaving the most important information for part 3: how do all these variant perform? What&#8217;s best?</p>
]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Very Fast HashMap in C++: Hopscotch &#038; Robin Hood Hashing (Part 1)</title>
		<link>http://martin.ankerl.com/2016/09/15/very-fast-hashmap-in-c-part-1/</link>
		<comments>http://martin.ankerl.com/2016/09/15/very-fast-hashmap-in-c-part-1/#respond</comments>
		<pubDate>Thu, 15 Sep 2016 06:32:39 +0000</pubDate>
		<dc:creator><![CDATA[martinus]]></dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=1581</guid>
		<description><![CDATA[Part 1: Hopscotch &#038; Robin Hood Hashing Part 2: Implementation Variants Part 3: Benchmark Results A while ago I&#8217;ve spent significant time researching and implementing a fast Hopscotch hash table for C++. My current source code can be found in my github repository at martinus/robin-hood-hashing. After spending some time optimizing, I am mostly happy with &#8230; <p class="link-more"><a href="http://martin.ankerl.com/2016/09/15/very-fast-hashmap-in-c-part-1/" class="more-link">Continue reading<span class="screen-reader-text"> "Very Fast HashMap in C++: Hopscotch &#038; Robin Hood Hashing (Part 1)"</span></a></p>]]></description>
				<content:encoded><![CDATA[<ul>
<li><a href="http://martin.ankerl.com/2016/09/15/very-fast-hashmap-in-c-part-1/">Part 1: Hopscotch &#038; Robin Hood Hashing</a></li>
<li><a href="http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-2/">Part 2: Implementation Variants</a></li>
<li><a href="http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-3/">Part 3: Benchmark Results</a></li>
</ul>
<hr />
<p>A while ago I&#8217;ve spent significant time researching and implementing a fast <a href="https://en.wikipedia.org/wiki/Hopscotch_hashing">Hopscotch</a> hash table for C++. My current source code can be found in my github repository at <a href="https://github.com/martinus/robin-hood-hashing">martinus/robin-hood-hashing</a>. After spending some time optimizing, I am mostly happy with the results. Insertion time is much faster than <a href="http://en.cppreference.com/w/cpp/container/unordered_map">std::unordered_map</a> and it uses far less memory.</p>
<h1>Benchmarks</h1>
<p>In this simple benchmark I have measured time while sequentially adding an entry (int -&gt; int) to the hashmap, similar to <a href="http://incise.org/hash-table-benchmarks.html">incise.org&#8217;s benchmark</a>. As a hash function, I am using <a href="http://en.cppreference.com/w/cpp/utility/hash">std::hash</a>:</p>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/09/hopscotch_std_time.png"><img class="aligncenter size-full wp-image-1589" src="http://martin.ankerl.com/wp-content/uploads/2016/09/hopscotch_std_time.png" alt="hopscotch_std_time" width="600" height="455" srcset="http://martin.ankerl.com/wp-content/uploads/2016/09/hopscotch_std_time.png 600w, http://martin.ankerl.com/wp-content/uploads/2016/09/hopscotch_std_time-300x228.png 300w" sizes="(max-width: 600px) 100vw, 600px" /></a><br />
Whenever a jump occurs, the hashmap got too full and it is reallocating. Interestingly, std::unordered_map has to allocate memory whenever it inserts an element (since it&#8217;s a linked list), while the Hopscotch hash table only allocates once and uses that memory.</p>
<p><a href="http://martin.ankerl.com/wp-content/uploads/2016/09/hopscotch_std_mem.png"><img class="aligncenter size-full wp-image-1588" src="http://martin.ankerl.com/wp-content/uploads/2016/09/hopscotch_std_mem.png" alt="hopscotch_std_mem" width="600" height="455" /></a></p>
<p>I am using Visual Studio 2015 Update 3, 64 bit, Intel i5-4670 @ 3.4GHZ. Here is a comparison table (best values <strong>bold</strong>)</p>
<table>
<tr>
<th>Hashtable</th>
<th>Time insert 30M integers</th>
<th>Memory insert 30M integers</th>
<th>Time query 30M existing</th>
<th>Time query 30M nonexisting</th>
</tr>
<tr>
<th>unordered_map</th>
<td>11.56 sec (100%)</td>
<td>1493 MB (100%)</td>
<td>1.84 sec (100%)</td>
<td>1.92 sec (100%)</td>
</tr>
<tr>
<th>Hopscotch</th>
<td><strong>3.44 sec (30%)</strong></td>
<td><strong>321 MB (22%)</strong></td>
<td><strong>1.50 sec (81%)</strong></td>
<td><strong>1.48 sec (77%)</strong></td>
</tr>
</table>
<p>Insertion is really fast and much more efficient, query time is also a bit faster than std::unordered_map, even though we need to check the hop bitmap of 32 elements.</p>
<h1>Robin Hood Hashing vs. Hopscotch</h1>
<p>After contemplating a while, I have come to the conclusion that Hopscotch is just a bad version of <a href="http://codecapsule.com/2013/11/11/robin-hood-hashing/">Robin Hood Hashing</a>. Here is my reasoning:</p>
<ol>
<li>Hopscotch&#8217;s bitmap naturally has to be quite sparse. For a perfectly full hashmap, where each bucket contains a corresponding entry, of the 32 hop bits there will be just a single bit that is set to 1. Wikipedia has a <a href="https://en.wikipedia.org/wiki/Hopscotch_hashing">nice representation</a>: <a href="http://martin.ankerl.com/wp-content/uploads/2016/09/Hopscotch-wiki-example.png"><img src="http://martin.ankerl.com/wp-content/uploads/2016/09/Hopscotch-wiki-example.png" alt="hopscotch-wiki-example" width="433" height="376" class="aligncenter size-full wp-image-1602" srcset="http://martin.ankerl.com/wp-content/uploads/2016/09/Hopscotch-wiki-example.png 433w, http://martin.ankerl.com/wp-content/uploads/2016/09/Hopscotch-wiki-example-300x261.png 300w" sizes="(max-width: 433px) 100vw, 433px" /></a></li>
<li>Is there a better way to represent the hop bitmap? On way would be a linked list of offsets. Unfortunately, linked lists are not very cache friendly.</li>
<li>To store the linked list more efficiently, we can put them into an array. How about just storing the offsets next to the buckets? So the above example from a) could be stored like this: <a href="http://martin.ankerl.com/wp-content/uploads/2016/09/hopscotch_as_offsetarray.png"><img src="http://martin.ankerl.com/wp-content/uploads/2016/09/hopscotch_as_offsetarray.png" alt="hopscotch_as_offsetarray" width="473" height="169" class="aligncenter size-full wp-image-1604" srcset="http://martin.ankerl.com/wp-content/uploads/2016/09/hopscotch_as_offsetarray.png 473w, http://martin.ankerl.com/wp-content/uploads/2016/09/hopscotch_as_offsetarray-300x107.png 300w" sizes="(max-width: 473px) 100vw, 473px" /></a><br />
Will this work? Surprisingly, yes! When querying for an element, we just need to sequentially check the offsets. Say we want to check if &#8216;b&#8217; is in the map:</p>
<ol>
<li>We hash &#8216;b&#8217; and get index 6.
<li>The offset at index 6 is 0: That means at index 6 is an element that actually belongs there: It&#8217;s not b, so we have to continue checking.
<li>At index 7 we would expect an offset 1 if it contains an element that was indexed to 6. Since it is taken by something else, it will have a higher value, so we are certain this is not the bucket we are looking for.
<li>At index 8 we expect an offset 2 if it contains an element that was indexed to 6. It is to, so check the value, and bam! We found the element.
</ol>
<p>If we query an element that is not in the map, we just need to check hop size offsets.</p>
<li>All this sounds increasingly similar to Robin Hood Hashing. Once we have the offset, we can use it as clever as robin hood hashing does: It enables us to use the cool &#8220;take from the rich&#8221; algorithm. So now we can ditch the hop size, and just keep swapping elements exactly like robin hood hashing does.<br />
<h1>What now?</h1>
<p>With these insights, I believe I have a great idea to implement a highly efficient variant of the robin hood hash table, that takes some ideas from the hopscotch implementation. In my next post, <a href="http://martin.ankerl.com/2016/09/21/very-fast-hashmap-in-c-part-2/">part 2</a>, I will explain these ideas and (hopefully) have a fantastically fast and memory efficient hash table in my repository.</p>
]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2016/09/15/very-fast-hashmap-in-c-part-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Analyzing Keto Calculator Demographics</title>
		<link>http://martin.ankerl.com/2016/06/06/analyzing-keto-calculator-demographics/</link>
		<comments>http://martin.ankerl.com/2016/06/06/analyzing-keto-calculator-demographics/#respond</comments>
		<pubDate>Mon, 06 Jun 2016 14:36:48 +0000</pubDate>
		<dc:creator><![CDATA[martinus]]></dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=1533</guid>
		<description><![CDATA[Recently my Keto Calculator has grown huge. So big, that in January 2016 alone I&#8217;ve had 222,781 page views. That is a record for my site, and I have no reason to believe that it will slow down anytime soon. In my quest to make all the visitors as happy as possible, I&#8217;ve done quite &#8230; <p class="link-more"><a href="http://martin.ankerl.com/2016/06/06/analyzing-keto-calculator-demographics/" class="more-link">Continue reading<span class="screen-reader-text"> "Analyzing Keto Calculator Demographics"</span></a></p>]]></description>
				<content:encoded><![CDATA[<p>Recently my <a href="http://keto-calculator.ankerl.com">Keto Calculator</a> has grown huge. So big, that in January 2016 alone I&#8217;ve had 222,781 page views. That is a record for my site, and I have no reason to believe that it will slow down anytime soon. In my quest to make all the visitors as happy as possible, I&#8217;ve done quite a bit of analysis of my visitors to find out what I need to do with my homepage. Here is some of the data that I have gathered using <a href="http://www.google.com/analytics/">Google Analytics</a>.</p>
<p>Each graph is color coded: <em style="padding:0.2em;background-color:#068cd7;color:white">blue</em> stands for mobile devices, <em style="padding:0.2em;background-color:#ed561a;color:white">orange</em> for tablets, and <em style="padding:0.2em;background-color:#50b432;color:white">green</em> for desktops.</p>
<h1>Where Do the Users Come From?</h1>
<p>I have created a bar chart showing the total number of sessions for January 2016, sorted by top countries.</p>
<p><img src="http://martin.ankerl.com/wp-content/uploads/2016/02/country.png" alt="country" width="741" height="518" class="aligncenter size-full wp-image-1535" srcset="http://martin.ankerl.com/wp-content/uploads/2016/02/country.png 741w, http://martin.ankerl.com/wp-content/uploads/2016/02/country-300x210.png 300w" sizes="(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px" /> </p>
<p>By far the most visitors come from the US, followed by Canada, UK, and Australia &#8211; all english speaking countries. The first non-english speaking country is Germany, and only with 0.69% of all sessions.</p>
<p>For fast access for the majority of my users, my hosting server should sit in the US. I have recently switched to <a href="https://t1hosting.com/aff.php?aff=49">T1Hosting</a> which is both cheaper and faster than my previous webhoster. Also, they were really fast to respond to my questions. So far I am pretty happy with them!</li>
<p>Translation the calculator is currently not really useful. I am sure that translating it into German would increase the number of users from Germany, but it does not look like the effort would really be worth it. What I have done is add an automatic translation feature to the top of the calculator to provide some usability for non-English speakers. Unfortunately the quality is quite bad.</p>
<p>Almost half of my users come from mobile devices! To be precies, 48.8% mobile, 41.7% desktop, 9.5% tablets. That means it is absolutely essential that the keto calculator works well on mobile and on the desktop. It took me quite a while to make it look good on mobile, and now I&#8217;m happy with the result. I&#8217;ve done most of the testing with <a href="https://developer.chrome.com/devtools">Chrome DevTools</a>, which are absolutely fantastic!</p>
<h1>How Old Are My Visitors?</h1>
<p><img src="http://martin.ankerl.com/wp-content/uploads/2016/02/age.png" alt="age" width="741" height="518" class="aligncenter size-full wp-image-1534" srcset="http://martin.ankerl.com/wp-content/uploads/2016/02/age.png 741w, http://martin.ankerl.com/wp-content/uploads/2016/02/age-300x210.png 300w" sizes="(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px" /></p>
<p>Most visitors are 25-34 years old. I guess that&#8217;s a typical result for a website with nutrition as a topic. Interestingly, the graph does not show any data for younger than 18 year olds. I have updated the calculator with some safety checks so that even when somebody very young tries to use the calculator it will give reasonable advice. If you are under 18, it will show a warning. Under 15 the calculator even refuses to give you any results.</p>
<h1>What Gender Are My Visitors?</h1>
<p><img src="http://martin.ankerl.com/wp-content/uploads/2016/02/gender.png" alt="gender" width="741" height="518" class="aligncenter size-full wp-image-1536" srcset="http://martin.ankerl.com/wp-content/uploads/2016/02/gender.png 741w, http://martin.ankerl.com/wp-content/uploads/2016/02/gender-300x210.png 300w" sizes="(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px" /></p>
<p>There are a lot more female visitors! It seems that females are much more sensitive about nutrition topics. Also, female tend to use more mobile devices.</p>
<p>It would probably help to have some gender specific advise on the keto calculator, especially for women. E.g. breastfeeding comes up from time to time. Unfortunately I know nothing about these topics, so it&#8217;s best to go to the dedicated subreddit <a href="https://www.reddit.com/r/xxketo">/r/xxketo</a> with these kind of questions. </p>
<h1>How Big Are the Screens?</h1>
<p><img src="http://martin.ankerl.com/wp-content/uploads/2016/02/resolution.png" alt="resolution" width="741" height="518" class="aligncenter size-full wp-image-1538" srcset="http://martin.ankerl.com/wp-content/uploads/2016/02/resolution.png 741w, http://martin.ankerl.com/wp-content/uploads/2016/02/resolution-300x210.png 300w" sizes="(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px" /></p>
<p>Lots of visitors use smartphones, and the screen resolutions reflect this. The sizes range from quite narrow with just 360 pixels to quite large with 1440 pixels. I&#8217;ve tuned the layout to be nicely visible on all these ranges. Thanks to <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media">@media</a> it gracefully switches between these layouts and looks quite readable on very wide screens and very small screens.</p>
]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2016/06/06/analyzing-keto-calculator-demographics/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Analytics Experiments is Buggy</title>
		<link>http://martin.ankerl.com/2016/01/22/google-analytics-experiments-is-buggy/</link>
		<comments>http://martin.ankerl.com/2016/01/22/google-analytics-experiments-is-buggy/#respond</comments>
		<pubDate>Fri, 22 Jan 2016 13:34:41 +0000</pubDate>
		<dc:creator><![CDATA[martinus]]></dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=1516</guid>
		<description><![CDATA[Google Analytics has a very interesting nice feature: it is possible to use it for A/B testing, and in a nice client-side way that just uses javascript. I am using this to improve my keto calculator website. An interesting feature is that google uses a multi-armed bandit implementation, which optimizes the A/B split ratio while &#8230; <p class="link-more"><a href="http://martin.ankerl.com/2016/01/22/google-analytics-experiments-is-buggy/" class="more-link">Continue reading<span class="screen-reader-text"> "Google Analytics Experiments is Buggy"</span></a></p>]]></description>
				<content:encoded><![CDATA[<p>Google Analytics has a very interesting nice feature: it is possible to use it for <a href="https://support.google.com/analytics/answer/1745216">A/B testing</A>, and in a nice client-side way that <a href="https://developers.google.com/analytics/solutions/experiments-client-side">just uses javascript</a>. I am using this to improve my <a href="http://keto-calculator.ankerl.com/">keto calculator</a> website. An interesting feature is that google uses a <a href="https://support.google.com/analytics/answer/2844870?hl=en">multi-armed bandit</a> implementation, which optimizes the A/B split ratio while optimizing.</p>
<p>Unfortunately, Google&#8217;s implementation is quite buggy. Here are a few problems that I ran into while testing:</p>
<h2>Inaccurate Number</h2>
<p>While testing, Google Analytics shows a &#8220;Probability of Outperforming Original&#8221;. This number can is often incorrect, and does not match with what is actually used for the homepage A/B split ratio. It seems that the numbers in the Analytics UI is calculated based on data that is only partly up-to date. In reality the probability should is at least 99%, but the UI shows 84.1%. The number is updated about twice a day, and it jumps around wildly even though there is not much change in the relative ratio between A and B test.<br />
<img src="http://martin.ankerl.com/wp-content/uploads/2016/01/analytics.png" alt="analytics" width="975" height="575" class="aligncenter size-full wp-image-1517" srcset="http://martin.ankerl.com/wp-content/uploads/2016/01/analytics.png 975w, http://martin.ankerl.com/wp-content/uploads/2016/01/analytics-300x177.png 300w, http://martin.ankerl.com/wp-content/uploads/2016/01/analytics-768x453.png 768w" sizes="(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px" /></p>
<h2>Incorrect Graphs</h2>
<p>The above graph is sometimes not up to date. It seems that the graph data can be delayed for 1-2 days. Sometimes it shows the current days as no data, even though it&#8217;s already recorded in the &#8220;Adsense&#8221; view.</p>
<p>By the way, when optimizing for Adsense Revenue, it seems that the &#8220;AdSense&#8221; view is much more accurate than the &#8220;Conversions&#8221; view. What really counts is the &#8220;<a href="https://support.google.com/adsense/answer/190515?ctx=as2&#038;rd=1">AdSense eCPM</a>&#8221; value (which by the way should be renamed to RPM).</p>
<h2>Incorrect/Inaccurate Results with Multiple Variants</h2>
<p>I&#8217;ve tried to use the multi-armed bandit to find the optimum variant out of 20 different ones. It seems that this has failed completely. While having a look at the experiments.js file that google integrates, it can be seen that some variants had a probability to be chosen of 0, so they were not at all considered any more. With multi-armed bandit Google usually has a selection probability for each variant that is exactly the probability of it outperforming the original. The javascript file for the above screenshot contains this data:</p>
<p></p><pre class="crayon-plain-tag">&quot;api_version&quot;: &quot;V1&quot;,
&quot;method&quot;: &quot;experiments.get&quot;,
&quot;data&quot;: {
	&quot;kind&quot;: &quot;cx/api#experiment&quot;,
	&quot;id&quot;: &quot;xxxxxxxxxxxxxxxxxxxxxx&quot;,
	&quot;self_link&quot;: &quot;/cx/api/V1/experiments/xxxxxxxxxxxxxxxxxxxxxx&quot;,
	&quot;updated&quot;: &quot;2016-01-22T00:36:33.752Z&quot;,
	&quot;participation&quot;: 1,
	&quot;items&quot;: [{
		&quot;kind&quot;: &quot;cx/api#combination&quot;,
		&quot;id&quot;: &quot;0&quot;,
		&quot;weight&quot;: 0.019,
		&quot;disabled&quot;: false
	}, {
		&quot;kind&quot;: &quot;cx/api#combination&quot;,
		&quot;id&quot;: &quot;1&quot;,
		&quot;weight&quot;: 0.98099999999999998,
		&quot;disabled&quot;: false
	}]
}</pre><p></p>
<p>So even though the screenshot says a 84.1% probability of outperforming, the file has a selection probability of the variant of 98.1% which should be more correct. In my test with 20 variants, about 10 variants had a weight of 0, which means that they were never shown to the user. When I noticed this, I added my own selection code (in 50% of the cases, just randomly present a variation to the user) so that the 0 probability variants have a chance to be actually visible to some users, and while this had some effect on the results, it still seemed that the multi-armed bandit just can not deal with so many variants at the same time. Some variants which are actually very similar got a completely different probability of outperforming the original.</p>
<h2>Verdict</h2>
<p>All in all Google Analytics is really excellent for A/B testing, but has a few quirks that one should be aware of. When A/B testing, a <a href="http://www.evanmiller.org/ab-testing/chi-squared.html">Chi-Square test</a> for comparison is always helpful. E.g. a Chi-Squared test of click through ratio of the above example (ok, it&#8217;s not the same as testing AdSense Revenue like google does, but the difference should be marginal in my case) shows that <a href="http://www.evanmiller.org/ab-testing/chi-squared.html#!150/5415;1268/34916@99">with a confidence level of 99% we can say that the variant is more successful</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2016/01/22/google-analytics-experiments-is-buggy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Body Fat Comparison Pictures</title>
		<link>http://martin.ankerl.com/2016/01/04/body-fat-comparison-pictures/</link>
		<comments>http://martin.ankerl.com/2016/01/04/body-fat-comparison-pictures/#respond</comments>
		<pubDate>Mon, 04 Jan 2016 19:22:52 +0000</pubDate>
		<dc:creator><![CDATA[martinus]]></dc:creator>
				<category><![CDATA[health]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=1406</guid>
		<description><![CDATA[Here is a collection of visual body fat charts. Use these to estimate your personal body fat for the keto calculator. See below for men. Women As you can see, even the same body fat percentag (here twice 15%) can look quite different, depending on your muscles and where the body fat is positioned. The &#8230; <p class="link-more"><a href="http://martin.ankerl.com/2016/01/04/body-fat-comparison-pictures/" class="more-link">Continue reading<span class="screen-reader-text"> "Body Fat Comparison Pictures"</span></a></p>]]></description>
				<content:encoded><![CDATA[<p>Here is a collection of visual body fat charts. Use these to estimate your personal body fat for the <a href="http://keto-calculator.ankerl.com/">keto calculator</a>. See below for <a href="#men">men</a>.</p>
<h1>Women</h1>
<p><img class="size-full wp-image-1428 alignnone" src="http://martin.ankerl.com/wp-content/uploads/2016/01/body-fat-percentage-pictures-female.jpg" alt="body-fat-percentages-female-high" width="477" height="296" srcset="http://martin.ankerl.com/wp-content/uploads/2016/01/body-fat-percentage-pictures-female.jpg 477w, http://martin.ankerl.com/wp-content/uploads/2016/01/body-fat-percentage-pictures-female-300x186.jpg 300w" sizes="(max-width: 477px) 100vw, 477px" /><br />
<img class="size-full wp-image-1430 alignnone" src="http://martin.ankerl.com/wp-content/uploads/2016/01/female-body-fat-percentage-pictures.jpg" alt="low female body fat percentages" width="400" height="273" srcset="http://martin.ankerl.com/wp-content/uploads/2016/01/female-body-fat-percentage-pictures.jpg 400w, http://martin.ankerl.com/wp-content/uploads/2016/01/female-body-fat-percentage-pictures-300x205.jpg 300w" sizes="(max-width: 400px) 100vw, 400px" /><br />
<img class="size-full wp-image-1427 alignleft" src="http://martin.ankerl.com/wp-content/uploads/2016/01/15-percent-body-fat-female1.jpg" alt="15% female body fat comparrison" width="294" height="273" /><br />
<img class="size-full wp-image-1429 alignnone" src="http://martin.ankerl.com/wp-content/uploads/2016/01/female-8-9-percent-body-fat.jpg" alt="female at 8-9 percent body fat" width="183" height="279" /><br />
<img src="http://martin.ankerl.com/wp-content/uploads/2016/01/5GZMP.jpg" alt="5GZMP" width="1446" height="502" class="aligncenter size-full wp-image-1452" srcset="http://martin.ankerl.com/wp-content/uploads/2016/01/5GZMP.jpg 1446w, http://martin.ankerl.com/wp-content/uploads/2016/01/5GZMP-300x104.jpg 300w, http://martin.ankerl.com/wp-content/uploads/2016/01/5GZMP-768x267.jpg 768w, http://martin.ankerl.com/wp-content/uploads/2016/01/5GZMP-1024x355.jpg 1024w, http://martin.ankerl.com/wp-content/uploads/2016/01/5GZMP-1200x417.jpg 1200w" sizes="(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px" /></p>
<p>As you can see, even the same body fat percentag (here twice 15%) can look quite different, depending on your muscles and where the body fat is positioned. The minimum possible body fat percentage is 8-9%. This low is not sustainable, and very unhealthy! If you are female, don&#8217;t go that low.</p>
<p><a name="men"></a></p>
<h1>Men</h1>
<p><img class="alignnone size-full wp-image-1432" src="http://martin.ankerl.com/wp-content/uploads/2016/01/pictures-of-body-fat-percentages.jpg" alt="Men at different body fat levels" width="390" height="241" srcset="http://martin.ankerl.com/wp-content/uploads/2016/01/pictures-of-body-fat-percentages.jpg 390w, http://martin.ankerl.com/wp-content/uploads/2016/01/pictures-of-body-fat-percentages-300x185.jpg 300w" sizes="(max-width: 390px) 100vw, 390px" /></p>
<p><img class="alignnone  size-full wp-image-1431" src="http://martin.ankerl.com/wp-content/uploads/2016/01/male-body-fat-percentages-pictures.jpg" alt="male body fat percentages" width="400" height="234" srcset="http://martin.ankerl.com/wp-content/uploads/2016/01/male-body-fat-percentages-pictures.jpg 400w, http://martin.ankerl.com/wp-content/uploads/2016/01/male-body-fat-percentages-pictures-300x176.jpg 300w" sizes="(max-width: 400px) 100vw, 400px" /></p>
<p><img class="alignleft size-full wp-image-1426" src="http://martin.ankerl.com/wp-content/uploads/2016/01/10-percent-body-fat-male-pictures1.jpg" alt="10-percent-body-fat-male-pictures1" width="338" height="246" srcset="http://martin.ankerl.com/wp-content/uploads/2016/01/10-percent-body-fat-male-pictures1.jpg 338w, http://martin.ankerl.com/wp-content/uploads/2016/01/10-percent-body-fat-male-pictures1-300x218.jpg 300w" sizes="(max-width: 338px) 100vw, 338px" /></p>
<p><img class="alignnone size-full wp-image-1425" src="http://martin.ankerl.com/wp-content/uploads/2016/01/4-percent-body-fat-male.jpg" alt="Picture of a man at 3-4% body fat" width="165" height="254" /><br />
<img src="http://martin.ankerl.com/wp-content/uploads/2016/01/army-body-fat-calculator1.jpg" alt="" width="1418" height="454" class="aligncenter size-full wp-image-1451" srcset="http://martin.ankerl.com/wp-content/uploads/2016/01/army-body-fat-calculator1.jpg 1418w, http://martin.ankerl.com/wp-content/uploads/2016/01/army-body-fat-calculator1-300x96.jpg 300w, http://martin.ankerl.com/wp-content/uploads/2016/01/army-body-fat-calculator1-768x246.jpg 768w, http://martin.ankerl.com/wp-content/uploads/2016/01/army-body-fat-calculator1-1024x328.jpg 1024w, http://martin.ankerl.com/wp-content/uploads/2016/01/army-body-fat-calculator1-1200x384.jpg 1200w" sizes="(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px" /><br />
As above with the female pictures, here are also two images with the same body fat percentage: 10% can look quite different, depending on how muscular you are and where your body fat is positioned. The lowest male can go os 3-4%, but this is not at all healthy at all. It is only possible to reach such low body fat for a very short period of time. I&#8217;d say the lowest you should go to still be healthy is 10%.</p>
<h1>Back to the Keto Calculator</h1>
<p>Now when you have made up your mind where about your body fat percentage might be, head back to the <a href="http://keto-calculator.ankerl.com/">keto calculator</a> and enter your number.</p>
<h1>Sources</h1>
<ul>
<li><a href="http://www.leighpeele.com/body-fat-pictures-and-percentages">Leigh Peele &#8211; Body Fat Pictures and Percentages</a>
<li><a href="http://aibeauty2013.pixnet.net/blog/post/437975866-ai-beauty-%E6%8A%BD%E8%84%82">ai beauty</a>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2016/01/04/body-fat-comparison-pictures/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Beautiful Git Logs</title>
		<link>http://martin.ankerl.com/2015/12/22/beautiful-git-logs/</link>
		<comments>http://martin.ankerl.com/2015/12/22/beautiful-git-logs/#comments</comments>
		<pubDate>Tue, 22 Dec 2015 07:35:55 +0000</pubDate>
		<dc:creator><![CDATA[martinus]]></dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://martin.ankerl.com/?p=1346</guid>
		<description><![CDATA[git has a very configurable logging options. I&#8217;ve played a while with the configuration, and found an awesome alias that looks just beautiful. It only works as of git 1.8.3 (March 24, 2013) because it uses auto coloring. [crayon-59628499f2533779403218/] git l git ls]]></description>
				<content:encoded><![CDATA[<p>git has a very configurable logging options. I&#8217;ve played a while with the configuration, and found an awesome alias that looks just beautiful. It only works as of git 1.8.3 (March 24, 2013) because it uses <tt>auto</tt> coloring.</p>
<p></p><pre class="crayon-plain-tag">git config --global alias.l 'log --graph --pretty=format:&quot;%C(auto)%h%&lt;(3)%d %s %C(bold blue)(%cr, %an)%Creset&quot; --abbrev-commit --all'
git config --global alias.ls 'log --graph --pretty=format:&quot;%C(auto)%h%&lt;(3)%d %s %C(bold blue)(%cr, %an)%Creset%n&quot; --abbrev-commit --all --find-copies -M --stat'</pre><p></p>
<h3>git l</h3>
<p><img src="http://martin.ankerl.com/wp-content/uploads/2015/12/git_l.png" alt="git_l" width="938" height="586" class="aligncenter size-full wp-image-1348" srcset="http://martin.ankerl.com/wp-content/uploads/2015/12/git_l.png 938w, http://martin.ankerl.com/wp-content/uploads/2015/12/git_l-300x187.png 300w, http://martin.ankerl.com/wp-content/uploads/2015/12/git_l-768x480.png 768w" sizes="(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px" /></p>
<h3>git ls</h3>
<p><img src="http://martin.ankerl.com/wp-content/uploads/2015/12/git_ls-1.png" alt="git_ls" width="938" height="586" class="aligncenter size-full wp-image-1352" srcset="http://martin.ankerl.com/wp-content/uploads/2015/12/git_ls-1.png 938w, http://martin.ankerl.com/wp-content/uploads/2015/12/git_ls-1-300x187.png 300w, http://martin.ankerl.com/wp-content/uploads/2015/12/git_ls-1-768x480.png 768w" sizes="(max-width: 706px) 89vw, (max-width: 767px) 82vw, 740px" /></p>
]]></content:encoded>
			<wfw:commentRss>http://martin.ankerl.com/2015/12/22/beautiful-git-logs/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.856 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2017-07-09 21:31:38 -->

<!-- Compression = gzip -->