[5602] | 1 | #region License Information
|
---|
| 2 | /* HeuristicLab
|
---|
| 3 | * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
|
---|
| 4 | *
|
---|
| 5 | * This file is part of HeuristicLab.
|
---|
| 6 | *
|
---|
| 7 | * HeuristicLab is free software: you can redistribute it and/or modify
|
---|
| 8 | * it under the terms of the GNU General Public License as published by
|
---|
| 9 | * the Free Software Foundation, either version 3 of the License, or
|
---|
| 10 | * (at your option) any later version.
|
---|
| 11 | *
|
---|
| 12 | * HeuristicLab is distributed in the hope that it will be useful,
|
---|
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 15 | * GNU General Public License for more details.
|
---|
| 16 | *
|
---|
| 17 | * You should have received a copy of the GNU General Public License
|
---|
| 18 | * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
|
---|
| 19 | */
|
---|
| 20 | #endregion
|
---|
| 21 |
|
---|
[5955] | 22 | using System;
|
---|
| 23 | using System.Collections.Generic;
|
---|
| 24 | using System.ComponentModel;
|
---|
| 25 | using System.Linq;
|
---|
| 26 | using HeuristicLab.Clients.Hive.Jobs;
|
---|
[5614] | 27 | using HeuristicLab.Common;
|
---|
[5955] | 28 | using HeuristicLab.Core;
|
---|
| 29 | using HeuristicLab.Optimization;
|
---|
[6006] | 30 | using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
|
---|
[5602] | 31 |
|
---|
| 32 | namespace HeuristicLab.Clients.Hive {
|
---|
[6006] | 33 | [StorableClass]
|
---|
[5955] | 34 | public partial class HiveExperiment : IDeepCloneable, IContent, IProgressReporter {
|
---|
| 35 | private JobResultPoller jobResultPoller;
|
---|
[5602] | 36 |
|
---|
[6006] | 37 | [Storable]
|
---|
[5955] | 38 | private bool useLocalPlugins;
|
---|
| 39 | public bool UseLocalPlugins {
|
---|
| 40 | get { return useLocalPlugins; }
|
---|
| 41 | set { useLocalPlugins = value; }
|
---|
| 42 | }
|
---|
[5602] | 43 |
|
---|
[6006] | 44 | [Storable]
|
---|
[5955] | 45 | private ExecutionState executionState;
|
---|
| 46 | public ExecutionState ExecutionState {
|
---|
| 47 | get { return executionState; }
|
---|
| 48 | internal set {
|
---|
| 49 | if (executionState != value) {
|
---|
| 50 | executionState = value;
|
---|
| 51 | OnExecutionStateChanged();
|
---|
| 52 | }
|
---|
| 53 | }
|
---|
| 54 | }
|
---|
| 55 |
|
---|
[6006] | 56 | [Storable]
|
---|
[5955] | 57 | private TimeSpan executionTime;
|
---|
| 58 | public TimeSpan ExecutionTime {
|
---|
| 59 | get { return executionTime; }
|
---|
| 60 | internal set {
|
---|
| 61 | if (executionTime != value) {
|
---|
| 62 | executionTime = value;
|
---|
| 63 | OnExecutionTimeChanged();
|
---|
| 64 | }
|
---|
| 65 | }
|
---|
| 66 | }
|
---|
| 67 |
|
---|
[6006] | 68 | [Storable]
|
---|
| 69 | private ItemCollection<HiveJob> hiveJobs;
|
---|
| 70 | public ItemCollection<HiveJob> HiveJobs {
|
---|
| 71 | get { return hiveJobs; }
|
---|
[5955] | 72 | set {
|
---|
[6006] | 73 | DeregisterHiveJobsEvents();
|
---|
| 74 | if (hiveJobs != value) {
|
---|
| 75 | hiveJobs = value;
|
---|
| 76 | RegisterHiveJobsEvents();
|
---|
| 77 | OnHiveJobsChanged();
|
---|
[5955] | 78 | }
|
---|
| 79 | }
|
---|
| 80 | }
|
---|
| 81 |
|
---|
[6006] | 82 | [Storable]
|
---|
[5955] | 83 | private bool isProgressing;
|
---|
| 84 | public bool IsProgressing {
|
---|
| 85 | get { return isProgressing; }
|
---|
| 86 | set {
|
---|
| 87 | if (isProgressing != value) {
|
---|
| 88 | isProgressing = value;
|
---|
| 89 | OnIsProgressingChanged();
|
---|
| 90 | }
|
---|
| 91 | }
|
---|
| 92 | }
|
---|
| 93 |
|
---|
| 94 | /** include jobs when refreshing **/
|
---|
[6006] | 95 | [Storable]
|
---|
[5955] | 96 | private bool includeJobs;
|
---|
| 97 | public bool IncludeJobs {
|
---|
| 98 | get { return includeJobs; }
|
---|
| 99 | set { includeJobs = value; }
|
---|
| 100 | }
|
---|
| 101 |
|
---|
[6006] | 102 | [Storable]
|
---|
[5955] | 103 | private bool refreshAutomatically;
|
---|
| 104 | public bool RefreshAutomatically {
|
---|
| 105 | get { return refreshAutomatically; }
|
---|
| 106 | set {
|
---|
| 107 | if (refreshAutomatically != value) {
|
---|
| 108 | refreshAutomatically = value;
|
---|
| 109 | OnRefreshAutomaticallyChanged();
|
---|
| 110 | if (RefreshAutomatically) {
|
---|
| 111 | StartResultPolling();
|
---|
| 112 | } else {
|
---|
| 113 | StopResultPolling();
|
---|
| 114 | }
|
---|
| 115 | }
|
---|
| 116 | }
|
---|
| 117 | }
|
---|
| 118 |
|
---|
[6006] | 119 | [Storable]
|
---|
[5955] | 120 | private IProgress progress;
|
---|
| 121 | public IProgress Progress {
|
---|
| 122 | get { return progress; }
|
---|
| 123 | set { this.progress = value; }
|
---|
| 124 | }
|
---|
| 125 |
|
---|
| 126 | #region Constructors and Cloning
|
---|
| 127 | public HiveExperiment() {
|
---|
| 128 | this.ResourceNames = "HEAL";
|
---|
| 129 | this.includeJobs = true;
|
---|
| 130 | this.refreshAutomatically = true;
|
---|
| 131 | }
|
---|
| 132 |
|
---|
[5614] | 133 | protected HiveExperiment(HiveExperiment original, Cloner cloner) {
|
---|
[5779] | 134 | cloner.RegisterClonedObject(original, this);
|
---|
[5614] | 135 | this.OwnerUserId = original.OwnerUserId;
|
---|
| 136 | this.DateCreated = original.DateCreated;
|
---|
| 137 | this.ResourceNames = original.ResourceNames;
|
---|
| 138 | this.LastAccessed = original.LastAccessed;
|
---|
| 139 | this.Name = original.Name;
|
---|
| 140 | this.Description = original.Description;
|
---|
| 141 | this.Id = original.Id;
|
---|
[5955] | 142 |
|
---|
| 143 | this.UseLocalPlugins = original.UseLocalPlugins;
|
---|
| 144 | this.ExecutionTime = original.ExecutionTime;
|
---|
[5614] | 145 | }
|
---|
[5955] | 146 | public override IDeepCloneable Clone(Cloner cloner) {
|
---|
[5614] | 147 | return new HiveExperiment(this, cloner);
|
---|
| 148 | }
|
---|
[5955] | 149 | #endregion
|
---|
[5614] | 150 |
|
---|
| 151 | public override string ToString() {
|
---|
[5955] | 152 | return Name;
|
---|
[5614] | 153 | }
|
---|
| 154 |
|
---|
[5955] | 155 | #region Events
|
---|
| 156 | public event EventHandler ExecutionTimeChanged;
|
---|
| 157 | private void OnExecutionTimeChanged() {
|
---|
| 158 | EventHandler handler = ExecutionTimeChanged;
|
---|
| 159 | if (handler != null) handler(this, EventArgs.Empty);
|
---|
[5614] | 160 | }
|
---|
[5955] | 161 |
|
---|
| 162 | public event EventHandler ExecutionStateChanged;
|
---|
| 163 | private void OnExecutionStateChanged() {
|
---|
| 164 | EventHandler handler = ExecutionStateChanged;
|
---|
| 165 | if (handler != null) handler(this, EventArgs.Empty);
|
---|
| 166 | }
|
---|
| 167 |
|
---|
[6006] | 168 | public event EventHandler HiveJobsChanged;
|
---|
| 169 | private void OnHiveJobsChanged() {
|
---|
[5955] | 170 | if (jobResultPoller != null && jobResultPoller.IsPolling) {
|
---|
| 171 | jobResultPoller.Stop();
|
---|
| 172 | DeregisterResultPollingEvents();
|
---|
| 173 | }
|
---|
[6006] | 174 | if (HiveJobs != null && HiveJobs.Count > 0 && GetAllHiveJobs().All(x => x.Job.Id != Guid.Empty)) {
|
---|
[5955] | 175 | if (this.RefreshAutomatically)
|
---|
| 176 | StartResultPolling();
|
---|
| 177 | }
|
---|
[6006] | 178 | EventHandler handler = HiveJobsChanged;
|
---|
[5955] | 179 | if (handler != null) handler(this, EventArgs.Empty);
|
---|
| 180 | }
|
---|
| 181 |
|
---|
| 182 | public event EventHandler IsProgressingChanged;
|
---|
| 183 | private void OnIsProgressingChanged() {
|
---|
| 184 | EventHandler handler = IsProgressingChanged;
|
---|
| 185 | if (handler != null) handler(this, EventArgs.Empty);
|
---|
| 186 | }
|
---|
| 187 |
|
---|
| 188 | public event EventHandler RefreshAutomaticallyChanged;
|
---|
| 189 | private void OnRefreshAutomaticallyChanged() {
|
---|
| 190 | EventHandler handler = RefreshAutomaticallyChanged;
|
---|
| 191 | if (handler != null) handler(this, EventArgs.Empty);
|
---|
| 192 | }
|
---|
| 193 | #endregion
|
---|
| 194 |
|
---|
[6006] | 195 | private void RegisterHiveJobsEvents() {
|
---|
| 196 | //if (HiveJobs != null) {
|
---|
| 197 | // HiveJobs.JobStateChanged += new EventHandler(HiveJob_JobStateChanged);
|
---|
| 198 | //}
|
---|
[5955] | 199 | }
|
---|
| 200 |
|
---|
[6006] | 201 | private void DeregisterHiveJobsEvents() {
|
---|
| 202 | //if (HiveJobs != null) {
|
---|
| 203 | // HiveJobs.JobStateChanged -= new EventHandler(HiveJob_JobStateChanged);
|
---|
| 204 | //}
|
---|
[5955] | 205 | }
|
---|
| 206 |
|
---|
| 207 | private void HiveJob_JobStateChanged(object sender, EventArgs e) {
|
---|
[6006] | 208 | //if (this.HiveJobs != null) {
|
---|
| 209 | // this.RootJobId = HiveJobs.Job.Id;
|
---|
| 210 | //}
|
---|
[5955] | 211 | }
|
---|
| 212 |
|
---|
[6006] | 213 | public Experiment GetExperiment(int idx) {
|
---|
| 214 | if (this.HiveJobs != null) {
|
---|
| 215 | var hj = HiveJobs.ElementAtOrDefault(idx);
|
---|
| 216 | if (hj != null)
|
---|
| 217 | return hj.OptimizerJob.OptimizerAsExperiment;
|
---|
[5955] | 218 | }
|
---|
| 219 | return null;
|
---|
| 220 | }
|
---|
| 221 |
|
---|
[6006] | 222 | public void AddExperiment(Experiment experiment) {
|
---|
| 223 | if (this.HiveJobs == null)
|
---|
| 224 | this.HiveJobs = new ItemCollection<HiveJob>();
|
---|
| 225 | this.HiveJobs.Add(new HiveJob(experiment));
|
---|
| 226 | }
|
---|
| 227 |
|
---|
[5955] | 228 | public void SetExperiment(Experiment experiment) {
|
---|
[6006] | 229 | if (this.HiveJobs == null)
|
---|
| 230 | this.HiveJobs = new ItemCollection<HiveJob>();
|
---|
| 231 | else
|
---|
| 232 | this.HiveJobs.Clear();
|
---|
| 233 | this.HiveJobs.Add(new HiveJob(experiment));
|
---|
[5955] | 234 | }
|
---|
| 235 |
|
---|
| 236 | protected override void OnPropertyChanged(PropertyChangedEventArgs e) {
|
---|
| 237 | base.OnPropertyChanged(e);
|
---|
| 238 | if (e.PropertyName == "Name") {
|
---|
| 239 | OnToStringChanged();
|
---|
| 240 | }
|
---|
| 241 | }
|
---|
| 242 |
|
---|
| 243 | #region JobResultPoller Events
|
---|
| 244 |
|
---|
| 245 | public void StartResultPolling() {
|
---|
| 246 | if (jobResultPoller == null) {
|
---|
[6006] | 247 | jobResultPoller = new JobResultPoller(HiveJobs, /*ApplicationConstants.ResultPollingInterval*/new TimeSpan(0, 0, 5)); //TODO: find a better place for ApplicationConstants
|
---|
[5955] | 248 | RegisterResultPollingEvents();
|
---|
| 249 | }
|
---|
| 250 |
|
---|
| 251 | if (!jobResultPoller.IsPolling) {
|
---|
| 252 | jobResultPoller.Start();
|
---|
| 253 | }
|
---|
| 254 | }
|
---|
| 255 |
|
---|
| 256 | public void StopResultPolling() {
|
---|
[6006] | 257 | if (jobResultPoller != null && jobResultPoller.IsPolling) {
|
---|
[5955] | 258 | jobResultPoller.Stop();
|
---|
| 259 | }
|
---|
| 260 | }
|
---|
| 261 |
|
---|
| 262 | private void RegisterResultPollingEvents() {
|
---|
| 263 | jobResultPoller.ExceptionOccured += new EventHandler<EventArgs<Exception>>(jobResultPoller_ExceptionOccured);
|
---|
| 264 | jobResultPoller.JobResultsReceived += new EventHandler<EventArgs<IEnumerable<LightweightJob>>>(jobResultPoller_JobResultReceived);
|
---|
| 265 | jobResultPoller.IsPollingChanged += new EventHandler(jobResultPoller_IsPollingChanged);
|
---|
| 266 | }
|
---|
| 267 | private void DeregisterResultPollingEvents() {
|
---|
| 268 | jobResultPoller.ExceptionOccured -= new EventHandler<EventArgs<Exception>>(jobResultPoller_ExceptionOccured);
|
---|
| 269 | jobResultPoller.JobResultsReceived -= new EventHandler<EventArgs<IEnumerable<LightweightJob>>>(jobResultPoller_JobResultReceived);
|
---|
| 270 | jobResultPoller.IsPollingChanged -= new EventHandler(jobResultPoller_IsPollingChanged);
|
---|
| 271 | }
|
---|
| 272 | private void jobResultPoller_IsPollingChanged(object sender, EventArgs e) {
|
---|
| 273 | this.refreshAutomatically = jobResultPoller.IsPolling;
|
---|
| 274 | OnRefreshAutomaticallyChanged();
|
---|
| 275 | }
|
---|
| 276 | private void jobResultPoller_JobResultReceived(object sender, EventArgs<IEnumerable<LightweightJob>> e) {
|
---|
| 277 | foreach (LightweightJob lightweightJob in e.Value) {
|
---|
[6006] | 278 | HiveJob hj = GetHiveJobById(lightweightJob.Id);
|
---|
[5955] | 279 | if (hj != null) {
|
---|
| 280 | DateTime lastJobDataUpdate = hj.Job.LastJobDataUpdate;
|
---|
| 281 | hj.UpdateFromLightweightJob(lightweightJob);
|
---|
| 282 |
|
---|
| 283 | // lastJobDataUpdate equals DateTime.MinValue right after it was uploaded. When the first results are polled, this value is updated
|
---|
| 284 | if (lastJobDataUpdate != DateTime.MinValue && lastJobDataUpdate < hj.Job.LastJobDataUpdate) {
|
---|
| 285 | OptimizerJob optimizerJob = ExperimentManagerClient.LoadOptimizerJob(hj.Job.Id);
|
---|
| 286 | if (optimizerJob == null) {
|
---|
| 287 | // something bad happened to this job. bad job, BAAAD job!
|
---|
| 288 | } else {
|
---|
| 289 | // if the job is paused, download but don't integrate into parent optimizer (to avoid Prepare)
|
---|
| 290 | if (hj.Job.State == JobState.Paused) {
|
---|
| 291 | hj.OptimizerJob = optimizerJob;
|
---|
| 292 | } else {
|
---|
| 293 | if (lightweightJob.ParentJobId.HasValue) {
|
---|
[6006] | 294 | HiveJob parentHiveJob = GetHiveJobById(lightweightJob.ParentJobId.Value);
|
---|
[5955] | 295 | parentHiveJob.UpdateChildOptimizer(optimizerJob, hj.Job.Id);
|
---|
| 296 | }
|
---|
| 297 | }
|
---|
| 298 | }
|
---|
| 299 | }
|
---|
| 300 | }
|
---|
| 301 | }
|
---|
| 302 | GC.Collect(); // force GC, because .NET is too lazy here (deserialization takes a lot of memory)
|
---|
| 303 | if (AllJobsFinished()) {
|
---|
| 304 | this.ExecutionState = Core.ExecutionState.Stopped;
|
---|
| 305 | StopResultPolling();
|
---|
| 306 | //OnStopped();
|
---|
| 307 | }
|
---|
| 308 | UpdateTotalExecutionTime();
|
---|
| 309 | UpdateStats();
|
---|
| 310 | }
|
---|
| 311 |
|
---|
[6006] | 312 | public HiveJob GetHiveJobById(Guid jobId) {
|
---|
| 313 | foreach (HiveJob job in HiveJobs) {
|
---|
| 314 | HiveJob hj = job.GetHiveJobByJobId(jobId);
|
---|
| 315 | if (hj != null)
|
---|
| 316 | return hj;
|
---|
| 317 | }
|
---|
| 318 | return null;
|
---|
| 319 | }
|
---|
| 320 |
|
---|
[5955] | 321 | private void UpdateStats() {
|
---|
[6006] | 322 | var jobs = GetAllHiveJobs();
|
---|
[5955] | 323 | this.JobCount = jobs.Count();
|
---|
| 324 | this.CalculatingCount = jobs.Count(j => j.Job.State == JobState.Calculating);
|
---|
| 325 | this.FinishedCount = jobs.Count(j => j.Job.State == JobState.Finished);
|
---|
| 326 | }
|
---|
| 327 |
|
---|
[6006] | 328 | public IEnumerable<HiveJob> GetAllHiveJobs() {
|
---|
| 329 | var jobs = new List<HiveJob>();
|
---|
| 330 | foreach (HiveJob job in HiveJobs) {
|
---|
| 331 | jobs.AddRange(job.GetAllHiveJobs());
|
---|
| 332 | }
|
---|
| 333 | return jobs;
|
---|
| 334 | }
|
---|
| 335 |
|
---|
| 336 | public bool AllJobsFinished() {
|
---|
| 337 | return GetAllHiveJobs().All(j => j.Job.State == JobState.Finished
|
---|
[5955] | 338 | || j.Job.State == JobState.Aborted
|
---|
| 339 | || j.Job.State == JobState.Failed);
|
---|
| 340 | }
|
---|
| 341 |
|
---|
| 342 | private void jobResultPoller_ExceptionOccured(object sender, EventArgs<Exception> e) {
|
---|
| 343 | //OnExceptionOccured(e.Value);
|
---|
| 344 | }
|
---|
| 345 |
|
---|
| 346 | public void UpdateTotalExecutionTime() {
|
---|
[6006] | 347 | this.ExecutionTime = TimeSpan.FromMilliseconds(GetAllHiveJobs().Sum(x => x.Job.ExecutionTime.HasValue ? x.Job.ExecutionTime.Value.TotalMilliseconds : 0));
|
---|
[5955] | 348 | }
|
---|
| 349 | #endregion
|
---|
| 350 |
|
---|
| 351 | protected override void RaisePropertyChanged(string propertyName) {
|
---|
| 352 | if (!(propertyName == "ExecutionTime")
|
---|
| 353 | && !(propertyName == "JobCount")
|
---|
| 354 | && !(propertyName == "CalculatingCount")
|
---|
| 355 | && !(propertyName == "FinishedCount")) {
|
---|
| 356 | base.RaisePropertyChanged(propertyName);
|
---|
| 357 | }
|
---|
| 358 | }
|
---|
[6006] | 359 |
|
---|
| 360 | public bool IsFinished() {
|
---|
| 361 | return HiveJobs != null
|
---|
| 362 | && HiveJobs.All(x => x.Job.DateFinished.HasValue && x.Job.DateCreated.HasValue);
|
---|
| 363 | }
|
---|
[5602] | 364 | }
|
---|
| 365 | }
|
---|