<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
  <title>Coffee Space reports</title>
  <link>https://coffeespace.org.uk</link>
  <description>A simple personal blogging website</description>
  <item>
    <title>Smart Watch v2</title>
    <link>https://coffeespace.org.uk/projects/smart-watch-v2.html?md5sum=e199b4a67d1bd8bc35b1737b302556eb</link>
    <pubDate>Tue, 13 Jan 2026 00:00:00 +0000</pubDate>
    <enclosure url="https://coffeespace.org.uk/projects/smart-watch-v2.mp3" type="audio/mpeg" length="3121337" />
    <description>
      <![CDATA[
<link rel="stylesheet" type="text/css" href="/style.css" />
<p><img src="smart-watch-v2/hero.png" id="hero" class="hero" /></p>
<section id="smart-watch-v2" class="level2">
<h2>Smart Watch v2</h2>
<figure>
<img src="smart-watch-v2/preview.jpg" alt="Preview Image" />
<figcaption aria-hidden="true">Preview Image</figcaption>
</figure>
<p><em>This article is a continuation from <a
href="smart-watch-v1.html">Smart Watch v1</a>.</em></p>
<p>The following is a non-complete update regarding the changes to the
hardware and firmware.</p>
<section id="hardware" class="level3">
<h3>Hardware</h3>
<p>After realising there was an issue with v1 as highlighted in the
previous article, I made a v2 version. Shortly after submitting this
board, I discovered there was still an issue, hence a v2b version.</p>
<figure>
<img src="smart-watch-v2/three-boards.jpg"
alt="Three different revisions of the PCB" />
<figcaption aria-hidden="true">Three different revisions of the
PCB</figcaption>
</figure>
<p><em>At least I have some PCBs to give away…</em></p>
<p>I finally got v2b in the post, buzzed all the connections
successfully, and decided to solder it. To save some money I didn’t get
a stencil, so I hand-placed solder paste by eye. I then manually
pick-and-placed the surface mount components, and to my surprise - it
all went well!</p>
<figure>
<img src="smart-watch-v2/v3.jpg" alt="Hand-soldered watch v2b" />
<figcaption aria-hidden="true">Hand-soldered watch v2b</figcaption>
</figure>
<p>Once I was able to confirm that the battery charging circuit could
properly charge the battery (by checking the ADC currently sees 4.2V), I
was then able to solder the battery.</p>
<figure>
<img src="smart-watch-v2/v3-battery.jpg"
alt="Carefully soldered LiPo to PCB" />
<figcaption aria-hidden="true">Carefully soldered LiPo to
PCB</figcaption>
</figure>
<p>As you can see, there is very little mass to the battery and it did
not want to sit on the pads during soldering. I resulted to taping the
LiPo to a plastic case (that the OLED display was shipped in). You
obviously can’t tape the battery to the board, because it gets too
hot.</p>
<p>It was at this point, I greatly regretted having such a large ground
plane. My little USB soldering iron could hardly get hot enough to begin
to melt the solder, and as a result the LiPo battery got far hotter than
I was happy with.</p>
<p>During soldering, the watch of course sprung to life, indicating that
it had been done successfully.</p>
</section>
<section id="core-interface" class="level3">
<h3>Core Interface</h3>
<p>The core interface has come along nicely, with several graphics
utilities developed to support it. One is the ability to dump the screen
buffer so that I can produce “screenshots” from the device. These are
stored as <code>P4</code> <code>PBM</code> binary format - an old but
simple format.</p>
<figure>
<img src="smart-watch-v2/clock.png" alt="Clock interface" />
<figcaption aria-hidden="true">Clock interface</figcaption>
</figure>
<p>The main clock interface currently shows the measured battery
percentage (4.2V 100% - 3.2V 0%) - and this works really quite well
given that it is just an ADC reading via a switched ladder.</p>
<p>The time itself is grabbed via the RTC (which survives light and deep
sleep), and is currently pushed via a configuration file when the Python
files are deployed. It appears to keep time pretty well.</p>
<p>Micropython currently only supports 8x8 pixel fonts, which raises the
question: <em>How on earth is there a 16x16 font?</em> We draw the font
to the frame buffer, then perform an integer scaling to the frame
buffer. In theory I could attempt some form of anti-aliasing, but
instead we just embrace the blocky-ness.</p>
<figure>
<img src="smart-watch-v2/icons.png" alt="Icon design" />
<figcaption aria-hidden="true">Icon design</figcaption>
</figure>
<p>Several icons have been prototyped as app icons and icons within
apps. The artificial limitation of 8x8 icons is quite challenging. It is
technically possible to do vector graphics, but it’s a lot of work. The
icons again are <code>P4</code> <code>PBM</code> binary format, as
output by <code>mtPaint</code>.</p>
<figure>
<img src="smart-watch-v2/menu.png" alt="Menu design" />
<figcaption aria-hidden="true">Menu design</figcaption>
</figure>
<p>The menu itself is pretty slick, with the icon directory searched for
a same-name icon to display (scaled up), or the first letter of the app
name being used instead. In the middle of the display is the full name
of the app highlighted to be clear which app is highlighted.</p>
<p>The border around icon is actually a vector graphic and would
technically scale to any resolution display. The icon is pre-computed on
menu app start to prevent too much processing power being wasted - a
common theme in this watch.</p>
</section>
<section id="calculator" class="level3">
<h3>Calculator</h3>
<p>One of the first apps to be developed was the calculator, because it
is simple and shows off the use of Python very well.</p>
<figure>
<img src="smart-watch-v2/calc-1.png" alt="Calculator app equation" />
<figcaption aria-hidden="true">Calculator app equation</figcaption>
</figure>
<p>Normally the implementation of a calculator app that can handle
brackets, etc, is quite a pain. But with Python the values can be easily
evaluated. Very long expressions can be expressed and resolved quickly -
more than good enough for such a lightweight watch. Dare I say it - this
calculator is better than most default calculators in mobile phones.</p>
<figure>
<img src="smart-watch-v2/calc-2.png" alt="Calculator app result" />
<figcaption aria-hidden="true">Calculator app result</figcaption>
</figure>
<p>Beyond the expected functionality, <code>C</code> clears the display
and <code>y</code> writes the previous answer. You could for example do
the following:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dv">67</span> <span class="op">+</span> <span class="dv">1</span> <span class="op">=</span> <span class="co"># 68</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>y <span class="op">+</span> <span class="dv">1</span> <span class="op">=</span> <span class="co"># 69</span></span></code></pre></div>
<p>Being able to leverage the simplicity of Python allowed this app to
be developed in mere hours.</p>
</section>
<section id="power" class="level3">
<h3>Power</h3>
<p>One of the features I wanted to add was a WDT, i.e. a watch-dog
timer. The idea is that if you don’t keep responding to the timer, it
resets the device. In this way, it becomes impossible for an app to
enter into an infinite loop and crash the entire watch.</p>
<p>It turns out though that once started, you are not allowed to stop
the WDT in Micropython, despite it being supported by most modern
micro-controllers. The issue really appears when you enter a light/deep
sleep for a longer period than the WDT, and upon resuming the CPU the
WDT is instantly triggered. This pretty much means that the WDT cannot
be used in low-power applications. There is a <a
href="https://github.com/micropython/micropython/issues/18613">GitHub
issue</a> to hopefully resolve this one day.</p>
<p>Power consumption has been a serious concern, and until now, no
effort had been made to start the WiFi. After doing so, the device
immediately browned out (crashed due to low CPU power). <em>Uh oh.</em>
The problem is that I used a super cheap 300mA 3.3V low voltage drop-out
regulator, and during WiFi initialisation, it exceeds this current draw.
The reason for using such a low value is that it was <em>cheap</em>, at
<a href="https://www.mouser.co.uk/ProductDetail/595-TLV74033PDBVR">just
8p each</a>.</p>
<p>I therefore had to turn the WiFi on <em>carefully</em>. To give you
an idea:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># active()</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Turn the interface on/off carefully to reserve power usage.</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="co"># @param self Reference to self.</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="co"># @param act True to turn on WiFi, otherwise False.</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> active(<span class="va">self</span>, act <span class="op">=</span> <span class="va">True</span>) :</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">not</span> <span class="va">self</span>.wifi.active() <span class="op">==</span> act :</span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>    <span class="va">self</span>.wifi.active(act)</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>  <span class="cf">elif</span> act :</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>    <span class="co"># Test that the interface is *really* working</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>    <span class="cf">try</span> :</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>      rssi <span class="op">=</span> <span class="va">self</span>.wifi.status(<span class="st">&quot;rssi&quot;</span>)</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a>    <span class="cf">except</span> :</span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a>      <span class="co"># Trigger reset of interface</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a>      <span class="va">self</span>.wifi.active(<span class="va">False</span>)</span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a>      <span class="va">self</span>.wifi.active(<span class="va">True</span>)</span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a>  to <span class="op">=</span> time.ticks_ms() <span class="op">+</span> <span class="dv">500</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>  <span class="cf">while</span> time.ticks_ms() <span class="op">&lt;</span> to <span class="kw">and</span> <span class="kw">not</span> <span class="va">self</span>.wifi.active() <span class="op">==</span> act :</span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>    time.sleep_ms(<span class="dv">100</span>)</span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> act :</span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a>    <span class="va">self</span>.wifi.config(</span>
<span id="cb2-23"><a href="#cb2-23" aria-hidden="true" tabindex="-1"></a>      txpower <span class="op">=</span> <span class="dv">10</span>, <span class="co"># 10 dBm</span></span>
<span id="cb2-24"><a href="#cb2-24" aria-hidden="true" tabindex="-1"></a>      pm <span class="op">=</span> network.WLAN.PM_POWERSAVE,</span>
<span id="cb2-25"><a href="#cb2-25" aria-hidden="true" tabindex="-1"></a>    )</span>
<span id="cb2-26"><a href="#cb2-26" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span></span></code></pre></div>
<p>You first have to turn on WiFi to set the power configuration
options, otherwise that part of the controller is simply not away to
listen to the configuration requests. Sometimes it even pretends to be
on, but it’s actually not on, so you have to make sure that it’s not
tricking you. Even then, you still have to wait for the WiFi to actually
become alive and ready to talk.</p>
<p>The real tricks are to put it into a power saving mode
(<code>PM_POWERSAVE</code>) which turns down beacons, etc. You must also
turn down the transmission power from approximately 20dBm to 10dBm,
otherwise it consumes too much power during transmission.</p>
<figure>
<img src="smart-watch-v2/wifi.png" alt="WiFi" />
<figcaption aria-hidden="true">WiFi</figcaption>
</figure>
<p>If you do all of these things, then you can get the WiFi to stay on
reliably and not brown out the entire CPU.</p>
</section>
<section id="future-apps" class="level3">
<h3>Future Apps</h3>
<p>Now that WiFi is working, the really cool stuff can happen. I have
written a <code>http_get()</code> function that opens a socket, grabs
the data within a limited buffer and closes the socket, to any given URL
at any given port.</p>
<p>The intention is to build out a few features:</p>
<ul>
<li>Grab the time from an NTP server</li>
<li>Read weather predictions via a <a
href="https://open-meteo.com/">free API</a></li>
<li>Read RSS feeds</li>
</ul>
<p>In the future, I would then be interested in connecting to a server
that can sync information across devices (i.e. calendar, notes, etc), or
prepare media such as pictures, videos, web searches, wikipedia entries,
etc.</p>
<p>For the most part, I want as many features as possible to operate
correctly without needing the internet. If it’s possible to be done
without the internet, it should be done so.</p>
<p>Some out of the box ideas that I’ve not seen elsewhere:</p>
<ul>
<li>Offline translation for basic things. For example, you could select
the Japanese language, select that you want to find a facility, and
select between items such as a shop, toilet, etc. It then displays the
Japanese characters and you show this to the Japanese person.</li>
<li>Currency conversion. When abroad it can be difficult to figure out
how much things cost in a currency you can understand. The latest
conversion rates can be cached or manually entered. “<em>This thing for
ten thousand yen, is it a good deal or is it going to wipe out the
holiday budget?</em>”</li>
</ul>
</section>
<section id="future-hardware" class="level3">
<h3>Future Hardware</h3>
<p>If I do another spin of the watch, I would consider a few more
features:</p>
<ul>
<li>Buttons need to be side-mounted</li>
<li>A method to detect that the device is charging</li>
<li>Secure display and mount closer</li>
<li>Remove massive ground plane</li>
<li>Simplify reset &amp; boot buttons (maybe a single button or
temporary bridge)</li>
<li>Smaller download header (pins 2, 3, and 6 currently not
connected)</li>
</ul>
<p>Some nice to haves:</p>
<ul>
<li>IMU - would be nice for waking with arm up gesture, even better with
a magnetic compass</li>
<li>GPS - no idea how this would be powered or fitted</li>
<li>Microphone - allow the user to interact with the device via
audio</li>
<li>Speaker - play sounds to the user, uses a lot of power</li>
<li>Vibrator - notify the user, uses a lot of power</li>
</ul>
<iframe src="https://coffeespace.org.uk/dead/tag/watch/embed">
</iframe>
</section>
</section>
      ]]>
    </description>
  </item>
  <item>
    <title>Smart Watch v1</title>
    <link>https://coffeespace.org.uk/projects/smart-watch-v1.html?md5sum=614124a7a87a93b2e9b7bb11d8522b47</link>
    <pubDate>Sat, 29 Nov 2025 00:00:00 +0000</pubDate>
    <enclosure url="https://coffeespace.org.uk/projects/smart-watch-v1.mp3" type="audio/mpeg" length="7228962" />
    <description>
      <![CDATA[
<link rel="stylesheet" type="text/css" href="/style.css" />
<p><img src="smart-watch-v1/hero.png" id="hero" class="hero" /></p>
<section id="smart-watch-v1" class="level2">
<h2>Smart Watch v1</h2>
<figure>
<img src="smart-watch-v1/preview.jpg" alt="Preview Image" />
<figcaption aria-hidden="true">Preview Image</figcaption>
</figure>
<p>For a long time now, I have been interested in devices to be used for
personal organisation. Mobile phones contain too much distraction and
are an attention drain, one minute you are checking an email, the next
hour you just doom scrolled 30 second videos. It’s just insane.</p>
<p>What I want is a device that is limited by design to productivity, is
simple and can be built/hacked as features are needed. To be useful as a
productivity device, it needs to be able to connect to systems outside
of itself easily.</p>
<p>Additionally, I want to re-use the developed circuits elsewhere.</p>
<section id="problem" class="level3">
<h3>Problem</h3>
<p>The overall problem that we are trying to solve is the following:</p>
<p><em>A small productivity watch that is internet connected, to perform
a series of lightweight tasks that are synced with other devices via the
internet.</em></p>
<p>Examples of tasks of interest:</p>
<ul>
<li>Display the time and date, manually override these and set/display
different time zones.</li>
<li>Connect to a WiFi router with an SSID/password.</li>
<li>Synced capabilities:
<ul>
<li>Set multiple alerts throughout the day, that are synced to other
devices.</li>
<li>Check a series of RSS feeds, which can also be synced. I.e. to check
the latest news.</li>
<li>Check synced notes.</li>
<li>Check tasks and set as completed.</li>
<li>Check a simple calendar.</li>
</ul></li>
<li>Local capabilities:
<ul>
<li>Unit conversions.</li>
<li>Currency conversions (with latest conversions from online
sources).</li>
<li>Calculator.</li>
<li>Meeting calculator with multiple time zones.</li>
<li>QR code/barcode/image viewer (useful for scanning into events for
example).</li>
</ul></li>
</ul>
<p>Maybe I can think of other things, but I think these are already
useful services!</p>
<p>I have used some other devices…</p>
<section id="pinetime" class="level4">
<h4>Pinetime</h4>
<p>For over a year I was using the <a
href="https://pine64.org/devices/pinetime/">Pinetime</a>, based on
JF002’s <a
href="https://github.com/InfiniTimeOrg/InfiniTime">InfiniTime</a>
software.</p>
<p>The hardware is pretty good, but lacks WiFi. The only way to have
this device communicating with the outside world is to connect to
another device via Bluetooth, which limits the usefulness of the
device.</p>
<p>The software is interesting, but it is all baked into a large
mono-repo. I have nothing against this idea, but there is no real clean
idea of what an app is, and what the OS is. Probably one of the biggest
sins is that if you accidentally flash a bad firmware, it is possible to
brick your device.</p>
<p>Probably the most promising way forwards is <a
href="https://github.com/wasp-os/wasp-os">wasp-os</a> which is based on
micropython, but the hardware still suffers the same issue of
connectivity.</p>
</section>
<section id="t-watch-s3" class="level4">
<h4>T-Watch S3</h4>
<p>I am working with the <a
href="https://lilygo.cc/products/t-watch-s3">T-Watch S3</a> for another
project in micropython. The only real complaint with the device is the
cost and the watch strap (I have quite sensitive skin).</p>
<p>One possible issue is that the device offers too much, to say that it
would be possible to have chats on it and do mobile-phone-esque tasks
with it.</p>
</section>
</section>
<section id="proposal" class="level3">
<h3>Proposal</h3>
<p><em>Now for the chosen parts…</em></p>
<section id="parts" class="level4">
<h4>Parts</h4>
<p>The main controller chosen is the ESP32-S3-WROOM-1. It runs <a
href="https://micropython.org/">micropython</a> quite well from previous
experience.</p>
<figure>
<img src="smart-watch-v1/esp32.png"
alt="ESP32 S3 WROOM 1/2, source: https://www.atomic14.com/2023/11/21/esp32-s3-pins" />
<figcaption aria-hidden="true">ESP32 S3 WROOM 1/2, source: <a
href="https://www.atomic14.com/2023/11/21/esp32-s3-pins"
class="uri">https://www.atomic14.com/2023/11/21/esp32-s3-pins</a></figcaption>
</figure>
<p>The battery is <a
href="https://www.aliexpress.com/item/1005008747431465.html">30mAh
401012</a> (dimensions: 4mm x 10mm x 12mm). Assuming a total on time of
30 seconds per hour at 300mAh, and assuming the system is in a <a
href="https://randomnerdtutorials.com/esp32-deep-sleep-arduino-ide-wake-up-sources/">light
sleep or lower</a> with <a
href="https://lastminuteengineers.com/esp32-sleep-modes-power-consumption/">~1mAh
draw</a>, we can expect the system to run on a full charge for:</p>
<pre class="python-exec"><code>batt_mAh = 30
on_mAh = 260 # WiFi average peaks
off_mAh = 1
on_ratio = 0.5 / 60 # minutes per hour
usage_mAh = (on_ratio * on_mAh) + ((1 - on_ratio) * off_mAh)

hours = batt_mAh / usage_mAh
print(&quot;Expected usage of &quot; + str(hours) + &quot; hours&quot;)</code></pre>
<p>Then we are just touching on a 10 hour operating time.</p>
<p>The ADC IC is the <a
href="https://www.mouser.co.uk/ProductDetail/Microchip-Technology/MCP3021A7T-E-OT?qs=uHi2%2FQoPa5BNPERfVO0C4g%3D%3D">MCP3021A7T-E/OT</a>
which takes a supply between 2.7V and 5.5V, and can read within the same
range. <em>Foreshadowing: It is not not be.</em></p>
<p>The voltage regulator is the <a
href="https://www.mouser.co.uk/ProductDetail/Texas-Instruments/TLV74033PDBVR?qs=sPbYRqrBIVkaG2WMvPh1eg%3D%3D">TLV74033PDBVR</a>,
chosen because it is just 8 pence. It’ll take an input between 1.4V and
5.5V and produce a 3.3V voltage. It will output 300mA, which exactly
matches the expected spike current from the ESP32 during WiFi. There is
no <em>absolute maximum</em> current <a
href="https://www.ti.com/lit/ds/symlink/tlv740p.pdf">specified</a>, so I
assume we can maybe push the envelope slightly.</p>
<p>Otherwise the next highest current eating device is the 0.96” OLED
display with the SSD1306 driver, requiring ~20mA of power at maximum
contrast. Everything else is sipping power.</p>
<p>The chosen battery charging circuit is the <a
href="https://www.mouser.co.uk/ProductDetail/Microchip-Technology/MCP3021A7T-E-OT?qs=uHi2%2FQoPa5BNPERfVO0C4g%3D%3D">MCP73812T-420I/OT</a>,
which should charge a single cell LiPo at 50mA when the USB supply is
provided. It has constant voltage, constant current, thermal regulation,
etc.</p>
</section>
</section>
<section id="implementation" class="level3">
<h3>Implementation</h3>
<p>The first thing to notice is that it is a two-layer board and
everything is mounted single-side. This means that it can be
manufactured simply on a hot plate. The width and depth ~4cm x ~4cm, and
the height will likely be defined by the top of the OLED to the bottom
of the soldered through-hole headers. Offering the OLED to an existing
board shows a height ~17mm. The battery <em>should</em> fit nicely under
the display.</p>
<p>As you can see, I have chosen a ESP32 module and not the chip, so it
is certified and could be sold. The ESP32 module does take up the
majority of the design, though.</p>
<p>The only traces that were manually routed were the USB differential
pair, and if you look closely, there is a length matching wiggle near
the USB socket. It should be close enough for basic USB 2
communications.</p>
<figure>
<img src="smart-watch-v1/pcb_render_traces.png"
alt="KiCAD component placement &amp; traces" />
<figcaption aria-hidden="true">KiCAD component placement &amp;
traces</figcaption>
</figure>
<p>As you can see in the 3D render, there are clear cut-outs for a watch
strap. I look to further reinforce this with the 3D printed chassis. The
chassis is expected to attach as a “press fit” to secure it in
place.</p>
<p>Soldering will need to start with the surface mount components, then
the through-hole components, then finally the LiPo. The LiPo will be a
pain, but time will need to be taken to ensure it is not directly
touched by heat.</p>
<figure>
<img src="smart-watch-v1/pcb_render_front.png"
alt="KiCAD 3D render front" />
<figcaption aria-hidden="true">KiCAD 3D render front</figcaption>
</figure>
<figure>
<img src="smart-watch-v1/pcb_render_rear.png"
alt="KiCAD 3D render rear" />
<figcaption aria-hidden="true">KiCAD 3D render rear</figcaption>
</figure>
</section>
<section id="manufacturing" class="level3">
<h3>Manufacturing</h3>
<p>The PCB is sent for manufacturing, and I got quite a good deal on it.
Five PCBs for $2, $1.50 shipping charge from China, $0.70 tax, for a
total of $4.20. It’ll take a little while to arrive, but everything
does.</p>
<p>The real downside is that I didn’t get a stencil. I’m thinking that I
could probably cut one out on the vinyl cutter, or make a cardboard
single-use stencil.</p>
<figure>
<img src="smart-watch-v1/pcb_order.png" alt="JLPCB order for the PCB" />
<figcaption aria-hidden="true">JLPCB order for the PCB</figcaption>
</figure>
<figure>
<img src="smart-watch-v1/parts_order.png"
alt="Components order for the ICs" />
<figcaption aria-hidden="true">Components order for the ICs</figcaption>
</figure>
<figure>
<img src="smart-watch-v1/strap_order.png"
alt="Amazon order for the strap" />
<figcaption aria-hidden="true">Amazon order for the strap</figcaption>
</figure>
</section>
<section id="llm-review" class="level3">
<h3>LLM Review</h3>
<p>I was <em>surfing</em> the <em>World Wide Web</em> as I sometimes do,
and I came across an <a href="https://netlist.io">LLM netlist checking
tool</a>. I plugged in the datasheets for the ICs I use, and gave the
following prompt:</p>
<blockquote>
<p>“It is a small ESP32 based smart watch with two input buttons, and an
OLED display via I2C. There is a battery charge circuit for a single
cell LiPo, a voltage I2C ADC to monitor battery voltage, and a 3V3
voltage regulator for the ICs.”</p>
</blockquote>
<p>I wasn’t expecting much, I had already sent the board off to be
manufactured. But after a few minutes, it generated this:</p>
<blockquote>
<blockquote>
<p><strong>Overview</strong></p>
<p>Key blockers before layout: the Li-ion charger is effectively
unpowered, the 3.3 V rail lacks both the correct regulator variant and
the minimum capacitors, and the battery monitor will overdrive its ADC
input. Details by subsystem follow.</p>
<p><strong>1. Power-input &amp; Li-ion charging (U2 MCP73812, J1 USB-C,
J4 battery)</strong></p>
<ul>
<li><strong>Charger supply/enable not wired:</strong> Pins VIN (pin 4)
and CE (pin 1) of the MCP73812 share net N$11, but N$11 never reaches
the USB 5 V rail, so the IC never powers up and CE never sees the
required logic high. Tie both pins to the 5 V source and keep CE
accessible if you plan to gate charging.[^mcp-pin]</li>
<li><strong>Mandatory capacitors missing:</strong> The charger needs
≥1 µF from VDD to GND and ≥1 µF from VBAT to GND for
stability.[^mcp-cap] Add them close to the IC.</li>
<li><strong>Charge current check:</strong> R7 = 2 kΩ programs ≈500 mA
fast-charge current.[^mcp-rprog] Confirm the USB source, battery, and
PCB traces can safely handle that.</li>
<li><strong>Battery connector:</strong> Nothing obviously wrong; just
ensure pack protection/NTC (external) is addressed elsewhere.</li>
</ul>
<p><strong>2. 3.3 V regulation (U1 TLV7xx, 3v3 net)</strong></p>
<ul>
<li><strong>MPN/value mismatch:</strong> Net 3v3 relies on U1, but the
value is TLV70012 (1.2 V output). Verify the intended part; if you need
3.3 V pick TLV70033/TLV74033 etc.</li>
<li><strong>Input/output caps missing:</strong> TLV74x devices require
at least one 1 µF ceramic on VIN and one on VOUT located close to the
pins for stability and transient response.[^tlv-cap] Add them.</li>
<li><strong>VIN source:</strong> Once U2 is fixed, route USB 5 V (or
battery when USB absent) cleanly into VIN with appropriate
filtering.</li>
</ul>
<p><strong>3. MCU &amp; digital core (J3 ESP32-S3-WROOM-1, SW1–SW4,
R3–R6, C3–C4)</strong></p>
<ul>
<li><strong>Decoupling absent:</strong> The module needs the recommended
22 µF bulk plus 0.1 µF high-frequency capacitor right at its 3.3 V
pins.[^esp-supply] Add them on the 3v3 net.</li>
<li><strong>Boot/strap networks:</strong> RC networks (R3/C3, R5/C4) and
buttons appear to target strapping pins. Double-check the chosen
resistor values meet Espressif’s strap logic levels and that any buttons
pulling to 3.3 V have corresponding pulldowns or rely on internal
ones.</li>
</ul>
<p><strong>4. USB interface (J1, C1–C2, R1–R2)</strong></p>
<ul>
<li><strong>VBUS usage:</strong> Currently 5 V is only on J1; extend it
to the charger and any other circuits needing it. Consider adding input
reverse-polarity or surge protection if needed.</li>
<li><strong>Signal conditioning:</strong> 47 pF shunts on D± may be
aggressive; ensure they meet USB FS requirements once you know trace
lengths. No glaring mistakes otherwise; CC resistors (R1/R2) look
correct.</li>
</ul>
<p><strong>5. Battery monitor / I²C bus (J5 “MCP3021”, R7, J6
connector)</strong></p>
<ul>
<li><strong>Analog input over-voltage:</strong> MCP3021’s AIN must sit
between VSS and VDD.[^mcp-ain] Here AIN (pin 2) is tied to batt while
VDD (pin 4) is 3.3 V, so AIN can reach 4.2 V and violate the spec. Fix
by adding a resistor divider (and optional RC) or powering the ADC from
the battery and level-shifting I²C.</li>
<li><strong>Add I²C pull-ups:</strong> Nets N$13/N$14 lack pull-up
resistors. Provide ~4.7 kΩ to 3.3 V so both the MCP3021 and the OLED
connector (J6) have a defined bus idle level.</li>
<li><strong>Bus voltage domains:</strong> If you decide to run MCP3021
at battery voltage, include appropriate level shifting to protect the
ESP32 pins (absolute max VIO ≈ VDD + 0.3 V).[^esp-io]</li>
</ul>
<p><strong>6. User inputs &amp; connectors (SW3/SW4, J2,
J6)</strong></p>
<ul>
<li>Buttons simply short pins to 3.3 V; ensure firmware enables the
needed pulldowns (or add resistors) to avoid floating inputs. Otherwise
no electrical issues spotted.</li>
<li>Programming header (J2) and OLED connector (J6) look consistent with
shared I²C/SW nets.</li>
</ul>
<p><strong>Next steps</strong></p>
<ul>
<li>Rewire U2 VIN/CE to USB 5 V, add the required 1 µF caps on VIN and
VBAT, and confirm your intended charge current.</li>
<li>Substitute the correct 3.3 V LDO variant and place the mandatory
input/output capacitors; add the ESP32 bulk/decoupling caps.</li>
<li>Protect the MCP3021 input (divider) and add I²C pull-ups; reassess
level compatibility if the ADC runs from the battery.</li>
<li>After these fixes, rerun ERC/DRC before moving to layout.</li>
</ul>
</blockquote>
</blockquote>
<p>Addressing the points made:</p>
<ol type="1">
<li>I am purposefully under-charging the battery. It is 30mAh and a
500mAh charge would be charging it at 17C - for an unknown Chinese
battery normally rated at 1C. The watch charging in 30 minutes (2C) is
perfectly fine.</li>
<li>I used the 1.2V footprint because it is the same footprint and
pinout as the 3.3V part, but KiCAD did not have it by default. The
input/output capacitor pins was a calculated risk, but I think we can
bring those back in the next revision.</li>
<li>I’m not concerned about the ESP32 setup as I have tested this within
an inch of it’s life.</li>
<li>The signal conditioning I know to be fine as I have used this with
other circuits previously. What is a concern is that the USB 5V is not
in use, which I checked, and it’s true!</li>
</ol>
<figure>
<img src="smart-watch-v1/pcb_5v.png"
alt="U2 battery charge controller has no USB 5V connection" />
<figcaption aria-hidden="true">U2 battery charge controller has no USB
5V connection</figcaption>
</figure>
<p>And what’s worse, is that it should be!</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># monitor.py</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>power <span class="op">=</span> {</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;batt&quot;</span>: v_batt,</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;5v&quot;</span>: v_5v,</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;3v3&quot;</span>: v_3v3,</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;0v&quot;</span>: v_gnd,</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="co"># ...</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a>man <span class="op">=</span> MCP73812T_420I_OT(power)</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="co"># mcp73812t_420i_ot.py</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="st">&quot;5V&quot;</span> <span class="kw">in</span> power :</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a>  <span class="va">self</span>.man[<span class="dv">4</span>] <span class="op">+=</span> power[<span class="st">&quot;5V&quot;</span>]</span></code></pre></div>
<p>Can you spot it? It’s defined as <code>5v</code> in the power net and
<code>5V</code> in the check! It fails silently! Making it raise an
exception if the label is not found immediately shows the issue:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co"># mcp73812t_420i_ot.py (revised)</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="kw">not</span> <span class="st">&quot;5V&quot;</span> <span class="kw">in</span> power :</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">raise</span> <span class="pp">Exception</span>(<span class="st">&quot;No 5v found!&quot;</span>)</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="va">self</span>.man[<span class="dv">4</span>] <span class="op">+=</span> power[<span class="st">&quot;5V&quot;</span>]</span></code></pre></div>
<div class="sourceCode" id="cb4"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>  <span class="ex">File</span> <span class="st">&quot;/env/src/shared/mcp73812t_420i_ot.py&quot;</span>, line 33, in __init__</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="ex">raise</span> Exception<span class="er">(</span><span class="st">&quot;No 5v found!&quot;</span><span class="kw">)</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="ex">Exception:</span> No 5v found!</span></code></pre></div>
<p><strong>Note:</strong> The first version will need to somehow get 5V
from the USB bus, otherwise it will not be able to charge the LiPo.
There is no way to easily achieve this, so I will need to have a think
about it.</p>
<ol start="5" type="1">
<li>I believe I should be able to use the ESP32’s pull-ups, and that the
OLED display itself has weak pull-ups. That said, the MCP3021 poses a
<em>massive</em> issue. I saw the values I wanted to see in the
datasheet, and completely missed the values I did not want to see.</li>
</ol>
<figure>
<img src="smart-watch-v1/mcp3021_abs.png"
alt="The MCP3021 absolute limits" />
<figcaption aria-hidden="true">The MCP3021 absolute limits</figcaption>
</figure>
<p>The absolute limit is VDD + 0.6V, so 3.3V from the regulator,
bringing us up to 3.9V. 3.9V to 4.2V is not <em>too crazy</em>, maybe we
could get away with it?</p>
<p>This all said, I wanted to check if there are any known side effects
of missing the input/output capacitors:</p>
<blockquote>
<p>“What can be the consequence of missing the 3.3V input/output
capacitors? It is believed that the ESP32-S3-WROOM-1 module has it’s own
internal capacitors, and that the capacitance of the board is
sufficient?”</p>
</blockquote>
<blockquote>
<blockquote>
<p>Leaving out the regulator’s 3.3 V input/output capacitors is
risky:</p>
<ul>
<li><strong>Regulator stability:</strong> The TLV740 family explicitly
requires at least 1 µF of ceramic capacitance on both VIN and VOUT for
loop stability and transient response (§7.1.2, TI TLV740 datasheet
SBVS401B). Without them the LDO can oscillate, overshoot, or momentarily
drop out, which will show up as random brown-outs or crashes of the
ESP32, OLED, and ADC.</li>
<li><strong>Transient/PSRR degradation:</strong> Even if the circuit
seems to work on the bench, load steps from the ESP32’s radios or
display can inject noise back into the rail. Missing capacitors greatly
reduce PSRR and worsen line/load transients, so RF performance, ADC
readings, and I²C integrity suffer.</li>
<li><strong>Module expectations:</strong> The ESP32-S3-WROOM-1 reference
design still places bulk (≈22 µF) and high-frequency (0.1 µF) capacitors
right at the 3V3 pin (Fig. 7, esp32-s3-wroom-1 datasheet v1.4). The
module’s internal bypassing only covers on-module circuitry; it assumes
the host board supplies its own local decoupling.</li>
</ul>
<p>In short, rely on the datasheet values—place the required ≥1 µF
ceramics at the regulator pins (plus the usual 10 µF/0.1 µF pair near
the module). Skipping them invites instability and erratic behavior.</p>
</blockquote>
</blockquote>
<p>Okay, okay, I will put some capacitors in the new design.</p>
<p>And lastly, what the consequences are for running the ADC out of
spec:</p>
<blockquote>
<p>“MCP3021 analogue input can be VDD + 0.6V, where VDD should be 3.3V
and the maximum will be 3.3V + 0.6V = 3.9V. The battery fully charged is
4.2V. What will happen to the IC?”</p>
</blockquote>
<blockquote>
<blockquote>
<p>According to the MCP3021 datasheet, the analog input pin (AIN) must
always stay within VSS –0.3 V to VDD + 0.3 V (see “DC Electrical
Specifications,” DS20001805C, p. 3). With the device powered at 3.3 V,
any voltage above about 3.6 V violates that limit. Driving AIN with the
full 4.2 V from a freshly charged Li‑ion cell forward-biases the input’s
internal ESD/clamp structures. In practice that:</p>
<ul>
<li>Forces current through the protection diodes into the 3.3 V rail,
which can pull VDD above its nominal value, upsetting the ESP32 and
other loads.</li>
<li>Produces gross conversion errors because the sampling capacitor is
no longer referenced correctly.</li>
<li>Risks long-term damage: repeated or sustained over-voltage can
overheat the clamp diodes or core circuitry, eventually destroying the
ADC.</li>
</ul>
<p>You should scale or buffer the battery voltage so AIN always remains
within the allowed range—e.g., a resistor divider sized to keep the
maximum input ≤3.3 V (or add a buffer/level shifter if you need very
high input impedance), and optionally include a small series resistor to
limit any fault current.</p>
</blockquote>
</blockquote>
<figure>
<img src="smart-watch-v1/mcp3021_use.png"
alt="The MCP3021 usable limits" />
<figcaption aria-hidden="true">The MCP3021 usable limits</figcaption>
</figure>
<p>Well, the usable range is actually limited to within VDD + 0.3V…
Maybe it could still be used to detect low battery voltage?</p>
<figure>
<img src="smart-watch-v1/mcp3021_circuit.png"
alt="The MCP3021 hard circuit limits" />
<figcaption aria-hidden="true">The MCP3021 hard circuit
limits</figcaption>
</figure>
<p>Ah, and herein is the problem - those damn diodes. If we drive the
analogue input too high, then it will try to drive VDD.
<em>Damn</em>.</p>
<p><strong>Note:</strong> The ADC cannot be populated in the first
design.</p>
<p>Hmm, I think I will be looking for a new ADC in the next design, or I
need to be really clever about reliably measuring the 4.2V. To measure
4.2V with this current IC I would need to drive VDD with at least a
steady 3.9V, damn.</p>
<ol start="6" type="1">
<li>The feedback is fine.</li>
</ol>
</section>
<section id="conclusion" class="level3">
<h3>Conclusion</h3>
<p><strong>Is using an LLM for netlist inspection worth it?</strong> It
seems so! I have no idea how many hours this may have saved me in
debugging time!</p>
<p>Hopefully all of the parts arrive soon enough and the first revision
can be made.</p>
</section>
<section id="future" class="level3">
<h3>Future</h3>
<p>It looks as if micropython make using the OLED display quite easy
with the <a
href="https://docs.micropython.org/en/latest/esp8266/tutorial/ssd1306.html"><code>ssd1306</code></a>
library, offering a framebuffer and some handy drawing functions.</p>
<p>I may consider bringing back the <a
href="https://github.com/danielbarry/pt-draw">pt-draw</a> library to
draw lightweight vector graphics. Maybe I could try parsing some sub-set
of the SVG library via the micropython XML library <a
href="https://github.com/micropython/micropython-lib/tree/3a6ab0b46d6471bee00ae815444c624709dd4cdd/micropython/xmltok">xmltok</a>
(or perhaps <a
href="https://github.com/ThunderEX/uxml2dict/blob/master/uxml2dict.py">uxml2dict</a>
to get a dictionary) and just support line segments (makes designing in
external editors easier).</p>
<p>I still need to figure out how to communicate with the ADC to read
the battery level, but this should be quite simple via I2C. It’s
important that it can be read, though, as it will be a large part of the
power saving strategy.</p>
<p>The next step will be to build out the firmware development and
deployment system to make my life easier.</p>
</section>
<section id="fixing-the-adc" class="level3">
<h3>Fixing The ADC</h3>
<p>At the time of writing this part, everything is already sent off!</p>
<p>In a future revision, there is a viable path to bring the cost down.
After a chat with the people at the local <a
href="https://wiki.eehack.space/index.php/Main_Page">hackspace</a>, the
best approach is likely a resistor ladder, but via a MOSFET. That
circuit looks like so:</p>
<figure>
<img src="smart-watch-v1/new_adc.png"
alt="Resistor ladder enabled via MOSFET" />
<figcaption aria-hidden="true">Resistor ladder enabled via
MOSFET</figcaption>
</figure>
<p>This is with the <a
href="https://www.mouser.co.uk/ProductDetail/Diodes-Incorporated/DMN62D0U-7?qs=ANipbH0jDF1YQ7DvWYjVRw%3D%3D">DMN62D0U-7</a>,
an 8p IC. I <a
href="https://www.falstad.com/circuit/mosfet-beta.html">calculated the
MOSFET Beta</a> to be at 0.8 (<span
class="math inline"><em>R</em><sub><em>D</em><em>S</em></sub> = 2.5</span>,
<span
class="math inline"><em>V</em><sub><em>G</em><em>S</em></sub> = 1</span>,
Threshold <span class="math inline"> = 0.5</span>). In the <a
href="smart-watch-v1/circuitjs_new_adc.txt">simulation</a> (with
resistors all set to 10k) the off-current is ~200nA and the on-current
is ~700uA, which seems quite acceptable.</p>
<iframe src="https://coffeespace.org.uk/dead/tag/watch/embed">
</iframe>
</section>
</section>
      ]]>
    </description>
  </item>
  <item>
    <title>Compiler Comparison</title>
    <link>https://coffeespace.org.uk/projects/compiler-comparison.html?md5sum=11173b6b1217e67cd29bd8f3bb8c4119</link>
    <pubDate>Sat, 01 Nov 2025 00:00:00 +0000</pubDate>
    <enclosure url="https://coffeespace.org.uk/projects/compiler-comparison.mp3" type="audio/mpeg" length="2453255" />
    <description>
      <![CDATA[
<link rel="stylesheet" type="text/css" href="/style.css" />
<p><img src="compiler-comparison/hero.png" id="hero" class="hero" /></p>
<section id="compiler-comparison" class="level2">
<h2>Compiler Comparison</h2>
<figure>
<img src="compiler-comparison/preview.jpg" alt="Preview Image" />
<figcaption aria-hidden="true">Preview Image</figcaption>
</figure>
<p>I was recently experimenting with <code>tcc</code> for a project, and
wanted to benchmark <em>just</em> how good it really is when considering
other options. I of course though about <code>gcc</code>, but later
found <code>clang</code> to be something also worth testing. I think
discovered <code>fil-c</code> as a supposed memory safe version of C,
which was also worth a consideration.</p>
<p>For <code>tcc</code> I am using <a
href="https://github.com/TinyCC/tinycc">“tinycc”</a>, an unofficial
mirror that appears to be actively maintained.</p>
<p>For <code>fil-c</code> I am using the pre-compiled <a
href="https://github.com/pizlonator/fil-c/tree/v0.673">v0.673</a>,
specifically a pre-compiled version:</p>
<blockquote>
<p><code>filc-0.673-linux-x86_64.tar.xz</code> is the traditional,
self-contained <a href="https://fil-c.org/pizfix">“pizfix”</a>
distribution. It only includes the compiler, doesn’t require root, and
is based on the musl libc. <strong>This is recommended for quickly
trying out Fil-C.</strong></p>
</blockquote>
<p>As this version of <code>fil-c</code> is complied with musl libc,
this isn’t quite apples-to-apples, but it is good enough to give us an
idea.</p>
<p>Each test is run 10 times against a set of 9 compiler flags:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>FLAGS <span class="op">=</span> [</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;&quot;</span>,       <span class="co"># No optimisation</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;-O1&quot;</span>,    <span class="co"># Optimize</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;-O2&quot;</span>,    <span class="co"># Optimize even more</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;-O3&quot;</span>,    <span class="co"># Optimize yet more</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;-O0&quot;</span>,    <span class="co"># Reduce compilation time and make debugging produce the expected results</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;-Os&quot;</span>,    <span class="co"># Optimize for size</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;-Ofast&quot;</span>, <span class="co"># Disregard strict standards compliance</span></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;-Og&quot;</span>,    <span class="co"># Optimize while keeping in mind debugging experience</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>  <span class="st">&quot;-Oz&quot;</span>,    <span class="co"># Optimize aggressively for size rather than speed</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a>]</span></code></pre></div>
<p>For 10 runs, 9 flags and 4 compilers, we see <span
class="math inline">10 × 9 × 4 = 360</span> tests per graph. With 18
graphs that’s 6,480 tests. <em>It takes a while.</em></p>
<section id="compiling-tcc" class="level3">
<h3>Compiling TCC</h3>
<p>For the first test, we compile TCC and compare the final binary size
and how long it took to compile. The TCC binary was chosen because it’s
a relatively large project and it is written in compatible C.</p>
<figure>
<img src="compiler-comparison/compile_tcc_size.svg"
alt="Compilation size comparison for tcc" />
<figcaption aria-hidden="true">Compilation size comparison for
tcc</figcaption>
</figure>
<p><code>clang</code>, <code>gcc</code> and <code>tcc</code> produce
similar binary sizes, but <code>fil-c</code> produces are greatly larger
binary.</p>
<figure>
<img src="compiler-comparison/compile_tcc_time.svg"
alt="Compilation time comparison for tcc" />
<figcaption aria-hidden="true">Compilation time comparison for
tcc</figcaption>
</figure>
<p>Similarly, <code>fil-c</code> takes significantly longer to compile,
whilst <code>tcc</code> enjoys a reduction in compilation time.</p>
<p><code>fil-c</code> is likely to be bloated due to the memory safety
features, so it really depends on how much you value those. For roaring
performance, it does seem to not do as well.</p>
</section>
<section id="compiling-links" class="level3">
<h3>Compiling Links</h3>
<p>For the next test we compile Links, as it was one of the tests that
the TCC author used to <a href="https://bellard.org/tcc/">benchmark the
performance of TCC</a>. In Fabrice Bellard’s test, he got the following
performance figures:</p>
<table>
<thead>
<tr class="header">
<th>Compiler</th>
<th>Time(s)</th>
<th>lines/second</th>
<th>MBytes/second</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>TinyCC 0.9.22</td>
<td>2.27</td>
<td>859000</td>
<td>29.6</td>
</tr>
<tr class="even">
<td>GCC 3.2 -O0</td>
<td>20.0</td>
<td>98000</td>
<td>3.4</td>
</tr>
</tbody>
</table>
<figure>
<img src="compiler-comparison/compile_links_size.svg"
alt="Compilation size comparison for links" />
<figcaption aria-hidden="true">Compilation size comparison for
links</figcaption>
</figure>
<p>For binary size, each is relatively similar, but it is strange how
compiling options appear to make little or no difference to
<code>tcc</code> or <code>fil-c</code>.</p>
<figure>
<img src="compiler-comparison/compile_links_time.svg"
alt="Compilation time comparison for links" />
<figcaption aria-hidden="true">Compilation time comparison for
links</figcaption>
</figure>
<p>For compilation time, <code>tcc</code> appears to lose the edge that
it had, and <code>fil-c</code> appears to be somewhat consistent.</p>
</section>
<section id="compiling-u-database" class="level3">
<h3>Compiling u-database</h3>
<p>For the next test we compile and execute the performance test for <a
href="https://gitlab.com/danbarry16/u-database">u-database</a>, a
flat-binary database key-value store written in C. It will happily read
and write hundreds of thousands of records a second (sub microsecond per
transaction). In this high-performance application, small changes in
compiler and flags can be felt.</p>
<figure>
<img src="compiler-comparison/compile_u-database_size.svg"
alt="Compilation size comparison for u-database" />
<figcaption aria-hidden="true">Compilation size comparison for
u-database</figcaption>
</figure>
<p>When compiling my u-database library, there appears to be no real
binary size change for each compiler.</p>
<figure>
<img src="compiler-comparison/compile_u-database_time.svg"
alt="Compilation time comparison for u-database" />
<figcaption aria-hidden="true">Compilation time comparison for
u-database</figcaption>
</figure>
<p>The optimisation flags do appear to hit <code>gcc</code> and
<code>fil-c</code> strangely enough, otherwise there is an unexpected
uniformity across the software.</p>
<figure>
<img src="compiler-comparison/execute_u-database_time.svg"
alt="Execution time comparison for u-database" />
<figcaption aria-hidden="true">Execution time comparison for
u-database</figcaption>
</figure>
<p>With the execution time, it for some reason appears that the longer
it took to compile, the longer it also takes to run.</p>
</section>
<section id="compiling-smollibs" class="level3">
<h3>Compiling smollibs</h3>
<p>For the next test we compile a series of single-file headers from a
project called <a
href="https://gitlab.com/danbarry16/smol-libs">“smollibs”</a>. Each of
them is a tiny C99 library with a basic example test program.</p>
<p>For the next graphs, we will evaluate them together…</p>
<figure>
<img src="compiler-comparison/compile_smollibs_git_size.svg"
alt="Compilation size comparison for smollibs git" />
<figcaption aria-hidden="true">Compilation size comparison for smollibs
git</figcaption>
</figure>
<figure>
<img src="compiler-comparison/compile_smollibs_json_size.svg"
alt="Compilation size comparison for smollibs json" />
<figcaption aria-hidden="true">Compilation size comparison for smollibs
json</figcaption>
</figure>
<figure>
<img src="compiler-comparison/compile_smollibs_ppm_size.svg"
alt="Compilation size comparison for smollibs ppm" />
<figcaption aria-hidden="true">Compilation size comparison for smollibs
ppm</figcaption>
</figure>
<figure>
<img src="compiler-comparison/compile_smollibs_prop_size.svg"
alt="Compilation size comparison for smollibs prop" />
<figcaption aria-hidden="true">Compilation size comparison for smollibs
prop</figcaption>
</figure>
<figure>
<img src="compiler-comparison/compile_smollibs_serv_size.svg"
alt="Compilation size comparison for smollibs serv" />
<figcaption aria-hidden="true">Compilation size comparison for smollibs
serv</figcaption>
</figure>
<p>There appears to be a “striping” affect on the graphs, particularly
around the <code>-Ofast</code> flag. Looking at the GNU explanation for
the <a
href="https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html">flags</a>:</p>
<blockquote>
<p><code>-Ofast</code></p>
<p>Disregard strict standards compliance. <code>-Ofast</code> enables
all <code>-O3</code> optimizations. It also enables optimizations that
are not valid for all standard-compliant programs. It turns on
<code>-ffast-math</code>, <code>-fallow-store-data-races</code> and the
Fortran-specific <code>-fstack-arrays</code>, unless
<code>-fmax-stack-var-size</code> is specified, and
<code>-fno-protect-parens</code>. It turns off
<code>-fsemantic-interposition</code>.</p>
</blockquote>
<p>It doesn’t appear to specifically be the <code>-O3</code> flag as we
also test this, so it’s safe to assume that one of the other flags
causes the binary size to increase.</p>
<figure>
<img src="compiler-comparison/compile_smollibs_git_time.svg"
alt="Compilation time comparison for smollibs git" />
<figcaption aria-hidden="true">Compilation time comparison for smollibs
git</figcaption>
</figure>
<figure>
<img src="compiler-comparison/compile_smollibs_json_time.svg"
alt="Compilation time comparison for smollibs json" />
<figcaption aria-hidden="true">Compilation time comparison for smollibs
json</figcaption>
</figure>
<figure>
<img src="compiler-comparison/compile_smollibs_ppm_time.svg"
alt="Compilation time comparison for smollibs ppm" />
<figcaption aria-hidden="true">Compilation time comparison for smollibs
ppm</figcaption>
</figure>
<figure>
<img src="compiler-comparison/compile_smollibs_prop_time.svg"
alt="Compilation time comparison for smollibs prop" />
<figcaption aria-hidden="true">Compilation time comparison for smollibs
prop</figcaption>
</figure>
<figure>
<img src="compiler-comparison/compile_smollibs_serv_time.svg"
alt="Compilation time comparison for smollibs serv" />
<figcaption aria-hidden="true">Compilation time comparison for smollibs
serv</figcaption>
</figure>
<p>Rather than making a case for a specific compiler, these tests seem
to be making a case for testing which compiler specifically works for
your use-case!</p>
</section>
<section id="compiling-rclc" class="level3">
<h3>Compiling rclc</h3>
<p>For the last comparison, I wanted to see how well each compiler
performed when compiling rclc, the C-based wrapper for ROS2. The first
issue is that there is not an easy-to-point-to file that represents the
output of the compilation process, <code>colcon</code> hides files away
and I kind of ran out of time.</p>
<!--
![Compilation size comparison for rclc](compiler-comparison/compile_rclc_size.svg)
-->
<figure>
<img src="compiler-comparison/compile_rclc_time.svg"
alt="Compilation time comparison for rclc" />
<figcaption aria-hidden="true">Compilation time comparison for
rclc</figcaption>
</figure>
<p><code>clang</code> and <code>gcc</code> gave relatively predictable
compile times over all of the test flags, but <code>tcc</code> failed to
compile the project unfortunately. I <em>believe</em> it is because it
is a C99 based compiler, whereas rclc uses more modern C features.
<code>fil-c</code> also fails to compile, but I didn’t have time to try
and set it up correctly.</p>
</section>
<section id="conclusion" class="level3">
<h3>Conclusion</h3>
<p>Should you switch to <code>tcc</code> as your daily driver C
compiler? <em>Probably not</em>, but it’s not as terrible an option as
you may have original considered! But it will produce valid C code for
many projects, it is mostly faster to compile, and the execution time is
comparable. For speed or memory restricted applications, you may very
well consider <code>tcc</code> as a valid option!</p>
<p>In the future it would be good to get rclc working correctly, and to
compare libc implementations. Additionally it is important to consider
shared vs static library building - I suspect that we see a move towards
static libraries as disk size is cheap, RAM is plentiful, and the cost
of sharing memory across increasing numbers of cores is more heavily
felt.</p>
<iframe src="https://coffeespace.org.uk/dead/tag/compiler/embed">
</iframe>
</section>
</section>
      ]]>
    </description>
  </item>
  <item>
    <title>Genetic Programming</title>
    <link>https://coffeespace.org.uk/projects/genetic-programming.html?md5sum=c1b5ea98b4d4e1407181e788557393ed</link>
    <pubDate>Sat, 20 Sep 2025 00:00:00 +0000</pubDate>
    <enclosure url="https://coffeespace.org.uk/projects/genetic-programming.mp3" type="audio/mpeg" length="1294725" />
    <description>
      <![CDATA[
<link rel="stylesheet" type="text/css" href="/style.css" />
<p><img src="genetic-programming/hero.png" id="hero" class="hero" /></p>
<section id="genetic-programming" class="level2">
<h2>Genetic Programming</h2>
<figure>
<img src="genetic-programming/preview.jpg" alt="Preview Image" />
<figcaption aria-hidden="true">Preview Image</figcaption>
</figure>
<p>Laying beside me is <a
href="https://www.amazon.com/Field-Guide-Genetic-Programming/dp/1409200736"><em>A
Field Guide to Genetic Programming</em></a> by Poli, Langdon, McPhee, et
al. If you search the title online, it can be read for free.</p>
<p>My first introduction to evolutionary algorithms was genetic
algorithms (GAs), some 10+ years ago in an AI class, I believe held by
<a
href="https://scholar.google.co.uk/citations?user=p5CxQoQAAAAJ&amp;hl=en">Michael
L Walters</a> (a.k.a Mick). As soon as I heard the explanation, an
enormous light bulb went off in my brain. <strong>I had the knowledge to
make a machine learn.</strong> I went home that night and coded it for
myself. <em>Very cool.</em></p>
<p>I was also aware of genetic programming (GP), but I largely dismissed
it due to moving onto neural networks. Genetic programming is
essentially GA, but the thing being evolved is code. The only thing that
really changes is the structure being operated on, otherwise most
concepts are similar.</p>
<p>I had this vague feeling in my head that GA/GP was far more powerful
and worthy of investigation, but over time it was dismissed. I remember
being at an AI conference in New Zealand laughing along in my head with
some guys dismissing some work submitted on GAs - and I regret that.</p>
<section id="background" class="level3">
<h3>Background</h3>
<p>Both neural networks and GP take some input <span
class="math inline"><em>x</em></span>, and produce some output <span
class="math inline"><em>y</em></span>, using some learned model
<em>M</em>. We can consider this to be <span
class="math inline"><em>M</em>(<em>x</em>) = <em>y</em></span>. There is
then some fitness/error function that is used to adjust the model <span
class="math inline"><em>M</em></span> to better output the result.</p>
<p>The likes of LLMs are essentially just predictive models, where given
some current state <span
class="math inline"><em>s</em><sub><em>t</em></sub></span>, predict a
future state <span
class="math inline"><em>s</em><sub><em>t</em> + 1</sub></span>, i.e
<span
class="math inline"><em>M</em>(<em>s</em><sub><em>t</em></sub>) = <em>s</em><sub><em>t</em> + 1</sub></span>.
An agent can explore a predictive model by proposing an action <span
class="math inline"><em>a</em><sub><em>t</em></sub></span>, i.e. <span
class="math inline"><em>M</em>(<em>s</em><sub><em>t</em></sub>|<em>a</em><sub><em>t</em></sub>) = <em>s</em><sub><em>t</em> + 1</sub></span>.
Some more advanced agents may consider the result of following several
future actions <span
class="math inline"><em>A</em><sub><em>t</em></sub></span>, i.e. <span
class="math inline"><em>M</em>(<em>s</em><sub><em>t</em></sub>|<em>A</em><sub><em>t</em></sub>) = <em>s</em><sub><em>t</em> + 1</sub></span>
- the computation explodes for large action sequences.</p>
<p>This compute required can be extremely large for training and recall,
so before this really became feasible on better computers, researchers
developed reinforcement learning. The major idea was not to predict a
future state <span
class="math inline"><em>s</em><sub><em>t</em> + 1</sub></span>, but
instead the best future action <span
class="math inline"><em>a</em><sub><em>t</em> + 1</sub></span>,
i.e. <span
class="math inline"><em>M</em>(<em>s</em><sub><em>t</em></sub>) = <em>a</em><sub><em>t</em> + 1</sub></span>.</p>
</section>
<section id="structure" class="level3">
<h3>Structure</h3>
<p>A large breakthrough in deep learning was figuring out how to build
these deep structures. <a
href="https://en.wikipedia.org/wiki/AlexNet">AlexNet</a> arguably opened
the door to these deeper structures, but it took a while to get
there.</p>
<p>Given how important work on structures has been, it seems crazy that
we do not lean into GP for designing and building these structures.
Given how large these models are, what we need is either a
representative simplified/reduced model, or a reduced computation
training/evaluation.</p>
<p>I believe it is worth noting that whilst GP can be used for the
structure, that learning for weights, activation energies, etc, are
still far more efficiently addressed by the current learning
techniques.</p>
<p><em>This could be an interesting place for future work…</em></p>
</section>
<section id="intrinsically-motivated-gp-agents" class="level3">
<h3>Intrinsically Motivated GP Agents</h3>
<p>What I want to revisit is a GP-based agent where a fitness/error
function is not strongly defined. This would be a model in the form
<span
class="math inline"><em>M</em>(<em>s</em><sub><em>t</em></sub>|<em>A</em><sub><em>t</em></sub>) = <em>s</em><sub><em>t</em> + 1</sub></span>
where an algorithm searches over the predictive model and produces <span
class="math inline"><em>a</em><sub><em>t</em> + 1</sub></span>.</p>
<p>What, if, we setup our search that we look for the intrinsic
motivation algorithm itself? Possibly a bigger question yet, <em>how
would we know we found an interesting algorithm?</em> Do we rate
survival, exploration behaviour, collaboration with other agents, the
ability to terraform the environment, the ability to approximate these
measures cheaply? By what measure do we consider the agent
successful?</p>
<p>The answer is: <em>I’m not sure.</em> But I think we’re asking the
right questions.</p>
<iframe src="https://coffeespace.org.uk/dead/tag/ai/embed">
</iframe>
</section>
</section>
      ]]>
    </description>
  </item>
  <item>
    <title>Hash Functions</title>
    <link>https://coffeespace.org.uk/projects/hash-functions.html?md5sum=9397c51adfc6e5196a2d41ab49570208</link>
    <pubDate>Sun, 20 Feb 2022 00:00:00 +0000</pubDate>
    <enclosure url="https://coffeespace.org.uk/projects/hash-functions.mp3" type="audio/mpeg" length="7685843" />
    <description>
      <![CDATA[
<link rel="stylesheet" type="text/css" href="/style.css" />
<section id="hash-functions" class="level2">
<h2>Hash Functions</h2>
<figure>
<img src="hash-functions/preview.gif" alt="Preview Image" />
<figcaption aria-hidden="true">Preview Image</figcaption>
</figure>
<p>In a <a href="udatabase.html">previous post</a> where I released <a
href="https://gitlab.com/danbarry16/u-database">uDatabase</a>, I
discussed the important of good hashing and how it <em>really</em>
helped with the speed of my database library.</p>
<p>But that go me thinking: <em>How do I really know what I have done is
better?</em></p>
<p>My use-case is somewhat unique compared to other example hash
functions, as I need to be able to do the following:</p>
<ol type="1">
<li>Convert a <code>char*</code> arbitrary length to a
<code>char*</code> of fixed length.</li>
<li>The first two bytes should be very high quality hashing.</li>
<li>The remaining bytes are only required to be ‘unique’, but quality
does not so much matter. The remainder of the hash must be as fast as
possible.</li>
</ol>
<p>Use looks something like so:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">*</span> key <span class="op">=</span> <span class="st">&quot;some value&quot;</span><span class="op">;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span> hash<span class="op">[</span><span class="dv">16</span><span class="op">];</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>func<span class="op">(</span>key<span class="op">,</span> hash<span class="op">,</span> <span class="dv">16</span><span class="op">);</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="dt">uint16_t</span> shortHash <span class="op">=</span> <span class="op">*(</span><span class="dt">uint16_t</span><span class="op">*)</span>hash<span class="op">;</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="co">/* Do something with values */</span></span></code></pre></div>
<p><em>Why?</em> The first two bytes are used as a shorter hash for a
look-up table to reduce searching, whereas the rest of the hash is
simply to confirm that a given key is unique if the initial check
passes. This greatly reduces computation. Bare in mind, this hash
function may be run millions of times a second!</p>
<section id="inspiration" class="level3">
<h3>Inspiration</h3>
<p>Whilst searching on the wild world web I found <a
href="https://www.andreinc.net/2021/10/02/implementing-hash-tables-in-c-part-1">this
article</a> by Andrei Ciobanu on <em>Implementing Hash Tables in C</em>.
He kindly offers his <a
href="https://gist.github.com/skeeto/3c91495daaa5e91a52c03dd1b6033f6a">source
code</a> which was an inspiration for my testing.</p>
<p>Unfortunately I was unable to use his code or testing, as he was
interested in handling hash functions that return <code>uint32_t</code>
and I am interested in <code>char*</code>, as well as wanting to
visualize the quality of the hashes and benchmark the performance. I
therefore took the time to write my own tests.</p>
</section>
<section id="testing-previous-functions" class="level3">
<h3>Testing Previous Functions</h3>
<p>I created a small piece of checking code <a
href="https://gitlab.com/danbarry16/hash-check">here</a>. It outputs
results, as well as various visualisation in <a
href="http://davis.lbl.gov/Manuals/NETPBM/doc/pgm.html">PGM format</a>.
There is then a script to convert the PGM files to scaled JPG files
(which are displayed here). The idea is to be able to visualise the
collisions of the hash function, and therefore the quality. Black areas
mean large numbers of collisions, whereas white means lower numbers of
collisions.</p>
<p>In these tests, I test the collisions for <code>uint8_t</code>,
<code>uint16_t</code> and “<code>uint24_t</code>” (which doesn’t exist).
This in turn gives us single-byte and two-byte collisions, whereas the
three-byte collisions indicate the hashing quality after the initial
concentration area.</p>
<p><em>Why not test more bytes for collisions?</em> The problem is
storing the collisions in RAM. These tables are already quite large! The
program already consumes in excess of 500MB of RAM during testing and
each additional bit to be tested doubles that!</p>
<section id="results" class="level4">
<h4>Results</h4>
<p>I’ll start off by giving the main results (lower is better):</p>
<table>
<thead>
<tr class="header">
<th style="text-align: left;">func</th>
<th style="text-align: right;">ms</th>
<th style="text-align: right;">col=8</th>
<th style="text-align: right;">col=16</th>
<th style="text-align: right;">col=24</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">cust1</td>
<td style="text-align: right;">2634</td>
<td style="text-align: right;">16777200</td>
<td style="text-align: right;">16776960</td>
<td style="text-align: right;">16773120</td>
</tr>
<tr class="even">
<td style="text-align: left;">cust2</td>
<td style="text-align: right;">2839</td>
<td style="text-align: right;">16777001</td>
<td style="text-align: right;">16773120</td>
<td style="text-align: right;">16711680</td>
</tr>
<tr class="odd">
<td style="text-align: left;">cust3</td>
<td style="text-align: right;">2993</td>
<td style="text-align: right;"><strong>16776960</strong></td>
<td style="text-align: right;"><strong>16711680</strong></td>
<td style="text-align: right;">15902144</td>
</tr>
<tr class="even">
<td style="text-align: left;">cust4</td>
<td style="text-align: right;"><strong>2295</strong></td>
<td style="text-align: right;"><strong>16776960</strong></td>
<td style="text-align: right;"><strong>16711680</strong></td>
<td style="text-align: right;"><strong>15741061</strong></td>
</tr>
</tbody>
</table>
<p>We check <span class="math inline">2<sup>24</sup></span> keys
(16777216). We expect that for a single byte, there is no way to avoid a
collision. As we increase the number of bytes, good hashing algorithms
will decrease the number of collisions.</p>
<p>As you can see, the hashing function named <code>cust4</code> runs
faster and has the least collisions in each scenario.</p>
</section>
<section id="function-1" class="level4">
<h4>Function 1</h4>
<p>This was my initial “make something work” function. It did an ‘okay
job’ during initial testing.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">*</span> hash_cust1<span class="op">(</span><span class="dt">char</span><span class="op">*</span> s<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> d<span class="op">,</span> <span class="dt">int</span> n<span class="op">){</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> x <span class="op">=</span> <span class="op">-</span><span class="dv">1</span><span class="op">;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">while</span><span class="op">(</span>s<span class="op">[++</span>x<span class="op">])</span> d<span class="op">[</span>x <span class="op">%</span> n<span class="op">]</span> <span class="op">=</span> s<span class="op">[</span>x<span class="op">]</span> <span class="op">^</span> <span class="op">(</span>x <span class="op">&lt;</span> n <span class="op">?</span> <span class="ch">&#39;</span><span class="sc">\0</span><span class="ch">&#39;</span> <span class="op">:</span> d<span class="op">[</span>x <span class="op">%</span> n<span class="op">]</span> <span class="op">&lt;&lt;</span> <span class="dv">2</span><span class="op">);</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">while</span><span class="op">(</span>x <span class="op">&lt;</span> n<span class="op">)</span> d<span class="op">[</span>x<span class="op">++]</span> <span class="op">=</span> <span class="ch">&#39;</span><span class="sc">\0</span><span class="ch">&#39;</span><span class="op">;</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> d<span class="op">;</span></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>Performance:</strong> In terms of performance, this was my
second best forming algorithm. We pay heavily for the inline <a
href="https://www.tutorialspoint.com/c-cplusplus-ternary-operator">ternary
operator</a> and this for sure affects branch prediction.</p>
<p><strong>Collisions:</strong> This was <em>awful</em>.</p>
<figure>
<img src="hash-functions/cust1_16.pgm.jpg" alt="One byte" />
<figcaption aria-hidden="true">One byte</figcaption>
</figure>
<p>As can be seen in the one-byte output, the function was completely
unable to hash <code>char</code> characters with large overlap.</p>
<figure>
<img src="hash-functions/cust1_256.pgm.jpg" alt="Two bytes" />
<figcaption aria-hidden="true">Two bytes</figcaption>
</figure>
<p>The two-byte output shows how insanely bad this problem is, with
collisions typically happening in <em>exactly</em> the same
locations.</p>
<figure>
<img src="hash-functions/cust1_4096.pgm.jpg" alt="Three bytes" />
<figcaption aria-hidden="true">Three bytes</figcaption>
</figure>
<p>It obviously doesn’t improve as we look towards three-byte output. I
late realised it is <em>even worse than I thought</em>. If <span
class="math inline">|<em>s</em>| ≥ <em>n</em></span>, it overrides any
previous good effort attempt to hash the first two bytes. Ouch!</p>
</section>
<section id="function-2" class="level4">
<h4>Function 2</h4>
<p>At this time I has realised that my hashing function was
significantly holding back my program, so I looked to make some small
changes to improve test results.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">*</span> hash_cust2<span class="op">(</span><span class="dt">char</span><span class="op">*</span> s<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> d<span class="op">,</span> <span class="dt">int</span> n<span class="op">){</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> x <span class="op">=</span> <span class="op">-</span><span class="dv">1</span><span class="op">;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">while</span><span class="op">(</span>s<span class="op">[++</span>x<span class="op">])</span> d<span class="op">[</span>x <span class="op">%</span> n<span class="op">]</span> <span class="op">=</span> s<span class="op">[</span>x<span class="op">]</span> <span class="op">^</span> <span class="op">(</span>s<span class="op">[</span>x <span class="op">+</span> <span class="dv">1</span><span class="op">]</span> <span class="op">&lt;&lt;</span> <span class="dv">3</span><span class="op">);</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">while</span><span class="op">(</span>x <span class="op">&lt;</span> n<span class="op">)</span> d<span class="op">[</span>x<span class="op">++]</span> <span class="op">=</span> <span class="ch">&#39;</span><span class="sc">\0</span><span class="ch">&#39;</span><span class="op">;</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> d<span class="op">;</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>Performance:</strong> We managed to lose the ternary
operator, so things were looking good! But - for some reason, this
actually decreased performance. I imagine there was some cost to looking
one byte into the future and performing some operation on it with the
current byte. Perhaps there is some cost associated with accessing
memory more than once. I would imagine that <code>s[x + 1]</code> would
be kept in a register for the next loop, but clearly not?</p>
<p><strong>Collisions:</strong> It’s still not great, but clearly a
<em>massive</em> improvement!</p>
<figure>
<img src="hash-functions/cust2_16.pgm.jpg" alt="One byte" />
<figcaption aria-hidden="true">One byte</figcaption>
</figure>
<p>As we can see, the one-byte output is now more spread out! It’s still
a very repeatable, not very well spread pattern - but this is a
remarkably better distribution.</p>
<figure>
<img src="hash-functions/cust2_256.pgm.jpg" alt="Two bytes" />
<figcaption aria-hidden="true">Two bytes</figcaption>
</figure>
<p>Unfortunately this didn’t hold up as we look at the two-byte output.
It’s still a <em>much</em> better distribution, but not great.</p>
<figure>
<img src="hash-functions/cust2_4096.pgm.jpg" alt="Three bytes" />
<figcaption aria-hidden="true">Three bytes</figcaption>
</figure>
<p>One thing this function does well is to scatter the distribution
across the entire range. This is where we see that <code>s[x + 1]</code>
come into its own - but again it is too costly.</p>
</section>
<section id="function-3" class="level4">
<h4>Function 3</h4>
<p>It’s now that I decided to focus more heavily on the entropy of those
first two bytes, where here is achieved by having a dedicated line just
for hashing those first two bytes repeatedly.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">*</span> hash_cust3<span class="op">(</span><span class="dt">char</span><span class="op">*</span> s<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> d<span class="op">,</span> <span class="dt">int</span> n<span class="op">){</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int</span> x <span class="op">=</span> <span class="op">-</span><span class="dv">1</span><span class="op">;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">while</span><span class="op">(</span>s<span class="op">[++</span>x<span class="op">]){</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>    d<span class="op">[</span>x <span class="op">%</span> n<span class="op">]</span> <span class="op">=</span> s<span class="op">[</span>x<span class="op">];</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>    d<span class="op">[</span>x <span class="op">%</span> <span class="kw">sizeof</span><span class="op">(</span><span class="dt">uint16_t</span><span class="op">)]</span> <span class="op">^=</span> s<span class="op">[</span>x<span class="op">]</span> <span class="op">&lt;&lt;</span> <span class="dv">3</span><span class="op">;</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  <span class="cf">while</span><span class="op">(</span>x <span class="op">&lt;</span> n<span class="op">)</span> d<span class="op">[</span>x<span class="op">++]</span> <span class="op">=</span> <span class="ch">&#39;</span><span class="sc">\0</span><span class="ch">&#39;</span><span class="op">;</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> d<span class="op">;</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>Performance:</strong> As a result of this extra dedicated
operation, we lose performance. For the purpose of the application
though, this was worth it, as it reduced collisions and therefore
increased overall performance.</p>
<p><strong>Collisions:</strong> Collisions are tonnes better in this
version! It’s night and day!</p>
<figure>
<img src="hash-functions/cust3_16.pgm.jpg" alt="One byte" />
<figcaption aria-hidden="true">One byte</figcaption>
</figure>
<p>As you can see, for one-byte we have a much better spread, but still
not perfect.</p>
<figure>
<img src="hash-functions/cust3_256.pgm.jpg" alt="Two bytes" />
<figcaption aria-hidden="true">Two bytes</figcaption>
</figure>
<p>This is also the best two-byte output (so far) as we now see</p>
<figure>
<img src="hash-functions/cust3_4096.pgm.jpg" alt="Three bytes" />
<figcaption aria-hidden="true">Three bytes</figcaption>
</figure>
</section>
<section id="function-4" class="level4">
<h4>Function 4</h4>
<p>This is the ‘best’ function I could derive based on function 3
(<code>cust3</code>). It now uses <code>memset</code> to zero out the
memory, which means a bunch of optimizations methods can be used to
accelerate the zeroing of this space. Additionally everything is
in-lined to increase simplicity.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">*</span> hash_cust4<span class="op">(</span><span class="dt">char</span><span class="op">*</span> s<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> d<span class="op">,</span> <span class="dt">int</span> n<span class="op">){</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>  memset<span class="op">(</span>d<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> n<span class="op">);</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> <span class="op">*</span>s<span class="op">;</span> <span class="op">++</span>x<span class="op">)</span> <span class="op">*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">=</span> <span class="op">(*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">&lt;&lt;</span> <span class="dv">5</span><span class="op">)</span> <span class="op">^</span> <span class="op">*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">+</span> <span class="op">(</span>d<span class="op">[</span>x <span class="op">%</span> n<span class="op">]</span> <span class="op">^=</span> <span class="op">*</span>s<span class="op">++);</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> d<span class="op">;</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>Performance:</strong> The performance is better than function
3 (<code>cust3</code>), but not as as good as the functions before.</p>
<p><strong>Collisions:</strong> The number of collisions are reduced,
but not significantly. You can see there is a very visible pattern in
the visualisation and this this will ultimately cause larger numbers of
hash collisions.</p>
<figure>
<img src="hash-functions/cust4_16.pgm.jpg" alt="One byte" />
<figcaption aria-hidden="true">One byte</figcaption>
</figure>
<p>The one-byte spread clearly has a pattern, but this is significantly
better than previous attempts.</p>
<figure>
<img src="hash-functions/cust4_256.pgm.jpg" alt="Two bytes" />
<figcaption aria-hidden="true">Two bytes</figcaption>
</figure>
<p>The two-byte pattern is clearly much better than all previous
attempts - we can now be certain that hashes are distributed over the
entire space.</p>
<figure>
<img src="hash-functions/cust4_4096.pgm.jpg" alt="Three bytes" />
<figcaption aria-hidden="true">Three bytes</figcaption>
</figure>
<p>The thee-byte visualisation shows that we still suck at distributing
the data over multiple bytes. The entropy is entirely concentrated on
the first two bytes.</p>
</section>
</section>
<section id="testing-new-functions" class="level3">
<h3>Testing New Functions</h3>
<p>Ideally, we want a <em>faster</em> function that reduces collisions
with the exact same data. Is this possible? <em>Yes.</em></p>
<p>Armed with this new knowledge, I now test some new functions (and
display the results for previous algorithms during the same run window)
for <span class="math inline">2<sup>24</sup></span> keys:</p>
<table>
<thead>
<tr class="header">
<th style="text-align: left;">func</th>
<th style="text-align: right;">ms</th>
<th style="text-align: right;">col=8</th>
<th style="text-align: right;">col=16</th>
<th style="text-align: right;">col=24</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;"><em>cust1</em></td>
<td style="text-align: right;">4267</td>
<td style="text-align: right;">16777200</td>
<td style="text-align: right;">16776960</td>
<td style="text-align: right;">16773120</td>
</tr>
<tr class="even">
<td style="text-align: left;"><em>cust2</em></td>
<td style="text-align: right;">4506</td>
<td style="text-align: right;">16777001</td>
<td style="text-align: right;">16773120</td>
<td style="text-align: right;">16711680</td>
</tr>
<tr class="odd">
<td style="text-align: left;"><em>cust3</em></td>
<td style="text-align: right;">5292</td>
<td style="text-align: right;">16776960</td>
<td style="text-align: right;">16711680</td>
<td style="text-align: right;">15902144</td>
</tr>
<tr class="even">
<td style="text-align: left;"><em>cust4</em></td>
<td style="text-align: right;">4712</td>
<td style="text-align: right;">16776960</td>
<td style="text-align: right;">16711680</td>
<td style="text-align: right;">15741061</td>
</tr>
<tr class="odd">
<td style="text-align: left;">cust5</td>
<td style="text-align: right;">4602</td>
<td style="text-align: right;">16776960</td>
<td style="text-align: right;">16711680</td>
<td style="text-align: right;">15730195</td>
</tr>
<tr class="even">
<td style="text-align: left;">cust6</td>
<td style="text-align: right;">4761</td>
<td style="text-align: right;">16776960</td>
<td style="text-align: right;">16711680</td>
<td style="text-align: right;">15728390</td>
</tr>
<tr class="odd">
<td style="text-align: left;">cust7</td>
<td style="text-align: right;">4265</td>
<td style="text-align: right;">16776960</td>
<td style="text-align: right;">16711680</td>
<td style="text-align: right;">15632352</td>
</tr>
<tr class="even">
<td style="text-align: left;">cust8</td>
<td style="text-align: right;">4468</td>
<td style="text-align: right;">16776960</td>
<td style="text-align: right;">16711680</td>
<td style="text-align: right;">15728624</td>
</tr>
<tr class="odd">
<td style="text-align: left;">cust9</td>
<td style="text-align: right;">6168</td>
<td style="text-align: right;">16776960</td>
<td style="text-align: right;">16711680</td>
<td style="text-align: right;">6155480</td>
</tr>
<tr class="even">
<td style="text-align: left;">cust10</td>
<td style="text-align: right;">5329</td>
<td style="text-align: right;">16776960</td>
<td style="text-align: right;">16711680</td>
<td style="text-align: right;">6138576</td>
</tr>
<tr class="odd">
<td style="text-align: left;">cust11</td>
<td style="text-align: right;">5320</td>
<td style="text-align: right;">16776960</td>
<td style="text-align: right;">16711680</td>
<td style="text-align: right;">7083260</td>
</tr>
<tr class="even">
<td style="text-align: left;">cust12</td>
<td style="text-align: right;">4988</td>
<td style="text-align: right;">16776960</td>
<td style="text-align: right;">16711680</td>
<td style="text-align: right;"><strong>5915585</strong></td>
</tr>
<tr class="odd">
<td style="text-align: left;">cust13</td>
<td style="text-align: right;">4838</td>
<td style="text-align: right;">16776960</td>
<td style="text-align: right;">16711680</td>
<td style="text-align: right;"><strong>5915585</strong></td>
</tr>
</tbody>
</table>
<p>As you can see, <code>cust12</code> and <code>cust13</code> have the
least hash collisions whilst maintaining respectable timing (compared to
the <code>cust4</code> benchmark).</p>
<p>And for the purpose of really exaggerating the timing, I run them
also at <span class="math inline">2<sup>28</sup></span> keys
(268435456):</p>
<table>
<thead>
<tr class="header">
<th style="text-align: left;">func</th>
<th style="text-align: right;">ms</th>
<th style="text-align: right;">col=8</th>
<th style="text-align: right;">col=16</th>
<th style="text-align: right;">col=24</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;"><em>cust1</em></td>
<td style="text-align: right;">68992</td>
<td style="text-align: right;">268435440</td>
<td style="text-align: right;">268435200</td>
<td style="text-align: right;">268431360</td>
</tr>
<tr class="even">
<td style="text-align: left;"><em>cust2</em></td>
<td style="text-align: right;">74341</td>
<td style="text-align: right;">268435241</td>
<td style="text-align: right;">268431360</td>
<td style="text-align: right;">268369920</td>
</tr>
<tr class="odd">
<td style="text-align: left;"><em>cust3</em></td>
<td style="text-align: right;">78551</td>
<td style="text-align: right;">268435200</td>
<td style="text-align: right;">268369920</td>
<td style="text-align: right;">267386624</td>
</tr>
<tr class="even">
<td style="text-align: left;"><em>cust4</em></td>
<td style="text-align: right;">70847</td>
<td style="text-align: right;">268435200</td>
<td style="text-align: right;">268369920</td>
<td style="text-align: right;">267386624</td>
</tr>
<tr class="odd">
<td style="text-align: left;">cust5</td>
<td style="text-align: right;"><strong>66663</strong></td>
<td style="text-align: right;">268435200</td>
<td style="text-align: right;">268369920</td>
<td style="text-align: right;">267386644</td>
</tr>
<tr class="even">
<td style="text-align: left;">cust6</td>
<td style="text-align: right;">82937</td>
<td style="text-align: right;">268435200</td>
<td style="text-align: right;">268369920</td>
<td style="text-align: right;">267386624</td>
</tr>
<tr class="odd">
<td style="text-align: left;">cust7</td>
<td style="text-align: right;"><strong>65465</strong></td>
<td style="text-align: right;">268435200</td>
<td style="text-align: right;">268369920</td>
<td style="text-align: right;">261502963</td>
</tr>
<tr class="even">
<td style="text-align: left;">cust8</td>
<td style="text-align: right;"><strong>65944</strong></td>
<td style="text-align: right;">268435200</td>
<td style="text-align: right;">268369920</td>
<td style="text-align: right;">267386864</td>
</tr>
<tr class="odd">
<td style="text-align: left;">cust9</td>
<td style="text-align: right;">81174</td>
<td style="text-align: right;">268435200</td>
<td style="text-align: right;">268369920</td>
<td style="text-align: right;">251658253</td>
</tr>
<tr class="even">
<td style="text-align: left;">cust10</td>
<td style="text-align: right;">76063</td>
<td style="text-align: right;">268435200</td>
<td style="text-align: right;">268369920</td>
<td style="text-align: right;">251658241</td>
</tr>
<tr class="odd">
<td style="text-align: left;">cust11</td>
<td style="text-align: right;">71695</td>
<td style="text-align: right;">268435200</td>
<td style="text-align: right;">268369920</td>
<td style="text-align: right;">251658302</td>
</tr>
<tr class="even">
<td style="text-align: left;">cust12</td>
<td style="text-align: right;"><strong>66548</strong></td>
<td style="text-align: right;">268435200</td>
<td style="text-align: right;">268369920</td>
<td style="text-align: right;"><strong>251658240</strong></td>
</tr>
<tr class="odd">
<td style="text-align: left;">cust13</td>
<td style="text-align: right;"><strong>66037</strong></td>
<td style="text-align: right;">268435200</td>
<td style="text-align: right;">268369920</td>
<td style="text-align: right;"><strong>251658240</strong></td>
</tr>
</tbody>
</table>
<p>As you can see, <code>cust5</code>, <code>cust7</code>,
<code>cust8</code>, <code>cust12</code> and <code>cust13</code> all
outperform <code>cust14</code>. We’ll now go into a little more detail
about the algorithms and how they were designed…</p>
<section id="function-5" class="level4">
<h4>Function 5</h4>
<p>This is similar the function 4, but operates on the theory that we
are shifting our entropy out the front of the <code>uint16_t</code>.
Instead of shifting by 5, we instead shift by 3:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">*</span> hash_cust5<span class="op">(</span><span class="dt">char</span><span class="op">*</span> s<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> d<span class="op">,</span> <span class="dt">int</span> n<span class="op">){</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  memset<span class="op">(</span>d<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> n<span class="op">);</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> <span class="op">*</span>s<span class="op">;</span> <span class="op">++</span>x<span class="op">)</span> <span class="op">*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">=</span> <span class="op">(*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">&lt;&lt;</span> <span class="dv">3</span><span class="op">)</span> <span class="op">^</span> <span class="op">*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">+</span> <span class="op">(</span>d<span class="op">[</span>x <span class="op">%</span> n<span class="op">]</span> <span class="op">^=</span> <span class="op">*</span>s<span class="op">++);</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> d<span class="op">;</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Shifting by lower values seems to reduce the number of clock-cycles
required to do the shift. Ideally shift values should be as low as
possible.</p>
<p><strong>Performance:</strong> As can bee seen, we reduce the running
time when compared to function 4 (<code>cust4</code>).</p>
<p><strong>Collisions:</strong> We perform slightly worse on collisions,
but it is worth the speed-up.</p>
<figure>
<img src="hash-functions/cust5_16.pgm.jpg" alt="One byte" />
<figcaption aria-hidden="true">One byte</figcaption>
</figure>
<p>The one-byte pattern looks very good. No place in particular looks
overly concentrated.</p>
<figure>
<img src="hash-functions/cust5_256.pgm.jpg" alt="Two bytes" />
<figcaption aria-hidden="true">Two bytes</figcaption>
</figure>
<p>This scales well to the two-byte pattern where we see a relatively
nice distribution. At this point I realised that the blocky-ness
acutally comes from that XOR operation which can be addressed in the
future!</p>
<figure>
<img src="hash-functions/cust5_4096.pgm.jpg" alt="Three bytes" />
<figcaption aria-hidden="true">Three bytes</figcaption>
</figure>
<p>Three-byte pattern still have really poor hash distribution and is
causing tonnes of collisions.</p>
</section>
<section id="function-6" class="level4">
<h4>Function 6</h4>
<p>With function 6 (<code>cust6</code>) I experimented with using
<code>rotl16</code> instead of shift, my theory being that we were
shifting entropy straight off the bit.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">*</span> hash_cust6<span class="op">(</span><span class="dt">char</span><span class="op">*</span> s<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> d<span class="op">,</span> <span class="dt">int</span> n<span class="op">){</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>  memset<span class="op">(</span>d<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> n<span class="op">);</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> <span class="op">*</span>s<span class="op">;</span> <span class="op">++</span>x<span class="op">)</span> <span class="op">*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">=</span> rotl16<span class="op">(*(</span><span class="dt">int16_t</span><span class="op">*)</span>d<span class="op">,</span> <span class="dv">5</span><span class="op">)</span> <span class="op">^</span> <span class="op">*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">+</span> <span class="op">(</span>d<span class="op">[</span>x <span class="op">%</span> n<span class="op">]</span> <span class="op">^=</span> <span class="op">*</span>s<span class="op">++);</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> d<span class="op">;</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>Performance:</strong> Using the in-line function took a
massive performance hit!</p>
<p><strong>Collisions:</strong> It made only a little difference to the
number of collisions ultimately.</p>
<figure>
<img src="hash-functions/cust6_16.pgm.jpg" alt="One byte" />
<figcaption aria-hidden="true">One byte</figcaption>
</figure>
<p>In the one-byte pattern you can clearly see some blocking - very
interesting! There is clearly something going on here!</p>
<figure>
<img src="hash-functions/cust6_256.pgm.jpg" alt="Two bytes" />
<figcaption aria-hidden="true">Two bytes</figcaption>
</figure>
<p>This is not a bad distribution at all for the two-byte
distribution.</p>
<figure>
<img src="hash-functions/cust6_4096.pgm.jpg" alt="Three bytes" />
<figcaption aria-hidden="true">Three bytes</figcaption>
</figure>
<p>The three-byte pattern still sucks, argh!</p>
</section>
<section id="function-7" class="level4">
<h4>Function 7</h4>
<p>At this point, I realised that we could overcome the issue of losing
bits out the front of the bit shift simply by using larger integers
instead of rotation:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">*</span> hash_cust7<span class="op">(</span><span class="dt">char</span><span class="op">*</span> s<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> d<span class="op">,</span> <span class="dt">int</span> n<span class="op">){</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>  memset<span class="op">(</span>d<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> n<span class="op">);</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> <span class="op">*</span>s<span class="op">;</span> <span class="op">++</span>x<span class="op">)</span> <span class="op">*(</span><span class="dt">int32_t</span><span class="op">*)</span>d <span class="op">=</span> <span class="op">(*(</span><span class="dt">int32_t</span><span class="op">*)</span>d <span class="op">&lt;&lt;</span> <span class="dv">3</span><span class="op">)</span> <span class="op">^</span> <span class="op">*(</span><span class="dt">int32_t</span><span class="op">*)</span>d <span class="op">+</span> <span class="op">(</span>d<span class="op">[</span>x <span class="op">%</span> n<span class="op">]</span> <span class="op">^=</span> <span class="op">*</span>s<span class="op">++);</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> d<span class="op">;</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>Performance:</strong> It’s obviously much faster to use
larger integers rather than the dedicated rotation function.</p>
<p><strong>Collisions:</strong> We saw a nice little reduction in the
number of collisions, awesome!</p>
<figure>
<img src="hash-functions/cust7_16.pgm.jpg" alt="One byte" />
<figcaption aria-hidden="true">One byte</figcaption>
</figure>
<p>The one-byte pattern looks quite nice again.</p>
<figure>
<img src="hash-functions/cust7_256.pgm.jpg" alt="Two bytes" />
<figcaption aria-hidden="true">Two bytes</figcaption>
</figure>
<p>The two-byte pattern is still a little blocky.</p>
<figure>
<img src="hash-functions/cust7_4096.pgm.jpg" alt="Three bytes" />
<figcaption aria-hidden="true">Three bytes</figcaption>
</figure>
<p>The three-byte pattern still sucks…</p>
</section>
<section id="function-8" class="level4">
<h4>Function 8</h4>
<p>This was just an experiment in performing the <code>++x</code>
elsewhere.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">*</span> hash_cust8<span class="op">(</span><span class="dt">char</span><span class="op">*</span> s<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> d<span class="op">,</span> <span class="dt">int</span> n<span class="op">){</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  memset<span class="op">(</span>d<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> n<span class="op">);</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> <span class="op">*</span>s<span class="op">;)</span> <span class="op">*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">=</span> <span class="op">(*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">&lt;&lt;</span> <span class="dv">5</span><span class="op">)</span> <span class="op">^</span> <span class="op">*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">+</span> <span class="op">(</span>d<span class="op">[++</span>x <span class="op">%</span> n<span class="op">]</span> <span class="op">^=</span> <span class="op">*</span>s<span class="op">++);</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> d<span class="op">;</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>Performance:</strong> Runs a little slower.</p>
<p><strong>Collisions:</strong> A regression in reducing collisions.</p>
<figure>
<img src="hash-functions/cust8_16.pgm.jpg" alt="One byte" />
<figcaption aria-hidden="true">One byte</figcaption>
</figure>
<p>Nice one-byte pattern.</p>
<figure>
<img src="hash-functions/cust8_256.pgm.jpg" alt="Two bytes" />
<figcaption aria-hidden="true">Two bytes</figcaption>
</figure>
<p>A little blocky two-byte pattern, but okay-ish.</p>
<figure>
<img src="hash-functions/cust8_4096.pgm.jpg" alt="Three bytes" />
<figcaption aria-hidden="true">Three bytes</figcaption>
</figure>
<p>Again an awful three-byte pattern.</p>
</section>
<section id="function-9" class="level4">
<h4>Function 9</h4>
<p>At this point I was getting a little desperate, the three-byte
distributions have so-far sucked! I started experimenting with purposely
ensuring that the upper hash was <em>definitely</em> touched by our
algorithm:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">*</span> hash_cust9<span class="op">(</span><span class="dt">char</span><span class="op">*</span> s<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> d<span class="op">,</span> <span class="dt">int</span> n<span class="op">){</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>  memset<span class="op">(</span>d<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> n<span class="op">);</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> <span class="op">*</span>s<span class="op">;){</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">=</span> <span class="op">(*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">&lt;&lt;</span> <span class="dv">5</span><span class="op">)</span> <span class="op">^</span> <span class="op">*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">+</span> <span class="op">(</span>d<span class="op">[++</span>x <span class="op">%</span> n<span class="op">]</span> <span class="op">^=</span> <span class="op">*</span>s<span class="op">++);</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>    <span class="op">*(</span><span class="dt">int16_t</span><span class="op">*)(</span>d <span class="op">+</span> <span class="op">(</span>x <span class="op">%</span> n <span class="op">-</span> <span class="dv">1</span><span class="op">))</span> <span class="op">^=</span> <span class="op">*(</span><span class="dt">int16_t</span><span class="op">*)</span>d <span class="op">&lt;&lt;</span> <span class="dv">3</span><span class="op">;</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> d<span class="op">;</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>Performance:</strong> Doing too major calculations rather
than one of course had a massive impact on performance.</p>
<p><strong>Collisions:</strong> This is the first time we have seen such
a massive reduction in collisions!</p>
<figure>
<img src="hash-functions/cust9_16.pgm.jpg" alt="One byte" />
<figcaption aria-hidden="true">One byte</figcaption>
</figure>
<p>One-byte distribution doesn’t look all so bad.</p>
<figure>
<img src="hash-functions/cust9_256.pgm.jpg" alt="Two bytes" />
<figcaption aria-hidden="true">Two bytes</figcaption>
</figure>
<p>Two-byte distribution is a little blocky, but not all so bad.</p>
<figure>
<img src="hash-functions/cust9_4096.pgm.jpg" alt="Three bytes" />
<figcaption aria-hidden="true">Three bytes</figcaption>
</figure>
<p>The three-byte distribution is… <em>Wait a second!</em> That’s
awesome! We have a nice spread over the entire 3-byte distribution
space!</p>
</section>
<section id="function-10" class="level4">
<h4>Function 10</h4>
<p>So at this point, I needed to think of a completely different
approach. I turned back to my <a
href="http://www.cse.yorku.ca/~oz/hash.html">original resource</a> for
simple hash functions and thought it would be worth also checking out
the <code>sdmb</code> implementation, specifically the <code>gawk</code>
implementation:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">*</span> hash_cust10<span class="op">(</span><span class="dt">char</span><span class="op">*</span> s<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> d<span class="op">,</span> <span class="dt">int</span> n<span class="op">){</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>  memset<span class="op">(</span>d<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> n<span class="op">);</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> <span class="op">*</span>s<span class="op">;</span> <span class="op">++</span>x<span class="op">)</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">*(</span><span class="dt">int32_t</span><span class="op">*)</span>d <span class="op">=</span> <span class="op">(</span>d<span class="op">[</span>x <span class="op">%</span> n<span class="op">]</span> <span class="op">^=</span> <span class="op">*</span>s<span class="op">++)</span> <span class="op">+</span> <span class="op">(*(</span><span class="dt">int32_t</span><span class="op">*)</span>d <span class="op">&lt;&lt;</span> <span class="dv">6</span><span class="op">)</span> <span class="op">+</span> <span class="op">(*(</span><span class="dt">int32_t</span><span class="op">*)</span>d <span class="op">&lt;&lt;</span> <span class="dv">16</span><span class="op">)</span> <span class="op">-</span> <span class="op">*(</span><span class="dt">int32_t</span><span class="op">*)</span>d<span class="op">;</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> d<span class="op">;</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>Performance:</strong> A reduction in performance when
compared to function 9 (<code>cust9</code>). Still not as good as
function 4 (<code>cust4</code>), but I’ll take it!</p>
<p><strong>Collisions:</strong> Another reduction in collisions! I
believe the merit here is we see multiple ‘smears’/‘spreads’ of data
across the range.</p>
<figure>
<img src="hash-functions/cust10_16.pgm.jpg" alt="One byte" />
<figcaption aria-hidden="true">One byte</figcaption>
</figure>
<p>The one-byte pattern looks super cool!</p>
<figure>
<img src="hash-functions/cust10_256.pgm.jpg" alt="Two bytes" />
<figcaption aria-hidden="true">Two bytes</figcaption>
</figure>
<p>That two-byte pattern is quite evenly distributed too, not bad!</p>
<figure>
<img src="hash-functions/cust10_4096.pgm.jpg" alt="Three bytes" />
<figcaption aria-hidden="true">Three bytes</figcaption>
</figure>
<p>And look at that three-byte pattern, that’s <em>very</em> nice!</p>
</section>
<section id="function-11" class="level4">
<h4>Function 11</h4>
<p>We speed-up function 11 (<code>cust11</code>) by changing the order
of the operations (long story):</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">*</span> hash_cust11<span class="op">(</span><span class="dt">char</span><span class="op">*</span> s<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> d<span class="op">,</span> <span class="dt">int</span> n<span class="op">){</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>  memset<span class="op">(</span>d<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> n<span class="op">);</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> <span class="op">*</span>s<span class="op">;</span> <span class="op">++</span>x<span class="op">)</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">*(</span><span class="dt">uint32_t</span><span class="op">*)</span>d <span class="op">=</span> <span class="op">(*(</span><span class="dt">int32_t</span><span class="op">*)</span>d <span class="op">&lt;&lt;</span> <span class="dv">16</span><span class="op">)</span> <span class="op">+</span> <span class="op">(*(</span><span class="dt">int32_t</span><span class="op">*)</span>d <span class="op">&lt;&lt;</span> <span class="dv">6</span><span class="op">)</span> <span class="op">+</span> <span class="op">*(</span><span class="dt">int32_t</span><span class="op">*)</span>d <span class="op">+</span> <span class="op">(</span>d<span class="op">[</span>x <span class="op">%</span> n<span class="op">]</span> <span class="op">^=</span> <span class="op">*</span>s<span class="op">++);</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> d<span class="op">;</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>Performance:</strong> This gives us a little speed-up.</p>
<p><strong>Collisions:</strong> Collisions are for some reason slightly
higher, although the algorithm should be essentially the same for the
most part.</p>
<figure>
<img src="hash-functions/cust11_16.pgm.jpg" alt="One byte" />
<figcaption aria-hidden="true">One byte</figcaption>
</figure>
<p>Weird one-byte spread.</p>
<figure>
<img src="hash-functions/cust11_256.pgm.jpg" alt="Two bytes" />
<figcaption aria-hidden="true">Two bytes</figcaption>
</figure>
<p>Weirder two-byte spread.</p>
<figure>
<img src="hash-functions/cust11_4096.pgm.jpg" alt="Three bytes" />
<figcaption aria-hidden="true">Three bytes</figcaption>
</figure>
<p>Nice three-byte spread.</p>
</section>
<section id="function-12" class="level4">
<h4>Function 12</h4>
<p>Instead of bit-shifting with <code>(*(int32_t*)d &lt;&lt; 16)</code>,
we now just cast instead with <code>*(int16_t*)(d + 2)</code>. We also
use 16 + 5 bit shifting rather than 16 + 6 for a slightly nicer
distribution:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">*</span> hash_cust12<span class="op">(</span><span class="dt">char</span><span class="op">*</span> s<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> d<span class="op">,</span> <span class="dt">int</span> n<span class="op">){</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>  memset<span class="op">(</span>d<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> n<span class="op">);</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> <span class="op">*</span>s<span class="op">;</span> <span class="op">++</span>x<span class="op">)</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">*(</span><span class="dt">uint32_t</span><span class="op">*)</span>d <span class="op">=</span> <span class="op">*(</span><span class="dt">int16_t</span><span class="op">*)(</span>d <span class="op">+</span> <span class="dv">2</span><span class="op">)</span> <span class="op">+</span> <span class="op">(*(</span><span class="dt">int32_t</span><span class="op">*)</span>d <span class="op">&lt;&lt;</span> <span class="dv">5</span><span class="op">)</span> <span class="op">+</span> <span class="op">*(</span><span class="dt">int32_t</span><span class="op">*)</span>d <span class="op">+</span> <span class="op">(</span>d<span class="op">[</span>x <span class="op">%</span> n<span class="op">]</span> <span class="op">^=</span> <span class="op">*</span>s<span class="op">++);</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> d<span class="op">;</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>Performance:</strong> For our effort we get significant
speed-up, out-competing <code>funct4</code> once again!</p>
<p><strong>Collisions:</strong> Collisions are also reduced now owing to
the shifting of 16 + 5.</p>
<figure>
<img src="hash-functions/cust12_16.pgm.jpg" alt="One byte" />
<figcaption aria-hidden="true">One byte</figcaption>
</figure>
<p>A very nice one-byte distribution.</p>
<figure>
<img src="hash-functions/cust12_256.pgm.jpg" alt="Two bytes" />
<figcaption aria-hidden="true">Two bytes</figcaption>
</figure>
<p>And a very nice two-byte distribution to match.</p>
<figure>
<img src="hash-functions/cust12_4096.pgm.jpg" alt="Three bytes" />
<figcaption aria-hidden="true">Three bytes</figcaption>
</figure>
<p>The three-byte distribution, whilst not the prettiest to look at, is
much better than previous attempts.</p>
</section>
<section id="function-13" class="level4">
<h4>Function 13</h4>
<p>This function is a very small iteration of the previous function.</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span><span class="op">*</span> hash_cust13<span class="op">(</span><span class="dt">char</span><span class="op">*</span> s<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> d<span class="op">,</span> <span class="dt">int</span> n<span class="op">){</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>  memset<span class="op">(</span>d<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> n<span class="op">);</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> <span class="op">*</span>s<span class="op">;)</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>    <span class="op">*(</span><span class="dt">uint32_t</span><span class="op">*)</span>d <span class="op">=</span> <span class="op">*(</span><span class="dt">int16_t</span><span class="op">*)(</span>d <span class="op">+</span> <span class="dv">2</span><span class="op">)</span> <span class="op">+</span> <span class="op">(*(</span><span class="dt">int32_t</span><span class="op">*)</span>d <span class="op">&lt;&lt;</span> <span class="dv">5</span><span class="op">)</span> <span class="op">+</span> <span class="op">*(</span><span class="dt">int32_t</span><span class="op">*)</span>d <span class="op">+</span> <span class="op">(</span>d<span class="op">[</span>x<span class="op">++</span> <span class="op">%</span> n<span class="op">]</span> <span class="op">^=</span> <span class="op">*</span>s<span class="op">++);</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> d<span class="op">;</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><strong>Performance:</strong> Slightly better performance.</p>
<p><strong>Collisions:</strong> The same number of collisions. The below
exist just for completeness.</p>
<figure>
<img src="hash-functions/cust13_16.pgm.jpg" alt="One byte" />
<figcaption aria-hidden="true">One byte</figcaption>
</figure>
<figure>
<img src="hash-functions/cust13_256.pgm.jpg" alt="Two bytes" />
<figcaption aria-hidden="true">Two bytes</figcaption>
</figure>
<figure>
<img src="hash-functions/cust13_4096.pgm.jpg" alt="Three bytes" />
<figcaption aria-hidden="true">Three bytes</figcaption>
</figure>
</section>
</section>
<section id="final-thoughts" class="level3">
<h3>Final Thoughts</h3>
<p>I’m pretty happy with the final implementation and believe is is a
significant improvement over previous attempts. That said, I still
believe there are improvements that can be made in this space:</p>
<ol type="1">
<li><em>Single byte (<code>uint8_t</code>) addressing</em> - Removing
the dependence on large integers is ideal. Having a hash function that
can be used on <em>any</em> architecture (from an 8 bit microcontroller
to a 64 bit server) and produce the same result is clearly
beneficial.</li>
<li><em>Remove the <code>memset</code></em> - Ideally we do the wiping
as we setup the hash.</li>
<li><em>Spread bytes over the entire hash</em> - Even for short keys, we
should be able to sample any part of the hash and get a pretty decent
distribution.</li>
</ol>
<p>In future experiments I will look to sample the end of the hash too
when looking at the distribution. I suspect they <em>all</em> currently
absolutely suck at filling this space in which anything and we get
tonnes of collisions out there.</p>
<p>If you make improvements based on these tests, please let me know!
Better hashes are better for everybody!</p>
<iframe src="https://coffeespace.org.uk/dead/tag/hashfunctions/embed">
</iframe>
</section>
</section>
      ]]>
    </description>
  </item>
  <item>
    <title>Site Statistics</title>
    <link>https://coffeespace.org.uk/projects/site-statistics.html?md5sum=6165365bcb877dddf87c13c062df1e33</link>
    <pubDate>Fri, 23 Oct 2020 00:00:00 +0000</pubDate>
    <enclosure url="https://coffeespace.org.uk/projects/site-statistics.mp3" type="audio/mpeg" length="1025011" />
    <description>
      <![CDATA[
<link rel="stylesheet" type="text/css" href="/style.css" />
<section id="site-statistics" class="level2">
<h2>Site Statistics</h2>
<figure>
<img src="site-statistics/preview.gif" alt="Preview Image" />
<figcaption aria-hidden="true">Preview Image</figcaption>
</figure>
<p>I had a question somebody asked me: <em>How many people actually read
your site?</em> That was a good question - am I just shouting into the
void? So I have been tracking the site statistics for a while and wanted
to share some data.</p>
<p>I should note, this wasn’t done through some tracking script and it’s
not very robust. I simply check through the Nginx logs and analyse the
data - nothing more complicated than this. Data is accumulated over
time. Some flaws up front:</p>
<ol type="1">
<li>Geolocation is based on IPs, IP blocks move around, it’s just a
guestimation. I didn’t want to pry further than just a Country
name.</li>
<li>It doesn’t account for Tor or VPN use, so geolocation may be
skewed.</li>
<li>Counting of requests counts each individual resource request, not
each unique page load. They should overlap with caching, etc, but it’s
of course overestimating in this sense.</li>
<li>I make no attempt to separate bots and humans, a bots do contact the
site a reasonable amount.</li>
</ol>
<p>Regarding security, nothing else is going on. If you are concerned
about your IP being searched, bare in mind that your ISP will keep track
of IPs and their destination addresses, as well as much more intrusive
data. Most websites keep some sort of access log, sorry. I need it to
debug crashes, etc. The difference here is that I don’t run any
advertising, I don’t sell your data and I don’t send your information to
the government.</p>
<section id="requests" class="level3">
<h3>Requests</h3>
<p>So far I have tracked 121,418 unique requests since the 18th July
2020 till today, 23rd October 2020. I haven’t tracked the error log as
this was a trial.</p>
<figure>
<img src="site-statistics/date-freq.png"
alt="Site requests per day (larger view)" />
<figcaption aria-hidden="true">Site requests per day (<a
href="site-statistics/date-freq.png">larger view</a>)</figcaption>
</figure>
<p>As you can see, I have slowly crept from about 500 requests per day
to about 1,000 requests per day (double) in about 3 months. This is zero
search engine optimization (SEO), zero advertising and little up-keep.
Hell, it only supports HTTPS because it has to.</p>
</section>
<section id="locations" class="level3">
<h3>Locations</h3>
<p>Where are the requests coming from?</p>
<figure>
<img src="site-statistics/ip-freq-num.png"
alt="Request per location (larger view)" />
<figcaption aria-hidden="true">Request per location (<a
href="site-statistics/ip-freq-num.png">larger view</a>)</figcaption>
</figure>
<p>It seems they are mostly coming from the United States, followed next
by Singapore, China, Netherlands, France, Germany and New Zealand. I
have no idea why these particular Countries, but it’s an interesting
breakdown given I don’t have many friends in the US I’ve given my site
details to! Organic growth perhaps?</p>
<p>In 2017 I did a little <a href="server-logs.pdf">experiment</a> to
figure out who was attacking a server I was running based in Russia -
which looks greatly different from these logs. China featured massively
in those.</p>
</section>
<section id="future" class="level3">
<h3>Future</h3>
<p>So going forwards I want to start tracking a few more things:</p>
<ul>
<li>Errors (i.e. invalid requests) - this should indicate people trying
to attack the server.</li>
<li>SSH port - who is trying to log into my server?</li>
<li>Other ports - What else is being attacked?</li>
</ul>
<iframe src="/fc/79a59c54f9951188b28aa80cc0523d0ce6c4b5c618bf5f18eb867e412628e883">
</iframe>
</section>
</section>
      ]]>
    </description>
  </item>
  <item>
    <title>Nginx Log Parse</title>
    <link>https://coffeespace.org.uk/projects/nginx-log-parse.html?md5sum=c60be3e9c1034a8ccc082c559bdab6e0</link>
    <pubDate>Thu, 16 Jun 2022 00:00:00 +0000</pubDate>
    <enclosure url="https://coffeespace.org.uk/projects/nginx-log-parse.mp3" type="audio/mpeg" length="4453843" />
    <description>
      <![CDATA[
<link rel="stylesheet" type="text/css" href="/style.css" />
<section id="nginx-log-parse" class="level2">
<h2>Nginx Log Parse</h2>
<figure>
<img src="nginx-log-parse/preview.gif" alt="Preview Image" />
<figcaption aria-hidden="true">Preview Image</figcaption>
</figure>
<section id="background" class="level3">
<h3>Background</h3>
<p>I use a custom script to pull my nginx logs, manipulate them and then
graph the results for the website. It is responsible for a few
tasks:</p>
<ol type="1">
<li><em>Backup Dead Social</em> - Make a clone of Dead Social files <a
href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"><sup>1</sup></a>.</li>
<li><em>Get Logs</em> - Copy the logs from the server via
<code>scp</code>.</li>
<li><em>Merge Logs</em> - Merge the logs into a single file to be
processed.</li>
<li><em>Make Logs Unique</em> - Remove non-unique log entries.</li>
<li><em>Abstract Log Data</em> - Abstract data of interest, ready for
graphing.</li>
<li><em>Create Access Graph</em> - Generate the first graph.</li>
<li><em>Create Location Graph</em> - Generate the second graph.</li>
<li><em>Clean-up Temporary Files</em> - Remove the temporary files we
made along the way.</li>
<li><em>Display Nginx Data</em> - Use an old <a
href="https://npm.io/package/nginxparser"><code>nginx-parser</code></a>
program to process and visualise the logs.</li>
</ol>
<p>This system has been getting slower over the years, to the point
where it now takes the best part of a day to process the logs. This both
uses significant system resources and means that I cannot access
important data for quite some time.</p>
<p>How large is the data?</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> ls <span class="at">-lh</span> storage.txt</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ex">1.5G</span> storage.txt</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> wc <span class="at">-l</span> storage.txt</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="ex">7100816</span> storage.txt</span></code></pre></div>
<p>1.5 GB and 7 million entries being processed by an old bash script.
Yikes. Time to do some debugging.</p>
</section>
<section id="old-processing" class="level3">
<h3>Old Processing</h3>
<p>The first task was to add some timing code:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Time variables</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="va">time_beg</span><span class="op">=</span>0</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="va">time_end</span><span class="op">=</span>0</span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="va">time_run</span><span class="op">=</span>0</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="co"># time_start()</span></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="co"># Begin timing.</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="kw">function</span><span class="fu"> time_start</span> <span class="kw">{</span></span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>  <span class="va">time_beg</span><span class="op">=</span><span class="va">$(</span><span class="fu">date</span> +%s.%N<span class="va">)</span></span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a>  <span class="va">time_end</span><span class="op">=</span><span class="va">$time_beg</span></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a>  <span class="va">time_run</span><span class="op">=</span>0</span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a><span class="co"># time_start()</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a><span class="co">#</span></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="co"># Begin timing.</span></span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a><span class="kw">function</span><span class="fu"> time_stop</span> <span class="kw">{</span></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a>  <span class="va">time_end</span><span class="op">=</span><span class="va">$(</span><span class="fu">date</span> +%s.%N<span class="va">)</span></span>
<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a>  <span class="va">time_run</span><span class="op">=</span><span class="va">$(</span><span class="bu">echo</span> <span class="st">&quot;</span><span class="va">$time_end</span><span class="st"> - </span><span class="va">$time_beg</span><span class="st">&quot;</span> <span class="kw">|</span> <span class="fu">bc</span> <span class="at">-l</span><span class="va">)</span></span>
<span id="cb2-21"><a href="#cb2-21" aria-hidden="true" tabindex="-1"></a>  <span class="bu">echo</span> <span class="st">&quot;</span><span class="va">$time_run</span><span class="st">&quot;</span></span>
<span id="cb2-22"><a href="#cb2-22" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div>
<p>Now knowing how long one or more items takes to process is as simple
as:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">time_start</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ex">task_to_run</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="va">time_diff</span><span class="op">=</span><span class="st">&quot;</span><span class="va">$(</span><span class="ex">time_stop</span><span class="va">)</span><span class="st">&quot;</span></span></code></pre></div>
<p>I wrapped the main functions and timed how long they take:</p>
<table>
<thead>
<tr class="header">
<th style="text-align: left;">Action</th>
<th style="text-align: left;">Time (s)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">backup_dead_rt</td>
<td style="text-align: left;">187.880756921</td>
</tr>
<tr class="even">
<td style="text-align: left;">logs_get_rt</td>
<td style="text-align: left;">186.920260098</td>
</tr>
<tr class="odd">
<td style="text-align: left;">logs_append_rt</td>
<td style="text-align: left;">30.295236661</td>
</tr>
<tr class="even">
<td style="text-align: left;">logs_unique_rt</td>
<td style="text-align: left;">146.004416903</td>
</tr>
<tr class="odd">
<td style="text-align: left;">logs_abstract_rt</td>
<td style="text-align: left;">16861.844717878</td>
</tr>
<tr class="even">
<td style="text-align: left;">logs_process_rt</td>
<td style="text-align: left;">15.110010662</td>
</tr>
<tr class="odd">
<td style="text-align: left;">plot_access_rt</td>
<td style="text-align: left;">.256452260</td>
</tr>
<tr class="even">
<td style="text-align: left;">plot_location_rt</td>
<td style="text-align: left;">.134897756</td>
</tr>
<tr class="odd">
<td style="text-align: left;">logs_clean_rt</td>
<td style="text-align: left;">.325774132</td>
</tr>
<tr class="even">
<td style="text-align: left;">nginx_parser_rt</td>
<td style="text-align: left;">18131.561209403</td>
</tr>
</tbody>
</table>
<p>“nginx_parser_rt” is interactive and just represents how long I left
the computer to sit there in the background. “logs_abstract_rt”
represents 4.7 hours of straight processing. Oufe.</p>
</section>
<section id="re-write-processing" class="level3">
<h3>Re-Write Processing</h3>
<p>The old processing code was as follows:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="cf">while</span> <span class="bu">read</span> <span class="va">p</span><span class="kw">;</span> <span class="cf">do</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>  <span class="va">IFS</span><span class="op">=</span><span class="st">&#39; &#39;</span> <span class="bu">read</span> <span class="at">-r</span> <span class="at">-a</span> <span class="va">cols</span> <span class="op">&lt;&lt;&lt;</span> <span class="st">&quot;</span><span class="va">$p</span><span class="st">&quot;</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>  <span class="va">ip</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${cols</span><span class="op">[</span><span class="dv">0</span><span class="op">]</span><span class="va">}</span><span class="st">&quot;</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>  <span class="va">country</span><span class="op">=</span><span class="st">&quot;</span><span class="va">$(</span><span class="ex">geoiplookup</span> <span class="va">$ip</span> <span class="kw">|</span> <span class="fu">cut</span> <span class="at">-d</span> <span class="st">&quot; &quot;</span> <span class="at">-f</span> 4<span class="va">)</span><span class="st">&quot;</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>  <span class="va">country</span><span class="op">=</span><span class="va">${country</span><span class="op">::</span>-<span class="dv">1</span><span class="va">}</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="va">timestamp</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${cols</span><span class="op">[</span><span class="dv">3</span><span class="op">]:</span><span class="dv">1</span><span class="va">}</span><span class="st">&quot;</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  <span class="va">date</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${cols</span><span class="op">[</span><span class="dv">3</span><span class="op">]:</span><span class="dv">1</span><span class="op">:</span>-<span class="dv">9</span><span class="va">}</span><span class="st">&quot;</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>  <span class="va">time</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${cols</span><span class="op">[</span><span class="dv">3</span><span class="op">]:</span><span class="dv">13</span><span class="va">}</span><span class="st">&quot;</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a>  <span class="va">method</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${cols</span><span class="op">[</span><span class="dv">5</span><span class="op">]:</span><span class="dv">1</span><span class="va">}</span><span class="st">&quot;</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>  <span class="va">path</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${cols</span><span class="op">[</span><span class="dv">6</span><span class="op">]</span><span class="va">}</span><span class="st">&quot;</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>  <span class="va">response</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${cols</span><span class="op">[</span><span class="dv">8</span><span class="op">]</span><span class="va">}</span><span class="st">&quot;</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>  <span class="bu">echo</span> <span class="st">&quot;</span><span class="va">$date</span><span class="st">&quot;</span> <span class="op">&gt;&gt;</span> out-date.txt</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>  <span class="bu">echo</span> <span class="st">&quot;</span><span class="va">$country</span><span class="st">&quot;</span> <span class="op">&gt;&gt;</span> out-ip.txt</span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="cf">done</span> <span class="op">&lt;</span>storage.txt</span></code></pre></div>
<p>Line by line, we process each of the columns and pull out the
important data. My thinking was that we may be paying for
double-handling data, so I re-write this to the follows:</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Clean data</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="cf">while</span> <span class="va">IFS</span><span class="op">=</span><span class="st">&#39; &#39;</span>, <span class="bu">read</span> <span class="va">ip</span> <span class="va">z0</span> <span class="va">z1</span> <span class="va">timestamp</span> <span class="va">zone</span> <span class="va">method</span> <span class="va">path</span> <span class="va">type</span> <span class="va">response</span> <span class="va">size</span><span class="kw">;</span> <span class="cf">do</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>  <span class="va">country</span><span class="op">=</span><span class="st">&quot;</span><span class="va">$(</span><span class="ex">geoiplookup</span> <span class="va">$ip</span> <span class="kw">|</span> <span class="fu">cut</span> <span class="at">-d</span> <span class="st">&quot; &quot;</span> <span class="at">-f</span> 4<span class="va">)</span><span class="st">&quot;</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>  <span class="va">country</span><span class="op">=</span><span class="va">${country</span><span class="op">::</span>-<span class="dv">1</span><span class="va">}</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>  <span class="va">timestamp</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${timestamp</span><span class="op">:</span><span class="dv">1</span><span class="va">}</span><span class="st">&quot;</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>  <span class="va">date</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${timestamp</span><span class="op">::</span>-<span class="dv">9</span><span class="va">}</span><span class="st">&quot;</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>  <span class="va">time</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${timestamp</span><span class="op">:</span><span class="dv">13</span><span class="va">}</span><span class="st">&quot;</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>   <span class="va">zone</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${zone</span><span class="op">::</span>-<span class="dv">1</span><span class="va">}</span><span class="st">&quot;</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>   <span class="va">method</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${method</span><span class="op">:</span><span class="dv">1</span><span class="va">}</span><span class="st">&quot;</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>   <span class="va">type</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${type</span><span class="op">::</span>-<span class="dv">1</span><span class="va">}</span><span class="st">&quot;</span></span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>  <span class="bu">echo</span> <span class="st">&quot;</span><span class="va">$date</span><span class="st">&quot;</span> <span class="op">&gt;&gt;</span> out-date.txt</span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>  <span class="bu">echo</span> <span class="st">&quot;</span><span class="va">$country</span><span class="st">&quot;</span> <span class="op">&gt;&gt;</span> out-ip.txt</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a><span class="cf">done</span> <span class="op">&lt;</span>storage.txt</span></code></pre></div>
<p>And the results of that is as follows:</p>
<table>
<thead>
<tr class="header">
<th style="text-align: left;">Action</th>
<th style="text-align: left;">Time (s)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">backup_dead_rt</td>
<td style="text-align: left;">168.895424672</td>
</tr>
<tr class="even">
<td style="text-align: left;">logs_get_rt</td>
<td style="text-align: left;">205.790856856</td>
</tr>
<tr class="odd">
<td style="text-align: left;">logs_append_rt</td>
<td style="text-align: left;">26.603748814</td>
</tr>
<tr class="even">
<td style="text-align: left;">logs_unique_rt</td>
<td style="text-align: left;">130.087103720</td>
</tr>
<tr class="odd">
<td style="text-align: left;">logs_abstract_rt</td>
<td style="text-align: left;">14435.241596371</td>
</tr>
<tr class="even">
<td style="text-align: left;">logs_process_rt</td>
<td style="text-align: left;">11.781440252</td>
</tr>
<tr class="odd">
<td style="text-align: left;">plot_access_rt</td>
<td style="text-align: left;">.175404852</td>
</tr>
<tr class="even">
<td style="text-align: left;">plot_location_rt</td>
<td style="text-align: left;">.114184411</td>
</tr>
<tr class="odd">
<td style="text-align: left;">logs_clean_rt</td>
<td style="text-align: left;">.355445442</td>
</tr>
<tr class="even">
<td style="text-align: left;">nginx_parser_rt</td>
<td style="text-align: left;">24555.858216634</td>
</tr>
</tbody>
</table>
<p>It helped a little, but clearly we have to get a little more creative
here…</p>
</section>
<section id="c-implementation" class="level3">
<h3>C Implementation</h3>
<p>I suspected I’m mostly getting screwed by the
<code>geoiplookup</code> command, that loads a database of a few MB and
then looks up the full locations details, which I then have to filter
out.</p>
<p>A better system is to load the database (of just a few MB) into RAM
and then keep performing the searches against this for only the Country
code. Additionally if we process the all of the logs in C++ we further
save time.</p>
<p>I decided to use the <a
href="https://github.com/maxmind">maxmind</a>’s <a
href="https://github.com/maxmind/geoip-api-c">geoip-api-c</a>, which up
until now, has worked great.</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="co">//#define GEOIPDATADIR &quot;geoip-api-c/data/&quot;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#define GEOIPDATADIR </span><span class="st">&quot;/usr/share/GeoIP/&quot;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#define PACKAGE_VERSION </span><span class="st">&quot;1.6.12&quot;</span></span></code></pre></div>
<p>If you try to use the database yourself, you will likely need to
declare these variables. I had no end of trouble trying to link to the
development library and I suspect it is broken since quite a while. It
was much easier to directly include the files.</p>
<p>Note that the value for <code>GEOIPDATADIR</code> if for my system,
which I found through <code>man geoiplookup</code>. On Linux the
location appears to be: <code>/usr/share/GeoIP/</code>. Technically
there is a file in the repository at <code>geoip-api-c/data/</code> -
but this did not work for me and was far too small. There is an update
tool, but this requires you to register <a href="#fn2"
class="footnote-ref" id="fnref2"
role="doc-noteref"><sup>2</sup></a>.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&quot;geoip-api-c/libGeoIP/GeoIP_deprecated.c&quot;</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&quot;geoip-api-c/libGeoIP/GeoIP.c&quot;</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&quot;geoip-api-c/libGeoIP/GeoIPCity.c&quot;</span></span></code></pre></div>
<p>One little trap here is not including
<code>GeoIP_deprecated.c</code>.</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;stdarg.h&gt;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;stdbool.h&gt;</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;stdio.h&gt;</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;sys/time.h&gt;</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="pp">#define PARSER_VERSION </span><span class="st">&quot;0.0.1&quot;</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="pp">#define PARSER_LINE_LEN </span><span class="op">(</span><span class="dv">256</span><span class="pp"> </span><span class="op">*</span><span class="pp"> </span><span class="dv">256</span><span class="op">)</span></span></code></pre></div>
<p>We might need a larger line length if we expect to have someone
significantly testing our server. Most servers and browsers will allow
URLs of 65k. In theory, each of those fields could be significantly
large and this would cause issues with our parser.</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="co">/* Source: https://stackoverflow.com/a/51336144/2847743 */</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="dt">int64_t</span> currentTimeMillis<span class="op">(){</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">struct</span> timeval time<span class="op">;</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  gettimeofday<span class="op">(&amp;</span>time<span class="op">,</span> NULL<span class="op">);</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int64_t</span> s1 <span class="op">=</span> <span class="op">(</span><span class="dt">int64_t</span><span class="op">)(</span>time<span class="op">.</span>tv_sec<span class="op">)</span> <span class="op">*</span> <span class="dv">1000</span><span class="op">;</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>  <span class="dt">int64_t</span> s2 <span class="op">=</span> time<span class="op">.</span>tv_usec <span class="op">/</span> <span class="dv">1000</span><span class="op">;</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> s1 <span class="op">+</span> s2<span class="op">;</span></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Some timing code that repeatedly proves to be useful.</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> flog<span class="op">(</span><span class="dt">const</span> <span class="dt">char</span><span class="op">*</span> format<span class="op">,</span> <span class="op">...){</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>  <span class="dt">va_list</span> args<span class="op">;</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>  va_start<span class="op">(</span>args<span class="op">,</span> format<span class="op">);</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>  fprintf<span class="op">(</span>stderr<span class="op">,</span> <span class="st">&quot;[</span><span class="sc">%li</span><span class="st">] &quot;</span><span class="op">,</span> currentTimeMillis<span class="op">());</span></span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>  vfprintf<span class="op">(</span>stderr<span class="op">,</span> format<span class="op">,</span> args<span class="op">);</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>  fprintf<span class="op">(</span>stderr<span class="op">,</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span><span class="op">);</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>  va_end<span class="op">(</span>args<span class="op">);</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Nice little wrapper around <code>printf()</code> to allow me to
automatically add a timestamp to the front of logs.</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="co">/**</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="co"> * process()</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="co"> *</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="co"> * Process the logs.</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="co"> *</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="co"> * </span><span class="an">@param</span><span class="co"> </span><span class="cv">raw</span><span class="co"> The raw nginx logs.</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="co"> * </span><span class="an">@param</span><span class="co"> </span><span class="cv">date</span><span class="co"> The location of the date file.</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="co"> * </span><span class="an">@param</span><span class="co"> </span><span class="cv">date</span><span class="co"> The location of the location file.</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="co"> **/</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> process<span class="op">(</span><span class="dt">char</span><span class="op">*</span> raw<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> date<span class="op">,</span> <span class="dt">char</span><span class="op">*</span> loc<span class="op">){</span></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>  <span class="co">/* Setup buffers */</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>  <span class="dt">char</span> buff<span class="op">[</span>PARSER_LINE_LEN <span class="op">+</span> <span class="dv">1</span><span class="op">];</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>  <span class="co">/* Setup files */</span></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>  <span class="dt">FILE</span><span class="op">*</span> fraw <span class="op">=</span> raw <span class="op">!=</span> NULL <span class="op">?</span> fopen<span class="op">(</span>raw<span class="op">,</span> <span class="st">&quot;r&quot;</span><span class="op">)</span> <span class="op">:</span> NULL<span class="op">;</span></span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a>  <span class="dt">FILE</span><span class="op">*</span> fdate <span class="op">=</span> date <span class="op">!=</span> NULL <span class="op">?</span> fopen<span class="op">(</span>date<span class="op">,</span> <span class="st">&quot;a&quot;</span><span class="op">)</span> <span class="op">:</span> NULL<span class="op">;</span></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a>  <span class="dt">FILE</span><span class="op">*</span> floc <span class="op">=</span> loc <span class="op">!=</span> NULL <span class="op">?</span> fopen<span class="op">(</span>loc<span class="op">,</span> <span class="st">&quot;a&quot;</span><span class="op">)</span> <span class="op">:</span> NULL<span class="op">;</span></span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span><span class="op">(</span>fraw <span class="op">==</span> NULL<span class="op">){</span></span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a>    flog<span class="op">(</span><span class="st">&quot;Could not open &#39;</span><span class="sc">%s</span><span class="st">&#39; for parsing&quot;</span><span class="op">,</span> raw<span class="op">);</span></span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span><span class="op">;</span></span>
<span id="cb11-20"><a href="#cb11-20" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a>  <span class="co">/* Setup GeoIp */</span></span>
<span id="cb11-22"><a href="#cb11-22" aria-hidden="true" tabindex="-1"></a>  GeoIP<span class="op">*</span> gi <span class="op">=</span> GeoIP_open<span class="op">(</span>GEOIPDATADIR <span class="st">&quot;GeoIP.dat&quot;</span><span class="op">,</span> GEOIP_MEMORY_CACHE <span class="op">|</span> GEOIP_CHECK_CACHE<span class="op">);</span></span>
<span id="cb11-23"><a href="#cb11-23" aria-hidden="true" tabindex="-1"></a>  <span class="co">/* Loop over the file */</span></span>
<span id="cb11-24"><a href="#cb11-24" aria-hidden="true" tabindex="-1"></a>  <span class="cf">while</span><span class="op">(</span>fgets<span class="op">(</span>buff<span class="op">,</span> PARSER_LINE_LEN<span class="op">,</span> fraw<span class="op">)){</span></span>
<span id="cb11-25"><a href="#cb11-25" aria-hidden="true" tabindex="-1"></a>    <span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb11-26"><a href="#cb11-26" aria-hidden="true" tabindex="-1"></a>    <span class="dt">char</span><span class="op">*</span> ip <span class="op">=</span> NULL<span class="op">;</span></span>
<span id="cb11-27"><a href="#cb11-27" aria-hidden="true" tabindex="-1"></a>    <span class="dt">char</span><span class="op">*</span> date <span class="op">=</span> NULL<span class="op">;</span></span>
<span id="cb11-28"><a href="#cb11-28" aria-hidden="true" tabindex="-1"></a>    <span class="dt">char</span><span class="op">*</span> time <span class="op">=</span> NULL<span class="op">;</span></span>
<span id="cb11-29"><a href="#cb11-29" aria-hidden="true" tabindex="-1"></a>    <span class="dt">char</span><span class="op">*</span> path <span class="op">=</span> NULL<span class="op">;</span></span>
<span id="cb11-30"><a href="#cb11-30" aria-hidden="true" tabindex="-1"></a>    <span class="dt">char</span><span class="op">*</span> t <span class="op">=</span> strtok<span class="op">(</span>buff<span class="op">,</span> <span class="st">&quot; &quot;</span><span class="op">);</span></span>
<span id="cb11-31"><a href="#cb11-31" aria-hidden="true" tabindex="-1"></a>    <span class="cf">while</span><span class="op">(</span>t <span class="op">!=</span> NULL<span class="op">){</span></span>
<span id="cb11-32"><a href="#cb11-32" aria-hidden="true" tabindex="-1"></a>      <span class="cf">switch</span><span class="op">(</span>x<span class="op">++){</span></span>
<span id="cb11-33"><a href="#cb11-33" aria-hidden="true" tabindex="-1"></a>        <span class="cf">case</span> <span class="dv">0</span> <span class="op">:</span></span>
<span id="cb11-34"><a href="#cb11-34" aria-hidden="true" tabindex="-1"></a>          ip <span class="op">=</span> t<span class="op">;</span></span>
<span id="cb11-35"><a href="#cb11-35" aria-hidden="true" tabindex="-1"></a>          <span class="cf">break</span><span class="op">;</span></span>
<span id="cb11-36"><a href="#cb11-36" aria-hidden="true" tabindex="-1"></a>        <span class="cf">case</span> <span class="dv">1</span> <span class="op">:</span></span>
<span id="cb11-37"><a href="#cb11-37" aria-hidden="true" tabindex="-1"></a>        <span class="cf">case</span> <span class="dv">2</span> <span class="op">:</span></span>
<span id="cb11-38"><a href="#cb11-38" aria-hidden="true" tabindex="-1"></a>          <span class="co">/* Do nothing */</span></span>
<span id="cb11-39"><a href="#cb11-39" aria-hidden="true" tabindex="-1"></a>          <span class="cf">break</span><span class="op">;</span></span>
<span id="cb11-40"><a href="#cb11-40" aria-hidden="true" tabindex="-1"></a>        <span class="cf">case</span> <span class="dv">3</span> <span class="op">:</span></span>
<span id="cb11-41"><a href="#cb11-41" aria-hidden="true" tabindex="-1"></a>          date <span class="op">=</span> t <span class="op">+</span> <span class="dv">1</span><span class="op">;</span></span>
<span id="cb11-42"><a href="#cb11-42" aria-hidden="true" tabindex="-1"></a>          t<span class="op">[</span><span class="dv">12</span><span class="op">]</span> <span class="op">=</span> <span class="ch">&#39;</span><span class="sc">\0</span><span class="ch">&#39;</span><span class="op">;</span></span>
<span id="cb11-43"><a href="#cb11-43" aria-hidden="true" tabindex="-1"></a>          time <span class="op">=</span> t <span class="op">+</span> <span class="dv">13</span><span class="op">;</span></span>
<span id="cb11-44"><a href="#cb11-44" aria-hidden="true" tabindex="-1"></a>          <span class="cf">break</span><span class="op">;</span></span>
<span id="cb11-45"><a href="#cb11-45" aria-hidden="true" tabindex="-1"></a>        <span class="cf">case</span> <span class="dv">4</span> <span class="op">:</span></span>
<span id="cb11-46"><a href="#cb11-46" aria-hidden="true" tabindex="-1"></a>        <span class="cf">case</span> <span class="dv">5</span> <span class="op">:</span></span>
<span id="cb11-47"><a href="#cb11-47" aria-hidden="true" tabindex="-1"></a>          <span class="co">/* Do nothing */</span></span>
<span id="cb11-48"><a href="#cb11-48" aria-hidden="true" tabindex="-1"></a>          <span class="cf">break</span><span class="op">;</span></span>
<span id="cb11-49"><a href="#cb11-49" aria-hidden="true" tabindex="-1"></a>        <span class="cf">case</span> <span class="dv">6</span> <span class="op">:</span></span>
<span id="cb11-50"><a href="#cb11-50" aria-hidden="true" tabindex="-1"></a>          path <span class="op">=</span> t<span class="op">;</span></span>
<span id="cb11-51"><a href="#cb11-51" aria-hidden="true" tabindex="-1"></a>          <span class="cf">break</span><span class="op">;</span></span>
<span id="cb11-52"><a href="#cb11-52" aria-hidden="true" tabindex="-1"></a>        <span class="cf">default</span> <span class="op">:</span></span>
<span id="cb11-53"><a href="#cb11-53" aria-hidden="true" tabindex="-1"></a>          <span class="co">/* No more of interest, quit early */</span></span>
<span id="cb11-54"><a href="#cb11-54" aria-hidden="true" tabindex="-1"></a>          t <span class="op">=</span> NULL<span class="op">;</span></span>
<span id="cb11-55"><a href="#cb11-55" aria-hidden="true" tabindex="-1"></a>          <span class="cf">break</span><span class="op">;</span></span>
<span id="cb11-56"><a href="#cb11-56" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb11-57"><a href="#cb11-57" aria-hidden="true" tabindex="-1"></a>      <span class="co">/* Check if we can stop tokenizing early */</span></span>
<span id="cb11-58"><a href="#cb11-58" aria-hidden="true" tabindex="-1"></a>      <span class="cf">if</span><span class="op">(</span>t <span class="op">==</span> NULL<span class="op">){</span></span>
<span id="cb11-59"><a href="#cb11-59" aria-hidden="true" tabindex="-1"></a>        <span class="cf">break</span><span class="op">;</span></span>
<span id="cb11-60"><a href="#cb11-60" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span><span class="cf">else</span><span class="op">{</span></span>
<span id="cb11-61"><a href="#cb11-61" aria-hidden="true" tabindex="-1"></a>        t <span class="op">=</span> strtok<span class="op">(</span>NULL<span class="op">,</span> <span class="st">&quot; &quot;</span><span class="op">);</span></span>
<span id="cb11-62"><a href="#cb11-62" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb11-63"><a href="#cb11-63" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb11-64"><a href="#cb11-64" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span><span class="op">(</span>ip <span class="op">!=</span> NULL <span class="op">&amp;&amp;</span> floc <span class="op">!=</span> NULL<span class="op">){</span></span>
<span id="cb11-65"><a href="#cb11-65" aria-hidden="true" tabindex="-1"></a>      <span class="dt">char</span><span class="op">*</span> code <span class="op">=</span> GeoIP_country_code_by_addr<span class="op">(</span>gi<span class="op">,</span> ip<span class="op">);</span></span>
<span id="cb11-66"><a href="#cb11-66" aria-hidden="true" tabindex="-1"></a>      fprintf<span class="op">(</span>floc<span class="op">,</span> <span class="st">&quot;</span><span class="sc">%s\n</span><span class="st">&quot;</span><span class="op">,</span> code<span class="op">);</span></span>
<span id="cb11-67"><a href="#cb11-67" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb11-68"><a href="#cb11-68" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span><span class="op">(</span>date <span class="op">!=</span> NULL <span class="op">&amp;&amp;</span> fdate <span class="op">!=</span> NULL<span class="op">){</span></span>
<span id="cb11-69"><a href="#cb11-69" aria-hidden="true" tabindex="-1"></a>      fprintf<span class="op">(</span>fdate<span class="op">,</span> <span class="st">&quot;</span><span class="sc">%s\n</span><span class="st">&quot;</span><span class="op">,</span> date<span class="op">);</span></span>
<span id="cb11-70"><a href="#cb11-70" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb11-71"><a href="#cb11-71" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb11-72"><a href="#cb11-72" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>A few tricks going on here. Firstly note the use of the
<code>strtok()</code> function that creates tokenized strings in-place.
The second trick is that we only grab the interesting data and we drop
everything else as soon as possible. We try not to waste cycles
processing data we have no plan to use.</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="co">/**</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="co"> * help()</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="co"> *</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="co"> * Display program help.</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="co"> *</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a><span class="co"> * </span><span class="an">@param</span><span class="co"> </span><span class="cv">argc</span><span class="co"> Number of arguments.</span></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a><span class="co"> * </span><span class="an">@param</span><span class="co"> </span><span class="cv">argv</span><span class="co"> Pointer to the arguments.</span></span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a><span class="co"> * </span><span class="an">@param</span><span class="co"> </span><span class="cv">x</span><span class="co"> The current offset into the arguments.</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a><span class="co"> * </span><span class="an">@return</span><span class="co"> The new offset into the arguments.</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a><span class="co"> **/</span></span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> help<span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span><span class="op">**</span> argv<span class="op">,</span> <span class="dt">int</span> x<span class="op">){</span></span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a>  flog<span class="op">(</span><span class="st">&quot;./parser [OPT]&quot;</span><span class="op">);</span></span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a>  flog<span class="op">(</span><span class="st">&quot;&quot;</span><span class="op">);</span></span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a>  flog<span class="op">(</span><span class="st">&quot;  OPTions&quot;</span><span class="op">);</span></span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a>  flog<span class="op">(</span><span class="st">&quot;&quot;</span><span class="op">);</span></span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a>  flog<span class="op">(</span><span class="st">&quot;    -d  Append data to a date file&quot;</span><span class="op">);</span></span>
<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a>  flog<span class="op">(</span><span class="st">&quot;          &lt;STR&gt; Location of date file&quot;</span><span class="op">);</span></span>
<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a>  flog<span class="op">(</span><span class="st">&quot;    -h  Display this help and quit&quot;</span><span class="op">);</span></span>
<span id="cb12-19"><a href="#cb12-19" aria-hidden="true" tabindex="-1"></a>  flog<span class="op">(</span><span class="st">&quot;    -l  Append data to a location file&quot;</span><span class="op">);</span></span>
<span id="cb12-20"><a href="#cb12-20" aria-hidden="true" tabindex="-1"></a>  flog<span class="op">(</span><span class="st">&quot;          &lt;STR&gt; Location of location file&quot;</span><span class="op">);</span></span>
<span id="cb12-21"><a href="#cb12-21" aria-hidden="true" tabindex="-1"></a>  flog<span class="op">(</span><span class="st">&quot;    -r  The raw nginx logs to be read&quot;</span><span class="op">);</span></span>
<span id="cb12-22"><a href="#cb12-22" aria-hidden="true" tabindex="-1"></a>  flog<span class="op">(</span><span class="st">&quot;          &lt;STR&gt; Location of nginx logs&quot;</span><span class="op">);</span></span>
<span id="cb12-23"><a href="#cb12-23" aria-hidden="true" tabindex="-1"></a>  flog<span class="op">(</span><span class="st">&quot;    -v  Display version information&quot;</span><span class="op">);</span></span>
<span id="cb12-24"><a href="#cb12-24" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> x<span class="op">;</span></span>
<span id="cb12-25"><a href="#cb12-25" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb12-26"><a href="#cb12-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-27"><a href="#cb12-27" aria-hidden="true" tabindex="-1"></a><span class="co">/**</span></span>
<span id="cb12-28"><a href="#cb12-28" aria-hidden="true" tabindex="-1"></a><span class="co"> * main()</span></span>
<span id="cb12-29"><a href="#cb12-29" aria-hidden="true" tabindex="-1"></a><span class="co"> *</span></span>
<span id="cb12-30"><a href="#cb12-30" aria-hidden="true" tabindex="-1"></a><span class="co"> * Process the command line arguments.</span></span>
<span id="cb12-31"><a href="#cb12-31" aria-hidden="true" tabindex="-1"></a><span class="co"> *</span></span>
<span id="cb12-32"><a href="#cb12-32" aria-hidden="true" tabindex="-1"></a><span class="co"> * </span><span class="an">@param</span><span class="co"> </span><span class="cv">argc</span><span class="co"> The number of arguments provided.</span></span>
<span id="cb12-33"><a href="#cb12-33" aria-hidden="true" tabindex="-1"></a><span class="co"> * </span><span class="an">@param</span><span class="co"> </span><span class="cv">argv</span><span class="co"> The arguments provided.</span></span>
<span id="cb12-34"><a href="#cb12-34" aria-hidden="true" tabindex="-1"></a><span class="co"> * </span><span class="an">@return</span><span class="co"> The exit status of the program.</span></span>
<span id="cb12-35"><a href="#cb12-35" aria-hidden="true" tabindex="-1"></a><span class="co"> **/</span></span>
<span id="cb12-36"><a href="#cb12-36" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span><span class="op">**</span> argv<span class="op">){</span></span>
<span id="cb12-37"><a href="#cb12-37" aria-hidden="true" tabindex="-1"></a>  <span class="dt">static</span> <span class="dt">char</span><span class="op">*</span> raw <span class="op">=</span> NULL<span class="op">;</span></span>
<span id="cb12-38"><a href="#cb12-38" aria-hidden="true" tabindex="-1"></a>  <span class="dt">static</span> <span class="dt">char</span><span class="op">*</span> date <span class="op">=</span> NULL<span class="op">;</span></span>
<span id="cb12-39"><a href="#cb12-39" aria-hidden="true" tabindex="-1"></a>  <span class="dt">static</span> <span class="dt">char</span><span class="op">*</span> loc <span class="op">=</span> NULL<span class="op">;</span></span>
<span id="cb12-40"><a href="#cb12-40" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">int</span> x <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> x <span class="op">&lt;</span> argc<span class="op">;</span> x<span class="op">++){</span></span>
<span id="cb12-41"><a href="#cb12-41" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span><span class="op">(</span>argv<span class="op">[</span>x<span class="op">][</span><span class="dv">0</span><span class="op">]</span> <span class="op">==</span> <span class="ch">&#39;-&#39;</span><span class="op">){</span></span>
<span id="cb12-42"><a href="#cb12-42" aria-hidden="true" tabindex="-1"></a>      <span class="cf">switch</span><span class="op">(</span>argv<span class="op">[</span>x<span class="op">][</span><span class="dv">1</span><span class="op">]){</span></span>
<span id="cb12-43"><a href="#cb12-43" aria-hidden="true" tabindex="-1"></a>        <span class="cf">case</span> <span class="ch">&#39;d&#39;</span> <span class="op">:</span></span>
<span id="cb12-44"><a href="#cb12-44" aria-hidden="true" tabindex="-1"></a>          date <span class="op">=</span> argv<span class="op">[++</span>x<span class="op">];</span></span>
<span id="cb12-45"><a href="#cb12-45" aria-hidden="true" tabindex="-1"></a>          <span class="cf">break</span><span class="op">;</span></span>
<span id="cb12-46"><a href="#cb12-46" aria-hidden="true" tabindex="-1"></a>        <span class="cf">case</span> <span class="ch">&#39;h&#39;</span> <span class="op">:</span></span>
<span id="cb12-47"><a href="#cb12-47" aria-hidden="true" tabindex="-1"></a>          x <span class="op">=</span> help<span class="op">(</span>argc<span class="op">,</span> argv<span class="op">,</span> x<span class="op">);</span></span>
<span id="cb12-48"><a href="#cb12-48" aria-hidden="true" tabindex="-1"></a>          <span class="cf">return</span> EXIT_SUCCESS<span class="op">;</span></span>
<span id="cb12-49"><a href="#cb12-49" aria-hidden="true" tabindex="-1"></a>        <span class="cf">case</span> <span class="ch">&#39;l&#39;</span> <span class="op">:</span></span>
<span id="cb12-50"><a href="#cb12-50" aria-hidden="true" tabindex="-1"></a>          loc <span class="op">=</span> argv<span class="op">[++</span>x<span class="op">];</span></span>
<span id="cb12-51"><a href="#cb12-51" aria-hidden="true" tabindex="-1"></a>          <span class="cf">break</span><span class="op">;</span></span>
<span id="cb12-52"><a href="#cb12-52" aria-hidden="true" tabindex="-1"></a>        <span class="cf">case</span> <span class="ch">&#39;r&#39;</span> <span class="op">:</span></span>
<span id="cb12-53"><a href="#cb12-53" aria-hidden="true" tabindex="-1"></a>          raw <span class="op">=</span> argv<span class="op">[++</span>x<span class="op">];</span></span>
<span id="cb12-54"><a href="#cb12-54" aria-hidden="true" tabindex="-1"></a>          <span class="cf">break</span><span class="op">;</span></span>
<span id="cb12-55"><a href="#cb12-55" aria-hidden="true" tabindex="-1"></a>        <span class="cf">case</span> <span class="ch">&#39;v&#39;</span> <span class="op">:</span></span>
<span id="cb12-56"><a href="#cb12-56" aria-hidden="true" tabindex="-1"></a>          flog<span class="op">(</span><span class="st">&quot;Version: </span><span class="sc">%s</span><span class="st">&quot;</span><span class="op">,</span> PARSER_VERSION<span class="op">);</span></span>
<span id="cb12-57"><a href="#cb12-57" aria-hidden="true" tabindex="-1"></a>          <span class="cf">break</span><span class="op">;</span></span>
<span id="cb12-58"><a href="#cb12-58" aria-hidden="true" tabindex="-1"></a>        <span class="cf">default</span> <span class="op">:</span></span>
<span id="cb12-59"><a href="#cb12-59" aria-hidden="true" tabindex="-1"></a>          flog<span class="op">(</span><span class="st">&quot;Unknown option &#39;</span><span class="sc">%s</span><span class="st">&#39;&quot;</span><span class="op">,</span> argv<span class="op">[</span>x<span class="op">]);</span></span>
<span id="cb12-60"><a href="#cb12-60" aria-hidden="true" tabindex="-1"></a>          <span class="cf">break</span><span class="op">;</span></span>
<span id="cb12-61"><a href="#cb12-61" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb12-62"><a href="#cb12-62" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span><span class="cf">else</span><span class="op">{</span></span>
<span id="cb12-63"><a href="#cb12-63" aria-hidden="true" tabindex="-1"></a>      flog<span class="op">(</span><span class="st">&quot;Unknown parameter &#39;</span><span class="sc">%s</span><span class="st">&#39;&quot;</span><span class="op">,</span> argv<span class="op">[</span>x<span class="op">]);</span></span>
<span id="cb12-64"><a href="#cb12-64" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb12-65"><a href="#cb12-65" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb12-66"><a href="#cb12-66" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span><span class="op">(</span>raw <span class="op">!=</span> NULL<span class="op">){</span></span>
<span id="cb12-67"><a href="#cb12-67" aria-hidden="true" tabindex="-1"></a>    process<span class="op">(</span>raw<span class="op">,</span> date<span class="op">,</span> loc<span class="op">);</span></span>
<span id="cb12-68"><a href="#cb12-68" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span><span class="cf">else</span><span class="op">{</span></span>
<span id="cb12-69"><a href="#cb12-69" aria-hidden="true" tabindex="-1"></a>    flog<span class="op">(</span><span class="st">&quot;Require raw logs to be processed&quot;</span><span class="op">);</span></span>
<span id="cb12-70"><a href="#cb12-70" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> EXIT_FAILURE<span class="op">;</span></span>
<span id="cb12-71"><a href="#cb12-71" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb12-72"><a href="#cb12-72" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> EXIT_SUCCESS<span class="op">;</span></span>
<span id="cb12-73"><a href="#cb12-73" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The result?</p>
<table>
<thead>
<tr class="header">
<th style="text-align: left;">Action</th>
<th style="text-align: left;">Time (s)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">backup_dead_rt</td>
<td style="text-align: left;">154.661541988</td>
</tr>
<tr class="even">
<td style="text-align: left;">logs_get_rt</td>
<td style="text-align: left;">267.600526311</td>
</tr>
<tr class="odd">
<td style="text-align: left;">logs_append_rt</td>
<td style="text-align: left;">30.361294628</td>
</tr>
<tr class="even">
<td style="text-align: left;">logs_unique_rt</td>
<td style="text-align: left;">126.968953909</td>
</tr>
<tr class="odd">
<td style="text-align: left;">logs_abstract_rt</td>
<td style="text-align: left;">44.061660188</td>
</tr>
<tr class="even">
<td style="text-align: left;">logs_process_rt</td>
<td style="text-align: left;">11.607090069</td>
</tr>
<tr class="odd">
<td style="text-align: left;">plot_access_rt</td>
<td style="text-align: left;">.494797933</td>
</tr>
<tr class="even">
<td style="text-align: left;">plot_location_rt</td>
<td style="text-align: left;">.318292984</td>
</tr>
<tr class="odd">
<td style="text-align: left;">logs_clean_rt</td>
<td style="text-align: left;">.562272088</td>
</tr>
<tr class="even">
<td style="text-align: left;">nginx_parser_rt</td>
<td style="text-align: left;">8559.049334771</td>
</tr>
</tbody>
</table>
<p>A <strong>383x speed-up</strong> (or 38,268% speed-up) - not bad at
all!</p>
</section>
<section id="server" class="level3">
<h3>Server</h3>
<p>Encase you are wondering, this is the current server statistics:</p>
<figure>
<img src="nginx-log-parse/date-freq.png" alt="Larger version" />
<figcaption aria-hidden="true"><a
href="nginx-log-parse/date-freq.png">Larger version</a></figcaption>
</figure>
<figure>
<img src="nginx-log-parse/ip-freq-num.png" alt="Larger version" />
<figcaption aria-hidden="true"><a
href="nginx-log-parse/ip-freq-num.png">Larger version</a></figcaption>
</figure>
<p>The reason I needed to have this better processed is that my server
now hosts static files for another business and I need to ensure the
server resources stand up well. If I suddenly start seeing significant
increases in traffic I may consider upgrading the server to
accommodate.</p>
<iframe src="https://coffeespace.org.uk/dead/tag/nginxlogparse/embed">
</iframe>
</section>
</section>
<aside id="footnotes" class="footnotes footnotes-end-of-document"
role="doc-endnotes">
<hr />
<ol>
<li id="fn1"><p>This is a really terrible system and needs to be fixed
in the future.<a href="#fnref1" class="footnote-back"
role="doc-backlink">↩︎</a></p></li>
<li id="fn2"><p>It would be good to know what the Linux version of the
GeoIP data comes from and how to keep it up to date.<a href="#fnref2"
class="footnote-back" role="doc-backlink">↩︎</a></p></li>
</ol>
</aside>
      ]]>
    </description>
  </item>
  <item>
    <title>HTML Feature Missing</title>
    <link>https://coffeespace.org.uk/projects/html-feature-missing.html?md5sum=0a8be27505b1b9fd4fe1a3286589228f</link>
    <pubDate>Mon, 19 Oct 2020 00:00:00 +0000</pubDate>
    <enclosure url="https://coffeespace.org.uk/projects/html-feature-missing.mp3" type="audio/mpeg" length="1591345" />
    <description>
      <![CDATA[
<link rel="stylesheet" type="text/css" href="/style.css" />
<section id="html-feature-missing" class="level2">
<h2>HTML Feature Missing</h2>
<figure>
<img src="html-feature-missing/preview.gif" alt="Preview Image" />
<figcaption aria-hidden="true">Preview Image</figcaption>
</figure>
<section id="idea" class="level3">
<h3>Idea</h3>
<p>I was chatting with a friend about completely removing JS from the
web entirely and coming up with the various conditions that would or
wouldn’t work. One of the ideas was to build a lightweight browser that
supported HTML and CSS features, but did not allow even a single line of
JS to run. This is what we come up with:</p>
<ul>
<li>Social media would survive. You would have to say goodbye to
infinite scrolling, but for the most part the experience would be
recognizable. As long as you’re doing authentication via cookies over
TLS, it should be a smooth experience. There is for example <a
href="https://mbasic.facebook.com">mbasic</a> that I personally use to
access Facebook - it breaks all the time but actually much less than
letting their crappy scripts run in your browser 24/7.</li>
<li>Banking websites should be okay for the same reason. I suspect the
use of JS in banking software has actually caused more security issues
than it has ever resolved. For example, there have been multiple times a
banking site have been <a
href="https://borncity.com/win/2020/05/14/sicherheitsvorfall-bei-webseite-der-santander-bank-in-belgien/">compromised</a>
by having a CDN changed under them.</li>
<li>Chat applications can work, but of course it currently requires
manual reloading. That automatic loading of new content simply won’t
work currently.</li>
<li>Many niche cases, like running web torrents, etc. Given how many
niche cases there are, this would be a small minority of the web.
Generally, most of these could probably be re-worked into a desktop
application or run server side.</li>
</ul>
</section>
<section id="feature" class="level3">
<h3>Feature</h3>
<p>So the feature I am thinking of is a “automatic re-loader”
capability. It wouldn’t be intelligent or based on some event, but
instead time-based with several configuration options. I think the best
candidate for this would be an <code>&lt;iframe&gt;</code>, it already
has several nice sandboxing aspects and is well <a
href="https://www.w3schools.com/tags/tag_iframe.asp">supported</a>. In
the grand-scheme of things, programs like Dillo or Lynx could be
upgraded to support such a feature without too many changes to their
codebase.</p>
<p>Essentially I think the HTML would look something like this:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode html"><code class="sourceCode html"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;</span><span class="kw">iframe</span> <span class="er">src</span><span class="ot">=</span><span class="st">&quot;test.html&quot;</span> <span class="er">reload</span><span class="ot">=</span><span class="st">&quot;auto&quot;</span><span class="dt">&gt;</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;/</span><span class="kw">iframe</span><span class="dt">&gt;</span></span></code></pre></div>
<p>So the introduction would be:</p>
<table>
<colgroup>
<col style="width: 12%" />
<col style="width: 16%" />
<col style="width: 72%" />
</colgroup>
<thead>
<tr class="header">
<th style="text-align: left;">Attribute</th>
<th style="text-align: left;">Value</th>
<th style="text-align: left;">Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">reload</td>
<td style="text-align: left;">none</td>
<td style="text-align: left;">The type of reload to be performed. The
option <code>none</code></td>
</tr>
<tr class="even">
<td style="text-align: left;"></td>
<td style="text-align: left;">auto</td>
<td style="text-align: left;">is default and indicates that no reload
should be</td>
</tr>
<tr class="odd">
<td style="text-align: left;"></td>
<td style="text-align: left;">timer</td>
<td style="text-align: left;">performed. <code>auto</code> allows the
browser to select one</td>
</tr>
<tr class="even">
<td style="text-align: left;"></td>
<td style="text-align: left;">delta</td>
<td style="text-align: left;">that it believes is most suitable.
<code>timer</code> attempts to</td>
</tr>
<tr class="odd">
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">keep the reloads on a schedule, despite
how low the</td>
</tr>
<tr class="even">
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">networking or loading may take. If the
networking or</td>
</tr>
<tr class="odd">
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">loading is too slow, it simply reloads
when the</td>
</tr>
<tr class="even">
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">previous load is finished.
<code>delta</code> waits for the page</td>
</tr>
<tr class="odd">
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">to be fully loaded, then waits the
specified time and</td>
</tr>
<tr class="even">
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">then performs a reload. This ensures there
is a</td>
</tr>
<tr class="odd">
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">minimal delta per reload time.</td>
</tr>
</tbody>
</table>
<p>This is not without potential security issues:</p>
<ol type="1">
<li>DDoS external resources – Setting the timeout to 1 millisecond and
then pointing it to some external resource of a popular server would
potentially DDoS the external server. Therefore this should be an opt-in
option.</li>
<li>DDoS own server – If your server is under a heavy traffic load, you
may want to tell the reloader to slow down.</li>
<li>Recursive reloading – Potentially you could be asked to load an
iframe, that loads an iframe, which… You get the point. If each one of
these also has a reload timer, it could really bring your browsing
experience down to a crawl.</li>
</ol>
<p>Considering these possibilities and for the purpose of maintaining
backwards compatibility, a web page that offers the ability to reload
can throw a comment in the top of the webpage like so:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode html"><code class="sourceCode html"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;!DOCTYPE </span>html<span class="dt">&gt;</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="co">&lt;!-- @timeout=&quot;50&quot; --&gt;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="dt">&lt;</span><span class="kw">html</span><span class="dt">&gt;</span></span></code></pre></div>
<p><strong>Note:</strong> It would be nicer to have it in the “DOCTYPE”
declaration, but I’m unsure what issues this would cause for backwards
compatibility.</p>
<p>Only web pages that offer the timeout comment <em>before</em> the
<code>&lt;html&gt;</code> tag (or first HTML element) will be allowed to
perform the reload. A web server can thereby set this value to anything
that is suitable during page generation. The values would be like
so:</p>
<table>
<colgroup>
<col style="width: 12%" />
<col style="width: 16%" />
<col style="width: 72%" />
</colgroup>
<thead>
<tr class="header">
<th style="text-align: left;">Attribute</th>
<th style="text-align: left;">Value</th>
<th style="text-align: left;">Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">timeout</td>
<td style="text-align: left;">milliseconds</td>
<td style="text-align: left;">The timeout of the element in
milliseconds, where 0</td>
</tr>
<tr class="even">
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">means timeout is disabled. The default is
0, so this</td>
</tr>
<tr class="odd">
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">value must be set to a positive integer to
enable</td>
</tr>
<tr class="even">
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">automatic reloads. The browser itself may
want to set</td>
</tr>
<tr class="odd">
<td style="text-align: left;"></td>
<td style="text-align: left;"></td>
<td style="text-align: left;">a sane minimum value.</td>
</tr>
</tbody>
</table>
</section>
<section id="conclusion" class="level3">
<h3>Conclusion</h3>
<p>I think such a web feature would be worth considering. It literally
takes basic HTML and makes it interactive via a server, removing the
need for quite a bit of JS currently used.</p>
<p>Some potential applications of this feature:</p>
<ol type="1">
<li>IRC in the browser using only HTML (or other chat features)</li>
<li>Auto-updating email interface using only HTTP</li>
<li>New feeds or status bars for websites</li>
<li>Some basic types of games</li>
<li>Checking for document changes</li>
</ol>
<iframe src="/fc/860d521ac715a9bcc02ffa1cb828bb784720e5a64f7430ec05477236fbc8d9e2">
</iframe>
</section>
</section>
      ]]>
    </description>
  </item>
</channel>
</rss>
