package org.eclipse.core.internal.runtime;
import java.io.PrintWriter;
import java.util.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.PerformanceStats.PerformanceListener;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.osgi.framework.log.FrameworkLog;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
public class PerformanceStatsProcessor extends Job {
private static final PerformanceStatsProcessor instance = new PerformanceStatsProcessor();
private static final long SCHEDULE_DELAY = 2000;
private final ArrayList<PerformanceStats> changes = new ArrayList<>();
private final HashMap<PerformanceStats,Long> failures = new HashMap<>();
private final ListenerList<PerformanceListener> listeners = new ListenerList<>();
private FrameworkLog log;
public static void addListener(PerformanceListener listener) {
instance.listeners.add(listener);
}
public static void changed(PerformanceStats stats) {
synchronized (instance) {
instance.changes.add(stats);
}
instance.schedule(SCHEDULE_DELAY);
}
public static void failed(PerformanceStats stats, String pluginId, long elapsed) {
synchronized (instance) {
instance.failures.put(stats, Long.valueOf(elapsed));
}
instance.schedule(SCHEDULE_DELAY);
instance.logFailure(stats, pluginId, elapsed);
}
public static void printStats(PrintWriter out) {
long totalTime = 0;
int totalCount = 0;
PerformanceStats[] allStats = PerformanceStats.getAllStats();
for (PerformanceStats stats : allStats) {
totalTime += stats.getRunningTime();
totalCount += stats.getRunCount();
}
out.println("---------------------------------------------------------------");
for (PerformanceStats stats : allStats) {
out.print("Event: ");
out.print(stats.getEvent());
out.print(" Blame: ");
out.print(stats.getBlameString());
if (stats.getContext() != null) {
out.print(" Context: ");
out.print(stats.getContext());
}
out.println();
int runCount = stats.getRunCount();
if (runCount > 0) {
out.print("Run count: ");
out.print(Integer.toString(runCount));
out.print(" (");
out.print(Integer.toString((int) (runCount * 100.0 / totalCount)));
out.println(" % of total)");
}
long runTime = stats.getRunningTime();
if (runTime > 0) {
out.print("Duration (ms): ");
out.print(Long.toString(runTime));
out.print(" (");
out.print(Integer.toString((int) (runTime * 100.0 / totalTime)));
out.println(" % of total)");
}
out.println("");
}
}
public static void removeListener(PerformanceListener listener) {
instance.listeners.remove(listener);
}
private PerformanceStatsProcessor() {
super("Performance Stats");
setSystem(true);
setPriority(DECORATE);
BundleContext context = PlatformActivator.getContext();
String filter = '(' + FrameworkLog.SERVICE_PERFORMANCE + '=' + Boolean.TRUE + ')';
Collection<ServiceReference<FrameworkLog>> references;
FrameworkLog perfLog = null;
try {
references = context.getServiceReferences(FrameworkLog.class, filter);
if (references != null && !references.isEmpty()) {
perfLog = context.getService(references.iterator().next());
IPath logLocation = Platform.getLogFileLocation();
logLocation = logLocation.removeLastSegments(1).append("performance.log");
perfLog.setFile(logLocation.toFile(), false);
}
} catch (Exception e) {
IStatus error = new Status(IStatus.ERROR, Platform.PI_RUNTIME, 1, "Error loading performance log", e);
RuntimeLog.log(error);
}
if (perfLog == null)
perfLog = InternalPlatform.getDefault().getFrameworkLog();
log = perfLog;
}
private void logFailure(PerformanceStats stats, String pluginId, long elapsed) {
if (log == null)
return;
if (pluginId == null)
pluginId = Platform.PI_RUNTIME;
String msg = "Performance failure: " + stats.getEvent() + " blame: " + stats.getBlameString() + " context: " + stats.getContext() + " duration: " + elapsed;
Status status = new Status(IStatus.WARNING, pluginId, 1, msg, new RuntimeException());
log.log(new FrameworkLogEntry(status, status.getPlugin(), status.getSeverity(), status.getCode(), status.getMessage(), 0, status.getException(), null));
}
@Override
protected IStatus run(IProgressMonitor monitor) {
PerformanceStats[] events;
PerformanceStats[] failedEvents;
Long[] failedTimes;
synchronized (this) {
events = changes.toArray(new PerformanceStats[changes.size()]);
changes.clear();
failedEvents = failures.keySet().toArray(new PerformanceStats[failures.size()]);
failedTimes = failures.values().toArray(new Long[failures.size()]);
failures.clear();
}
for (PerformanceListener listener : listeners) {
if (events.length > 0)
listener.eventsOccurred(events);
for (int j = 0; j < failedEvents.length; j++)
listener.eventFailed(failedEvents[j], failedTimes[j].longValue());
}
schedule(SCHEDULE_DELAY);
return Status.OK_STATUS;
}
@Override
public boolean shouldRun() {
return !changes.isEmpty() || !failures.isEmpty();
}
}