Docs/Performance/Benchmark sources
Benchmarks

The twenty-one rows, both sides

Every row of the two performance tables (the tables themselves), as the two programs that were measured: the DominScript benchmark on the left, its Python twin on the right, verbatim from benchmarks/ in the repository. The Python side is idiomatic CPython (the timed loop inside a function, range-based loops, the standard library where a Python programmer would use it), not a transcription of the DominScript source; the two do the same work and print the same result line. Both print elapsed_ms; the runner takes the median of seven runs.

21 rowssource benchmarks/*.dom, benchmarks/*.pyrunner benchmarks/run_benchmarks.py

Recursive Fibonacci(28) pure

DominScript · benchmarks/fib.dom
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";

i64 Fib(i64 $N)
{
    if ($N < 2) { return($N); }
    return(Fib($N - 1) + Fib($N - 2));
}

i32 main()
{
    i64 $T0;
    i64 $T1;
    i64 $R;

    $T0 = timer.MonotonicMs();
    $R  = Fib(28);
    $T1 = timer.MonotonicMs();

    printf("fib(28) = %d\n", $R);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/fib.py
import time

# Twin of fib.dom. Idiomatic CPython: the timed code runs inside a
# function (fast locals), the recursion is the plain one.

def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

def main():
    t0 = time.perf_counter()
    r = fib(28)
    t1 = time.perf_counter()
    print(f"fib(28) = {r}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

Arithmetic loop, 10M iterations pure

DominScript · benchmarks/iter_sum.dom
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";

/* Sum 1..N modulo a prime -- a tight arithmetic loop; the modulo keeps
 * the running sum out of the overflow range. */
