<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Byron Wasti - Posts</title>
    <link rel="self" type="application/atom+xml" href="https://www.byronwasti.com/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://www.byronwasti.com/"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-02-15T00:00:00+00:00</updated>
    <id>https://www.byronwasti.com/atom.xml</id>
    <entry xml:lang="en">
        <title>On the Effectiveness of Retries and Timeouts in Distributed Systems</title>
        <published>2026-02-15T00:00:00+00:00</published>
        <updated>2026-02-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.byronwasti.com/2026-retries-and-timeouts/"/>
        <id>https://www.byronwasti.com/2026-retries-and-timeouts/</id>
        
        <content type="html" xml:base="https://www.byronwasti.com/2026-retries-and-timeouts/">&lt;p&gt;One of the adages that has stuck with me from my relatively brief employment at AWS was that every single network call had to have retries and timeouts. This can even be seen in the AWS CLI and SDKs, which all have retries (3 by default) and timeouts baked in.&lt;&#x2F;p&gt;
&lt;p&gt;On the surface this seems like a reasonable policy; retries are handy in case of arbitrary network failures and timeouts are a nice to have. However, I would argue that retries and timeouts by default across the entire system is &lt;em&gt;unreasonably&lt;&#x2F;em&gt; effective at mitigating a number of the challenges when developing a large-scale distributed system.&lt;&#x2F;p&gt;
&lt;p&gt;Retries by themselves have a number of nice properties that are easy to see: temporary network failures are mitigated (just retry), temporary service outages are mitigated (even nodes crashing mid-request; just retry), it is a forcing function for idempotency everywhere (if every client has retries, requests must be idempotent), and, combined with exponential back-offs, mitigates the effects of rate-limiting (trading it off for increased latency).&lt;&#x2F;p&gt;
&lt;p&gt;Timeouts add on a &lt;em&gt;system-wide backpressure mechanism&lt;&#x2F;em&gt;. The majority of services can be approximated as a priority queue of asynchronous requests to be processed. As their load increases, the number of requests to be processed increases, and the latency of a given request creeps up. Timing out latent requests reduces load on overloaded nodes, and with retries, gracefully rebalances to other nodes. Assuming exponential backoffs, this also gives time for a service to scale horizontally when under pressure. This effect &lt;em&gt;propagates outwards&lt;&#x2F;em&gt; from the point of overload: calling services will be stuck with more requests, they may timeout, scale-up, etc.&lt;&#x2F;p&gt;
&lt;p&gt;There are aspects to be aware of with this approach. If a client has timeouts lower than a service&#x27;s reasonable response time you may see increased load as requests are unnecessarily retried. Ensuring retries and timeouts are properly tuned is important, and having clients developed by the service owners ensures that this is the case. The benefit of trivially getting system-wide backpressure and robustness to network|node failure is well worth it, especially as compared to the complexity of other approaches (looking at you message queues).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;example-kubernetes-readiness-checks-keepalives&quot;&gt;Example: Kubernetes Readiness Checks &amp;amp; Keepalives&lt;&#x2F;h3&gt;
&lt;p&gt;Kubernetes (k8s) has a variety of &lt;a href=&quot;https:&#x2F;&#x2F;kubernetes.io&#x2F;docs&#x2F;concepts&#x2F;configuration&#x2F;liveness-readiness-startup-probes&#x2F;&quot;&gt;health checks&lt;&#x2F;a&gt; with the one relevant to this example being the &lt;em&gt;readiness probe&lt;&#x2F;em&gt;. The readiness probe determines if a Pod is accessible through the Service interface, and on failure a given Pod will be removed from matching service endpoints. This is &lt;em&gt;in theory&lt;&#x2F;em&gt; useful for temporarily removing a given Pod from serving production traffic if it is suffering from a recoverable error that takes time to restart (eg. restarting a connection pool).&lt;&#x2F;p&gt;
&lt;p&gt;However, k8s does &lt;em&gt;not&lt;&#x2F;em&gt; kill all connections to the pod that fails a readiness check, it &lt;em&gt;only&lt;&#x2F;em&gt; removes it from the service abstraction which means new connections won&#x27;t be made. The issue becomes apparent: connections made to the pod with a &lt;code&gt;Keep-Alive&lt;&#x2F;code&gt; set will remain active.&lt;&#x2F;p&gt;
&lt;p&gt;This caused an outage at my current company. Latencies spiked for requests to keep-alive&#x27;d connections to Pods with failing readiness checks which meant the latency spiked all the way through the system despite numerous other Pods being healthy and available to respond. Had we had timeouts and retries in place, this issue &lt;em&gt;would not have caused any problems&lt;&#x2F;em&gt;. The requests would have timed out, retried on healthy pods, and the connection pooling would have cleaned up the connections eventually. A small increase in latency, but not a spike to 10s+.&lt;&#x2F;p&gt;
&lt;p&gt;I love this example because it shows how complicated systems are today. The confluence of two &lt;em&gt;good&lt;&#x2F;em&gt; features, readiness checks in k8s and keep-alive connection pooling behavior, resulted in an outage. And it shows how unreasonably effective retries and timeouts are at preventing unexpected issues in a distributed system. The problem would have still occurred, but the &lt;em&gt;effect&lt;&#x2F;em&gt; would have been mitigated.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Atomic Polling Intervals for Highly Concurrent Workloads</title>
        <published>2024-05-24T00:00:00+00:00</published>
        <updated>2024-05-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.byronwasti.com/polling-atomics/"/>
        <id>https://www.byronwasti.com/polling-atomics/</id>
        
        <content type="html" xml:base="https://www.byronwasti.com/polling-atomics/">&lt;p&gt;One of the problems I&#x27;ve run into while developing &lt;a href=&quot;https:&#x2F;&#x2F;www.balterloadtesting.com&#x2F;balter&#x2F;&quot;&gt;Balter&lt;&#x2F;a&gt; is figuring out how often you are able to poll atomics without affecting data accuracy. For context, Balter is a distributed load testing framework, and under-the-hood it spawns a bunch of concurrent tasks which run the user&#x27;s load test scenario, as well as a Scenario Coordinator task which polls the data collected via atomics. For the purposes of this post, we&#x27;ll just consider Transactions Per Second (TPS).&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#1&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog_images&#x2F;adaptive_sampling&#x2F;ScenarioCoordinator.svg&quot; alt=&quot;tps-sampling&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If you aren&#x27;t familiar with atomics, they are primitive types which provide synchronization across threads at a hardware level, and are a core building block for many concurrent applications. For instance, Rust provides an atomic version of the &lt;code&gt;i32&lt;&#x2F;code&gt; integer type, &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;sync&#x2F;atomic&#x2F;struct.AtomicI32.html&quot;&gt;&lt;code&gt;AtomicI32&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;, which can be shared across threads and updated in a lock-free manner (avoiding the use of a &lt;code&gt;Mutex&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; Achieve the same goal, with the atomic
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; being much faster and lock-free.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; mutex_foo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;Arc::new(Mutex::new(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;));
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; atomic_foo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;Arc::new(AtomicI32::new(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;));
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In Balter, after each transaction we increment an atomic, which is done using the &lt;code&gt;.fetch_add()&lt;&#x2F;code&gt; method call and providing an &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;sync&#x2F;atomic&#x2F;enum.Ordering.html&quot;&gt;&lt;code&gt;Ordering&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. The &lt;code&gt;Ordering&lt;&#x2F;code&gt; is for specifying the kind of memory synchronization, and for this use-case we can use the most lenient option.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;some_transaction&lt;&#x2F;span&gt;&lt;span&gt;().await;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;ATOMIC&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;fetch_add&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, Ordering::Relaxed);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;On the Scenario Coordinator side we have a loop which runs on an interval and polls and resets the atomic:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;loop &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; elapsed &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; interval.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;next&lt;&#x2F;span&gt;&lt;span&gt;().await;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; value &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;ATOMIC&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;swap&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, Ordering::Relaxed);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; tps &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; value &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;f64 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span&gt; elapsed;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The question is: how often can the Scenario Coordinator loop run?&lt;&#x2F;p&gt;
&lt;p&gt;The reason we want to poll as often as possible is to speed up how fast Balter operates. Currently, Balter&#x27;s control loops for error rate matching and latency matching are slow. By polling more often, the control loops would be run more often and Balter would be faster at converging to a specified error rate or latency. However, we don&#x27;t want to provide &lt;em&gt;bad&lt;&#x2F;em&gt; data to the control loops which could lead to instability.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;atomic-experiments&quot;&gt;Atomic Experiments&lt;&#x2F;h1&gt;
&lt;p&gt;In order to understand the constraints involved in the polling intervals for atomics, I set up a &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;sampling-interval-atomics&#x2F;tree&#x2F;main&quot;&gt;repository&lt;&#x2F;a&gt; with code which runs a simple test. It spawns 100 concurrent tasks, each of which runs a simple loop that waits for 10ms (with noise added)&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#2&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; and then increments two atomics: a baseline atomic, and a test atomic. The main function then polls the baseline atomic every 1s (to establish what we &lt;em&gt;should&lt;&#x2F;em&gt; see), and polls the test atomic at varying intervals.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; Task loop
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;loop &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    tokio::sleep(delay_with_noise).await;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;TEST_ATOMIC&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;fetch_add&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, Ordering::Relaxed);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;BASELINE_ATOMIC&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;fetch_add&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, Ordering::Relaxed);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; Sampling loop
&lt;&#x2F;span&gt;&lt;span&gt;tokio::join&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;! &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    async {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;loop &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; Always 1s
&lt;&#x2F;span&gt;&lt;span&gt;            baseline_interval.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;next&lt;&#x2F;span&gt;&lt;span&gt;().await;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; baseline &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;BASELINE_ATOMIC&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;swap&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, Ordering::Relaxed);
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    },
&lt;&#x2F;span&gt;&lt;span&gt;    async {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;loop &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; Varies
&lt;&#x2F;span&gt;&lt;span&gt;            test_interval.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;next&lt;&#x2F;span&gt;&lt;span&gt;().await;
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; test &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;TEST_ATOMIC&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;swap&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;, Ordering::Relaxed);
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With this setup we are able to measure the effects of atomic polling intervals by directly comparing the test intervals with a baseline which is being taken in parallel (to minimize external variability).&lt;&#x2F;p&gt;
&lt;!doctype html&gt;
&lt;html lang=&quot;en&quot;&gt;

&lt;head&gt;
    &lt;meta charset=&quot;utf-8&quot; &#x2F;&gt;
&lt;&#x2F;head&gt;

&lt;body&gt;
    &lt;div&gt;
        &lt;script src=&quot;https:&#x2F;&#x2F;cdn.jsdelivr.net&#x2F;npm&#x2F;mathjax@3.2.2&#x2F;es5&#x2F;tex-svg.js&quot;&gt;&lt;&#x2F;script&gt;
        &lt;script src=&quot;https:&#x2F;&#x2F;cdn.plot.ly&#x2F;plotly-2.12.1.min.js&quot;&gt;&lt;&#x2F;script&gt;
        &lt;div id=&quot;plotly-html-element-0&quot; class=&quot;plotly-graph-div&quot; style=&quot;height:100%; width:100%;&quot;&gt;&lt;&#x2F;div&gt;

        &lt;script type=&quot;module&quot;&gt;
            const graph_div = document.getElementById(&quot;plotly-html-element-0&quot;);
            await Plotly.newPlot(graph_div, {
  &quot;data&quot;: [
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;1s&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        3.000614379
      ],
      &quot;y&quot;: [
        6991.722541058329
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;500ms&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        1.501355964,
        2.000996471,
        2.5012985629999998,
        3.001065984
      ],
      &quot;y&quot;: [
        6967.113506902806,
        6942.171125695903,
        7001.822805875642,
        6991.102240769012
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;200ms&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.601058854,
        0.801233186,
        1.000698425,
        1.200989001,
        1.40094088,
        1.60126324,
        1.801154444,
        2.001105164,
        2.201114602,
        2.400818769,
        2.601252825,
        2.8006289559999997,
        3.001336729
      ],
      &quot;y&quot;: [
        6928.345139696004,
        7001.850222770897,
        6920.8584883993035,
        6900.894090684783,
        6927.4357869501355,
        6901.428624046375,
        6974.76491773583,
        6926.74152851555,
        6941.338341943195,
        6976.463195885024,
        6976.326105680608,
        6923.250470182911,
        6973.416219835337
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;50ms&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.151284083,
        0.202200206,
        0.25146493,
        0.301532927,
        0.35163385,
        0.401659866,
        0.451990567,
        0.501032493,
        0.551567507,
        0.601829902,
        0.652049907,
        0.702092984,
        0.750996278,
        0.80163051,
        0.851877631,
        0.902002939,
        0.951252098,
        1.00127594,
        1.051415762,
        1.102024573,
        1.152108495,
        1.201839703,
        1.2521325349999999,
        1.301480921,
        1.35162862,
        1.4018150440000001,
        1.451207491,
        1.5012861769999999,
        1.551715805,
        1.601034852,
        1.65099347,
        1.70203327,
        1.7512992710000002,
        1.801411208,
        1.851748711,
        1.902239354,
        1.951774442,
        2.002041375,
        2.051556718,
        2.1017355110000002,
        2.152060869,
        2.2014267260000002,
        2.2515679459999998,
        2.3018332519999998,
        2.351059703,
        2.401451764,
        2.451733181,
        2.501888508,
        2.551876417,
        2.602141735,
        2.651128561,
        2.70157692,
        2.751767745,
        2.801937854,
        2.851062821,
        2.9015572450000002,
        2.951585069,
        3.001884695
      ],
      &quot;y&quot;: [
        6844.325199356571,
        6915.752532535168,
        6664.801558545385,
        6753.050865376301,
        6643.003757906554,
        6871.955796173377,
        6674.367001206329,
        6838.866717875213,
        6748.519092753139,
        6675.768994082201,
        6801.249431788271,
        6814.818255995864,
        6490.75402873847,
        6740.263631079185,
        6631.050727769383,
        6749.701715104974,
        6829.059356779095,
        6884.377331278343,
        6710.077301062984,
        7169.780340804456,
        6505.737494336507,
        6809.537712444797,
        6598.653602278852,
        6585.051653028617,
        6856.741347620457,
        6735.556159503992,
        6932.650801168372,
        6805.035593748423,
        6690.49760034475,
        6975.718288830439,
        6687.209670183682,
        6841.8696515822085,
        6569.374682472101,
        6632.862538845039,
        6782.8560241414025,
        6891.429095177183,
        6567.035213833483,
        6898.4136530943415,
        6691.734096555671,
        6629.958987035047,
        6838.242000159662,
        6728.094951387278,
        6709.680241849455,
        6771.810830641313,
        6698.134318901778,
        6783.121921174487,
        6591.599368080186,
        6706.7836399113985,
        6804.712631684442,
        7038.611309222554,
        6552.190830621623,
        6921.786526674665,
        6741.718151790228,
        6661.892695315527,
        6717.302857589595,
        6808.0592602960205,
        6688.057724645607,
        6803.605710580434
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;10ms&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.031828202,
        0.04187173,
        0.051866716,
        0.061900761,
        0.071982145,
        0.081737845,
        0.091789555,
        0.101792436,
        0.111884598,
        0.12185517,
        0.131889571,
        0.141956182,
        0.152105553,
        0.161118958,
        0.171114088,
        0.181127405,
        0.191123282,
        0.201127349,
        0.211054315,
        0.222107781,
        0.232136321,
        0.242134191,
        0.25208868,
        0.262093194,
        0.272116395,
        0.282123111,
        0.291103576,
        0.302138174,
        0.312119967,
        0.322262749,
        0.331260934,
        0.341154682,
        0.351178899,
        0.361130305,
        0.371227937,
        0.381334742,
        0.391499229,
        0.401479389,
        0.411494482,
        0.421446235,
        0.431454221,
        0.441481701,
        0.45148307,
        0.461424714,
        0.471452686,
        0.481473971,
        0.491574478,
        0.501548149,
        0.511592128,
        0.521553285,
        0.531536628,
        0.541616451,
        0.55173495,
        0.561758658,
        0.571808743,
        0.58190489,
        0.591962473,
        0.602052341,
        0.611987548,
        0.622053143,
        0.632114672,
        0.642111934,
        0.652154179,
        0.662142284,
        0.672295253,
        0.681282822,
        0.691433329,
        0.701488124,
        0.711635648,
        0.721780624,
        0.731802354,
        0.741924587,
        0.751964081,
        0.762027593,
        0.772043299,
        0.782078073,
        0.792084181,
        0.802212522,
        0.811127674,
        0.822293877,
        0.831277116,
        0.841321177,
        0.851289601,
        0.861308427,
        0.871263007,
        0.881334396,
        0.891338004,
        0.901483701,
        0.911483205,
        0.921628613,
        0.931715388,
        0.941841628,
        0.951836958,
        0.961897697,
        0.971942884,
        0.981871842,
        0.991746891,
        1.001723885,
        1.011939824,
        1.021945093,
        1.032005636,
        1.041972886,
        1.051935835,
        1.061812678,
        1.071855925,
        1.081843843,
        1.091812568,
        1.101914247,
        1.111981602,
        1.122276174,
        1.131311683,
        1.141309003,
        1.151483473,
        1.161615319,
        1.171712869,
        1.18178035,
        1.19173044,
        1.20180393,
        1.2117741340000001,
        1.221736494,
        1.231727397,
        1.241786801,
        1.251872689,
        1.26180281,
        1.271742543,
        1.281728618,
        1.2917665870000001,
        1.301782796,
        1.311886618,
        1.321873833,
        1.331964578,
        1.341993983,
        1.352059624,
        1.361067497,
        1.3720768859999999,
        1.381084181,
        1.391299131,
        1.401489892,
        1.411619511,
        1.42171503,
        1.431758997,
        1.441755506,
        1.4519161569999999,
        1.462020727,
        1.472031782,
        1.482103004,
        1.492111,
        1.502301898,
        1.511357394,
        1.521488827,
        1.531564394,
        1.541667641,
        1.551802995,
        1.56182953,
        1.571950878,
        1.582063873,
        1.591086169,
        1.601130687,
        1.611300097,
        1.621266842,
        1.631480914,
        1.641487402,
        1.651595558,
        1.661610466,
        1.671708979,
        1.6818067380000001,
        1.6918179439999999,
        1.701938104,
        1.7118723519999999,
        1.721838069,
        1.7319986219999999,
        1.741360082,
        1.75150621,
        1.761573237,
        1.771616863,
        1.781660836,
        1.7916906670000001,
        1.801685813,
        1.8116973299999999,
        1.821836361,
        1.831896213,
        1.84194299,
        1.851952298,
        1.862018068,
        1.872086211,
        1.882130563,
        1.892277421,
        1.901266615,
        1.911488006,
        1.9214718149999999,
        1.931485983,
        1.9414835510000001,
        1.951601981,
        1.961721481,
        1.9717724030000001,
        1.9818014659999998,
        1.9918491999999999,
        2.001865783,
        2.011845323,
        2.021848641,
        2.031929448,
        2.041953808,
        2.051932276,
        2.061978129,
        2.072035642,
        2.082064743,
        2.091957416,
        2.102021637,
        2.112067804,
        2.122267454,
        2.131241088,
        2.141356961,
        2.1514472319999998,
        2.161451176,
        2.171513393,
        2.181606144,
        2.191739611,
        2.201636154,
        2.211692092,
        2.22179835,
        2.231791546,
        2.2417440060000002,
        2.251831813,
        2.261993891,
        2.272015198,
        2.282033437,
        2.292095002,
        2.301088401,
        2.311126057,
        2.321294786,
        2.331327638,
        2.341361225,
        2.351340747,
        2.361449789,
        2.371481301,
        2.3814011600000002,
        2.391409603,
        2.401528923,
        2.411622038,
        2.421700516,
        2.431802026,
        2.441868978,
        2.451868549,
        2.461856484,
        2.471983767,
        2.481958521,
        2.491946234,
        2.501962451,
        2.5120529830000002,
        2.52213903,
        2.532111451,
        2.542278478,
        2.551290239,
        2.561477384,
        2.571600572,
        2.58156632,
        2.59159844,
        2.601625204,
        2.611660738,
        2.621747751,
        2.631779512,
        2.641808111,
        2.651841149,
        2.661809356,
        2.671801347,
        2.681889612,
        2.691970032,
        2.702051249,
        2.712102186,
        2.722151911,
        2.732100697,
        2.7411061180000003,
        2.75127273,
        2.761380851,
        2.7714429689999998,
        2.781479702,
        2.791624541,
        2.801512773,
        2.811469557,
        2.821506765,
        2.8312849890000003,
        2.842004047,
        2.8517450540000002,
        2.861330458,
        2.871956863,
        2.881574576,
        2.89125795,
        2.9019486580000002,
        2.911561986,
        2.92129167,
        2.932031832,
        2.941709352,
        2.951658682,
        2.961429435,
        2.971202822,
        2.982090045,
        2.991929627,
        3.001671666
      ],
      &quot;y&quot;: [
        6087.517705587521,
        5728.26798320236,
        5730.69524710463,
        6554.648838470007,
        6009.321459136698,
        5197.223557974944,
        6107.474760224358,
        6190.834071569095,
        6226.925664139488,
        5820.627494012346,
        5719.675186375195,
        5604.1879176217835,
        6361.09875837135,
        5846.257985651125,
        5938.851426134186,
        5931.736497884796,
        6832.959933051377,
        6291.2181514945105,
        6513.7633104682145,
        6277.344131686786,
        5356.163003037439,
        5604.392525059053,
        5211.784158343599,
        6533.005778898441,
        5942.729911839601,
        5197.002270100086,
        6304.708545483023,
        6179.2364144544035,
        5115.834456547794,
        6524.224363508904,
        5062.055471602402,
        6186.172595291265,
        6709.531327606912,
        5301.200272607485,
        6947.48458749533,
        6176.117641277147,
        6609.589958432636,
        5924.000303169428,
        6264.238091161368,
        5679.098767216188,
        6198.9844317308025,
        5748.656708773835,
        6444.64291235155,
        6127.491744517908,
        5763.173895127525,
        6188.29410085612,
        5788.975595838954,
        6148.576098025276,
        5952.710631489425,
        6318.9293483106385,
        5981.406148833509,
        6284.619212339204,
        5709.805525728213,
        6038.504566895489,
        6097.536188877281,
        5964.344643690891,
        6019.1836398588675,
        5393.493074215544,
        6090.046086632325,
        5973.907465666834,
        6026.109895937338,
        5614.674314623724,
        6088.830607991952,
        5683.009629653911,
        5693.572265991334,
        5052.237476433971,
        6297.757447294986,
        6093.616049261488,
        5758.560078068885,
        6366.797304858299,
        5677.230948399224,
        5870.607286648084,
        5767.6499701837565,
        5820.329262678195,
        5314.496984521195,
        6210.003437857903,
        6124.098567862998,
        5895.965202668481,
        5392.335065321399,
        6182.311317282155,
        5941.585172357405,
        6095.182367856446,
        5935.050878002195,
        6190.480191126654,
        6659.363860271629,
        6352.7709595781125,
        6262.4902501406195,
        6183.053747544522,
        6270.401666254736,
        5762.057470761213,
        5804.688122216684,
        6249.526007233572,
        6083.026724848564,
        5463.581071431783,
        5359.203099897053,
        6402.125775320596,
        6299.915121413837,
        5971.00174472671,
        5444.336144034687,
        6027.971293796038,
        6247.499438349801,
        5596.364935449272,
        5781.302379961101,
        6095.474947978931,
        6157.590280184697,
        5488.362981751616,
        5756.889112579776,
        6127.442236895815,
        5341.8058826136485,
        6191.193337037731,
        5658.230333649045,
        6367.003640334332,
        5573.569506374204,
        5854.763129629191,
        5891.365273526698,
        6197.189124798995,
        5882.508403887912,
        6523.692738816506,
        5096.245137545108,
        6390.768390202936,
        5372.415409827035,
        6872.63996937348,
        5727.827453578065,
        5761.750921541221,
        6131.978574866859,
        6480.332659350314,
        5694.4844498503335,
        5771.496767240374,
        6225.920830517647,
        5137.72211593969,
        6352.508910856496,
        6086.822096865187,
        6385.380431014838,
        5150.600392837196,
        5796.5887572014335,
        6586.461015098154,
        6195.576287723979,
        5744.543793137934,
        6799.411257053636,
        5719.583829421864,
        5783.221225306389,
        5955.0526239493165,
        6378.331933597201,
        5657.294886246359,
        5319.614048701732,
        6527.752242881961,
        5615.125894012682,
        6178.292180216881,
        5195.204984297273,
        6615.547057866016,
        5967.027761207505,
        6085.615003252376,
        5592.188153745859,
        6171.388243640659,
        6025.129812258629,
        5968.622949156285,
        5773.401739724405,
        6558.954261896169,
        6018.069785537234,
        5947.008778850093,
        6358.772575711423,
        6094.023469303184,
        5692.213724341269,
        5684.869100720893,
        7003.620530174074,
        4658.685237710685,
        6008.1746716849875,
        6115.297995958207,
        5727.989085822208,
        5829.031465872162,
        5667.69299140586,
        5898.25181098339,
        6344.775629177937,
        6048.85922835567,
        5940.051962541516,
        6174.930109653895,
        6073.659633140693,
        5990.568278143797,
        5984.641017293218,
        5660.893231498089,
        6557.128986293078,
        6280.216739490665,
        5354.960232726571,
        5991.3654438345275,
        6371.271358239212,
        5606.039221169459,
        5050.192807401367,
        6035.934581475841,
        6006.608836661763,
        5841.030343803918,
        6617.174842476411,
        6531.509700990099,
        5516.662129786717,
        5887.021404356635,
        6371.2361285447005,
        5762.381748299844,
        6161.125760899032,
        5646.7734210251965,
        5741.055920333056,
        5823.8389987048295,
        6371.169051677474,
        5270.630565691758,
        6118.262493911072,
        6428.826792544764,
        5816.437551652042,
        5139.287540568252,
        6021.759124784147,
        6155.963498131249,
        5055.110650571194,
        6358.697552871551,
        5515.832173155139,
        5811.8129677573825,
        5940.693532288325,
        6724.618908423179,
        5559.134248227852,
        6893.383144919939,
        5281.637348468121,
        6703.689366848572,
        5645.215645526988,
        6272.518553516535,
        5936.860806821081,
        5705.422723285124,
        5494.043864784312,
        6587.166515314703,
        5243.741594407075,
        6066.86936658975,
        5870.632590428207,
        5772.269189052098,
        6022.369597496276,
        6463.574085530439,
        5915.195519283538,
        6073.658157266199,
        6349.233784167145,
        5153.26914223311,
        6620.0793102922635,
        6842.141874618803,
        5434.432476519089,
        6419.097683052715,
        5937.375659306845,
        5812.0189646178815,
        5846.771870146756,
        6235.100532148978,
        4971.390071443088,
        6410.441326833146,
        6509.245298071694,
        5519.421002701506,
        6111.129807261664,
        5517.64958159914,
        5725.119584472481,
        6261.222830000221,
        5945.17017265187,
        5619.971652537189,
        6023.26823951916,
        5227.97545430671,
        6293.240706025743,
        6225.403172672971,
        6380.5963650259855,
        6021.815661727431,
        5574.6021127742015,
        6299.502169071828,
        5858.006506801952,
        5759.131929432001,
        6503.138355450901,
        5843.185169352443,
        5677.695689408691,
        5803.7924503258455,
        5681.235247586561,
        5891.887841359177,
        5949.702700793169,
        6172.265460084783,
        5702.509029592468,
        5312.737441093898,
        6653.669831595616,
        5184.491901779713,
        6729.483922869626,
        6446.584342623065,
        5764.046271010486,
        5733.17640645024,
        6277.934629261802,
        6605.216139185115,
        5051.25607014759,
        6581.445007070054,
        5619.665149697662,
        5737.085269415731,
        6356.522988616303,
        5788.817542432681,
        6395.819692249146,
        6026.278592180971,
        5016.6774251332245,
        6642.352115336739,
        6483.1357431481365,
        5038.956686580224,
        6776.402644581199,
        6212.400756897909,
        6070.320737893906,
        6451.966720755654,
        5197.459883992695,
        5826.360408030301
      ]
    }
  ],
  &quot;layout&quot;: {
    &quot;title&quot;: {
      &quot;text&quot;: &quot;100 Tasks, 10ms Delay with SkewNormal Noise&quot;
    },
    &quot;legend&quot;: {
      &quot;title&quot;: {
        &quot;text&quot;: &quot;Polling Interval&quot;
      }
    },
    &quot;xaxis&quot;: {
      &quot;title&quot;: {
        &quot;text&quot;: &quot;Time (s)&quot;
      }
    },
    &quot;yaxis&quot;: {
      &quot;title&quot;: {
        &quot;text&quot;: &quot;Measured TPS&quot;
      }
    }
  },
  &quot;config&quot;: {}
});
        &lt;&#x2F;script&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;body&gt;

&lt;&#x2F;html&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Interval&lt;&#x2F;th&gt;&lt;th&gt;Mean TPS (μ)&lt;&#x2F;th&gt;&lt;th&gt;Std (σ)&lt;&#x2F;th&gt;&lt;th&gt;Error&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1s&lt;&#x2F;td&gt;&lt;td&gt;6961.83&lt;&#x2F;td&gt;&lt;td&gt;21.28&lt;&#x2F;td&gt;&lt;td&gt;0.00%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;500ms&lt;&#x2F;td&gt;&lt;td&gt;6972.42&lt;&#x2F;td&gt;&lt;td&gt;19.43&lt;&#x2F;td&gt;&lt;td&gt;0.11%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;200ms&lt;&#x2F;td&gt;&lt;td&gt;6945.46&lt;&#x2F;td&gt;&lt;td&gt;29.87&lt;&#x2F;td&gt;&lt;td&gt;0.40%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;50ms&lt;&#x2F;td&gt;&lt;td&gt;6749.78&lt;&#x2F;td&gt;&lt;td&gt;130.69&lt;&#x2F;td&gt;&lt;td&gt;2.98%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;10ms&lt;&#x2F;td&gt;&lt;td&gt;5965.96&lt;&#x2F;td&gt;&lt;td&gt;428.99&lt;&#x2F;td&gt;&lt;td&gt;14.48%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The fact that we get more noise when polling more often is not surprising, but what is surprising is just how far off the mean TPS is for the &lt;code&gt;10ms&lt;&#x2F;code&gt; interval. Initially I thought it had to do with how close the polling interval was to the latency of each atomic update (both being 10ms). However, repeating this with a &lt;code&gt;10us&lt;&#x2F;code&gt; delay had a similar issue (though the error was lower):&lt;&#x2F;p&gt;
&lt;!doctype html&gt;
&lt;html lang=&quot;en&quot;&gt;

&lt;head&gt;
    &lt;meta charset=&quot;utf-8&quot; &#x2F;&gt;
&lt;&#x2F;head&gt;

