diff --git a/README.md b/README.md index bca02e5..a90ad5f 100644 --- a/README.md +++ b/README.md @@ -102,3 +102,122 @@ some benchmarks as well as the test suite used to validate the behavior of the q 3. The deque in that module is a value type 4. I was bored during my programming class + +## Performance metrics +------------------------------------------ + +To outline just how much faster a deque is than a regular dynamic array when doing insertion and popping +near the ends, here are some performance metrics I took on my laptop with an 8-core Ryzen 7 4700U. + +Both collections have been filled with 500000 elements and the time taken for each operation has been +recorded. The average, minimum and maximum time taken are shown here, as well as the standard deviation +for each micro-benchmark. + + +## Appending at the end + +### LinkedDeque + +Time taken: `0.325591755` seconds. Results: + + - min: `0.0` + - max: `0.010444388` + - avg: `3.415999800000153e-07` + - stdev: `1.643969031599315e-05` + +### seq + +Time taken: `0.283606824` seconds. Results: + + - min: `2.499999999239222e-07` + - max: `0.001853333999999984` + - avg: `2.750403260000028e-07` + - stdev: `3.929418946682074e-06` + +## Popping the head + +### LinkedDeque + +Time taken: `0.008184640000000076` seconds. Results: + + - min: `2.499999999239222e-07` + - max: `1.186499999994428e-05` + - avg: `2.64712133333553e-07` + - stdev: `9.675646231323721e-08` + +### seq + +Time taken: `2.3356288` seconds. Results: + + - min: `0.0001166700000001519` + - max: `0.002396426000000229` + - avg: `0.0001549421693333322` + - stdev: `8.55174518472766e-05` + +## Adding at the left side + +### LinkedDeque + +Time taken: `0.3028111230000001` seconds. Results: + + - min: `2.699999996913505e-07` + - max: `0.01986077199999992` + - avg: `3.19837340000251e-07` + - stdev: `2.808711098829249e-05` + +### seq + +Time taken: `23.515489255` seconds. Results: + + - min: `2.700000001354397e-07` + - max: `0.002371210999999818` + - avg: `4.657242209800181e-05` + - stdev: `3.14827288610087e-05` + +## Random access (10000 times) + +### LinkedDeque + +Time taken: `8.208724628999995` seconds. Results: + + - min: `9.920000003660334e-07` + - max: `0.002548661999998814` + - avg: `0.0008192961785821358` + - stdev: `0.0004795569727666707` + +### seq + +Time taken: `0.00333773400000581` seconds. Results: + + - min: `1.599999990276046e-07` + - max: `9.759999997527302e-06` + - avg: `1.632506749111258e-07` + - stdev: `9.612951140246536e-08` + +## Popping the tail + +### LinkedDeque + +Time taken: `0.004907793000000993` seconds. Results: + - min: `1.499999982002009e-07` + - max: '8.515999994074264e-06` + - avg: `1.609196000041869e-07` + - stdev: `9.069790474947947e-08` + +### seq + +Time taken: `0.004914629999994702` seconds. Results: + - min: `1.499999982002009e-07` + - max: `6.697999999971671e-06` + - avg: `1.62365333385613e-07` + - stdev: `5.410771724203826e-08` + + +## TODOs + +There are many possible implementations for double-ended queues: the current one is based on the usual textbook implementation of +a doubly linked list, but that isn't the best choice for cache locality and has significant memory overhead for each link in +the chain; Other possibilities involve using a list of subarrays to alleviate both of these issues, while some other options +make use of ring buffers or specialized dynamic arrays growing from the center that can be used to allow even fast random accessing +and can be made really efficient using lazy evaluation. The goal of this module is to implement most (possibly all) of these approaches, +because I find them fascinating. diff --git a/src/nimdeque.nim b/src/nimdeque.nim index 1a40577..768d054 100644 --- a/src/nimdeque.nim +++ b/src/nimdeque.nim @@ -34,4 +34,5 @@ export insert export extend export reversedPairs export clear -export clearPop \ No newline at end of file +export clearPop +export extendLeft \ No newline at end of file diff --git a/tests/linked.nim b/tests/linked.nim index bafe4f9..f4259a3 100644 --- a/tests/linked.nim +++ b/tests/linked.nim @@ -20,7 +20,7 @@ import ../src/nimdeque when isMainModule: const size = 1500 - const benchSize = 1500000 + const benchSize = 500000 echo &"Running tests with queue of size {size}" var deque = newLinkedDeque[int]() @@ -129,6 +129,12 @@ when isMainModule: doAssert deque[i] == s[i] doAssert old + len(s) == deque.len() + echo "\t- Testing extendLeft()" + old = deque.len() + deque.extendLeft(s) + for i in countup(0, 5): + doAssert deque[i] == s[5 - i] + echo "\t- Testing clear()" deque.clear() doAssert deque.len() == 0