From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from [87.239.111.99] (localhost [127.0.0.1]) by dev.tarantool.org (Postfix) with ESMTP id 12C6D16599E9; Tue, 23 Dec 2025 13:38:28 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 12C6D16599E9 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=tarantool.org; s=dev; t=1766486308; bh=j5yfBLW0KO9+0858T2KXzmqYhKYbTb0vAeXGnLlmhSc=; h=Date:To:Cc:References:In-Reply-To:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=oPdxwo3mBuLMw5Vx1N7+8j1ae7QiRV7ExPS2TrmzvWpiP/S+l0xB5099L+00mbwTg oxfM7ATalcAz//d2pHzxBYx8ia2S7xJx9X+H35P5Q5/J23IvX25pbS5X88ZN6eizQr r95w36uYtAE444xgxlDe32wcJwXj8G6pQBaCsWOc= Received: from send266.i.mail.ru (send266.i.mail.ru [95.163.59.105]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 4A81516599E5 for ; Tue, 23 Dec 2025 13:37:59 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 dev.tarantool.org 4A81516599E5 Received: by exim-smtp-7b4fb89df9-f7qdb with esmtpa (envelope-from ) id 1vXzmA-0000000046l-1NkE; Tue, 23 Dec 2025 13:37:58 +0300 Content-Type: multipart/alternative; boundary="------------3y4ZOl7jMY3w5lZ32SGW0Y01" Message-ID: Date: Tue, 23 Dec 2025 13:37:58 +0300 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird To: Sergey Kaplun Cc: tarantool-patches@dev.tarantool.org References: Content-Language: en-US In-Reply-To: X-Mailru-Src: smtp X-4EC0790: 10 X-7564579A: 78E4E2B564C1792B X-77F55803: 4F1203BC0FB41BD9169BA2A4A1D10D0062704CAB6E7D333A6DF0C3F071CADCBE182A05F5380850400C609AC15F25D1443DE06ABAFEAF67051028251B807E0DFA6DBB412B9F8581CAE32BF596A4C5394D X-7FA49CB5: FF5795518A3D127A4AD6D5ED66289B5278DA827A17800CE746D93DAA4671895CEA1F7E6F0F101C67BD4B6F7A4D31EC0BCC500DACC3FED6E28638F802B75D45FF8AA50765F7900637AC83A81C8FD4AD23D82A6BABE6F325AC2E85FA5F3EDFCBAA7353EFBB55337566EF210049E62C3CC5CF02796FC070CC20D146867C1E5D46D7746A3EFB6D0B2BC5389733CBF5DBD5E913377AFFFEAFD269176DF2183F8FC7C07E7E81EEA8A9722B8941B15DA834481FCF19DD082D7633A0EF3E4896CB9E6436389733CBF5DBD5E9D5E8D9A59859A8B6957A4DEDD2346B42CC7F00164DA146DA6F5DAA56C3B73B237318B6A418E8EAB8D32BA5DBAC0009BE9E8FC8737B5C22492377BE1BE24488CF76E601842F6C81A12EF20D2F80756B5FB606B96278B59C4276E601842F6C81A127C277FBC8AE2E8B12FAD46FC5E3949A3AA81AA40904B5D99C9F4D5AE37F343AD1F44FA8B9022EA23BBE47FD9DD3FB595F5C1EE8F4F765FC72CEEB2601E22B093A03B725D353964B0B7D0EA88DDEDAC722CA9DD8327EE493B89ED3C7A62817819EF166FBCB559E95C4224003CC83647689D4C264860C145E X-C1DE0DAB: 0D63561A33F958A5374BE022DAB801515002B1117B3ED696E908FBF87E07BF46E772F934B9BCD185823CB91A9FED034534781492E4B8EEAD3C056C6FCE5AFF8EBDAD6C7F3747799A X-C8649E89: 1C3962B70DF3F0AD73CAD6646DEDE191716CD42B3DD1D34CAB70F9BE574AE9C625B6776AC983F447FC0B9F89525902EE6F57B2FD27647F25E66C117BDB76D659A88CB8179E2AE5F54604445CE79B63E25E57B847A24D938F1B5AFA4C45481D224D82D79918DEF145B8341EE9D5BE9A0AC5164B7A816E001105CB097BA505BE428C88101B80AD58C48CD93680B12512CF4C41F94D744909CE2512F26BEC029E55448553D2254B8D95CD72808BE417F3B9E0E7457915DAA85F X-D57D3AED: 3ZO7eAau8CL7WIMRKs4sN3D3tLDjz0dLbV79QFUyzQ2Ujvy7cMT6pYYqY16iZVKkSc3dCLJ7zSJH7+u4VD18S7Vl4ZUrpaVfd2+vE6kuoey4m4VkSEu53w8ahmwBjZKM/YPHZyZHvz5uv+WouB9+ObcCpyrx6l7KImUglyhkEat/+ysWwi0gdhEs0JGjl6ggRWTy1haxBpVdbIX1nthFXMZebaIdHP2ghjoIc/363UZI6Kf1ptIMVdtTL5f5BIXb1Q3+Ck+4Dpc= X-Mailru-Sender: 811C44EDE0507D1FFB106D83BFFB684FBE88B6E9B9051C6672C88FB39F7EDAED1B269D4DDBF8BC6DE59C81BF1DA436C6645D15D82EE4B272BD6E4642A116CA93524AA66B5ACBE6721EF430B9A63E2A504198E0F3ECE9B5443453F38A29522196 X-Mras: Ok Subject: Re: [Tarantool-patches] [PATCH v1 luajit 10/41] perf: adjust fasta in LuaJIT-benches X-BeenThere: tarantool-patches@dev.tarantool.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Sergey Bronnikov via Tarantool-patches Reply-To: Sergey Bronnikov Errors-To: tarantool-patches-bounces@dev.tarantool.org Sender: "Tarantool-patches" This is a multi-part message in MIME format. --------------3y4ZOl7jMY3w5lZ32SGW0Y01 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Hello, thanks for the patch! See my comments. Sergey On 10/24/25 13:50, Sergey Kaplun wrote: > This patch adjusts the aforementioned test to use the benchmark > framework introduced before. The default arguments are adjusted > according to the file. The arguments to the script still > can be provided in the command line run. > > Since the result output (with the different input parameter value) > produced by this benchmark is used in other benchmarks > ( and ), the original script is used as a > library (inside the subdirectory) with the updated default input > value and returns the number of items processed. The output for the > benchmark itself is suppressed and not checked since it is irrational to > store in the repository such huge files for testing. > --- > perf/LuaJIT-benches/fasta.lua | 120 +++++++---------------------- > perf/LuaJIT-benches/libs/fasta.lua | 98 +++++++++++++++++++++++ > 2 files changed, 125 insertions(+), 93 deletions(-) > create mode 100644 perf/LuaJIT-benches/libs/fasta.lua > > diff --git a/perf/LuaJIT-benches/fasta.lua b/perf/LuaJIT-benches/fasta.lua > index 7ce60804..d0dc005d 100644 > --- a/perf/LuaJIT-benches/fasta.lua > +++ b/perf/LuaJIT-benches/fasta.lua > @@ -1,95 +1,29 @@ > - > -local Last = 42 > -local function random(max) > - local y = (Last * 3877 + 29573) % 139968 > - Last = y > - return (max * y) / 139968 > -end > - > -local function make_repeat_fasta(id, desc, s, n) > - local write, sub = io.write, string.sub > - write(">", id, " ", desc, "\n") > - local p, sn, s2 = 1, #s, s..s > - for i=60,n,60 do > - write(sub(s2, p, p + 59), "\n") > - p = p + 60; if p > sn then p = p - sn end > - end > - local tail = n % 60 > - if tail > 0 then write(sub(s2, p, p + tail-1), "\n") end > -end > - > -local function make_random_fasta(id, desc, bs, n) > - io.write(">", id, " ", desc, "\n") > - loadstring([=[ > - local write, char, unpack, n, random = io.write, string.char, unpack, ... > - local buf, p = {}, 1 > - for i=60,n,60 do > - for j=p,p+59 do ]=]..bs..[=[ end > - buf[p+60] = 10; p = p + 61 > - if p >= 2048 then write(char(unpack(buf, 1, p-1))); p = 1 end > - end > - local tail = n % 60 > - if tail > 0 then > - for j=p,p+tail-1 do ]=]..bs..[=[ end > - p = p + tail; buf[p] = 10; p = p + 1 > - end > - write(char(unpack(buf, 1, p-1))) > - ]=], desc)(n, random) > -end > - > -local function bisect(c, p, lo, hi) > - local n = hi - lo > - if n == 0 then return "buf[j] = "..c[hi].."\n" end > - local mid = math.floor(n / 2) > - return "if r < "..p[lo+mid].." then\n"..bisect(c, p, lo, lo+mid).. > - "else\n"..bisect(c, p, lo+mid+1, hi).."end\n" > -end > - > -local function make_bisect(tab) > - local c, p, sum = {}, {}, 0 > - for i,row in ipairs(tab) do > - c[i] = string.byte(row[1]) > - sum = sum + row[2] > - p[i] = sum > - end > - return "local r = random(1)\n"..bisect(c, p, 1, #tab) > -end > - > -local alu = > - "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG".. > - "GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA".. > - "CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT".. > - "ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA".. > - "GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG".. > - "AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC".. > - "AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA" > - > -local iub = make_bisect{ > - { "a", 0.27 }, > - { "c", 0.12 }, > - { "g", 0.12 }, > - { "t", 0.27 }, > - { "B", 0.02 }, > - { "D", 0.02 }, > - { "H", 0.02 }, > - { "K", 0.02 }, > - { "M", 0.02 }, > - { "N", 0.02 }, > - { "R", 0.02 }, > - { "S", 0.02 }, > - { "V", 0.02 }, > - { "W", 0.02 }, > - { "Y", 0.02 }, > -} > - > -local homosapiens = make_bisect{ > - { "a", 0.3029549426680 }, > - { "c", 0.1979883004921 }, > - { "g", 0.1975473066391 }, > - { "t", 0.3015094502008 }, > +local bench = require("bench").new(arg) > + > +local stdout = io.output() > + > +local benchmark > +benchmark = { > + name = "fasta", > + -- XXX: The result file may take up to 278 Mb for the default > + -- settings. To check the correctness of the script, run it as > + -- is from the console. > + skip_check = true, > + setup = function() > + io.output("/dev/null") > + end, > + payload = function() > + -- Run the benchmark as is from the file. > + local items = require("fasta") > + -- Remove it from the cache to be sure the benchmark will run > + -- at the next iteration. > + package.loaded["fasta"] = nil > + benchmark.items = items > + end, > + teardown = function() > + io.output(stdout) > + end, > } > > -local N = tonumber(arg and arg[1]) or 1000 > -make_repeat_fasta('ONE', 'Homo sapiens alu', alu, N*2) > -make_random_fasta('TWO', 'IUB ambiguity codes', iub, N*3) > -make_random_fasta('THREE', 'Homo sapiens frequency', homosapiens, N*5) > +bench:add(benchmark) > +bench:run_and_report() > diff --git a/perf/LuaJIT-benches/libs/fasta.lua b/perf/LuaJIT-benches/libs/fasta.lua > new file mode 100644 > index 00000000..9c72c244 > --- /dev/null > +++ b/perf/LuaJIT-benches/libs/fasta.lua > @@ -0,0 +1,98 @@ > + > +local Last = 42 > +local function random(max) > + local y = (Last * 3877 + 29573) % 139968 > + Last = y > + return (max * y) / 139968 > +end > + > +local function make_repeat_fasta(id, desc, s, n) > + local write, sub = io.write, string.sub > + write(">", id, " ", desc, "\n") > + local p, sn, s2 = 1, #s, s..s > + for i=60,n,60 do more whitespaces please > + write(sub(s2, p, p + 59), "\n") > + p = p + 60; if p > sn then p = p - sn end > + end > + local tail = n % 60 > + if tail > 0 then write(sub(s2, p, p + tail-1), "\n") end more whitespaces please. Here and below. > +end > + > +local function make_random_fasta(id, desc, bs, n) > + io.write(">", id, " ", desc, "\n") > + loadstring([=[ > + local write, char, unpack, n, random = io.write, string.char, unpack, ... > + local buf, p = {}, 1 > + for i=60,n,60 do > + for j=p,p+59 do ]=]..bs..[=[ end > + buf[p+60] = 10; p = p + 61 > + if p >= 2048 then write(char(unpack(buf, 1, p-1))); p = 1 end > + end > + local tail = n % 60 > + if tail > 0 then > + for j=p,p+tail-1 do ]=]..bs..[=[ end > + p = p + tail; buf[p] = 10; p = p + 1 > + end > + write(char(unpack(buf, 1, p-1))) > + ]=], desc)(n, random) > +end > + > +local function bisect(c, p, lo, hi) > + local n = hi - lo > + if n == 0 then return "buf[j] = "..c[hi].."\n" end > + local mid = math.floor(n / 2) > + return "if r < "..p[lo+mid].." then\n"..bisect(c, p, lo, lo+mid).. > + "else\n"..bisect(c, p, lo+mid+1, hi).."end\n" > +end > + > +local function make_bisect(tab) > + local c, p, sum = {}, {}, 0 > + for i,row in ipairs(tab) do > + c[i] = string.byte(row[1]) > + sum = sum + row[2] > + p[i] = sum > + end > + return "local r = random(1)\n"..bisect(c, p, 1, #tab) > +end > + > +local alu = > + "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG".. > + "GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA".. > + "CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT".. > + "ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA".. > + "GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG".. > + "AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC".. > + "AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA" > + > +local iub = make_bisect{ > + { "a", 0.27 }, > + { "c", 0.12 }, > + { "g", 0.12 }, > + { "t", 0.27 }, > + { "B", 0.02 }, > + { "D", 0.02 }, > + { "H", 0.02 }, > + { "K", 0.02 }, > + { "M", 0.02 }, > + { "N", 0.02 }, > + { "R", 0.02 }, > + { "S", 0.02 }, > + { "V", 0.02 }, > + { "W", 0.02 }, > + { "Y", 0.02 }, > +} > + > +local homosapiens = make_bisect{ > + { "a", 0.3029549426680 }, > + { "c", 0.1979883004921 }, > + { "g", 0.1975473066391 }, > + { "t", 0.3015094502008 }, > +} > + > +local N = tonumber(arg and arg[1]) or 25e6 > + > +make_repeat_fasta('ONE', 'Homo sapiens alu', alu, N*2) > +make_random_fasta('TWO', 'IUB ambiguity codes', iub, N*3) > +make_random_fasta('THREE', 'Homo sapiens frequency', homosapiens, N*5) > + > +return N*2 + N*3 + N*5 --------------3y4ZOl7jMY3w5lZ32SGW0Y01 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 7bit