&lt;body&gt;
    &lt;div&gt;
        &lt;script src=&quot;https:&#x2F;&#x2F;cdn.jsdelivr.net&#x2F;npm&#x2F;mathjax@3.2.2&#x2F;es5&#x2F;tex-svg.js&quot;&gt;&lt;&#x2F;script&gt;
        &lt;script src=&quot;https:&#x2F;&#x2F;cdn.plot.ly&#x2F;plotly-2.12.1.min.js&quot;&gt;&lt;&#x2F;script&gt;
        &lt;div id=&quot;plotly-html-element&quot; class=&quot;plotly-graph-div&quot; style=&quot;height:100%; width:100%;&quot;&gt;&lt;&#x2F;div&gt;

        &lt;script type=&quot;module&quot;&gt;
            const graph_div = document.getElementById(&quot;plotly-html-element&quot;);
            await Plotly.newPlot(graph_div, {
  &quot;data&quot;: [
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;1s&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        3.000583724
      ],
      &quot;y&quot;: [
        85094.43640513808
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;500ms&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        1.501755083,
        2.001352923,
        2.500763065,
        3.001500886
      ],
      &quot;y&quot;: [
        85838.81374896882,
        85805.90258442855,
        86699.79010287549,
        86396.73273590668
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;200ms&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.601396483,
        0.800911255,
        1.000569352,
        1.200562692,
        1.400356314,
        1.6005644879999998,
        1.800787538,
        2.000367825,
        2.201168627,
        2.4007458919999998,
        2.600366636,
        2.800922984,
        3.000440867
      ],
      &quot;y&quot;: [
        84803.1023307551,
        86157.6754247047,
        83532.33380386126,
        86641.48414503969,
        84409.83448240663,
        85274.54922169585,
        85543.38379076491,
        85912.1818992166,
        87459.13936001433,
        86074.21002665166,
        86736.27868155227,
        86993.80198401015,
        85930.73755054493
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;50ms&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.151776919,
        0.200944152,
        0.251766983,
        0.300931744,
        0.351170093,
        0.401652688,
        0.45096256,
        0.500991208,
        0.551483813,
        0.601527814,
        0.651066941,
        0.701558007,
        0.751269932,
        0.801532634,
        0.851494386,
        0.901001992,
        0.950946367,
        1.001814887,
        1.051039548,
        1.100915218,
        1.151719491,
        1.201688518,
        1.251492792,
        1.301365782,
        1.351654908,
        1.401225924,
        1.451625607,
        1.5016743259999998,
        1.551525515,
        1.60177975,
        1.651821032,
        1.7013273500000001,
        1.751028364,
        1.8012635700000001,
        1.851864766,
        1.901782713,
        1.950844139,
        2.001494051,
        2.050960772,
        2.101148546,
        2.151480087,
        2.201328199,
        2.251213873,
        2.300817409,
        2.351277181,
        2.401522236,
        2.450947686,
        2.501328247,
        2.551261374,
        2.60145286,
        2.650876059,
        2.701352826,
        2.751129405,
        2.801238878,
        2.850850281,
        2.901542473,
        2.95166102,
        3.001604717
      ],
      &quot;y&quot;: [
        85366.8690447314,
        83877.00933333422,
        83799.21615086362,
        86665.65458564981,
        83897.43430193797,
        85746.60463096328,
        84533.71503013573,
        87368.7309331963,
        86319.09878820727,
        88205.76547816141,
        85163.37994244765,
        84119.7586839395,
        85723.73496928418,
        81425.24292365446,
        85718.75946894684,
        82350.64504672047,
        84442.74189312384,
        87504.55423184492,
        82231.39444166323,
        82903.40327603374,
        83199.91956503244,
        81315.03691476317,
        82692.02348235958,
        78496.82015845066,
        84871.48213853136,
        85582.50126768104,
        84396.96855076846,
        82479.06924286227,
        80504.39379706272,
        82562.11307096723,
        82014.18343639623,
        80620.75880110112,
        81308.69808469512,
        83081.13296915876,
        87015.8154570591,
        85106.26628729138,
        82744.00276109677,
        87331.19198105071,
        88303.99635826469,
        84441.20956255347,
        83023.3393875232,
        82859.82634544252,
        80232.92972661484,
        82827.09885423104,
        85828.6319518681,
        83265.93935712523,
        83694.67718537078,
        83755.92506441745,
        84196.98810050366,
        83125.50176307886,
        83910.62427617505,
        85176.39419775443,
        82653.81893306007,
        86516.99986836067,
        85663.88022411763,
        85522.3853000368,
        84726.30056129576,
        86253.08220089263
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;10ms&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.030695281,
        0.040130063,
        0.050653795,
        0.061009694,
        0.070651585,
        0.080289903,
        0.090626371,
        0.101138187,
        0.110758197,
        0.120262467,
        0.130893447,
        0.140517508,
        0.151200106,
        0.160660006,
        0.170507339,
        0.180202225,
        0.191089433,
        0.200760913,
        0.210539847,
        0.220356014,
        0.231212138,
        0.240904109,
        0.25075827,
        0.260617672,
        0.27113659,
        0.280676247,
        0.290459926,
        0.300175824,
        0.310825514,
        0.320314208,
        0.330983186,
        0.340665858,
        0.350152467,
        0.361063803,
        0.370859185,
        0.380537273,
        0.391216669,
        0.400662843,
        0.410273018,
        0.421129279,
        0.430431521,
        0.440795212,
        0.450310224,
        0.460929732,
        0.471229168,
        0.480293858,
        0.490737331,
        0.500257404,
        0.510688336,
        0.520223547,
        0.530487376,
        0.541014869,
        0.55021793,
        0.560584778,
        0.570151484,
        0.580442388,
        0.591008872,
        0.600227421,
        0.610917155,
        0.620142852,
        0.630393672,
        0.640761665,
        0.650254915,
        0.660828505,
        0.670960631,
        0.680498446,
        0.691158855,
        0.700475563,
        0.710195716,
        0.720613567,
        0.730890147,
        0.74018347,
        0.750802065,
        0.761015646,
        0.770137149,
        0.78092145,
        0.790338399,
        0.800786888,
        0.810114732,
        0.820760088,
        0.831197506,
        0.840303993,
        0.850706614,
        0.860878314,
        0.870517223,
        0.881190713,
        0.890472659,
        0.900570675,
        0.911167001,
        0.920287761,
        0.930847813,
        0.940253909,
        0.951003687,
        0.960306262,
        0.971145184,
        0.980731921,
        0.990271782,
        1.001174381,
        1.010371531,
        1.020243452,
        1.030904352,
        1.040551087,
        1.050405429,
        1.060302367,
        1.071206228,
        1.080808331,
        1.090516801,
        1.10032575,
        1.1102208199999999,
        1.121131709,
        1.130873237,
        1.140669909,
        1.150394316,
        1.161278729,
        1.170879721,
        1.180498816,
        1.190303093,
        1.201219998,
        1.210838487,
        1.220550458,
        1.230345614,
        1.241167016,
        1.250753672,
        1.260509973,
        1.270229771,
        1.281040645,
        1.290725178,
        1.300443604,
        1.310233684,
        1.321166167,
        1.330863087,
        1.340586085,
        1.350425833,
        1.360202392,
        1.370915075,
        1.380638443,
        1.390357456,
        1.401287238,
        1.410872802,
        1.4207297190000001,
        1.430447677,
        1.440118316,
        1.450862153,
        1.460678863,
        1.470495127,
        1.481127273,
        1.490632864,
        1.5012275370000001,
        1.510500973,
        1.5202612979999999,
        1.5305710829999999,
        1.540858533,
        1.550135531,
        1.560983302,
        1.570631122,
        1.580348699,
        1.5910311510000001,
        1.600735293,
        1.610363547,
        1.620120225,
        1.6310126299999999,
        1.640732289,
        1.6501692700000001,
        1.6610522680000002,
        1.670617745,
        1.680333539,
        1.69093228,
        1.7005167650000002,
        1.710118561,
        1.721110855,
        1.730929756,
        1.7407717900000002,
        1.7506053929999998,
        1.760348494,
        1.771099062,
        1.780687682,
        1.7904645019999998,
        1.800242248,
        1.8101260890000002,
        1.820899835,
        1.830641978,
        1.8404366890000001,
        1.850314587,
        1.861256196,
        1.870830843,
        1.880585894,
        1.890299218,
        1.9001298389999999,
        1.911123999,
        1.92079305,
        1.930587244,
        1.940373509,
        1.95115873,
        1.96080718,
        1.970233028,
        1.980813073,
        1.990306057,
        2.000191571,
        2.010429338,
        2.021066055,
        2.030149215,
        2.040478363,
        2.051264576,
        2.060505763,
        2.070229631,
        2.080708643,
        2.090406639,
        2.100851419,
        2.110245564,
        2.120775435,
        2.130239408,
        2.140899817,
        2.150303655,
        2.161217966,
        2.170830341,
        2.180366129,
        2.190320637,
        2.201023103,
        2.210190871,
        2.220685012,
        2.230156537,
        2.240144726,
        2.250709409,
        2.26018814,
        2.271092362,
        2.280679488,
        2.290112462,
        2.300769821,
        2.310398568,
        2.32021744,
        2.330910099,
        2.340542612,
        2.350379515,
        2.36013512,
        2.371148495,
        2.38092067,
        2.39069686,
        2.400455572,
        2.410275453,
        2.420130099,
        2.43096611,
        2.440707572,
        2.450303306,
        2.461289945,
        2.470873794,
        2.480567708,
        2.49080109,
        2.501224589,
        2.510489347,
        2.520822261,
        2.5301330589999997,
        2.540831222,
        2.550288279,
        2.561118433,
        2.570717054,
        2.580360879,
        2.590139721,
        2.600873308,
        2.610541215,
        2.620160875,
        2.631114668,
        2.640813151,
        2.650671367,
        2.660487833,
        2.670234946,
        2.681125699,
        2.690799874,
        2.700586246,
        2.710207916,
        2.721114782,
        2.730822064,
        2.740596794,
        2.750123831,
        2.761013125,
        2.770593497,
        2.780293548,
        2.791108931,
        2.80076462,
        2.810728063,
        2.820329976,
        2.830114812,
        2.841214928,
        2.850691589,
        2.8601033300000003,
        2.870623258,
        2.880307522,
        2.891040723,
        2.9006351820000003,
        2.91077809,
        2.920127025,
        2.93065643,
        2.94111233,
        2.950546358,
        2.961059969,
        2.970211995,
        2.980905864,
        2.991261032,
        3.000796684
      ],
      &quot;y&quot;: [
        76299.3684263676,
        88649.78674691611,
        79507.95558293225,
        88744.0321455046,
        75109.79643930744,
        93492.74916109208,
        84793.10482422888,
        71917.3516098578,
        83568.3518935947,
        77958.11330061886,
        82622.29200847815,
        80345.92295310917,
        71520.72435761041,
        78427.40666364651,
        83374.0924144709,
        82142.77767469088,
        75842.38023509695,
        80666.18372280942,
        79606.59351336252,
        80054.37130665923,
        83129.10806748371,
        75479.67886193887,
        75759.18136208873,
        78834.88631152287,
        73185.39287804655,
        75404.06509403448,
        78971.24748661576,
        88351.43784348587,
        89791.70817916551,
        73591.0513281585,
        84678.5461258154,
        94324.6295578322,
        69149.9306432106,
        81169.35207965731,
        82883.41453145177,
        82568.04461028072,
        73821.9777656762,
        82439.8055771138,
        77877.82157431768,
        84825.23306271929,
        73147.43339748833,
        77630.54530362991,
        81184.93141716204,
        91496.21379517694,
        80151.09728633321,
        68003.98114735346,
        83822.12498027852,
        87744.8263456766,
        85423.70344033907,
        75221.75010004296,
        95356.01884807069,
        81710.4132113754,
        87887.61816137929,
        85125.90603347101,
        75952.28502104696,
        85903.19887423715,
        81936.28336655295,
        78125.71042817876,
        82625.9743819174,
        89327.01852441231,
        88229.85792683696,
        83633.82657466698,
        76747.60239319893,
        93646.10269671222,
        82571.06403354082,
        80491.80588653246,
        76623.89559649194,
        80763.59207817992,
        85333.47143623883,
        84801.44260445205,
        76034.94301511608,
        85142.49681992283,
        80732.5703056163,
        83066.17496332833,
        79316.4578690509,
        91108.9562393153,
        85896.73336077256,
        83438.85257856648,
        84535.27498830596,
        87177.30572123839,
        80556.05468952339,
        77642.7807063125,
        85090.20636009597,
        73636.32828490878,
        92803.1005363753,
        74261.53339253404,
        86895.8150688993,
        79752.92675739074,
        87761.42718707521,
        74070.86988071383,
        80756.41845284161,
        84947.77174972612,
        87974.69527855807,
        81993.31671990249,
        88741.46300844866,
        74547.7282511662,
        72045.99026580785,
        86091.8677192188,
        73762.86655805686,
        87767.18713877798,
        82540.06976470118,
        66536.30479541935,
        83326.50158536599,
        81830.42328946265,
        77192.93298252343,
        75315.87096929397,
        77593.21074620326,
        78254.86991290079,
        92267.76555651161,
        80045.45791437113,
        80476.75348498832,
        75918.6437068693,
        75621.97632358663,
        82372.42515237126,
        76476.47861112832,
        79442.10685039575,
        78815.49244686481,
        83872.13679376163,
        76213.5625817612,
        84265.67441070426,
        77621.73199700224,
        83284.73564529371,
        74954.46702119695,
        74313.80101485438,
        79380.27079621344,
        82697.70979879094,
        75992.97172240914,
        76605.93571517148,
        83747.45325167321,
        78096.58559399215,
        78434.7733386949,
        75574.52938087362,
        80189.93888682552,
        85277.66407422567,
        82458.78160370236,
        78116.37817501716,
        77532.47819097321,
        80450.04535061202,
        74961.0294623519,
        77172.35279956224,
        75331.23248213826,
        81539.66657689067,
        92158.69450994728,
        75480.56820198451,
        77087.18312665424,
        74325.3669781292,
        85023.46468925664,
        83101.989744876,
        70092.87496402502,
        84204.41205779892,
        85140.71300238697,
        82886.94874077686,
        69264.780013776,
        82857.45685698722,
        81180.16201415601,
        86683.16578131297,
        75788.4674973542,
        86076.33331215582,
        67643.93007180872,
        89132.14344227547,
        74466.16162262857,
        85820.43309034627,
        69329.96668326324,
        81074.18957932449,
        86557.84051091543,
        78099.43713242094,
        82969.16547472816,
        76072.46967751358,
        79561.0208321391,
        75245.87896052319,
        81341.4737025486,
        74271.95381472824,
        78737.97454245693,
        77407.07744215705,
        79200.38427053337,
        69522.08107378773,
        85627.42684708443,
        74400.98420199574,
        87403.21205322885,
        85326.2283192247,
        73391.6469593023,
        79723.10020906232,
        79697.03492126282,
        82803.0282098012,
        79591.7515614572,
        75575.9715645407,
        77680.37090823501,
        78880.29860388782,
        82439.19322865862,
        74125.26168533789,
        76133.00984675634,
        74520.56907492789,
        76714.65544768603,
        83189.4328877347,
        78768.69864825682,
        83236.4476496848,
        67924.46605304998,
        92530.22981251394,
        90900.83591373128,
        81332.2805923918,
        81881.05313814309,
        76350.8857657135,
        90642.32113944055,
        66632.99479329778,
        86811.63166372146,
        85169.20281626163,
        76878.05890589069,
        79440.55418172957,
        78183.61025558134,
        84640.45763759017,
        76961.3021383522,
        84500.46736740583,
        77646.3526984631,
        88701.47371926883,
        73592.79857992676,
        77468.18160857132,
        75099.21332847272,
        81558.33575634469,
        80761.04181547683,
        88538.4123808522,
        78870.13072945713,
        90987.70256346762,
        81053.62238723462,
        86477.48351111932,
        81862.21021295985,
        84184.27497674398,
        80697.00056369229,
        85892.78352047128,
        71647.8702406099,
        87110.29886466896,
        83138.46514293812,
        66969.23607831947,
        92205.2637547467,
        80911.57746000797,
        80911.5484281631,
        81409.83146882842,
        76755.17632328121,
        69726.48280682667,
        79417.70471738245,
        87960.73259147521,
        84172.06740367837,
        76492.30033548271,
        69106.79659520907,
        85212.6471866894,
        68424.3571950097,
        85452.00847706635,
        83328.01731445096,
        86064.08620520993,
        83422.27737096838,
        83165.10111444007,
        69183.06153897474,
        92976.30923015616,
        80679.00225930367,
        76456.60858093206,
        79970.5126231168,
        71233.21784478976,
        92216.95780102698,
        82775.73909307773,
        77698.51496222941,
        70470.29770452848,
        80438.83252122204,
        75189.0825082264,
        81904.94022673048,
        77807.5807086783,
        81196.24840111299,
        80807.54330776464,
        77504.03308023991,
        84548.51752912768,
        68675.96943576471,
        80977.16039191146,
        87141.93489841357,
        78423.91153556283,
        82088.51354495047,
        88171.19413489939,
        75521.93444903774,
        77722.36928481916,
        77239.21479946567,
        80360.25922268681,
        74574.94842909269,
        67768.07209903277,
        90070.02227428685,
        86763.6945746742,
        66036.08132913982,
        88983.46144873192,
        79639.72719533827,
        77034.32966016703,
        88313.7134983571,
        88576.76601337697,
        75990.05578727832,
        87001.3298069321,
        75920.11852172174,
        89273.17149511234,
        77186.56305208187,
        79298.16153948745,
        70900.60811960815,
        91605.01056483614,
        79925.05516382905,
        79193.69518152214
      ]
    }
  ],
  &quot;layout&quot;: {
    &quot;title&quot;: {
      &quot;text&quot;: &quot;100 Tasks, 10µs Delay with SkewNormal Noise&quot;
    },
    &quot;legend&quot;: {
      &quot;title&quot;: {
        &quot;text&quot;: &quot;Polling Interval&quot;
      }
    },
    &quot;xaxis&quot;: {
      &quot;title&quot;: {
        &quot;text&quot;: &quot;Time (s)&quot;
      }
    },
    &quot;yaxis&quot;: {
      &quot;title&quot;: {
        &quot;text&quot;: &quot;Measured TPS&quot;
      }
    }
  },
  &quot;config&quot;: {}
});
        &lt;&#x2F;script&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;body&gt;

&lt;&#x2F;html&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Interval&lt;&#x2F;th&gt;&lt;th&gt;Mean TPS (μ)&lt;&#x2F;th&gt;&lt;th&gt;Std (σ)&lt;&#x2F;th&gt;&lt;th&gt;Error&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1s&lt;&#x2F;td&gt;&lt;td&gt;86135.64&lt;&#x2F;td&gt;&lt;td&gt;1052.31&lt;&#x2F;td&gt;&lt;td&gt;0.00%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;500ms&lt;&#x2F;td&gt;&lt;td&gt;85767.45&lt;&#x2F;td&gt;&lt;td&gt;792.22&lt;&#x2F;td&gt;&lt;td&gt;0.12%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;200ms&lt;&#x2F;td&gt;&lt;td&gt;85747.23&lt;&#x2F;td&gt;&lt;td&gt;1017.96&lt;&#x2F;td&gt;&lt;td&gt;0.33%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;50ms&lt;&#x2F;td&gt;&lt;td&gt;84122.80&lt;&#x2F;td&gt;&lt;td&gt;2059.60&lt;&#x2F;td&gt;&lt;td&gt;2.46%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;10ms&lt;&#x2F;td&gt;&lt;td&gt;80539.52&lt;&#x2F;td&gt;&lt;td&gt;5925.21&lt;&#x2F;td&gt;&lt;td&gt;5.91%&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;It would seem that the smaller the polling interval is, the higher the error in measured TPS. I decided to plot out what the relationship is between the polling interval and the error in measurement, and did this for a wide range of concurrent tasks, latency per task, and polling intervals.&lt;&#x2F;p&gt;
&lt;!doctype html&gt;
&lt;html lang=&quot;en&quot;&gt;

&lt;head&gt;
    &lt;meta charset=&quot;utf-8&quot; &#x2F;&gt;
&lt;&#x2F;head&gt;

