diff --git a/bench/algorithm/coro-prime-sieve/1.pony b/bench/algorithm/coro-prime-sieve/1.pony new file mode 100644 index 000000000..42cc91d12 --- /dev/null +++ b/bench/algorithm/coro-prime-sieve/1.pony @@ -0,0 +1,30 @@ +// Single-thread implementation + +actor Main + new create(env: Env) => + let n: USize = + try + env.args(1)?.usize()? + else + 100 + end + + let primes = Array[U64] + var count: USize = 0 + var i: U64 = 2 + while count < n do + var is_prime = true + for p in primes.values() do + if (p * p) > i then break end + if (i % p) == 0 then + is_prime = false + break + end + end + if is_prime then + env.out.write(i.string() + "\n") + primes.push(i) + count = count + 1 + end + i = i + 1 + end diff --git a/bench/algorithm/fannkuch-redux/1.pony b/bench/algorithm/fannkuch-redux/1.pony new file mode 100644 index 000000000..7eb86d43a --- /dev/null +++ b/bench/algorithm/fannkuch-redux/1.pony @@ -0,0 +1,96 @@ +// Based on the OCaml version from "The Computer Language Benchmarks Game" +// https://salsa.debian.org/benchmarksgame-team/benchmarksgame/ + +use "collections" + +actor Main + new create(env: Env) => + let n: USize = try env.args(1)?.usize()? else 7 end + Fannkuch(env, n) + +class Fannkuch + let _env: Env + var _perm: Array[USize] + var _copy: Array[USize] + var _max_flips: USize = 0 + var _checksum: ISize = 0 + var _perm_count: USize = 0 + let _n: USize + + new create(env: Env, n: USize) => + _env = env + _n = n + _perm = recover Array[USize](n) end + _copy = recover Array[USize](n) end + + for i in Range[USize](0, n) do + _perm.push(i) + end + + run() + print_results() + + fun ref run() => + // This is a direct translation of the recursive permutation + // generation from the OCaml version. + do_iter(_n) + + fun ref do_iter(ht: USize) => + if ht == 1 then + // Process the permutation + _copy.clear() + for i in Range[USize](0, _perm.size()) do + try _copy.push(_perm(i)?) end + end + + let flips = count_flips(_copy) + + // Update checksum: add for even permutations, subtract for odd + if (_perm_count % 2) == 0 then + _checksum = _checksum + flips.isize() + else + _checksum = _checksum - flips.isize() + end + + if flips > _max_flips then + _max_flips = flips + end + + _perm_count = _perm_count + 1 + else + for i in Range[USize](0, ht) do + do_iter(ht - 1) + // Rotate the first `ht` elements + if ht > 1 then + try + let t = _perm(0)? + for j in Range[USize](1, ht) do + _perm(j-1)? = _perm(j)? + end + _perm(ht-1)? = t + end + end + end + end + + fun ref count_flips(p: Array[USize]): USize => + var flips: USize = 0 + try + var first = p(0)? + while first != 0 do + // Flip the first `first + 1` elements + for i in Range[USize](0, (first / 2) + 1) do + let k = first - i + let t = p(i)? + p(i)? = p(k)? + p(k)? = t + end + flips = flips + 1 + first = p(0)? + end + end + flips + + fun ref print_results() => + _env.out.print(_checksum.string()) + _env.out.print("Pfannkuchen(" + _n.string() + ") = " + _max_flips.string()) diff --git a/bench/algorithm/fasta/1.pony b/bench/algorithm/fasta/1.pony new file mode 100644 index 000000000..f02f1a768 --- /dev/null +++ b/bench/algorithm/fasta/1.pony @@ -0,0 +1,107 @@ +// Based on the Rust (1.rs) implementation. + +use "collections" + +class RNG + var seed: U32 + new create() => + seed = 42 + fun ref next(max: F64): F64 => + seed = ((seed * 3877) + 29573) % 139968 + (max * seed.f64()) / 139968.0 + +struct Amino + let l: U8 + let p: F64 + new create(l': U8, p': F64) => + l = l' + p = p' + +actor Main + new create(env: Env) => + let n: USize = try env.args(1)?.usize()? else 10 end + let stdout = env.out + let rng = RNG + let alu: String val = + "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTC" + + "AGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCG" + + "TGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGG" + + "AGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA" + + stdout.print(">ONE Homo sapiens alu") + try _repeat_and_wrap(stdout, alu, 2 * n)? end + + let iub = recover iso Array[Amino](15) + .> push(Amino(97, 0.27)) .> push(Amino(99, 0.12)) .> push(Amino(103, 0.12)) .> push(Amino(116, 0.27)) + .> push(Amino(66, 0.02)) .> push(Amino(68, 0.02)) .> push(Amino(72, 0.02)) .> push(Amino(75, 0.02)) + .> push(Amino(77, 0.02)) .> push(Amino(78, 0.02)) .> push(Amino(82, 0.02)) .> push(Amino(83, 0.02)) + .> push(Amino(86, 0.02)) .> push(Amino(87, 0.02)) .> push(Amino(89, 0.02)) + end + stdout.print(">TWO IUB ambiguity codes") + try _generate_and_wrap(stdout, recover val consume iub end, 3 * n, rng)? end + + let hs = recover iso Array[Amino](4) + .> push(Amino(97, 0.3029549426680)) .> push(Amino(99, 0.1979883004921)) + .> push(Amino(103, 0.1975473066391)) .> push(Amino(116, 0.3015094502008)) + end + stdout.print(">THREE Homo sapiens frequency") + try _generate_and_wrap(stdout, recover val consume hs end, 5 * n, rng)? end + + fun _repeat_and_wrap(out: OutStream, seq: String val, count: USize) ? => + let max_line: USize = 60 + let slen = seq.size() + let sbytes: Array[U8] val = seq.array() + let padded = recover iso Array[U8](slen + max_line) end + var i: USize = 0 + while i < (slen + max_line) do + padded.push(sbytes(i % slen)?) + i = i + 1 + end + var off: USize = 0 + var idx: USize = 0 + while idx < count do + let rem = count - idx + let line_len = if rem < max_line then rem else max_line end + let line_arr = recover iso Array[U8](line_len) end + var t: USize = 0 + while t < line_len do + line_arr.push(padded(off + t)?) + t = t + 1 + end + out.print(String.from_array(consume line_arr)) + off = off + line_len + if off >= slen then off = off - slen end + idx = idx + line_len + end + + fun _generate_and_wrap(out: OutStream, nts: Array[Amino] val, count: USize, rng: RNG ref) ? => + let max_line: USize = 60 + var cum: F64 = 0 + let cum_tot = recover iso Array[F64](nts.size()) end + var ni: USize = 0 + while ni < nts.size() do + cum = cum + nts(ni)?.p + cum_tot.push(cum) + ni = ni + 1 + end + var idx: USize = 0 + while idx < count do + let rem = count - idx + let line_len = if rem < max_line then rem else max_line end + let line = recover iso Array[U8](line_len) end + var j: USize = 0 + while j < line_len do + let r = rng.next(1.0) + var c: USize = 0 + var ti: USize = 0 + while ti < cum_tot.size() do + let t = cum_tot(ti)? + if r > t then c = c + 1 else break end + ti = ti + 1 + end + line.push(nts(c)?.l) + j = j + 1 + end + out.print(String.from_array(consume line)) + idx = idx + line_len + end diff --git a/bench/algorithm/knucleotide/1.pony b/bench/algorithm/knucleotide/1.pony new file mode 100644 index 000000000..a9b7d55e0 --- /dev/null +++ b/bench/algorithm/knucleotide/1.pony @@ -0,0 +1,247 @@ +// Based on the OCaml (3.ml) and C implementations in this repo; single-threaded; +use "collections" +use "files" + +primitive Nuc + fun code(u: U8): U8 => + // map both cases to 2-bit codes: a=0, t=1, c=2, g=3; others -> 255 + match u + | U8('A') | U8('a') => 0 + | U8('T') | U8('t') => 1 + | U8('C') | U8('c') => 2 + | U8('G') | U8('g') => 3 + else 255 end + + fun chr(c: U8): U8 => + // reverse map for printing (uppercase) + match c + | 0 => U8('A') + | 1 => U8('T') + | 2 => U8('C') + else U8('G') end + +primitive IO + fun read_all(env: Env, file_name: String val): String val => + let auth = env.root + let file_auth = FileAuth(auth) + let path = FilePath(file_auth, file_name) + let f = File(path) + if not f.valid() then + "" + else + var buf = recover iso String end + while f.valid() do + let chunk = f.read_string(1 << 16) + if chunk.size() == 0 then break end + buf = (consume buf) + consume chunk + end + consume buf + end + + fun three_sequence(input: String val): Array[U8] val ? => + // Extract only the sequence after a header line starting with ">THREE" + let a = input.array() + let n = input.size() + var i: USize = 0 + var found: Bool = false + // Seek to a line starting with '>THREE' + while i < n do + if a(i)? == U8('>') then + // read line start and check for "THREE" + var j = i + 1 + if (j + 4) < n then + if (a(j)? == U8('T')) and (a(j+1)? == U8('H')) and (a(j+2)? == U8('R')) and (a(j+3)? == U8('E')) and (a(j+4)? == U8('E')) then + // skip to end of line + j = j + 5 + while (j < n) and (a(j)? != U8('\n')) do j = j + 1 end + if j < n then j = j + 1 end + i = j + found = true + break + end + end + end + // skip to next line + while (i < n) and (a(i)? != U8('\n')) do i = i + 1 end + if i < n then i = i + 1 end + end + let out = recover iso Array[U8] end + if not found then + consume out + else + // read sequence until next '>' or EOF; ignore non-ATCG + while i < n do + let b = a(i)? + if b == U8('>') then break end + let c = Nuc.code(b) + if c != 255 then out.push(c) end + i = i + 1 + end + consume out + end + +primitive Pack + fun pack_seq(seq: Array[U8] val, off: USize, k: USize): U64 ? => + var key: U64 = 0 + var i: USize = 0 + while i < k do + key = (key << 2) or seq(off + i)?.u64() + i = i + 1 + end + key + + fun pack_str(s: String val): (U64, USize) ? => + let a = s.array() + let k = s.size() + var key: U64 = 0 + var i: USize = 0 + while i < k do + let c = Nuc.code(a(i)?) + key = (key << 2) or c.u64() + i = i + 1 + end + (key, k) + + fun unpack(key: U64, k: USize): String val ? => + let out = recover iso Array[U8](k) end + var tmp: U64 = key + var i: USize = 0 + // produce reversed then reverse into correct order + let rev = recover iso Array[U8](k) end + while i < k do + let c = (tmp and 3).u8() + rev.push(Nuc.chr(c)) + tmp = tmp >> 2 + i = i + 1 + end + // reverse rev into out + var j: USize = 0 + while j < k do + out.push(rev(k - 1 - j)?) + j = j + 1 + end + String.from_array(consume out) + +primitive KMers + fun counts_array(seq: Array[U8] val, k: USize): Array[USize] val ? => + let len = if k >= 32 then USize.max_value() else (USize(1) << (k << 1)) end + let out = recover iso Array[USize](len) end + if (k == 0) or (seq.size() < k) then + // fill zeros to length + var i: USize = 0 + while i < len do out.push(0); i = i + 1 end + consume out + else + // initialize counts with zeros + var i: USize = 0 + while i < len do out.push(0); i = i + 1 end + let mask: U64 = if k >= 32 then U64.max_value() else ((U64(1) << (k.u64() * 2)) - U64(1)) end + var key: U64 = Pack.pack_seq(seq, 0, k)? + out(key.usize())? = out(key.usize())? + 1 + i = k + while i < seq.size() do + key = ((key << 2) or seq(i)?.u64()) and mask + let idx = key.usize() + out(idx)? = out(idx)? + 1 + i = i + 1 + end + consume out + end + + fun count_pattern(seq: Array[U8] val, key: U64, k: USize): USize ? => + if (k == 0) or (seq.size() < k) then return 0 end + let mask: U64 = if k >= 32 then U64.max_value() else ((U64(1) << (k.u64() * 2)) - U64(1)) end + var rolling: U64 = Pack.pack_seq(seq, 0, k)? + var cnt: USize = if rolling == key then 1 else 0 end + var i: USize = k + while i < seq.size() do + rolling = ((rolling << 2) or seq(i)?.u64()) and mask + if rolling == key then cnt = cnt + 1 end + i = i + 1 + end + cnt + +primitive Sorter + fun sort_freq(a: Array[(String val, F64)] ref) ? => + // insertion sort: small arrays (4 or 16 elements) + var i: USize = 1 + while i < a.size() do + let key = a(i)? + var j: ISize = i.isize() - 1 + while j >= ISize(0) do + let cur = a(j.usize())? + if (cur._2 < key._2) or ((cur._2 == key._2) and (cur._1 > key._1)) then + a(j.usize() + 1)? = cur + j = j - 1 + else + break + end + end + a((j + 1).usize())? = key + i = i + 1 + end + +primitive Format + fun fixed3(x: F64): String val => + var y = x * 1000.0 + if y < 0 then y = 0 end + let n = (y + 0.5).floor().u64() + let ip = (n / 1000).u64() + let fp = (n % 1000).u64() + let out = recover iso String end + out.append(ip.string()) + out.push(U8('.')) + out.push(((fp / 100).u8()) + U8('0')) + out.push((((fp / 10) % 10).u8()) + U8('0')) + out.push(((fp % 10).u8()) + U8('0')) + recover val consume out end + +actor Main + new create(env: Env) => + try + let file_name = try env.args(1)? else "25000_in" end + let input = IO.read_all(env, file_name) + let seq = IO.three_sequence(input)? + let seqlen = seq.size() + + // Frequencies for k=1, k=2 + let ks: Array[USize] val = [USize(1); USize(2)] + for k in ks.values() do + let counts = KMers.counts_array(seq, k)? + let total: F64 = ((seqlen - k) + 1).f64() + let items = Array[(String val, F64)] + var idx: USize = 0 + while idx < counts.size() do + let c = counts(idx)? + if c > 0 then + let s = Pack.unpack(idx.u64(), k)? + items.push((s, (c.f64() * 100.0) / total)) + end + idx = idx + 1 + end + Sorter.sort_freq(items)? + for it in items.values() do + let line = recover iso String end + line.append(it._1) + line.push(U8(' ')) + line.append(Format.fixed3(it._2)) + env.out.print(consume line) + end + env.out.print("") + end + + // Specific pattern counts + let patterns: Array[String] val = + [ "GGT"; "GGTA"; "GGTATT"; "GGTATTTTAATT"; "GGTATTTTAATTTATAGT" ] + for p in patterns.values() do + let packed = Pack.pack_str(p)? + let key: U64 = packed._1 + let k: USize = packed._2 + let c = KMers.count_pattern(seq, key, k)? + let line2 = recover iso String end + line2.append(c.string()) + line2.push(U8('\t')) + line2.append(p) + env.out.print(consume line2) + end + end diff --git a/bench/algorithm/lru/1.pony b/bench/algorithm/lru/1.pony index 34e0fda9a..27c23dfbb 100644 --- a/bench/algorithm/lru/1.pony +++ b/bench/algorithm/lru/1.pony @@ -1,3 +1,6 @@ +// Based on OCaml (1.ml) and Zig implementation. +// It timeouts on bigger data + use "collections" class LCG diff --git a/bench/algorithm/mandelbrot/1.pony b/bench/algorithm/mandelbrot/1.pony new file mode 100644 index 000000000..bde736048 --- /dev/null +++ b/bench/algorithm/mandelbrot/1.pony @@ -0,0 +1,239 @@ +// based on 1.zig +use "collections" + +actor Main + new create(env: Env) => + let n0: USize = try env.args(1)?.usize()? else 8 end + let n = ((n0 + 7) / 8) * 8 + let size = n + let inv: F64 = 2.0 / n.f64() + let stdout = env.out + stdout.print("P4\n" + size.string() + " " + size.string()) + let pixels = recover iso Array[U8](size * (size / 8)) end + var y: USize = 0 + while y < size do + let ci = (y.f64() * inv) - 1.0 + var x: USize = 0 + var byte: U8 = 0 + var bit: USize = 0 + while x < size do + let cr = (x.f64() * inv) - 1.5 + var zr: F64 = 0 + var zi: F64 = 0 + var trmti: F64 = 0 + var k: USize = 0 + var inside = true + while k < 50 do + zi = (2.0 * zr * zi) + ci + zr = trmti + cr + let tr = zr * zr + let ti = zi * zi + if (tr + ti) > 4.0 then + inside = false + break + end + trmti = tr - ti + k = k + 1 + end + byte = byte << 1 + if inside then byte = byte or 0x01 end + bit = bit + 1 + if bit == 8 then + pixels.push(byte) + byte = 0 + bit = 0 + end + x = x + 1 + end + y = y + 1 + end + // Compute MD5 digest of pixel bytes and print + let digest = _md5_hex(consume pixels) + stdout.print(digest) + + fun _hex(bs: Array[U8] val): String val => + let buf = recover iso Array[U8](bs.size() * 2) end + for b in bs.values() do + let hi: U8 = (b >> 4) and 0x0F + let lo: U8 = b and 0x0F + let dhi = hi.u32() + let dlo = lo.u32() + buf.push((if dhi < 10 then 48 + dhi else 87 + dhi end).u8()) + buf.push((if dlo < 10 then 48 + dlo else 87 + dlo end).u8()) + end + String.from_array(consume buf) + + fun _md5_hex(bytes: Array[U8] iso): String val => + var md5 = MD5 + let bval: Array[U8] val = consume bytes + try + md5.update(bval)? + end + let dig = + try + md5.final()? + else + recover iso Array[U8](0) end + end + _hex(consume dig) +class MD5 + var _a: U32 = 0x67452301 + var _b: U32 = 0xefcdab89 + var _c: U32 = 0x98badcfe + var _d: U32 = 0x10325476 + var _len: U64 = 0 + var _buf: Array[U8] = Array[U8] + + fun ref update(data: Array[U8] box) ? => + _len = _len + (data.size().u64() * 8) + var i: USize = 0 + while i < data.size() do + _buf.push(data(i)?) + if _buf.size() == 64 then + let block = recover iso Array[U8](64) end + var m: USize = 0 + while m < 64 do block.push(_buf(m)?); m = m + 1 end + let bval: Array[U8] val = consume block + _transform(bval)? + _buf.clear() + end + i = i + 1 + end + + fun ref final(): Array[U8] iso^ ? => + _buf.push(0x80) + while (_buf.size() % 64) != 56 do _buf.push(0) end + var l: U64 = _len + var j: USize = 0 + while j < 8 do + _buf.push((l and 0xff).u8()) + l = l >> 8 + j = j + 1 + end + var k: USize = 0 + while k < _buf.size() do + let block = recover iso Array[U8](64) end + var m: USize = 0 + while m < 64 do block.push(_buf(k + m)?); m = m + 1 end + let bval: Array[U8] val = consume block + _transform(bval)? + k = k + 64 + end + let out = recover iso Array[U8](16) end + out.push((_a and 0xff).u8()) + out.push(((_a >> 8) and 0xff).u8()) + out.push(((_a >> 16) and 0xff).u8()) + out.push(((_a >> 24) and 0xff).u8()) + out.push((_b and 0xff).u8()) + out.push(((_b >> 8) and 0xff).u8()) + out.push(((_b >> 16) and 0xff).u8()) + out.push(((_b >> 24) and 0xff).u8()) + out.push((_c and 0xff).u8()) + out.push(((_c >> 8) and 0xff).u8()) + out.push(((_c >> 16) and 0xff).u8()) + out.push(((_c >> 24) and 0xff).u8()) + out.push((_d and 0xff).u8()) + out.push(((_d >> 8) and 0xff).u8()) + out.push(((_d >> 16) and 0xff).u8()) + out.push(((_d >> 24) and 0xff).u8()) + out + + fun _to_u32_le(b: Array[U8] box, o: USize): U32 ? => + b(o)?.u32() or (b(o+1)?.u32() << 8) or (b(o+2)?.u32() << 16) or (b(o+3)?.u32() << 24) + + fun ref _transform(block: Array[U8] box) ? => + var a = _a + var b = _b + var c = _c + var d = _d + let s1: Array[U32] iso = recover iso Array[U32](4) end; s1.push(7); s1.push(12); s1.push(17); s1.push(22) + let s2: Array[U32] iso = recover iso Array[U32](4) end; s2.push(5); s2.push(9); s2.push(14); s2.push(20) + let s3: Array[U32] iso = recover iso Array[U32](4) end; s3.push(4); s3.push(11); s3.push(16); s3.push(23) + let s4: Array[U32] iso = recover iso Array[U32](4) end; s4.push(6); s4.push(10); s4.push(15); s4.push(21) + let k: Array[U32] iso = recover iso Array[U32](64) end + k.push(0xd76aa478); k.push(0xe8c7b756); k.push(0x242070db); k.push(0xc1bdceee); k.push(0xf57c0faf); k.push(0x4787c62a); k.push(0xa8304613); k.push(0xfd469501) + k.push(0x698098d8); k.push(0x8b44f7af); k.push(0xffff5bb1); k.push(0x895cd7be); k.push(0x6b901122); k.push(0xfd987193); k.push(0xa679438e); k.push(0x49b40821) + k.push(0xf61e2562); k.push(0xc040b340); k.push(0x265e5a51); k.push(0xe9b6c7aa); k.push(0xd62f105d); k.push(0x02441453); k.push(0xd8a1e681); k.push(0xe7d3fbc8) + k.push(0x21e1cde6); k.push(0xc33707d6); k.push(0xf4d50d87); k.push(0x455a14ed); k.push(0xa9e3e905); k.push(0xfcefa3f8); k.push(0x676f02d9); k.push(0x8d2a4c8a) + k.push(0xfffa3942); k.push(0x8771f681); k.push(0x6d9d6122); k.push(0xfde5380c); k.push(0xa4beea44); k.push(0x4bdecfa9); k.push(0xf6bb4b60); k.push(0xbebfbc70) + k.push(0x289b7ec6); k.push(0xeaa127fa); k.push(0xd4ef3085); k.push(0x04881d05); k.push(0xd9d4d039); k.push(0xe6db99e5); k.push(0x1fa27cf8); k.push(0xc4ac5665) + k.push(0xf4292244); k.push(0x432aff97); k.push(0xab9423a7); k.push(0xfc93a039); k.push(0x655b59c3); k.push(0x8f0ccc92); k.push(0xffeff47d); k.push(0x85845dd1) + k.push(0x6fa87e4f); k.push(0xfe2ce6e0); k.push(0xa3014314); k.push(0x4e0811a1); k.push(0xf7537e82); k.push(0xbd3af235); k.push(0x2ad7d2bb); k.push(0xeb86d391) + var x: Array[U32] iso = recover iso Array[U32](16) end + var i: USize = 0 + while i < 64 do + x.push(_to_u32_le(block, i)?) + i = i + 4 + end + + // Round 1 + a = _r1(a, b, c, d, x(0)?, s1(0)?, k(0)?) ; d = _r1(d, a, b, c, x(1)?, s1(1)?, k(1)?) + c = _r1(c, d, a, b, x(2)?, s1(2)?, k(2)?) ; b = _r1(b, c, d, a, x(3)?, s1(3)?, k(3)?) + a = _r1(a, b, c, d, x(4)?, s1(0)?, k(4)?) ; d = _r1(d, a, b, c, x(5)?, s1(1)?, k(5)?) + c = _r1(c, d, a, b, x(6)?, s1(2)?, k(6)?) ; b = _r1(b, c, d, a, x(7)?, s1(3)?, k(7)?) + a = _r1(a, b, c, d, x(8)?, s1(0)?, k(8)?) ; d = _r1(d, a, b, c, x(9)?, s1(1)?, k(9)?) + c = _r1(c, d, a, b, x(10)?, s1(2)?, k(10)?) ; b = _r1(b, c, d, a, x(11)?, s1(3)?, k(11)?) + a = _r1(a, b, c, d, x(12)?, s1(0)?, k(12)?) ; d = _r1(d, a, b, c, x(13)?, s1(1)?, k(13)?) + c = _r1(c, d, a, b, x(14)?, s1(2)?, k(14)?) ; b = _r1(b, c, d, a, x(15)?, s1(3)?, k(15)?) + + // Round 2 + a = _r2(a, b, c, d, x(1)?, s2(0)?, k(16)?) ; d = _r2(d, a, b, c, x(6)?, s2(1)?, k(17)?) + c = _r2(c, d, a, b, x(11)?, s2(2)?, k(18)?) ; b = _r2(b, c, d, a, x(0)?, s2(3)?, k(19)?) + a = _r2(a, b, c, d, x(5)?, s2(0)?, k(20)?) ; d = _r2(d, a, b, c, x(10)?, s2(1)?, k(21)?) + c = _r2(c, d, a, b, x(15)?, s2(2)?, k(22)?) ; b = _r2(b, c, d, a, x(4)?, s2(3)?, k(23)?) + a = _r2(a, b, c, d, x(9)?, s2(0)?, k(24)?) ; d = _r2(d, a, b, c, x(14)?, s2(1)?, k(25)?) + c = _r2(c, d, a, b, x(3)?, s2(2)?, k(26)?) ; b = _r2(b, c, d, a, x(8)?, s2(3)?, k(27)?) + a = _r2(a, b, c, d, x(13)?, s2(0)?, k(28)?) ; d = _r2(d, a, b, c, x(2)?, s2(1)?, k(29)?) + c = _r2(c, d, a, b, x(7)?, s2(2)?, k(30)?) ; b = _r2(b, c, d, a, x(12)?, s2(3)?, k(31)?) + + // Round 3 + a = _r3(a, b, c, d, x(5)?, s3(0)?, k(32)?) ; d = _r3(d, a, b, c, x(8)?, s3(1)?, k(33)?) + c = _r3(c, d, a, b, x(11)?, s3(2)?, k(34)?) ; b = _r3(b, c, d, a, x(14)?, s3(3)?, k(35)?) + a = _r3(a, b, c, d, x(1)?, s3(0)?, k(36)?) ; d = _r3(d, a, b, c, x(4)?, s3(1)?, k(37)?) + c = _r3(c, d, a, b, x(7)?, s3(2)?, k(38)?) ; b = _r3(b, c, d, a, x(10)?, s3(3)?, k(39)?) + a = _r3(a, b, c, d, x(13)?, s3(0)?, k(40)?) ; d = _r3(d, a, b, c, x(0)?, s3(1)?, k(41)?) + c = _r3(c, d, a, b, x(3)?, s3(2)?, k(42)?) ; b = _r3(b, c, d, a, x(6)?, s3(3)?, k(43)?) + a = _r3(a, b, c, d, x(9)?, s3(0)?, k(44)?) ; d = _r3(d, a, b, c, x(12)?, s3(1)?, k(45)?) + c = _r3(c, d, a, b, x(15)?, s3(2)?, k(46)?) ; b = _r3(b, c, d, a, x(2)?, s3(3)?, k(47)?) + + // Round 4 + a = _r4(a, b, c, d, x(0)?, s4(0)?, k(48)?) ; d = _r4(d, a, b, c, x(7)?, s4(1)?, k(49)?) + c = _r4(c, d, a, b, x(14)?, s4(2)?, k(50)?) ; b = _r4(b, c, d, a, x(5)?, s4(3)?, k(51)?) + a = _r4(a, b, c, d, x(12)?, s4(0)?, k(52)?) ; d = _r4(d, a, b, c, x(3)?, s4(1)?, k(53)?) + c = _r4(c, d, a, b, x(10)?, s4(2)?, k(54)?) ; b = _r4(b, c, d, a, x(1)?, s4(3)?, k(55)?) + a = _r4(a, b, c, d, x(8)?, s4(0)?, k(56)?) ; d = _r4(d, a, b, c, x(15)?, s4(1)?, k(57)?) + c = _r4(c, d, a, b, x(6)?, s4(2)?, k(58)?) ; b = _r4(b, c, d, a, x(13)?, s4(3)?, k(59)?) + a = _r4(a, b, c, d, x(4)?, s4(0)?, k(60)?) ; d = _r4(d, a, b, c, x(11)?, s4(1)?, k(61)?) + c = _r4(c, d, a, b, x(2)?, s4(2)?, k(62)?) ; b = _r4(b, c, d, a, x(9)?, s4(3)?, k(63)?) + + _a = (_a + a) and 0xffffffff + _b = (_b + b) and 0xffffffff + _c = (_c + c) and 0xffffffff + _d = (_d + d) and 0xffffffff + + fun _rotl(x: U32, s: U32): U32 => ((x << s) or (x >> (32 - s))) and 0xffffffff + + fun _f(x: U32, y: U32, z: U32): U32 => (x and y) or ((not x) and z) + fun _g(x: U32, y: U32, z: U32): U32 => (x and z) or (y and (not z)) + fun _h(x: U32, y: U32, z: U32): U32 => x xor y xor z + fun _ii(x: U32, y: U32, z: U32): U32 => y xor (x or (not z)) + + fun _r1(a: U32, b: U32, c: U32, d: U32, x: U32, s: U32, t: U32): U32 => + var r = a + _f(b, c, d) + x + t + r = _rotl(r, s) + (r + b) and 0xffffffff + + fun _r2(a: U32, b: U32, c: U32, d: U32, x: U32, s: U32, t: U32): U32 => + var r = a + _g(b, c, d) + x + t + r = _rotl(r, s) + (r + b) and 0xffffffff + + fun _r3(a: U32, b: U32, c: U32, d: U32, x: U32, s: U32, t: U32): U32 => + var r = a + _h(b, c, d) + x + t + r = _rotl(r, s) + (r + b) and 0xffffffff + + fun _r4(a: U32, b: U32, c: U32, d: U32, x: U32, s: U32, t: U32): U32 => + var r = a + _ii(b, c, d) + x + t + r = _rotl(r, s) + (r + b) and 0xffffffff diff --git a/bench/algorithm/merkletrees/1.pony b/bench/algorithm/merkletrees/1.pony new file mode 100644 index 000000000..ccf72abf7 --- /dev/null +++ b/bench/algorithm/merkletrees/1.pony @@ -0,0 +1,96 @@ +// based on 1.go implementation +primitive _NoneI64 + +class Node + var _hash: I64 = 0 + var _has_hash: Bool = false + var _left: (Node | None) + var _right: (Node | None) + + new create(depth: USize) => + if depth > 0 then + let d = depth - 1 + _left = Node(d) + _right = Node(d) + else + _left = None + _right = None + end + + fun ref cal_hash() => + if _has_hash then return end + match _left + | None => + // leaf + _hash = 1 + _has_hash = true + return + | let l: Node => l.cal_hash() + end + match _right + | let r: Node => r.cal_hash() + | None => None + end + let hl: I64 = match _left | let l': Node => l'.get_hash() | None => 0 end + let hr: I64 = match _right | let r': Node => r'.get_hash() | None => 0 end + _hash = hl + hr + _has_hash = true + + fun box get_hash(): I64 => + if _has_hash then _hash else 0 end + + fun box check(): Bool => + if not _has_hash then + false + elseif (_left is None) and (_right is None) then + true + else + var ok: Bool = true + match _left + | let l: Node box => + if not l.check() then ok = false end + | None => None + end + match _right + | let r: Node box => + if not r.check() then ok = false end + | None => None + end + ok + end + +actor Main + new create(env: Env) => + let min_depth: USize = 4 + let n: USize = try env.args(1)?.usize()? else 10 end + let max_depth = if (min_depth + 2) > n then min_depth + 2 else n end + + let stretch_depth = max_depth + 1 + let stretch_tree = recover iso Node(stretch_depth) end + stretch_tree.cal_hash() + env.out.print("stretch tree of depth " + stretch_depth.string() + + "\t root hash: " + stretch_tree.get_hash().string() + + " check: " + (if stretch_tree.check() then "true" else "false" end)) + + let long_lived_tree = Node(max_depth) + + var depth = min_depth + while depth <= max_depth do + let iterations: USize = USize(1).shl((max_depth - depth) + min_depth) + var sum: I64 = 0 + var i: USize = 0 + while i < iterations do + let t = recover iso Node(depth) end + t.cal_hash() + sum = sum + t.get_hash() + i = i + 1 + end + env.out.print(iterations.string() + "\t trees of depth " + depth.string() + + "\t root hash sum: " + sum.string()) + depth = depth + 2 + end + + long_lived_tree.cal_hash() + env.out.print("long lived tree of depth " + max_depth.string() + + "\t root hash: " + long_lived_tree.get_hash().string() + + " check: " + (if long_lived_tree.check() then "true" else "false" end)) diff --git a/bench/algorithm/nsieve/1.pony b/bench/algorithm/nsieve/1.pony new file mode 100644 index 000000000..aa6bf7768 --- /dev/null +++ b/bench/algorithm/nsieve/1.pony @@ -0,0 +1,83 @@ +// based on 1.go +use "collections" + +actor Main + new create(env: Env) => + let n: U32 = try env.args(1)?.u32()? else 4 end + var i: U32 = 0 + while i < 3 do + let base: U32 = 10000 + _nsieve(env, (base << (n - i)).u64()) + i = i + 1 + end + + fun _nsieve(env: Env, n: U64) => + if n < 2 then + var buf = recover iso Array[U8](32) end + buf = _append_bytes(consume buf, "Primes up to ") + buf = _append_u64_padded(consume buf, n) + buf.push(32) + buf = _append_u64_padded(consume buf, 0) + buf.push(10) + env.out.write(String.from_array(consume buf)) + return + end + let size = n.usize() + let flags = Array[Bool].init(false, size) + var count: U64 = 0 + var i: U64 = 2 + while i < n do + if (try not flags(i.usize())? else false end) then + count = count + 1 + var j: U64 = i + i + while j < n do + try flags.update(j.usize(), true)? end + j = j + i + end + end + i = i + 1 + end + var buf2 = recover iso Array[U8](32) end + buf2 = _append_bytes(consume buf2, "Primes up to ") + buf2 = _append_u64_padded(consume buf2, n) + buf2.push(32) + buf2 = _append_u64_padded(consume buf2, count) + buf2.push(10) + env.out.write(String.from_array(consume buf2)) + + fun _append_bytes(buf: Array[U8] iso, s: String): Array[U8] iso^ => + let a = s.array() + for b in a.values() do + buf.push(b) + end + consume buf + + fun _append_u64_padded(buf: Array[U8] iso, x: U64): Array[U8] iso^ => + // convert to decimal digits + var tmp = recover iso Array[U8](20) end + var v = x + if v == 0 then + tmp.push(48) + else + while v > 0 do + let d: U8 = (48 + (v % 10).u32()).u8() + tmp.push(d) + v = v / 10 + end + end + // left pad to width 8 + var digits: USize = tmp.size() + var pad: USize = if digits >= 8 then 0 else (8 - digits) end + var k: USize = 0 + while k < pad do + buf.push(32) + k = k + 1 + end + // write digits in reverse + while digits > 0 do + digits = digits - 1 + try + buf.push(tmp(digits)?) + end + end + consume buf diff --git a/bench/algorithm/regex-redux/1.pony b/bench/algorithm/regex-redux/1.pony new file mode 100644 index 000000000..b77c3cc38 --- /dev/null +++ b/bench/algorithm/regex-redux/1.pony @@ -0,0 +1,283 @@ +// Based on Python code +use "files" + +primitive StripFasta + fun apply(s: String val): String val ? => + let a = s.array() + let out = recover iso Array[U8] end + var i: USize = 0 + while i < s.size() do + let c = a(i)? + if c == U8('>') then + // skip until end of line (inclusive) + i = i + 1 + while (i < s.size()) and (a(i)? != U8('\n')) do i = i + 1 end + if i < s.size() then i = i + 1 end + elseif c == U8('\n') then + i = i + 1 + else + out.push(c) + i = i + 1 + end + end + recover val String.from_array(consume out) end// Very small matcher for the benchmark patterns: +// supports concatenation, character classes like [acg], and alternation with '|'. +primitive SimplePattern + fun count_in(s: String val, pat: String val): USize ? => + var total: USize = 0 + var i: USize = 0 + while i < s.size() do + let len = _match_len(s, i, pat)? + if len > 0 then + total = total + 1 + i = i + len + else + i = i + 1 + end + end + total + + fun _match_len(s: String val, off: USize, pat: String val): USize ? => + for alt in pat.split_by("|").values() do + let l = _match_seq_len(s, off, alt)? + if l > 0 then return l end + end + 0 + + fun _match_seq_len(s: String val, off: USize, p: String val): USize ? => + var i: USize = off + var j: USize = 0 + let sa = s.array() + let pa = p.array() + while j < p.size() do + let pc = pa(j)? + if pc == U8('[') then + j = j + 1 + var matched: Bool = false + while (j < p.size()) and (pa(j)? != U8(']')) do + if (i < s.size()) and (sa(i)? == pa(j)?) then matched = true end + j = j + 1 + end + if (j >= p.size()) or (pa(j)? != U8(']')) then return 0 end + if not matched then return 0 end + i = i + 1 + j = j + 1 + else + if (i >= s.size()) or (sa(i)? != pc) then return 0 end + i = i + 1 + j = j + 1 + end + end + i - off + +// Replace tHa[Nt] -> <4> +primitive Replace1 + fun apply(s: String val): String val ? => + let a = s.array() + let out = recover iso Array[U8] end + var i: USize = 0 + while i < s.size() do + if (i + 3) < s.size() then + if (a(i)? == U8('t')) and (a(i+1)? == U8('H')) and (a(i+2)? == U8('a')) then + let c3 = a(i+3)? + if (c3 == U8('N')) or (c3 == U8('t')) then + out.push(U8('<')); out.push(U8('4')); out.push(U8('>')) + i = i + 4 + continue + end + end + end + out.push(a(i)?) + i = i + 1 + end + recover val String.from_array(consume out) end + +// Replace aND|caN|Ha[DS]|WaS -> <3> +primitive Replace2 + fun apply(s: String val): String val ? => + let a = s.array() + let out = recover iso Array[U8] end + var i: USize = 0 + while i < s.size() do + var matched = false + // aND + if (i + 2) < s.size() then + if (a(i)? == U8('a')) and (a(i+1)? == U8('N')) and (a(i+2)? == U8('D')) then + out.push(U8('<')); out.push(U8('3')); out.push(U8('>')) + i = i + 3 + matched = true + end + end + // caN + if (not matched) and ((i + 2) < s.size()) then + if (a(i)? == U8('c')) and (a(i+1)? == U8('a')) and (a(i+2)? == U8('N')) then + out.push(U8('<')); out.push(U8('3')); out.push(U8('>')) + i = i + 3 + matched = true + end + end + // Ha[DS] + if (not matched) and ((i + 2) < s.size()) then + if (a(i)? == U8('H')) and (a(i+1)? == U8('a')) then + let c2 = a(i+2)? + if (c2 == U8('D')) or (c2 == U8('S')) then + out.push(U8('<')); out.push(U8('3')); out.push(U8('>')) + i = i + 3 + matched = true + end + end + end + // WaS + if (not matched) and ((i + 2) < s.size()) then + if (a(i)? == U8('W')) and (a(i+1)? == U8('a')) and (a(i+2)? == U8('S')) then + out.push(U8('<')); out.push(U8('3')); out.push(U8('>')) + i = i + 3 + matched = true + end + end + if not matched then + out.push(a(i)?) + i = i + 1 + end + end + recover val String.from_array(consume out) end + +// Replace a[NSt]|BY => <2> +primitive Replace3 + fun apply(s: String val): String val ? => + let a = s.array() + let out = recover iso Array[U8] end + var i: USize = 0 + while i < s.size() do + var matched = false + // a[NSt] + if (i + 1) < s.size() then + if a(i)? == U8('a') then + let c1 = a(i+1)? + if (c1 == U8('N')) or (c1 == U8('S')) or (c1 == U8('t')) then + out.push(U8('<')); out.push(U8('2')); out.push(U8('>')) + i = i + 2 + matched = true + end + end + end + // BY + if (not matched) and ((i + 1) < s.size()) then + if (a(i)? == U8('B')) and (a(i+1)? == U8('Y')) then + out.push(U8('<')); out.push(U8('2')); out.push(U8('>')) + i = i + 2 + matched = true + end + end + if not matched then + out.push(a(i)?) + i = i + 1 + end + end + recover val String.from_array(consume out) end + +// Replace <[^>]*> => | +primitive Replace4 + fun apply(s: String val): String val ? => + let a = s.array() + let out = recover iso Array[U8] end + var i: USize = 0 + while i < s.size() do + if a(i)? == U8('<') then + // replace until next '>' (if any) + out.push(U8('|')) + i = i + 1 + while (i < s.size()) and (a(i)? != U8('>')) do i = i + 1 end + if i < s.size() then i = i + 1 end + else + out.push(a(i)?) + i = i + 1 + end + end + recover val String.from_array(consume out) end + +// Replace \|[^|][^|]*\| => - +primitive Replace5 + fun apply(s: String val): String val ? => + let a = s.array() + let out = recover iso Array[U8] end + var i: USize = 0 + while i < s.size() do + if a(i)? == U8('|') then + // Look for pattern: || + if (i + 2) < s.size() then // Need at least |x| + let n1 = a(i+1)? + if n1 != U8('|') then // First char after | must not be | + // Find the closing | + var k = i + 2 + while (k < s.size()) and (a(k)? != U8('|')) do k = k + 1 end + if (k < s.size()) and (a(k)? == U8('|')) then + // Found complete pattern |...| with at least one non-pipe char + out.push(U8('-')) + i = k + 1 + continue + end + end + end + end + out.push(a(i)?) + i = i + 1 + end + recover val String.from_array(consume out) end + +actor Main + new create(env: Env) => + // Read input file arg or default to 25000_in as in bench. + let file_name = try env.args(1)? else "25000_in" end + + // Load file contents + let auth = env.root + let file_auth = FileAuth(auth) + let path = FilePath(file_auth, file_name) + let f = File(path) + if not f.valid() then + env.out.print("") + return + end + var buf = recover iso String end + while f.valid() do + let chunk = f.read_string(1 << 16) + if chunk.size() == 0 then break end + buf = (consume buf) + consume chunk + end + let input_str: String val = consume buf + let input_len = input_str.size() + + // Strip headers and newlines + let sequence: String val = try StripFasta(input_str)? else return end + let sequence_len = sequence.size() + + // Count variants + var variants = Array[String] + variants.push("agggtaaa|tttaccct") + variants.push("[cgt]gggtaaa|tttaccc[acg]") + variants.push("a[act]ggtaaa|tttacc[agt]t") + variants.push("ag[act]gtaaa|tttac[agt]ct") + variants.push("agg[act]taaa|ttta[agt]cct") + variants.push("aggg[acg]aaa|ttt[cgt]ccct") + variants.push("agggt[cgt]aa|tt[acg]accct") + variants.push("agggta[cgt]a|t[acg]taccct") + variants.push("agggtaa[cgt]|[acg]ttaccct") + + for pat in variants.values() do + let c = try SimplePattern.count_in(sequence, pat)? else 0 end + env.out.print(pat + " " + c.string()) + end + + // Sequential substitutions + var cur: String val = sequence + cur = try Replace1(cur)? else return end + cur = try Replace2(cur)? else return end + cur = try Replace3(cur)? else return end + cur = try Replace4(cur)? else return end + cur = try Replace5(cur)? else return end + + env.out.print("") + env.out.print(input_len.string()) + env.out.print(sequence_len.string()) + env.out.print(cur.size().string()) diff --git a/bench/algorithm/spectral-norm/1.pony b/bench/algorithm/spectral-norm/1.pony new file mode 100644 index 000000000..3299c6a38 --- /dev/null +++ b/bench/algorithm/spectral-norm/1.pony @@ -0,0 +1,93 @@ +// Single-threaded implementation of the spectral norm benchmark. +// Based on OCaml (2.ml) and Zig implementation. +// It timeouts on bigger data + +actor Main + new create(env: Env) => + let n: USize = try env.args(1)?.usize()? else 100 end + let iters: USize = 10 + let u = Array[F64].init(1.0, n) + let v = Array[F64].init(0.0, n) + let x = Array[F64].init(0.0, n) // reusable scratch + + var i: USize = 0 + while i < iters do + try _ata_times_u(v, u, x)? end + try _ata_times_u(u, v, x)? end + i = i + 1 + end + + var vBv: F64 = 0 + var vv: F64 = 0 + var k: USize = 0 + try + while k < n do + vBv = vBv + (u(k)? * v(k)?) + vv = vv + (v(k)? * v(k)?) + k = k + 1 + end + end + let res = (vBv / vv).sqrt() + // format to 9 decimals + let s = _fmt9(res) + env.out.print(consume s) + + fun _a(i: USize, j: USize): F64 => + let ij = i + j + 1.0 / (((ij * (ij + 1)) >> 1) + i + 1).f64() + + fun _a_times_u(u: Array[F64] box, v: Array[F64] ref) ? => + let n = u.size() + var i: USize = 0 + while i < n do + var sum: F64 = 0 + var j: USize = 0 + while j < n do + sum = sum + (_a(i, j) * u(j)?) + j = j + 1 + end + v.update(i, sum)? + i = i + 1 + end + + fun _at_times_u(u: Array[F64] box, v: Array[F64] ref) ? => + let n = u.size() + var i: USize = 0 + while i < n do + var sum: F64 = 0 + var j: USize = 0 + while j < n do + sum = sum + (_a(j, i) * u(j)?) + j = j + 1 + end + v.update(i, sum)? + i = i + 1 + end + + fun _ata_times_u(out: Array[F64] ref, inp: Array[F64] box, scratch: Array[F64] ref) ? => + // scratch and out are length n + _a_times_u(inp, scratch)? + _at_times_u(scratch, out)? + + fun _fmt9(x: F64): String iso^ => + var i: I64 = x.trunc().i64() + let frac: F64 = (x - i.f64()).abs() + var f: I64 = (frac * 1_000_000_000.0).round().i64() + if f == 1_000_000_000 then + f = 0 + if x >= 0 then + i = i + 1 + else + i = i - 1 + end + end + let s = recover iso String end + let istr = i.string() + s.append(consume istr) + s.push(46) + let fs = f.string() + let pad: USize = if fs.size() < 9 then 9 - fs.size() else 0 end + var k: USize = 0 + while k < pad do s.push(48); k = k + 1 end + s.append(consume fs) + consume s \ No newline at end of file diff --git a/bench/bench_pony.yaml b/bench/bench_pony.yaml index 21003ce40..d1809717d 100644 --- a/bench/bench_pony.yaml +++ b/bench/bench_pony.yaml @@ -12,19 +12,48 @@ problems: - name: lru source: - 1.pony + - name: merkletrees + source: + - 1.pony + - name: fasta + source: + - 1.pony + - name: nsieve + source: + - 1.pony + - name: spectral-norm + source: + - 1.pony + - name: mandelbrot + source: + - 1.pony + - name: fannkuch-redux + source: + - 1.pony + - name: coro-prime-sieve + source: + - 1.pony + - name: regex-redux + source: + - 1.pony + - name: knucleotide + source: + - 1.pony + compiler_version_command: ponyc --version -compiler_version_regex: -runtime_version_parameter: -runtime_version_regex: +compiler_version_regex: "" +runtime_version_parameter: "" +runtime_version_regex: "" source_rename_to: app.pony + environments: - os: linux compiler: ponyc version: latest - docker: ponylang/ponyc:release - # docker: ponylang/ponyc:latest + docker: "ponylang/ponyc:release" include: pony - build: corral update && corral run -- ponyc --cpu=broadwell -s -o=out -b=app --verbose=3 + env: + LDFLAGS: "-lcrypto" + build: "ponyc --cpu=ivybridge -s -o=out -b=app --verbose=3" out_dir: out run_cmd: app - allow_failure: true