i32 main()
{
    i64 $T0;
    i64 $T1;
    i64 $N    = 10000000;
    i64 $Sum  = 0;
    i64 $I    = 1;
    i64 $Mod  = 1000000007;

    $T0 = timer.MonotonicMs();
    while ($I <= $N)
    {
        $Sum = ($Sum + $I * $I) % $Mod;
        $I   = $I + 1;
    }
    $T1 = timer.MonotonicMs();

    printf("sum = %d\n", $Sum);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/iter_sum.py
import time

# Twin of iter_sum.dom. Idiomatic CPython: the loop runs inside a
# function over range(), not a module-level while with a hand-kept counter.

def main():
    N = 10_000_000
    MOD = 1_000_000_007
    t0 = time.perf_counter()
    s = 0
    for i in range(1, N + 1):
        s = (s + i * i) % MOD
    t1 = time.perf_counter()
    print(f"sum = {s}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

Sieve of Eratosthenes, N=5M plugin

Both sides write their own idiom: Python marks the multiples with a slice assignment and counts with sum(); DominScript marks with blob.FillStep and counts with blob.CountByte. Both run in C — this row compares the two languages’ bulk-byte paths.

DominScript · benchmarks/sieve.dom
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";
plugin "../plugins/blob/BlobPlugin";
/* Sieve of Eratosthenes -- the marking is blob.FillStep (one C loop per prime),
   the count is blob.CountByte (one C pass). N = 5 000 000; the twin is sieve.py. */
i32 main()
{
    i64 $T0;
    i64 $T1;
    i64 $N = 5000000;
    blob $Sieve[5000000];
    i64 $I;
    i64 $R = 0;
    i64 $Count = 0;
    $Sieve[0] = 1;
    $Sieve[1] = 1;
    $T0 = timer.MonotonicMs();
    $I = 2;
    while ($I * $I < $N)
    {
        if ($Sieve[$I] == 0)
        {
            $R = blob.FillStep(ref $Sieve, $I * $I, $I, ($N - 1 - $I * $I) / $I + 1, 1);
        }
        $I += 1;
    }
    $Count = blob.CountByte($Sieve, 0);
    $T1 = timer.MonotonicMs();
    printf("primes_below_%d = %d\n", $N, $Count);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/sieve.py
import time
# Twin of sieve.dom. Idiomatic CPython: a bytearray sieve inside a function;
# the marking is slice assignment, the count is N - sum(sieve) -- both run in C.
def main():
    N = 5_000_000
    sieve = bytearray(N)   # 0 = prime candidate, 1 = composite (a u8 array, as in the script)
    sieve[0] = 1
    sieve[1] = 1
    t0 = time.perf_counter()
    i = 2
    while i * i < N:
        if sieve[i] == 0:
            sieve[i * i::i] = b"\x01" * len(range(i * i, N, i))
        i += 1
    count = N - sum(sieve)
    t1 = time.perf_counter()
    print(f"primes_below_{N} = {count}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")
main()

Mandelbrot 200×200, 200 iter pure

DominScript · benchmarks/mandel.dom
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";

/* Mandelbrot escape-time count -- nested double arithmetic. */
i32 main()
{
    i64    $T0;
    i64    $T1;
    i32    $W       = 200;
    i32    $H       = 200;
    i32    $MaxIter = 200;
    i64    $Total   = 0;   /* iteration sum as the checksum */
    i32    $Px;
    i32    $Py;
    double $X0;
    double $Y0;
    double $X;
    double $Y;
    double $XTemp;
    i32    $Iter;

    $T0 = timer.MonotonicMs();
    $Py = 0;
    while ($Py < $H)
    {
        $Px = 0;
        while ($Px < $W)
        {
            $X0 = -2.0 + 3.0 * $Px / $W;
            $Y0 = -1.5 + 3.0 * $Py / $H;
            $X    = 0.0;
            $Y    = 0.0;
            $Iter = 0;
            while ($Iter < $MaxIter)
            {
                if ($X * $X + $Y * $Y > 4.0) { goto done; }
                $XTemp = $X * $X - $Y * $Y + $X0;
                $Y     = 2.0 * $X * $Y + $Y0;
                $X     = $XTemp;
                $Iter += 1;
            }
            done:
            $Total += $Iter;
            $Px += 1;
        }
        $Py += 1;
    }
    $T1 = timer.MonotonicMs();

    printf("checksum = %d\n", $Total);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/mandel.py
import time

# Twin of mandel.dom. Idiomatic CPython: the loops run inside a
# function; the escape loop is the plain iteration count the script also does.

def main():
    W = 200
    H = 200
    MAX_ITER = 200
    t0 = time.perf_counter()
    total = 0
    for py in range(H):
        y0 = -1.5 + 3.0 * py / H
        for px in range(W):
            x0 = -2.0 + 3.0 * px / W
            x = 0.0
            y = 0.0
            it = 0
            while it < MAX_ITER:
                if x * x + y * y > 4.0:
                    break
                x, y = x * x - y * y + x0, 2.0 * x * y + y0
                it += 1
            total += it
    t1 = time.perf_counter()
    print(f"checksum = {total}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

N-body, 5 bodies, 20k steps pure

DominScript · benchmarks/nbody.dom
plugin "builtin:struct";
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";
plugin "builtin:num";

/* N-body (5 bodies, 20k steps) -- double arithmetic on struct members: the
   schema fields ($B[i].x, $B[i].vx) are read and written in a tight loop.
   The square root is the language's own num.Sqrt (builtin:num), which is what
   a user would write; the Python twin calls Python's built-in math.sqrt. */
struct Body { double x; double y; double z; double vx; double vy; double vz; double m; }

i32 main()
{
    i64    $T0;
    i64    $T1;
    i32    $Steps = 20000;
    i32    $N = 5;
    blob   $B[280];
    i32    $I; i32 $J; i32 $S;
    double $DX; double $DY; double $DZ; double $D2; double $Mag; double $Dt = 0.01;
    double $E;

    $B assign Body;
    $B[0].x = 0.0;  $B[0].y = 0.0;  $B[0].z = 0.0;  $B[0].vx = 0.0;   $B[0].vy = 0.0;   $B[0].vz = 0.0;   $B[0].m = 39.47;
    $B[1].x = 4.84; $B[1].y = -1.16; $B[1].z = -0.10; $B[1].vx = 0.606; $B[1].vy = 2.81;  $B[1].vz = -0.02; $B[1].m = 0.037;
    $B[2].x = 8.34; $B[2].y = 4.12;  $B[2].z = -0.40; $B[2].vx = -1.01; $B[2].vy = 1.82;  $B[2].vz = 0.008; $B[2].m = 0.011;
    $B[3].x = 12.89; $B[3].y = -15.11; $B[3].z = -0.22; $B[3].vx = 1.08; $B[3].vy = 0.868; $B[3].vz = -0.01; $B[3].m = 0.0017;
    $B[4].x = 15.37; $B[4].y = -25.91; $B[4].z = 0.179; $B[4].vx = 0.979; $B[4].vy = 0.594; $B[4].vz = -0.034; $B[4].m = 0.002;

    $T0 = timer.MonotonicMs();
    $S = 0;
    while ($S < $Steps)
    {
        $I = 0;
        while ($I < $N)
        {
            $J = $I + 1;
            while ($J < $N)
            {
                $DX = $B[$I].x - $B[$J].x;
                $DY = $B[$I].y - $B[$J].y;
                $DZ = $B[$I].z - $B[$J].z;
                $D2 = $DX * $DX + $DY * $DY + $DZ * $DZ;
                $Mag = $Dt / ($D2 * num.Sqrt($D2));
                $B[$I].vx = $B[$I].vx - $DX * $B[$J].m * $Mag;
                $B[$I].vy = $B[$I].vy - $DY * $B[$J].m * $Mag;
                $B[$I].vz = $B[$I].vz - $DZ * $B[$J].m * $Mag;
                $B[$J].vx = $B[$J].vx + $DX * $B[$I].m * $Mag;
                $B[$J].vy = $B[$J].vy + $DY * $B[$I].m * $Mag;
                $B[$J].vz = $B[$J].vz + $DZ * $B[$I].m * $Mag;
                $J += 1;
            }
            $I += 1;
        }
        $I = 0;
        while ($I < $N)
        {
            $B[$I].x = $B[$I].x + $Dt * $B[$I].vx;
            $B[$I].y = $B[$I].y + $Dt * $B[$I].vy;
            $B[$I].z = $B[$I].z + $Dt * $B[$I].vz;
            $I += 1;
        }
        $S += 1;
    }
    $T1 = timer.MonotonicMs();
    $E = 0.0;
    $I = 0;
    while ($I < $N) { $E = $E + 0.5 * $B[$I].m * ($B[$I].vx * $B[$I].vx + $B[$I].vy * $B[$I].vy + $B[$I].vz * $B[$I].vz); $I += 1; }
    printf("energy = %.6f\n", $E);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/nbody.py
import time, math

# Twin of nbody.dom. Idiomatic CPython: the step loop runs inside a
# function over lists of floats (the script's struct members), math.sqrt.
STEPS = 20000

def main():
    B = [[0.0,0.0,0.0,0.0,0.0,0.0,39.47],[4.84,-1.16,-0.10,0.606,2.81,-0.02,0.037],[8.34,4.12,-0.40,-1.01,1.82,0.008,0.011],[12.89,-15.11,-0.22,1.08,0.868,-0.01,0.0017],[15.37,-25.91,0.179,0.979,0.594,-0.034,0.002]]
    dt = 0.01
    sqrt = math.sqrt
    t0 = time.perf_counter()
    n = len(B)
    for _ in range(STEPS):
        for i in range(n):
            bi = B[i]
            for j in range(i + 1, n):
                bj = B[j]
                dx = bi[0] - bj[0]; dy = bi[1] - bj[1]; dz = bi[2] - bj[2]
                d2 = dx*dx + dy*dy + dz*dz
                mag = dt / (d2 * sqrt(d2))
                bi[3] -= dx * bj[6] * mag; bi[4] -= dy * bj[6] * mag; bi[5] -= dz * bj[6] * mag
                bj[3] += dx * bi[6] * mag; bj[4] += dy * bi[6] * mag; bj[5] += dz * bi[6] * mag
        for b in B:
            b[0] += dt * b[3]; b[1] += dt * b[4]; b[2] += dt * b[5]
    t1 = time.perf_counter()
    e = sum(0.5 * b[6] * (b[3]*b[3] + b[4]*b[4] + b[5]*b[5]) for b in B)
    print(f"energy = {e:.6f}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

Fannkuch-redux, n=8 pure

DominScript · benchmarks/fannkuch.dom
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";

/* Fannkuch-redux (n=8) -- integer arrays: permutation, swap, prefix reversal by
   index. Checksum and max flips as usual. */
i32 main()
{
    i64 $T0; i64 $T1;
    i32 $N = 8;
    i32 $Perm[8]; i32 $Perm1[8]; i32 $Count[8];
    i32 $MaxFlips = 0; i32 $Checksum = 0; i32 $PermCount = 0;
    i32 $R; i32 $I; i32 $K; i32 $Flips; i32 $Tmp; i32 $Lo; i32 $Hi; i32 $Perm0;

    $I = 0; while ($I < $N) { $Perm1[$I] = $I; $I += 1; }
    $T0 = timer.MonotonicMs();
    $R = $N;
    while (1)
    {
        while ($R != 1) { $Count[$R - 1] = $R; $R -= 1; }
        $I = 0; while ($I < $N) { $Perm[$I] = $Perm1[$I]; $I += 1; }
        $Flips = 0;
        $K = $Perm[0];
        while ($K != 0)
        {
            $Lo = 0; $Hi = $K;
            while ($Lo < $Hi) { $Tmp = $Perm[$Lo]; $Perm[$Lo] = $Perm[$Hi]; $Perm[$Hi] = $Tmp; $Lo += 1; $Hi -= 1; }
            $Flips += 1;
            $K = $Perm[0];
        }
        if ($Flips > $MaxFlips) { $MaxFlips = $Flips; }
        if (($PermCount % 2) == 0) { $Checksum += $Flips; } else { $Checksum -= $Flips; }
        while (1)
        {
            if ($R == $N) { printf("checksum = %d maxflips = %d\n", $Checksum, $MaxFlips); $T1 = timer.MonotonicMs(); printf("elapsed_ms = %d\n", $T1 - $T0); return(0); }
            $Perm0 = $Perm1[0];
            $I = 0; while ($I < $R) { $Perm1[$I] = $Perm1[$I + 1]; $I += 1; }
            $Perm1[$R] = $Perm0;
            $Count[$R] -= 1;
            if ($Count[$R] > 0) { break; }
            $R += 1;
        }
        $PermCount += 1;
    }
    return(0);
}
Python · benchmarks/fannkuch.py
import time

# Twin of fannkuch.dom: the classic permutation/flip kernel in a function (the call site is inside main()).
N = 8
def fannkuch(n):
    perm1 = list(range(n)); count = [0]*n
    maxflips = 0; checksum = 0; permcount = 0; r = n
    while True:
        while r != 1:
            count[r-1] = r; r -= 1
        perm = perm1[:]
        flips = 0; k = perm[0]
        while k != 0:
            perm[0:k+1] = perm[k::-1]
            flips += 1; k = perm[0]
        if flips > maxflips: maxflips = flips
        checksum += flips if permcount % 2 == 0 else -flips
        while True:
            if r == n: return checksum, maxflips
            perm0 = perm1[0]
            for i in range(r): perm1[i] = perm1[i+1]
            perm1[r] = perm0
            count[r] -= 1
            if count[r] > 0: break
            r += 1
        permcount += 1
def main():
    t0 = time.perf_counter()
    c, m = fannkuch(N)
    t1 = time.perf_counter()
    print(f"checksum = {c} maxflips = {m}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

String find, 3 kB × 200k plugin

DominScript · benchmarks/str_find.dom
plugin "builtin:print";
plugin "../plugins/str/StrPlugin";
plugin "../plugins/timer/TimerPlugin";

/* String find in ~3 KB of text, N iterations. Most of the work is inside
 * the str plugin (memchr + memcmp). */
i32 main()
{
    i64    $T0;
    i64    $T1;
    string $Text[3200];
    string $Needle[16];
    i32    $N = 200000;
    i32    $I = 0;
    i64    $Sum = 0;
    i32    $Pos = 0;

    /* ~3 KB of text; the needle "TARGET" occurs once, near the end */
    $Text = str.Repeat("Lorem ipsum dolor sit amet, ", 100);
    $Text = str.Insert($Text, 2700, "TARGET");
    $Needle = "TARGET";

    $T0 = timer.MonotonicMs();
    while ($I < $N)
    {
        $Pos = str.Find($Text, $Needle);
        $Sum = $Sum + $Pos;
        $I   = $I + 1;
    }
    $T1 = timer.MonotonicMs();

    printf("pos = %d\n", $Pos);
    printf("sum = %d\n", $Sum);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/str_find.py
import time

# Twin of str_find.dom. Idiomatic CPython: str.find inside a function.

def main():
    text = "Lorem ipsum dolor sit amet, " * 100
    text = text[:2700] + "TARGET" + text[2700:]
    needle = "TARGET"
    N = 200_000
    t0 = time.perf_counter()
    total = 0
    pos = -1
    for _ in range(N):
        pos = text.find(needle)
        total += pos
    t1 = time.perf_counter()
    print(f"pos = {pos}")
    print(f"sum = {total}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

JSON parse + read, 30k plugin

DominScript · benchmarks/json_parse.dom
plugin "builtin:print";
plugin "../plugins/json/JsonPlugin";
plugin "../plugins/timer/TimerPlugin";

/* JSON parse + sub-object read + Free: the typical parse-and-extract
 * pattern, N iterations. */
i32 main()
{
    i64    $T0;
    i64    $T1;
    string $Doc[256];
    i32    $N = 30000;
    i32    $I = 0;
    i64    $H;
    i64    $AgeSum = 0;
    string $LastName[32];

    $Doc = "{\"user\":{\"name\":\"Ada Lovelace\",\"age\":36,\"admin\":true},\"tags\":[\"alpha\",\"beta\",\"gamma\"],\"score\":9.5}";

    $T0 = timer.MonotonicMs();
    while ($I < $N)
    {
        $H        = json.Parse($Doc);
        $LastName = json.GetString($H, "user.name");
        $AgeSum   = $AgeSum + json.GetInt($H, "user.age");
        json.Free($H);
        $I = $I + 1;
    }
    $T1 = timer.MonotonicMs();

    printf("last_name = %s\n", $LastName);
    printf("age_sum = %d\n", $AgeSum);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/json_parse.py
import json
import time

# Twin of json_parse.dom. Idiomatic CPython: json.loads inside a function.

def main():
    doc = &#x27;{"user":{"name":"Ada Lovelace","age":36,"admin":true},"tags":["alpha","beta","gamma"],"score":9.5}'
    N = 30_000
    loads = json.loads
    t0 = time.perf_counter()
    age_sum = 0
    last_name = ""
    for _ in range(N):
        obj = loads(doc)
        user = obj["user"]
        last_name = user["name"]
        age_sum += user["age"]
    t1 = time.perf_counter()
    print(f"last_name = {last_name}")
    print(f"age_sum = {age_sum}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

SHA-256, 1 kB × 20k plugin

DominScript · benchmarks/sha256.dom
plugin "builtin:print";
plugin "../plugins/crypto/CryptoPlugin";
plugin "../plugins/str/StrPlugin";
plugin "../plugins/timer/TimerPlugin";

/* SHA-256 over 1 KB of data, N iterations. Most of the work is inside the
 * crypto plugin (SHA-NI when the CPU has it, portable C otherwise). */
i32 main()
{
    i64    $T0;
    i64    $T1;
    string $Data[1100];
    string $Hash[80];
    i32    $N = 20000;
    i32    $I = 0;
    i64    $Sum = 0;

    /* ~1 KB of text (28 * 35 = 980 bytes) */
    $Data = str.Repeat("Lorem ipsum dolor sit amet, ", 35);

    $T0 = timer.MonotonicMs();
    while ($I < $N)
    {
        $Hash = crypto.Sha256Hex($Data);
        $Sum  = $Sum + $Hash.Length;
        $I    = $I + 1;
    }
    $T1 = timer.MonotonicMs();

    printf("hash_prefix = %s\n", str.Left($Hash, 16));
    printf("sum = %d\n", $Sum);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/sha256.py
import hashlib
import time

# Twin of sha256.dom. Idiomatic CPython: hashlib inside a function.

def main():
    data = ("Lorem ipsum dolor sit amet, " * 35).encode("ascii")   # 980 bytes, as in the script
    N = 20_000
    sha256 = hashlib.sha256
    t0 = time.perf_counter()
    total = 0
    h = ""
    for _ in range(N):
        h = sha256(data).hexdigest()
        total += len(h)
    t1 = time.perf_counter()
    print(f"hash_prefix = {h[:16]}")
    print(f"sum = {total}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

Plugin call, 1M × str.Len plugin

DominScript · benchmarks/call_overhead.dom
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";
plugin "../plugins/str/StrPlugin";

/* The cost of a plugin call: one million cheap verbs (str.Len on a short
   literal) -- the language's second baseline number after fib. */
i32 main()
{
    i64 $T0; i64 $T1;
    i32 $N = 1000000;
    i32 $I = 0;
    i64 $Sum = 0;
    $T0 = timer.MonotonicMs();
    while ($I < $N) { $Sum = $Sum + str.Len("hello"); $I += 1; }
    $T1 = timer.MonotonicMs();
    printf("sum = %d\n", $Sum);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/call_overhead.py
import time

# Twin of call_overhead.dom: one cheap builtin call per iteration. Idiomatic
# CPython: the loop runs inside a function over range().

def main():
    N = 1000000
    t0 = time.perf_counter()
    s = 0
    for _ in range(N):
        s += len("hello")
    t1 = time.perf_counter()
    print(f"sum = {s}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

Map put + get, 200k keys plugin

DominScript · benchmarks/map_ops.dom
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";
plugin "../plugins/str/StrPlugin";
plugin "../plugins/map/MapPlugin";

/* Map: 200k keys inserted, then 200k looked up -- the hash path and the
   plugin call together (the collections row). */
i32 main()
{
    i64 $T0; i64 $T1;
    i32 $N = 200000;
    i32 $I = 0;
    i64 $Sum = 0;
    map.Create("bench", 1024);
    $T0 = timer.MonotonicMs();
    while ($I < $N) { map.PutInt("bench", "k" + str.FromInt($I), $I * 3); $I += 1; }
    $I = 0;
    while ($I < $N) { $Sum = $Sum + map.GetInt("bench", "k" + str.FromInt($I)); $I += 1; }
    $T1 = timer.MonotonicMs();
    printf("sum = %d\n", $Sum);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    map.Destroy("bench");
    return(0);
}
Python · benchmarks/map_ops.py
import time

# Twin of map_ops.dom: dict put + get with string keys, inside a function.

def main():
    N = 200000
    d = {}
    t0 = time.perf_counter()
    for i in range(N):
        d["k" + str(i)] = i * 3
    s = 0
    for i in range(N):
        s += d["k" + str(i)]
    t1 = time.perf_counter()
    print(f"sum = {s}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

Regex match, 100k lines plugin

DominScript · benchmarks/regex_match.dom
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";
plugin "../plugins/str/StrPlugin";
plugin "../plugins/regex/RegexPlugin";

/* Regex: 100k log lines filtered with one compiled pattern (str_find is the
   raw search; this is the Spencer engine's path). */
i32 main()
{
    i64 $T0; i64 $T1;
    i32 $N = 100000;
    i32 $I = 0;
    i32 $Hits = 0;
    i64 $Re = regex.Compile("^[A-Z]+ [0-9]+: [a-z]+ [a-z]+$");
    $T0 = timer.MonotonicMs();
    while ($I < $N)
    {
        string $Line[128] = (($I % 3) == 0) ? ("ERROR " + str.FromInt($I) + ": disk full") : ("info " + str.FromInt($I) + " ok");
        $Hits = $Hits + regex.Match($Re, $Line);
        $I += 1;
    }
    $T1 = timer.MonotonicMs();
    printf("hits = %d\n", $Hits);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/regex_match.py
import time, re

# Twin of regex_match.dom: a compiled pattern matched per line, inside a function.

def main():
    N = 100000
    pat = re.compile(r"^[A-Z]+ [0-9]+: [a-z]+ [a-z]+$")
    match = pat.match
    t0 = time.perf_counter()
    hits = 0
    for i in range(N):
        line = ("ERROR " + str(i) + ": disk full") if i % 3 == 0 else ("info " + str(i) + " ok")
        if match(line):
            hits += 1
    t1 = time.perf_counter()
    print(f"hits = {hits}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

Packet data path, 200k frames workload

DominScript · benchmarks/w1_packets.dom
/* Packet data path: a receive buffer with 100 packed frames; per frame a typed
   view, field reads, validation and an in-place modify. 2000 passes = 200k frames. */
plugin "builtin:struct";
plugin "builtin:blob";
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";

struct SensorFrame packet { u8 version; u8 kind; u16 sensorId; i32 value; u8 flags; }

i32 main()
{
    blob $Buf[900]; $Buf.Length = 0;
    blob $F[9];
    i64 $T0; i64 $T1;
    i32 $I = 0; i32 $Pass = 0; i64 $Sum = 0; i32 $Bad = 0;

    $F assign SensorFrame;
    $I = 0;
    while ($I < 100)
    {
        $F.version = 1; $F.kind = $I % 5; $F.sensorId = 4000 + $I; $F.value = $I * 3; $F.flags = 0;
        if ($I % 7 == 0) { $F.version = 2; }
        if ($I == 0) { $Buf = $F; } else { $Buf = $Buf + $F; }
        $I = $I + 1;
    }

    $T0 = timer.MonotonicMs();
    while ($Pass < 2000)
    {
        $I = 0;
        while ($I < 100)
        {
            $F = $Buf[$I * 9 .. $I * 9 + 8];
            $F assign SensorFrame;
            if ($F.version != 1) { $Bad = $Bad + 1; $I = $I + 1; continue; }
            if ($F.kind == 3) { $F.value = $F.value * 2; $F.flags = 0x80; }
            $Sum = $Sum + $F.value + $F.sensorId;
            $I = $I + 1;
        }
        $Pass = $Pass + 1;
    }
    $T1 = timer.MonotonicMs();
    printf("sum=%d bad=%d\n", $Sum, $Bad);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/w1_packets.py
import struct, time

# Twin of w1_packets.dom: 100 packed frames (u8 u8 u16 i32 u8 = 9 bytes,
# little-endian, packed) in one receive buffer; 2000 passes = 200k frames.
# Same work: slice the frame out (the script copies it into a frame blob
# too), validate, conditional modify of that frame, sum. Idiomatic CPython
#: one bytearray slice per frame,
# struct.unpack_from / pack_into, inside a function.
FRAME = struct.Struct("<BBHiB")

def main():
    buf = bytearray(900)
    for i in range(100):
        version = 2 if i % 7 == 0 else 1
        FRAME.pack_into(buf, i * 9, version, i % 5, 4000 + i, i * 3, 0)
    unpack_from = FRAME.unpack_from
    pack_into = FRAME.pack_into
    t0 = time.perf_counter()
    total = 0
    bad = 0
    for _ in range(2000):
        for off in range(0, 900, 9):
            f = buf[off:off + 9]
            version, kind, sensor_id, value, flags = unpack_from(f)
            if version != 1:
                bad += 1
                continue
            if kind == 3:
                value *= 2
                flags = 0x80
                pack_into(f, 0, version, kind, sensor_id, value, flags)
            total += value + sensor_id
    t1 = time.perf_counter()
    print(f"sum={total} bad={bad}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

Log lines, 100k workload

DominScript · benchmarks/w2_lines.dom
/* Log-line processing: build a line, find and slice fields, parse an integer,
   count by key, format a summary. 100k lines. */
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";
plugin "../plugins/str/StrPlugin";

i32 main()
{
    string $Line[128];
    string $Key[32];
    string $Out[128];
    i64 $T0; i64 $T1;
    i32 $I = 0; i64 $Total = 0; i32 $Errors = 0; i32 $P;

    $T0 = timer.MonotonicMs();
    while ($I < 100000)
    {
        $Line = "2026-09-09 host" + str.FromInt($I % 17) + " GET /api/item/" + str.FromInt($I) + " 200 " + str.FromInt(($I * 37) % 5000);
        $P = str.Find($Line, " GET ");
        if ($P < 0) { $Errors = $Errors + 1; $I = $I + 1; continue; }
        $Key = str.Sub($Line, 11, $P - 11);
        $Total = $Total + str.ToInt(str.Sub($Line, str.FindLast($Line, " ") + 1));
        if (str.EndsWith($Key, "host3")) { $Out = str.Upper($Key) + ":" + str.FromInt($I); }
        $I = $I + 1;
    }
    $T1 = timer.MonotonicMs();
    printf("total=%d errors=%d out=%s\n", $Total, $Errors, $Out);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/w2_lines.py
import time

# Twin of w2_lines.dom: build a log line, find/slice/parse, count, format.
# Idiomatic CPython: inside a function; f-string for the line.

def main():
    t0 = time.perf_counter()
    total = 0
    errors = 0
    out = ""
    for i in range(100000):
        line = f"2026-09-09 host{i % 17} GET /api/item/{i} 200 {(i * 37) % 5000}"
        p = line.find(" GET ")
        if p < 0:
            errors += 1
            continue
        key = line[11:p]
        total += int(line[line.rfind(" ") + 1:])
        if key.endswith("host3"):
            out = key.upper() + ":" + str(i)
    t1 = time.perf_counter()
    print(f"total={total} errors={errors} out={out}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

Header parsing by hand, 200k headers workload

DominScript · benchmarks/w3_headers.dom
/* w3_headers: IPv4 + TCP header parsing -- the BASELINE for bit fields and byte order
   (rev31zzrg). 1000 headers of 40 bytes (20 IPv4 + 20 TCP) in NETWORK (big-endian) byte
   order in one receive buffer; 200 passes = 200k headers. Every field is extracted the way
   a script has to do it today: byte reads from the buffer, shifts, masks and ORs -- 4-bit
   and 6-bit fields, a 13-bit field and a 9-bit field that cross a byte boundary, big-endian
   u16 and u32 fields. The fields are summed so nothing is skipped. This is the "before"
   number for schema bit fields and `big` schemas (TODO [BITFIELD/ENDIAN]). */
plugin "builtin:blob";
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";

#define NHDR 1000
#define HLEN 40

i32 main()
{
    blob $Buf[40000];
    i64 $Seed = 12345;
    i32 $I = 0; i32 $K = 0; i32 $O = 0; i32 $Pass = 0;
    i64 $Sum = 0; i64 $Syn = 0; i64 $Frag = 0;
    i64 $T0; i64 $T1;
    i64 $Version; i64 $Ihl; i64 $Dscp; i64 $Ecn; i64 $TotLen; i64 $Id; i64 $Flags; i64 $FragOff;
    i64 $Ttl; i64 $Proto; i64 $Src; i64 $Dst;
    i64 $SPort; i64 $DPort; i64 $Seq; i64 $Ack; i64 $DataOff; i64 $TcpFlags; i64 $Window;

    /* build the buffer: deterministic pseudo-random headers, written byte by byte */
    while ($I < NHDR)
    {
        $O = $I * HLEN;
        $K = 0;
        while ($K < HLEN)
        {
            $Seed = ($Seed * 1103515245 + 12345) & 0x7FFFFFFF;
            $Buf[$O + $K] = ($Seed >> 16) & 0xFF;
            $K = $K + 1;
        }
        $Buf[$O] = 0x45;          /* version 4, ihl 5 */
        $Buf[$O + 9] = 6;         /* TCP */
        $Buf[$O + 32] = (5 << 4) | ($Buf[$O + 32] & 1);   /* data offset 5, NS bit random */
        $I = $I + 1;
    }

    $T0 = timer.MonotonicMs();
    while ($Pass < 200)
    {
        $I = 0;
        while ($I < NHDR)
        {
            $O = $I * HLEN;
            /* IPv4 */
            $Version = $Buf[$O] >> 4;
            $Ihl     = $Buf[$O] & 0x0F;
            $Dscp    = $Buf[$O + 1] >> 2;
            $Ecn     = $Buf[$O + 1] & 0x03;
            $TotLen  = ($Buf[$O + 2] << 8) | $Buf[$O + 3];
            $Id      = ($Buf[$O + 4] << 8) | $Buf[$O + 5];
            $Flags   = $Buf[$O + 6] >> 5;
            $FragOff = (($Buf[$O + 6] & 0x1F) << 8) | $Buf[$O + 7];
            $Ttl     = $Buf[$O + 8];
            $Proto   = $Buf[$O + 9];
            $Src     = ($Buf[$O + 12] << 24) | ($Buf[$O + 13] << 16) | ($Buf[$O + 14] << 8) | $Buf[$O + 15];
            $Dst     = ($Buf[$O + 16] << 24) | ($Buf[$O + 17] << 16) | ($Buf[$O + 18] << 8) | $Buf[$O + 19];
            /* TCP */
            $SPort    = ($Buf[$O + 20] << 8) | $Buf[$O + 21];
            $DPort    = ($Buf[$O + 22] << 8) | $Buf[$O + 23];
            $Seq      = ($Buf[$O + 24] << 24) | ($Buf[$O + 25] << 16) | ($Buf[$O + 26] << 8) | $Buf[$O + 27];
            $Ack      = ($Buf[$O + 28] << 24) | ($Buf[$O + 29] << 16) | ($Buf[$O + 30] << 8) | $Buf[$O + 31];
            $DataOff  = $Buf[$O + 32] >> 4;
            $TcpFlags = (($Buf[$O + 32] & 0x01) << 8) | $Buf[$O + 33];
            $Window   = ($Buf[$O + 34] << 8) | $Buf[$O + 35];

            if (($TcpFlags & 0x02) != 0) { $Syn = $Syn + 1; }
            if ($FragOff != 0) { $Frag = $Frag + 1; }
            $Sum = $Sum + $Version + $Ihl + $Dscp + $Ecn + $TotLen + $Id + $Flags + $FragOff + $Ttl + $Proto
                 + ($Src & 0xFFFF) + ($Dst >> 16) + $SPort + $DPort + ($Seq & 0xFFFFF) + ($Ack >> 12)
                 + $DataOff + $TcpFlags + $Window;
            $I = $I + 1;
        }
        $Pass = $Pass + 1;
    }
    $T1 = timer.MonotonicMs();
    printf("sum=%d syn=%d frag=%d\n", $Sum, $Syn, $Frag);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/w3_headers.py
import struct, time

# Twin of w3_headers.dom: 1000 IPv4 + TCP headers (40 bytes, network byte order) in one
# receive buffer; 200 passes = 200k headers; 19 fields per header, including the 4-, 6-,
# 13- and 9-bit fields. Idiomatic CPython: struct.unpack_from with the network format
# for the byte-aligned fields, shifts and masks for the bit fields, the same sums.
HDR = struct.Struct("!BBHHHBBHIIHHIIBBHHH")
NHDR = 1000
HLEN = 40

def build():
    buf = bytearray(NHDR * HLEN)
    seed = 12345
    for i in range(NHDR):
        o = i * HLEN
        for k in range(HLEN):
            seed = (seed * 1103515245 + 12345) & 0x7FFFFFFF
            buf[o + k] = (seed >> 16) & 0xFF
        buf[o] = 0x45
        buf[o + 9] = 6
        buf[o + 32] = (5 << 4) | (buf[o + 32] & 1)
    return buf

def main():
    buf = build()
    unpack_from = HDR.unpack_from
    t0 = time.perf_counter()
    total = 0; syn = 0; frag = 0
    for _ in range(200):
        for i in range(NHDR):
            o = i * HLEN
            (b0, b1, totlen, ident, fragw, ttl, proto, _csum, src, dst,
             sport, dport, seq, ack, b32, b33, window, _tcsum, _urg) = unpack_from(buf, o)
            version = b0 >> 4; ihl = b0 & 0x0F
            dscp = b1 >> 2; ecn = b1 & 0x03
            flags = fragw >> 13; fragoff = fragw & 0x1FFF
            dataoff = b32 >> 4
            tcpflags = ((b32 & 0x01) << 8) | b33
            if tcpflags & 0x02: syn += 1
            if fragoff != 0: frag += 1
            total += (version + ihl + dscp + ecn + totlen + ident + flags + fragoff + ttl + proto
                      + (src & 0xFFFF) + (dst >> 16) + sport + dport + (seq & 0xFFFFF) + (ack >> 12)
                      + dataoff + tcpflags + window)
    t1 = time.perf_counter()
    print(f"sum={total} syn={syn} frag={frag}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

if __name__ == "__main__":
    main()

Header parsing with a schema, 200k headers workload

DominScript · benchmarks/w3_headers_schema.dom
/* w3_headers_schema: the same IPv4 + TCP header parse as w3_headers, but the fields come from
   a `packet big` schema with BIT FIELDS (NyRef 14.3a/b) instead of hand-written byte reads,
   shifts and masks. Same buffer, same passes, same sums -- the two benchmarks must print the
   same sum line. (rev31zzro) */
plugin "builtin:struct";
plugin "builtin:blob";
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";

#define NHDR 1000
#define HLEN 40

struct Hdr packet big {
    u8  version : 4; u8  ihl : 4; u8  dscp : 6; u8  ecn : 2;
    u16 totlen; u16 id; u8 flags : 3; u16 fragoff : 13;
    u8  ttl; u8  proto; u16 csum; u32 src; u32 dst;
    u16 sport; u16 dport; u32 seq; u32 ack;
    u8  dataoff : 4; u8 rsv : 3; u16 tcpflags : 9; u16 window; u16 tcsum; u16 urg;
}

i32 main()
{
    blob $Buf[40000];
    blob $F[40];
    i64 $Seed = 12345;
    i32 $I = 0; i32 $K = 0; i32 $O = 0; i32 $Pass = 0;
    i64 $Sum = 0; i64 $Syn = 0; i64 $Frag = 0;
    i64 $T0; i64 $T1;

    while ($I < NHDR)
    {
        $O = $I * HLEN;
        $K = 0;
        while ($K < HLEN)
        {
            $Seed = ($Seed * 1103515245 + 12345) & 0x7FFFFFFF;
            $Buf[$O + $K] = ($Seed >> 16) & 0xFF;
            $K = $K + 1;
        }
        $Buf[$O] = 0x45;
        $Buf[$O + 9] = 6;
        $Buf[$O + 32] = (5 << 4) | ($Buf[$O + 32] & 1);
        $I = $I + 1;
    }

    $F assign Hdr;
    $T0 = timer.MonotonicMs();
    while ($Pass < 200)
    {
        $I = 0;
        while ($I < NHDR)
        {
            $F = $Buf[$I * HLEN .. $I * HLEN + HLEN - 1];
            if (($F.tcpflags & 0x02) != 0) { $Syn = $Syn + 1; }
            if ($F.fragoff != 0) { $Frag = $Frag + 1; }
            $Sum = $Sum + $F.version + $F.ihl + $F.dscp + $F.ecn + $F.totlen + $F.id;
            $Sum = $Sum + $F.flags + $F.fragoff + $F.ttl + $F.proto + ($F.src & 0xFFFF) + ($F.dst >> 16);
            $Sum = $Sum + $F.sport + $F.dport + ($F.seq & 0xFFFFF) + ($F.ack >> 12);
            $Sum = $Sum + $F.dataoff + $F.tcpflags + $F.window;
            $I = $I + 1;
        }
        $Pass = $Pass + 1;
    }
    $T1 = timer.MonotonicMs();
    printf("sum=%d syn=%d frag=%d\n", $Sum, $Syn, $Frag);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/w3_headers_schema.py
import struct, time

# Twin of w3_headers_schema.dom (the same Python program as w3_headers.py: CPython has one idiomatic way; the DominScript side reads a `packet big` schema with bit fields): 1000 IPv4 + TCP headers (40 bytes, network byte order) in one
# receive buffer; 200 passes = 200k headers; 19 fields per header, including the 4-, 6-,
# 13- and 9-bit fields. Idiomatic CPython: struct.unpack_from with the network format
# for the byte-aligned fields, shifts and masks for the bit fields, the same sums.
HDR = struct.Struct("!BBHHHBBHIIHHIIBBHHH")
NHDR = 1000
HLEN = 40

def build():
    buf = bytearray(NHDR * HLEN)
    seed = 12345
    for i in range(NHDR):
        o = i * HLEN
        for k in range(HLEN):
            seed = (seed * 1103515245 + 12345) & 0x7FFFFFFF
            buf[o + k] = (seed >> 16) & 0xFF
        buf[o] = 0x45
        buf[o + 9] = 6
        buf[o + 32] = (5 << 4) | (buf[o + 32] & 1)
    return buf

def main():
    buf = build()
    unpack_from = HDR.unpack_from
    t0 = time.perf_counter()
    total = 0; syn = 0; frag = 0
    for _ in range(200):
        for i in range(NHDR):
            o = i * HLEN
            (b0, b1, totlen, ident, fragw, ttl, proto, _csum, src, dst,
             sport, dport, seq, ack, b32, b33, window, _tcsum, _urg) = unpack_from(buf, o)
            version = b0 >> 4; ihl = b0 & 0x0F
            dscp = b1 >> 2; ecn = b1 & 0x03
            flags = fragw >> 13; fragoff = fragw & 0x1FFF
            dataoff = b32 >> 4
            tcpflags = ((b32 & 0x01) << 8) | b33
            if tcpflags & 0x02: syn += 1
            if fragoff != 0: frag += 1
            total += (version + ihl + dscp + ecn + totlen + ident + flags + fragoff + ttl + proto
                      + (src & 0xFFFF) + (dst >> 16) + sport + dport + (seq & 0xFFFFF) + (ack >> 12)
                      + dataoff + tcpflags + window)
    t1 = time.perf_counter()
    print(f"sum={total} syn={syn} frag={frag}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

if __name__ == "__main__":
    main()

for loop, 3M iterations style

DominScript · benchmarks/for_loop.dom
/* The same arithmetic loop written as a `while` and as a `for`. elapsed_ms is the
   `for` variant -- the most common loop form, measured as such. */
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";

i32 main()
{
    i64 $I = 0; i64 $Sum = 0; i64 $T0; i64 $T1;
    $T0 = timer.MonotonicMs();
    while ($I < 3000000) { $Sum = $Sum + $I * 3 + 1; $I = $I + 1; }
    $T1 = timer.MonotonicMs();
    printf("sum_while=%d while_ms = %d\n", $Sum, $T1 - $T0);
    $Sum = 0;
    $T0 = timer.MonotonicMs();
    for ($I = 0; $I < 3000000; $I = $I + 1) { $Sum = $Sum + $I * 3 + 1; }
    $T1 = timer.MonotonicMs();
    printf("sum_for=%d\n", $Sum);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/for_loop.py
import time

# Twin of for_loop.dom; elapsed_ms is the for loop. Idiomatic CPython: inside a function.

def main():
    t0 = time.perf_counter(); s = 0
    for i in range(3000000):
        s += i * 3 + 1
    t1 = time.perf_counter()
    print(f"sum_for={s}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

Local declared in the loop body, 3M iterations style

DominScript · benchmarks/local_in_loop.dom
/* The same arithmetic loop twice: with the temporary declared outside the loop,
   and with it declared inside the body -- the ordinary habit. elapsed_ms is the
   inside variant. */
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";

i32 main()
{
    i64 $I = 0; i64 $Sum = 0; i64 $T0; i64 $T1; i64 $T;
    $T0 = timer.MonotonicMs();
    while ($I < 3000000) { $T = $I * 3 + 1; $Sum = $Sum + $T; $I = $I + 1; }
    $T1 = timer.MonotonicMs();
    printf("sum_outer=%d outer_ms = %d\n", $Sum, $T1 - $T0);
    $I = 0; $Sum = 0;
    $T0 = timer.MonotonicMs();
    while ($I < 3000000) { i64 $L = $I * 3 + 1; $Sum = $Sum + $L; $I = $I + 1; }
    $T1 = timer.MonotonicMs();
    printf("sum_inner=%d\n", $Sum);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/local_in_loop.py
import time

# Twin of local_in_loop.dom. Python has no block scope, so both variants are the
# same code; elapsed_ms is the loop with the temporary assigned in the body.
# Idiomatic CPython: inside a function.

def main():
    t0 = time.perf_counter(); s = 0
    for i in range(3000000):
        t = i * 3 + 1
        s += t
    t1 = time.perf_counter()
    print(f"sum_inner={s}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

Helper function called in the loop, 3M iterations style

DominScript · benchmarks/helper_loop.dom
/* What people actually write: the same arithmetic loop twice, once calling a
   one-line helper function per iteration, once with the expression inline.
   elapsed_ms is the helper variant. */
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";

i64 Step(i64 $X) { return($X * 3 + 1); }

i32 main()
{
    i64 $I = 0; i64 $Sum = 0; i64 $T0; i64 $T1; i64 $Inline;
    $T0 = timer.MonotonicMs();
    while ($I < 3000000) { $Sum = $Sum + ($I * 3 + 1); $I = $I + 1; }
    $T1 = timer.MonotonicMs();
    $Inline = $T1 - $T0;
    printf("sum_inline=%d inline_ms = %d\n", $Sum, $Inline);
    $I = 0; $Sum = 0;
    $T0 = timer.MonotonicMs();
    while ($I < 3000000) { $Sum = $Sum + Step($I); $I = $I + 1; }
    $T1 = timer.MonotonicMs();
    printf("sum_helper=%d\n", $Sum);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/helper_loop.py
import time

# Twin of helper_loop.dom: the same loop with the expression inline, then with
# a one-line helper called per iteration. elapsed_ms is the HELPER variant.
# Idiomatic CPython: inside a function.

def step(x):
    return x * 3 + 1

def main():
    t0 = time.perf_counter(); s = 0
    for i in range(3000000):
        s += (i * 3 + 1)
    t1 = time.perf_counter()
    print(f"sum_inline={s} inline_ms = {int((t1 - t0) * 1000)}")
    t0 = time.perf_counter(); s = 0
    for i in range(3000000):
        s += step(i)
    t1 = time.perf_counter()
    print(f"sum_helper={s}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

Integer × double in the loop, 3M iterations style

DominScript · benchmarks/mixed_arith.dom
/* The same loop twice: with double-only operands, and with an integer variable
   mixed into the double arithmetic (`$Acc + $I * 0.5`). elapsed_ms is the mixed
   variant. */
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";

i32 main()
{
    i64 $I = 0; double $Acc = 0.0; double $X = 0.0; i64 $T0; i64 $T1;
    $T0 = timer.MonotonicMs();
    while ($I < 3000000) { $X = $X + 1.0; $Acc = $Acc + $X * 0.5; $I = $I + 1; }
    $T1 = timer.MonotonicMs();
    printf("acc_double=%f double_ms = %d\n", $Acc, $T1 - $T0);
    $I = 0; $Acc = 0.0;
    $T0 = timer.MonotonicMs();
    while ($I < 3000000) { $Acc = $Acc + $I * 0.5; $I = $I + 1; }
    $T1 = timer.MonotonicMs();
    printf("acc_mixed=%f\n", $Acc);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/mixed_arith.py
import time

# Twin of mixed_arith.dom; elapsed_ms is the loop that mixes an int with a float.
# Idiomatic CPython: inside a function.

def main():
    t0 = time.perf_counter(); acc = 0.0
    for i in range(3000000):
        acc += i * 0.5
    t1 = time.perf_counter()
    print(f"acc_mixed={acc:f}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()

Packet data path organised into a function style

DominScript · benchmarks/w1_packets_helper.dom
/* The packet data path with the per-frame work organised into a function
   (HandleFrame with a ref blob parameter). 2000 passes = 200k frames. */
plugin "builtin:struct";
plugin "builtin:blob";
plugin "builtin:print";
plugin "../plugins/timer/TimerPlugin";

struct SensorFrame packet { u8 version; u8 kind; u16 sensorId; i32 value; u8 flags; }

i64 HandleFrame(ref blob $Fr)
{
    $Fr assign SensorFrame;
    if ($Fr.version != 1) { return(0 - 1); }
    if ($Fr.kind == 3) { $Fr.value = $Fr.value * 2; $Fr.flags = 0x80; }
    return($Fr.value + $Fr.sensorId);
}

i32 main()
{
    i64 $R = 0;
    blob $Buf[900]; $Buf.Length = 0;
    blob $F[9];
    i64 $T0; i64 $T1;
    i32 $I = 0; i32 $Pass = 0; i64 $Sum = 0; i32 $Bad = 0;

    $F assign SensorFrame;
    $I = 0;
    while ($I < 100)
    {
        $F.version = 1; $F.kind = $I % 5; $F.sensorId = 4000 + $I; $F.value = $I * 3; $F.flags = 0;
        if ($I % 7 == 0) { $F.version = 2; }
        if ($I == 0) { $Buf = $F; } else { $Buf = $Buf + $F; }
        $I = $I + 1;
    }

    $T0 = timer.MonotonicMs();
    while ($Pass < 2000)
    {
        $I = 0;
        while ($I < 100)
        {
            $F = $Buf[$I * 9 .. $I * 9 + 8];
            $F assign SensorFrame;
            $R = HandleFrame($F);
            if ($R < 0) { $Bad = $Bad + 1; } else { $Sum = $Sum + $R; }
            $I = $I + 1;
        }
        $Pass = $Pass + 1;
    }
    $T1 = timer.MonotonicMs();
    printf("sum=%d bad=%d\n", $Sum, $Bad);
    printf("elapsed_ms = %d\n", $T1 - $T0);
    return(0);
}
Python · benchmarks/w1_packets_helper.py
import struct, time

# Twin of w1_packets_helper.dom: the packet path with the per-frame work in a
# function. Idiomatic CPython: one bytearray slice per frame (the
# script copies the frame too), unpack_from / pack_into, the loop inside a function.
FRAME = struct.Struct("<BBHiB")

def handle_frame(f):
    version, kind, sensor_id, value, flags = FRAME.unpack_from(f)
    if version != 1:
        return -1
    if kind == 3:
        value *= 2
        flags = 0x80
        FRAME.pack_into(f, 0, version, kind, sensor_id, value, flags)
    return value + sensor_id

def main():
    buf = bytearray(900)
    for i in range(100):
        version = 2 if i % 7 == 0 else 1
        FRAME.pack_into(buf, i * 9, version, i % 5, 4000 + i, i * 3, 0)
    t0 = time.perf_counter()
    total = 0
    bad = 0
    for _ in range(2000):
        for off in range(0, 900, 9):
            r = handle_frame(buf[off:off + 9])
            if r < 0:
                bad += 1
            else:
                total += r
    t1 = time.perf_counter()
    print(f"sum={total} bad={bad}")
    print(f"elapsed_ms = {int((t1 - t0) * 1000)}")

main()