&lt;body&gt;
    &lt;div&gt;
        &lt;script src=&quot;https:&#x2F;&#x2F;cdn.jsdelivr.net&#x2F;npm&#x2F;mathjax@3.2.2&#x2F;es5&#x2F;tex-svg.js&quot;&gt;&lt;&#x2F;script&gt;
        &lt;script src=&quot;https:&#x2F;&#x2F;cdn.plot.ly&#x2F;plotly-2.12.1.min.js&quot;&gt;&lt;&#x2F;script&gt;
        &lt;div id=&quot;plotly-html-element-2&quot; class=&quot;plotly-graph-div&quot; style=&quot;height:100%; width:100%;&quot;&gt;&lt;&#x2F;div&gt;

        &lt;script type=&quot;module&quot;&gt;
            const graph_div = document.getElementById(&quot;plotly-html-element-2&quot;);
            await Plotly.newPlot(graph_div, {
  &quot;data&quot;: [
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;100 Tasks, 500ms Delay&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.5,
        0.35,
        0.2,
        0.1,
        0.05,
        0.025,
        0.01,
        0.001,
        0.0005,
        0.0001
      ],
      &quot;y&quot;: [
        0.11351790037846297,
        0.05130716518726367,
        0.4089199860756375,
        1.19684034022259,
        3.005477272634529,
        2.7847736824609237,
        9.702982553869676,
        48.09277754514595,
        76.04489947355735,
        94.20988772546043
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;500 Tasks, 500ms Delay&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.5,
        0.35,
        0.2,
        0.1,
        0.05,
        0.025,
        0.01,
        0.001,
        0.0005,
        0.0001
      ],
      &quot;y&quot;: [
        0.15135872599334152,
        0.339837581150195,
        0.4989592851071975,
        1.1852026352764564,
        2.822453784868588,
        6.011552513587567,
        14.442598349647318,
        48.59495716943095,
        76.55587230382088,
        94.15828975934441
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;100 Tasks, 100ms Delay&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.5,
        0.35,
        0.2,
        0.1,
        0.05,
        0.025,
        0.01,
        0.001,
        0.0005,
        0.0001
      ],
      &quot;y&quot;: [
        0.11315048736773527,
        0.28115495088558606,
        0.6680679265085946,
        1.3564020698688297,
        2.338980984063709,
        4.931275323133434,
        13.9738206524226,
        50.507559162778925,
        71.34178699502104,
        94.10051097861856
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;500 Tasks, 100ms Delay&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.5,
        0.35,
        0.2,
        0.1,
        0.05,
        0.025,
        0.01,
        0.001,
        0.0005,
        0.0001
      ],
      &quot;y&quot;: [
        0.09017030432371578,
        0.19780232273838855,
        0.5893947718612634,
        1.0381773401860612,
        2.683744082490861,
        3.1344034634877413,
        12.454237261067556,
        57.59566608250984,
        71.43404178801381,
        94.3341871349802
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;100 Tasks, 10ms Delay&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.5,
        0.35,
        0.2,
        0.1,
        0.05,
        0.025,
        0.01,
        0.001,
        0.0005,
        0.0001
      ],
      &quot;y&quot;: [
        0.15173760438089662,
        0.24138657677376738,
        0.5729707094017205,
        0.5574069791324187,
        1.8364485198181246,
        5.291621168339975,
        8.424667506832675,
        58.54160508215072,
        71.47827821468883,
        94.10519165378099
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;500 Tasks, 10ms Delay&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.5,
        0.35,
        0.2,
        0.1,
        0.05,
        0.025,
        0.01,
        0.001,
        0.0005,
        0.0001
      ],
      &quot;y&quot;: [
        0.1603894895032257,
        0.22903246422861434,
        0.4947845241266943,
        0.8888733631063142,
        3.0547498068351104,
        3.763443038396118,
        14.022289971513825,
        41.629875893650244,
        73.53421224697502,
        94.03080952268341
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;100 Tasks, 200µs Delay&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.5,
        0.35,
        0.2,
        0.1,
        0.05,
        0.025,
        0.01,
        0.001,
        0.0005,
        0.0001
      ],
      &quot;y&quot;: [
        0.15774513640591806,
        0.18173049457212825,
        0.3087831317790013,
        0.6970650094417676,
        2.7499465810654886,
        5.596574358865196,
        9.516750231100474,
        58.34046876891629,
        72.88621663281903,
        94.04751534145053
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;500 Tasks, 200µs Delay&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.5,
        0.35,
        0.2,
        0.1,
        0.05,
        0.025,
        0.01,
        0.001,
        0.0005,
        0.0001
      ],
      &quot;y&quot;: [
        0.1239032186416958,
        0.1808995063835833,
        0.49799768808485884,
        0.4905524632268621,
        2.490848591170996,
        4.695345869497867,
        7.412799735095474,
        56.61224103142104,
        65.3551758902386,
        92.65267908594203
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;100 Tasks, 10µs Delay&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.5,
        0.35,
        0.2,
        0.1,
        0.05,
        0.025,
        0.01,
        0.001,
        0.0005,
        0.0001
      ],
      &quot;y&quot;: [
        0.08605146466003541,
        0.21388473478311776,
        0.3307379375336491,
        0.7305543139892543,
        2.2990878912379933,
        4.757930616200371,
        8.54866023649886,
        43.94562125311801,
        75.9458717608522,
        93.97157089016511
      ]
    },
    {
      &quot;type&quot;: &quot;scatter&quot;,
      &quot;name&quot;: &quot;500 Tasks, 10µs Delay&quot;,
      &quot;mode&quot;: &quot;lines&quot;,
      &quot;x&quot;: [
        0.5,
        0.35,
        0.2,
        0.1,
        0.05,
        0.025,
        0.01,
        0.001,
        0.0005,
        0.0001
      ],
      &quot;y&quot;: [
        0.12936472818822237,
        0.30674287446399967,
        0.5388719339883161,
        1.308774406244052,
        2.68169085440357,
        5.201231228057005,
        11.7061941387928,
        60.027926667466645,
        74.74235548359184,
        93.81305898552002
      ]
    }
  ],
  &quot;layout&quot;: {
    &quot;title&quot;: {
      &quot;text&quot;: &quot;Atomic Polling Interval Error Rates&quot;
    },
    &quot;legend&quot;: {
      &quot;title&quot;: {
        &quot;text&quot;: &quot;Task Count \u0026 Delay&quot;
      }
    },
    &quot;xaxis&quot;: {
      &quot;title&quot;: {
        &quot;text&quot;: &quot;Polling Interval (s)&quot;
      }
    },
    &quot;yaxis&quot;: {
      &quot;title&quot;: {
        &quot;text&quot;: &quot;Percent Error&quot;
      }
    }
  },
  &quot;config&quot;: {}
});
        &lt;&#x2F;script&gt;
    &lt;&#x2F;div&gt;
&lt;&#x2F;body&gt;

