blob: 974b17797ec40449437a7c422f85bcbea224ac88 [file] [log] [blame]
/**
********************************************************************************
* Copyright (c) 2020 Eclipse APP4MC contributors.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************
*/
package org.eclipse.app4mc.atdb._import.btf;
import java.lang.reflect.InvocationTargetException;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.app4mc.atdb.ATDBConnection;
import org.eclipse.app4mc.atdb.MetricAggregation;
import org.eclipse.app4mc.atdb._import.btf.model.BTFCombiState;
import org.eclipse.app4mc.atdb._import.btf.model.BTFCountMetric;
import org.eclipse.app4mc.atdb._import.btf.model.BTFEntityState;
import org.eclipse.app4mc.atdb._import.btf.model.BTFEntityType;
import org.eclipse.app4mc.atdb._import.btf.model.BTFInterInstanceMetric;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.Enumerator;
import org.eclipse.jface.operation.IRunnableWithProgress;
public class ATDBMetricCalculator implements IRunnableWithProgress {
private final ATDBConnection con;
public ATDBMetricCalculator(final ATDBConnection con) {
this.con = con;
}
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException {
monitor.beginTask("Calculating metrics...", 100);
try {
final Statement statement = this.con.createStatement();
final PreparedStatement metricStmt = this.con.getPreparedStatementFor("INSERT INTO metric(name, dimension) VALUES(?, ?);");
final Set<String> entityInstanceTimeMetrics = new LinkedHashSet<>();
// for each state: add a '[state]Time' metric signifying how long the entity instance was in that state
for (final BTFEntityState state : BTFEntityState.actStates) {
entityInstanceTimeMetrics.add(state + "Time");
metricStmt.setString(1, state + "Time");
metricStmt.setString(2, "time");
metricStmt.addBatch();
final List<String> entityInstanceStateTimesQuerys = new ArrayList<>();
state.entityType2InOutEvents.forEach((entityType, inOut) -> {
// map and collect events as SQL list
final String incomingEvents = inOut.getKey().stream().map(e -> "'" + e.toString().toLowerCase() + "'").collect(Collectors.joining(", "));
// map and collect events as SQL list
final String outgoingEvents = inOut.getValue().stream().map(e -> "'" + e.toString().toLowerCase() + "'").collect(Collectors.joining(", "));
final String query = "SELECT"//
+ " entityId,"//
+ " entityInstance,"//
+ " IFNULL(SUM(CASE"//
+ " WHEN eventTypeId IN (SELECT id FROM eventType WHERE name IN (" + incomingEvents + ")) THEN -timestamp"//
+ " WHEN eventTypeId IN (SELECT id FROM eventType WHERE name IN (" + outgoingEvents + ")) THEN timestamp"//
+ " END), 0) " + state + "Time "//
+ "FROM " + entityType.getName() + "InstanceRuntimeTraceEvent GROUP BY entityId, entityInstance "//
+ "HAVING (SELECT isComplete FROM " + entityType.getName() + "InstanceTraceInfo WHERE "//
+ " entityId = " + entityType.getName() + "InstanceRuntimeTraceEvent.entityId AND "//
+ " entityInstance = " + entityType.getName() + "InstanceRuntimeTraceEvent.entityInstance)";
entityInstanceStateTimesQuerys.add(query);
});
final String entityInstanceMetricQuery = "INSERT INTO entityInstanceMetricValue SELECT "//
+ " entityId,"//
+ " entityInstance,"//
+ " (SELECT id FROM metric WHERE name = '" + state + "Time'),"//
+ " " + state + "Time FROM (" + String.join(" UNION ", entityInstanceStateTimesQuerys)//
+ ");";
statement.addBatch(entityInstanceMetricQuery);
}
// consider combi states for processes
for (final BTFCombiState cState : BTFCombiState.values()) {
entityInstanceTimeMetrics.add(cState + "Time");
metricStmt.setString(1, cState + "Time");
metricStmt.setString(2, "time");
metricStmt.addBatch();
final String stateTimes = cState.getStates().stream().map(s -> "'" + s + "Time'").collect(Collectors.joining(", "));
final String query = "INSERT INTO entityInstanceMetricValue SELECT\n"
+ " entityId,\n"
+ " entityInstance,\n"
+ " (SELECT id FROM metric WHERE name = '" + cState + "Time'),\n"
+ " SUM(value)\n"
+ "FROM entityInstanceMetricValue WHERE\n"
+ " metricId IN (SELECT id FROM metric WHERE name IN (" + stateTimes + ")) AND\n"
+ " (SELECT isComplete\n"
+ " FROM " + BTFEntityType.PROCESS.getName() + "InstanceTraceInfo\n"
+ " WHERE entityId = entityInstanceMetricValue.entityId AND\n"
+ " entityInstance = entityInstanceMetricValue.entityInstance\n"
+ " ) = 1\n"
+ "GROUP BY entityId, entityInstance;";
statement.addBatch(query);
}
// calculate inter-instance metrics
for (final BTFInterInstanceMetric metric : BTFInterInstanceMetric.values()) {
entityInstanceTimeMetrics.add(metric.toString());
metricStmt.setString(1, metric.toString());
metricStmt.setString(2, "time");
metricStmt.addBatch();
final List<String> iiMetricQueries = new ArrayList<>();
metric.entityType2FirstAndSecond.forEach((entityType, firstAndSecondInstEvent) -> {
final String query = "SELECT A.entityId, A.entityInstance, SUM(B.timestamp - A.timestamp) AS " + metric + " "//
+ "FROM (SELECT * FROM " + entityType.getName() + "InstanceRuntimeTraceEvent) AS A "//
+ "INNER JOIN " + entityType.getName() + "InstanceRuntimeTraceEvent AS B ON "//
+ " B.entityId = A.entityId AND B.entityInstance = A.entityInstance + 1 "//
+ " WHERE A.eventTypeId = (SELECT id FROM eventType WHERE name = '" + firstAndSecondInstEvent.getKey() + "') AND "//
+ " B.eventTypeId = (SELECT id FROM eventType WHERE name = '" + firstAndSecondInstEvent.getValue() + "') "//
+ " GROUP BY A.entityId, A.entityInstance "//
+ " HAVING (SELECT isComplete FROM " + entityType.getName() + "InstanceTraceInfo WHERE "//
+ " entityId = A.entityId AND "//
+ " entityInstance = A.entityInstance) AND "//
+ " (SELECT isComplete FROM " + entityType.getName() + "InstanceTraceInfo WHERE "//
+ " entityId = B.entityId AND "//
+ " entityInstance = B.entityInstance)";
iiMetricQueries.add(query);
});
statement.addBatch("INSERT INTO entityInstanceMetricValue SELECT "//
+ " entityId,"//
+ " entityInstance,"//
+ " (SELECT id FROM metric WHERE name = '" + metric + "'),"//
+ " " + metric + " FROM (" + String.join(" UNION ", iiMetricQueries)//
+ ");");
}
// calculate stimuli activate2activate distances
final Entry<Enumerator, Enumerator> activateEventPair = BTFInterInstanceMetric.activateToActivate.entityType2FirstAndSecond
.entrySet().iterator().next().getValue();
final String query = "SELECT A.sourceEntityId, A.sourceEntityInstance, SUM(B.timestamp - A.timestamp) AS "
+ BTFInterInstanceMetric.activateToActivate + "\n"//
+ "FROM (\n"
+ " SELECT * FROM " + BTFEntityType.PROCESS.getName() + "InstanceRuntimeTraceEvent) AS A "//
+ "INNER JOIN " + BTFEntityType.PROCESS.getName() + "InstanceRuntimeTraceEvent AS B ON "//
+ "B.entityId = A.entityId AND B.entityInstance = A.entityInstance + 1\n"//
+ " WHERE A.eventTypeId = (SELECT id FROM eventType WHERE name = '" + activateEventPair.getKey() + "') AND\n"//
+ " B.eventTypeId = (SELECT id FROM eventType WHERE name = '" + activateEventPair.getValue() + "') AND\n"//
+ " A.sourceEntityId = B.sourceEntityId\n"//
+ " GROUP BY A.sourceEntityId, A.sourceEntityInstance HAVING\n"
+ " (SELECT isComplete FROM " + BTFEntityType.PROCESS.getName() + "InstanceTraceInfo WHERE "//
+ "entityId = A.entityId AND entityInstance = A.entityInstance) AND\n"//
+ " (SELECT isComplete FROM " + BTFEntityType.PROCESS.getName() + "InstanceTraceInfo WHERE "//
+ "entityId = B.entityId AND entityInstance = B.entityInstance)";
statement.addBatch("INSERT INTO entityInstanceMetricValue SELECT\n"//
+ " sourceEntityId,\n"//
+ " sourceEntityInstance,\n"//
+ " (SELECT id FROM metric WHERE name = '" + BTFInterInstanceMetric.activateToActivate + "'),\n"//
+ " " + BTFInterInstanceMetric.activateToActivate + "\n"
+ "FROM (" + query//
+ ");");
// calculate entity metrics min max avg for all time metric values
for (final String entityInstanceTimeMetric : entityInstanceTimeMetrics) {
for (final MetricAggregation kind : MetricAggregation.values()) {
metricStmt.setString(1, entityInstanceTimeMetric + "_" + kind);
metricStmt.setString(2, "time");
metricStmt.addBatch();
}
}
for (final MetricAggregation kind : MetricAggregation.values()) {
statement.addBatch("INSERT INTO entityMetricValue SELECT "//
+ " entityId,"//
+ " (SELECT id FROM metric WHERE name = (SELECT name FROM metric WHERE id = metricId) || '_" + kind + "'),"//
+ " " + kind.getSQLStr("value") + " FROM entityInstanceMetricValue WHERE "//
+ "metricId IN (SELECT id FROM metric WHERE dimension = 'time') GROUP BY entityId, metricId;");
}
// insert entity specific count metrics
for (final BTFCountMetric cm : BTFCountMetric.values()) {
metricStmt.setString(1, cm.toString());
metricStmt.setString(2, "count");
metricStmt.addBatch();
statement.addBatch("INSERT INTO entityMetricValue SELECT "//
+ " entityId,"//
+ " (SELECT id FROM metric WHERE name = '" + cm + "') AS metricId,"//
+ " SUM(" + cm.eventToCount.toString().toLowerCase() + "EventCount) AS value "//
+ "FROM " + cm.entityType.getName() + "InstanceTraceInfo GROUP BY entityId;");
}
// execute all statements
this.con.executeBatchStatements(metricStmt);
monitor.worked(70);
this.con.executeBatchStatements(statement);
monitor.worked(30);
} catch (SQLException e) {
throw new InvocationTargetException(e);
}
}
}