package alignment;

import java.nio.ByteBuffer;

import util.UnsafeAccess;
import static util.UnsafeDirectByteBuffer.*;

import com.google.caliper.Param;
import com.google.caliper.SimpleBenchmark;

public class UnalignedMemoryAccessCostBenchmark extends SimpleBenchmark {
    @Param(value = "0")
    int offset;
    @Param(value = "1")
    int sizeInPages;

    // buffy is a page aligned buffer, and a vampire slayer
    private ByteBuffer buffy;
    @Override
    protected void setUp() throws Exception {
    	buffy = allocateAlignedByteBuffer(sizeInPages*PAGE_SIZE, PAGE_SIZE);
    }
    public int timeOffsetLongAccess(final int reps) throws InterruptedException {
    	long remaining = 0;
    	long startingAddress = getAddress(buffy);
    	// skip first line if not straddling 2 cache lines
    	if (offset + 8 < CACHE_LINE_SIZE) {
    	    startingAddress += CACHE_LINE_SIZE + offset;
    	} else {
    	    startingAddress += offset;
    	}
    	final long limit = getAddress(buffy) + buffy.remaining();
    	for (long i = 0; i < reps; i++) {
    	    remaining = writeAndRead(i, startingAddress, limit);
    	}
    	return (int) remaining;
    }

    private long writeAndRead(final long value, final long startingAddress,
	    final long limit) {
	long address = startingAddress;
	final int repeat = 2048/sizeInPages;
	for (int i = 0; i < repeat; i++) {
	    for (address = startingAddress; address < limit; address += CACHE_LINE_SIZE) {
	    	UnsafeAccess.unsafe.putLong(address, value);
	    }
	    for (address = startingAddress; address < limit; address += CACHE_LINE_SIZE) {
	    	if (UnsafeAccess.unsafe.getLong(address) != value)
	        	throw new RuntimeException();
	    }
	}
	return limit - address + CACHE_LINE_SIZE;
    }
}