Skip to content
Snippets Groups Projects
Commit a7da2c1f authored by Christian Wulf's avatar Christian Wulf
Browse files

added performance test for circular access

parent 73e698db
Branches
Tags
No related merge requests found
......@@ -28,11 +28,12 @@ import java.util.Arrays;
*
* @param <T>
*/
public class CircularArray<T> {
public final class CircularArray<T> {
private final long logSize;
private final T[] segment;
private final long mask;
private long currentIndex;
/**
*
......@@ -54,6 +55,12 @@ public class CircularArray<T> {
return this.segment[(int) (i & this.mask)]; // risk of overflow
}
public T getNext() {
long index = this.currentIndex;
this.currentIndex = (this.currentIndex + 1) & this.mask;
return this.segment[(int) index];
}
public void put(final long i, final T o) {
this.segment[(int) (i & this.mask)] = o; // risk of overflow
}
......
/***************************************************************************
* Copyright 2014 Kieker Project (http://kieker-monitoring.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
package teetime.util.concurrent.workstealing;
import java.util.Arrays;
/**
*
* @author Christian Wulf
*
* @see "Dynamic Circular WorkStealing Deque"
*
* @since 1.10
*
* @param <T>
*/
public final class CircularIntArray<T> {
private final int logSize;
private final T[] segment;
private final int mask;
private int currentIndex;
/**
*
* @param logSize
* The initial size of this array in log2, i.e., the number of bits to use
*/
@SuppressWarnings("unchecked")
public CircularIntArray(final int logSize) {
this.logSize = logSize;
this.segment = (T[]) new Object[1 << this.logSize];
this.mask = this.getCapacity() - 1; // mask = 0..01..1
}
public int getCapacity() {
return this.segment.length;
}
public T get(final int i) {
return this.segment[i & this.mask]; // risk of overflow
}
public T getNext() {
int index = this.currentIndex;
this.currentIndex = (this.currentIndex + 1) & this.mask;
return this.segment[index];
}
public void put(final int i, final T o) {
this.segment[i & this.mask] = o; // risk of overflow
}
public CircularIntArray<T> grow(final int b, final int t) {
final CircularIntArray<T> a = new CircularIntArray<T>(this.logSize + 1);
for (int i = t; i < b; i++) {
a.put(i, this.get(i));
}
return a;
}
public CircularIntArray<T> shrink(final int b, final int t) {
final CircularIntArray<T> a = new CircularIntArray<T>(this.logSize - 1);
for (int i = t; i < b; i++) {
a.put(i, this.get(i));
}
return a;
}
@Override
public String toString() {
return Arrays.toString(this.segment);
}
}
/***************************************************************************
* Copyright 2014 Kieker Project (http://kieker-monitoring.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
package teetime.util.concurrent.workstealing;
import java.util.Arrays;
/**
*
* @author Christian Wulf
*
* @see "Dynamic Circular WorkStealing Deque"
*
* @since 1.10
*
* @param <T>
*/
public final class CircularModIntArray<T> {
private final int logSize;
private final T[] segment;
private final int size;
private int currentIndex;
/**
*
* @param logSize
* The initial size of this array in log2, i.e., the number of bits to use
*/
@SuppressWarnings("unchecked")
public CircularModIntArray(final int logSize) {
this.logSize = logSize;
this.segment = (T[]) new Object[1 << this.logSize];
this.size = this.segment.length;
}
public int getCapacity() {
return this.segment.length;
}
public T get(final int i) {
return this.segment[i % this.size]; // risk of overflow
}
public T getNext() {
int index = this.currentIndex;
this.currentIndex = (this.currentIndex + 1) % this.size;
return this.segment[index];
}
public void put(final int i, final T o) {
this.segment[i % this.size] = o; // risk of overflow
}
public CircularModIntArray<T> grow(final int b, final int t) {
final CircularModIntArray<T> a = new CircularModIntArray<T>(this.logSize + 1);
for (int i = t; i < b; i++) {
a.put(i, this.get(i));
}
return a;
}
public CircularModIntArray<T> shrink(final int b, final int t) {
final CircularModIntArray<T> a = new CircularModIntArray<T>(this.logSize - 1);
for (int i = t; i < b; i++) {
a.put(i, this.get(i));
}
return a;
}
@Override
public String toString() {
return Arrays.toString(this.segment);
}
}
package teetime.util.list;
public final class CircularList<T> {
private static final class Node<T> {
T value;
Node<T> next;
}
private Node<T> headNode;
private Node<T> lastNode;
private Node<T> currentNode;
public void add(final T value) {
Node<T> newNode = new Node<T>();
newNode.value = value;
if (this.headNode == null) { // newNode is the first node
this.headNode = this.lastNode = newNode;
this.currentNode = newNode;
}
this.lastNode.next = newNode;
newNode.next = this.headNode;
}
public T getNext() {
T value = this.currentNode.value;
this.currentNode = this.currentNode.next;
return value;
}
}
package teetime.util;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.lessThan;
import static org.junit.Assert.assertThat;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import org.junit.runners.MethodSorters;
import teetime.util.concurrent.workstealing.CircularArray;
import teetime.util.concurrent.workstealing.CircularIntArray;
import teetime.util.concurrent.workstealing.CircularModIntArray;
import teetime.util.list.CircularList;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class CircularCollectionsTest {
private static final int NUM_OBJECTS_TO_CREATE_IN_POW2 = 2;
private static final int NUM_OBJECTS_TO_CREATE = (int) Math.pow(2, NUM_OBJECTS_TO_CREATE_IN_POW2);
private static final int NUM_ACCESSES = 100000000;
private static final int WARMUP_ITERATIONS = 3;
private static final Map<String, Long> durations = new LinkedHashMap<String, Long>();
private StopWatch stopWatch;
protected Description description;
@Before
public void setup() {
this.stopWatch = new StopWatch();
}
@Rule
public final TestRule watcher = new TestWatcher() {
@Override
protected void starting(final Description description) {
CircularCollectionsTest.this.description = description;
}
};
@After
public void tearDown() {
CircularCollectionsTest.durations.put(this.description.getDisplayName(), this.stopWatch.getDurationInNs());
}
@Test
public void testCircularIntArray() throws Exception {
CircularIntArray<Object> circularArray = new CircularIntArray<Object>(NUM_OBJECTS_TO_CREATE_IN_POW2);
for (int i = 0; i < NUM_OBJECTS_TO_CREATE; i++) {
circularArray.put(i, new Object());
}
int warmupIterations = WARMUP_ITERATIONS;
while (warmupIterations-- > 0) {
for (int i = 0; i < NUM_ACCESSES; i++) {
circularArray.getNext().toString();
}
}
this.stopWatch.start();
for (int i = 0; i < NUM_ACCESSES; i++) {
circularArray.getNext().toString();
}
this.stopWatch.end();
}
@Test
public void testCircularModIntArray() throws Exception {
CircularModIntArray<Object> circularArray = new CircularModIntArray<Object>(NUM_OBJECTS_TO_CREATE_IN_POW2);
for (int i = 0; i < NUM_OBJECTS_TO_CREATE; i++) {
circularArray.put(i, new Object());
}
int warmupIterations = WARMUP_ITERATIONS;
while (warmupIterations-- > 0) {
for (int i = 0; i < NUM_ACCESSES; i++) {
circularArray.getNext().toString();
}
}
this.stopWatch.start();
for (int i = 0; i < NUM_ACCESSES; i++) {
circularArray.getNext().toString();
}
this.stopWatch.end();
}
@Test
public void testCircularList() throws Exception {
CircularList<Object> circularList = new CircularList<Object>();
for (int i = 0; i < NUM_OBJECTS_TO_CREATE; i++) {
circularList.add(new Object());
}
int warmupIterations = WARMUP_ITERATIONS;
while (warmupIterations-- > 0) {
for (int i = 0; i < NUM_ACCESSES; i++) {
circularList.getNext().toString();
}
}
this.stopWatch.start();
for (int i = 0; i < NUM_ACCESSES; i++) {
circularList.getNext().toString();
}
this.stopWatch.end();
}
@Test
public void testCircularLongArray() throws Exception {
CircularArray<Object> circularArray = new CircularArray<Object>(NUM_OBJECTS_TO_CREATE_IN_POW2);
for (int i = 0; i < NUM_OBJECTS_TO_CREATE; i++) {
circularArray.put(i, new Object());
}
int warmupIterations = WARMUP_ITERATIONS;
while (warmupIterations-- > 0) {
for (int i = 0; i < NUM_ACCESSES; i++) {
circularArray.getNext().toString();
}
}
this.stopWatch.start();
for (int i = 0; i < NUM_ACCESSES; i++) {
circularArray.getNext().toString();
}
this.stopWatch.end();
}
@AfterClass
public static void afterClass() {
Long circularIntArrayInNs = durations.get("testCircularIntArray(teetime.util.CircularCollectionsTest)");
Long circularModIntArrayInNs = durations.get("testCircularModIntArray(teetime.util.CircularCollectionsTest)");
Long circularListInNs = durations.get("testCircularList(teetime.util.CircularCollectionsTest)");
Long circularLongArrayInNs = durations.get("testCircularLongArray(teetime.util.CircularCollectionsTest)");
for (Entry<String, Long> entry : durations.entrySet()) {
System.out.println(entry.getKey() + ": " + TimeUnit.NANOSECONDS.toMillis(entry.getValue()) + " ms");
}
assertThat(circularListInNs, is(lessThan(circularModIntArrayInNs)));
// testCircularIntArray(teetime.util.CircularCollectionsTest): 13202 ms
// testCircularList(teetime.util.CircularCollectionsTest): 13957 ms
// testCircularLongArray(teetime.util.CircularCollectionsTest): 12620 ms
// testCircularModIntArray(teetime.util.CircularCollectionsTest): 14015 ms
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment