cdc.perfs.core.runtime.RuntimeEnvironment Maven / Gradle / Ivy
package cdc.perfs.core.runtime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import cdc.perfs.api.MeasureLevel;
import cdc.perfs.api.RuntimeManager;
import cdc.perfs.api.RuntimeProbe;
import cdc.perfs.api.Source;
import cdc.perfs.core.EnvironmentKind;
import cdc.perfs.core.impl.AbstractContext;
import cdc.perfs.core.impl.AbstractEnvironment;
import cdc.perfs.core.impl.SourceImpl;
import cdc.util.time.RefTime;
/**
* Implementation of Environment for runtime measures.
*
* @author Damien Carbonne
*
*/
public final class RuntimeEnvironment extends AbstractEnvironment implements RuntimeManager.RuntimeService {
static final RuntimeEnvironment INSTANCE = new RuntimeEnvironment();
/**
* Map of Threads to associated contexts.
*/
private final Map contexts = new HashMap<>();
/**
* Map of source names to dumb probes.
* When present, a source is associated to an array of dumb probes, one for
* each level.
*/
private final Map dumbs = new HashMap<>();
/**
* Collection of Contexts that can be safely used in a multi-threaded
* environment
*/
private final List safeContexts = new CopyOnWriteArrayList<>();
private RuntimeEnvironment() {
super(RefTime.REF_NANOS, RefTime.REF_INSTANT);
}
public static RuntimeEnvironment getInstance() {
return INSTANCE;
}
@Override
public EnvironmentKind getKind() {
return EnvironmentKind.RUNTIME;
}
@Override
public List extends AbstractContext> getContexts() {
return safeContexts;
}
@Override
public void removeDeadContexts() {
final ArrayList deads = new ArrayList<>();
for (final RuntimeContext context : safeContexts) {
if (!context.isAlive()) {
deads.add(context);
}
}
safeContexts.removeAll(deads);
}
@Override
public long getCurrentNanos() {
return System.nanoTime();
}
@Override
public long getElapsedNanos() {
return System.nanoTime() - refNanos;
}
/**
* Returns the RuntimeContext associated to calling thread.
*
* If necessary, a new context is created.
* If current thread was already associated to a context, this context is returned.
*
* @return The RuntimeContext associated to calling thread.
*/
public synchronized RuntimeContext getCurrentContext() {
final Thread thread = Thread.currentThread();
RuntimeContext context = contexts.get(thread);
if (context == null) {
context = new RuntimeContext(this, contexts.size() + 1, thread);
contexts.put(context.getThread(), context);
safeContexts.add(context);
fireContextCreation(context);
}
return context;
}
/**
* Creates a probe that can be used to create measures at a given level and
* associated to a source.
*
* @param source The source for which a probe must be created.
* @param level The level of generated measures.
* @return An appropriate probe (matching source and level).
*/
@Override
public RuntimeProbe createProbe(Source source,
MeasureLevel level) {
if (source.isEnabled(level)) {
return new RuntimeSmartProbe((SourceImpl) source, level);
} else {
return getDumbProbe((SourceImpl) source, level);
}
}
@Override
public RuntimeProbe createProbe(Source source) {
return createProbe(source, MeasureLevel.MINOR);
}
private RuntimeDumbProbe getDumbProbe(SourceImpl source,
MeasureLevel level) {
RuntimeDumbProbe[] probes = dumbs.get(source.getName());
if (probes == null) {
probes = new RuntimeDumbProbe[MeasureLevel.values().length];
dumbs.put(source.getName(), probes);
}
if (probes[level.ordinal()] == null) {
probes[level.ordinal()] = new RuntimeDumbProbe(source, level);
}
return probes[level.ordinal()];
}
}