From 7608b6f0040ada497f15b70b8a9e8b8aa9e1019d Mon Sep 17 00:00:00 2001 From: Reid 'arrdem' McKenzie Date: Thu, 19 Aug 2021 23:45:15 -0600 Subject: [PATCH] Document benchmark results --- projects/jobq/README.md | 56 +++++++++++++++++++++++ projects/jobq/benchmark.py | 13 ++++++ projects/jobq/src/python/jobq/__init__.py | 2 +- 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/projects/jobq/README.md b/projects/jobq/README.md index d9b5a96..914faf5 100644 --- a/projects/jobq/README.md +++ b/projects/jobq/README.md @@ -1,3 +1,59 @@ # Jobq Abusing sqlite3 as a job queue. + +## Benchmarks + +Benchmarks are extremely steady. +Flushing a sqlite file to disk seems to be the limiting factor of I/O, and pipelining multiple message writes is undoubtably the way to go. +However the purpose of the API is to use the sqlite file as the shared checkpoint between potentially many processes, so 'large' transactions are an antipattern. + +Tests suggest that this library is rock steady at 100 writes per sec. and 100 polls per sec. and completely bounded by sqlite controlled I/O as evidenced by using `":memory:"` which doesn't have to `fsync()`. + +``` shell +$ bazel run :benchmark + +... + +Target //projects/jobq:benchmark up-to-date: + bazel-bin/projects/jobq/benchmark + +... + +Ran 'insert' 10000 times, total time 101.810816516 (s) + mean: 0.010148992843 (s) + median: 0.009474293 (s) + stddev: 0.006727934042954838 (s) + test overhead: 3.20888086e-05 (s) + +Ran 'poll' 10000 times, total time 100.482262487 (s) + mean: 0.0100152467857 (s) + median: 0.0095528585 (s) + stddev: 0.00821730176268304 (s) + test overhead: 3.2979463000000004e-05 (s) + +Ran 'append_event' 10000 times, total time 105.015296419 (s) + mean: 0.0104681294652 (s) + median: 0.009592544 (s) + stddev: 0.007321370576225584 (s) + test overhead: 3.34001767e-05 (s) + +Testing with :memory: +Ran 'insert' 10000 times, total time 0.37031511 (s) + mean: 3.3595880100000005e-05 (s) + median: 2.96015e-05 (s) + stddev: 1.045088890675899e-05 (s) + test overhead: 3.4356309e-06 (s) + +Ran 'poll' 10000 times, total time 1.17148314 (s) + mean: 0.0001128911222 (s) + median: 9.7398e-05 (s) + stddev: 3.213524197973896e-05 (s) + test overhead: 4.2571917999999996e-06 (s) + +Ran 'append_event' 10000 times, total time 0.415490332 (s) + mean: 3.78861989e-05 (s) + median: 3.3019e-05 (s) + stddev: 1.1752889674795285e-05 (s) + test overhead: 3.6628343e-06 (s) +``` diff --git a/projects/jobq/benchmark.py b/projects/jobq/benchmark.py index 582ae18..9d4b854 100644 --- a/projects/jobq/benchmark.py +++ b/projects/jobq/benchmark.py @@ -10,6 +10,7 @@ from random import randint, choice import string from statistics import mean, median, stdev import tempfile +import logging from jobq import JobQueue @@ -75,7 +76,17 @@ def test_poll(q, reps): bench(poll, reps) +def test_append(q, reps): + def append_event(): + q.append_event(randint(1, reps), {"foo": "bar"}) + + bench(append_event, reps) + + if __name__ == "__main__": + # No logs + logging.getLogger().setLevel(logging.WARN) + # Test params reps = 10000 path = "/tmp/jobq-bench.sqlite3" @@ -89,8 +100,10 @@ if __name__ == "__main__": q = JobQueue(path) test_insert(q, reps) test_poll(q, reps) + test_append(q, reps) print(f"Testing with :memory:") q = JobQueue(":memory:") test_insert(q, reps) test_poll(q, reps) + test_append(q, reps) diff --git a/projects/jobq/src/python/jobq/__init__.py b/projects/jobq/src/python/jobq/__init__.py index e0ac59a..bd6a963 100644 --- a/projects/jobq/src/python/jobq/__init__.py +++ b/projects/jobq/src/python/jobq/__init__.py @@ -116,7 +116,7 @@ WHERE ; """ -_POLL_SQL = """\ +_POLL_SQL = f"""\ UPDATE `job` SET `events` = json_insert(events, '$[#]', json_array('job_state_advanced', json_object('old', json(state), 'new', json(:state), 'timestamp', CURRENT_TIMESTAMP)))