|
|
|
@ -9,7 +9,7 @@ using LogicAPI.Server.Components;
|
|
|
|
|
using LogicAPI.Services;
|
|
|
|
|
using LogicWorld.Server.Circuitry;
|
|
|
|
|
|
|
|
|
|
namespace CriticalPathAnalyzer.Server {
|
|
|
|
|
namespace CriticalPathAnalyzer.Server.Tool {
|
|
|
|
|
public class ServerPathTracer {
|
|
|
|
|
// Reflection/Delegate access helpers:
|
|
|
|
|
private static readonly Func<InputPeg, Cluster> GetCluster;
|
|
|
|
@ -44,8 +44,6 @@ namespace CriticalPathAnalyzer.Server {
|
|
|
|
|
) {
|
|
|
|
|
response = null;
|
|
|
|
|
|
|
|
|
|
var clusterTime = new Dictionary<Cluster, int>();
|
|
|
|
|
|
|
|
|
|
CriticalPathAnalyzerServer.LoggerInstance.Info("Trace start");
|
|
|
|
|
|
|
|
|
|
// Validate, that the peg is actually existing:
|
|
|
|
@ -54,23 +52,41 @@ namespace CriticalPathAnalyzer.Server {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var clusterNodes = new List<ClusterNode>();
|
|
|
|
|
var nodeQueue = new Queue<ClusterNode>();
|
|
|
|
|
|
|
|
|
|
// An input peg, only has a single cluster.
|
|
|
|
|
// An output peg however can be connected to multiple clusters.
|
|
|
|
|
// It only makes sense to then select all these clusters as primary cluster.
|
|
|
|
|
var collectedClusters = new HashSet<Cluster>();
|
|
|
|
|
CollectMainClusters(start, collectedClusters);
|
|
|
|
|
|
|
|
|
|
CriticalPathAnalyzerServer.LoggerInstance.Info("collected main clusters");
|
|
|
|
|
CriticalPathAnalyzerServer.LoggerInstance.Info($"collected {collectedClusters.Count} main clusters");
|
|
|
|
|
|
|
|
|
|
// Collect clusters that get powered by the original cluster by fast buffers
|
|
|
|
|
var collectedDrains = new HashSet<Cluster>();
|
|
|
|
|
// Collect clusters that get powered by the original cluster using relays or fast buffers
|
|
|
|
|
var oneWayConnectedClusters = new HashSet<Cluster>();
|
|
|
|
|
var twoWayConnectedClusters = new HashSet<Cluster>();
|
|
|
|
|
foreach (Cluster cluster in collectedClusters) {
|
|
|
|
|
GetLinkedClusters(cluster, collectedDrains, GetFollowers);
|
|
|
|
|
GetLinkedClusters(cluster, oneWayConnectedClusters, twoWayConnectedClusters, GetFollowers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
collectedClusters.UnionWith(collectedDrains);
|
|
|
|
|
CriticalPathAnalyzerServer.LoggerInstance.Info(
|
|
|
|
|
$"collected {oneWayConnectedClusters.Count} one way linked clusters");
|
|
|
|
|
CriticalPathAnalyzerServer.LoggerInstance.Info(
|
|
|
|
|
$"collected {twoWayConnectedClusters.Count} two way linked clusters");
|
|
|
|
|
|
|
|
|
|
// collectedClusters.UnionWith(oneWayConnectedClusters);
|
|
|
|
|
collectedClusters.UnionWith(twoWayConnectedClusters);
|
|
|
|
|
|
|
|
|
|
CriticalPathAnalyzerServer.LoggerInstance.Info($"union {collectedClusters.Count} clusters");
|
|
|
|
|
|
|
|
|
|
CriticalPathAnalyzerServer.LoggerInstance.Info("collected linked clusters");
|
|
|
|
|
clusterNodes.Add(new ClusterNode() {
|
|
|
|
|
Index = clusterNodes.Count,
|
|
|
|
|
Clusters = collectedClusters.ToList(),
|
|
|
|
|
Time = 0,
|
|
|
|
|
PrevNodeStateId = null,
|
|
|
|
|
NextNodes = new Dictionary<int, int>(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var perimeterComponents = new HashSet<ComponentAddress>();
|
|
|
|
|
var collectedNextClusters = new HashSet<Cluster>();
|
|
|
|
@ -165,7 +181,8 @@ namespace CriticalPathAnalyzer.Server {
|
|
|
|
|
|
|
|
|
|
private static void GetLinkedClusters(
|
|
|
|
|
Cluster startingPoint,
|
|
|
|
|
HashSet<Cluster> collectedClusters,
|
|
|
|
|
HashSet<Cluster> oneWayConnectedClusters,
|
|
|
|
|
HashSet<Cluster> twoWayConnectedClusters,
|
|
|
|
|
Func<ClusterLinker, List<ClusterLinker>> linkedLinkerGetter
|
|
|
|
|
) {
|
|
|
|
|
var clustersToProcess = new Queue<ClusterLinker>();
|
|
|
|
@ -175,17 +192,26 @@ namespace CriticalPathAnalyzer.Server {
|
|
|
|
|
|
|
|
|
|
clustersToProcess.Enqueue(startingLinker);
|
|
|
|
|
// While the starting cluster is no source, the algorithm needs to skip it when encountered.
|
|
|
|
|
// collectedClusters.Add(startingPoint);
|
|
|
|
|
while (clustersToProcess.TryDequeue(out ClusterLinker linkerToCheck)) {
|
|
|
|
|
List<ClusterLinker> listOfLinkedLinkers = linkedLinkerGetter(linkerToCheck); // Is never null.
|
|
|
|
|
foreach (ClusterLinker linkedLinker in listOfLinkedLinkers) {
|
|
|
|
|
Cluster clusterOfLinkedLinker = linkedLinker.ClusterBeingLinked; // Should never be null.
|
|
|
|
|
if (collectedClusters.Add(clusterOfLinkedLinker)) {
|
|
|
|
|
List<ClusterLinker> listOfBackLinkers = linkedLinkerGetter(linkedLinker); // Is never null.
|
|
|
|
|
if (listOfBackLinkers.Contains(linkerToCheck)) {
|
|
|
|
|
// bidirectional - a relay
|
|
|
|
|
if (twoWayConnectedClusters.Add(clusterOfLinkedLinker)) {
|
|
|
|
|
// Element was not yet present in the array, so keep looking into it!
|
|
|
|
|
clustersToProcess.Enqueue(linkedLinker);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// unidirectional - a fast buffer
|
|
|
|
|
oneWayConnectedClusters.Add(clusterOfLinkedLinker);
|
|
|
|
|
// stop propagation
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
twoWayConnectedClusters.Remove(startingPoint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static ClusterDetails CollectClusterInformation(Cluster cluster) {
|