APL Notes: Lil Mistakes
  1. Non-syntax: then
  2. Using goawk

Non-syntax: then

 (on _ x do if x then 2 else 3 end end) @ range 3
(3,2,2)
 (on _ x do if x 2 else 3 end end) @ range 3
(3,2,2)

The then is a variable whose value is thrown away, as it's followed by 2.

 if 1 then else 2 end
0
 then:2 if 1 then else 3 end
2

Using goawk

Goawk is an embeddable awk implementation in go, which offers

  1. extensions to the language that are implemented in go
  2. binary deployment as a static executable

These are pretty neat features, but the performance and resource characteristics of goawk are absolutely abysmal compared to GNU Awk, which is itself generally bad compared to the C and even the JS implementation.

Here's Node vs. C:

Benchmark 1 (9 runs): node node.js words7.lil
  measurement          mean ± σ            min … max           outliers         delta
  wall_time           616ms ± 9.35ms     606ms …  633ms          0 ( 0%)        0%
  peak_rss           81.4MB ±  826KB    80.2MB … 83.0MB          0 ( 0%)        0%
  cpu_cycles         3.01G  ± 29.9M     2.96G  … 3.05G           0 ( 0%)        0%
  instructions       13.0G  ± 23.1M     12.9G  … 13.0G           0 ( 0%)        0%
  cache_references   81.2M  ± 6.97M     75.6M  … 93.9M           0 ( 0%)        0%
  cache_misses       8.16M  ±  168K     7.88M  … 8.40M           0 ( 0%)        0%
  branch_misses      8.17M  ±  162K     7.92M  … 8.43M           0 ( 0%)        0%
Benchmark 2 (449 runs): lilt words7.lil
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          11.1ms ±  486us    10.2ms … 15.0ms         26 ( 6%)        ⚡- 98.2% ±  0.1%
  peak_rss           17.4MB ±  121KB    17.0MB … 17.6MB          4 ( 1%)        ⚡- 78.7% ±  0.1%
  cpu_cycles         23.0M  ±  768K     22.4M  … 33.8M          39 ( 9%)        ⚡- 99.2% ±  0.1%
  instructions       83.8M  ± 3.87      83.8M  … 83.8M           9 ( 2%)        ⚡- 99.4% ±  0.0%
  cache_references   1.15M  ± 23.2K     1.09M  … 1.35M          34 ( 8%)        ⚡- 98.6% ±  0.8%
  cache_misses       31.0K  ± 1.60K     28.7K  … 41.5K          25 ( 6%)        ⚡- 99.6% ±  0.2%
  branch_misses       102K  ± 1.43K     99.9K  …  127K           8 ( 2%)        ⚡- 98.8% ±  0.2%

Then Node vs. GNU Awk:

Benchmark 1 (9 runs): node node.js words7.lil
  measurement          mean ± σ            min … max           outliers         delta
  wall_time           614ms ± 44.4ms     587ms …  731ms          1 (11%)        0%
  peak_rss           81.0MB ±  648KB    80.0MB … 82.0MB          0 ( 0%)        0%
  cpu_cycles         3.06G  ±  229M     2.94G  … 3.66G           1 (11%)        0%
  instructions       13.0G  ± 18.9M     13.0G  … 13.0G           0 ( 0%)        0%
  cache_references   83.9M  ± 18.0M     74.4M  …  131M           1 (11%)        0%
  cache_misses       8.25M  ±  255K     7.94M  … 8.77M           0 ( 0%)        0%
  branch_misses      8.13M  ±  124K     8.05M  … 8.37M           0 ( 0%)        0%
Benchmark 2 (3 runs): lila words7.lil
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          16.3s  ±  513ms    15.8s  … 16.8s           0 ( 0%)        💩+2552.8% ± 56.3%
  peak_rss           48.2MB ±  133KB    48.1MB … 48.4MB          0 ( 0%)        ⚡- 40.5% ±  1.1%
  cpu_cycles         65.1G  ± 2.31G     63.5G  … 67.7G           0 ( 0%)        💩+2025.6% ± 51.2%
  instructions        201G  ±  680       201G  …  201G           0 ( 0%)        💩+1447.7% ±  0.2%
  cache_references   2.94G  ±  147M     2.83G  … 3.11G           0 ( 0%)        💩+3408.1% ± 120.1%
  cache_misses        164M  ± 8.00M      154M  …  168M           0 ( 0%)        💩+1882.6% ± 64.6%
  branch_misses      10.1M  ±  208K     9.93M  … 10.3M           0 ( 0%)        💩+ 24.3% ±  2.6%

Then Goawk vs. GNU Awk:

Benchmark 1 (3 runs): ../goawk/goawk -f /usr/local/bin/lila words7.lil                                          
  measurement          mean ± σ            min … max           outliers         delta                           
  wall_time          21.9s  ±  366ms    21.6s  … 22.3s           0 ( 0%)        0%                              
  peak_rss            233MB ± 6.17MB     229MB …  240MB          0 ( 0%)        0%                              
  cpu_cycles          145G  ± 1.17G      144G  …  146G           0 ( 0%)        0%                              
  instructions        351G  ±  620M      350G  …  351G           0 ( 0%)        0%                              
  cache_references   7.14G  ±  164M     6.99G  … 7.32G           0 ( 0%)        0%                              
  cache_misses        991M  ± 7.68M      984M  …  999M           0 ( 0%)        0%
  branch_misses       334M  ± 5.00M      329M  …  339M           0 ( 0%)        0%
Benchmark 2 (3 runs): lila words7.lil
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          16.1s  ±  333ms    15.9s  … 16.5s           0 ( 0%)        ⚡- 26.4% ±  3.6%
  peak_rss           48.0MB ± 10.8KB    48.0MB … 48.0MB          0 ( 0%)        ⚡- 79.4% ±  4.2%
  cpu_cycles         64.2G  ±  425M     63.9G  … 64.7G           0 ( 0%)        ⚡- 55.8% ±  1.4%
  instructions        201G  ± 9.92K      201G  …  201G           0 ( 0%)        ⚡- 42.7% ±  0.3%
  cache_references   2.91G  ± 42.1M     2.87G  … 2.95G           0 ( 0%)        ⚡- 59.3% ±  3.8%
  cache_misses        170M  ± 4.44M      165M  …  174M           0 ( 0%)        ⚡- 82.8% ±  1.4%
  branch_misses      10.3M  ±  360K     10.1M  … 10.7M           0 ( 0%)        ⚡- 96.9% ±  2.4%

On a larger version of this problem, C Lil takes 1s and 1.11GB of memory vs. Goawk Lil which pegged 7 CPUs for more than 40 minutes before I interrupted it.