Hello,

thanks for the patch! See my comments.

Sergey

On 10/24/25 13:50, Sergey Kaplun wrote:
This patch adjusts the aforementioned test to use the benchmark
framework introduced before. The default arguments are adjusted
according to the <PARAM_x86.txt> file. The arguments to the script still
can be provided in the command line run.

Since the result output (with the different input parameter value)
produced by this benchmark is used in other benchmarks
(<k-nucleotide.lua> and <revcomp.lua>), the original script is used as a
library (inside the <libs/> subdirectory) with the updated default input
value and returns the number of items processed. The output for the
benchmark itself is suppressed and not checked since it is irrational to
store in the repository such huge files for testing.
---
 perf/LuaJIT-benches/fasta.lua      | 120 +++++++----------------------
 perf/LuaJIT-benches/libs/fasta.lua |  98 +++++++++++++++++++++++
 2 files changed, 125 insertions(+), 93 deletions(-)
 create mode 100644 perf/LuaJIT-benches/libs/fasta.lua

diff --git a/perf/LuaJIT-benches/fasta.lua b/perf/LuaJIT-benches/fasta.lua
index 7ce60804..d0dc005d 100644
--- a/perf/LuaJIT-benches/fasta.lua
+++ b/perf/LuaJIT-benches/fasta.lua
@@ -1,95 +1,29 @@
-
-local Last = 42
-local function random(max)
-  local y = (Last * 3877 + 29573) % 139968
-  Last = y
-  return (max * y) / 139968
-end
-
-local function make_repeat_fasta(id, desc, s, n)
-  local write, sub = io.write, string.sub
-  write(">", id, " ", desc, "\n")
-  local p, sn, s2 = 1, #s, s..s
-  for i=60,n,60 do
-    write(sub(s2, p, p + 59), "\n")
-    p = p + 60; if p > sn then p = p - sn end
-  end
-  local tail = n % 60
-  if tail > 0 then write(sub(s2, p, p + tail-1), "\n") end
-end
-
-local function make_random_fasta(id, desc, bs, n)
-  io.write(">", id, " ", desc, "\n")
-  loadstring([=[
-    local write, char, unpack, n, random = io.write, string.char, unpack, ...
-    local buf, p = {}, 1
-    for i=60,n,60 do
-      for j=p,p+59 do ]=]..bs..[=[ end
-      buf[p+60] = 10; p = p + 61
-      if p >= 2048 then write(char(unpack(buf, 1, p-1))); p = 1 end
-    end
-    local tail = n % 60
-    if tail > 0 then
-      for j=p,p+tail-1 do ]=]..bs..[=[ end
-      p = p + tail; buf[p] = 10; p = p + 1
-    end
-    write(char(unpack(buf, 1, p-1)))
-  ]=], desc)(n, random)
-end
-
-local function bisect(c, p, lo, hi)
-  local n = hi - lo
-  if n == 0 then return "buf[j] = "..c[hi].."\n" end
-  local mid = math.floor(n / 2)
-  return "if r < "..p[lo+mid].." then\n"..bisect(c, p, lo, lo+mid)..
-         "else\n"..bisect(c, p, lo+mid+1, hi).."end\n"
-end
-
-local function make_bisect(tab)
-  local c, p, sum = {}, {}, 0
-  for i,row in ipairs(tab) do
-    c[i] = string.byte(row[1])
-    sum = sum + row[2]
-    p[i] = sum
-  end
-  return "local r = random(1)\n"..bisect(c, p, 1, #tab)
-end
-
-local alu =
-  "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG"..
-  "GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA"..
-  "CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT"..
-  "ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA"..
-  "GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG"..
-  "AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC"..
-  "AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA"
-
-local iub = make_bisect{
-  { "a", 0.27 },
-  { "c", 0.12 },
-  { "g", 0.12 },
-  { "t", 0.27 },
-  { "B", 0.02 },
-  { "D", 0.02 },
-  { "H", 0.02 },
-  { "K", 0.02 },
-  { "M", 0.02 },
-  { "N", 0.02 },
-  { "R", 0.02 },
-  { "S", 0.02 },
-  { "V", 0.02 },
-  { "W", 0.02 },
-  { "Y", 0.02 },
-}
-
-local homosapiens = make_bisect{
-  { "a", 0.3029549426680 },
-  { "c", 0.1979883004921 },
-  { "g", 0.1975473066391 },
-  { "t", 0.3015094502008 },
+local bench = require("bench").new(arg)
+
+local stdout = io.output()
+
+local benchmark
+benchmark = {
+  name = "fasta",
+  -- XXX: The result file may take up to 278 Mb for the default
+  -- settings. To check the correctness of the script, run it as
+  -- is from the console.
+  skip_check = true,
+  setup = function()
+    io.output("/dev/null")
+  end,
+  payload = function()
+    -- Run the benchmark as is from the file.
+    local items = require("fasta")
+    -- Remove it from the cache to be sure the benchmark will run
+    -- at the next iteration.
+    package.loaded["fasta"] = nil
+    benchmark.items = items
+  end,
+  teardown = function()
+    io.output(stdout)
+  end,
 }
 
-local N = tonumber(arg and arg[1]) or 1000
-make_repeat_fasta('ONE', 'Homo sapiens alu', alu, N*2)
-make_random_fasta('TWO', 'IUB ambiguity codes', iub, N*3)
-make_random_fasta('THREE', 'Homo sapiens frequency', homosapiens, N*5)
+bench:add(benchmark)
+bench:run_and_report()
diff --git a/perf/LuaJIT-benches/libs/fasta.lua b/perf/LuaJIT-benches/libs/fasta.lua
new file mode 100644
index 00000000..9c72c244
--- /dev/null
+++ b/perf/LuaJIT-benches/libs/fasta.lua
@@ -0,0 +1,98 @@
+
+local Last = 42
+local function random(max)
+  local y = (Last * 3877 + 29573) % 139968
+  Last = y
+  return (max * y) / 139968
+end
+
+local function make_repeat_fasta(id, desc, s, n)
+  local write, sub = io.write, string.sub
+  write(">", id, " ", desc, "\n")
+  local p, sn, s2 = 1, #s, s..s
+  for i=60,n,60 do
more whitespaces please
+    write(sub(s2, p, p + 59), "\n")
+    p = p + 60; if p > sn then p = p - sn end
+  end
+  local tail = n % 60
+  if tail > 0 then write(sub(s2, p, p + tail-1), "\n") end
more whitespaces please. Here and below.
+end
+
+local function make_random_fasta(id, desc, bs, n)
+  io.write(">", id, " ", desc, "\n")
+  loadstring([=[
+    local write, char, unpack, n, random = io.write, string.char, unpack, ...
+    local buf, p = {}, 1
+    for i=60,n,60 do
+      for j=p,p+59 do ]=]..bs..[=[ end
+      buf[p+60] = 10; p = p + 61
+      if p >= 2048 then write(char(unpack(buf, 1, p-1))); p = 1 end
+    end
+    local tail = n % 60
+    if tail > 0 then
+      for j=p,p+tail-1 do ]=]..bs..[=[ end
+      p = p + tail; buf[p] = 10; p = p + 1
+    end
+    write(char(unpack(buf, 1, p-1)))
+  ]=], desc)(n, random)
+end
+
+local function bisect(c, p, lo, hi)
+  local n = hi - lo
+  if n == 0 then return "buf[j] = "..c[hi].."\n" end
+  local mid = math.floor(n / 2)
+  return "if r < "..p[lo+mid].." then\n"..bisect(c, p, lo, lo+mid)..
+         "else\n"..bisect(c, p, lo+mid+1, hi).."end\n"
+end
+
+local function make_bisect(tab)
+  local c, p, sum = {}, {}, 0
+  for i,row in ipairs(tab) do
+    c[i] = string.byte(row[1])
+    sum = sum + row[2]
+    p[i] = sum
+  end
+  return "local r = random(1)\n"..bisect(c, p, 1, #tab)
+end
+
+local alu =
+  "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG"..
+  "GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA"..
+  "CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT"..
+  "ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA"..
+  "GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG"..
+  "AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC"..
+  "AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA"
+
+local iub = make_bisect{
+  { "a", 0.27 },
+  { "c", 0.12 },
+  { "g", 0.12 },
+  { "t", 0.27 },
+  { "B", 0.02 },
+  { "D", 0.02 },
+  { "H", 0.02 },
+  { "K", 0.02 },
+  { "M", 0.02 },
+  { "N", 0.02 },
+  { "R", 0.02 },
+  { "S", 0.02 },
+  { "V", 0.02 },
+  { "W", 0.02 },
+  { "Y", 0.02 },
+}
+
+local homosapiens = make_bisect{
+  { "a", 0.3029549426680 },
+  { "c", 0.1979883004921 },
+  { "g", 0.1975473066391 },
+  { "t", 0.3015094502008 },
+}
+
+local N = tonumber(arg and arg[1]) or 25e6
+
+make_repeat_fasta('ONE', 'Homo sapiens alu', alu, N*2)
+make_random_fasta('TWO', 'IUB ambiguity codes', iub, N*3)
+make_random_fasta('THREE', 'Homo sapiens frequency', homosapiens, N*5)
+
+return N*2 + N*3 + N*5
--------------3y4ZOl7jMY3w5lZ32SGW0Y01--