| /** |
| ******************************************************************************** |
| * 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); |
| } |
| } |
| |
| } |