&lt;&#x2F;html&gt;
&lt;p&gt;As we can see from the graph above, the error is closely correlated to the polling interval. As the polling interval gets smaller, the error in measurement increases exponentially. In fact, this type of graph is reminiscent of a common issue in concurrent applications: contention.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;lock-free-contention-free&quot;&gt;Lock-Free != Contention Free&lt;&#x2F;h1&gt;
&lt;p&gt;The reason we use atomics in concurrent applications is to avoid locking. Locking can often lead to high rates of contention if too many threads are trying to access the same value. Atomics would seem to avoid this issue but at the end of the day there is no free lunch when it comes to memory synchronization, and atomics still run into issues with contention.&lt;&#x2F;p&gt;
&lt;p&gt;When we poll the atomic with a call to &lt;code&gt;.swap(0, Ordering::Relaxed)&lt;&#x2F;code&gt; the CPU has to ensure that every core&#x27;s cache is flushed and replaced with the new value. Additionally, before we return the value, we need to ensure that every &lt;code&gt;fetch_add()&lt;&#x2F;code&gt; was applied to the value. The &lt;code&gt;.swap()&lt;&#x2F;code&gt; call is a linearization point and this has overhead and leads to contention if called too often.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;.fetch_add()&lt;&#x2F;code&gt; does not lead to contention (despite being called far more often and from more threads) I believe because it is monotonic (always increasing). Unfortunately I can&#x27;t find too many details online on how atomics are handled at the hardware level, but in general monotonic operations in concurrent systems are quite easy to deal with as the ordering doesn&#x27;t matter, so it is not too surprising there is minimal contention for this call.&lt;&#x2F;p&gt;
&lt;p&gt;What isn&#x27;t particularly clear to me is &lt;em&gt;where&lt;&#x2F;em&gt; the contention is taking place. Since the baseline atomic and test atomic are both incremented in the task loop, and the baseline atomic is unaffected by the contention, it would seem that the contention is entirely in the &lt;code&gt;.swap()&lt;&#x2F;code&gt; call. How this works at a hardware level, with the &lt;code&gt;fetch_add()&lt;&#x2F;code&gt; being unaffected, but &lt;code&gt;.swap()&lt;&#x2F;code&gt; being affected, would be interesting to learn about, but I haven&#x27;t found any good sources for this information.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;next-steps&quot;&gt;Next Steps&lt;&#x2F;h1&gt;
&lt;p&gt;Its clear that polling atomics faster is not a viable strategy for &lt;a href=&quot;https:&#x2F;&#x2F;www.balterloadtesting.com&#x2F;balter&#x2F;&quot;&gt;Balter&lt;&#x2F;a&gt; to speed up it&#x27;s control loops. Moving forward, I will be investigating alternative control algorithms for Balter to make it faster, and plan to do a similar deep dive for that work in the near future.&lt;&#x2F;p&gt;
&lt;p&gt;Hopefully this little deep dive into atomic polling intervals is useful for anyone else who happens to have a similar problem!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;1&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;em&gt;This situation is a bit more complicated by the presence of latency data, which can&#x27;t be collected directly via atomics, but that will be for another blog post.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;2&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;em&gt;Running the experiment with noise mimics reality better, but it also avoids data artifacts which were occurring as the atomic increments tended to &quot;align&quot; in time without noise.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;style&gt;
.footnote-definition {
    display: flex;
    flex-direction: row;
}
&lt;&#x2F;style&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Performance Pitfalls of Async Function Pointers (and Why It Might Not Matter)</title>
        <published>2024-01-29T00:00:00+00:00</published>
        <updated>2024-01-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.byronwasti.com/async-func-pointers/"/>
        <id>https://www.byronwasti.com/async-func-pointers/</id>
        
        <content type="html" xml:base="https://www.byronwasti.com/async-func-pointers/">&lt;p&gt;I have been working on a distributed load testing framework for Rust called &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;balter&quot;&gt;Balter&lt;&#x2F;a&gt;, and one of the primary things it does is takes a user-defined function and runs it in a loop. If we consider the world of non-async Rust, we could write a (greatly) simplified version of this with a normal &lt;a href=&quot;https:&#x2F;&#x2F;doc.rust-lang.org&#x2F;std&#x2F;primitive.fn.html&quot;&gt;function pointer&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; Balter code
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;load_test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;user_func&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span&gt;()) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;loop &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;user_func&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; User Code
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    balter::load_test(my_load_test_scenario);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;my_load_test_scenario&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What is handy about function pointers is that they&#x27;re lightweight and flexible.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;We can use any function so long as it has the same signature.&lt;&#x2F;li&gt;
&lt;li&gt;We can run the function in multiple threads without any change in the user code.&lt;&#x2F;li&gt;
&lt;li&gt;We can send the function pointer to other machines (or use &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;dtolnay&#x2F;linkme&quot;&gt;&lt;code&gt;linkme&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; to gather them all up into an array)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;load_test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;user_func&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span&gt;()) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;_ in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;THREADS &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        thread::spawn(|| {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;loop &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;user_func&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;            }
&lt;&#x2F;span&gt;&lt;span&gt;        });
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;load_test&lt;&#x2F;span&gt;&lt;span&gt;(my_func_a);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;load_test&lt;&#x2F;span&gt;&lt;span&gt;(my_func_b);
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;load_test&lt;&#x2F;span&gt;&lt;span&gt;(my_func_c);
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But if we want the most bang for our buck when building a tool for load testing, we want to leverage Rust&#x27;s async support. For example, in the context of load testing a web server we will be largely IO bound, and using Tokio to handle concurrency should give us far better performance.&lt;&#x2F;p&gt;
&lt;p&gt;The issue is that an &lt;em&gt;async function pointer&lt;&#x2F;em&gt; doesn&#x27;t really exist. The above code can&#x27;t be converted to support async by just throwing the &lt;code&gt;async&lt;&#x2F;code&gt; keyword in front of our functions. The following is &lt;em&gt;not&lt;&#x2F;em&gt; valid Rust.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span&gt; async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;load_test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;user_func&lt;&#x2F;span&gt;&lt;span&gt;: async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span&gt;()) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;_ in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;TASKS &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        tokio::spawn(|| async {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;loop &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;user_func&lt;&#x2F;span&gt;&lt;span&gt;().await;
&lt;&#x2F;span&gt;&lt;span&gt;            }
&lt;&#x2F;span&gt;&lt;span&gt;        });
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;load_test&lt;&#x2F;span&gt;&lt;span&gt;(foo).await;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we dig into the implementation details of how async works, we find that an &lt;code&gt;async fn()&lt;&#x2F;code&gt; in Rust is equivalent to a function returning a Future, &lt;code&gt;fn() -&amp;gt; impl Future&lt;&#x2F;code&gt;. Under the hood, the compiler generates a struct which implements the &lt;code&gt;Future&lt;&#x2F;code&gt; trait as the return value. While it might seem like our problem is solved, this is actually the root of the issue. Two &lt;code&gt;async fn()&lt;&#x2F;code&gt;s with the &lt;em&gt;exact same signature&lt;&#x2F;em&gt; are entirely different!&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;sync_foo&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;sync_bar&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; No problem in the sync world
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; arr: [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[sync_foo, sync_bar];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;bar&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; We can&amp;#39;t do this!
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; (even if we pretend we can use `impl Future` here)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; arr: [&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; impl Future&amp;lt;Output=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;] &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[foo, bar];
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Written this way it might be apparent why this is an issue. The &lt;code&gt;impl Future&amp;lt;Output=i32&amp;gt;&lt;&#x2F;code&gt; has to resolve to a concrete type at compile time, and the compiler generates two different opaque types for &lt;code&gt;foo()&lt;&#x2F;code&gt; and &lt;code&gt;bar()&lt;&#x2F;code&gt;&#x27;s return values. We can&#x27;t treat the two function pointers for &lt;code&gt;foo()&lt;&#x2F;code&gt; and &lt;code&gt;bar()&lt;&#x2F;code&gt; the same, because they &lt;em&gt;aren&#x27;t&lt;&#x2F;em&gt; the same.&lt;&#x2F;p&gt;
&lt;p&gt;The common solution for this problem is to &lt;code&gt;Box::pin()&lt;&#x2F;code&gt; the &lt;code&gt;Future&lt;&#x2F;code&gt;. A function which returns a &lt;code&gt;Future&lt;&#x2F;code&gt; trait object, while it may look ugly, does make &quot;async function pointers&quot; work (and we can always hide it behind a macro).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; Pin&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;Box&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;dyn Future&amp;lt;Output=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;Box&lt;&#x2F;span&gt;&lt;span&gt;::pin(async {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; Our usual async code
&lt;&#x2F;span&gt;&lt;span&gt;    })
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;bar&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; Pin&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;Box&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;dyn Future&amp;lt;Output=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;Box&lt;&#x2F;span&gt;&lt;span&gt;::pin(async {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; Our usual async code
&lt;&#x2F;span&gt;&lt;span&gt;    })
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; This works now!
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; arr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[foo, bar];
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is an unfortunate lack of symmetry between &lt;code&gt;async fn&lt;&#x2F;code&gt; and &lt;code&gt;fn&lt;&#x2F;code&gt;, but when considering the implementation details it makes sense. An &lt;code&gt;async fn()&lt;&#x2F;code&gt; is unlike any other &lt;code&gt;async fn()&lt;&#x2F;code&gt;, despite what their signatures may be!&lt;&#x2F;p&gt;
&lt;h1 id=&quot;performance&quot;&gt;Performance&lt;&#x2F;h1&gt;
&lt;p&gt;[Update 2&#x2F;16] &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;async-fn-pointer-perf&#x2F;issues&#x2F;1&quot;&gt;Fixed &lt;code&gt;black_box&lt;&#x2F;code&gt; usage&lt;&#x2F;a&gt; for normal function pointers. Thanks &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;c00t&quot;&gt;@c00t&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;p&gt;To measure the performance of our &quot;async function pointers,&quot; I created a handful of benchmarks. For a baseline, I wanted to measure the sync function pointer performance, as well as a boxed function pointer. Then, get a baseline of a normal async function. Finally, the performance of the &lt;code&gt;fn() -&amp;gt; Pin&amp;lt;Box&amp;lt;dyn Future&amp;gt;&amp;gt;&lt;&#x2F;code&gt; &quot;async function pointer.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;The exact benchmark code can be &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;async-fn-pointer-perf&quot;&gt;found on Github&lt;&#x2F;a&gt;. For each situation, I run a &quot;load test&quot; which calls the supplied function 250M times. An example given the sync function pointer baseline is as shown.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;std::hint::black_box;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;load_test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;black_box&lt;&#x2F;span&gt;&lt;span&gt;(foo));
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;load_test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; i &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;..&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;250_000_000 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; _res &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span&gt;(i);
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;arg&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;black_box&lt;&#x2F;span&gt;&lt;span&gt;(arg &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;* &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The benchmarks were run with a release build of the binaries, and timed using hyperfine with minimal system load (closing all browsers and heavy applications). This was all run on an 11th Gen i5 Intel Framework, running NixOS.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;function-pointer
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;function-pointer
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;     429.1 ms ±   7.0 ms    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 428.2 ms, System: 1.1 ms&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;   418.9 ms … 436.7 ms    10 runs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;boxed-function-pointer
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;boxed-function-pointer
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;     537.9 ms ±   2.5 ms    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 536.5 ms, System: 1.4 ms&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;   536.1 ms … 544.0 ms    10 runs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;async-func
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;async-func
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;     407.6 ms ±   3.6 ms    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 402.2 ms, System: 2.8 ms&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;   403.7 ms … 411.6 ms    10 runs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;async-boxed-naive
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;async-boxed-naive
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;      4.985 s ±  0.090 s    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 4.965 s, System: 0.004 s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;    4.922 s …  5.198 s    10 runs
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;source: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;async-fn-pointer-perf&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;async-fn-pointer-perf&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;del&gt;It is unclear what the additional time for the &lt;code&gt;async-func&lt;&#x2F;code&gt; is due to, it very well could be a constant factor startup time for the Tokio runtime.&lt;&#x2F;del&gt; What truly stands out is the &lt;code&gt;async-boxed-naive&lt;&#x2F;code&gt; run time: 5 &lt;em&gt;seconds&lt;&#x2F;em&gt;. That is a whole order of magnitude greater than every other situation. &lt;code&gt;Box::pin()&lt;&#x2F;code&gt; is apparently &lt;em&gt;really&lt;&#x2F;em&gt; slow.&lt;&#x2F;p&gt;
&lt;p&gt;This makes some amount of sense: creating a &lt;code&gt;Pin&amp;lt;Box&amp;lt;dyn Future&amp;gt;&amp;gt;&lt;&#x2F;code&gt; requires some of heavy lifting. We are putting the entire function state on the heap, which function pointers and async functions can put on the stack, and &lt;em&gt;what&lt;&#x2F;em&gt; has to be put on the heap is larger (at least compared to normal function pointers).&lt;&#x2F;p&gt;
&lt;p&gt;While it isn&#x27;t surprising that &lt;code&gt;Box::pin()&lt;&#x2F;code&gt; is slower than normal async performance, just how much slower is. &lt;code&gt;Box::pin()&lt;&#x2F;code&gt; is often recommended to get around various &quot;async function pointer&quot; issues, but rarely with the caveat &quot;and it will be ~10x slower.&quot; Except &lt;em&gt;is it&lt;&#x2F;em&gt;? (I&#x27;ll come back to this question)&lt;&#x2F;p&gt;
&lt;h1 id=&quot;alternatives&quot;&gt;Alternatives&lt;&#x2F;h1&gt;
&lt;p&gt;Unfortunately I have yet to find a single good &quot;universal&quot; alternative. Each alternative suggested below is fairly specific to the situation at hand, and involves trade-offs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;1-push-the-box-pin-to-the-edge&quot;&gt;1. Push the &lt;code&gt;Box::pin()&lt;&#x2F;code&gt; to the Edge&lt;&#x2F;h2&gt;
&lt;p&gt;Instead of using a &lt;code&gt;fn() -&amp;gt; Pin&amp;lt;Box&amp;lt;dyn Future&amp;gt;&amp;gt;&lt;&#x2F;code&gt; where we would naturally want the async function pointer, we can lift the &lt;code&gt;Box::pin()&lt;&#x2F;code&gt; as far up as possible. What this means is using generics for any function call which might be in the hot-path, and keeping &lt;code&gt;Box::pin()&lt;&#x2F;code&gt; on the cold path. The goal we are trying to achieve is having our effective &quot;async function pointer&quot; actually encompass all of the code that would run the function it is calling.&lt;&#x2F;p&gt;
&lt;p&gt;This approach is specific to only certain situations where lifting the &lt;code&gt;Box::pin()&lt;&#x2F;code&gt; is possible. In general, using generics has better performance than boxing, but comes with the trade-off of increased binary size (due to monomorphization).&lt;&#x2F;p&gt;
&lt;p&gt;For our working example of load testing, this would mean pushing all of the actual &lt;code&gt;load_test&lt;&#x2F;code&gt; functionality &lt;em&gt;into&lt;&#x2F;em&gt; the &lt;code&gt;Box::pin()&lt;&#x2F;code&gt;, such that rather than passing &quot;async function pointers&quot; into a &lt;code&gt;load_test&lt;&#x2F;code&gt; function, we instead have &quot;async function pointers&quot; of a load tested function. An example of this is below.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;load_test_wrapper&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;load_test&lt;&#x2F;span&gt;&lt;span&gt;: Pin&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;Box&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;dyn Future&amp;gt;&amp;gt;) {
&lt;&#x2F;span&gt;&lt;span&gt;    load_test.await;
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;load_test&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;T, F&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span&gt;: T)
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;where&lt;&#x2F;span&gt;&lt;span&gt; T: Fn() -&amp;gt; F,
&lt;&#x2F;span&gt;&lt;span&gt;      F: Future&amp;lt;Output=&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;loop &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span&gt;().await;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;bar&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; This works; now each &amp;quot;async function pointer&amp;quot; includes
&lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; the load test code which runs the function.
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; arr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[Pin::Box(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;load_test&lt;&#x2F;span&gt;&lt;span&gt;(foo)), Pin::Box(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;load_test&lt;&#x2F;span&gt;&lt;span&gt;(bar))];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The performance of this alternative approach as compared to the others is below, labeled as &lt;code&gt;async-boxed-invert&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;function-pointer
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;function-pointer
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;     429.1 ms ±   7.0 ms    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 428.2 ms, System: 1.1 ms&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;   418.9 ms … 436.7 ms    10 runs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;boxed-function-pointer
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;boxed-function-pointer
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;     537.9 ms ±   2.5 ms    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 536.5 ms, System: 1.4 ms&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;   536.1 ms … 544.0 ms    10 runs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;async-func
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;async-func
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;     407.6 ms ±   3.6 ms    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 402.2 ms, System: 2.8 ms&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;   403.7 ms … 411.6 ms    10 runs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;async-boxed-naive
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;async-boxed-naive
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;      4.985 s ±  0.090 s    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 4.965 s, System: 0.004 s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;    4.922 s …  5.198 s    10 runs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;async-boxed-invert
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;async-boxed-invert
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;     318.1 ms ±   1.2 ms    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 316.6 ms, System: 2.2 ms&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;   317.1 ms … 320.9 ms    10 runs
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What is confusing to me is why this ends up &lt;em&gt;faster&lt;&#x2F;em&gt; than the &lt;code&gt;async-func&lt;&#x2F;code&gt; case (which is just calling async functions normally). If anything, this approach ought to be &lt;em&gt;slower&lt;&#x2F;em&gt;! I would love to know if anyone has theories as to why this has a speedup.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;2-use-an-enum&quot;&gt;2. Use an Enum&lt;&#x2F;h2&gt;
&lt;p&gt;By using an Enum, we can just fake having an async function pointer to a fairly convincing degree. By enumerating each async function we would like to call into an Enum, and then defining an &lt;code&gt;impl&lt;&#x2F;code&gt; on the Enum which &lt;em&gt;calls&lt;&#x2F;em&gt; those functions, we can have something that works like a function pointer.&lt;&#x2F;p&gt;
&lt;p&gt;The tricky part to the Enum solution is that &lt;em&gt;creating&lt;&#x2F;em&gt; this Enum requires knowledge of all async functions at compile-time. Unfortunately, unless &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rust-lang&#x2F;rust&#x2F;issues&#x2F;44034&quot;&gt;stateful proc macros&lt;&#x2F;a&gt; become a thing, this will be tricky to do for libraries which want to construct this for users (without having the user gather up all of their async functions into one spot).&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;load_test&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span&gt;: Func)
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;loop &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        func.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;().await;
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;bar&lt;&#x2F;span&gt;&lt;span&gt;() -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;enum &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;Func &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    Foo,
&lt;&#x2F;span&gt;&lt;span&gt;    Bar,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;Func &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    async &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;run&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;i32 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;match &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;            Func::Foo &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span&gt;().await,
&lt;&#x2F;span&gt;&lt;span&gt;            Func::Bar &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;bar&lt;&#x2F;span&gt;&lt;span&gt;().await,
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Results, labeled &lt;code&gt;async-enum&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;function-pointer
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;function-pointer
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;     429.1 ms ±   7.0 ms    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 428.2 ms, System: 1.1 ms&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;   418.9 ms … 436.7 ms    10 runs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;boxed-function-pointer
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;boxed-function-pointer
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;     537.9 ms ±   2.5 ms    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 536.5 ms, System: 1.4 ms&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;   536.1 ms … 544.0 ms    10 runs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;async-func
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;async-func
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;     407.6 ms ±   3.6 ms    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 402.2 ms, System: 2.8 ms&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;   403.7 ms … 411.6 ms    10 runs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;async-boxed-naive
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;async-boxed-naive
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;      4.985 s ±  0.090 s    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 4.965 s, System: 0.004 s&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;    4.922 s …  5.198 s    10 runs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;async-boxed-invert
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;async-boxed-invert
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;     318.1 ms ±   1.2 ms    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 316.6 ms, System: 2.2 ms&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;   317.1 ms … 320.9 ms    10 runs
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;hyperfine target&#x2F;release&#x2F;async-enum
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Benchmark 1: target&#x2F;release&#x2F;async-enum
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Time (mean ± σ&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;     526.5 ms ±   0.8 ms    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;User: 524.2 ms, System: 2.6 ms&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;]
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Range (min … max&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;   525.6 ms … 528.1 ms    10 runs
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Just slightly slower than async functions normally, which is a reasonable trade-off.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;3-reset-the-future&quot;&gt;3. Reset the Future&lt;&#x2F;h2&gt;
&lt;p&gt;One niche and clever strategy is to &lt;em&gt;reset&lt;&#x2F;em&gt; the future. If we want to continuously rerun a given async function, then if after every run we were able to &quot;reset&quot; the function back to its start, we could just reuse the &lt;code&gt;Pin&amp;lt;Box&amp;lt;dyn Future&amp;gt;&amp;gt;&lt;&#x2F;code&gt; that we already have. This trick is used by the &lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;tower&#x2F;latest&#x2F;src&#x2F;tower&#x2F;limit&#x2F;rate&#x2F;service.rs.html#106-109&quot;&gt;&lt;code&gt;Tower&lt;&#x2F;code&gt; rate-limiting functionality&lt;&#x2F;a&gt; for the &lt;code&gt;sleep&lt;&#x2F;code&gt; Future, to avoid having to re-&lt;code&gt;Box::pin&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;RateLimit &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    ...
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;sleep&lt;&#x2F;span&gt;&lt;span&gt;: Pin&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;Box&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;Sleep&amp;gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;impl &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;RateLimit &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;call&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;...
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; The service is disabled until further notice
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; Reset the sleep future in place, so that we don&amp;#39;t have to
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; deallocate the existing box and allocate a new one.
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.sleep.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;as_mut&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;reset&lt;&#x2F;span&gt;&lt;span&gt;(until);
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;source: simplified snippet from &lt;a href=&quot;https:&#x2F;&#x2F;docs.rs&#x2F;tower&#x2F;latest&#x2F;src&#x2F;tower&#x2F;limit&#x2F;rate&#x2F;service.rs.html#106-109&quot;&gt;&lt;code&gt;Tower&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;&lt;em&gt;Unfortunately&lt;&#x2F;em&gt; this requires that you have control over the &lt;code&gt;Future&lt;&#x2F;code&gt; involved (and can implement a &lt;code&gt;.reset()&lt;&#x2F;code&gt; method on it), though I am curious if this can be captured in a library to apply for all &lt;code&gt;async fn&lt;&#x2F;code&gt;...  I have not created this library nor do I even know how to do this for a single async function, so doubly-unfortunate, I do not have any benchmarking for the performance of this approach. It was just too neat to not mention.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;results&quot;&gt;Results&lt;&#x2F;h1&gt;
&lt;p&gt;It&#x27;s one thing to benchmark something on a small scale, but another to apply it at a larger scale. I initially used &lt;code&gt;Box::pin()&lt;&#x2F;code&gt; to get &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;balter&quot;&gt;Balter&lt;&#x2F;a&gt; off the ground, but always intended to remove it. Profiling async code can be tricky, so it wasn&#x27;t clear to me what the performance implications were going to be. Hence why I did this testing. However, I still had to find out: &lt;em&gt;does the seemingly poor performance of &lt;code&gt;Box::pin()&lt;&#x2F;code&gt; actually matter?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As far as I can tell, the answer is... maybe not? At least, for Balter, using the first technique of lifting the &lt;code&gt;Box::pin()&lt;&#x2F;code&gt; out of the hot-path has made no difference in benchmarks. This is surprising, as I was expecting at least &lt;em&gt;some improvement&lt;&#x2F;em&gt; from the small-scale benchmarks. With and without &lt;code&gt;Box::pin()&lt;&#x2F;code&gt; the Balter framework overhead caps at an output of ~750K TPS on my machine (which means running the framework against a no-op function).&lt;&#x2F;p&gt;
&lt;p&gt;Balter isn&#x27;t quite at the point where it is ready for proper profiling and benchmarking, and this all came about primarily due to curiosity. There are some clear suspects for performance improvements from the profiling I have done, and these could be drowning out the impact of &lt;code&gt;Box::pin()&lt;&#x2F;code&gt;. I was just so surprised by the small-scale benchmarks and figured I would share!&lt;&#x2F;p&gt;
&lt;p&gt;As always with performance matters, it all comes down to profiling and measuring. &lt;code&gt;Box::pin()&lt;&#x2F;code&gt; &lt;em&gt;seems&lt;&#x2F;em&gt; slow but it might not matter for your use-case!&lt;&#x2F;p&gt;
&lt;p&gt;[Update 2&#x2F;14] Thanks to @matthieum on Reddit for &lt;a href=&quot;https:&#x2F;&#x2F;old.reddit.com&#x2F;r&#x2F;rust&#x2F;comments&#x2F;1amuyum&#x2F;performance_pitfalls_of_async_function_pointers&#x2F;kprxcrq&#x2F;&quot;&gt;comments on additional strategies&lt;&#x2F;a&gt;. I will be looking into those and updating the post accordingly with timing measurements!&lt;&#x2F;p&gt;
&lt;p&gt;[Update 2&#x2F;16] Thanks to @coot on Github for filing the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;async-fn-pointer-perf&#x2F;issues&#x2F;1&quot;&gt;issue on black_box usage&lt;&#x2F;a&gt; which lead to incorrect measurements for the normal function pointer cases.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Prusto Watch #4: A Retrospective</title>
        <published>2018-05-09T17:36:17-04:00</published>
        <updated>2018-05-09T17:36:17-04:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.byronwasti.com/prusto-watch-4/"/>
        <id>https://www.byronwasti.com/prusto-watch-4/</id>
        
        <content type="html" xml:base="https://www.byronwasti.com/prusto-watch-4/">&lt;p&gt;The past few months of working on the Prusto Watch has been both frustrating and rewarding. This post will go through what I did and what I learned during the process.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;project-summary-so-far&quot;&gt;Project Summary So Far&lt;&#x2F;h2&gt;
&lt;p&gt;First, I will start off with a summary of what has been accomplished so far in the project.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Four PCB revisions, with the final revision being a great form factor and also a two-layer board.&lt;&#x2F;li&gt;
&lt;li&gt;Functioning BLE, Display and button peripherals.&lt;&#x2F;li&gt;
&lt;li&gt;Two libraries written in Rust which are hardware-agnostic. One for the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;rn4870&quot;&gt;BLE module&lt;&#x2F;a&gt; and one for the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;ls010b7dh01&quot;&gt;memory display&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Bug fix for the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jamwaffles&#x2F;embedded-graphics&#x2F;pull&#x2F;13&quot;&gt;&lt;code&gt;embedded-graphics&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; library&#x27;s Bresenham line-drawing algorithm.&lt;&#x2F;li&gt;
&lt;li&gt;Developed a simulator for the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;jamwaffles&#x2F;embedded-graphics&#x2F;pull&#x2F;29&quot;&gt;&lt;code&gt;embedded-graphics&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; library.&lt;&#x2F;li&gt;
&lt;li&gt;Various additions to the &lt;code&gt;stm32f30x-hal&lt;&#x2F;code&gt; library (although not upstreamed due to maintainer issues, I&#x27;ve found some of my additions present in other forks).&lt;&#x2F;li&gt;
&lt;li&gt;Basic setup for the Prusto Watch firmware using the RTFM framework.&lt;&#x2F;li&gt;
&lt;li&gt;3D printable case design which fits all the hardware and is only 9.5mm thick! (It is surprisingly pleasant to wear)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Even though the Prusto Watch is not a fully usable smart watch (yet), I think I have made significant progress in getting something very close to a usable smart watch. Ideally over the next few weeks I will be able to develop out the firmware side of the watch and make it more functional.&lt;&#x2F;p&gt;
&lt;p&gt;The most recent Prusto Watch in it&#x27;s case shown below:&lt;&#x2F;p&gt;
&lt;img src=&quot;[object]&quot; &#x2F;&gt;
&lt;h2 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;&#x2F;h2&gt;
&lt;p&gt;The main goal of this project was to learn and to document much of what I had learned. So I will go over some of the major points of failure of the project, since they seem to coincide with where I learned the most.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;1-how-to-design-hardware-for-debugging&quot;&gt;1. How to Design Hardware For Debugging&lt;&#x2F;h3&gt;
&lt;p&gt;The most significant time sink, and also the most avoidable, was dealing with hardware issues. One of the biggest issues I seemed to continually run into was being unable to easily scope or otherwise debug what was going wrong. By the fourth revision I had finally figured out a system that worked, but not without three revisions of headaches.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;prusto_watch&#x2F;prusto_watch_ver0.1.svg&quot; alt=&quot;watch v0.1&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The first PCB (shown above) I naively did not put any headers or other scoping points, and thus was basically unable to know what was going wrong. I learned how important it is to put debugging points on hardware, especially on the first revision of a board.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;prusto_watch&#x2F;prusto_watch_ver0.2.svg&quot; alt=&quot;watch v0.2&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The second PCB (above) I put large headers on, and was able to make a lot of progress. However, I was unsure of which direction the connector should face on the LCD. I spent far too many hours debugging &quot;software&quot; issues when I just needed to flip the connector. I learned that if I am unsure of a particular connection, I should just design a board with all of the possibilities at once so that I can test them all in parallel.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;prusto_watch&#x2F;prusto_watch_ver0.3.svg&quot; alt=&quot;watch v0.3&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The third PCB revision (above) I made sure to have headers, however to save space I made them 1.27mm pitch thinking it would be easy to just solder leads to them for testing. This worked for the most part, but was very unwieldy and difficult to solder correctly.
I also did not put silkscreen for any of the connections because I did not have space on the top layer. I quickly realized once working with the board that silkscreen on the back would have worked just as well.
Finally, I thought having such a weird board shape would be fine when designing a case, which was far from the truth&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;prusto_watch&#x2F;prusto_watch_ver0.4.svg&quot; alt=&quot;watch v0.4&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The final PCB revision (above) had a board shape designed in CAD, so it was very easy to design a case for. Additionally, I ordered 1.27mm pitch header breakouts which made it much easier to quickly test various peripherals. Finally, I made sure all of the external connections did not interfere with either the battery or the display, which made the debugging components available even when the watch is fully assembled.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, the main lessons I learned was to design hardware with a focus on being able to debug it. Even having a pad available to test voltage was a sanity saver at various points of development.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;2-using-the-bus-pirate-to-verify-if-it-is-a-software-or-hardware-issue&quot;&gt;2. Using the Bus Pirate to Verify if it is a Software or Hardware Issue&lt;&#x2F;h3&gt;
&lt;p&gt;One of the most challenging parts of embedded development is the fact that issues can either be hardware or software. In order to deal with this in the past I relied on knowing firmware really well, and basically trusting that my firmware was correct. This works surprisingly effectively with AVR and other simple microcontrollers, since the firmware is straightforward and there isn&#x27;t much complexity going on. However, Arm is significantly more complicated than AVR and I was unfamiliar with it. Thus, many of the issues I ran into I had no idea if they were hardware or firmware or both.&lt;&#x2F;p&gt;
&lt;p&gt;This is where I learned just &lt;em&gt;how&lt;&#x2F;em&gt; useful a device like the Bus Pirate is. The Bus Pirate allowed me to quickly verify if problems in communication with a peripheral was hardware or software, since I could completely rely on the Bus Pirate getting the communication protocol correct. If I had known about solutions like the Bus Pirate at the start of this project I could have saved a lot of time debugging silly issues (like the LCD connector).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;3-the-importance-of-knowing-the-microcontroller&quot;&gt;3. The Importance of Knowing the Microcontroller&lt;&#x2F;h3&gt;
&lt;p&gt;For a while I relied on my very basic understanding of Arm in order to get firmware development done. I avoided diving deeply into how Arm worked until I ran into a very strange error, which I talk about [here]({{&amp;lt;ref &quot;prusto_watch_3.md&quot;&amp;gt;}}). By putting off truly learning the details of how an Arm chip works, I wasted time &quot;trying&quot; things until it worked instead of being able to effectively read the MCU&#x27;s datasheet. I also missed out on learning to use awesome debugging tools, especially GDB, effectively.&lt;&#x2F;p&gt;
&lt;p&gt;Although now that I have a much better understanding of how Arm works and how to debug it effectively, the next project that I use an Arm chip on will go much more smoothly.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;4-using-rust-to-start-was-probably-a-bad-idea-but-it-thankfully-worked-out&quot;&gt;4. Using Rust to Start Was Probably a Bad Idea (but it thankfully worked out)&lt;&#x2F;h3&gt;
&lt;p&gt;At the beginning of the project I was excited by the idea of using Rust, a language which I think has amazing promise for systems development, as the main programming language for the Prusto Watch. However, at the time Rust barely had support for Arm chips.&lt;&#x2F;p&gt;
&lt;p&gt;Through the project Rust actually gained mainline support of Arm, although only on the nightly branch. This meant that every few weeks things would break with no documentation. In general, the documentation is not exactly stellar for Rust on embedded (which makes sense given how new the ecosystem is).&lt;&#x2F;p&gt;
&lt;p&gt;In retrospect, it was a really bad idea to use Rust, especially since I did not know how to develop for Arm using C and thus couldn&#x27;t even reference what worked in C. If Rust&#x27;s Arm support had been poorly implemented or otherwise buggy, I would have been in a whole heap of trouble.&lt;&#x2F;p&gt;
&lt;p&gt;However, in general things worked really well. I was also able to contribute to the embedded ecosystem, and I plan on continuing to contribute. From my experience I think Rust has amazing potential to make embedded development much nicer and more safe, and it is progressing in a really awesome way.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;other-smaller-things-learned&quot;&gt;Other (Smaller) Things Learned&lt;&#x2F;h2&gt;
&lt;p&gt;Through the project I also learned a number of smaller things.&lt;&#x2F;p&gt;
&lt;p&gt;I learned:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;How to place components by hand using tweezers. Since I was using 0.6mm thick PCBs instead of the standard 1.6mm thickness, the pick-and-place was not able to properly &quot;let go&quot; of components, and they would not be in the correct placement. I was forced to use tweezers to place components, which I got pretty good at by the end.&lt;&#x2F;li&gt;
&lt;li&gt;The importance of having components ordered before you need them. Twice I was burned because I did not realize I was out of a certain component, or really low on a component, while I was soldering up a new board. I ended up ordering an SMD case for keeping all my components, and developing a system for keeping track of components I am low on.&lt;&#x2F;li&gt;
&lt;li&gt;Getting super thin PCBs may not be the best idea. Once I went to 0.6mm thick boards they began becoming extremely unreliable. Depending on how they were held or looked at they would fail to turn on, or power certain components, or even allow me to program the MCU.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;Whats Next&lt;&#x2F;h2&gt;
&lt;p&gt;I plan on continuing firmware development of the Prusto Watch to make it into a usable smart watch of sorts. Depending on how that goes I will continue refining the hardware and firmware. It would be awesome to have a community that is developing a fully open source smart watch, so once I get it to a certain point I hope to have a proper announcement and get others working on it.&lt;&#x2F;p&gt;
&lt;p&gt;Overall, I think this project has been a success regardless of where it ends up since I have learned a significant amount about hardware development as well as firmware development with Arm chips.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Prusto Watch #3: Learning How to Properly Debug Arm</title>
        <published>2018-04-29T13:36:43-04:00</published>
        <updated>2018-04-29T13:36:43-04:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.byronwasti.com/prusto-watch-3/"/>
        <id>https://www.byronwasti.com/prusto-watch-3/</id>
        
        <content type="html" xml:base="https://www.byronwasti.com/prusto-watch-3/">&lt;p&gt;This post will document my experience debugging a strange error I ran into while developing firmware for the Prusto Watch. Through the process I learned how the startup process for Arm actually works and how to use debugging tools in a much more effective way. Those that are familiar with Arm assembly and debugging will probably not learn anything from this, but I think it could be useful for those that are new to Arm.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;&#x2F;h2&gt;
&lt;p&gt;After soldering the third version of the Prusto Watch hardware, I flashed &lt;code&gt;blinky&lt;&#x2F;code&gt; onto it to ensure that everything was functioning properly. The program loaded just fine, and the LED blinked.  Next I tried to flash the firmware for showing graphics on the memory LCD. Once again it loaded just fine on the MCU, but nothing displayed when running the program through GDB. Ctrl-C&#x27;ing made GDB output the following:&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#fcf0ca;color:#282828aa;&quot;&gt;&lt;code&gt;&lt;span&gt;^C
&lt;&#x2F;span&gt;&lt;span&gt;Program received signal SIGINT, Interrupt.
&lt;&#x2F;span&gt;&lt;span&gt;0x1fffeec2 in ?? ()
&lt;&#x2F;span&gt;&lt;span&gt;(gdb) 
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Obviously something went wrong, which is weird since the firmware ran just fine on previous iterations. At the time, I had no idea what this error meant, so I attempted to flash the &lt;code&gt;release&lt;&#x2F;code&gt; version (which has compile-time optimizations) of the same firmware.  In retrospect, this doesn&#x27;t make any sense to do (but I&#x27;m glad I did it). What I found is that the &lt;code&gt;release&lt;&#x2F;code&gt; version of the firmware ran just fine, and shapes displayed on the screen.&lt;&#x2F;p&gt;
&lt;p&gt;This seemed like a bug in the compiler. Since embedded Rust is using a nightly version of the compiler, something could have broken in a recent change. But after searching through issue logs, and talking on IRC, this seemed like an issue only I was having. IRC members also found it &lt;em&gt;really&lt;&#x2F;em&gt; weird that it worked when in &lt;code&gt;release&lt;&#x2F;code&gt; mode and not in &lt;code&gt;debug&lt;&#x2F;code&gt; mode. So began my journey debugging Arm and learning how things work.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-to-a-minimum-complete-verifiable-example&quot;&gt;Getting to A Minimum, Complete, Verifiable Example&lt;&#x2F;h2&gt;
&lt;p&gt;The graphics code for the memory LCD is rather large if you include dependencies, so there are many, many places for things to go wrong. In order to get to the root of the problem, I slowly took code out of the library until I was left with just what was broken. I found the issue was with the initialization of the main display object,&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;impl&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;SPI, CS, DISP, E&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;Ls010b7dh01&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;SPI, CS, DISP&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;where
&lt;&#x2F;span&gt;&lt;span&gt;    SPI: Write&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;, Error = E&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    CS: OutputPin,
&lt;&#x2F;span&gt;&lt;span&gt;    DISP: OutputPin,
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F;&#x2F; Create a new Ls010b7dh01 object
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F;&#x2F;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F;&#x2F; `disp` is the pin connected to the display_enable pin of
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F;&#x2F; the memory LCD.
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;spi&lt;&#x2F;span&gt;&lt;span&gt;: SPI, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;cs&lt;&#x2F;span&gt;&lt;span&gt;: CS, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;disp&lt;&#x2F;span&gt;&lt;span&gt;: DISP) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;Self &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        disp.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;set_low&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;        cs.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;set_low&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; buffer &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;]; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;128&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;Self &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;            spi,
&lt;&#x2F;span&gt;&lt;span&gt;            cs,
&lt;&#x2F;span&gt;&lt;span&gt;            disp,
&lt;&#x2F;span&gt;&lt;span&gt;            buffer,
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The code would hang (as in run indefinitely) when the control sequence reached this function, and it &lt;em&gt;seemed&lt;&#x2F;em&gt; to occur right at the &lt;code&gt;disp.set_low();&lt;&#x2F;code&gt; line. When I took out that line the program still didn&#x27;t work. However, taking out the &lt;code&gt;let buffer = [[0; 16]; 128];&lt;&#x2F;code&gt; line made the program run. So it seemed like the issue is with initializing a &quot;lot&quot; of memory on the stack. The minimum, complete, verifiable example I had was then:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;() {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; Insert a breakpoint
&lt;&#x2F;span&gt;&lt;span&gt;    asm::bkpt();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; The error line, initializing memory on the stack
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; buffer &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;16&lt;&#x2F;span&gt;&lt;span&gt;]; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;128&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; Another breakpoint which we never hit in `debug` mode
&lt;&#x2F;span&gt;&lt;span&gt;    asm::bkpt();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;loop &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; Wait on interrupt, apparently needed due to a bug in LLVM
&lt;&#x2F;span&gt;&lt;span&gt;        asm::wfi();
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;h2 id=&quot;understanding-the-error&quot;&gt;Understanding the Error&lt;&#x2F;h2&gt;
&lt;p&gt;In order to debug the issue I was having, I had to first understand the error GDB was outputting (with help from people on IRC). Loading the &lt;code&gt;debug&lt;&#x2F;code&gt; version of the firmware again, I got GDB to the same spot. This time, I tried to find the backtrace.&lt;&#x2F;p&gt;
&lt;pre style=&quot;background-color:#fcf0ca;color:#282828aa;&quot;&gt;&lt;code&gt;&lt;span&gt;^C
&lt;&#x2F;span&gt;&lt;span&gt;Program received signal SIGINT, Interrupt.
&lt;&#x2F;span&gt;&lt;span&gt;0x1fffeec2 in ?? ()
&lt;&#x2F;span&gt;&lt;span&gt;(gdb) bt
&lt;&#x2F;span&gt;&lt;span&gt;#0  0x1fffeec2 in ?? ()
&lt;&#x2F;span&gt;&lt;span&gt;#1  0x1fffee9e in ?? ()
&lt;&#x2F;span&gt;&lt;span&gt;Backtrace stopped: previous frame identical to this frame (corrupt stack?)
&lt;&#x2F;span&gt;&lt;span&gt;(gdb)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What this means is that something went wrong with the stack memory, and generally it is due to stack overflow where the stack runs out of memory. However, I am using a microcontroller with &lt;em&gt;more&lt;&#x2F;em&gt; SRAM (40KB) than my previous microcontroller (12KB), so it didn&#x27;t make sense that I was running out of memory since it worked fine on the previous microcontroller.&lt;&#x2F;p&gt;
&lt;p&gt;However, the fact that the issue was with the stack makes sense given the code that was breaking, so I knew I was on the right track.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;arm-vector-tables&quot;&gt;Arm Vector Tables&lt;&#x2F;h2&gt;
&lt;p&gt;Since I knew I had &lt;em&gt;enough&lt;&#x2F;em&gt; SRAM, the issue was definitely not a stack overflow. I learned on IRC that it was most likely a linking error, and that my vector table might be wrong. Coming from the world of AVR, I had no idea what a vector table even was.&lt;&#x2F;p&gt;
&lt;p&gt;The Arm vector table is actually quite straightforward. It is a list of places in memory for use by the Arm Core. Most of it is just a list of function-pointers for dealing with interrupts. For instance, if there is a serial receive interrupt, then the Arm Core will set the program counter to the value in the vector table corresponding to the serial receive interrupt. AVR does have interrupt vectors, which I have used, but the vector table is handled under-the-hood, and thus I never had to explicitly create it. In Arm, however, it has to be explicitly created, probably to keep things flexible.&lt;&#x2F;p&gt;
&lt;p&gt;The reason this has relevance to my problem is that the first value of the Arm vector table is where the stack memory is located. Members on IRC figured that this value was incorrect, and thus why the stack was corrupt.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;arm-tools&quot;&gt;Arm Tools&lt;&#x2F;h2&gt;
&lt;p&gt;Thankfully there are some really awesome tools for inspecting these types of issues. One of which is the &lt;code&gt;objdump&lt;&#x2F;code&gt; tool. Using it, I was able to quickly verify that my stack was in fact in the right place:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#282828;&quot;&gt;$ arm-none-eabi-objdump -D target&#x2F;thumbv7em-none-eabihf&#x2F;debug&#x2F;cortex-m-quickstart &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;head -n10
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;target&#x2F;thumbv7em-none-eabihf&#x2F;debug&#x2F;cortex-m-quickstart:     file format elf32-littlearm
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Disassembly of section .vector_table:
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;08000000 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;_svector_table&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;:
&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;8000000:       2000a000        andcs   sl, r0, r0
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The flash memory of the STM32f303 MCU I am using starts at &lt;code&gt;0x0800_0000&lt;&#x2F;code&gt;. The first value, which corresponds to the stack memory location, is &lt;code&gt;0x2000_a000&lt;&#x2F;code&gt;. The SRAM of the MCU is located at &lt;code&gt;0x2000_0000&lt;&#x2F;code&gt; and &lt;code&gt;0xa000&lt;&#x2F;code&gt; is 40KB. Since the stack is top-down, this means that the vector table is correct, and the stack memory is located at the right place.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;digging-through-assembly&quot;&gt;Digging Through Assembly&lt;&#x2F;h2&gt;
&lt;p&gt;Given that my vector table was correct, I stumped the folks on IRC. The last bit of advice I got was &quot;step through the assembly and try to find something going wrong.&quot;&lt;&#x2F;p&gt;
&lt;p&gt;Once again I started up GDB, but instead of letting the program run I was going to step through every line of assembly and figure out where things go wrong. From reading the GDB documentation, the commands I would need are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;stepi&lt;&#x2F;code&gt; for stepping through the code one assembly instruction at a time&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;display&#x2F;i $sp&lt;&#x2F;code&gt; and &lt;code&gt;display&#x2F;i $pc&lt;&#x2F;code&gt; for displaying the stack pointer and program counter at each step.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;disas&lt;&#x2F;code&gt; for disassembling and printing the assembly.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I started up GDB, and just to get my bearings I ran &lt;code&gt;disas&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;gdb&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt; disas
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;Dump of assembler code for function cortex_m_rt::reset_handler:
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;0x08000400 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;+0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;:     push    {r7, lr}
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;0x08000402 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;+2&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;:     mov     r7, sp
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;0x08000404 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;+4&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;:     sub     sp, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;#16
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;=&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;x08000406 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;+6&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;:     movw    r0, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;#0
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;0x0800040a &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;+10&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;:    movt    r0, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;#8192       ; 0x2000
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;0x0800040e &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;+14&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;:    movw    r1, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;#0
&lt;&#x2F;span&gt;&lt;span&gt;   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;0x08000412 &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;+18&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;:    movt    r1, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;#8192       ; 0x2000
&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;gdb&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;.text&lt;&#x2F;code&gt; section (where the actual program is) is located at 0x0800_0400, since the vector table is 0x400 bytes long. So this shows that the program counter is on the fourth instruction, after completing three instructions. The first three instructions are:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;push R7 and the link register (LR) onto the stack&lt;&#x2F;li&gt;
&lt;li&gt;Move the stack pointer (SP) into R7&lt;&#x2F;li&gt;
&lt;li&gt;Subtract the number 16 from SP&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Since our vector table defines the stack pointer to start at 0x2000_a000, at this point we would expect the stack pointer to be at 0x2000_9ff0 (which is 0x2000_a000 - 16). However, upon inspecting this register using GDB, I found it to be very different.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;gdb&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt; display $sp
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;1: $sp = (void &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;0x20001240
&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;gdb&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The difference between where I expect the stack pointer to be, and where it actually is, is a difference of about 36KB. This means something is very amiss, and it happens immediately.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;an-issue-from-the-past&quot;&gt;An Issue From The Past&lt;&#x2F;h2&gt;
&lt;p&gt;When I first soldered the new revision of the PCB, I was able to flash &lt;code&gt;blinky&lt;&#x2F;code&gt; on it just fine. However, the program did not run when the board was unplugged from my computer. This was an issue, since a smart watch is not very usable if you have to have it plugged into GDB in order to run firmware.&lt;&#x2F;p&gt;
&lt;p&gt;After trying to figure out the issue, someone suggested checking my &lt;code&gt;boot0&lt;&#x2F;code&gt; pin, and ensuring that it was tied low. It turns out that in the latest revision, I had accidentally tied my &lt;code&gt;boot0&lt;&#x2F;code&gt; pin high.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;boot0&lt;&#x2F;code&gt; pin defines the &lt;em&gt;aliasing&lt;&#x2F;em&gt; of the 0x0000_0000 memory region. This is the region of memory that is used when the microcontroller starts. If &lt;code&gt;boot0&lt;&#x2F;code&gt; is low, the memory region is aliased to the flash memory, or 0x0800_0000, which is where my code is.  However, if the &lt;code&gt;boot0&lt;&#x2F;code&gt; pin is high, it is aliased to the system memory, or 0x1FFF_D800, where the STM bootloader is located.&lt;&#x2F;p&gt;
&lt;p&gt;What I learned is that when GDB is running, it coerces the program counter into the right position, which for me is 0x0800_0000. But when GDB was not being used, and the board was running unconnected, the microcontroller was running the code in the system memory.&lt;&#x2F;p&gt;
&lt;p&gt;This seemed like a small issue. It just meant this revision would not be able to run without being connected to GDB, which is annoying (since I can&#x27;t wear it) but also not a deal breaker since I just need to do development with it. Little did I know that this issue is also what is making the stack pointer all crazy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-root-cause&quot;&gt;The Root Cause&lt;&#x2F;h2&gt;
&lt;p&gt;After spending a long time trying to figure out why the stack pointer was so wrong, I remembered the issue I had with the &lt;code&gt;boot0&lt;&#x2F;code&gt; pin. What if the vector-table is set before GDB is able to coerce the program counter?&lt;&#x2F;p&gt;
&lt;p&gt;I examined the system memory region, 0x1FFF_D800, to see what the vector table in system memory sets the stack pointer to.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;gdb&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt; x 0x1fffd800  &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;# inspect the memory at the address
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;0x1fffd800:     0x20001258
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The system memory vector table has the stack sized much smaller than it could be. In fact, this value is &lt;em&gt;almost&lt;&#x2F;em&gt; the value that GDB shows the stack pointer to be on initial start up. GDB showed the stack pointer to be 0x20001250 (before it had 16 subtracted from it), while the system memory vector table sets it to 0x20001258. This is a difference of 8 bytes, which can be explained to be missing since the stack pointer has to be aligned in memory, so those 8 bytes are truncated. Aha! This seems really promising.&lt;&#x2F;p&gt;
&lt;p&gt;My theory, then, is that the vector table is sourced from &lt;em&gt;system memory&lt;&#x2F;em&gt;, and then GDB coerces the program counter to &lt;em&gt;flash memory&lt;&#x2F;em&gt; to run the program. Since the system memory stack size is so small, we actually &lt;em&gt;do&lt;&#x2F;em&gt; have a stack overflow error.&lt;&#x2F;p&gt;
&lt;p&gt;This also explains why the program is able to run in &lt;code&gt;release&lt;&#x2F;code&gt; mode. Due to compile-time optimizations, the stack usage is much lower and does not cause it to overflow. Running the firmware on older revisions with the correct &lt;code&gt;boot0&lt;&#x2F;code&gt; pin helps reinforce my theory, since the stack pointer is consistently in the right place. It seems like this is the issue, and one that will be fixed in the next board revision!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;&#x2F;h2&gt;
&lt;p&gt;From the process of debugging this issue, I learned a &lt;em&gt;lot&lt;&#x2F;em&gt; about Arm. As frustrating and as long as it took, I have a significantly better grasp about what is going on under-the-hood. I also know how to use my tools much more effectively even though I&#x27;m positive that there are still many tricks that are waiting to be learned.&lt;&#x2F;p&gt;
&lt;p&gt;Although I have made no progress on actually writing firmware for the watch, I think it has been completely worth it from a learning perspective. A few times I thought about just working with an older revision, and hoping that the next revision of the board would work fine because &lt;em&gt;who knows&lt;&#x2F;em&gt; what could be going wrong. But deep down I wanted to &lt;em&gt;know&lt;&#x2F;em&gt; why it wasn&#x27;t working. And now, I&#x27;m pretty sure I do.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Prusto Watch #2: Basic Driver Support</title>
        <published>2018-03-27T13:24:40-04:00</published>
        <updated>2018-03-27T13:24:40-04:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.byronwasti.com/prusto-watch-2/"/>
        <id>https://www.byronwasti.com/prusto-watch-2/</id>
        
        <content type="html" xml:base="https://www.byronwasti.com/prusto-watch-2/">&lt;p&gt;The goal of the past few weeks has been to develop basic driver support for the various peripherals on the Prusto Watch. This includes the BLE module, the LCD display, the IMU and touch-sensing. So far I have made major progress in developing drivers for the BLE module and for the LCD display. I am having difficulty getting the IMU soldered on correctly, so I have been unable to make progress in actually communicating with it. I have been looking into alternative solutions that will hopefully be easier to solder for future iterations. I have also decided to not pursue touch-sensing, and to instead just use discrete buttons on the outer shell of the Prusto Watch.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ble-module-github-repo&quot;&gt;BLE Module (&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;rn4870&quot;&gt;Github Repo&lt;&#x2F;a&gt;)&lt;&#x2F;h2&gt;
&lt;p&gt;The first driver I have in a semi-usable state is the RN4870 BLE driver. In terms of functionality the driver can only do the basic necessities, but it is not difficult to add functionality as I need it. One of the hurdles I am running into is figuring out how to deal with incoming UART data on the microcontroller side. Currently the driver exposes a blocking read of the RX pin. One issue with this is that it will block everything until a message has been received. Another issue is that an overrun error is common in case a message comes in when I am not trying to read it.&lt;&#x2F;p&gt;
&lt;p&gt;Below is a screenshot of a phone app which is communicating to the RN4870 device, with firmware running on the microcontroller which provides an &quot;echo&quot; channel.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog_images&#x2F;prusto_watch_2&#x2F;ble_echo.png&quot; alt=&quot;BLE echo&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So far the &quot;echo&quot; only works if one character is sent at a time from the phone, since the UART peripheral will immediately overrun if more than one character is sent at a time. This is due to the fact that my only way of reading the RX channel is by doing a blocking read.&lt;&#x2F;p&gt;
&lt;p&gt;There are two potential options that I see to fix this issue. One is to have the UART RX pin cause an interrupt and to fill a circular buffer from the interrupt. The other is to actually get DMA working and to have the UART peripheral pipe in received data into a memory location. Since I know very little about how to get DMA working, I will most likely attempt at getting the interrupt method working. Hopefully this is enough to avoid having constant overruns and to allow non-blocking reading of UART.&lt;&#x2F;p&gt;
&lt;p&gt;The other issue is that the RN4870 seems to be rather finicky to connect to. Sometimes the echo channel is working fine but other times it doesn&#x27;t work at all. I plan to investigate this issue further once I get the IMU situation sorted out.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, at some point I will have to look into what is required for an Android phone to send push-notifications over bluetooth. Hopefully there is some simple, default service that Android provides so I don&#x27;t have to delve too much into Android development.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lcd-memory-display-github-repo&quot;&gt;LCD Memory Display (&lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;ls010b7dh01&quot;&gt;Github Repo&lt;&#x2F;a&gt;)&lt;&#x2F;h2&gt;
&lt;p&gt;The second driver I have is for the memory LCD. It took far longer than it should have to get the display to work, mostly because the &lt;a href=&quot;https:&#x2F;&#x2F;media.digikey.com&#x2F;pdf&#x2F;Data%20Sheets&#x2F;Sharp%20PDFs&#x2F;LS010B7DH01.pdf&quot;&gt;datasheet&lt;&#x2F;a&gt; for the display is not entirely clear about how to wire the display. As far as I can tell, the datasheet is actually &lt;em&gt;incorrect&lt;&#x2F;em&gt; and says to wire it up backwards.&lt;&#x2F;p&gt;
&lt;p&gt;After many hours of trying to get any sort of communication working with Arduino libraries and a bus-pirate, I found a picture of a breakout board for a memory LCD and upon zooming in, found that it had the connector footprint mirrored from what I had. I desoldered the connector and resoldered it on backwards, and things just worked.&lt;&#x2F;p&gt;
&lt;p&gt;A good lesson I learned here is if the datasheet is in any way unclear about the footprint, find a reference design or someone else&#x27;s breakout board.&lt;&#x2F;p&gt;
&lt;p&gt;Below is a demo of the Prusto Watch drawing concentric circles on the display.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog_images&#x2F;prusto_watch_2&#x2F;display_demo.gif&quot; alt=&quot;LCD demo&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Currently the driver exposes the ability to clear the display, draw individual pixels, draw boxes and draw circles. I plan to clean up the code a little bit at some point, as well as add functionality for drawing text. Otherwise I am very happy with the speed of the library as well as the refresh-rate of the display.&lt;&#x2F;p&gt;
&lt;p&gt;There are a few tricks I used to make the driver memory efficient and quick. One trick was using a lookup-table for converting bytes from MSB to LSB order. The display requires the pixel addresses in LSB order, but currently the &lt;code&gt;embedded-hal&lt;&#x2F;code&gt; in Rust has no trait for setting the endianess of SPI communication, so I was stuck with only MSB.&lt;&#x2F;p&gt;
&lt;p&gt;The other trick was having the shadow buffer (in-memory version of what is displayed) store all of the data in a 128x16 (~2K) byte array and using lookup-tables for updating the bits of the shadow buffer based on X and Y values. In this way pixels of the shadow buffer can be changed almost as fast as array indexing. This also made flushing the buffer to the display easy since I could format the data in the way the LCD wanted.&lt;&#x2F;p&gt;
&lt;p&gt;One interesting thing I found while working is that when compiling the code in debug mode, the display lags while updating (you can see the individual lines update one at a time). However, when running in release mode with optimizations, the display behaves as shown above and is extremely quick to update.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;imu&quot;&gt;IMU&lt;&#x2F;h2&gt;
&lt;p&gt;The IMU is the last major peripheral I need to write a driver for and I don&#x27;t expect it to be too much of a problem once I can actually talk to it. However, I have had a lot of difficulty soldering the IMU on correctly.&lt;&#x2F;p&gt;
&lt;p&gt;After being extremely careful with solder-paste, I was able to reflow a board that seemed like the IMU was finally soldered correctly. But when trying to power it on, I found that the board was drawing 10mA when it should only be drawing less than 1mA, since this board only had the IMU and two bypass capacitors on it. It is unclear what exactly was going wrong since I was unable to find any shorts.&lt;&#x2F;p&gt;
&lt;p&gt;Due to the difficulty in soldering my current IMU, I am planning on using a &lt;a href=&quot;https:&#x2F;&#x2F;www.digikey.com&#x2F;product-detail&#x2F;en&#x2F;stmicroelectronics&#x2F;LIS3DETR&#x2F;497-16262-1-ND&#x2F;5799914&quot;&gt;different chip&lt;&#x2F;a&gt; for future iterations of the Prusto Watch. It will only be an accelerometer, but it draws less power and should hopefully be easier to solder on. I am also hoping that it is possible to hand-solder, since it would be awesome if this project could be assembled carefully with just a soldering iron.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;&#x2F;h2&gt;
&lt;p&gt;I am a bit behind schedule in terms of driver development, but I have worked through a number of road-blocks which should mean the rest of the driver development should be quick. I will hopefully not fry any more microcontrollers&#x2F;boards in the future since the tricky part of the 5V, LCD development is done (playing with 5V on a 3.3V board was a recipe for disaster).&lt;&#x2F;p&gt;
&lt;p&gt;I plan to have a third revision of the Prusto Watch development board out by late this week or early next week, and ideally it will be in a form factor which can actually be worn (although it will be bulky). In this way I can start working on packaging and getting the various devices working together.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Writing A Rust Driver for the RN4870 BLE Module</title>
        <published>2018-03-04T17:08:02-05:00</published>
        <updated>2018-03-04T17:08:02-05:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.byronwasti.com/writing-a-ble-driver-in-rust/"/>
        <id>https://www.byronwasti.com/writing-a-ble-driver-in-rust/</id>
        
        <content type="html" xml:base="https://www.byronwasti.com/writing-a-ble-driver-in-rust/">&lt;p&gt;&lt;em&gt;The repository for the driver is located here: https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;rn4870&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This post will document my process and thoughts on writing a driver for a bluetooth module using Rust and the &lt;code&gt;embedded-hal&lt;&#x2F;code&gt; crate. Note that this is not a driver release, as the driver is not complete and will most likely be going through a rewrite due to things I learned while writing the driver.&lt;&#x2F;p&gt;
&lt;p&gt;The specific bluetooth device I will be using is the RN4870 BLE castellated module. It features a simple UART interface and handles most of the complexities of BLE itself, making it very easy to get a simple BLE connection up and running. It also comes in a variety of sizes and packages, as shown below.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;blog_images&#x2F;ble_driver&#x2F;rn4870_image.jpg&quot; alt=&quot;image of BLE module&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;serial-interface&quot;&gt;Serial Interface&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;code&gt;embedded-hal&lt;&#x2F;code&gt; crate defines two traits for working with serial, &lt;code&gt;Read&lt;&#x2F;code&gt; and &lt;code&gt;Write&lt;&#x2F;code&gt;. Both traits have an associated error type as well as functions which implement serial transmission and reception. Of course the benefit of the HAL trait system is that we don&#x27;t have to care about the MCU-specific details and we can just use the &lt;code&gt;read()&lt;&#x2F;code&gt; and &lt;code&gt;write()&lt;&#x2F;code&gt; method calls on structs that implement one or both of these traits.&lt;&#x2F;p&gt;
&lt;p&gt;For writing a driver, I planned on simply having a struct which contains a generic object which implements both the &lt;code&gt;Read&lt;&#x2F;code&gt; and &lt;code&gt;Write&lt;&#x2F;code&gt; traits.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;hal::serial::{Read, Write};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;Rn4870&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;UART&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;uart&lt;&#x2F;span&gt;&lt;span&gt;: UART,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;impl&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;UART&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;Rn4870&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;UART&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;where
&lt;&#x2F;span&gt;&lt;span&gt;    UART: Write&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; + Read&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; Implementation of the driver
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, this immediately brings up an issue. The &lt;code&gt;stm32f30x-hal&lt;&#x2F;code&gt; crate, which implements the HAL traits for the stm32f30x series of microcontrollers (which is the MCU I have available for testing), has the serial interface split into two objects, a TX object and an RX object. In order to do this, the HAL implementation has to use various &lt;code&gt;unsafe&lt;&#x2F;code&gt; routines, such as:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;Ok&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;unsafe &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    ptr::read_volatile(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;$USARTX&lt;&#x2F;span&gt;&lt;span&gt;::ptr()).rdr &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;*const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;_ as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;*const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;span&gt;});
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The reason this has to be done is because the TX and RX functionality of UART have the same registers being used, which doesn&#x27;t really mesh well with the Rust ownership system. However, this unsafe workaround not only looks gross, but it also seems to do away with all of the benefits of the &lt;code&gt;svd2rust&lt;&#x2F;code&gt; generated crate which gives us safe access to registers.&lt;&#x2F;p&gt;
&lt;p&gt;So, instead of modifying my crate, I decided to add an implementation of the HAL traits for the &lt;code&gt;Serial&lt;&#x2F;code&gt; struct of the &lt;code&gt;stm32f30x-hal&lt;&#x2F;code&gt; crate. This implementation is much cleaner looking and avoids unsafe Rust.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;Ok&lt;&#x2F;span&gt;&lt;span&gt;((&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.usart.rdr.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;read&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;bits&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;0xFF&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;)
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The issue that still remains is that my driver crate requires for the Serial object to be &lt;em&gt;one&lt;&#x2F;em&gt; object with both &lt;code&gt;Read&lt;&#x2F;code&gt; and &lt;code&gt;Write&lt;&#x2F;code&gt; traits implemented. For microcontroller crates with the split TX&#x2F;RX implementation users will have to add an additional serial HAL implementation which abides by my driver&#x27;s requirements. What is unclear is whether or not this is the correct way to move forward; should drivers dictate how the HAL traits are implemented, or should there be a standard style of HAL trait implementation?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;serial-errors&quot;&gt;Serial Errors&lt;&#x2F;h2&gt;
&lt;p&gt;Before the RN4870 starts responding to serial transmission it needs to be reset by pulling the &lt;code&gt;nRST&lt;&#x2F;code&gt; pin low for a few milliseconds and then high. The RN4870 will then send a &quot;%REBOOT%&quot; ASCII message over its TX pin. To account for this, I can easily extend my &lt;code&gt;Rn4870&lt;&#x2F;code&gt; struct to take in an output pin, and then add a method which takes in a &lt;code&gt;Delay&lt;&#x2F;code&gt; object and implements the reset routine.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;hal::serial::{Read, Write};
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;hal::digital::OutputPin;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;use &lt;&#x2F;span&gt;&lt;span&gt;hal::blocking::delay::{DelayMs};
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;Rn4870&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;UART, NRST&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;uart&lt;&#x2F;span&gt;&lt;span&gt;: UART,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;nrst&lt;&#x2F;span&gt;&lt;span&gt;: NRST,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;impl&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;UART, NRST&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;Rn4870&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;UART, NRST&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;where
&lt;&#x2F;span&gt;&lt;span&gt;    UART: Write&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; + Read&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    NRST: OutputPin
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;reset&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;DELAY: DelayMs&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;u16&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;delay&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; DELAY) {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.nrst.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;set_low&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;        delay.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;delay_ms&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;u16&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.nrst.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;set_high&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This worked as expected, and using a digital analyzer I was able to verify that the RN4870 sent a &quot;%REBOOT%&quot; message. However, our driver ought to verify that a reboot occurred; we already have access to the serial interface!&lt;&#x2F;p&gt;
&lt;p&gt;I modified the &lt;code&gt;reset()&lt;&#x2F;code&gt; method to actually verify that the &quot;%REBOOT%&quot; message occurred, and for now we will just &lt;code&gt;panic!&lt;&#x2F;code&gt; if it doesn&#x27;t or any error occurs.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;reset&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;DELAY: DelayMs&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;u16&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;delay&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; DELAY) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.nrst.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;set_low&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;    delay.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;delay_ms&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;u16&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.nrst.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;set_high&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; expected &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#79740e;&quot;&gt;&amp;#39;%&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#79740e;&quot;&gt;&amp;#39;R&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#79740e;&quot;&gt;&amp;#39;E&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#79740e;&quot;&gt;&amp;#39;B&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#79740e;&quot;&gt;&amp;#39;O&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#79740e;&quot;&gt;&amp;#39;O&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#79740e;&quot;&gt;&amp;#39;T&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;b&lt;&#x2F;span&gt;&lt;span style=&quot;color:#79740e;&quot;&gt;&amp;#39;%&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;];
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; value &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;in&lt;&#x2F;span&gt;&lt;span&gt; expected {
&lt;&#x2F;span&gt;&lt;span&gt;        rec &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;block!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.uart.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;read&lt;&#x2F;span&gt;&lt;span&gt;()).&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;unwrap&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; rec &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;!=&lt;&#x2F;span&gt;&lt;span&gt; value {
&lt;&#x2F;span&gt;&lt;span&gt;            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;panic!&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#79740e;&quot;&gt;&amp;quot;Invalid value received&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);
&lt;&#x2F;span&gt;&lt;span&gt;        }
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This implementation has one obvious issue, which is if the RN4870 device never sends any data, we will be blocking forever. I am not entirely sure how to resolve this issue, since ideally we want to just wait a certain amount of time for a response and then emit an error. However, I do not see an easy way to do this, so currently my driver crate only has blocking reads and writes.&lt;&#x2F;p&gt;
&lt;p&gt;The other issue, which I ran into when running the code, is that it immediately has an &quot;Overrun&quot; error, which is when there is unread data in the read register of the UART peripheral and additional data comes in. This is normally not a big issue, and can be easily avoided by reading the entire data stream into memory before doing validation checks. However, I also realized that -- as far as I can tell -- there is no clean way to deal with &lt;em&gt;any&lt;&#x2F;em&gt; hardware errors.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;handling-hardware-errors&quot;&gt;Handling Hardware Errors&lt;&#x2F;h2&gt;
&lt;p&gt;First, I am going to back up a step. The stm32f30x family of microcontrollers will throw an &quot;Overrun&quot; error if there is unread data in the &lt;code&gt;RDR&lt;&#x2F;code&gt; register of a UART peripheral. When this error occurs, new data is thrown away and the &lt;code&gt;RDR&lt;&#x2F;code&gt; register will retain the old data. This error is also a persistent error, meaning it won&#x27;t resolve itself, even if you try to read from the &lt;code&gt;RDR&lt;&#x2F;code&gt; register. The way to resolve the error is to set the &lt;code&gt;ORECF&lt;&#x2F;code&gt; bit in the &lt;code&gt;ICR&lt;&#x2F;code&gt; register.&lt;&#x2F;p&gt;
&lt;p&gt;First, there are no HAL traits for dealing with serial errors, so my driver has no device-agnostic way of dealing with the overrun error.&lt;&#x2F;p&gt;
&lt;p&gt;Second, the &lt;code&gt;stm32f30x-hal&lt;&#x2F;code&gt; crate does not automatically reset the overrun error when it occurs. There is a similar issue for the SPI peripheral of this device, as noted here: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;japaric&#x2F;stm32f30x-hal&#x2F;issues&#x2F;13&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;japaric&#x2F;stm32f30x-hal&#x2F;issues&#x2F;13 &lt;&#x2F;a&gt;. The proposed solution is to automatically handle the error when it occurs. However, is auto-resetting the error the correct way to handle this situation? Currently nobody other than the OP has responded to the issue, and there is a pull-request which implements the auto-resetting of the SPI errors sitting with no responses. This does not instill confidence in me that this issue will be resolved soon.&lt;&#x2F;p&gt;
&lt;p&gt;So, as far as I can tell, there is no method for handling the overrun error in a clean, device-agnostic way. I decided to implement a workaround that allows users of the driver to have a device-specific handling of errors. To do this, I added a method which takes in a closure which will be run on the UART registers.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;handle_error&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;T: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;Fn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; UART) -&amp;gt; ()&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span&gt;: T) {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.uart);
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, I had to add functionality to the &lt;code&gt;stm32f30x-hal&lt;&#x2F;code&gt; crate for clearing the overrun error.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;pub fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;clear_overrun_error&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;u8 &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.usart.icr.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;write&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;w&lt;&#x2F;span&gt;&lt;span&gt;| w.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;orecf&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;set_bit&lt;&#x2F;span&gt;&lt;span&gt;());
&lt;&#x2F;span&gt;&lt;span&gt;    (&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.usart.rdr.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;read&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;bits&lt;&#x2F;span&gt;&lt;span&gt;() &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;&amp;amp; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#8f3f71;&quot;&gt;0xFF&lt;&#x2F;span&gt;&lt;span&gt;) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#b23c15;&quot;&gt;as &lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;u8
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And now I can use my error handling routine in my driver like so:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span&gt;ble.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;handle_error&lt;&#x2F;span&gt;&lt;span&gt;(|&lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;uart&lt;&#x2F;span&gt;&lt;span&gt;| { uart.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#b57614;&quot;&gt;clear_overflow_error&lt;&#x2F;span&gt;&lt;span&gt;(); } );
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, is this the correct way moving forward? Should driver crates expose safety-hatches for device-specific error routines? Is there a better way to handle errors within the microcontrollers HAL crates?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;implementing-a-state-machine&quot;&gt;Implementing a State Machine&lt;&#x2F;h2&gt;
&lt;p&gt;The final thing I want to talk about for my driver is attempting to implement a state machine using the type system of Rust. This state machine is based on the work done here: &lt;a href=&quot;https:&#x2F;&#x2F;hoverbear.org&#x2F;2016&#x2F;10&#x2F;12&#x2F;rust-state-machine-pattern&#x2F;&quot;&gt;https:&#x2F;&#x2F;hoverbear.org&#x2F;2016&#x2F;10&#x2F;12&#x2F;rust-state-machine-pattern&#x2F; &lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;My reasoning for using a state-machine is due to the two modes of the RN4870 module. It is either in Command Mode, where you can send different configuration commands, or it is in Data Mode, where it sends UART data over BLE. It would be nice if certain functionality is exposed based on the mode the module is in.&lt;&#x2F;p&gt;
&lt;p&gt;I won&#x27;t go through all of the small details of my implementation, which can be found in the &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;rn4870&#x2F;tree&#x2F;v0.1.0&quot;&gt;tagged driver repository&lt;&#x2F;a&gt;, but I do want to discuss some of the larger issues with having a state machine implemented using the type system.&lt;&#x2F;p&gt;
&lt;p&gt;The general idea behind the type system state machine I used (and is described in the blog post above) is that there are various structs which encompass the various states a system can be in. There is then a main struct (the state machine) which contains one of the various structs. Currently for my driver these are empty structs, but one could easily have data connected with them.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;CommandMode &lt;&#x2F;span&gt;&lt;span&gt;{}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;DataMode &lt;&#x2F;span&gt;&lt;span&gt;{}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;pub struct &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;Rn4870&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;UART, NRST, S&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;uart&lt;&#x2F;span&gt;&lt;span&gt;: UART,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;nrst&lt;&#x2F;span&gt;&lt;span&gt;: NRST,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#282828;&quot;&gt;_state&lt;&#x2F;span&gt;&lt;span&gt;: S,
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In order to implement state-specific functionality, you just have an implementation step which requires the state to be a specific struct. For instance:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#fcf0ca;color:#282828aa;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;impl&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;UART, NRST&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#407959;&quot;&gt;Rn4870&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;UART, NRST, DataMode&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;where
&lt;&#x2F;span&gt;&lt;span&gt;    UART: Write&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; + Read&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#9d0006;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    NRST: OutputPin,
&lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-style:italic;color:#928374;&quot;&gt;&#x2F;&#x2F; Functionality specific to the DataMode state    
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There are various other ways of implementing a state machine in Rust, but this method gets you a clean interface which hides away the implementation details from the user. However, one of the big issues with a state machine like this is how to handle errors.&lt;&#x2F;p&gt;
&lt;p&gt;For instance, in order to transition from data mode to command mode for the RN4870 you have to send &quot;$$$&quot; over serial and the RN4870 will then respond with &quot;CMD&amp;gt; &quot;. What if there is a hardware serial error when trying to receive the RN4870 message, and we have no idea if the response was &quot;CMD&amp;gt; &quot; or some other message? Which state are we actually in?&lt;&#x2F;p&gt;
&lt;p&gt;Currently if there is an error during a state transition, my driver will return that error and destroy the &lt;code&gt;Rn4870&lt;&#x2F;code&gt; object (since it is consumed by the state-transition method call and only the error is returned). This is not great behavior, and I don&#x27;t see a great way to rectify the situation given my current implementation.&lt;&#x2F;p&gt;
&lt;p&gt;It would be great to read about other methods for having state machines in drivers, and possibly having a collection of best-practices for writing drivers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;&#x2F;h2&gt;
&lt;p&gt;The Rust embedded ecosystem is still very young and it seems like there are still a few big issues with the &lt;code&gt;embedded-hal&lt;&#x2F;code&gt; trait system, such as error handling. I think there are a lot of places for less experienced embedded developers (such as myself) to contribute, but it would be nice to have a more organized system for driver submission and feedback. I would also love to beef up the &lt;code&gt;stm32f30x-hal&lt;&#x2F;code&gt; crate with additional functionality, but the lack of direction in how to do so and lack of any comments on current pull-requests has made me hesitant.&lt;&#x2F;p&gt;
&lt;p&gt;I also think it would be awesome to have a living best-practices document for writing drivers. This way people new to the embedded-Rust ecosystem can get going much more quickly.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Prusto Watch #1: First Steps into Arm and Embedded Rust</title>
        <published>2018-02-12T21:34:57-05:00</published>
        <updated>2018-02-12T21:34:57-05:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.byronwasti.com/prusto-watch-1/"/>
        <id>https://www.byronwasti.com/prusto-watch-1/</id>
        
        <summary type="html">&lt;p&gt;In this post I will describe my initial dive into Arm development using Rust. There are potentially many mistakes in my understanding, so this post should not be used as a reference for how to do embedded development in Rust. However, I think it is useful to describe the learning process so that those more experienced can see the pain-points of beginners.&lt;&#x2F;p&gt;</summary>
        
    </entry>
    <entry xml:lang="en">
        <title>Prusto Watch #0: Design &amp; Goals of the Project</title>
        <published>2017-11-23T09:59:59-05:00</published>
        <updated>2017-11-23T09:59:59-05:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://www.byronwasti.com/prusto-watch-0/"/>
        <id>https://www.byronwasti.com/prusto-watch-0/</id>
        
        <content type="html" xml:base="https://www.byronwasti.com/prusto-watch-0/">&lt;p&gt;The Prusto Watch is an Open Source smart watch with firmware written in Rust, or at least it will be that one day. Currently, the Prusto Watch is just a concept. I plan on writing a series of blog posts documenting my progress in developing the watch, with a focus on going through my thought process. A large goal of this project is to help document the current state of embedded development in Rust, since currently there is not a lot out there.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Code Repo is here: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;prusto-watch&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;prusto-watch&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Hardware Repo is here: &lt;a href=&quot;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;prusto-watch-hardware&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;byronwasti&#x2F;prusto-watch-hardware&lt;&#x2F;a&gt;&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Before I dive into the details, this post will be an overview of what this project will entail.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;functionality&quot;&gt;Functionality&lt;&#x2F;h2&gt;
&lt;p&gt;The Prusto Watch is going to have only basic features of a smart watch, and will not be running a full OS such as Android or iOS. The core features that are needed:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Bluetooth connectivity: Ideally BLE for simple phone connectivity&lt;&#x2F;li&gt;
&lt;li&gt;Screen: Low-power OLED or E-ink&lt;&#x2F;li&gt;
&lt;li&gt;IMU: Accelerometer, gyroscope and magnetometer (for compass functionality)&lt;&#x2F;li&gt;
&lt;li&gt;Vibration: Small vibration motor for notifications&lt;&#x2F;li&gt;
&lt;li&gt;User input: Capacitive-touch &quot;ring&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Obviously different users will require different functionality, and since this will be an open source project, anyone is free to fork the project and add additional features. There are also a few features which are pretty broad, such as user input. This could be buttons, it could be a touchscreen, or it could even be voice-processing. For this project I am planning on having a small ring around the screen which will be able to detect the users fingers using capacitive touch.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;overall-goals-of-the-project&quot;&gt;Overall Goals of the Project&lt;&#x2F;h2&gt;
&lt;p&gt;The project has two overarching goals.&lt;&#x2F;p&gt;
&lt;p&gt;First, the project will attempt to utilize as much open-source software and hardware as possible. This will lower the bar of entry for people who want to hack on the project.&lt;&#x2F;p&gt;
&lt;p&gt;Second, the project will attempt to use bleeding-edge Rust embedded best-practices. This will bring a lot of headaches with it, considering the fact that a lot of the embedded work in Rust is rapidly evolving. However, by keeping up with the bleeding-edge design this project will be a good test-case for all of the work done.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
