packages feed

atomic-counter 0.1 → 0.1.1

raw patch · 7 files changed

+904/−706 lines, 7 filesdep ~tastydep ~tasty-benchPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: tasty, tasty-bench

API changes (from Hackage documentation)

- Control.Concurrent.Counter.Unlifted: set :: Counter s -> Int# -> State# s -> State# s
+ Control.Concurrent.Counter.Unlifted: set :: Counter s -> Int# -> State# s -> (# State# s #)

Files

Changelog.md view
@@ -1,3 +1,9 @@+# 0.1.1++- On non-javascript platforms the counter is implemented directly in+  CMM instead of using singleton primitive array. Likely to occupy+  less memory and perform faster (https://github.com/sergv/atomic-counter/pull/3).+ # 0.1  Initial release
+ Counter.cmm view
@@ -0,0 +1,96 @@+#include "Cmm.h"++INFO_TABLE(stg_Counter, 0, 1, MUT_PRIM, "Counter", "Counter") ()+{+  foreign "C" barf("stg_Counter entered!", NULL) never returns;+}++stg_newCounterzh (W_ x)+{+  P_ c;+  ("ptr" c) = ccall allocate(MyCapability() "ptr", BYTES_TO_WDS(SIZEOF_StgHeader + WDS(1)));+  SET_HDR(c, stg_Counter_info, CCCS);+  W_[c + SIZEOF_StgHeader] = x;+  return (c);+}++stg_atomicGetCounterzh (P_ c)+{+  W_ x;+  // load_seqcst64 is available since GHC 9.4+  (x) = prim %load_seqcst64(c + SIZEOF_StgHeader);+  return (x);+}++stg_atomicSetCounterzh (P_ c, W_ x)+{+  // store_seqcst64 is available since GHC 9.4+  prim %store_seqcst64(c + SIZEOF_StgHeader, x);+  return ();+}++stg_atomicAddCounterzh (P_ c, W_ x)+{+  W_ y;+#if __GLASGOW_HASKELL__ >= 907+  (y) = prim %fetch_add64(c + SIZEOF_StgHeader, x);+#else+  (y) = ccall hs_atomic_add64(c + SIZEOF_StgHeader, x);+#endif+  return (y);+}++stg_atomicSubCounterzh (P_ c, W_ x)+{+  W_ y;+#if __GLASGOW_HASKELL__ >= 907+  (y) = prim %fetch_sub64(c + SIZEOF_StgHeader, x);+#else+  (y) = ccall hs_atomic_sub64(c + SIZEOF_StgHeader, x);+#endif+  return (y);+}++stg_atomicAndCounterzh (P_ c, W_ x)+{+  W_ y;+#if __GLASGOW_HASKELL__ >= 907+  (y) = prim %fetch_and64(c + SIZEOF_StgHeader, x);+#else+  (y) = ccall hs_atomic_and64(c + SIZEOF_StgHeader, x);+#endif+  return (y);+}++stg_atomicOrCounterzh (P_ c, W_ x)+{+  W_ y;+#if __GLASGOW_HASKELL__ >= 907+  (y) = prim %fetch_or64(c + SIZEOF_StgHeader, x);+#else+  (y) = ccall hs_atomic_or64(c + SIZEOF_StgHeader, x);+#endif+  return (y);+}++stg_atomicXorCounterzh (P_ c, W_ x)+{+  W_ y;+#if __GLASGOW_HASKELL__ >= 907+  (y) = prim %fetch_xor64(c + SIZEOF_StgHeader, x);+#else+  (y) = ccall hs_atomic_xor64(c + SIZEOF_StgHeader, x);+#endif+  return (y);+}++stg_atomicNandCounterzh (P_ c, W_ x)+{+  W_ y;+#if __GLASGOW_HASKELL__ >= 907+  (y) = prim %fetch_nand64(c + SIZEOF_StgHeader, x);+#else+  (y) = ccall hs_atomic_nand64(c + SIZEOF_StgHeader, x);+#endif+  return (y);+}
Readme.md view
@@ -8,699 +8,714 @@  Good use case is a shared counter that multiple threads increment. -Operations translate to atomic CPU instructions which make these cells-way faster that even vanilla `IORef`. Value inside the cell is unboxed-which contributes to outperforming all other shared vars because they-box the value they store. For integers boxing is especially bad.--# Benchmark--### Summary--Depending on number of threads `Counter` from this package can be-up to 10 times faster than next best `TVar` from the `stm` package.--### Details--The benchmark is to spawn N threads each of which will increment the-same counter by 1 for a number of iterations.--Test setup: Intel i5-9600K CPU @ 3.70GHz, 6 cores, no hyperthreading, GHC 9.4.4.--NB `IORef inconsistent` is the benchmark that just reads and writes-`IORef` with the fastest functions the `IORef` supports. It gives-wrong results when multiple threads access `IORef` this way since-these reads and writes are not synchronized. It’s included only for-speed comparison purposes. All others do proper synchronization of-increments between the threads. Current package is shown as `Counter`.--```-$ cabal run --builddir /tmp/dist bench -- -j1 --timeout 30-All-  Correctness:          OK (15.52s)-    +++ OK, passed 10000 tests.-  Read/write contention with 10 iterations and 1 threads-    Counter:            OK (0.42s)-      785  ns ±  27 ns-    IORef inconsistent: OK (0.16s)-      1.12 μs ±  95 ns-    IORef atomic:       OK (0.16s)-      1.08 μs ±  99 ns-    MVar:               OK (0.62s)-      1.15 μs ±  40 ns-    TMVar:              OK (0.50s)-      896  ns ±  31 ns-    TVar:               OK (0.15s)-      1.01 μs ±  92 ns-    Addr:               OK (0.74s)-      679  ns ±  48 ns-  Read/write contention with 100 iterations and 1 threads-    Counter:            OK (0.15s)-      1.01 μs ±  89 ns-    IORef inconsistent: OK (0.23s)-      3.38 μs ± 198 ns-    IORef atomic:       OK (0.44s)-      3.03 μs ±  91 ns-    MVar:               OK (0.24s)-      3.35 μs ± 167 ns-    TMVar:              OK (0.17s)-      4.64 μs ± 328 ns-    TVar:               OK (0.14s)-      4.09 μs ± 372 ns-    Addr:               OK (0.57s)-      1.04 μs ±  43 ns-  Read/write contention with 1000 iterations and 1 threads-    Counter:            OK (0.17s)-      4.80 μs ± 389 ns-    IORef inconsistent: OK (0.16s)-      18.4 μs ± 1.4 μs-    IORef atomic:       OK (0.19s)-      23.3 μs ± 2.1 μs-    MVar:               OK (0.13s)-      15.6 μs ± 1.3 μs-    TMVar:              OK (0.21s)-      49.5 μs ± 4.8 μs-    TVar:               OK (0.16s)-      38.3 μs ± 3.3 μs-    Addr:               OK (0.22s)-      5.88 μs ± 369 ns-  Read/write contention with 10000 iterations and 1 threads-    Counter:            OK (0.18s)-      41.8 μs ± 2.7 μs-    IORef inconsistent: OK (0.23s)-      224  μs ±  21 μs-    IORef atomic:       OK (0.18s)-      169  μs ±  15 μs-    MVar:               OK (0.20s)-      187  μs ±  15 μs-    TMVar:              OK (0.21s)-      409  μs ±  25 μs-    TVar:               OK (0.16s)-      304  μs ±  25 μs-    Addr:               OK (0.22s)-      52.7 μs ± 4.1 μs-  Read/write contention with 10 iterations and 2 threads-    Counter:            OK (0.11s)-      7.05 μs ± 667 ns-    IORef inconsistent: OK (0.22s)-      7.43 μs ± 599 ns-    IORef atomic:       OK (0.22s)-      7.19 μs ± 719 ns-    MVar:               OK (0.47s)-      7.42 μs ± 671 ns-    TMVar:              OK (0.24s)-      8.01 μs ± 773 ns-    TVar:               OK (0.22s)-      7.45 μs ± 585 ns-    Addr:               OK (0.23s)-      6.99 μs ± 601 ns-  Read/write contention with 100 iterations and 2 threads-    Counter:            OK (0.16s)-      8.88 μs ± 749 ns-    IORef inconsistent: OK (0.16s)-      12.1 μs ± 975 ns-    IORef atomic:       OK (0.16s)-      12.1 μs ± 736 ns-    MVar:               OK (0.13s)-      17.6 μs ± 1.7 μs-    TMVar:              OK (0.18s)-      29.7 μs ± 2.2 μs-    TVar:               OK (0.14s)-      24.8 μs ± 2.0 μs-    Addr:               OK (0.29s)-      8.52 μs ± 555 ns-  Read/write contention with 1000 iterations and 2 threads-    Counter:            OK (0.85s)-      42.8 μs ± 1.2 μs-    IORef inconsistent: OK (4.85s)-      140  μs ± 2.1 μs-    IORef atomic:       OK (0.30s)-      277  μs ±  12 μs-    MVar:               OK (0.33s)-      5.29 ms ± 224 μs-    TMVar:              OK (0.64s)-      270  μs ±  16 μs-    TVar:               OK (0.64s)-      306  μs ±  18 μs-    Addr:               OK (0.23s)-      47.4 μs ± 2.1 μs-  Read/write contention with 10000 iterations and 2 threads-    Counter:            OK (0.11s)-      298  μs ±  28 μs-    IORef inconsistent: OK (0.08s)-      1.01 ms ±  99 μs-    IORef atomic:       OK (0.99s)-      1.26 ms ±  19 μs-    MVar:               OK (0.45s)-      62.7 ms ± 3.9 ms-    TMVar:              OK (0.42s)-      2.96 ms ± 257 μs-    TVar:               OK (6.90s)-      3.26 ms ± 149 μs-    Addr:               OK (0.08s)-      527  μs ±  45 μs-  Read/write contention with 10 iterations and 4 threads-    Counter:            OK (0.16s)-      15.0 μs ± 820 ns-    IORef inconsistent: OK (0.17s)-      16.4 μs ± 946 ns-    IORef atomic:       OK (0.38s)-      19.2 μs ± 937 ns-    MVar:               OK (0.20s)-      27.5 μs ± 2.4 μs-    TMVar:              OK (0.10s)-      20.2 μs ± 1.3 μs-    TVar:               OK (0.19s)-      18.2 μs ± 781 ns-    Addr:               OK (0.09s)-      15.5 μs ± 1.4 μs-  Read/write contention with 100 iterations and 4 threads-    Counter:            OK (0.40s)-      23.1 μs ± 1.8 μs-    IORef inconsistent: OK (0.09s)-      56.3 μs ± 4.7 μs-    IORef atomic:       OK (0.24s)-      157  μs ± 3.9 μs-    MVar:               OK (0.16s)-      1.20 ms ± 115 μs-    TMVar:              OK (0.07s)-      193  μs ±  19 μs-    TVar:               OK (0.13s)-      214  μs ± 7.9 μs-    Addr:               OK (0.39s)-      22.3 μs ± 491 ns-  Read/write contention with 1000 iterations and 4 threads-    Counter:            OK (0.17s)-      242  μs ±  13 μs-    IORef inconsistent: OK (0.07s)-      485  μs ±  32 μs-    IORef atomic:       OK (2.02s)-      1.51 ms ±  54 μs-    MVar:               OK (0.19s)-      12.4 ms ± 1.2 ms-    TMVar:              OK (0.14s)-      2.01 ms ±  76 μs-    TVar:               OK (0.07s)-      1.92 ms ±  99 μs-    Addr:               OK (0.08s)-      233  μs ±  12 μs-  Read/write contention with 10000 iterations and 4 threads-    Counter:            OK (0.17s)-      2.44 ms ±  82 μs-    IORef inconsistent: OK (0.08s)-      4.49 ms ± 291 μs-    IORef atomic:       OK (0.84s)-      18.3 ms ± 941 μs-    MVar:               OK (0.39s)-      125  ms ±  12 ms-    TMVar:              OK (0.16s)-      18.7 ms ± 1.8 ms-    TVar:               OK (0.08s)-      18.8 ms ± 1.3 ms-    Addr:               OK (0.67s)-      2.27 ms ±  80 μs-  Read/write contention with 10 iterations and 6 threads-    Counter:            OK (0.23s)-      24.1 μs ± 1.7 μs-    IORef inconsistent: OK (0.25s)-      26.1 μs ± 1.4 μs-    IORef atomic:       OK (0.18s)-      41.1 μs ± 2.2 μs-    MVar:               OK (0.32s)-      46.8 μs ± 3.2 μs-    TMVar:              OK (0.53s)-      33.8 μs ± 2.5 μs-    TVar:               OK (0.07s)-      32.5 μs ± 2.7 μs-    Addr:               OK (0.12s)-      24.5 μs ± 2.4 μs-  Read/write contention with 100 iterations and 6 threads-    Counter:            OK (0.29s)-      40.2 μs ± 3.1 μs-    IORef inconsistent: OK (0.12s)-      100  μs ± 5.9 μs-    IORef atomic:       OK (0.14s)-      352  μs ±  30 μs-    MVar:               OK (0.12s)-      1.82 ms ± 168 μs-    TMVar:              OK (0.92s)-      544  μs ±  43 μs-    TVar:               OK (0.23s)-      561  μs ±  28 μs-    Addr:               OK (0.30s)-      38.9 μs ± 2.1 μs-  Read/write contention with 1000 iterations and 6 threads-    Counter:            OK (0.87s)-      477  μs ± 4.3 μs-    IORef inconsistent: OK (0.20s)-      1.01 ms ±  61 μs-    IORef atomic:       OK (0.85s)-      3.05 ms ± 154 μs-    MVar:               OK (0.62s)-      19.8 ms ± 1.5 ms-    TMVar:              OK (0.06s)-      4.65 ms ± 428 μs-    TVar:               OK (0.25s)-      4.78 ms ± 117 μs-    Addr:               OK (0.22s)-      477  μs ±  32 μs-  Read/write contention with 10000 iterations and 6 threads-    Counter:            OK (2.01s)-      4.82 ms ± 131 μs-    IORef inconsistent: OK (0.12s)-      9.87 ms ± 230 μs-    IORef atomic:       OK (6.61s)-      66.0 ms ±  24 ms-    MVar:               OK (1.31s)-      194  ms ± 3.5 ms-    TMVar:              OK (0.63s)-      52.3 ms ± 290 μs-    TVar:               OK (0.07s)-      48.5 ms ± 4.5 ms-    Addr:               OK (0.03s)-      4.82 ms ± 479 μs-  Read/write contention with 10 iterations and 8 threads-    Counter:            OK (0.13s)-      26.3 μs ± 2.1 μs-    IORef inconsistent: OK (0.16s)-      28.8 μs ± 1.8 μs-    IORef atomic:       OK (0.25s)-      56.2 μs ± 5.2 μs-    MVar:               OK (0.71s)-      95.8 μs ± 9.1 μs-    TMVar:              OK (0.19s)-      52.3 μs ± 1.8 μs-    TVar:               OK (0.18s)-      47.9 μs ± 2.0 μs-    Addr:               OK (0.13s)-      26.1 μs ± 1.9 μs-  Read/write contention with 100 iterations and 8 threads-    Counter:            OK (0.05s)-      60.9 μs ± 5.5 μs-    IORef inconsistent: OK (0.58s)-      120  μs ± 2.4 μs-    IORef atomic:       OK (0.62s)-      706  μs ± 9.6 μs-    MVar:               OK (0.16s)-      2.26 ms ± 209 μs-    TMVar:              OK (0.07s)-      571  μs ±  53 μs-    TVar:               OK (0.28s)-      556  μs ± 6.8 μs-    Addr:               OK (0.10s)-      58.8 μs ± 5.0 μs-  Read/write contention with 1000 iterations and 8 threads-    Counter:            OK (0.28s)-      588  μs ±  17 μs-    IORef inconsistent: OK (1.07s)-      1.15 ms ± 8.3 μs-    IORef atomic:       OK (5.86s)-      6.91 ms ± 986 μs-    MVar:               OK (0.71s)-      22.9 ms ± 842 μs-    TMVar:              OK (0.16s)-      6.10 ms ± 542 μs-    TVar:               OK (0.09s)-      5.76 ms ± 457 μs-    Addr:               OK (0.07s)-      624  μs ±  49 μs-  Read/write contention with 10000 iterations and 8 threads-    Counter:            OK (0.65s)-      5.99 ms ± 259 μs-    IORef inconsistent: OK (0.08s)-      11.4 ms ± 403 μs-    IORef atomic:       OK (9.50s)-      160  ms ±  43 ms-    MVar:               OK (0.74s)-      246  ms ±  21 ms-    TMVar:              OK (0.04s)-      50.4 ms ± 3.0 ms-    TVar:               OK (0.79s)-      58.5 ms ± 1.3 ms-    Addr:               OK (0.17s)-      5.51 ms ± 226 μs-  Read/write contention with 10 iterations and 12 threads-    Counter:            OK (0.14s)-      29.8 μs ± 2.8 μs-    IORef inconsistent: OK (0.08s)-      34.5 μs ± 2.8 μs-    IORef atomic:       OK (0.27s)-      71.0 μs ± 3.3 μs-    MVar:               OK (0.23s)-      229  μs ±  15 μs-    TMVar:              OK (0.87s)-      81.1 μs ± 697 ns-    TVar:               OK (0.21s)-      76.2 μs ± 5.6 μs-    Addr:               OK (0.14s)-      29.3 μs ± 2.3 μs-  Read/write contention with 100 iterations and 12 threads-    Counter:            OK (0.25s)-      92.8 μs ± 7.8 μs-    IORef inconsistent: OK (0.06s)-      179  μs ±  16 μs-    IORef atomic:       OK (0.43s)-      976  μs ±  30 μs-    MVar:               OK (0.43s)-      3.07 ms ± 172 μs-    TMVar:              OK (0.11s)-      946  μs ±  44 μs-    TVar:               OK (0.24s)-      1.05 ms ±  43 μs-    Addr:               OK (0.24s)-      90.4 μs ± 4.5 μs-  Read/write contention with 1000 iterations and 12 threads-    Counter:            OK (0.11s)-      1.01 ms ±  37 μs-    IORef inconsistent: OK (0.10s)-      1.76 ms ± 174 μs-    IORef atomic:       OK (2.73s)-      11.9 ms ± 434 μs-    MVar:               OK (0.28s)-      36.3 ms ± 2.7 ms-    TMVar:              OK (0.07s)-      10.6 ms ± 819 μs-    TVar:               OK (0.25s)-      9.24 ms ± 596 μs-    Addr:               OK (0.84s)-      902  μs ±  61 μs-  Read/write contention with 10000 iterations and 12 threads-    Counter:            OK (0.25s)-      9.15 ms ± 853 μs-    IORef inconsistent: OK (0.12s)-      18.7 ms ± 904 μs-    IORef atomic:       OK (2.28s)-      292  ms ±  19 ms-    MVar:               OK (5.38s)-      350  ms ± 4.1 ms-    TMVar:              OK (2.57s)-      104  ms ± 5.6 ms-    TVar:               OK (0.62s)-      104  ms ± 3.0 ms-    Addr:               OK (0.12s)-      9.65 ms ± 799 μs-  Read/write contention with 10 iterations and 16 threads-    Counter:            OK (0.09s)-      40.4 μs ± 2.8 μs-    IORef inconsistent: OK (0.11s)-      47.7 μs ± 2.9 μs-    IORef atomic:       OK (0.29s)-      133  μs ± 8.6 μs-    MVar:               OK (0.76s)-      390  μs ±  13 μs-    TMVar:              OK (0.08s)-      98.5 μs ± 6.9 μs-    TVar:               OK (1.18s)-      125  μs ±  10 μs-    Addr:               OK (0.09s)-      40.6 μs ± 2.7 μs-  Read/write contention with 100 iterations and 16 threads-    Counter:            OK (0.08s)-      133  μs ± 6.5 μs-    IORef inconsistent: OK (0.14s)-      275  μs ± 9.8 μs-    IORef atomic:       OK (1.04s)-      1.28 ms ±  31 μs-    MVar:               OK (0.57s)-      4.34 ms ± 330 μs-    TMVar:              OK (0.60s)-      1.39 ms ± 8.3 μs-    TVar:               OK (0.16s)-      1.40 ms ±  73 μs-    Addr:               OK (0.16s)-      130  μs ±  12 μs-  Read/write contention with 1000 iterations and 16 threads-    Counter:            OK (0.30s)-      1.31 ms ±  82 μs-    IORef inconsistent: OK (0.14s)-      2.51 ms ±  56 μs-    IORef atomic:       OK (3.03s)-      14.6 ms ± 1.4 ms-    MVar:               OK (0.71s)-      46.5 ms ± 3.9 ms-    TMVar:              OK (0.08s)-      13.8 ms ± 721 μs-    TVar:               OK (0.69s)-      12.8 ms ± 806 μs-    Addr:               OK (0.29s)-      1.33 ms ±  23 μs-  Read/write contention with 10000 iterations and 16 threads-    Counter:            OK (0.16s)-      12.9 ms ± 1.1 ms-    IORef inconsistent: OK (0.15s)-      25.5 ms ± 2.2 ms-    IORef atomic:       OK (8.01s)-      515  ms ±  51 ms-    MVar:               OK (1.57s)-      501  ms ±  31 ms-    TMVar:              OK (0.88s)-      149  ms ±  11 ms-    TVar:               OK (1.72s)-      145  ms ± 1.1 ms-    Addr:               OK (0.08s)-      11.4 ms ± 480 μs-  Read/write contention with 10 iterations and 20 threads-    Counter:            OK (0.11s)-      50.2 μs ± 4.9 μs-    IORef inconsistent: OK (0.10s)-      57.2 μs ± 3.8 μs-    IORef atomic:       OK (0.35s)-      192  μs ±  17 μs-    MVar:               OK (0.26s)-      533  μs ±  29 μs-    TMVar:              OK (0.10s)-      162  μs ±  14 μs-    TVar:               OK (0.05s)-      166  μs ±  11 μs-    Addr:               OK (0.09s)-      48.5 μs ± 3.3 μs-  Read/write contention with 100 iterations and 20 threads-    Counter:            OK (0.05s)-      170  μs ±  14 μs-    IORef inconsistent: OK (0.16s)-      334  μs ±  11 μs-    IORef atomic:       OK (0.53s)-      1.44 ms ± 112 μs-    MVar:               OK (0.35s)-      5.29 ms ± 217 μs-    TMVar:              OK (0.05s)-      1.90 ms ± 114 μs-    TVar:               OK (0.05s)-      1.75 ms ± 111 μs-    Addr:               OK (0.05s)-      131  μs ±  11 μs-  Read/write contention with 1000 iterations and 20 threads-    Counter:            OK (0.18s)-      1.73 ms ±  38 μs-    IORef inconsistent: OK (0.04s)-      3.06 ms ± 305 μs-    IORef atomic:       OK (0.44s)-      17.4 ms ± 797 μs-    MVar:               OK (1.80s)-      56.3 ms ± 1.3 ms-    TMVar:              OK (0.44s)-      18.7 ms ± 761 μs-    TVar:               OK (0.05s)-      18.3 ms ± 1.8 ms-    Addr:               OK (0.05s)-      1.72 ms ± 103 μs-  Read/write contention with 10000 iterations and 20 threads-    Counter:            OK (0.05s)-      17.6 ms ± 1.2 ms-    IORef inconsistent: OK (0.04s)-      31.2 ms ± 1.8 ms-    IORef atomic:       OK (10.54s)-      659  ms ± 346 ms-    MVar:               OK (1.96s)-      627  ms ±  46 ms-    TMVar:              OK (1.10s)-      192  ms ± 9.0 ms-    TVar:               OK (1.09s)-      183  ms ±  16 ms-    Addr:               OK (0.21s)-      17.0 ms ± 260 μs-  Read/write contention with 10 iterations and 32 threads-    Counter:            OK (0.12s)-      70.1 μs ± 2.7 μs-    IORef inconsistent: OK (0.08s)-      86.8 μs ± 7.5 μs-    IORef atomic:       OK (0.95s)-      183  μs ±  12 μs-    MVar:               OK (0.23s)-      913  μs ±  46 μs-    TMVar:              OK (0.07s)-      281  μs ±  15 μs-    TVar:               OK (0.07s)-      283  μs ±  20 μs-    Addr:               OK (0.12s)-      69.4 μs ± 3.2 μs-  Read/write contention with 100 iterations and 32 threads-    Counter:            OK (0.05s)-      280  μs ±  27 μs-    IORef inconsistent: OK (0.06s)-      487  μs ±  37 μs-    IORef atomic:       OK (0.07s)-      1.89 ms ± 121 μs-    MVar:               OK (0.57s)-      8.50 ms ± 703 μs-    TMVar:              OK (0.04s)-      3.04 ms ± 280 μs-    TVar:               OK (0.07s)-      2.95 ms ± 175 μs-    Addr:               OK (0.04s)-      277  μs ±  26 μs-  Read/write contention with 1000 iterations and 32 threads-    Counter:            OK (0.08s)-      2.75 ms ± 198 μs-    IORef inconsistent: OK (0.03s)-      5.20 ms ± 388 μs-    IORef atomic:       OK (0.39s)-      22.5 ms ± 809 μs-    MVar:               OK (0.68s)-      92.3 ms ± 4.3 ms-    TMVar:              OK (0.18s)-      31.4 ms ± 2.2 ms-    TVar:               OK (0.09s)-      30.0 ms ± 2.5 ms-    Addr:               OK (0.04s)-      2.85 ms ± 243 μs-  Read/write contention with 10000 iterations and 32 threads-    Counter:            OK (0.08s)-      28.1 ms ± 708 μs-    IORef inconsistent: OK (0.07s)-      53.6 ms ± 1.4 ms-    IORef atomic:       OK (9.80s)-      1.223 s ± 410 ms-    MVar:               OK (7.32s)-      1.009 s ±  37 ms-    TMVar:              OK (0.17s)-      296  ms ±  23 ms-    TVar:               OK (1.76s)-      302  ms ± 5.6 ms-    Addr:               OK (0.08s)-      29.1 ms ± 2.6 ms-  Read/write contention with 10 iterations and 64 threads-    Counter:            OK (0.05s)-      127  μs ±  12 μs-    IORef inconsistent: OK (0.12s)-      158  μs ± 5.8 μs-    IORef atomic:       OK (0.05s)-      320  μs ±  29 μs-    MVar:               OK (0.23s)-      1.86 ms ± 145 μs-    TMVar:              OK (1.06s)-      529  μs ±  41 μs-    TVar:               OK (0.26s)-      569  μs ±  24 μs-    Addr:               OK (0.06s)-      125  μs ±  11 μs-  Read/write contention with 100 iterations and 64 threads-    Counter:            OK (0.04s)-      564  μs ±  47 μs-    IORef inconsistent: OK (0.04s)-      1.03 ms ±  98 μs-    IORef atomic:       OK (0.31s)-      3.96 ms ± 240 μs-    MVar:               OK (1.15s)-      17.6 ms ± 1.3 ms-    TMVar:              OK (0.30s)-      6.30 ms ± 476 μs-    TVar:               OK (0.30s)-      6.28 ms ±  66 μs-    Addr:               OK (0.06s)-      560  μs ±  24 μs-  Read/write contention with 1000 iterations and 64 threads-    Counter:            OK (0.14s)-      4.93 ms ±  91 μs-    IORef inconsistent: OK (0.03s)-      8.83 ms ± 711 μs-    IORef atomic:       OK (6.68s)-      110  ms ±  21 ms-    MVar:               OK (1.34s)-      188  ms ± 7.7 ms-    TMVar:              OK (0.36s)-      64.3 ms ± 4.0 ms-    TVar:               OK (0.08s)-      64.3 ms ± 2.3 ms-    Addr:               OK (0.04s)-      5.85 ms ± 457 μs-  Read/write contention with 10000 iterations and 64 threads-    Counter:            OK (0.08s)-      59.1 ms ± 2.2 ms-    IORef inconsistent: OK (0.14s)-      102  ms ± 5.3 ms-    IORef atomic:       OK (11.44s)-      2.924 s ± 306 ms-    MVar:               OK (6.17s)-      1.982 s ±  34 ms-    TMVar:              OK (0.35s)-      657  ms ± 5.3 ms-    TVar:               OK (3.62s)-      631  ms ±  83 ms-    Addr:               OK (0.03s)-      47.7 ms ± 3.7 ms-  Read/write contention with 10 iterations and 128 threads-    Counter:            OK (0.08s)-      232  μs ±  11 μs-    IORef inconsistent: OK (0.12s)-      322  μs ±  11 μs-    IORef atomic:       OK (0.36s)-      636  μs ±  14 μs-    MVar:               OK (0.23s)-      3.65 ms ± 264 μs-    TMVar:              OK (1.04s)-      1.07 ms ±  59 μs-    TVar:               OK (0.07s)-      1.09 ms ±  97 μs-    Addr:               OK (0.05s)-      227  μs ±  22 μs-  Read/write contention with 100 iterations and 128 threads-    Counter:            OK (0.04s)-      1.16 ms ±  85 μs-    IORef inconsistent: OK (0.03s)-      2.08 ms ± 182 μs-    IORef atomic:       OK (0.07s)-      5.79 ms ± 393 μs-    MVar:               OK (1.14s)-      35.6 ms ± 1.1 ms-    TMVar:              OK (0.62s)-      13.1 ms ± 417 μs-    TVar:               OK (0.07s)-      10.4 ms ± 412 μs-    Addr:               OK (0.13s)-      1.10 ms ±  95 μs-  Read/write contention with 1000 iterations and 128 threads-    Counter:            OK (0.04s)-      11.7 ms ± 1.2 ms-    IORef inconsistent: OK (0.06s)-      21.8 ms ± 2.0 ms-    IORef atomic:       OK (10.69s)-      318  ms ±  82 ms-    MVar:               OK (5.87s)-      373  ms ± 8.3 ms-    TMVar:              OK (0.36s)-      133  ms ± 4.1 ms-    TVar:               OK (0.17s)-      128  ms ± 8.6 ms-    Addr:               OK (0.07s)-      10.0 ms ± 504 μs-  Read/write contention with 10000 iterations and 128 threads-    Counter:            OK (0.33s)-      119  ms ± 8.4 ms-    IORef inconsistent: OK (0.28s)-      210  ms ±  11 ms-    IORef atomic:       OK (11.27s)-      6.930 s ± 818 ms-    MVar:               OK (12.48s)-      3.977 s ±  43 ms-    TMVar:              OK (3.52s)-      1.316 s ±  11 ms-    TVar:               OK (1.60s)-      1.291 s ± 126 ms-    Addr:               OK (0.67s)-      118  ms ± 3.0 ms--All 309 tests passed (264.24s)+Operations translate to atomic CPU instructions which involve memory+barrier. For limited set of operation this package provides in+concurrent setting they tend to be faster than atomic modify operation+on `IORef`s and other shared var types. Value inside the `Counter`+type is unboxed which contributes to outperforming all other shared+vars because they box the value they store. For integers boxing is+especially bad.++For single-threaded use case this package will likely not outperform+vanilla `IORef`s or `STRef`s (it depends on whether GHC adds memory+barrier for them or not, cf+https://gitlab.haskell.org/ghc/ghc/-/issues/22764, if it does end up+adding the same memory barrier then both this package and `IORef`+should be equal). All in all, operations this package provides will+incur guaranteed memory barrier which will serve no purpose in+single-threaded settings so for that use case this package is probably+not the best. The intended use of this package is in the concurrent+setting where it does seem like a clear winner (please see benchmarks+below).++# Benchmark++### Summary++Depending on number of threads `Counter` from this package can be+up to 10 times faster than next best `TVar` from the `stm` package.++### Details++The benchmark is to spawn N threads each of which will increment the+same counter by 1 for a number of iterations.++Test setup: Intel i5-9600K CPU @ 3.70GHz, 6 cores, no hyperthreading, GHC 9.6.1.++NB `IORef inconsistent` is the benchmark that just reads and writes+`IORef` with the fastest functions the `IORef` supports. It gives+wrong results when multiple threads access `IORef` this way since+these reads and writes are not synchronized. It’s included only for+speed comparison purposes. All others do proper synchronization of+increments between the threads. Current package is shown as `Counter`.++```+$ cabal run bench -- -j1 --timeout 300 --stdev 2+All+  Correctness:          OK (13.97s)+    +++ OK, passed 10000 tests.+  Read/write contention with 10 iterations and 1 threads+    Counter:            OK (14.23s)+      839  ns ±  33 ns+    IORef inconsistent: OK (1.08s)+      1.03 μs ±  36 ns, 1.23x+    IORef atomic:       OK (1.30s)+      1.25 μs ±  40 ns, 1.48x+    MVar:               OK (10.53s)+      1.24 μs ±  13 ns, 1.48x+    TMVar:              OK (0.65s)+      1.18 μs ±  30 ns, 1.41x+    TVar:               OK (0.33s)+      1.13 μs ±  45 ns, 1.35x+    Addr:               OK (3.37s)+      818  ns ±  28 ns, 0.97x+  Read/write contention with 100 iterations and 1 threads+    Counter:            OK (1.47s)+      1.35 μs ±  24 ns+    IORef inconsistent: OK (17.27s)+      2.09 μs ±  47 ns, 1.55x+    IORef atomic:       OK (0.45s)+      3.22 μs ± 122 ns, 2.38x+    MVar:               OK (3.15s)+      2.97 μs ±  30 ns, 2.20x+    TMVar:              OK (1.24s)+      4.65 μs ±  64 ns, 3.44x+    TVar:               OK (2.43s)+      4.61 μs ± 158 ns, 3.41x+    Addr:               OK (1.16s)+      1.09 μs ±  22 ns, 0.80x+  Read/write contention with 1000 iterations and 1 threads+    Counter:            OK (0.47s)+      6.48 μs ± 235 ns+    IORef inconsistent: OK (0.78s)+      2.76 μs ±  88 ns, 0.43x+    IORef atomic:       OK (0.60s)+      17.5 μs ± 399 ns, 2.69x+    MVar:               OK (2.09s)+      15.8 μs ± 208 ns, 2.43x+    TMVar:              OK (0.40s)+      48.3 μs ± 1.9 μs, 7.46x+    TVar:               OK (0.55s)+      32.4 μs ± 713 ns, 5.00x+    Addr:               OK (0.34s)+      4.73 μs ± 189 ns, 0.73x+  Read/write contention with 10000 iterations and 1 threads+    Counter:            OK (0.50s)+      58.4 μs ± 2.1 μs+    IORef inconsistent: OK (0.42s)+      23.8 μs ± 829 ns, 0.41x+    IORef atomic:       OK (0.73s)+      168  μs ± 3.8 μs, 2.87x+    MVar:               OK (0.66s)+      157  μs ± 4.6 μs, 2.69x+    TMVar:              OK (2.09s)+      512  μs ± 7.2 μs, 8.78x+    TVar:               OK (1.39s)+      321  μs ± 6.7 μs, 5.50x+    Addr:               OK (47.12s)+      43.8 μs ± 562 ns, 0.75x+  Read/write contention with 10 iterations and 2 threads+    Counter:            OK (1.10s)+      7.85 μs ± 144 ns+    IORef inconsistent: OK (1.93s)+      7.65 μs ± 201 ns, 0.97x+    IORef atomic:       OK (0.54s)+      8.16 μs ± 235 ns, 1.04x+    MVar:               OK (7.81s)+      7.81 μs ±  72 ns, 0.99x+    TMVar:              OK (0.49s)+      7.98 μs ± 292 ns, 1.02x+    TVar:               OK (1.91s)+      7.98 μs ± 181 ns, 1.02x+    Addr:               OK (2.01s)+      7.64 μs ± 213 ns, 0.97x+  Read/write contention with 100 iterations and 2 threads+    Counter:            OK (1.00s)+      8.50 μs ± 290 ns+    IORef inconsistent: OK (8.00s)+      8.13 μs ± 133 ns, 0.96x+    IORef atomic:       OK (2.80s)+      13.3 μs ± 358 ns, 1.56x+    MVar:               OK (4.64s)+      19.2 μs ± 473 ns, 2.25x+    TMVar:              OK (5.52s)+      32.3 μs ± 1.1 μs, 3.80x+    TVar:               OK (83.27s)+      30.5 μs ± 279 ns, 3.59x+    Addr:               OK (4.38s)+      8.71 μs ± 333 ns, 1.03x+  Read/write contention with 1000 iterations and 2 threads+    Counter:            OK (28.57s)+      43.7 μs ± 106 ns+    IORef inconsistent: OK (0.91s)+      17.2 μs ± 669 ns, 0.39x+    IORef atomic:       OK (130.48s)+      223  μs ±  10 μs, 5.09x+    MVar:               OK (1.19s)+      5.11 ms ± 173 μs, 116.88x+    TMVar:              OK (0.33s)+      295  μs ± 7.7 μs, 6.75x+    TVar:               OK (1.44s)+      337  μs ±  10 μs, 7.71x+    Addr:               OK (0.47s)+      49.3 μs ± 915 ns, 1.13x+  Read/write contention with 10000 iterations and 2 threads+    Counter:            OK (0.51s)+      466  μs ±  17 μs+    IORef inconsistent: OK (13.49s)+      190  μs ± 1.2 μs, 0.41x+    IORef atomic:       OK (71.77s)+      1.80 ms ±  33 μs, 3.86x+    MVar:               OK (7.23s)+      60.1 ms ± 505 μs, 128.83x+    TMVar:              OK (1.50s)+      2.39 ms ±  39 μs, 5.13x+    TVar:               OK (108.24s)+      3.13 ms ± 405 μs, 6.70x+    Addr:               OK (0.29s)+      531  μs ±  20 μs, 1.14x+  Read/write contention with 10 iterations and 4 threads+    Counter:            OK (2.33s)+      15.5 μs ± 384 ns+    IORef inconsistent: OK (2.41s)+      15.6 μs ±  52 ns, 1.01x+    IORef atomic:       OK (1.56s)+      19.5 μs ± 487 ns, 1.26x+    MVar:               OK (1.51s)+      28.9 μs ± 647 ns, 1.87x+    TMVar:              OK (2.88s)+      19.9 μs ± 439 ns, 1.29x+    TVar:               OK (0.38s)+      18.2 μs ± 332 ns, 1.18x+    Addr:               OK (0.59s)+      15.3 μs ± 477 ns, 0.99x+  Read/write contention with 100 iterations and 4 threads+    Counter:            OK (1.63s)+      25.3 μs ± 723 ns+    IORef inconsistent: OK (0.35s)+      17.6 μs ± 451 ns, 0.69x+    IORef atomic:       OK (0.46s)+      154  μs ± 2.1 μs, 6.08x+    MVar:               OK (0.62s)+      1.20 ms ±  38 μs, 47.27x+    TMVar:              OK (0.12s)+      191  μs ± 7.4 μs, 7.54x+    TVar:               OK (0.14s)+      221  μs ± 6.6 μs, 8.71x+    Addr:               OK (0.75s)+      21.0 μs ± 228 ns, 0.83x+  Read/write contention with 1000 iterations and 4 threads+    Counter:            OK (0.17s)+      242  μs ± 6.7 μs+    IORef inconsistent: OK (0.15s)+      103  μs ± 2.7 μs, 0.43x+    IORef atomic:       OK (2.28s)+      1.71 ms ±  36 μs, 7.07x+    MVar:               OK (0.41s)+      12.9 ms ± 338 μs, 53.16x+    TMVar:              OK (0.29s)+      2.08 ms ±  65 μs, 8.61x+    TVar:               OK (0.17s)+      2.23 ms ±  73 μs, 9.21x+    Addr:               OK (0.58s)+      234  μs ± 1.9 μs, 0.97x+  Read/write contention with 10000 iterations and 4 threads+    Counter:            OK (0.17s)+      2.24 ms ±  60 μs+    IORef inconsistent: OK (9.34s)+      1.00 ms ±  31 μs, 0.45x+    IORef atomic:       OK (70.87s)+      22.0 ms ± 820 μs, 9.80x+    MVar:               OK (0.74s)+      126  ms ± 1.9 ms, 56.07x+    TMVar:              OK (0.33s)+      19.0 ms ± 670 μs, 8.48x+    TVar:               OK (0.09s)+      20.8 ms ± 732 μs, 9.27x+    Addr:               OK (0.18s)+      2.45 ms ±  97 μs, 1.09x+  Read/write contention with 10 iterations and 6 threads+    Counter:            OK (6.77s)+      23.9 μs ± 813 ns+    IORef inconsistent: OK (0.42s)+      23.4 μs ± 712 ns, 0.98x+    IORef atomic:       OK (0.70s)+      39.4 μs ± 747 ns, 1.65x+    MVar:               OK (1.32s)+      50.0 μs ± 1.0 μs, 2.09x+    TMVar:              OK (0.52s)+      35.3 μs ± 449 ns, 1.47x+    TVar:               OK (3.93s)+      32.6 μs ±  93 ns, 1.37x+    Addr:               OK (0.42s)+      23.4 μs ± 381 ns, 0.98x+  Read/write contention with 100 iterations and 6 threads+    Counter:            OK (1.20s)+      47.8 μs ± 866 ns+    IORef inconsistent: OK (0.24s)+      26.9 μs ± 983 ns, 0.56x+    IORef atomic:       OK (1.46s)+      483  μs ±  17 μs, 10.10x+    MVar:               OK (2.01s)+      1.86 ms ±  13 μs, 38.97x+    TMVar:              OK (0.49s)+      519  μs ± 4.5 μs, 10.86x+    TVar:               OK (14.78s)+      521  μs ±  14 μs, 10.91x+    Addr:               OK (0.56s)+      43.1 μs ± 1.6 μs, 0.90x+  Read/write contention with 1000 iterations and 6 threads+    Counter:            OK (13.77s)+      459  μs ± 8.8 μs+    IORef inconsistent: OK (0.23s)+      207  μs ± 4.1 μs, 0.45x+    IORef atomic:       OK (2.10s)+      3.48 ms ±  70 μs, 7.58x+    MVar:               OK (0.64s)+      19.3 ms ± 555 μs, 42.03x+    TMVar:              OK (1.07s)+      5.55 ms ± 161 μs, 12.08x+    TVar:               OK (0.27s)+      4.85 ms ± 189 μs, 10.56x+    Addr:               OK (27.53s)+      461  μs ± 4.8 μs, 1.00x+  Read/write contention with 10000 iterations and 6 threads+    Counter:            OK (0.52s)+      4.88 ms ± 142 μs+    IORef inconsistent: OK (0.25s)+      2.25 ms ±  24 μs, 0.46x+    IORef atomic:       OK (66.59s)+      75.5 ms ±  11 ms, 15.46x+    MVar:               OK (2.85s)+      193  ms ± 4.2 ms, 39.54x+    TMVar:              OK (0.16s)+      54.9 ms ± 1.6 ms, 11.25x+    TVar:               OK (10.04s)+      47.1 ms ± 339 μs, 9.64x+    Addr:               OK (0.52s)+      4.94 ms ±  89 μs, 1.01x+  Read/write contention with 10 iterations and 8 threads+    Counter:            OK (1.84s)+      27.3 μs ± 1.0 μs+    IORef inconsistent: OK (1.98s)+      27.5 μs ± 1.0 μs, 1.01x+    IORef atomic:       OK (0.91s)+      56.1 μs ± 787 ns, 2.06x+    MVar:               OK (0.69s)+      94.9 μs ± 3.2 μs, 3.48x+    TMVar:              OK (1.35s)+      56.1 μs ± 1.5 μs, 2.06x+    TVar:               OK (0.36s)+      51.7 μs ± 1.5 μs, 1.89x+    Addr:               OK (0.24s)+      26.3 μs ± 672 ns, 0.96x+  Read/write contention with 100 iterations and 8 threads+    Counter:            OK (1.41s)+      63.1 μs ± 1.2 μs+    IORef inconsistent: OK (8.38s)+      33.3 μs ± 503 ns, 0.53x+    IORef atomic:       OK (0.59s)+      709  μs ±  21 μs, 11.25x+    MVar:               OK (1.21s)+      2.31 ms ±  49 μs, 36.65x+    TMVar:              OK (4.67s)+      667  μs ±  18 μs, 10.58x+    TVar:               OK (4.81s)+      690  μs ± 6.5 μs, 10.94x+    Addr:               OK (0.69s)+      59.6 μs ± 1.7 μs, 0.94x+  Read/write contention with 1000 iterations and 8 threads+    Counter:            OK (0.16s)+      583  μs ±  13 μs+    IORef inconsistent: OK (1.13s)+      304  μs ± 3.5 μs, 0.52x+    IORef atomic:       OK (93.87s)+      7.12 ms ± 158 μs, 12.22x+    MVar:               OK (1.54s)+      24.4 ms ± 541 μs, 41.83x+    TMVar:              OK (0.09s)+      6.32 ms ± 241 μs, 10.84x+    TVar:               OK (0.67s)+      6.36 ms ± 221 μs, 10.92x+    Addr:               OK (0.56s)+      540  μs ±  20 μs, 0.93x+  Read/write contention with 10000 iterations and 8 threads+    Counter:            OK (5.13s)+      5.67 ms ±  68 μs+    IORef inconsistent: OK (0.16s)+      3.14 ms ±  69 μs, 0.55x+    IORef atomic:       OK (35.04s)+      148  ms ± 319 μs, 26.14x+    MVar:               OK (1.58s)+      230  ms ± 8.7 ms, 40.61x+    TMVar:              OK (26.99s)+      65.9 ms ± 4.1 ms, 11.62x+    TVar:               OK (3.41s)+      66.6 ms ± 779 μs, 11.75x+    Addr:               OK (0.16s)+      5.84 ms ± 164 μs, 1.03x+  Read/write contention with 10 iterations and 12 threads+    Counter:            OK (0.54s)+      30.5 μs ± 452 ns+    IORef inconsistent: OK (0.29s)+      32.4 μs ± 820 ns, 1.06x+    IORef atomic:       OK (7.93s)+      70.3 μs ± 436 ns, 2.30x+    MVar:               OK (0.44s)+      232  μs ± 8.7 μs, 7.59x+    TMVar:              OK (13.74s)+      80.4 μs ± 2.3 μs, 2.64x+    TVar:               OK (1.73s)+      79.2 μs ± 2.7 μs, 2.60x+    Addr:               OK (0.26s)+      29.6 μs ± 1.0 μs, 0.97x+  Read/write contention with 100 iterations and 12 threads+    Counter:            OK (0.49s)+      98.0 μs ± 1.1 μs+    IORef inconsistent: OK (0.66s)+      48.2 μs ± 561 ns, 0.49x+    IORef atomic:       OK (0.88s)+      1.07 ms ±  39 μs, 10.89x+    MVar:               OK (0.86s)+      3.18 ms ±  61 μs, 32.48x+    TMVar:              OK (0.21s)+      1.00 ms ±  21 μs, 10.19x+    TVar:               OK (0.12s)+      1.06 ms ±  29 μs, 10.77x+    Addr:               OK (0.13s)+      94.0 μs ± 2.7 μs, 0.96x+  Read/write contention with 1000 iterations and 12 threads+    Counter:            OK (6.78s)+      955  μs ± 5.9 μs+    IORef inconsistent: OK (0.22s)+      466  μs ±  16 μs, 0.49x+    IORef atomic:       OK (2.46s)+      11.1 ms ± 109 μs, 11.62x+    MVar:               OK (1.14s)+      34.3 ms ± 923 μs, 35.98x+    TMVar:              OK (8.60s)+      10.7 ms ± 226 μs, 11.22x+    TVar:               OK (4.18s)+      9.82 ms ±  42 μs, 10.29x+    Addr:               OK (0.42s)+      1.00 ms ±  40 μs, 1.05x+  Read/write contention with 10000 iterations and 12 threads+    Counter:            OK (1.99s)+      9.45 ms ± 116 μs+    IORef inconsistent: OK (7.78s)+      4.74 ms ± 7.4 μs, 0.50x+    IORef atomic:       OK (82.99s)+      304  ms ±  66 ms, 32.15x+    MVar:               OK (11.29s)+      343  ms ± 8.3 ms, 36.34x+    TMVar:              OK (0.33s)+      116  ms ± 1.9 ms, 12.23x+    TVar:               OK (10.63s)+      105  ms ± 1.5 ms, 11.15x+    Addr:               OK (3.97s)+      9.47 ms ± 361 μs, 1.00x+  Read/write contention with 10 iterations and 16 threads+    Counter:            OK (0.20s)+      42.1 μs ± 1.3 μs+    IORef inconsistent: OK (0.18s)+      40.5 μs ± 1.4 μs, 0.96x+    IORef atomic:       OK (1.08s)+      153  μs ± 662 ns, 3.63x+    MVar:               OK (1.56s)+      408  μs ± 9.1 μs, 9.69x+    TMVar:              OK (2.43s)+      128  μs ± 1.9 μs, 3.04x+    TVar:               OK (0.16s)+      135  μs ± 5.0 μs, 3.19x+    Addr:               OK (0.32s)+      40.6 μs ± 940 ns, 0.96x+  Read/write contention with 100 iterations and 16 threads+    Counter:            OK (0.32s)+      131  μs ± 2.1 μs+    IORef inconsistent: OK (1.68s)+      75.4 μs ± 1.6 μs, 0.58x+    IORef atomic:       OK (4.05s)+      1.27 ms ±  45 μs, 9.70x+    MVar:               OK (4.53s)+      4.39 ms ±  85 μs, 33.50x+    TMVar:              OK (0.16s)+      1.48 ms ±  40 μs, 11.30x+    TVar:               OK (1.20s)+      1.45 ms ± 5.5 μs, 11.06x+    Addr:               OK (4.85s)+      131  μs ± 1.3 μs, 1.00x+  Read/write contention with 1000 iterations and 16 threads+    Counter:            OK (0.15s)+      1.05 ms ±  32 μs+    IORef inconsistent: OK (0.28s)+      632  μs ±  12 μs, 0.60x+    IORef atomic:       OK (53.85s)+      16.3 ms ± 1.5 ms, 15.58x+    MVar:               OK (2.98s)+      46.6 ms ± 672 μs, 44.57x+    TMVar:              OK (0.09s)+      15.2 ms ± 472 μs, 14.54x+    TVar:               OK (0.36s)+      14.6 ms ± 354 μs, 13.96x+    Addr:               OK (0.15s)+      1.38 ms ±  47 μs, 1.32x+  Read/write contention with 10000 iterations and 16 threads+    Counter:            OK (0.17s)+      13.3 ms ± 301 μs+    IORef inconsistent: OK (0.16s)+      5.73 ms ± 119 μs, 0.43x+    IORef atomic:       OK (117.97s)+      464  ms ±  38 ms, 34.81x+    MVar:               OK (14.95s)+      481  ms ± 4.5 ms, 36.11x+    TMVar:              OK (1.80s)+      155  ms ± 2.7 ms, 11.65x+    TVar:               OK (7.20s)+      146  ms ± 663 μs, 10.93x+    Addr:               OK (5.34s)+      12.8 ms ± 187 μs, 0.96x+  Read/write contention with 10 iterations and 20 threads+    Counter:            OK (0.19s)+      49.3 μs ± 1.9 μs+    IORef inconsistent: OK (0.20s)+      48.2 μs ± 1.7 μs, 0.98x+    IORef atomic:       OK (5.11s)+      188  μs ± 5.2 μs, 3.82x+    MVar:               OK (4.08s)+      536  μs ± 5.4 μs, 10.86x+    TMVar:              OK (1.44s)+      159  μs ± 531 ns, 3.23x+    TVar:               OK (0.37s)+      176  μs ± 3.0 μs, 3.57x+    Addr:               OK (0.82s)+      50.6 μs ± 1.0 μs, 1.03x+  Read/write contention with 100 iterations and 20 threads+    Counter:            OK (0.10s)+      171  μs ± 5.7 μs+    IORef inconsistent: OK (0.25s)+      90.0 μs ± 2.1 μs, 0.52x+    IORef atomic:       OK (9.07s)+      1.52 ms ±  59 μs, 8.87x+    MVar:               OK (2.90s)+      5.61 ms ± 159 μs, 32.73x+    TMVar:              OK (1.57s)+      1.85 ms ±  54 μs, 10.77x+    TVar:               OK (0.19s)+      1.88 ms ±  28 μs, 10.98x+    Addr:               OK (0.18s)+      169  μs ± 3.8 μs, 0.98x+  Read/write contention with 1000 iterations and 20 threads+    Counter:            OK (0.74s)+      1.68 ms ±  65 μs+    IORef inconsistent: OK (0.18s)+      881  μs ±  24 μs, 0.52x+    IORef atomic:       OK (73.70s)+      21.3 ms ± 600 μs, 12.66x+    MVar:               OK (0.94s)+      61.0 ms ± 1.4 ms, 36.31x+    TMVar:              OK (7.19s)+      18.1 ms ± 472 μs, 10.75x+    TVar:               OK (7.26s)+      18.1 ms ± 494 μs, 10.79x+    Addr:               OK (0.09s)+      1.74 ms ±  43 μs, 1.04x+  Read/write contention with 10000 iterations and 20 threads+    Counter:            OK (6.72s)+      16.2 ms ± 174 μs+    IORef inconsistent: OK (6.36s)+      7.73 ms ± 247 μs, 0.48x+    IORef atomic:       OK (21.41s)+      641  ms ± 264 μs, 39.55x+    MVar:               OK (38.82s)+      609  ms ±  21 ms, 37.53x+    TMVar:              OK (4.56s)+      192  ms ± 648 μs, 11.82x+    TVar:               OK (1.13s)+      193  ms ± 7.5 ms, 11.91x+    Addr:               OK (0.43s)+      16.8 ms ± 581 μs, 1.03x+  Read/write contention with 10 iterations and 32 threads+    Counter:            OK (1.01s)+      73.7 μs ± 1.3 μs+    IORef inconsistent: OK (0.51s)+      72.0 μs ± 777 ns, 0.98x+    IORef atomic:       OK (0.24s)+      178  μs ± 3.8 μs, 2.41x+    MVar:               OK (0.91s)+      919  μs ±  17 μs, 12.47x+    TMVar:              OK (2.27s)+      277  μs ± 4.4 μs, 3.76x+    TVar:               OK (0.15s)+      299  μs ±  10 μs, 4.06x+    Addr:               OK (0.50s)+      71.8 μs ± 2.6 μs, 0.97x+  Read/write contention with 100 iterations and 32 threads+    Counter:            OK (0.29s)+      280  μs ± 6.4 μs+    IORef inconsistent: OK (1.44s)+      150  μs ± 3.2 μs, 0.53x+    IORef atomic:       OK (0.25s)+      1.74 ms ±  56 μs, 6.22x+    MVar:               OK (1.19s)+      9.06 ms ± 269 μs, 32.31x+    TMVar:              OK (4.80s)+      2.98 ms ±  36 μs, 10.64x+    TVar:               OK (19.94s)+      3.10 ms ±  27 μs, 11.04x+    Addr:               OK (0.55s)+      272  μs ± 9.4 μs, 0.97x+  Read/write contention with 1000 iterations and 32 threads+    Counter:            OK (2.27s)+      2.69 ms ±  48 μs+    IORef inconsistent: OK (2.18s)+      1.27 ms ±  23 μs, 0.47x+    IORef atomic:       OK (62.21s)+      35.2 ms ± 4.3 ms, 13.08x+    MVar:               OK (5.90s)+      89.9 ms ± 233 μs, 33.44x+    TMVar:              OK (2.96s)+      30.7 ms ± 470 μs, 11.40x+    TVar:               OK (5.98s)+      30.4 ms ± 124 μs, 11.30x+    Addr:               OK (0.29s)+      2.75 ms ±  93 μs, 1.02x+  Read/write contention with 10000 iterations and 32 threads+    Counter:            OK (0.08s)+      28.8 ms ± 1.0 ms+    IORef inconsistent: OK (0.32s)+      12.9 ms ± 351 μs, 0.45x+    IORef atomic:       OK (82.13s)+      1.180 s ±  65 ms, 41.02x+    MVar:               OK (128.00s)+      982  ms ±  14 ms, 34.15x+    TMVar:              OK (0.17s)+      299  ms ± 7.6 ms, 10.41x+    TVar:               OK (7.51s)+      316  ms ±  12 ms, 11.00x+    Addr:               OK (1.36s)+      27.0 ms ± 871 μs, 0.94x+  Read/write contention with 10 iterations and 64 threads+    Counter:            OK (0.84s)+      132  μs ± 3.3 μs+    IORef inconsistent: OK (0.44s)+      132  μs ± 2.4 μs, 1.00x+    IORef atomic:       OK (0.18s)+      323  μs ± 6.5 μs, 2.45x+    MVar:               OK (0.47s)+      1.89 ms ±  74 μs, 14.33x+    TMVar:              OK (4.18s)+      557  μs ± 1.7 μs, 4.22x+    TVar:               OK (2.19s)+      575  μs ± 1.6 μs, 4.36x+    Addr:               OK (0.19s)+      125  μs ± 2.8 μs, 0.95x+  Read/write contention with 100 iterations and 64 threads+    Counter:            OK (0.28s)+      568  μs ±  13 μs+    IORef inconsistent: OK (0.32s)+      284  μs ± 2.9 μs, 0.50x+    IORef atomic:       OK (0.21s)+      2.62 ms ±  95 μs, 4.62x+    MVar:               OK (2.37s)+      18.1 ms ± 688 μs, 31.81x+    TMVar:              OK (0.15s)+      6.24 ms ± 173 μs, 10.98x+    TVar:               OK (5.00s)+      6.30 ms ± 162 μs, 11.08x+    Addr:               OK (2.06s)+      555  μs ± 7.4 μs, 0.98x+  Read/write contention with 1000 iterations and 64 threads+    Counter:            OK (0.59s)+      5.80 ms ± 111 μs+    IORef inconsistent: OK (2.10s)+      2.49 ms ±  96 μs, 0.43x+    IORef atomic:       OK (2.36s)+      75.8 ms ± 396 μs, 13.06x+    MVar:               OK (2.88s)+      188  ms ± 4.8 ms, 32.41x+    TMVar:              OK (5.95s)+      61.7 ms ± 176 μs, 10.63x+    TVar:               OK (1.52s)+      63.8 ms ± 2.4 ms, 11.00x+    Addr:               OK (0.28s)+      5.52 ms ± 167 μs, 0.95x+  Read/write contention with 10000 iterations and 64 threads+    Counter:            OK (2.74s)+      56.6 ms ± 2.2 ms+    IORef inconsistent: OK (10.26s)+      26.0 ms ± 746 μs, 0.46x+    IORef atomic:       OK (100.70s)+      3.018 s ± 328 ms, 53.35x+    MVar:               OK (30.56s)+      1.994 s ±  16 ms, 35.25x+    TMVar:              OK (0.36s)+      665  ms ± 3.4 ms, 11.76x+    TVar:               OK (1.79s)+      653  ms ± 2.4 ms, 11.55x+    Addr:               OK (11.06s)+      57.0 ms ± 546 μs, 1.01x+  Read/write contention with 10 iterations and 128 threads+    Counter:            OK (0.67s)+      240  μs ± 5.9 μs+    IORef inconsistent: OK (1.43s)+      247  μs ± 8.5 μs, 1.03x+    IORef atomic:       OK (1.38s)+      642  μs ± 6.2 μs, 2.68x+    MVar:               OK (1.92s)+      3.83 ms ±  34 μs, 15.94x+    TMVar:              OK (16.12s)+      1.11 ms ±  23 μs, 4.63x+    TVar:               OK (4.27s)+      1.15 ms ±  36 μs, 4.78x+    Addr:               OK (0.16s)+      230  μs ± 6.9 μs, 0.96x+  Read/write contention with 100 iterations and 128 threads+    Counter:            OK (0.26s)+      1.15 ms ±  42 μs+    IORef inconsistent: OK (0.31s)+      560  μs ±  18 μs, 0.49x+    IORef atomic:       OK (0.31s)+      7.80 ms ± 274 μs, 6.81x+    MVar:               OK (0.55s)+      36.2 ms ± 1.2 ms, 31.54x+    TMVar:              OK (19.40s)+      12.4 ms ±  20 μs, 10.78x+    TVar:               OK (0.62s)+      13.1 ms ± 411 μs, 11.39x+    Addr:               OK (0.13s)+      1.12 ms ±  24 μs, 0.98x+  Read/write contention with 1000 iterations and 128 threads+    Counter:            OK (0.15s)+      8.93 ms ± 264 μs+    IORef inconsistent: OK (0.52s)+      5.28 ms ± 104 μs, 0.59x+    IORef atomic:       OK (80.71s)+      310  ms ±  57 ms, 34.68x+    MVar:               OK (5.86s)+      378  ms ± 3.1 ms, 42.38x+    TMVar:              OK (1.51s)+      131  ms ± 3.5 ms, 14.62x+    TVar:               OK (3.07s)+      129  ms ± 981 μs, 14.44x+    Addr:               OK (4.47s)+      11.3 ms ± 139 μs, 1.27x+  Read/write contention with 10000 iterations and 128 threads+    Counter:            OK (1.37s)+      112  ms ± 3.3 ms+    IORef inconsistent: OK (5.13s)+      53.3 ms ± 571 μs, 0.47x+    IORef atomic:       OK (11.14s)+      6.952 s ±  54 ms, 61.84x+    MVar:               OK (12.70s)+      4.075 s ± 154 ms, 36.25x+    TMVar:              OK (3.51s)+      1.268 s ± 5.7 ms, 11.27x+    TVar:               OK (0.71s)+      1.306 s ±  50 ms, 11.62x+    Addr:               OK (11.18s)+      117  ms ± 1.7 ms, 1.04x++All 309 tests passed (2397.33s) ```  # Memory overhead
atomic-counter.cabal view
@@ -5,7 +5,7 @@ name:   atomic-counter version:-  0.1+  0.1.1 synopsis:   Mutable counters that can be modified with atomic operatinos @@ -38,11 +38,21 @@  homepage:   https://github.com/sergv/atomic-counter+bug-reports:+  https://github.com/sergv/atomic-counter/issues  source-repository head   type: git   location: https://github.com/sergv/atomic-counter.git +flag dev+  description:+    Enable development flags+  default:+    False+  manual:+    True+ common ghc-options   default-language:     Haskell2010@@ -78,6 +88,14 @@     src   build-depends:     , base >= 4.14 && < 5+  if impl(ghc >= 9.4) && !arch(javascript)+    cmm-sources:+      Counter.cmm+    cpp-options:+      -DUSE_CMM+    if flag(dev)+      ghc-options:+        -dcmm-lint  library test-utils   import: ghc-options@@ -125,8 +143,8 @@     , base >= 4.14     , primitive     , stm-    , tasty-    , tasty-bench+    , tasty >= 1.4.2+    , tasty-bench >= 0.3.2     , tasty-quickcheck     , test-utils   ghc-options:@@ -134,4 +152,3 @@     -threaded     "-with-rtsopts=-N -A32M"     -main-is BenchMain-
bench/BenchMain.hs view
@@ -26,6 +26,7 @@ import Test.QuickCheck import Test.Tasty import Test.Tasty.Bench+import Test.Tasty.Patterns.Printer import Test.Tasty.QuickCheck qualified as QC import Test.Tasty.Runners qualified as Tasty @@ -110,9 +111,9 @@                 g === expected         ] -  let benchmarks =+  let benchmarks = map (mapLeafBenchmarks addCompare)         [ bgroup ("Read/write contention with " ++ show (unIterations n) ++ " iterations and " ++ show (length threads) ++ " threads")-          [ bench "Counter" $+          [ bench counterBenchName $             whnfIO (spawnAndCall threads (C.new 0)      (\ref _ -> callN n (incrementCounter ref 1)))           , bench "IORef inconsistent" $             whnfIO (spawnAndCall threads (newIORef 0)   (\ref _ -> callN n (incrementIORefInconsistent ref 1)))@@ -143,3 +144,12 @@     localOption (Tasty.NumThreads 1) $       testGroup "All" $       tests ++ benchmarks++counterBenchName :: String+counterBenchName = "Counter"++addCompare :: [String] -> Benchmark -> Benchmark+addCompare (name : path)+  | name /= counterBenchName+  = bcompare (printAwkExpr (locateBenchmark (counterBenchName : path)))+addCompare _ = id
src/Control/Concurrent/Counter/Lifted/ST.hs view
@@ -75,7 +75,7 @@   -> Int   -> ST s () set (Counter c) (I# x) = ST $ \s1 -> case Unlifted.set c x s1 of-  s2 -> (# s2, () #)+  (# s2 #) -> (# s2, () #)   {-# INLINE add #-}
src/Control/Concurrent/Counter/Unlifted.hs view
@@ -16,10 +16,13 @@ -- 'Control.Concurrent.Counter.Counter' module. ---------------------------------------------------------------------------- -{-# LANGUAGE CPP              #-}-{-# LANGUAGE MagicHash        #-}-{-# LANGUAGE UnboxedTuples    #-}-{-# LANGUAGE UnliftedNewtypes #-}+{-# LANGUAGE CPP                  #-}+{-# LANGUAGE GHCForeignImportPrim #-}+{-# LANGUAGE KindSignatures       #-}+{-# LANGUAGE MagicHash            #-}+{-# LANGUAGE UnboxedTuples        #-}+{-# LANGUAGE UnliftedFFITypes     #-}+{-# LANGUAGE UnliftedNewtypes     #-}  module Control.Concurrent.Counter.Unlifted   ( Counter@@ -56,7 +59,55 @@  #define ADD_HASH(x) x# +#if defined(USE_CMM) && SIZEOF_HSINT == 8+ -- | Memory location that supports select few atomic operations.+newtype Counter s = Counter (Any :: UnliftedType)++-- | Create new counter with initial value.+foreign import prim "stg_newCounterzh"+  new :: Int# -> State# s -> (# State# s, Counter s #)++-- | Atomically read the counter's value.+foreign import prim "stg_atomicGetCounterzh"+  get :: Counter s -> State# s -> (# State# s, Int# #)++-- | Atomically assign new value to the counter.+foreign import prim "stg_atomicSetCounterzh"+  set :: Counter s -> Int# -> State# s -> (# State# s #)++-- | Atomically add an amount to the counter and return its old value.+foreign import prim "stg_atomicAddCounterzh"+  add :: Counter s -> Int# -> State# s -> (# State# s, Int# #)++-- | Atomically subtract an amount from the counter and return its old value.+foreign import prim "stg_atomicSubCounterzh"+  sub :: Counter s -> Int# -> State# s -> (# State# s, Int# #)++-- | Atomically combine old value with a new one via bitwise and. Returns old counter value.+foreign import prim "stg_atomicAndCounterzh"+  and :: Counter s -> Int# -> State# s -> (# State# s, Int# #)++-- | Atomically combine old value with a new one via bitwise or. Returns old counter value.+foreign import prim "stg_atomicOrCounterzh"+  or :: Counter s -> Int# -> State# s -> (# State# s, Int# #)++-- | Atomically combine old value with a new one via bitwise xor. Returns old counter value.+foreign import prim "stg_atomicXorCounterzh"+  xor :: Counter s -> Int# -> State# s -> (# State# s, Int# #)++-- | Atomically combine old value with a new one via bitwise nand. Returns old counter value.+foreign import prim "stg_atomicNandCounterzh"+  nand :: Counter s -> Int# -> State# s -> (# State# s, Int# #)++-- | Compare the underlying pointers of two counters.+sameCounter :: Counter s -> Counter s -> Bool+sameCounter (Counter x) (Counter y) =+  isTrue# (reallyUnsafePtrEquality# x y)++#else++-- | Memory location that supports select few atomic operations. newtype Counter s = Counter (MutableByteArray# s)  {-# INLINE new #-}@@ -75,8 +126,9 @@  {-# INLINE set #-} -- | Atomically assign new value to the counter.-set :: Counter s -> Int# -> State# s -> State# s-set (Counter arr) = atomicWriteIntArray# arr 0#+set :: Counter s -> Int# -> State# s -> (# State# s #)+set (Counter arr) n = \s1 -> case atomicWriteIntArray# arr 0# n s1 of+  s2 -> (# s2 #)   {-# INLINE add #-}@@ -115,3 +167,5 @@ sameCounter :: Counter s -> Counter s -> Bool sameCounter (Counter x) (Counter y) =   isTrue# (sameMutableByteArray# x y)++#endif