// Path: src/main/java/com/db/logger/api/impl/logger/buffer/ICircularLongsBuffer.java
// public interface ICircularLongsBuffer {
// 
// 	/** @return in longs (8 bytes) */
// 	public int length();
// 
// 	public void put( final long position,
// 	                 final long value );
// 
// 	public void putOrdered( final long position,
// 	                        final long value );
// 
// 	public void putVolatile( final long position,
// 	                         final long value );
// 
// 	public long get( final long position );
// 
// 	public long getVolatile( final long position );
// }
// 
// Path: src/main/java/com/db/logger/api/impl/logger/buffer/UnsafeCircularLongsBuffer.java
// public class UnsafeCircularLongsBuffer implements ICircularLongsBuffer {
// 
// 	private final long[] array;
// 	private final transient int mask;
// 
// 	public UnsafeCircularLongsBuffer( final int length ) {
// 		checkArgument(
// 				( length & ( length - 1 ) ) == 0,
// 				"length(%s) must be 2^N", length
// 		);
// 		this.array = new long[length];
// 		this.mask = length - 1;
// 	}
// 
// 	public UnsafeCircularLongsBuffer( final int length,
// 	                                  final long fillWithValue ) {
// 		this( length );
// 		Arrays.fill( array, fillWithValue );
// 	}
// 
// 	@Override
// 	public int length() {
// 		return array.length;
// 	}
// 
// 	@Override
// 	public void put( final long position,
// 	                 final long value ) {
// 		final long rawIndex = rawIndex( index( position ) );
// 		UNSAFE.putLong( array, rawIndex, value );
// 	}
// 
// 	@Override
// 	public void putOrdered( final long position,
// 	                        final long value ) {
// 		final long rawIndex = rawIndex( index( position ) );
// 		UNSAFE.putOrderedLong( array, rawIndex, value );
// 	}
// 
// 	@Override
// 	public void putVolatile( final long position,
// 	                         final long value ) {
// 		final long rawIndex = rawIndex( index( position ) );
// 		UNSAFE.putLongVolatile( array, rawIndex, value );
// 	}
// 
// 	@Override
// 	public long get( final long position ) {
// 		final long rawIndex = rawIndex( index( position ) );
// 		return UNSAFE.getLong( array, rawIndex );
// 	}
// 
// 	@Override
// 	public long getVolatile( final long position ) {
// 		final long rawIndex = rawIndex( index( position ) );
// 		return UNSAFE.getLongVolatile( array, rawIndex );
// 	}
// 
// 	/*=================== DARK MAGIC =========================*/
// 
// 	private static final Unsafe UNSAFE = UnsafeHelper.unsafe();
// 	private static final int BASE_ARRAY_OFFSET;
// 	private static final int INDEX_SHIFT;
// 
// 	static {
// 		BASE_ARRAY_OFFSET = UNSAFE.arrayBaseOffset( long[].class );
// 		final int indexScale = UNSAFE.arrayIndexScale( long[].class );
// 		if( Integer.bitCount( indexScale ) != 1 ) {
// 			throw new AssertionError( "Array index scale " + indexScale + " must be power of 2" );
// 		}
// 		INDEX_SHIFT = Integer.numberOfTrailingZeros( indexScale );
// 	}
// 
// 	private static long rawIndex( final int index ) {
// 		return BASE_ARRAY_OFFSET + ( index << INDEX_SHIFT );
// 	}
// 
// 	private int index( final long position ) {
// 		return ( int ) ( position & mask );
// 	}
// }
// 
// Path: src/main/java/com/db/logger/api/impl/logger/RecordHelper.java
// public static long header( final RecordType type,
//                            final int formatId,
//                            final int argumentsCount ) {
// 	//[type x 15][formatId x 32][argumentsCount x 16]
// 	return ( ( ( long ) type.id() ) << 48 )
// 			| ( formatId << 16 )
// 			| argumentsCount;
// }


import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import com.db.logger.api.impl.logger.*;
import com.db.logger.api.impl.logger.buffer.ICircularLongsBuffer;
import com.db.logger.api.impl.logger.buffer.UnsafeCircularLongsBuffer;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.logic.BlackHole;
import static com.db.logger.api.impl.logger.RecordHelper.RecordType.LOG_RECORD;
import static com.db.logger.api.impl.logger.RecordHelper.header;
package com.db.logger.benchmarks;




/**
 * We use many (3) single-writer single-reader ring buffers, one per each
 * 'logging' thread, instead of one multi-writer single reader ring buffer
 * for all them at once.
 *
 * @author ruslan
 *         created 22.11.13 at 20:04
 */
@BenchmarkMode( { Mode.AverageTime } )
@OutputTimeUnit( TimeUnit.NANOSECONDS )
@State( Scope.Group )
public class MultiBuffersWriteAndDrainBenchmark {
	public static final int LENGTH_POW = Integer.getInteger( "length-pow", 14 );
	public static final int CELLS_PER_RECORD = Integer.getInteger( "cells-per-record", 8 );//8longs = 1 cache line
	public static final int WRITER_BACKOFF = Integer.getInteger( "writer-backoff", 20 );

	public static final WaitingStrategy WAITING_STRATEGY = new WaitingStrategy.LimitedSpinning( 1024 * 128 );

	public static final AtomicInteger ID_GENERATOR = new AtomicInteger( 1 );

	public static final Sequencer.Drainer DRAIN_DUMMY = new MCSDSequencer.Drainer() {
		@Override
		public int available( final long startSequence,
		                      final long sentinelSequence ) {
			return ( int ) ( sentinelSequence - startSequence );
		}
	};

