From d9cd1beca2009b9b27ff8f63b99ea368854f2397 Mon Sep 17 00:00:00 2001 From: Markus Quaritsch <markus.quaritsch@tugraz.at> Date: Mon, 2 Nov 2015 17:40:15 +0100 Subject: [PATCH] refactoring: VectoRuns now use background worker, driving cycle has progress indicator, vectorun updates progress --- .../Models/Connector/Ports/ISimulationPort.cs | 1 + VectoCore/Models/Simulation/IVectoRun.cs | 4 +- .../Models/Simulation/Impl/JobContainer.cs | 115 +++++++++++++++++- VectoCore/Models/Simulation/Impl/VectoRun.cs | 11 +- .../Impl/DistanceBasedDrivingCycle.cs | 11 ++ .../Impl/EngineOnlyDrivingCycle.cs | 5 + .../Impl/TimeBasedDrivingCycle.cs | 5 + .../Integration/FullCycleDeclarationTest.cs | 4 +- 8 files changed, 146 insertions(+), 10 deletions(-) diff --git a/VectoCore/Models/Connector/Ports/ISimulationPort.cs b/VectoCore/Models/Connector/Ports/ISimulationPort.cs index 77026657a8..a30199ffef 100644 --- a/VectoCore/Models/Connector/Ports/ISimulationPort.cs +++ b/VectoCore/Models/Connector/Ports/ISimulationPort.cs @@ -33,5 +33,6 @@ namespace TUGraz.VectoCore.Models.Connector.Ports IResponse Request(Second absTime, Second dt); IResponse Initialize(); + double Progress { get; } } } \ No newline at end of file diff --git a/VectoCore/Models/Simulation/IVectoRun.cs b/VectoCore/Models/Simulation/IVectoRun.cs index eb359549ab..63a7b080ad 100644 --- a/VectoCore/Models/Simulation/IVectoRun.cs +++ b/VectoCore/Models/Simulation/IVectoRun.cs @@ -1,3 +1,5 @@ +using System.ComponentModel; + namespace TUGraz.VectoCore.Models.Simulation { /// <summary> @@ -8,7 +10,7 @@ namespace TUGraz.VectoCore.Models.Simulation /// <summary> /// Run the simulation. /// </summary> - void Run(); + void Run(BackgroundWorker worker = null); string Name { get; } diff --git a/VectoCore/Models/Simulation/Impl/JobContainer.cs b/VectoCore/Models/Simulation/Impl/JobContainer.cs index d399e270a4..6edded3df1 100644 --- a/VectoCore/Models/Simulation/Impl/JobContainer.cs +++ b/VectoCore/Models/Simulation/Impl/JobContainer.cs @@ -1,5 +1,8 @@ +using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; +using System.Threading; using System.Threading.Tasks; using TUGraz.VectoCore.Models.Simulation.Data; @@ -14,7 +17,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl /// </summary> public class JobContainer : LoggingObject { - private readonly List<IVectoRun> _runs = new List<IVectoRun>(); + internal readonly List<JobEntry> Runs = new List<JobEntry>(); private readonly SummaryFileWriter _sumWriter; private static int _jobNumber; @@ -31,32 +34,132 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl public void AddRun(IVectoRun run) { _jobNumber++; - _runs.Add(run); + Runs.Add(new JobEntry() { + Run = run, + Container = this, + }); } public void AddRuns(IEnumerable<IVectoRun> runs) { _jobNumber++; - _runs.AddRange(runs); + //Runs.AddRange(runs); + foreach (var run in runs) { + Runs.Add(new JobEntry() { + Run = run, + Container = this, + }); + } } public void AddRuns(SimulatorFactory factory) { factory.SumWriter = _sumWriter; factory.JobNumber = _jobNumber++; - _runs.AddRange(factory.SimulationRuns()); + AddRuns(factory.SimulationRuns()); } /// <summary> /// Execute all runs, waits until finished. /// </summary> - public void Execute() + public void Execute(bool multithreaded = true) { Log.Info("VectoRun started running. Executing Runs."); - Task.WaitAll(_runs.Select(r => Task.Factory.StartNew(r.Run)).ToArray()); + foreach (var job in Runs) { + job.Worker = new BackgroundWorker() { + WorkerSupportsCancellation = true, + WorkerReportsProgress = true, + }; + job.Worker.DoWork += job.DoWork; + job.Worker.ProgressChanged += job.ProgressChanged; + job.Worker.RunWorkerCompleted += job.RunWorkerCompleted; + if (multithreaded) { + job.Started = true; + job.Worker.RunWorkerAsync(); + } + } + if (!multithreaded) { + var entry = Runs.First(); + entry.Started = true; + entry.Worker.RunWorkerAsync(); + } + //Task.WaitAll(_runs.Select(r => Task.Factory.StartNew(r.Run)).ToArray()); _sumWriter.Finish(); } + + public void Cancel() + { + foreach (var job in Runs) { + if (job.Worker != null && job.Worker.WorkerSupportsCancellation) { + job.Worker.CancelAsync(); + } + } + } + + private static AutoResetEvent resetEvent = new AutoResetEvent(false); + + public void WaitFinished() + { + resetEvent.WaitOne(); + } + + + private void JobCompleted(JobEntry jobEntry) + { + var next = Runs.FirstOrDefault(x => x.Started == false); + if (next != null) { + next.Started = true; + next.Worker.RunWorkerAsync(); + } + if (Runs.Count(x => x.Done == true) == Runs.Count()) { + _sumWriter.Finish(); + resetEvent.Set(); + } + } + + public Dictionary<string, double> GetProgress() + { + return Runs.ToDictionary(jobEntry => jobEntry.Run.Name, jobEntry => jobEntry.Progress); + } + + public bool AllCompleted + { + get { return (Runs.Count(x => x.Done == true) == Runs.Count()); } + } + + internal class JobEntry + { + public IVectoRun Run; + public JobContainer Container; + public double Progress; + public bool Done; + public bool Started; + public bool Success; + public bool Canceled; + + public BackgroundWorker Worker; + + public void DoWork(object sender, DoWorkEventArgs e) + { + var worker = sender as BackgroundWorker; + Run.Run(worker); + if (worker != null && worker.CancellationPending) { + e.Cancel = true; + Canceled = true; + } + Success = Run.FinishedWithoutErrors; + Done = true; + Container.JobCompleted(this); + } + + public void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {} + + public void ProgressChanged(object sender, ProgressChangedEventArgs e) + { + Progress = e.ProgressPercentage / 1000.0; + } + } } } \ No newline at end of file diff --git a/VectoCore/Models/Simulation/Impl/VectoRun.cs b/VectoCore/Models/Simulation/Impl/VectoRun.cs index d5e36a81ae..6280199125 100644 --- a/VectoCore/Models/Simulation/Impl/VectoRun.cs +++ b/VectoCore/Models/Simulation/Impl/VectoRun.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel; using TUGraz.VectoCore.Exceptions; using TUGraz.VectoCore.Models.Connector.Ports; using TUGraz.VectoCore.Models.Connector.Ports.Impl; @@ -37,7 +38,7 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl } - public void Run() + public void Run(BackgroundWorker worker = null) { Log.Info("VectoJob started running."); @@ -50,6 +51,14 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl Container.CommitSimulationStep(AbsTime, dt); AbsTime += dt; } + if (worker != null) { + worker.ReportProgress((int)(CyclePort.Progress * 1000)); + if (worker.CancellationPending) { + Log.Info("Background Task canceled!"); + Container.FinishSimulation(); + return; + } + } } while (response is ResponseSuccess); } catch (VectoSimulationException vse) { Log.Error("SIMULATION RUN ABORTED! ========================"); diff --git a/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs b/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs index f3c72f5885..fa9cdab03e 100644 --- a/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs +++ b/VectoCore/Models/SimulationComponent/Impl/DistanceBasedDrivingCycle.cs @@ -224,6 +224,17 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl CycleIntervalIterator.LeftSample.RoadGradient); } + public double Progress + { + get + { + return Data.Entries.Count > 0 + ? ((CurrentState.Distance - Data.Entries.First().Distance) / + (Data.Entries.Last().Distance - Data.Entries.First().Distance)).Value() + : 0; + } + } + public Meter CycleStartDistance { get { return Data.Entries.Count > 0 ? Data.Entries.First().Distance : 0.SI<Meter>(); } diff --git a/VectoCore/Models/SimulationComponent/Impl/EngineOnlyDrivingCycle.cs b/VectoCore/Models/SimulationComponent/Impl/EngineOnlyDrivingCycle.cs index 7f70161620..aa69f91b6b 100644 --- a/VectoCore/Models/SimulationComponent/Impl/EngineOnlyDrivingCycle.cs +++ b/VectoCore/Models/SimulationComponent/Impl/EngineOnlyDrivingCycle.cs @@ -75,6 +75,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl return NextComponent.Initialize(Data.Entries[index].EngineTorque, Data.Entries[index].EngineSpeed); } + public double Progress + { + get { throw new NotImplementedException(); } + } + public Meter StartDistance { get { throw new NotImplementedException(); } diff --git a/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs b/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs index 49c2374a05..e22232b233 100644 --- a/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs +++ b/VectoCore/Models/SimulationComponent/Impl/TimeBasedDrivingCycle.cs @@ -69,6 +69,11 @@ namespace TUGraz.VectoCore.Models.SimulationComponent.Impl throw new NotImplementedException(); } + public double Progress + { + get { throw new NotImplementedException(); } + } + public Meter StartDistance { get { return 0.SI<Meter>(); } diff --git a/VectoCoreTest/Integration/FullCycleDeclarationTest.cs b/VectoCoreTest/Integration/FullCycleDeclarationTest.cs index 317cb31e09..c09ae48552 100644 --- a/VectoCoreTest/Integration/FullCycleDeclarationTest.cs +++ b/VectoCoreTest/Integration/FullCycleDeclarationTest.cs @@ -131,8 +131,8 @@ namespace TUGraz.VectoCore.Tests.Integration jobContainer.Execute(); - foreach (var run in jobContainer._runs) { - Assert.IsTrue(run.FinishedWithoutErrors); + foreach (var run in jobContainer.Runs) { + Assert.IsTrue(run.Run.FinishedWithoutErrors); } } } -- GitLab