owned this note
owned this note
Published
Linked with GitHub
# RISC-V Cache implementation and software optimization case study
###### tags:`Course`, `Final Project`
## Overview

### Features
* 32-bit RISC-V ISA CPU core.
* Support RISC-V integer (I), multiplication and division (M), and CSR instructions (Z) extensions (RV32IMZicsr).
* Supports user, supervisor and machine mode privilege levels.
* Basic MMU support - capable of booting Linux with atomics (RV-A) SW emulation.
* Implements base ISA spec v2.1 and privileged ISA spec v1.11.
* Verified using Google's RISCV-DV random instruction sequences using cosimulation against C++ ISA model.
* Support for instruction / data cache, AXI bus interfaces or tightly coupled memories.
* Configurable number of pipeline stages and result forwarding options.
* Synthesizable Verilog 2001, Verilator and FPGA friendly.
* Coremark: 2.94 CoreMark/MHz
* Dhrystone: 1.25 DMIPS/MHz ('legal compile options' / 337 instructions per iteration)
## Analyze RISC-V Core with cache by [Reference](https://hackmd.io/@_UHs74UQS7uNne9_7SwQFQ/HyFHdpw3t#Overview)
### Environment Setup
* :::danger
Please use **ubuntu20.04**, or else it will report ERROR when building
:::
* **Git clone the project**
```bash=
$ git clone https://github.com/ultraembedded/riscv.git
```
* **Install the required package**
```bash=
$ sudo apt-get install libelf-dev binutils-dev build-essential
```
* **Install GTKwave**
```bash=
$ sudo apt install gtkwave
```
* **Install Verilator**
```bash=
git clone https://github.com/verilator/verilator # first time install
# Every time you need to build:
unsetenv VERILATOR_ROOT # For csh; ignore error if on bash
unset VERILATOR_ROOT # For bash
cd verilator
git pull # Make sure git repository is up-to-date
git tag # See what versions exist
git checkout v{version} # Switch to specified release version
sudo apt-get install git perl python3 make autoconf g++ flex bison ccache
autoconf # Create ./configure script
./configure # Configure and create Makefile
make # Build Verilator itself (if error, try just 'make')
sudo make install
```
:::warning
Success with Verilator **v4.110**
Report **ERROR** with v4.012 by the versiom of the reference

