From a3fc124ada3dfd1b8f8803808e012c0aa48cb66e Mon Sep 17 00:00:00 2001 From: rina Date: Fri, 21 Aug 2026 14:05:52 +1000 Subject: [PATCH 1/2] bench: add `CCFQueue.append`, including right-associative version Throughputs for "CCList.append", "List.append", "CCFun_vec.append", "Pvec.append", "Sek.concat", "CCFQueue.append", "CCFQueue.append (r-assoc)" each running 3 times for at least 2 CPU seconds: CCList.append: 2.02 WALL ( 2.01 usr + 0.00 sys = 2.02 CPU, minor = 9993.60 MB, major = 0 B) @ 6881.88/s (n=13880) 2.01 WALL ( 2.01 usr + 0.00 sys = 2.01 CPU, minor = 9993.60 MB, major = 0 B) @ 6897.54/s (n=13880) 2.09 WALL ( 2.08 usr + 0.00 sys = 2.09 CPU, minor = 9993.60 MB, major = 0 B) @ 6650.14/s (n=13880) List.append: 2.20 WALL ( 2.20 usr + 0.00 sys = 2.20 CPU, minor = 11758.32 MB, major = 0 B) @ 7418.49/s (n=16331) 2.23 WALL ( 2.22 usr + 0.00 sys = 2.23 CPU, minor = 11758.32 MB, major = 0 B) @ 7336.55/s (n=16331) 2.20 WALL ( 2.20 usr + 0.00 sys = 2.20 CPU, minor = 11758.32 MB, major = 0 B) @ 7430.92/s (n=16331) CCFun_vec.append: 2.12 WALL ( 2.12 usr + 0.00 sys = 2.12 CPU, minor = 28591.61 MB, major = 0 B) @ 871.78/s (n=1851) 2.13 WALL ( 2.13 usr + 0.00 sys = 2.13 CPU, minor = 28591.61 MB, major = 0 B) @ 869.39/s (n=1851) 2.12 WALL ( 2.11 usr + 0.00 sys = 2.12 CPU, minor = 28591.61 MB, major = 0 B) @ 874.99/s (n=1851) Pvec.append: 2.20 WALL ( 2.20 usr + 0.00 sys = 2.20 CPU, minor = 12912.84 MB, major = 0 B) @ 2209.16/s (n=4865) 2.24 WALL ( 2.24 usr + 0.00 sys = 2.24 CPU, minor = 12912.84 MB, major = 0 B) @ 2171.91/s (n=4865) 2.25 WALL ( 2.25 usr + 0.00 sys = 2.25 CPU, minor = 12912.84 MB, major = 0 B) @ 2161.75/s (n=4865) Sek.concat: 2.18 WALL ( 2.17 usr + 0.00 sys = 2.18 CPU, minor = 17026.66 MB, major = 0 B) @ 1444267.83/s (n=3143771) 2.17 WALL ( 2.17 usr + 0.00 sys = 2.17 CPU, minor = 17026.66 MB, major = 0 B) @ 1448128.44/s (n=3143771) 2.16 WALL ( 2.16 usr + 0.00 sys = 2.16 CPU, minor = 17026.66 MB, major = 0 B) @ 1452894.19/s (n=3143771) CCFQueue.append: 2.25 WALL ( 2.24 usr + 0.00 sys = 2.25 CPU, minor = 14796.36 MB, major = 0 B) @ 1420.12/s (n=3191) 2.25 WALL ( 2.24 usr + 0.00 sys = 2.25 CPU, minor = 14796.36 MB, major = 0 B) @ 1421.24/s (n=3191) 2.22 WALL ( 2.22 usr + 0.00 sys = 2.22 CPU, minor = 14796.36 MB, major = 0 B) @ 1435.99/s (n=3191) CCFQueue.append (r-assoc): 2.21 WALL ( 2.21 usr + 0.00 sys = 2.21 CPU, minor = 14615.03 MB, major = 0 B) @ 949.97/s (n=2101) 2.22 WALL ( 2.22 usr + 0.00 sys = 2.22 CPU, minor = 14615.03 MB, major = 0 B) @ 944.86/s (n=2101) 2.30 WALL ( 2.30 usr + 0.00 sys = 2.30 CPU, minor = 14615.03 MB, major = 0 B) @ 913.02/s (n=2101) --- benchs/run_benchs.ml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/benchs/run_benchs.ml b/benchs/run_benchs.ml index dddf908ed..b565e6687 100644 --- a/benchs/run_benchs.ml +++ b/benchs/run_benchs.ml @@ -166,6 +166,9 @@ module L = struct let s1 = Sek.Persistent.of_array 0 (Array.of_list l1) in let s2 = Sek.Persistent.of_array 0 (Array.of_list l2) in let s3 = Sek.Persistent.of_array 0 (Array.of_list l3) in + let q1 = CCFQueue.of_list l1 in + let q2 = CCFQueue.of_list l2 in + let q3 = CCFQueue.of_list l3 in let bench_list l1 l2 l3 () = opaque_ignore List.(append (append l1 l2) l3) in @@ -181,6 +184,12 @@ module L = struct let bench_sek l1 l2 l3 () = opaque_ignore Sek.Persistent.(concat (concat l1 l2) l3) in + let bench_ccfqueue l1 l2 l3 () = + opaque_ignore CCFQueue.(append (append l1 l2) l3) + in + let bench_ccfqueue_r l1 l2 l3 () = + opaque_ignore CCFQueue.(append l1 (append l2 l3)) + in B.throughputN time ~repeat [ "CCList.append", bench_list l1 l2 l3, (); @@ -188,6 +197,8 @@ module L = struct "CCFun_vec.append", bench_funvec v1 v2 v3, (); "Pvec.append", bench_pvec pv1 pv2 pv3, (); "Sek.concat", bench_sek s1 s2 s3, (); + "CCFQueue.append", bench_ccfqueue q1 q2 q3, (); + "CCFQueue.append (r-assoc)", bench_ccfqueue_r q1 q2 q3, (); ] (* FLATTEN *) From 4d2dc5b6c179b1ad8f4fa818ebb98db324b7495d Mon Sep 17 00:00:00 2001 From: rina Date: Fri, 21 Aug 2026 14:13:48 +1000 Subject: [PATCH 2/2] CCFQueue: `append` that iterates over the shorter operand to achieve `min(m, n)` runtime. *** Run benchmarks for path "list.append.10000" Throughputs for "CCList.append", "List.append", "CCFun_vec.append", "Pvec.append", "Sek.concat", "CCFQueue.append", "CCFQueue.append (r-assoc)" each running 3 times for at least 2 CPU seconds: CCList.append: 2.17 WALL ( 2.16 usr + 0.00 sys = 2.17 CPU, minor = 10821.60 MB, major = 0 B) @ 6939.78/s (n=15030) 2.20 WALL ( 2.19 usr + 0.00 sys = 2.20 CPU, minor = 10821.60 MB, major = 0 B) @ 6840.74/s (n=15030) 2.18 WALL ( 2.18 usr + 0.00 sys = 2.18 CPU, minor = 10821.60 MB, major = 0 B) @ 6899.68/s (n=15030) List.append: 2.24 WALL ( 2.24 usr + 0.00 sys = 2.24 CPU, minor = 11154.96 MB, major = 0 B) @ 6921.46/s (n=15493) 2.24 WALL ( 2.24 usr + 0.00 sys = 2.24 CPU, minor = 11154.96 MB, major = 0 B) @ 6911.63/s (n=15493) 2.22 WALL ( 2.21 usr + 0.00 sys = 2.22 CPU, minor = 11154.96 MB, major = 0 B) @ 6990.08/s (n=15493) CCFun_vec.append: 2.07 WALL ( 2.06 usr + 0.00 sys = 2.07 CPU, minor = 26367.31 MB, major = 0 B) @ 826.18/s (n=1707) 2.05 WALL ( 2.05 usr + 0.00 sys = 2.05 CPU, minor = 26367.31 MB, major = 0 B) @ 831.38/s (n=1707) 2.06 WALL ( 2.05 usr + 0.00 sys = 2.06 CPU, minor = 26367.31 MB, major = 0 B) @ 830.34/s (n=1707) Pvec.append: 2.06 WALL ( 2.06 usr + 0.00 sys = 2.06 CPU, minor = 11609.61 MB, major = 0 B) @ 2123.31/s (n=4374) 2.01 WALL ( 2.01 usr + 0.00 sys = 2.01 CPU, minor = 11609.61 MB, major = 0 B) @ 2176.21/s (n=4374) 2.05 WALL ( 2.05 usr + 0.00 sys = 2.05 CPU, minor = 11609.61 MB, major = 0 B) @ 2134.59/s (n=4374) Sek.concat: 2.02 WALL ( 2.01 usr + 0.00 sys = 2.02 CPU, minor = 15610.98 MB, major = 0 B) @ 1429794.82/s (n=2882382) 2.17 WALL ( 2.17 usr + 0.00 sys = 2.17 CPU, minor = 17030.75 MB, major = 0 B) @ 1447474.09/s (n=3144526) 2.00 WALL ( 2.00 usr + 0.00 sys = 2.00 CPU, minor = 15610.98 MB, major = 0 B) @ 1440124.59/s (n=2882382) CCFQueue.append: 2.07 WALL ( 2.07 usr + 0.00 sys = 2.07 CPU, minor = 13725.24 MB, major = 0 B) @ 1427.06/s (n=2960) 2.09 WALL ( 2.08 usr + 0.00 sys = 2.08 CPU, minor = 13725.24 MB, major = 0 B) @ 1419.77/s (n=2960) 2.07 WALL ( 2.06 usr + 0.00 sys = 2.06 CPU, minor = 13725.24 MB, major = 0 B) @ 1433.62/s (n=2960) CCFQueue.append (r-assoc): 2.03 WALL ( 2.03 usr + 0.00 sys = 2.03 CPU, minor = 13524.57 MB, major = 0 B) @ 1434.53/s (n=2917) 2.06 WALL ( 2.06 usr + 0.00 sys = 2.06 CPU, minor = 13524.57 MB, major = 0 B) @ 1416.82/s (n=2917) 2.06 WALL ( 2.06 usr + 0.00 sys = 2.06 CPU, minor = 13524.57 MB, major = 0 B) @ 1417.23/s (n=2917) *** Run benchmarks for path "list.append.100000" Throughputs for "CCList.append", "List.append", "CCFun_vec.append", "Pvec.append", "Sek.concat", "CCFQueue.append", "CCFQueue.append (r-assoc)" each running 3 times for at least 4 CPU seconds: CCList.append: 4.28 WALL ( 4.27 usr + 0.01 sys = 4.28 CPU, minor = 5961.60 MB, major = 0 B) @ 193.64/s (n=828) 4.38 WALL ( 4.37 usr + 0.01 sys = 4.38 CPU, minor = 5961.60 MB, major = 0 B) @ 189.06/s (n=828) 4.39 WALL ( 4.37 usr + 0.02 sys = 4.39 CPU, minor = 5961.60 MB, major = 0 B) @ 188.82/s (n=828) List.append: 4.27 WALL ( 4.26 usr + 0.01 sys = 4.27 CPU, minor = 5846.40 MB, major = 0 B) @ 190.31/s (n=812) 4.25 WALL ( 4.23 usr + 0.01 sys = 4.24 CPU, minor = 5846.40 MB, major = 0 B) @ 191.29/s (n=812) 4.25 WALL ( 4.24 usr + 0.01 sys = 4.25 CPU, minor = 5846.40 MB, major = 0 B) @ 191.05/s (n=812) CCFun_vec.append: 4.38 WALL ( 4.37 usr + 0.01 sys = 4.38 CPU, minor = 61842.82 MB, major = 0 B) @ 64.60/s (n=283) 4.43 WALL ( 4.42 usr + 0.01 sys = 4.43 CPU, minor = 61842.82 MB, major = 0 B) @ 63.86/s (n=283) 4.41 WALL ( 4.40 usr + 0.01 sys = 4.41 CPU, minor = 61842.82 MB, major = 0 B) @ 64.11/s (n=283) Pvec.append: 4.22 WALL ( 4.21 usr + 0.01 sys = 4.22 CPU, minor = 22446.20 MB, major = 0 B) @ 193.31/s (n=816) 4.26 WALL ( 4.25 usr + 0.01 sys = 4.26 CPU, minor = 22446.20 MB, major = 0 B) @ 191.71/s (n=816) 4.27 WALL ( 4.27 usr + 0.01 sys = 4.27 CPU, minor = 22446.20 MB, major = 0 B) @ 190.89/s (n=816) Sek.concat: 4.18 WALL ( 4.17 usr + 0.00 sys = 4.18 CPU, minor = 32803.53 MB, major = 0 B) @ 973097.90/s (n=4063867) 4.23 WALL ( 4.22 usr + 0.00 sys = 4.23 CPU, minor = 32803.53 MB, major = 0 B) @ 961667.63/s (n=4063867) 4.20 WALL ( 4.20 usr + 0.01 sys = 4.20 CPU, minor = 32803.53 MB, major = 0 B) @ 967258.97/s (n=4063867) CCFQueue.append: 4.50 WALL ( 4.50 usr + 0.01 sys = 4.50 CPU, minor = 27234.49 MB, major = 0 B) @ 130.43/s (n=587) 4.48 WALL ( 4.47 usr + 0.01 sys = 4.48 CPU, minor = 27234.49 MB, major = 0 B) @ 130.98/s (n=587) 4.42 WALL ( 4.40 usr + 0.01 sys = 4.42 CPU, minor = 27234.49 MB, major = 0 B) @ 132.92/s (n=587) CCFQueue.append (r-assoc): 4.42 WALL ( 4.42 usr + 0.01 sys = 4.42 CPU, minor = 27559.08 MB, major = 0 B) @ 134.31/s (n=594) 4.44 WALL ( 4.43 usr + 0.01 sys = 4.44 CPU, minor = 27559.08 MB, major = 0 B) @ 133.83/s (n=594) 4.43 WALL ( 4.42 usr + 0.01 sys = 4.43 CPU, minor = 27559.08 MB, major = 0 B) @ 134.14/s (n=594) --- src/data/CCFQueue.ml | 35 ++++++++++++++++++++++++++++++++++- src/data/CCFQueue.mli | 2 +- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/data/CCFQueue.ml b/src/data/CCFQueue.ml index 2fdf0234c..67be65b17 100644 --- a/src/data/CCFQueue.ml +++ b/src/data/CCFQueue.ml @@ -240,6 +240,11 @@ let add_iter_front seq q = seq (fun x -> l := x :: !l); List.fold_left (fun q x -> cons x q) q !l +let add_iter_front_rev q seq = + let q = ref q in + seq (fun x -> q := cons x !q); + !q + let add_iter_back q seq = let q = ref q in seq (fun x -> q := snoc !q x); @@ -269,11 +274,39 @@ let rec to_iter : 'a. 'a t -> 'a iter = k y); _digit_to_iter tail k +let _digit_to_iter_rev : type l. ('a, l) digit -> 'a iter = + fun d k -> + match d with + | Zero -> () + | One x -> k x + | Two (x, y) -> + k y; + k x + | Three (x, y, z) -> + k z; + k y; + k x + +let rec to_iter_rev : 'a. 'a t -> 'a iter = + fun q k -> + match q with + | Shallow d -> _digit_to_iter_rev d k + | Deep (_, hd, (lazy q'), tail) -> + _digit_to_iter_rev tail k; + to_iter_rev q' (fun (x, y) -> + k y; + k x); + _digit_to_iter_rev hd k + let append q1 q2 = match q1, q2 with | Shallow Zero, _ -> q2 | _, Shallow Zero -> q1 - | _ -> add_iter_back q1 (to_iter q2) + | _ -> + if size q1 < size q2 then + add_iter_front_rev q2 (to_iter_rev q1) + else + add_iter_back q1 (to_iter q2) let add_seq_front seq q = (* reversed seq *) diff --git a/src/data/CCFQueue.mli b/src/data/CCFQueue.mli index eaaad54b5..364866df2 100644 --- a/src/data/CCFQueue.mli +++ b/src/data/CCFQueue.mli @@ -86,7 +86,7 @@ val init : 'a t -> 'a t val append : 'a t -> 'a t -> 'a t (** Append two queues. Elements from the second one come after elements of the first one. - Linear in the size of the second queue. *) + Linear in the size of the shorter queue. *) val rev : 'a t -> 'a t (** Reverse the queue, [O(n)] complexity.