package com.bigdata.util.concurrent;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import com.bigdata.counters.CounterSet;
import com.bigdata.counters.Instrument;
import com.bigdata.journal.AbstractTask;
import com.bigdata.journal.ConcurrencyManager;
import com.bigdata.util.concurrent.IQueueCounters.ITaskCounters;
/**
* Class captures various data about the execution of {@link AbstractTask}s.
* These data are collected by the {@link ConcurrencyManager} in groups the
* different services on which the tasks are run.
* <p>
* Note: The field names here are consistent with those in the
* {@link ThreadPoolExecutorStatisticsTask}.
* <p>
* Note: The various counters are {@link AtomicLong}s since we need them to be
* thread-safe. (<code>counter++</code> and <code>counter+=foo</code> are
* NOT guaranteed to be thread-safe for simple fields or even
* <code>volatile</code> fields).
*
* @see ThreadPoolExecutorStatisticsTask
*/
public class TaskCounters {
public String toString() {
return getClass().getSimpleName() + //
"{#submit=" + taskSubmitCount + //
",#complete=" + taskCompleteCount + //
",#fail=" + taskFailCount + //
",#success=" + taskSuccessCount + //
",#queueWaitingTime=" + queueWaitingNanoTime + //
// ",#lockWaitingTime=" + lockWaitingNanoTime + //
",#serviceTime=" + serviceNanoTime + //
// ",#commitWaitingTime=" + commitWaitingNanoTime + //
// ",#commitServiceTime=" + commitServiceNanoTime + //
",#queuingTime=" + queuingNanoTime + //
"}";
}
/** #of tasks that have been submitted. */
final public AtomicLong taskSubmitCount = new AtomicLong();
/** #of tasks that have been completed. */
final public AtomicLong taskCompleteCount = new AtomicLong();
/** #of tasks that failed. */
final public AtomicLong taskFailCount = new AtomicLong();
/** #of tasks that succeeded. */
final public AtomicLong taskSuccessCount = new AtomicLong();
/**
* The timestamp in nanoseconds when the last task arrived.
*/
final public AtomicLong lastArrivalNanoTime = new AtomicLong();
/**
* Cumulative elapsed time in nanoseconds between the arrival of tasks.
*/
final public AtomicLong interArrivalNanoTime = new AtomicLong();
/**
* Cumulative elapsed time in nanoseconds waiting on the queue pending
* service.
*/
final public AtomicLong queueWaitingNanoTime = new AtomicLong();
/**
* Cumulative elapsed time in nanoseconds consumed by tasks while assigned
* to a worker thread.
* <p>
* Note: Since this is aggregated over concurrent tasks the reported elapsed
* time MAY exceed the actual elapsed time during which those tasks were
* executed.
* <p>
* Note: Service time on the client includes queuing time on the service and
* the checkpoint time (for write tasks).
*/
final public AtomicLong serviceNanoTime = new AtomicLong();
/**
* Cumulative elapsed time in nanoseconds consumed by write tasks while
* checkpointing their indices.
* <p>
* Note: Since this is aggregated over concurrent tasks the reported elapsed
* time MAY exceed the actual elapsed time during which those tasks were
* executed.
* <p>
* Note: This time is already reported by the {@link #serviceNanoTime} but
* is broken out here for additional detail. Checkpoint time can be most of
* the service time for a task since indices buffer writes and but are
* required to flush those writes to the backing during during a checkpoint.
*/
final public AtomicLong checkpointNanoTime = new AtomicLong();
/**
* Cumulative elapsed time in nanoseconds consumed by tasks from when they
* are submitted until they are complete.
* <p>
* Note: Queuing time on the client includes queuing time on the service.
*/
final public AtomicLong queuingNanoTime = new AtomicLong();
/** Ctor */
public TaskCounters() {
}
/**
* Note: The elapsed time counters ({@link #queueWaitingNanoTime},
* {@link #serviceNanoTime}, and {@link #queuingNanoTime}) are reported as
* cumulative <i>milliseconds</i> by this method. These data are turned
* into moving averages by the {@link ThreadPoolExecutorStatisticsTask}.
*/
public CounterSet getCounters() {
final CounterSet counterSet = new CounterSet();
// count of all tasks submitted to the service.
counterSet.addCounter(ITaskCounters.TaskSubmitCount,
new Instrument<Long>() {
public void sample() {
setValue(taskSubmitCount.get());
}
});
// count of all tasks completed by the service (failed + success).
counterSet.addCounter(ITaskCounters.TaskCompleteCount,
new Instrument<Long>() {
public void sample() {
setValue(taskCompleteCount.get());
}
});
// count of all tasks which failed during execution.
counterSet.addCounter(ITaskCounters.TaskFailCount,
new Instrument<Long>() {
public void sample() {
setValue(taskFailCount.get());
}
});
// count of all tasks which were successfully executed.
counterSet.addCounter(ITaskCounters.TaskSuccessCount,
new Instrument<Long>() {
public void sample() {
setValue(taskSuccessCount.get());
}
});
counterSet.addCounter(ITaskCounters.InterArrivalTime,
new Instrument<Long>() {
public void sample() {
setValue(TimeUnit.NANOSECONDS
.toMillis(interArrivalNanoTime.get()));
}
});
counterSet.addCounter(ITaskCounters.QueueWaitingTime,
new Instrument<Long>() {
public void sample() {
setValue(TimeUnit.NANOSECONDS
.toMillis(queueWaitingNanoTime.get()));
}
});
counterSet.addCounter(ITaskCounters.ServiceTime,
new Instrument<Long>() {
public void sample() {
setValue(TimeUnit.NANOSECONDS.toMillis(serviceNanoTime
.get()));
}
});
counterSet.addCounter(ITaskCounters.CheckpointTime,
new Instrument<Long>() {
public void sample() {
setValue(TimeUnit.NANOSECONDS.toMillis(checkpointNanoTime
.get()));
}
});
counterSet.addCounter(ITaskCounters.QueuingTime,
new Instrument<Long>() {
public void sample() {
setValue(TimeUnit.NANOSECONDS.toMillis(queuingNanoTime
.get()));
}
});
return counterSet;
}
}