:::
* **Install systemc from** [systemc-2.3.3](https://www.accellera.org/images/downloads/standards/systemc/systemc-2.3.3.tar.gz) **and follow the following instruction**
```bash=
tar -xzf systemc-2.3.3.tar.gz
cd systemc-2.3.3
mkdir objdir && cd objdir
sudo mkdir /usr/local/systemc-2.3.3
sudo ../configure --prefix=/usr/local/systemc-2.3.3/
#You can configure with no prefix, but cautious about the folder path
sudo make
sudo make install
```
:::warning
success with systemc-2.3.3
systemc-2.3.4 may face problems
:::
### Modify Makefile
* Modify makefile in `/riscv/top_tcm_axi/tb/` and `/riscv/top_cache_axi/tb/`
Change the `VERILATOR_SRC` and `SYSTEMC_HOME` to the path where you install systemc and verilator
**Add on 'SYSTEMC_INCLUDE', 'SYSTEMC_LIBDIR', 'LD_LIBRARY_PATH'.**
You will need to set the SYSTEMC_INCLUDE environment variable to point to the include directory with systemc.h in it, and set the SYSTEMC_LIBDIR, LD_LIBRARY_PATH environment variable to point to the directory with libsystemc.a in it.
```makefile=
###############################################################################
## Tool paths
###############################################################################
VERILATOR_SRC ?= /home/dhiptmc/Desktop/verilator/include
SYSTEMC_HOME ?= /home/dhiptmc/Desktop/systemc-2.3.3
SYSTEMC_INCLUDE = /home/dhiptmc/Desktop/systemc-2.3.3/include
SYSTEMC_LIBDIR = /home/dhiptmc/Desktop/systemc-2.3.3/lib-linux64
LD_LIBRARY_PATH = /home/dhiptmc/Desktop/systemc-2.3.3/lib-linux64
TEST_IMAGE ?= ../../isa_sim/images/basic.elf
CORE ?= riscv
export VERILATOR_SRC
export SYSTEMC_HOME
export SYSTEMC_INCLUDE
export SYSTEMC_LIBDIR
export LD_LIBRARY_PATH
```
### Run the program & Observe
* **Run top_tcm_axi/tb**
```bash=
cd riscv/top_tcm_axi/tb/
make
make run
```
Results:
```bash=
./build/test.x -f ../../isa_sim/images/basic.elf
SystemC 2.3.3-Accellera --- Jan 6 2023 19:52:37
Copyright (c) 1996-2018 by all Contributors,
ALL RIGHTS RESERVED
Info: (I702) default timescale unit used for tracing: 1 ns (sysc_wave.vcd)
Memory: 0x2000 - 0x3cd3 (Size=7KB) [.text]
Memory: 0x3cd4 - 0x3ce7 (Size=0KB) [.data]
Memory: 0x3ce8 - 0x4d07 (Size=4KB) [.bss]
Starting from 0x00002000
Test:
1. Initialised data
2. Multiply
3. Divide
4. Shift left
5. Shift right
6. Shift right arithmetic
7. Signed comparision
8. Word access
9. Byte access
10. Comparision
TB: Aborted at 109020 ns
```
* **Run top_cache_axi/tb**
```bash=
cd riscv/top_cache_axi/tb/
make
make run
```
Results:
```bash=
./build/test.x -f ../../isa_sim/images/basic.elf
SystemC 2.3.3-Accellera --- Jan 6 2023 19:52:37
Copyright (c) 1996-2018 by all Contributors,
ALL RIGHTS RESERVED
Info: (I702) default timescale unit used for tracing: 1 ns (sysc_wave.vcd)
Memory: 0x2000 - 0x3cd3 (Size=7KB) [.text]
Memory: 0x3cd4 - 0x3ce7 (Size=0KB) [.data]
Memory: 0x3ce8 - 0x4d07 (Size=4KB) [.bss]
Starting from 0x00002000
Test:
1. Initialised data
2. Multiply
3. Divide
4. Shift left
5. Shift right
6. Shift right arithmetic
7. Signed comparision
8. Word access
9. Byte access
10. Comparision
TB: Aborted at 157910 ns
```
:::warning
Do not immediately retry the execution after failing to do so. You should restore the data status in the folder to the previous status before retrying.
:::
* **Observe of the cache & AXI**
* Cache
:::danger
The Cache part of VCD file is unable to open . We're still figuring out the problem where it located.

:::
* AXI
[**AXI(Advanced Xtensible Interface)**](http://www.gstitt.ece.ufl.edu/courses/fall15/eel4720_5721/labs/refs/AXI4_specification.pdf) is is an interface protocol defined by ARM as par of the AMBA (Advanced Microcontroller Bus Architecture) standard.

As the computing demands rise, **AHB(Advanced High performance Bus)** started to fall short in meeting the demands of the system which were ever hungry for more bandwidths. AXI was then invented with "**outstanding transaction**".
It can be observed in the diagram shown below, as the number of OTs (outstanding transaction) increase in AXI, the efficiency increases.

The AXI protocol is burst-based and defines the following independent transaction channels:
• read address
• read data
• write address
• write data
• write response
* **Read transaction**

A read data channel to transfer data from the slave to the master.
* **Write transaction**

A write data channel to transfer data from the master to the slave. In a write transaction, the slave uses the write response channel to signal the completion of the transfer to the master.
* **Handshake**
All five transaction channels use the same VALID/READY handshake process to transfer address, data, and control information. This two-way flow control mechanism means both the master and slave can control the rate at which the information moves between master and slave.



* **Burst Type**
The AXI protocol defines three burst types:
* **FIXED :** In a fixed burst, the address is the same for every transfer in the burst.
This burst type is used for repeated accesses to the same location such as when loading or emptying a FIFO.
* **INCR :** Incrementing. In an incrementing burst, the address for each transfer in the burst is an increment of the address for the previous transfer. The increment value depends on the size of the transfer. For example, the address for each transfer in a burst with a size of four bytes is the previous address plus four.
This burst type is used for accesses to normal sequential memory.
* **WRAP :** A wrapping burst is similar to an incrementing burst, except that the address wraps around to a lower address if an upper address limit is reached.
The following restrictions apply to wrapping bursts:
• the start address must be aligned to the size of each transfer
• the length of the burst must be 2, 4, 8, or 16 transfers.
The behavior of a wrapping burst is:
• The lowest address used by the burst is aligned to the total size of the data to be transferred, that is, to ((size of each transfer in the burst) × (number of transfers in the burst)). This address is defined as the wrap boundary.
• After each transfer, the address increments in the same way as for an INCR burst. However,
if this incremented address is ((wrap boundary) + (total size of data to be transferred))
then the address wraps round to the wrap boundary.
• The first transfer in the burst can use an address that is higher than the wrap boundary, subject
to the restrictions that apply to wrapping bursts. This means that the address wraps for any
WRAP burst for which the first address is higher than the wrap boundary.
This burst type is used for cache line accesses.
* **Waveform of Read Instruction**

* Read Addresss Channel

1. araddress = 0x2000.
2. arburst = 0x01 ,According to the Burst type define in "axi4_defines.h",it's INCREMENTAL type.
```=c
enum eAXI4_BURST
{
AXI4_BURST_FIXED,
AXI4_BURST_INCR,
AXI4_BURST_WRAP
};
```
3. arid = 0(from master 0).
4. arlen = 0x07, Request len+1,total 8 data from memory ,due to the burst type is INCR,it's mean master request data from address 0x2000 , 0x2004 ... 0x2018 , 0x201C.
```=c
//from "tb_axi4_mem.cpp"
// Unroll burst
for (int i=0;i<((int)(axi_first.ARLEN) + 1);i++)
{
axi4_master item = axi_first;
item.ARVALID = true;
item.ARADDR = next_addr;
item.WLAST = (i == axi_first.ARLEN);
axi_rd_q.push(item);
// Generate next address
next_addr = calc_next_addr(next_addr, axi_first.ARBURST, axi_first.ARLEN);
}
```
5. arvalid = 1 && arready = 1 ,means Handshake done , read address transaction ended.
* Read data Channel

1. rid = 0.(to master 0)
2. rdata : means the data from slave(Instruction memory).
3. rvalid = 1 & rready = 1.means read data Handshake done,In the mean time the rdata(memory output) is avaliable.
observe the above image can found there were total 8 clks of handshake occurred. It means memory send 8(burst_len+1,from address 0x2000 , 0x2004 ... 0x2018 , 0x201C) avaliable data back.
Instruction in basic.elf:
```
Disassembly of section .text:
00002000 <boot_vector>:
2000: 2580006f j 2258 <start>
2004: 0000 unimp
...
00002008 <ipc_vector>:
...
2010: 1140006f j 2124 <isr_vector>
...
00002020 <arg_argc>:
2020: 0000 unimp
...
```
Data send back from Instruction memory(Signal in first line is rdata):

4. rlast pull up only when it's the last data from this read data transaction(handshake&&(data_cnt==ar_len))
```=c
item.WLAST = (i == axi_first.ARLEN);
axi_o.RLAST = item.WLAST;
```
5. resp = 0 ,according to "axi4_defines.h",the read data response is okay (avaliable with handshake,means the data is error or not).
```=c
enum eAXI4_RESP
{
AXI4_RESP_OKAY,
AXI4_RESP_EXOKAY,
AXI4_RESP_SLVERR,
AXI4_RESP_DECERR
};
```
* **Waveform of Write Data**

* Write address channel

1. awaddr=0x4020 , write data from address 0x4020.
2. awburst = 0x01 , INCREMENT type.
3. awid = 0x0 ,request send from master 0.
4. awlen = 0x07 , send total of 8 datas (len +1) to data memory .
5. awvalid = 1 & awready = 1 , Handshake occurred,Write address transaction ended.
* Write data channel

1. wdata ,Data send from master which is going to write in data memory(only avaliable when handshake occurred).
It will keep procedure until total 8 of data complete transmission,that is, write data to memory address 0x4020,0x4024 .... 0x4030,0x403C.
2. wstrb , determine which Byte in Word is willing to write.
In waveform the signal wstrb is 0xF,so write in the whole Word to memory.
```=c
//from tb_axi4_mem.cpp
//-----------------------------------------------------------------
// write32: Write a 32-bit word to memory
//-----------------------------------------------------------------
void tb_axi4_mem::write32(uint32_t addr, uint32_t data, uint8_t strb)
{
for (int i=0;i<4;i++)
if (strb & (1 << i))
tb_memory::write(addr + i,data >> (i*8));
}
```
3. wvalid = 1 & wready = 1 , Handshake occurred. wdata,wstrb and wlast only avaliable when this situation happened. It can be observed that there are 8 handshakes in waveform,means master send 8 data to slave(memory).
4. wlast, when master is going to send the last data , the signal wlast pull up , and the write data transaction ended.
* Write Respond Channel

1. bid=0 , slave send data to master 0.
2. bresp=0x00 , the same as rresp,check write data succeded or not.
```=c
enum eAXI4_RESP
{
AXI4_RESP_OKAY,
AXI4_RESP_EXOKAY,
AXI4_RESP_SLVERR,
AXI4_RESP_DECERR
};
```
3. bvalid = 1 & bready = 1 , Handshake occurred , bid and bresp only avaliable when this situation happened.Write Response transaction ended.
* **Arbiter**
Generally speaking, some channel in AXI have arbiter and decoder according to their design.
* SAMD(Share Address Multiple Data)
High performance , allow outstanding.

* SASD(Share Address Share Data)
Low cost.

* Arbiter in waveform

It seems there are no arbiter in this case.
After I check tb_axi4_mem.c file , the original aurthor build 2 AXI bus directly (one for Instruction,one for data) , so the need of arbiter is unnecessary.
## The [problem](https://leetcode.com/problems/flipping-an-image/) pick at before works
### row-major vs. column-major
* **The meaning of row-major & column-major**
* Row-major : the consecutive elements of a row reside next to each other

* Column-major : the consecutive elements of a column reside next to each other

* For example, the array could be stored in two possible ways:
$$\begin{bmatrix} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ \end{bmatrix}$$
| Address | r_Access | r_Value | c_Access | c_Value |
|:---:|:---:|:---:|:---:|:---:|
| 0 |A[0][0]|$a_{11}$|A[0][0]|$a_{11}$|
| 1 |A[0][1]|$a_{12}$|A[1][0]|$a_{21}$|
| 2 |A[0][2]|$a_{13}$|A[0][1]|$a_{12}$|
| 3 |A[1][0]|$a_{21}$|A[1][1]|$a_{22}$|
| 4 |A[1][1]|$a_{22}$|A[0][2]|$a_{13}$|
| 5 |A[1][2]|$a_{23}$|A[1][2]|$a_{23}$|
* **C code for dealing problem with Row/Col-major**
```c=
#include <stdio.h>
#include <stdlib.h>
#define ROWS 3
#define COLS 4
#define IMGSIZE 12
int main()
{
int image[ROWS][COLS] = { {1,1,0,0},
{1,0,1,1},
{0,1,1,0}};
int row_image[IMGSIZE];
int col_image[IMGSIZE];
for(int r=0; r<ROWS; r++){ //row-major
for(int c=0; c<COLS; c++) row_image[COLS*r+c] = image[r][c];
}
for(int c=0; c<COLS; c++){ //col-majar
for(int r=0; r<COLS; r++) col_image[ROWS*c+r] = image[r][c];
}
printf("The row major result is \n");
flipimage(row_image, IMGSIZE, 'r');
printf("\nThe col major result is \n");
flipimage(col_image, IMGSIZE, 'c');
return 0;
}
void flipimage(int image[IMGSIZE], int imageSize, char type){
int left_pointer;
int right_pointer;
int pivot;
int temp;
for(int i=0; i<imageSize; i++){
if(image[i]==0) image[i]=1;
else image[i]=0;
}
if(type == 'r'){ //Row-major solution
pivot=0;
right_pointer=pivot+COLS-1;
while(pivot<COLS*ROWS){ //if left smaller than last row's first element
left_pointer = pivot;
while(left_pointer<right_pointer){
temp = image[left_pointer];
image[left_pointer] = image[right_pointer];
image[right_pointer] = temp;
left_pointer++;
right_pointer--;
}
pivot += COLS;
right_pointer = pivot+COLS-1;
}
for(int i=0; i<imageSize; i++){
if((i+1)%COLS == 0) printf("%d\n", image[i]);
else printf("%d, ", image[i]);
}
}
if(type == 'c'){
pivot=0;
right_pointer=pivot+ROWS*(COLS-1);
while(pivot<ROWS){
left_pointer = pivot;
while((right_pointer-left_pointer)>=ROWS){
temp = image[left_pointer];
image[left_pointer] = image[right_pointer];
image[right_pointer] = temp;
left_pointer+=ROWS;
right_pointer-=ROWS;
}
pivot++;
right_pointer=pivot+ROWS*(COLS-1);
}
for(int i=0; i<imageSize/4; i++){
printf(" %d, %d, %d, %d\n", image[i], image[i+ROWS], image[i+2*ROWS], image[i+3*ROWS]);
}
}
}
```
* **Result**

* **The performance compare**
:::success
Because we can't run .elf on his RISCV-Core. So we try to imitate the Cache behavior by the spec giving in his file as below.
* Total 16KB
* 2-way set
* 1-word width per block
* 2048 liines
:::
* Row-Major

* Col-Major

* By the hit rate result generated by $Ripes$, we can found that the **Row-major** performance is $better$ than **Col-major** due to the input of array is retangle shape, with row's length larger than column's length.
## The [specific problem](https://github.com/scandum/rotate) analyzation
* **Introduction to rotating**
A rotation is to swap the left side of an array with the right side.

After the rotation the data is as following.

* **C code for various rotations and benchmark**
rotate.h:
``` C=
#ifndef ROTATE_H
#define ROTATE_H
void outsidein_reversal(int *array, size_t block_size)
{
int *pta, *ptb, swap;
pta = array;
ptb = array + block_size;
block_size /= 2;
while (block_size--)
{
swap = *pta; *pta++ = *--ptb; *ptb = swap;
}
}
void insideout_reversal(int *array, size_t block_size)
{
int *pta, *ptb, swap;
ptb = array + block_size;
block_size /= 2;
pta = array + block_size;
ptb -= block_size;
while (block_size--)
{
swap = *--pta; *pta = *ptb; *ptb++ = swap;
}
}
void forward_block_swap(int *array, const size_t start1, const size_t start2, size_t block_size)
{
int *pta, *ptb, swap;
pta = array + start1;
ptb = array + start2;
while (block_size--)
{
swap = *pta; *pta++ = *ptb; *ptb++ = swap;
}
}
void backward_block_swap(int *array, const size_t start1, const size_t start2, size_t block_size)
{
int *pta, *ptb, swap;
pta = array + start1 + block_size;
ptb = array + start2 + block_size;
while (block_size--)
{
swap = *--pta; *pta = *--ptb; *ptb = swap;
}
}
void auxiliary_rotation(int *array, size_t left, size_t right)
{
int *pta, *ptb, *ptc, *swap;
pta = array;
ptb = array + left;
ptc = array + right;
if (left < right)
{
swap = malloc(left * sizeof(int));
memcpy(swap, pta, left * sizeof(int));
memmove(pta, ptb, right * sizeof(int));
memcpy(ptc, swap, left * sizeof(int));
}
else
{
swap = malloc(right * sizeof(int));
memcpy(swap, ptb, right * sizeof(int));
memmove(ptc, pta, left * sizeof(int));
memcpy(pta, swap, right * sizeof(int));
}
free(swap);
}
void stack_rotation(int *array, size_t left, size_t right)
{
int *pta, *ptb, *ptc, swap[8];
pta = array;
ptb = array + left;
ptc = array + right;
if (left < right)
{
memcpy(swap, pta, left * sizeof(int));
memmove(pta, ptb, right * sizeof(int));
memcpy(ptc, swap, left * sizeof(int));
}
else
{
memcpy(swap, ptb, right * sizeof(int));
memmove(ptc, pta, left * sizeof(int));
memcpy(pta, swap, right * sizeof(int));
}
}
// 3 reversal - Origin unknown, but prior to 1981
void reversal_rotation(int *array, size_t left, size_t right)
{
outsidein_reversal(array, left);
outsidein_reversal(array + left, right);
outsidein_reversal(array, left + right);
}
// 2021 - Bridge rotation by Igor van den Hoven
void bridge_rotation(int *array, size_t left, size_t right)
{
int *pta, *ptb, *ptc, *ptd, *swap;
pta = array;
ptb = pta + left;
ptc = pta + right;
ptd = ptc + left;
if (left < right)
{
size_t bridge = right - left;
if (bridge < left)
{
swap = malloc(bridge * sizeof(int));
memcpy(swap, ptb, bridge * sizeof(int));
while (left--)
{
*--ptc = *--ptd; *ptd = *--ptb;
}
memcpy(pta, swap, bridge * sizeof(int));
}
else
{
swap = malloc(left * sizeof(int));
memcpy(swap, pta, left * sizeof(int));
memmove(pta, ptb, right * sizeof(int));
memcpy(ptc, swap, left * sizeof(int));
}
}
else if (right < left)
{
size_t bridge = left - right;
if (bridge < right)
{
swap = malloc(bridge * sizeof(int));
memcpy(swap, ptc, bridge * sizeof(int));
while (right--)
{
*ptc++ = *pta; *pta++ = *ptb++;
}
memcpy(ptd - bridge, swap, bridge * sizeof(int));
}
else
{
swap = malloc(right * sizeof(int));
memcpy(swap, ptb, right * sizeof(int));
memmove(ptc, pta, left * sizeof(int));
memcpy(pta, swap, right * sizeof(int));
}
}
else
{
swap = malloc(1 * sizeof(int));
while (left--)
{
*swap = *pta; *pta++ = *ptb; *ptb++ = *swap;
}
}
free(swap);
}
// 2021 - Conjoined Triple Reversal rotation by Igor van den Hoven
void contrev_rotation(int *array, size_t left, size_t right)
{
int *pta, *ptb, *ptc, *ptd, swap;
size_t loop;
pta = array;
ptb = array + left;
ptc = array + left;
ptd = array + left + right;
if (left > right)
{
loop = right / 2;
while (loop--)
{
swap = *--ptb; *ptb = *pta; *pta++ = *ptc; *ptc++ = *--ptd; *ptd = swap;
}
loop = (ptb - pta) / 2;
while (loop--)
{
swap = *--ptb; *ptb = *pta; *pta++ = *--ptd; *ptd = swap;
}
loop = (ptd - pta) / 2;
while (loop--)
{
swap = *pta; *pta++ = *--ptd; *ptd = swap;
}
}
else if (left < right)
{
loop = left / 2;
while (loop--)
{
swap = *--ptb; *ptb = *pta; *pta++ = *ptc; *ptc++ = *--ptd; *ptd = swap;
}
loop = (ptd - ptc) / 2;
while (loop--)
{
swap = *ptc; *ptc++ = *--ptd; *ptd = *pta; *pta++ = swap;
}
loop = (ptd - pta) / 2;
while (loop--)
{
swap = *pta; *pta++ = *--ptd; *ptd = swap;
}
}
else
{
loop = left;
while (loop--)
{
swap = *pta; *pta++ = *ptb; *ptb++ = swap;
}
}
}
// 2021 - Trinity rotation by Igor van den Hoven (Conjoined Triple Reversal + Bridge rotation)
#define MAX_AUX 8
void trinity_rotation(int *array, size_t left, size_t right)
{
int *pta, *ptb, *ptc, *ptd, swap[MAX_AUX];
size_t loop;
if (left < right)
{
if (left <= MAX_AUX)
{
memcpy(swap, array, left * sizeof(int));
memmove(array, array + left, right * sizeof(int));
memcpy(array + right, swap, left * sizeof(int));
}
else
{
pta = array;
ptb = pta + left;
loop = right - left;
if (loop <= MAX_AUX && loop > 3)
{
ptc = pta + right;
ptd = ptc + left;
memcpy(swap, ptb, loop * sizeof(int));
while (left--)
{
*--ptc = *--ptd; *ptd = *--ptb;
}
memcpy(pta, swap, loop * sizeof(int));
}
else
{
ptc = ptb;
ptd = ptc + right;
loop = left / 2;
while (loop--)
{
*swap = *--ptb; *ptb = *pta; *pta++ = *ptc; *ptc++ = *--ptd; *ptd = *swap;
}
loop = (ptd - ptc) / 2;
while (loop--)
{
*swap = *ptc; *ptc++ = *--ptd; *ptd = *pta; *pta++ = *swap;
}
loop = (ptd - pta) / 2;
while (loop--)
{
*swap = *pta; *pta++ = *--ptd; *ptd = *swap;
}
}
}
}
else if (right < left)
{
if (right <= MAX_AUX)
{
memcpy(swap, array + left, right * sizeof(int));
memmove(array + right, array, left * sizeof(int));
memcpy(array, swap, right * sizeof(int));
}
else
{
pta = array;
ptb = pta + left;
loop = left - right;
if (loop <= MAX_AUX && loop > 3)
{
ptc = pta + right;
ptd = ptc + left;
memcpy(swap, ptc, loop * sizeof(int));
while (right--)
{
*ptc++ = *pta; *pta++ = *ptb++;
}
memcpy(ptd - loop, swap, loop * sizeof(int));
}
else
{
ptc = ptb;
ptd = ptc + right;
loop = right / 2;
while (loop--)
{
*swap = *--ptb; *ptb = *pta; *pta++ = *ptc; *ptc++ = *--ptd; *ptd = *swap;
}
loop = (ptb - pta) / 2;
while (loop--)
{
*swap = *--ptb; *ptb = *pta; *pta++ = *--ptd; *ptd = *swap;
}
loop = (ptd - pta) / 2;
while (loop--)
{
*swap = *pta; *pta++ = *--ptd; *ptd = *swap;
}
}
}
}
else
{
pta = array;
ptb = pta + left;
while (left--)
{
*swap = *pta; *pta++ = *ptb; *ptb++ = *swap;
}
}
}
#undef MAX_AUX
// 1981 - Gries-Mills rotation by David Gries and Harlan Mills
void griesmills_rotation(int *array, size_t left, size_t right)
{
size_t start = 0;
while (left && right)
{
if (left <= right)
{
do
{
forward_block_swap(array, start, start + left, left);
start += left;
right -= left;
}
while (left <= right);
}
else
{
do
{
forward_block_swap(array, start + left - right, start + left, right);
left -= right;
}
while (right <= left);
}
}
}
// 2020 - Grail rotation by the Holy Grail Sort project (Gries-Mills derived)
void grail_rotation(int *array, size_t left, size_t right)
{
size_t min = left <= right ? left : right;
size_t start = 0;
while (min > 1)
{
if (left <= right)
{
do
{
forward_block_swap(array, start, start + left, left);
start += left;
right -= left;
}
while (left <= right);
min = right;
}
else
{
do
{
backward_block_swap(array, start + left - right, start + left, right);
left -= right;
}
while (right <= left);
min = left;
}
}
if (min)
{
stack_rotation(array + start, left, right);
}
}
// 2021 - Piston rotation by Igor van den Hoven. Based on the successive swap described by Gries and Mills in 1981.
void piston_rotation(int *array, size_t left, size_t right)
{
size_t start = 0;
while (left > 0)
{
while (left <= right)
{
forward_block_swap(array, start, start + right, left);
right -= left;
}
if (right <= 0)
{
break;
}
do
{
forward_block_swap(array, start, start + left, right);
left -= right;
start += right;
}
while (right <= left);
}
/* if (left && right)
{
stack_rotation(array + start, left, right);
}*/
}
// 2021 - Helix rotation by Control (grail derived)
void helix_rotation(int *array, size_t left, size_t right)
{
int swap;
size_t start = 0;
size_t end = left + right;
size_t mid = left;
while (1)
{
if (left > right)
{
if (right <= 1)
{
break;
}
while (mid > start)
{
swap = array[--mid]; array[mid] = array[--end]; array[end] = swap;
}
mid += (left %= right);
right = end - mid;
}
else
{
if (left <= 1)
{
break;
}
while (mid < end)
{
swap = array[mid]; array[mid++] = array[start]; array[start++] = swap;
}
mid -= (right %= left);
left = mid - start;
}
}
if (left && right)
{
stack_rotation(array + start, left, right);
}
}
// 2021 - Drill rotation by Igor van den Hoven (grail derived with piston and helix loops)
void drill_rotation(int *array, size_t left, size_t right)
{
int swap;
size_t start = 0;
size_t end = left + right;
size_t mid = left;
size_t loop;
while (left > 1)
{
if (left <= right)
{
loop = end - mid - (right %= left);
do
{
swap = array[mid]; array[mid++] = array[start]; array[start++] = swap;
}
while (--loop);
}
if (right <= 1)
{
break;
}
loop = mid - start - (left %= right);
do
{
swap = array[--mid]; array[mid] = array[--end]; array[end] = swap;
}
while (--loop);
}
if (left && right)
{
stack_rotation(array + start, left, right);
}
}
// 1965 - Juggling aka Dolphin rotation
int gcd(int a, int b)
{
int r;
while (b)
{
r = a % b;
a = b;
b = r;
}
return a;
}
void juggling_rotation(int *array, size_t left, size_t right)
{
int *pta, *ptb, *ptc, *ptd, swap;
const size_t nmemb = left + right;
if (left == 0)
{
return;
}
ptd = array + gcd(left, nmemb);
for (ptc = array ; ptc < ptd ; ptc++)
{
swap = *ptc;
pta = ptc;
while (1)
{
ptb = pta + left;
if (ptb >= array + nmemb)
{
ptb -= nmemb;
if (ptb == ptc)
{
break;
}
}
*pta = *ptb;
pta = ptb;
}
*pta = swap;
}
}
#endif
```
bench.c:
```c=
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <math.h>
#include "rotate.h"
long long utime()
{
struct timeval now_time;
gettimeofday(&now_time, NULL);
return now_time.tv_sec * 1000000LL + now_time.tv_usec;
}
typedef void ROTATEFUNC(int *array, size_t left, size_t right);
void test_sort(void *array, void *unsorted, void *valid, int max, int samples, int repetitions, int left, int right, const char *name, char *desc, size_t size)
{
ROTATEFUNC *rotate;
long long start, end, total, best, average;
size_t rep, sam;
int *pta = (int *) array, *ptv = (int *) valid, cnt;
static int legend;
if (*name == '*')
{
if (legend == 0)
{
legend = 1;
printf("%s\n", "| Name | Items | Type | Best | Average | Loops | Samples | Distribution |");
printf("%s\n", "| --------- | -------- | ---- | -------- | -------- | --------- | ------- | ---------------- |");
}
else
{
printf("%s\n", "| | | | | | | | |");
}
return;
}
switch (name[0] + name[1] * 128 + name[2] * 16384)
{
case 'a' + 'u' * 128 + 'x' * 16384:
rotate = auxiliary_rotation;
break;
case 'b' + 'r' * 128 + 'i' * 16384:
rotate = bridge_rotation;
break;
case 'c' + 'o' * 128 + 'n' * 16384:
rotate = contrev_rotation;
break;
case 'd' + 'r' * 128 + 'i' * 16384:
rotate = drill_rotation;
break;
case 'g' + 'r' * 128 + 'a' * 16384:
rotate = grail_rotation;
break;
case 'g' + 'r' * 128 + 'i' * 16384:
rotate = griesmills_rotation;
break;
case 'h' + 'e' * 128 + 'l' * 16384:
rotate = helix_rotation;
break;
case 'j' + 'u' * 128 + 'g' * 16384:
rotate = juggling_rotation;
break;
case 'p' + 'i' * 128 + 's' * 16384:
rotate = piston_rotation;
break;
case 'r' + 'e' * 128 + 'v' * 16384:
rotate = reversal_rotation;
break;
case 't' + 'r' * 128 + 'i' * 16384:
rotate = trinity_rotation;
break;
default:
printf("Unknown rotation: (%s). Valid rotations are: auxiliary, bridge, contrev, drill, grail, griesmills, helix, juggling, piston, reversal, trinity\n", name);
return;
}
best = average = 0;
for (sam = 0 ; sam < samples ; sam++)
{
total = 0;
start = utime();
for (rep = 0 ; rep < repetitions ; rep++)
{
memcpy(array, unsorted, max * size);
rotate(array, left, right);
}
end = utime();
total = end - start;
if (!best || total < best)
{
best = total;
}
average += total;
}
average /= samples;
printf("|%10s | %8d | %4d | %f | %f | %9d | %7d | %16s |\n", name, max, (int) size * 8, best / 1000000.0, average / 1000000.0, repetitions, samples, desc);
for (cnt = 0 ; cnt < max ; cnt++)
{
if (pta[cnt] != ptv[cnt])
{
printf(" validate: array[%d] != valid[%d]. (%d vs %d\n", cnt, cnt, pta[cnt], ptv[cnt]);
break;
}
}
}
int main(int argc, char **argv)
{
int max = 1000000;
int samples = 200;
int repetitions = 1;
int seed = 0;
int cnt, left, right, index;
int *a_array, *r_array, *v_array;
char dist[40], *sorts[] = { "*", "bridge", "helix", "trinity", "reversal" };
// char dist[40], *sorts[] = { "*", "contrev", "piston", "griesmills", "juggler" };
// char dist[40], *sorts[] = { "*", "auxiliary", "bridge", "contrev", "drill", "grail", "griesmills", "helix", "juggling", "piston", "reversal", "trinity" };
if (argc >= 1 && argv[1] && *argv[1])
{
max = atoi(argv[1]);
}
if (argc >= 2 && argv[2] && *argv[2])
{
samples = atoi(argv[2]);
}
if (argc >= 3 && argv[3] && *argv[3])
{
repetitions = atoi(argv[3]);
}
if (argc >= 4 && argv[4] && *argv[4])
{
seed = atoi(argv[4]);
}
printf("Benchmark: array size: %d, samples: %d, repetitions: %d, seed: %d\n\n", max, samples, repetitions, seed);
// 32 bit
a_array = (int *) malloc(max * sizeof(int));
r_array = (int *) malloc(max * sizeof(int));
v_array = (int *) malloc(max * sizeof(int));
for (cnt = 0 ; cnt < max ; cnt++)
{
r_array[cnt] = cnt;
}
int values[] = { 1, 1000, 99999, 199998, 299997, 399996, 499995, 0};
for (index = 0 ; values[index] != 0 ; index++)
{
left = values[index];
right = max - left;
memcpy(v_array, r_array, max * sizeof(int));
auxiliary_rotation(v_array, left, right);
sprintf(dist, "%d/%d", left, right);
for (cnt = 0 ; cnt < sizeof(sorts) / sizeof(char *) ; cnt++)
{
test_sort(a_array, r_array, v_array, max, samples, repetitions, left, right, sorts[cnt], dist, sizeof(int));
}
}
for (left = 1 ; left <= 9 ; left ++)
{
right = max - left;
memcpy(v_array, r_array, max * sizeof(int));
auxiliary_rotation(v_array, left, right);
sprintf(dist, "%d/%d", left, right);
for (cnt = 0 ; cnt < sizeof(sorts) / sizeof(char *) ; cnt++)
{
test_sort(a_array, r_array, v_array, max, samples, repetitions, left, right, sorts[cnt], dist, sizeof(int));
}
}
for (left = max / 3 ; left < max / 3 + 5 ; left++)
{
right = max - left;
memcpy(v_array, r_array, max * sizeof(int));
auxiliary_rotation(v_array, left, right);
sprintf(dist, "%d/%d", left, right);
for (cnt = 0 ; cnt < sizeof(sorts) / sizeof(char *) ; cnt++)
{
test_sort(a_array, r_array, v_array, max, samples, repetitions, left, right, sorts[cnt], dist, sizeof(int));
}
}
for (left = max / 2 ; left < max / 2 + 9 ; left++)
{
right = max - left;
memcpy(v_array, r_array, max * sizeof(int));
auxiliary_rotation(v_array, left, right);
sprintf(dist, "%d/%d", left, right);
for (cnt = 0 ; cnt < sizeof(sorts) / sizeof(char *) ; cnt++)
{
test_sort(a_array, r_array, v_array, max, samples, repetitions, left, right, sorts[cnt], dist, sizeof(int));
}
}
for (left = max * 10 / 100 - 1 ; left < max ; left += max * 10 / 100 - 1)
{
right = max - left;
memcpy(v_array, r_array, max * sizeof(int));
auxiliary_rotation(v_array, left, right);
sprintf(dist, "%d/%d", left, right);
for (cnt = 0 ; cnt < sizeof(sorts) / sizeof(char *) ; cnt++)
{
test_sort(a_array, r_array, v_array, max, samples, repetitions, left, right, sorts[cnt], dist, sizeof(int));
}
}
free(a_array);
free(r_array);
free(v_array);
return 0;
}
```
* **Result:**
Benchmark: array size: 1000000, samples: 200, repetitions: 1, seed: 0
| Name | Items | Type | Best | Average | Loops | Samples | Distribution |
| --------- | -------- | ---- | -------- | -------- | --------- | ------- | ---------------- |
| bridge | 1000000 | 32 | 0.000999 | 0.000562 | 1 | 200 | 1/999999 |
| helix | 1000000 | 32 | 0.000000 | 0.000457 | 1 | 200 | 1/999999 |
| trinity | 1000000 | 32 | 0.000000 | 0.000452 | 1 | 200 | 1/999999 |
| reversal | 1000000 | 32 | 0.000985 | 0.001492 | 1 | 200 | 1/999999 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000404 | 1 | 200 | 1000/999000 |
| helix | 1000000 | 32 | 0.000999 | 0.002212 | 1 | 200 | 1000/999000 |
| trinity | 1000000 | 32 | 0.000995 | 0.001047 | 1 | 200 | 1000/999000 |
| reversal | 1000000 | 32 | 0.000994 | 0.001502 | 1 | 200 | 1000/999000 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.001000 | 0.000397 | 1 | 200 | 99999/900001 |
| helix | 1000000 | 32 | 0.001506 | 0.002200 | 1 | 200 | 99999/900001 |
| trinity | 1000000 | 32 | 0.000997 | 0.001100 | 1 | 200 | 99999/900001 |
| reversal | 1000000 | 32 | 0.000989 | 0.001512 | 1 | 200 | 99999/900001 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000432 | 1 | 200 | 199998/800002 |
| helix | 1000000 | 32 | 0.001986 | 0.002239 | 1 | 200 | 199998/800002 |
| trinity | 1000000 | 32 | 0.000993 | 0.001010 | 1 | 200 | 199998/800002 |
| reversal | 1000000 | 32 | 0.000997 | 0.001387 | 1 | 200 | 199998/800002 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000532 | 1 | 200 | 299997/700003 |
| helix | 1000000 | 32 | 0.001995 | 0.002205 | 1 | 200 | 299997/700003 |
| trinity | 1000000 | 32 | 0.000994 | 0.001015 | 1 | 200 | 299997/700003 |
| reversal | 1000000 | 32 | 0.000993 | 0.001407 | 1 | 200 | 299997/700003 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000999 | 0.000830 | 1 | 200 | 399996/600004 |
| helix | 1000000 | 32 | 0.001509 | 0.002155 | 1 | 200 | 399996/600004 |
| trinity | 1000000 | 32 | 0.000987 | 0.001025 | 1 | 200 | 399996/600004 |
| reversal | 1000000 | 32 | 0.000994 | 0.001427 | 1 | 200 | 399996/600004 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.001000 | 0.000870 | 1 | 200 | 499995/500005 |
| helix | 1000000 | 32 | 0.001001 | 0.002215 | 1 | 200 | 499995/500005 |
| trinity | 1000000 | 32 | 0.000997 | 0.001015 | 1 | 200 | 499995/500005 |
| reversal | 1000000 | 32 | 0.000992 | 0.001402 | 1 | 200 | 499995/500005 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.001000 | 0.000422 | 1 | 200 | 1/999999 |
| helix | 1000000 | 32 | 0.000000 | 0.000396 | 1 | 200 | 1/999999 |
| trinity | 1000000 | 32 | 0.000000 | 0.000405 | 1 | 200 | 1/999999 |
| reversal | 1000000 | 32 | 0.000996 | 0.001377 | 1 | 200 | 1/999999 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000407 | 1 | 200 | 2/999998 |
| helix | 1000000 | 32 | 0.001504 | 0.002232 | 1 | 200 | 2/999998 |
| trinity | 1000000 | 32 | 0.000000 | 0.000410 | 1 | 200 | 2/999998 |
| reversal | 1000000 | 32 | 0.000995 | 0.001397 | 1 | 200 | 2/999998 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.001001 | 0.000407 | 1 | 200 | 3/999997 |
| helix | 1000000 | 32 | 0.000996 | 0.002230 | 1 | 200 | 3/999997 |
| trinity | 1000000 | 32 | 0.000000 | 0.000397 | 1 | 200 | 3/999997 |
| reversal | 1000000 | 32 | 0.000991 | 0.001375 | 1 | 200 | 3/999997 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000401 | 1 | 200 | 4/999996 |
| helix | 1000000 | 32 | 0.001505 | 0.002189 | 1 | 200 | 4/999996 |
| trinity | 1000000 | 32 | 0.000000 | 0.000402 | 1 | 200 | 4/999996 |
| reversal | 1000000 | 32 | 0.000995 | 0.001387 | 1 | 200 | 4/999996 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000417 | 1 | 200 | 5/999995 |
| helix | 1000000 | 32 | 0.001001 | 0.002200 | 1 | 200 | 5/999995 |
| trinity | 1000000 | 32 | 0.000000 | 0.000402 | 1 | 200 | 5/999995 |
| reversal | 1000000 | 32 | 0.000991 | 0.001396 | 1 | 200 | 5/999995 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000417 | 1 | 200 | 6/999994 |
| helix | 1000000 | 32 | 0.001505 | 0.002205 | 1 | 200 | 6/999994 |
| trinity | 1000000 | 32 | 0.000999 | 0.000402 | 1 | 200 | 6/999994 |
| reversal | 1000000 | 32 | 0.000996 | 0.001477 | 1 | 200 | 6/999994 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000407 | 1 | 200 | 7/999993 |
| helix | 1000000 | 32 | 0.001503 | 0.002148 | 1 | 200 | 7/999993 |
| trinity | 1000000 | 32 | 0.000000 | 0.000417 | 1 | 200 | 7/999993 |
| reversal | 1000000 | 32 | 0.000980 | 0.001407 | 1 | 200 | 7/999993 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000410 | 1 | 200 | 8/999992 |
| helix | 1000000 | 32 | 0.001514 | 0.002167 | 1 | 200 | 8/999992 |
| trinity | 1000000 | 32 | 0.000000 | 0.000412 | 1 | 200 | 8/999992 |
| reversal | 1000000 | 32 | 0.000992 | 0.001405 | 1 | 200 | 8/999992 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.001003 | 0.000405 | 1 | 200 | 9/999991 |
| helix | 1000000 | 32 | 0.001504 | 0.002146 | 1 | 200 | 9/999991 |
| trinity | 1000000 | 32 | 0.000506 | 0.000970 | 1 | 200 | 9/999991 |
| reversal | 1000000 | 32 | 0.000989 | 0.001507 | 1 | 200 | 9/999991 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.001000 | 0.000597 | 1 | 200 | 333333/666667 |
| helix | 1000000 | 32 | 0.000992 | 0.001587 | 1 | 200 | 333333/666667 |
| trinity | 1000000 | 32 | 0.000998 | 0.001060 | 1 | 200 | 333333/666667 |
| reversal | 1000000 | 32 | 0.000994 | 0.001480 | 1 | 200 | 333333/666667 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000998 | 0.000958 | 1 | 200 | 333334/666666 |
| helix | 1000000 | 32 | 0.001991 | 0.002205 | 1 | 200 | 333334/666666 |
| trinity | 1000000 | 32 | 0.001000 | 0.001042 | 1 | 200 | 333334/666666 |
| reversal | 1000000 | 32 | 0.000997 | 0.001390 | 1 | 200 | 333334/666666 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000993 | 0.001040 | 1 | 200 | 333335/666665 |
| helix | 1000000 | 32 | 0.001505 | 0.002162 | 1 | 200 | 333335/666665 |
| trinity | 1000000 | 32 | 0.000503 | 0.001045 | 1 | 200 | 333335/666665 |
| reversal | 1000000 | 32 | 0.000988 | 0.001422 | 1 | 200 | 333335/666665 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000995 | 0.000980 | 1 | 200 | 333336/666664 |
| helix | 1000000 | 32 | 0.001507 | 0.002210 | 1 | 200 | 333336/666664 |
| trinity | 1000000 | 32 | 0.000999 | 0.001015 | 1 | 200 | 333336/666664 |
| reversal | 1000000 | 32 | 0.000993 | 0.001397 | 1 | 200 | 333336/666664 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000998 | 0.000955 | 1 | 200 | 333337/666663 |
| helix | 1000000 | 32 | 0.001000 | 0.002214 | 1 | 200 | 333337/666663 |
| trinity | 1000000 | 32 | 0.000996 | 0.000980 | 1 | 200 | 333337/666663 |
| reversal | 1000000 | 32 | 0.000997 | 0.001422 | 1 | 200 | 333337/666663 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000997 | 0.000850 | 1 | 200 | 500000/500000 |
| helix | 1000000 | 32 | 0.000993 | 0.001160 | 1 | 200 | 500000/500000 |
| trinity | 1000000 | 32 | 0.000999 | 0.000875 | 1 | 200 | 500000/500000 |
| reversal | 1000000 | 32 | 0.000996 | 0.001401 | 1 | 200 | 500000/500000 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.001002 | 0.000840 | 1 | 200 | 500001/499999 |
| helix | 1000000 | 32 | 0.001505 | 0.002304 | 1 | 200 | 500001/499999 |
| trinity | 1000000 | 32 | 0.000993 | 0.001025 | 1 | 200 | 500001/499999 |
| reversal | 1000000 | 32 | 0.000996 | 0.001371 | 1 | 200 | 500001/499999 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000998 | 0.000845 | 1 | 200 | 500002/499998 |
| helix | 1000000 | 32 | 0.001000 | 0.002200 | 1 | 200 | 500002/499998 |
| trinity | 1000000 | 32 | 0.001002 | 0.000845 | 1 | 200 | 500002/499998 |
| reversal | 1000000 | 32 | 0.000987 | 0.001417 | 1 | 200 | 500002/499998 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000994 | 0.000832 | 1 | 200 | 500003/499997 |
| helix | 1000000 | 32 | 0.001983 | 0.002277 | 1 | 200 | 500003/499997 |
| trinity | 1000000 | 32 | 0.000999 | 0.000910 | 1 | 200 | 500003/499997 |
| reversal | 1000000 | 32 | 0.000992 | 0.001460 | 1 | 200 | 500003/499997 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000999 | 0.000940 | 1 | 200 | 500004/499996 |
| helix | 1000000 | 32 | 0.001506 | 0.002340 | 1 | 200 | 500004/499996 |
| trinity | 1000000 | 32 | 0.000998 | 0.000885 | 1 | 200 | 500004/499996 |
| reversal | 1000000 | 32 | 0.000993 | 0.001370 | 1 | 200 | 500004/499996 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000909 | 1 | 200 | 500005/499995 |
| helix | 1000000 | 32 | 0.001000 | 0.002285 | 1 | 200 | 500005/499995 |
| trinity | 1000000 | 32 | 0.000992 | 0.001167 | 1 | 200 | 500005/499995 |
| reversal | 1000000 | 32 | 0.000995 | 0.001462 | 1 | 200 | 500005/499995 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000997 | 0.000857 | 1 | 200 | 500006/499994 |
| helix | 1000000 | 32 | 0.001976 | 0.002411 | 1 | 200 | 500006/499994 |
| trinity | 1000000 | 32 | 0.000907 | 0.001154 | 1 | 200 | 500006/499994 |
| reversal | 1000000 | 32 | 0.000994 | 0.001517 | 1 | 200 | 500006/499994 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.001000 | 0.000895 | 1 | 200 | 500007/499993 |
| helix | 1000000 | 32 | 0.001507 | 0.002325 | 1 | 200 | 500007/499993 |
| trinity | 1000000 | 32 | 0.000998 | 0.001022 | 1 | 200 | 500007/499993 |
| reversal | 1000000 | 32 | 0.000990 | 0.001415 | 1 | 200 | 500007/499993 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000999 | 0.000870 | 1 | 200 | 500008/499992 |
| helix | 1000000 | 32 | 0.001989 | 0.002260 | 1 | 200 | 500008/499992 |
| trinity | 1000000 | 32 | 0.000998 | 0.001040 | 1 | 200 | 500008/499992 |
| reversal | 1000000 | 32 | 0.000996 | 0.001397 | 1 | 200 | 500008/499992 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000999 | 0.000397 | 1 | 200 | 99999/900001 |
| helix | 1000000 | 32 | 0.001496 | 0.002165 | 1 | 200 | 99999/900001 |
| trinity | 1000000 | 32 | 0.000999 | 0.000985 | 1 | 200 | 99999/900001 |
| reversal | 1000000 | 32 | 0.000990 | 0.001382 | 1 | 200 | 99999/900001 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000999 | 0.000417 | 1 | 200 | 199998/800002 |
| helix | 1000000 | 32 | 0.001988 | 0.002210 | 1 | 200 | 199998/800002 |
| trinity | 1000000 | 32 | 0.000997 | 0.000967 | 1 | 200 | 199998/800002 |
| reversal | 1000000 | 32 | 0.000988 | 0.001415 | 1 | 200 | 199998/800002 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000557 | 1 | 200 | 299997/700003 |
| helix | 1000000 | 32 | 0.001514 | 0.002208 | 1 | 200 | 299997/700003 |
| trinity | 1000000 | 32 | 0.000999 | 0.001000 | 1 | 200 | 299997/700003 |
| reversal | 1000000 | 32 | 0.000989 | 0.001462 | 1 | 200 | 299997/700003 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000997 | 0.000817 | 1 | 200 | 399996/600004 |
| helix | 1000000 | 32 | 0.000999 | 0.002237 | 1 | 200 | 399996/600004 |
| trinity | 1000000 | 32 | 0.000983 | 0.001053 | 1 | 200 | 399996/600004 |
| reversal | 1000000 | 32 | 0.000989 | 0.001447 | 1 | 200 | 399996/600004 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000852 | 1 | 200 | 499995/500005 |
| helix | 1000000 | 32 | 0.001503 | 0.002237 | 1 | 200 | 499995/500005 |
| trinity | 1000000 | 32 | 0.000988 | 0.001035 | 1 | 200 | 499995/500005 |
| reversal | 1000000 | 32 | 0.000995 | 0.001467 | 1 | 200 | 499995/500005 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000820 | 1 | 200 | 599994/400006 |
| helix | 1000000 | 32 | 0.001990 | 0.002330 | 1 | 200 | 599994/400006 |
| trinity | 1000000 | 32 | 0.000995 | 0.001030 | 1 | 200 | 599994/400006 |
| reversal | 1000000 | 32 | 0.000506 | 0.001387 | 1 | 200 | 599994/400006 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000522 | 1 | 200 | 699993/300007 |
| helix | 1000000 | 32 | 0.001984 | 0.002322 | 1 | 200 | 699993/300007 |
| trinity | 1000000 | 32 | 0.000985 | 0.001100 | 1 | 200 | 699993/300007 |
| reversal | 1000000 | 32 | 0.000996 | 0.001397 | 1 | 200 | 699993/300007 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000372 | 1 | 200 | 799992/200008 |
| helix | 1000000 | 32 | 0.001512 | 0.002330 | 1 | 200 | 799992/200008 |
| trinity | 1000000 | 32 | 0.000993 | 0.001045 | 1 | 200 | 799992/200008 |
| reversal | 1000000 | 32 | 0.000997 | 0.001530 | 1 | 200 | 799992/200008 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.001001 | 0.000325 | 1 | 200 | 899991/100009 |
| helix | 1000000 | 32 | 0.001996 | 0.002327 | 1 | 200 | 899991/100009 |
| trinity | 1000000 | 32 | 0.000986 | 0.001054 | 1 | 200 | 899991/100009 |
| reversal | 1000000 | 32 | 0.000997 | 0.001382 | 1 | 200 | 899991/100009 |
| | | | | | | | |
| bridge | 1000000 | 32 | 0.000000 | 0.000290 | 1 | 200 | 999990/10 |
| helix | 1000000 | 32 | 0.001503 | 0.002337 | 1 | 200 | 999990/10 |
| trinity | 1000000 | 32 | 0.000994 | 0.001030 | 1 | 200 | 999990/10 |
| reversal | 1000000 | 32 | 0.000982 | 0.001387 | 1 | 200 | 999990/10 |
Overall performance:
trinity > helix > reversal > bridge
| Name | Items | Type | Best | Average | Loops | Samples | Distribution |
| --------- | -------- | ---- | -------- | -------- | --------- | ------- | ---------------- |
| contrev | 1000000 | 32 | 0.000996 | 0.001154 | 1 | 200 | 1/999999 |
| piston | 1000000 | 32 | 0.003001 | 0.004461 | 1 | 200 | 1/999999 |
|griesmills | 1000000 | 32 | 0.003503 | 0.004223 | 1 | 200 | 1/999999 |
| juggler | 1000000 | 32 | 0.000996 | 0.001255 | 1 | 200 | 1/999999 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000998 | 0.001050 | 1 | 200 | 1000/999000 |
| piston | 1000000 | 32 | 0.000984 | 0.001725 | 1 | 200 | 1000/999000 |
|griesmills | 1000000 | 32 | 0.000996 | 0.001647 | 1 | 200 | 1000/999000 |
| juggler | 1000000 | 32 | 0.000999 | 0.001969 | 1 | 200 | 1000/999000 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000996 | 0.001035 | 1 | 200 | 99999/900001 |
| piston | 1000000 | 32 | 0.000992 | 0.001677 | 1 | 200 | 99999/900001 |
|griesmills | 1000000 | 32 | 0.000988 | 0.001715 | 1 | 200 | 99999/900001 |
| juggler | 1000000 | 32 | 0.000997 | 0.001815 | 1 | 200 | 99999/900001 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.001000 | 0.000995 | 1 | 200 | 199998/800002 |
| piston | 1000000 | 32 | 0.000997 | 0.001722 | 1 | 200 | 199998/800002 |
|griesmills | 1000000 | 32 | 0.000998 | 0.002005 | 1 | 200 | 199998/800002 |
| juggler | 1000000 | 32 | 0.001002 | 0.002095 | 1 | 200 | 199998/800002 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.001002 | 0.000955 | 1 | 200 | 299997/700003 |
| piston | 1000000 | 32 | 0.000995 | 0.001627 | 1 | 200 | 299997/700003 |
|griesmills | 1000000 | 32 | 0.000997 | 0.001679 | 1 | 200 | 299997/700003 |
| juggler | 1000000 | 32 | 0.001506 | 0.002250 | 1 | 200 | 299997/700003 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000998 | 0.000960 | 1 | 200 | 399996/600004 |
| piston | 1000000 | 32 | 0.000911 | 0.001709 | 1 | 200 | 399996/600004 |
|griesmills | 1000000 | 32 | 0.000992 | 0.001742 | 1 | 200 | 399996/600004 |
| juggler | 1000000 | 32 | 0.001722 | 0.002256 | 1 | 200 | 399996/600004 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000997 | 0.001037 | 1 | 200 | 499995/500005 |
| piston | 1000000 | 32 | 0.000995 | 0.001812 | 1 | 200 | 499995/500005 |
|griesmills | 1000000 | 32 | 0.001995 | 0.002710 | 1 | 200 | 499995/500005 |
| juggler | 1000000 | 32 | 0.001978 | 0.002263 | 1 | 200 | 499995/500005 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000998 | 0.001072 | 1 | 200 | 1/999999 |
| piston | 1000000 | 32 | 0.003469 | 0.004402 | 1 | 200 | 1/999999 |
|griesmills | 1000000 | 32 | 0.003000 | 0.004301 | 1 | 200 | 1/999999 |
| juggler | 1000000 | 32 | 0.000508 | 0.001268 | 1 | 200 | 1/999999 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000999 | 0.001040 | 1 | 200 | 2/999998 |
| piston | 1000000 | 32 | 0.001998 | 0.004253 | 1 | 200 | 2/999998 |
|griesmills | 1000000 | 32 | 0.002511 | 0.003727 | 1 | 200 | 2/999998 |
| juggler | 1000000 | 32 | 0.000996 | 0.001437 | 1 | 200 | 2/999998 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000988 | 0.001053 | 1 | 200 | 3/999997 |
| piston | 1000000 | 32 | 0.003000 | 0.005062 | 1 | 200 | 3/999997 |
|griesmills | 1000000 | 32 | 0.001995 | 0.002855 | 1 | 200 | 3/999997 |
| juggler | 1000000 | 32 | 0.000995 | 0.001510 | 1 | 200 | 3/999997 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000996 | 0.001066 | 1 | 200 | 4/999996 |
| piston | 1000000 | 32 | 0.002999 | 0.004779 | 1 | 200 | 4/999996 |
|griesmills | 1000000 | 32 | 0.001992 | 0.002430 | 1 | 200 | 4/999996 |
| juggler | 1000000 | 32 | 0.000990 | 0.001382 | 1 | 200 | 4/999996 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000992 | 0.001068 | 1 | 200 | 5/999995 |
| piston | 1000000 | 32 | 0.002997 | 0.004117 | 1 | 200 | 5/999995 |
|griesmills | 1000000 | 32 | 0.001000 | 0.002137 | 1 | 200 | 5/999995 |
| juggler | 1000000 | 32 | 0.000982 | 0.001355 | 1 | 200 | 5/999995 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000997 | 0.000965 | 1 | 200 | 6/999994 |
| piston | 1000000 | 32 | 0.002000 | 0.003928 | 1 | 200 | 6/999994 |
|griesmills | 1000000 | 32 | 0.001002 | 0.002139 | 1 | 200 | 6/999994 |
| juggler | 1000000 | 32 | 0.000822 | 0.001412 | 1 | 200 | 6/999994 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000998 | 0.000990 | 1 | 200 | 7/999993 |
| piston | 1000000 | 32 | 0.002994 | 0.004123 | 1 | 200 | 7/999993 |
|griesmills | 1000000 | 32 | 0.000999 | 0.002022 | 1 | 200 | 7/999993 |
| juggler | 1000000 | 32 | 0.000991 | 0.001444 | 1 | 200 | 7/999993 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000000 | 0.001018 | 1 | 200 | 8/999992 |
| piston | 1000000 | 32 | 0.002995 | 0.003666 | 1 | 200 | 8/999992 |
|griesmills | 1000000 | 32 | 0.000998 | 0.002175 | 1 | 200 | 8/999992 |
| juggler | 1000000 | 32 | 0.000994 | 0.001440 | 1 | 200 | 8/999992 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000996 | 0.001016 | 1 | 200 | 9/999991 |
| piston | 1000000 | 32 | 0.001999 | 0.003753 | 1 | 200 | 9/999991 |
|griesmills | 1000000 | 32 | 0.000997 | 0.001902 | 1 | 200 | 9/999991 |
| juggler | 1000000 | 32 | 0.000910 | 0.001450 | 1 | 200 | 9/999991 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000983 | 0.000993 | 1 | 200 | 333333/666667 |
| piston | 1000000 | 32 | 0.001505 | 0.002467 | 1 | 200 | 333333/666667 |
|griesmills | 1000000 | 32 | 0.001993 | 0.002990 | 1 | 200 | 333333/666667 |
| juggler | 1000000 | 32 | 0.001000 | 0.002030 | 1 | 200 | 333333/666667 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000997 | 0.000970 | 1 | 200 | 333334/666666 |
| piston | 1000000 | 32 | 0.001001 | 0.002537 | 1 | 200 | 333334/666666 |
|griesmills | 1000000 | 32 | 0.001000 | 0.002120 | 1 | 200 | 333334/666666 |
| juggler | 1000000 | 32 | 0.000998 | 0.002044 | 1 | 200 | 333334/666666 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000999 | 0.000990 | 1 | 200 | 333335/666665 |
| piston | 1000000 | 32 | 0.001513 | 0.002423 | 1 | 200 | 333335/666665 |
|griesmills | 1000000 | 32 | 0.000997 | 0.001777 | 1 | 200 | 333335/666665 |
| juggler | 1000000 | 32 | 0.001000 | 0.002084 | 1 | 200 | 333335/666665 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000993 | 0.000999 | 1 | 200 | 333336/666664 |
| piston | 1000000 | 32 | 0.001992 | 0.002352 | 1 | 200 | 333336/666664 |
|griesmills | 1000000 | 32 | 0.000990 | 0.001723 | 1 | 200 | 333336/666664 |
| juggler | 1000000 | 32 | 0.001000 | 0.002103 | 1 | 200 | 333336/666664 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000995 | 0.001033 | 1 | 200 | 333337/666663 |
| piston | 1000000 | 32 | 0.001507 | 0.002306 | 1 | 200 | 333337/666663 |
|griesmills | 1000000 | 32 | 0.000997 | 0.001667 | 1 | 200 | 333337/666663 |
| juggler | 1000000 | 32 | 0.000999 | 0.002070 | 1 | 200 | 333337/666663 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.001000 | 0.000845 | 1 | 200 | 500000/500000 |
| piston | 1000000 | 32 | 0.000000 | 0.000847 | 1 | 200 | 500000/500000 |
|griesmills | 1000000 | 32 | 0.001000 | 0.000842 | 1 | 200 | 500000/500000 |
| juggler | 1000000 | 32 | 0.000998 | 0.001795 | 1 | 200 | 500000/500000 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000983 | 0.000999 | 1 | 200 | 500001/499999 |
| piston | 1000000 | 32 | 0.001987 | 0.003023 | 1 | 200 | 500001/499999 |
|griesmills | 1000000 | 32 | 0.001998 | 0.002638 | 1 | 200 | 500001/499999 |
| juggler | 1000000 | 32 | 0.000999 | 0.001965 | 1 | 200 | 500001/499999 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.001003 | 0.000959 | 1 | 200 | 500002/499998 |
| piston | 1000000 | 32 | 0.001000 | 0.002874 | 1 | 200 | 500002/499998 |
|griesmills | 1000000 | 32 | 0.000999 | 0.002040 | 1 | 200 | 500002/499998 |
| juggler | 1000000 | 32 | 0.001000 | 0.002060 | 1 | 200 | 500002/499998 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000999 | 0.000999 | 1 | 200 | 500003/499997 |
| piston | 1000000 | 32 | 0.001993 | 0.002638 | 1 | 200 | 500003/499997 |
|griesmills | 1000000 | 32 | 0.000997 | 0.001842 | 1 | 200 | 500003/499997 |
| juggler | 1000000 | 32 | 0.001000 | 0.002005 | 1 | 200 | 500003/499997 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000508 | 0.000985 | 1 | 200 | 500004/499996 |
| piston | 1000000 | 32 | 0.001988 | 0.002618 | 1 | 200 | 500004/499996 |
|griesmills | 1000000 | 32 | 0.000993 | 0.002035 | 1 | 200 | 500004/499996 |
| juggler | 1000000 | 32 | 0.001000 | 0.002037 | 1 | 200 | 500004/499996 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000994 | 0.000990 | 1 | 200 | 500005/499995 |
| piston | 1000000 | 32 | 0.001994 | 0.002528 | 1 | 200 | 500005/499995 |
|griesmills | 1000000 | 32 | 0.000997 | 0.001797 | 1 | 200 | 500005/499995 |
| juggler | 1000000 | 32 | 0.001000 | 0.002083 | 1 | 200 | 500005/499995 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000999 | 0.000985 | 1 | 200 | 500006/499994 |
| piston | 1000000 | 32 | 0.001997 | 0.002565 | 1 | 200 | 500006/499994 |
|griesmills | 1000000 | 32 | 0.000997 | 0.001845 | 1 | 200 | 500006/499994 |
| juggler | 1000000 | 32 | 0.001984 | 0.002188 | 1 | 200 | 500006/499994 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000508 | 0.001120 | 1 | 200 | 500007/499993 |
| piston | 1000000 | 32 | 0.001997 | 0.002655 | 1 | 200 | 500007/499993 |
|griesmills | 1000000 | 32 | 0.000998 | 0.001878 | 1 | 200 | 500007/499993 |
| juggler | 1000000 | 32 | 0.001994 | 0.002308 | 1 | 200 | 500007/499993 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000997 | 0.001024 | 1 | 200 | 500008/499992 |
| piston | 1000000 | 32 | 0.001506 | 0.002658 | 1 | 200 | 500008/499992 |
|griesmills | 1000000 | 32 | 0.000998 | 0.001864 | 1 | 200 | 500008/499992 |
| juggler | 1000000 | 32 | 0.001503 | 0.002200 | 1 | 200 | 500008/499992 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000897 | 0.001015 | 1 | 200 | 99999/900001 |
| piston | 1000000 | 32 | 0.000988 | 0.001670 | 1 | 200 | 99999/900001 |
|griesmills | 1000000 | 32 | 0.000988 | 0.001727 | 1 | 200 | 99999/900001 |
| juggler | 1000000 | 32 | 0.000997 | 0.001820 | 1 | 200 | 99999/900001 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000997 | 0.001003 | 1 | 200 | 199998/800002 |
| piston | 1000000 | 32 | 0.000992 | 0.001737 | 1 | 200 | 199998/800002 |
|griesmills | 1000000 | 32 | 0.001507 | 0.002105 | 1 | 200 | 199998/800002 |
| juggler | 1000000 | 32 | 0.001000 | 0.002062 | 1 | 200 | 199998/800002 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000991 | 0.001004 | 1 | 200 | 299997/700003 |
| piston | 1000000 | 32 | 0.000998 | 0.001617 | 1 | 200 | 299997/700003 |
|griesmills | 1000000 | 32 | 0.000988 | 0.001655 | 1 | 200 | 299997/700003 |
| juggler | 1000000 | 32 | 0.001507 | 0.002208 | 1 | 200 | 299997/700003 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000995 | 0.000990 | 1 | 200 | 399996/600004 |
| piston | 1000000 | 32 | 0.000997 | 0.001692 | 1 | 200 | 399996/600004 |
|griesmills | 1000000 | 32 | 0.000991 | 0.001747 | 1 | 200 | 399996/600004 |
| juggler | 1000000 | 32 | 0.001508 | 0.002141 | 1 | 200 | 399996/600004 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000993 | 0.000988 | 1 | 200 | 499995/500005 |
| piston | 1000000 | 32 | 0.000991 | 0.001737 | 1 | 200 | 499995/500005 |
|griesmills | 1000000 | 32 | 0.001993 | 0.002650 | 1 | 200 | 499995/500005 |
| juggler | 1000000 | 32 | 0.001503 | 0.002060 | 1 | 200 | 499995/500005 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000988 | 0.001030 | 1 | 200 | 599994/400006 |
| piston | 1000000 | 32 | 0.000991 | 0.001672 | 1 | 200 | 599994/400006 |
|griesmills | 1000000 | 32 | 0.000995 | 0.001727 | 1 | 200 | 599994/400006 |
| juggler | 1000000 | 32 | 0.001995 | 0.002303 | 1 | 200 | 599994/400006 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000991 | 0.001035 | 1 | 200 | 699993/300007 |
| piston | 1000000 | 32 | 0.000996 | 0.001602 | 1 | 200 | 699993/300007 |
|griesmills | 1000000 | 32 | 0.000997 | 0.001647 | 1 | 200 | 699993/300007 |
| juggler | 1000000 | 32 | 0.002999 | 0.004158 | 1 | 200 | 699993/300007 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000993 | 0.001025 | 1 | 200 | 799992/200008 |
| piston | 1000000 | 32 | 0.000994 | 0.001655 | 1 | 200 | 799992/200008 |
|griesmills | 1000000 | 32 | 0.000997 | 0.001657 | 1 | 200 | 799992/200008 |
| juggler | 1000000 | 32 | 0.002506 | 0.003488 | 1 | 200 | 799992/200008 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000508 | 0.001055 | 1 | 200 | 899991/100009 |
| piston | 1000000 | 32 | 0.000996 | 0.001612 | 1 | 200 | 899991/100009 |
|griesmills | 1000000 | 32 | 0.000996 | 0.001645 | 1 | 200 | 899991/100009 |
| juggler | 1000000 | 32 | 0.002996 | 0.004048 | 1 | 200 | 899991/100009 |
| | | | | | | | |
| contrev | 1000000 | 32 | 0.000508 | 0.001065 | 1 | 200 | 999990/10 |
| piston | 1000000 | 32 | 0.000997 | 0.001915 | 1 | 200 | 999990/10 |
|griesmills | 1000000 | 32 | 0.002980 | 0.003693 | 1 | 200 | 999990/10 |
| juggler | 1000000 | 32 | 0.000999 | 0.001995 | 1 | 200 | 999990/10 |
Overall performance:
contrev > piston > griesmills > juggler
**Noted that performance may vary depending on the specific implemention and array size, from worst to best the order is:**
Juggling Rotation (juggler)
Gries-Mills Rotation (griesmills)
Successive Rotation (piston)
Bridge Rotation (bridge)
Triple Reversal Rotation (reversal)
Helix Rotation (helix)
Conjoined Triple Reversal Rotation (contrev)
Trinity Rotation (trinity)