Overview
Striped transactional counter that minimizes write conflicts across processor cores.
(import (std stm))
(import (std stm counter))
(def requests (make-tcounter 0L))
;; Per-request addition: stripes writes by CPU to avoid transaction conflicts
(atomically (fun (tx) (tcounter-add! tx requests 1L)))
;; Periodic read: sums across all stripes
(atomically (fun (tx) (tcounter-ref tx requests)))
(TCounter T) stores a numeric counter of type T (implementing
Num, such as int, long, or double). Its value is partitioned across
multiple per-CPU striped locations. Add operations write only to the stripe
corresponding to the executing CPU, allowing concurrent transactions on
different cores to commit without conflicts.
Read vs write trade-offs. tcounter-ref inspects all stripes
to compute the total sum, conflicting with concurrent writes. Use this
counter when additions are frequent and reads are infrequent (e.g. request
and error metrics). If a value is read as often as it is written, a standard
Loc is preferred.
Overflow. Fixed-width integers wrap on overflow using two’s complement arithmetic across stripes.
Credits. Based on the Accumulator design in kcas_data (https://github.com/ocaml-multicore/kcas).
See also: TCounter, tcounter-add!, tcounter-ref
Reference
Types
TCounter
record ↑ Types
Striped transactional counter holding a numeric value of type %a.
%a- The numeric type (must implement Num).
See also: make-tcounter
Functions
make-tcounter
function ↑ Functions
(: make-tcounter (-> %a (TCounter %a)))
(make-tcounter initial)
Creates a new striped counter initialized with a value.
initial- Initial value (e.g. 0L for a long counter).
- returns
- A new striped transactional counter.
Allocates one stripe per CPU core, rounded up to the nearest power of two.
tcounter-add!
function ↑ Functions
(: tcounter-add! (-> Tx (TCounter %a) %a void))
(tcounter-add! tx c n)
Adds n to the counter within a transaction.
tx- The transaction log context.
c- The counter.
n- The value to add.
Updates only the stripe assigned to the current CPU core and reads no other
stripes. Does not return the updated total; call tcounter-ref to read
the full sum.
tcounter-sub!
function ↑ Functions
(: tcounter-sub! (-> Tx (TCounter %a) %a void))
(tcounter-sub! tx c n)
Subtracts n from the counter within a transaction.
tx- The transaction log context.
c- The counter.
n- The value to subtract.
tcounter-ref
function ↑ Functions
(: tcounter-ref (-> Tx (TCounter %a) %a))
(tcounter-ref tx c)
Computes the total sum across all stripes within a transaction.
tx- The transaction log context.
c- The counter.
- returns
- The aggregate sum of all stripes.
Reads all stripes, causing conflicts with any concurrent transactions performing additions.
tcounter-set!
function ↑ Functions
(: tcounter-set! (-> Tx (TCounter %a) %a void))
(tcounter-set! tx c value)
Overwrites all counter stripes with a new value within a transaction.
tx- The transaction log context.
c- The counter.
value- The new value to assign.
Writes to all stripes, conflicting with concurrent transactions that add to the counter.