public void CommandStarted(CommandBuildStep command) { lock (lockObject) { long startTime = stopWatch.ElapsedTicks; commandExecutionIntervals.Add(command, new TimeInterval(startTime)); // Get a list of unique input files var inputFiles = command.Command.GetInputFiles().Distinct().ToList(); // Store it aside, so that we're sure to remove the same entries during CommandEnded commandInputFiles.Add(command, inputFiles); // Setup start read time for each file entry var inputHash = new HashSet <ObjectUrl>(); foreach (ObjectUrl inputUrl in inputFiles) { if (inputHash.Contains(inputUrl)) { logger.Error($"The command '{command.Title}' has several times the file '{inputUrl.Path}' as input. Input Files must not be duplicated"); } inputHash.Add(inputUrl); ObjectAccesses inputAccesses; if (!objectsAccesses.TryGetValue(inputUrl, out inputAccesses)) { objectsAccesses.Add(inputUrl, inputAccesses = new ObjectAccesses()); } inputAccesses.Reads.Add(new TimeInterval <BuildStep>(command, startTime)); } } }
public void CommandStarted(CommandBuildStep command) { lock (lockObject) { long startTime = stopWatch.ElapsedTicks; commandExecutionIntervals.Add(command, new TimeInterval(startTime)); // Get a list of unique input files var inputFiles = command.Command.GetInputFiles().Distinct().ToList(); // Store it aside, so that we're sure to remove the same entries during CommandEnded commandInputFiles.Add(command, inputFiles); // Setup start read time for each file entry var inputHash = new HashSet<ObjectUrl>(); foreach (ObjectUrl inputUrl in inputFiles) { if (inputHash.Contains(inputUrl)) logger.Error("The command '{0}' has several times the file '{1}' as input. Input Files must not be duplicated", command.Title, inputUrl.Path); inputHash.Add(inputUrl); ObjectAccesses inputAccesses; if (!objectsAccesses.TryGetValue(inputUrl, out inputAccesses)) { objectsAccesses.Add(inputUrl, inputAccesses = new ObjectAccesses()); } inputAccesses.Reads.Add(new TimeInterval<BuildStep>(command, startTime)); } } }
public void CommandEnded(CommandBuildStep command) { lock (lockObject) { TimeInterval commandInterval = commandExecutionIntervals[command]; long startTime = commandInterval.StartTime; long endTime = stopWatch.ElapsedTicks; commandInterval.End(endTime); commandExecutionIntervals.Remove(command); foreach (var outputObject in command.Result.OutputObjects) { var outputUrl = outputObject.Key; ObjectAccesses inputAccess; if (objectsAccesses.TryGetValue(outputUrl, out inputAccess)) { foreach (TimeInterval <BuildStep> input in inputAccess.Reads.Where(input => input.Object != command && input.Overlap(startTime, endTime))) { logger.Error($"Command {command} is writing {outputUrl} while command {input.Object} is reading it"); } } ObjectAccesses outputAccess; if (!objectsAccesses.TryGetValue(outputUrl, out outputAccess)) { objectsAccesses.Add(outputUrl, outputAccess = new ObjectAccesses()); } foreach (var output in outputAccess.Writes.Where(output => output.Object.Key != command && output.Overlap(startTime, endTime))) { if (outputObject.Value != output.Object.Value) { logger.Error($"Commands {command} and {output.Object} are both writing {outputUrl} at the same time, but they are different objects"); } } outputAccess.Writes.Add(new TimeInterval <KeyValuePair <BuildStep, ObjectId> >(new KeyValuePair <BuildStep, ObjectId>(command, outputObject.Value), startTime, endTime)); } foreach (ObjectUrl inputUrl in command.Result.InputDependencyVersions.Keys) { ObjectAccesses outputAccess; if (objectsAccesses.TryGetValue(inputUrl, out outputAccess)) { foreach (TimeInterval <KeyValuePair <BuildStep, ObjectId> > output in outputAccess.Writes.Where(output => output.Object.Key != command && output.Overlap(startTime, endTime))) { logger.Error($"Command {output.Object} is writing {inputUrl} while command {command} is reading it"); } } } // Notify that we're done reading input files List <ObjectUrl> inputFiles; if (commandInputFiles.TryGetValue(command, out inputFiles)) { commandInputFiles.Remove(command); foreach (ObjectUrl input in inputFiles) { objectsAccesses[input].Reads.Single(x => x.Object == command).End(endTime); } } // "Garbage collection" of accesses var newEarliestCommandAliveStartTime = commandExecutionIntervals.Count > 0 ? commandExecutionIntervals.Min(x => x.Value.StartTime) : endTime; if (newEarliestCommandAliveStartTime > earliestCommandAliveStartTime) { earliestCommandAliveStartTime = newEarliestCommandAliveStartTime; // We can remove objects whose all R/W accesses are "completed" (EndTime is set) // and happened before all the current running commands started, since they won't affect us foreach (var objectAccesses in objectsAccesses.ToList()) { if (objectAccesses.Value.Reads.All(x => x.EndTime != 0 && x.EndTime < earliestCommandAliveStartTime) && objectAccesses.Value.Writes.All(x => x.EndTime != 0 && x.EndTime < earliestCommandAliveStartTime)) { objectsAccesses.Remove(objectAccesses.Key); } } } } }
public void CommandEnded(CommandBuildStep command) { lock (lockObject) { TimeInterval commandInterval = commandExecutionIntervals[command]; long startTime = commandInterval.StartTime; long endTime = stopWatch.ElapsedTicks; commandInterval.End(endTime); commandExecutionIntervals.Remove(command); foreach (var outputObject in command.Result.OutputObjects) { var outputUrl = outputObject.Key; ObjectAccesses inputAccess; if (objectsAccesses.TryGetValue(outputUrl, out inputAccess)) { foreach (TimeInterval<BuildStep> input in inputAccess.Reads.Where(input => input.Object != command && input.Overlap(startTime, endTime))) { logger.Error("Command {0} is writing {1} while command {2} is reading it", command, outputUrl, input.Object); } } ObjectAccesses outputAccess; if (!objectsAccesses.TryGetValue(outputUrl, out outputAccess)) { objectsAccesses.Add(outputUrl, outputAccess = new ObjectAccesses()); } foreach (var output in outputAccess.Writes.Where(output => output.Object.Key != command && output.Overlap(startTime, endTime))) { if (outputObject.Value != output.Object.Value) logger.Error("Commands {0} and {1} are both writing {2} at the same time, but they are different objects", command, output.Object, outputUrl); } outputAccess.Writes.Add(new TimeInterval<KeyValuePair<BuildStep, ObjectId>>(new KeyValuePair<BuildStep, ObjectId>(command, outputObject.Value), startTime, endTime)); } foreach (ObjectUrl inputUrl in command.Result.InputDependencyVersions.Keys) { ObjectAccesses outputAccess; if (objectsAccesses.TryGetValue(inputUrl, out outputAccess)) { foreach (TimeInterval<KeyValuePair<BuildStep, ObjectId>> output in outputAccess.Writes.Where(output => output.Object.Key != command && output.Overlap(startTime, endTime))) { logger.Error("Command {0} is writing {1} while command {2} is reading it", output.Object, inputUrl, command); } } } // Notify that we're done reading input files List<ObjectUrl> inputFiles; if (commandInputFiles.TryGetValue(command, out inputFiles)) { commandInputFiles.Remove(command); foreach (ObjectUrl input in inputFiles) { objectsAccesses[input].Reads.Single(x => x.Object == command).End(endTime); } } // "Garbage collection" of accesses var newEarliestCommandAliveStartTime = commandExecutionIntervals.Count > 0 ? commandExecutionIntervals.Min(x => x.Value.StartTime) : endTime; if (newEarliestCommandAliveStartTime > earliestCommandAliveStartTime) { earliestCommandAliveStartTime = newEarliestCommandAliveStartTime; // We can remove objects whose all R/W accesses are "completed" (EndTime is set) // and happened before all the current running commands started, since they won't affect us foreach (var objectAccesses in objectsAccesses.ToList()) { if (objectAccesses.Value.Reads.All(x => x.EndTime != 0 && x.EndTime < earliestCommandAliveStartTime) && objectAccesses.Value.Writes.All(x => x.EndTime != 0 && x.EndTime < earliestCommandAliveStartTime)) objectsAccesses.Remove(objectAccesses.Key); } } } }