	static {
// Path: src/main/java/com/db/logger/api/impl/logger/buffer/ICircularLongsBuffer.java
// public interface ICircularLongsBuffer {
// 
// 	/** @return in longs (8 bytes) */
// 	public int length();
// 
// 	public void put( final long position,
// 	                 final long value );
// 
// 	public void putOrdered( final long position,
// 	                        final long value );
// 
// 	public void putVolatile( final long position,
// 	                         final long value );
// 
// 	public long get( final long position );
// 
// 	public long getVolatile( final long position );
// }
// 
// Path: src/main/java/com/db/logger/api/impl/logger/buffer/UnsafeCircularLongsBuffer.java
// public class UnsafeCircularLongsBuffer implements ICircularLongsBuffer {
// 
// 	private final long[] array;
// 	private final transient int mask;
// 
// 	public UnsafeCircularLongsBuffer( final int length ) {
// 		checkArgument(
// 				( length & ( length - 1 ) ) == 0,
// 				"length(%s) must be 2^N", length
// 		);
// 		this.array = new long[length];
// 		this.mask = length - 1;
// 	}
// 
// 	public UnsafeCircularLongsBuffer( final int length,
// 	                                  final long fillWithValue ) {
// 		this( length );
// 		Arrays.fill( array, fillWithValue );
// 	}
// 
// 	@Override
// 	public int length() {
// 		return array.length;
// 	}
// 
// 	@Override
// 	public void put( final long position,
// 	                 final long value ) {
// 		final long rawIndex = rawIndex( index( position ) );
// 		UNSAFE.putLong( array, rawIndex, value );
// 	}
// 
// 	@Override
// 	public void putOrdered( final long position,
// 	                        final long value ) {
// 		final long rawIndex = rawIndex( index( position ) );
// 		UNSAFE.putOrderedLong( array, rawIndex, value );
// 	}
// 
// 	@Override
// 	public void putVolatile( final long position,
// 	                         final long value ) {
// 		final long rawIndex = rawIndex( index( position ) );
// 		UNSAFE.putLongVolatile( array, rawIndex, value );
// 	}
// 
// 	@Override
// 	public long get( final long position ) {
// 		final long rawIndex = rawIndex( index( position ) );
// 		return UNSAFE.getLong( array, rawIndex );
// 	}
// 
// 	@Override
// 	public long getVolatile( final long position ) {
// 		final long rawIndex = rawIndex( index( position ) );
// 		return UNSAFE.getLongVolatile( array, rawIndex );
// 	}
// 
// 	/*=================== DARK MAGIC =========================*/
// 
// 	private static final Unsafe UNSAFE = UnsafeHelper.unsafe();
// 	private static final int BASE_ARRAY_OFFSET;
// 	private static final int INDEX_SHIFT;
// 
// 	static {
// 		BASE_ARRAY_OFFSET = UNSAFE.arrayBaseOffset( long[].class );
// 		final int indexScale = UNSAFE.arrayIndexScale( long[].class );
// 		if( Integer.bitCount( indexScale ) != 1 ) {
// 			throw new AssertionError( "Array index scale " + indexScale + " must be power of 2" );
// 		}
// 		INDEX_SHIFT = Integer.numberOfTrailingZeros( indexScale );
// 	}
// 
// 	private static long rawIndex( final int index ) {
// 		return BASE_ARRAY_OFFSET + ( index << INDEX_SHIFT );
// 	}
// 
// 	private int index( final long position ) {
// 		return ( int ) ( position & mask );
// 	}
// }
// 
// Path: src/main/java/com/db/logger/api/impl/logger/RecordHelper.java
// public static long header( final RecordType type,
//                            final int formatId,
//                            final int argumentsCount ) {
// 	//[type x 15][formatId x 32][argumentsCount x 16]
// 	return ( ( ( long ) type.id() ) << 48 )
// 			| ( formatId << 16 )
// 			| argumentsCount;
// }


// Path: src/main/java/com/db/logger/benchmarks/MultiBuffersWriteAndDrainBenchmark.java
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import com.db.logger.api.impl.logger.*;
import com.db.logger.api.impl.logger.buffer.ICircularLongsBuffer;
import com.db.logger.api.impl.logger.buffer.UnsafeCircularLongsBuffer;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.logic.BlackHole;
import static com.db.logger.api.impl.logger.RecordHelper.RecordType.LOG_RECORD;
import static com.db.logger.api.impl.logger.RecordHelper.header;

package com.db.logger.benchmarks;




/**
 * We use many (3) single-writer single-reader ring buffers, one per each
 * 'logging' thread, instead of one multi-writer single reader ring buffer
 * for all them at once.
 *
 * @author ruslan
 *         created 22.11.13 at 20:04
 */
@BenchmarkMode( { Mode.AverageTime } )
@OutputTimeUnit( TimeUnit.NANOSECONDS )
@State( Scope.Group )
public class MultiBuffersWriteAndDrainBenchmark {
	public static final int LENGTH_POW = Integer.getInteger( "length-pow", 14 );
	public static final int CELLS_PER_RECORD = Integer.getInteger( "cells-per-record", 8 );//8longs = 1 cache line
	public static final int WRITER_BACKOFF = Integer.getInteger( "writer-backoff", 20 );

	public static final WaitingStrategy WAITING_STRATEGY = new WaitingStrategy.LimitedSpinning( 1024 * 128 );

	public static final AtomicInteger ID_GENERATOR = new AtomicInteger( 1 );

	public static final Sequencer.Drainer DRAIN_DUMMY = new MCSDSequencer.Drainer() {
		@Override
		public int available( final long startSequence,
		                      final long sentinelSequence ) {
			return ( int ) ( sentinelSequence - startSequence );
		}
	};

	static {
		System.out.printf( "len=2^%d, record=%d, payload=%d\n", LENGTH_POW, CELLS_PER_RECORD, WRITER_BACKOFF );