public static void TaskLink(TimelineEntry entry) { if (!IsTaskLink(entry)) { return; } TimelineBuildEntry timelineBuildEntry = entry as TimelineBuildEntry; // because these messages aren't related to each other in any way other than parsing messages, // we'll be keeping a list of timeline entries which will open/close as the messages are processed List <TimelineEntry> linkEntries = new List <TimelineEntry>(); IEnumerable <MessageEvent> messages = timelineBuildEntry.BuildEntry.ChildEvents.Where(_ => _ is MessageEvent) .Select(_ => _ as MessageEvent); // find Pass 1 and Pass 2 foreach (MessageEvent message in messages) { // Linker: Pass 1 Match matchLinkerPass1 = s_LinkPass1.Match(message.Message); if (matchLinkerPass1.Success) { double elapsedTimeFromMessage = Double.Parse(matchLinkerPass1.Groups[2].Value, CultureInfo.InvariantCulture); TimeSpan elapsedTime = TimeSpanFromSeconds(elapsedTimeFromMessage); DateTime startTimestamp = message.Timestamp - elapsedTime; if (startTimestamp < timelineBuildEntry.StartTimestamp) { startTimestamp = timelineBuildEntry.StartTimestamp; } TimelineEntry pass1Entry = new TimelineEntry(s_LinkerPass1Name, message.Context.NodeId, startTimestamp, message.Timestamp); linkEntries.Add(pass1Entry); pass1Entry.ThreadAffinity.SetParameters(pass1Entry.ThreadAffinity.ThreadId, ThreadAffinity.s_OffsetFromParentPostProcessedEntries, ThreadAffinity.s_OffsetFromParentPostProcessedEntriesIncrement); continue; } // Linker: Pass 2 Match matchLinkerPass2 = s_LinkPass2.Match(message.Message); if (matchLinkerPass2.Success) { double elapsedTimeFromMessage = Double.Parse(matchLinkerPass2.Groups[2].Value, CultureInfo.InvariantCulture); TimeSpan elapsedTime = TimeSpanFromSeconds(elapsedTimeFromMessage); DateTime startTimestamp = message.Timestamp - elapsedTime; if (linkEntries.Count > 0 && startTimestamp < linkEntries.Last().EndTimestamp) { startTimestamp = linkEntries.Last().EndTimestamp; } TimelineEntry pass2Entry = new TimelineEntry(s_LinkerPass2Name, message.Context.NodeId, startTimestamp, message.Timestamp); linkEntries.Add(pass2Entry); pass2Entry.ThreadAffinity.SetParameters(pass2Entry.ThreadAffinity.ThreadId, ThreadAffinity.s_OffsetFromParentPostProcessedEntries, ThreadAffinity.s_OffsetFromParentPostProcessedEntriesIncrement); continue; } } // this is the function that will be applied to all common linker messages except Pass 1 and Pass 2 messages Action <TimelineEntry, Tuple <MessageEvent, Match> > perCommonLinkerMessage = (parent, tuple) => { MessageEvent message = tuple.Item1; Match match = tuple.Item2; double elapsedTimeFromMessage = Double.Parse(match.Groups[3].Value, CultureInfo.InvariantCulture); TimeSpan elapsedTime = TimeSpanFromSeconds(elapsedTimeFromMessage); DateTime startTimestamp = message.Timestamp - elapsedTime; if (parent.ChildEntries.Count == 0 && startTimestamp < parent.StartTimestamp) { startTimestamp = parent.StartTimestamp; } else if (parent.ChildEntries.Count > 0 && startTimestamp < parent.ChildEntries.Last().EndTimestamp) { startTimestamp = parent.ChildEntries.Last().EndTimestamp; } TimelineEntry linkerEntry = new TimelineEntry(match.Groups[2].Value.Trim(), message.Context.NodeId, startTimestamp, message.Timestamp); parent.AddChild(linkerEntry); }; // add entries within Pass 1 TimelineEntry parentEntry = linkEntries.Find(_ => _.Name == s_LinkerPass1Name); if (parentEntry != null) { IEnumerable <Tuple <MessageEvent, Match> > messagesBeforePass1 = messages.TakeWhile(_ => !s_LinkPass1.Match(_.Message).Success) // take messages until Pass 1 message .Select(_ => new Tuple <MessageEvent, Match>(_, s_LinkCommon.Match(_.Message))) // match with common regex .Where(_ => _.Item2.Success); // only take positive ones foreach (Tuple <MessageEvent, Match> tuple in messagesBeforePass1) { perCommonLinkerMessage(parentEntry, tuple); } } // add entries within Pass 2 parentEntry = linkEntries.Find(_ => _.Name == s_LinkerPass2Name); if (parentEntry != null) { IEnumerable <Tuple <MessageEvent, Match> > messagesBeforePass2 = messages.SkipWhile(_ => !s_LinkPass1.Match(_.Message).Success) // skip all messages until Pass 1 .Skip(1) // skip Pass 1 included .TakeWhile(_ => !s_LinkPass2.Match(_.Message).Success) // take messages until Pass 2 message .Select(_ => new Tuple <MessageEvent, Match>(_, s_LinkCommon.Match(_.Message))) // match with common regex .Where(_ => _.Item2.Success); // only take positive ones foreach (Tuple <MessageEvent, Match> tuple in messagesBeforePass2) { perCommonLinkerMessage(parentEntry, tuple); } } // add them all to the Link task linkEntries.ForEach(timelineBuildEntry.AddChild); }
private void ProcessMessageEvent(MessageEvent e, TimelineBuilderContext context) { Debug.Assert(context.HasOpenBuilds); // a message can be executed as part of any entry: build, project, target or task BuildEntry parentEntry = null; // part of the build? if (e.Context == null) { parentEntry = context.RootEntry; } else { MessageEventContext messageContext = e.Context as MessageEventContext; // part of a task? if (messageContext.TaskId != null) { Debug.Assert(messageContext.ProjectId != null); Debug.Assert(messageContext.TargetId != null); parentEntry = context.OpenTaskEntries.Find(taskEntry => { TaskEventContext taskContext = taskEntry.Context as TaskEventContext; Debug.Assert(taskContext != null); return(taskContext.NodeId == messageContext.NodeId && taskContext.ContextId == messageContext.ContextId && taskContext.ProjectId == messageContext.ProjectId && taskContext.TargetId == messageContext.TargetId && taskContext.TaskId == messageContext.TaskId); }); } // part of a target? else if (messageContext.TargetId != null) { Debug.Assert(messageContext.ProjectId != null); Debug.Assert(messageContext.TaskId == null); parentEntry = context.OpenTargetEntries.Find(targetEntry => { TargetEventContext targetContext = targetEntry.Context as TargetEventContext; Debug.Assert(targetContext != null); return(targetContext.NodeId == messageContext.NodeId && targetContext.ContextId == messageContext.ContextId && targetContext.ProjectId == messageContext.ProjectId && targetContext.TargetId == messageContext.TargetId); }); } // part of a project? else if (messageContext.ProjectId != null) { Debug.Assert(messageContext.TargetId == null); Debug.Assert(messageContext.TaskId == null); parentEntry = context.OpenProjectEntries.Find(projectEntry => { ProjectEventContext projectContext = projectEntry.Context as ProjectEventContext; Debug.Assert(projectContext != null); return(projectContext.NodeId == messageContext.NodeId && projectContext.ContextId == messageContext.ContextId && projectContext.ProjectId == messageContext.ProjectId); }); } // part of the build itself? else { parentEntry = context.RootEntry; } } Debug.Assert(parentEntry != null); parentEntry.AddChild(e); }