cdc.perfs.core.impl.AbstractMeasure Maven / Gradle / Ivy
package cdc.perfs.core.impl;
import cdc.perfs.api.MeasureLevel;
import cdc.perfs.core.Environment;
import cdc.perfs.core.Measure;
import cdc.perfs.core.MeasureStatus;
import cdc.perfs.core.SpanPosition;
import cdc.util.lang.ByteMasks;
/**
* Base implementation of Measure.
*
* Measures are associated to a Context (Thread) and are organized as a forest.
*
* @author Damien Carbonne
*/
public abstract class AbstractMeasure implements Measure {
/**
* Cached values of MeasureStatus to avoid frequent clones.
*/
private static final MeasureStatus[] MEASURE_STATUS_VALUES = MeasureStatus.values();
/**
* Cached values of MeasureLevel to avoid frequent clones.
*/
private static final MeasureLevel[] MEASURE_LEVEL_VALUES = MeasureLevel.values();
/** Associated source. */
private final SourceImpl source;
/** Detail of the measure. Given by the probe at measure initialization. */
private final String details;
/** First child measure (is null if no child). */
private AbstractMeasure firstChild = null;
/** Next sibling measure (is null if last sibling). */
private AbstractMeasure nextSibling = null;
/** Absolute start 'time' of the measure. */
protected final long begin;
/**
* Absolute end 'time' of the measure.
*
* Meaningful when the measure is frozen.
*/
protected long end;
private final int depth;
/** Mask for status and level. */
private byte bits = 0;
protected AbstractMeasure(AbstractMeasure parent,
AbstractMeasure previous,
SourceImpl source,
String details,
long begin,
long end,
MeasureStatus status,
MeasureLevel level,
AbstractContext context) {
this.source = source;
this.details = details;
this.begin = begin;
this.end = end;
setStatus(status);
setLevel(level);
if (parent == null) {
context.roots.add(this);
this.depth = 0;
} else if (previous == null) {
parent.firstChild = this;
this.depth = parent.depth + 1;
} else {
previous.nextSibling = this;
this.depth = parent.depth + 1;
}
context.incrementMeasuresCount();
source.incrementMeasuresCount();
}
@Override
public final Environment getEnvironment() {
return getSource().getEnvironment();
}
@Override
public final SourceImpl getSource() {
return source;
}
@Override
public final String getDetails() {
return details;
}
protected final void setStatus(MeasureStatus value) {
bits = ByteMasks.set(bits, 0, value, MEASURE_STATUS_VALUES, true);
}
@Override
public final MeasureStatus getStatus() {
return ByteMasks.get(bits, 0, MEASURE_STATUS_VALUES, true);
}
private final void setLevel(MeasureLevel value) {
bits = ByteMasks.set(bits, 2, value, MEASURE_LEVEL_VALUES, true);
}
@Override
public final MeasureLevel getLevel() {
return ByteMasks.get(bits, 2, MEASURE_LEVEL_VALUES, true);
}
@Override
public final String getLabel() {
if (details == null) {
return getSource().getName();
} else {
return getSource().getName() + "." + details;
}
}
@Override
public final int getDepth() {
return depth;
}
@Override
public final int getHeight() {
int max = 0;
for (AbstractMeasure child = firstChild; child != null; child = child.nextSibling) {
max = Math.max(max, child.getHeight());
}
return max + 1;
}
@Override
public final long getAbsoluteBeginNanos() {
return begin;
}
@Override
public long getRelativeBeginNanos() {
return getEnvironment().toRelative(begin);
}
@Override
public final long getAbsoluteEndNanos() {
return end;
}
@Override
public long getAbsoluteEndOrCurrentNanos() {
if (getStatus() == MeasureStatus.RUNNING) {
return getEnvironment().getCurrentNanos();
} else {
return end;
}
}
@Override
public final long getRelativeEndNanos() {
return getEnvironment().toRelative(end);
}
@Override
public final long getRelativeEndOrCurrentNanos() {
if (getStatus() == MeasureStatus.RUNNING) {
return getEnvironment().getElapsedNanos();
} else {
return getEnvironment().toRelative(end);
}
}
@Override
public final AbstractMeasure getFirstChild() {
return firstChild;
}
@Override
public final int getChildrenCount() {
int count = 0;
AbstractMeasure child = firstChild;
while (child != null) {
count++;
child = child.nextSibling;
}
return count;
}
@Override
public final AbstractMeasure getChild(int index) {
int count = 0;
AbstractMeasure child = firstChild;
while (count < index && child != null) {
count++;
child = child.nextSibling;
}
return child;
}
@Override
public final AbstractMeasure getLastChild() {
AbstractMeasure child = firstChild;
if (child != null) {
while (child.nextSibling != null) {
child = child.nextSibling;
}
}
return child;
}
@Override
public final AbstractMeasure getNextSibling() {
return nextSibling;
}
@Override
public final AbstractMeasure getFirstChild(long inf,
long sup) {
if (sup < inf) {
return null;
} else {
AbstractMeasure child = firstChild;
while (child != null) {
if (child.getAbsoluteBeginNanos() <= sup && child.getAbsoluteEndNanos() >= inf) {
return child;
}
child = child.nextSibling;
}
return null;
}
}
@Override
public final AbstractMeasure getFirstSubChild(int level,
long inf,
long sup) {
AbstractMeasure result = this;
for (int index = 0; index < level && result != null; index++) {
result = result.getFirstChild(inf, sup);
}
return result;
}
@Override
public final SpanPosition getPosition(long inf,
long sup) {
if (begin > sup) {
return SpanPosition.OUTSIDE;
} else {
final long cend = getAbsoluteEndOrCurrentNanos();
if (cend < inf) {
return SpanPosition.OUTSIDE;
} else if (inf <= begin && cend <= sup) {
return SpanPosition.INSIDE;
} else {
return SpanPosition.OVERLAP;
}
}
}
public final int compareToNano(long nanos) {
if (nanos < begin) {
return 1;
} else if (nanos > end) {
return -1;
} else {
return 0;
}
}
/**
* Remove all children measures if this measure is not RUNNING.
*/
public final void safeRemoveChildren() {
if (getStatus() != MeasureStatus.RUNNING) {
removeChildren();
}
}
private void removeChildren() {
if (firstChild != null) {
assert getStatus() != MeasureStatus.RUNNING;
for (AbstractMeasure child = firstChild; child != null; child = child.nextSibling) {
child.removeChildren();
}
AbstractMeasure current = firstChild;
final AbstractMeasure next = current.nextSibling;
while (current != null) {
current.nextSibling = null;
current = next;
}
firstChild = null;
}
}
protected final void freezeLastChild(long end) {
AbstractMeasure child = firstChild;
if (child != null) {
while (child.nextSibling != null) {
child = child.nextSibling;
}
if (child.getStatus() == MeasureStatus.RUNNING) {
child.end = end;
child.setStatus(MeasureStatus.FROZEN_ON_ERROR);
child.freezeLastChild(end);
}
}
}
public final int compareToAbsolute(long time) {
if (time < begin) {
return 1;
} else if (time > getAbsoluteEndOrCurrentNanos()) {
return -1;
} else {
return 0;
}
}
@Override
public String toString() {
return "[" + getSource() + " " + getDetails() + " " + getStatus() + " " + getLevel() + "]";
}
}