3 using System.Collections.Generic;
4 using System.Diagnostics;
6 using SiliconStudio.Core.Diagnostics;
7 using SiliconStudio.Core.Serialization.Assets;
8 using SiliconStudio.Core.Storage;
10 namespace SiliconStudio.BuildEngine
15 internal class CommandIOMonitor
20 private readonly Dictionary<ObjectUrl, List<TimeInterval<BuildStep>>> readAccesses =
new Dictionary<ObjectUrl, List<TimeInterval<BuildStep>>>();
25 private readonly Dictionary<ObjectUrl, List<TimeInterval<KeyValuePair<BuildStep, ObjectId>>>> writeAccesses =
new Dictionary<ObjectUrl, List<TimeInterval<KeyValuePair<BuildStep, ObjectId>>>>();
30 private readonly Dictionary<CommandBuildStep, TimeInterval> commandExecutionIntervals =
new Dictionary<CommandBuildStep, TimeInterval>();
32 private readonly
ILogger logger;
34 private readonly
object lockObject =
new object();
36 private readonly Stopwatch stopWatch =
new Stopwatch();
38 public CommandIOMonitor(
ILogger logger)
44 public void CommandStarted(CommandBuildStep command)
48 long startTime = stopWatch.ElapsedTicks;
49 commandExecutionIntervals.Add(command,
new TimeInterval(startTime));
51 var inputHash =
new HashSet<ObjectUrl>();
52 foreach (
ObjectUrl inputUrl
in command.Command.GetInputFiles())
54 if (inputHash.Contains(inputUrl))
55 logger.Error(
"The command '{0}' has several times the file '{1}' as input. Input Files must not be duplicated", command.Title, inputUrl.
Path);
56 inputHash.Add(inputUrl);
58 List<TimeInterval<BuildStep>> inputReadAccess;
59 if (!readAccesses.TryGetValue(inputUrl, out inputReadAccess))
61 inputReadAccess =
new List<TimeInterval<BuildStep>> {
new TimeInterval<BuildStep>(command, startTime) };
62 readAccesses.Add(inputUrl, inputReadAccess);
66 inputReadAccess.Add(
new TimeInterval<BuildStep>(command, startTime));
72 public void CommandEnded(CommandBuildStep command)
76 TimeInterval commandInterval = commandExecutionIntervals[command];
77 long startTime = commandInterval.StartTime;
78 long endTime = stopWatch.ElapsedTicks;
79 commandInterval.End(endTime);
81 foreach (var outputObject
in command.Result.OutputObjects)
83 var outputUrl = outputObject.Key;
84 List<TimeInterval<BuildStep>> inputReadAccess;
85 if (readAccesses.TryGetValue(outputUrl, out inputReadAccess))
87 foreach (TimeInterval<BuildStep> input
in inputReadAccess.Where(input => input.Object != command && input.Overlap(startTime, endTime)))
89 logger.Error(
"Command {0} is writing {1} while command {2} is reading it", command, outputUrl, input.Object);
93 List<TimeInterval<KeyValuePair<BuildStep, ObjectId>>> outputWriteAccess;
94 if (!writeAccesses.TryGetValue(outputUrl, out outputWriteAccess))
96 outputWriteAccess =
new List<TimeInterval<KeyValuePair<BuildStep, ObjectId>>> {
new TimeInterval<KeyValuePair<BuildStep, ObjectId>>(
new KeyValuePair<BuildStep, ObjectId>(command, outputObject.Value), startTime, endTime) };
97 writeAccesses.Add(outputUrl, outputWriteAccess);
101 foreach (var output
in outputWriteAccess.Where(output => output.Object.Key != command && output.Overlap(startTime, endTime)))
103 if (outputObject.Value != output.Object.Value)
104 logger.Error(
"Commands {0} and {1} are both writing {2} at the same time, but they are different objects", command, output.Object, outputUrl);
106 outputWriteAccess.Add(
new TimeInterval<KeyValuePair<BuildStep, ObjectId>>(
new KeyValuePair<BuildStep, ObjectId>(command, outputObject.Value), startTime, endTime));
110 foreach (
ObjectUrl inputUrl
in command.Result.InputDependencyVersions.Keys)
112 List<TimeInterval<KeyValuePair<BuildStep, ObjectId>>> outputWriteAccess;
113 if (writeAccesses.TryGetValue(inputUrl, out outputWriteAccess))
115 foreach (TimeInterval<KeyValuePair<BuildStep, ObjectId>> output
in outputWriteAccess.Where(output => output.Object.Key != command && output.Overlap(startTime, endTime)))
117 logger.Error(
"Command {0} is writing {1} while command {2} is reading it", output.Object, inputUrl, command);
122 foreach (
ObjectUrl input
in command.Command.GetInputFiles())
124 readAccesses[input].Single(x => x.Object == command).
End(endTime);