/** * Parses summaries into a list view using the network stream for name lookup. * * @param NetworkStream Network stream used for name lookup * @param Summaries Summaries to parse into listview * @param ListView List view to parse data into */ public static void ParseStreamIntoListView( NetworkStream NetworkStream, Dictionary<int,TypeSummary> Summaries, ListView ListView ) { ListView.BeginUpdate(); ListView.Items.Clear(); // Columns are total size KByte, count, avg size in bytes, avg size in bits and associated name. var Columns = new string[6]; foreach( var SummaryEntry in Summaries ) { Columns[0] = ((float)SummaryEntry.Value.SizeBits / 8 / 1024).ToString("0.0"); Columns[1] = SummaryEntry.Value.Count.ToString(); Columns[2] = ((float)SummaryEntry.Value.SizeBits / 8 / SummaryEntry.Value.Count).ToString("0.0"); Columns[3] = ((float)SummaryEntry.Value.SizeBits / SummaryEntry.Value.Count).ToString("0.0"); Columns[4] = SummaryEntry.Value.TimeInMS.ToString("0.00"); Columns[5] = NetworkStream.GetName(SummaryEntry.Key); ListView.Items.Add(new ListViewItem(Columns)); } ListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize); ListView.EndUpdate(); }
/** * Returns whether the token matches/ passes based on the passed in filters. * * @param ActorFilter Actor filter to match against * @param PropertyFilter Property filter to match against * @param RPCFilter RPC filter to match against * * @return true if it matches, false otherwise */ public override bool MatchesFilters(string ActorFilter, string PropertyFilter, string RPCFilter) { return((ActorFilter.Length == 0 || NetworkStream.GetName(ActorNameIndex).ToUpperInvariant().Contains(ActorFilter.ToUpperInvariant())) && (RPCFilter.Length == 0 || NetworkStream.GetName(FunctionNameIndex).ToUpperInvariant().Contains(RPCFilter.ToUpperInvariant()))); }
/** * Parses passed in data stream into a network stream container class * * @param ParserStream Raw data stream, needs to support seeking * @return NetworkStream data was parsed into */ public static NetworkStream Parse(MainWindow InMainWindow, Stream ParserStream) { var StartTime = DateTime.UtcNow; // Network stream the file is parsed into. NetworkStream = new NetworkStream(); // Serialize the header. This will also return an endian-appropriate binary reader to // be used for reading the data. BinaryReader BinaryStream = null; NetworkStream.Header = StreamHeader.ReadHeader(ParserStream, out BinaryStream); // Scratch variables used for building stream. Required as we emit information in reverse // order needed for parsing. var CurrentFrameTokens = new List <TokenBase>(); TokenReplicateActor LastActorToken = null; List <TokenReplicateProperty> LastProperties = new List <TokenReplicateProperty>(); List <TokenWritePropertyHeader> LastPropertyHeaders = new List <TokenWritePropertyHeader>(); Dictionary <int, TokenPropertyComparison> ObjectNamesToPropertyComparisons = new Dictionary <int, TokenPropertyComparison>(); TokenFrameMarker LastFrameMarker = null; InMainWindow.ShowProgress(true); int Count = 0; var AllFrames = new PartialNetworkStream(NetworkStream.NameIndexUnreal, 1.0f / 30.0f); int EarlyOutMinutes = InMainWindow.GetMaxProfileMinutes(); // Parse stream till we reach the end, marked by special token. bool bHasReachedEndOfStream = false; List <TokenBase> TokenList = new List <TokenBase>(); float FrameStartTime = -1.0f; float FrameEndTime = -1.0f; while (bHasReachedEndOfStream == false) { if (Count++ % 1000 == 0) { float Percent = (float)ParserStream.Position / (float)ParserStream.Length; InMainWindow.UpdateProgress((int)(Percent * 100)); } if (ParserStream.Position == ParserStream.Length) { // We reached stream early (must not have been finalized properly, but we can still read it) break; } TokenBase Token = null; try { Token = TokenBase.ReadNextToken(BinaryStream, NetworkStream); } catch (System.IO.EndOfStreamException) { // We reached stream early (must not have been finalized properly, but we can still read it) break; } if (Token.TokenType == ETokenTypes.NameReference) { NetworkStream.NameArray.Add((Token as TokenNameReference).Name); // Find "Unreal" name index used for misc socket parsing optimizations. if (NetworkStream.NameArray[NetworkStream.NameArray.Count - 1] == "Unreal") { NetworkStream.NameIndexUnreal = NetworkStream.NameArray.Count - 1; } continue; } if (Token.TokenType == ETokenTypes.ConnectionReference) { if (NetworkStream.GetVersion() < 12) { NetworkStream.AddressArray.Add((Token as TokenConnectionReference).Address); } else { NetworkStream.StringAddressArray.Add((Token as TokenConnectionStringReference).Address); } continue; } if (Token.TokenType == ETokenTypes.ConnectionChange) { // We need to setup CurrentConnectionIndex, since it's used in ReadNextToken NetworkStream.CurrentConnectionIndex = (Token as TokenConnectionChanged).AddressIndex; continue; } TokenList.Add(Token); // Track frame start/end times manually so we can bail out when we hit the amount of time we want to load if (Token.TokenType == ETokenTypes.FrameMarker) { var TokenFrameMarker = (TokenFrameMarker)Token; if (FrameStartTime < 0) { FrameStartTime = TokenFrameMarker.RelativeTime; FrameEndTime = TokenFrameMarker.RelativeTime; } else { FrameEndTime = TokenFrameMarker.RelativeTime; } } if (EarlyOutMinutes > 0 && ((FrameEndTime - FrameStartTime) > 60 * EarlyOutMinutes)) { break; } } for (int i = 0; i < TokenList.Count; i++) { if (i % 1000 == 0) { float Percent = (float)(i + 1) / (float)(TokenList.Count); InMainWindow.UpdateProgress((int)(Percent * 100)); } TokenBase Token = TokenList[i]; // Convert current tokens to frame if we reach a frame boundary or the end of the stream. if (((Token.TokenType == ETokenTypes.FrameMarker) || (Token.TokenType == ETokenTypes.EndOfStreamMarker)) // Nothing to do if we don't have any tokens, e.g. first frame. && (CurrentFrameTokens.Count > 0)) { // Figure out delta time of previous frame. Needed as partial network stream lacks relative // information for last frame. We assume 30Hz for last frame and for the first frame in case // we receive network traffic before the first frame marker. float DeltaTime = 1 / 30.0f; if (Token.TokenType == ETokenTypes.FrameMarker && LastFrameMarker != null) { DeltaTime = ((TokenFrameMarker)Token).RelativeTime - LastFrameMarker.RelativeTime; } // Create per frame partial stream and add it to the full stream. var FrameStream = new PartialNetworkStream(CurrentFrameTokens, NetworkStream.NameIndexUnreal, DeltaTime); AllFrames.AddStream(FrameStream); NetworkStream.Frames.Add(FrameStream); CurrentFrameTokens.Clear(); Debug.Assert(LastProperties.Count == 0); // We shouldn't have any properties now Debug.Assert(LastPropertyHeaders.Count == 0); // We shouldn't have any property headers now either // Finish up actor summary of last pending actor before switching frames. HandleActorSummary(NetworkStream, LastActorToken); LastActorToken = null; } // Keep track of last frame marker. if (Token.TokenType == ETokenTypes.FrameMarker) { LastFrameMarker = (TokenFrameMarker)Token; ObjectNamesToPropertyComparisons = new Dictionary <int, TokenPropertyComparison>(); //Console.Out.WriteLine("EndOfFrame: " + NetworkStream.Frames.Count.ToString("0")); } // Bail out if we hit the end. We already flushed tokens above. if (Token.TokenType == ETokenTypes.EndOfStreamMarker) { Debug.Assert(LastProperties.Count == 0); // We shouldn't have any properties now Debug.Assert(LastPropertyHeaders.Count == 0); // We shouldn't have any property headers now either bHasReachedEndOfStream = true; // Finish up actor summary of last pending actor at end of stream HandleActorSummary(NetworkStream, LastActorToken); } // Keep track of per frame tokens. else { // Keep track of last actor context for property replication. if (Token.TokenType == ETokenTypes.ReplicateActor) { // Encountered a new actor so we can finish up existing one for summary. FinishActorProperties(Token as TokenReplicateActor, LastProperties, LastPropertyHeaders); Debug.Assert(LastProperties.Count == 0); // We shouldn't have any properties now Debug.Assert(LastPropertyHeaders.Count == 0); // We shouldn't have any property headers now either HandleActorSummary(NetworkStream, LastActorToken); LastActorToken = Token as TokenReplicateActor; } // Keep track of RPC summary else if (Token.TokenType == ETokenTypes.SendRPC) { var TokenSendRPC = Token as TokenSendRPC; NetworkStream.UpdateSummary(ref NetworkStream.RPCNameToSummary, TokenSendRPC.FunctionNameIndex, TokenSendRPC.GetNumTotalBits(), 0.0f); } // Add properties to the actor token instead of network stream and keep track of summary. if (Token.TokenType == ETokenTypes.ReplicateProperty) { var TokenReplicateProperty = Token as TokenReplicateProperty; NetworkStream.UpdateSummary(ref NetworkStream.PropertyNameToSummary, TokenReplicateProperty.PropertyNameIndex, TokenReplicateProperty.NumBits, 0); //LastActorToken.Properties.Add(TokenReplicateProperty); LastProperties.Add(TokenReplicateProperty); } else if (Token.TokenType == ETokenTypes.WritePropertyHeader) { var TokenWritePropertyHeader = Token as TokenWritePropertyHeader; LastPropertyHeaders.Add(TokenWritePropertyHeader); } else if (Token.TokenType == ETokenTypes.PropertyComparison) { var TokenPropertyComparison = Token as TokenPropertyComparison; ObjectNamesToPropertyComparisons[TokenPropertyComparison.ObjectNameIndex] = TokenPropertyComparison; HandleObjectComparison(NetworkStream, TokenPropertyComparison); } else if (Token.TokenType == ETokenTypes.ReplicatePropertiesMetaData) { var TokenReplicatePropertiesMetaData = Token as TokenReplicatePropertiesMetaData; TokenPropertyComparison Comparison = null; if (ObjectNamesToPropertyComparisons.TryGetValue(TokenReplicatePropertiesMetaData.ObjectNameIndex, out Comparison)) { HandleObjectReplication(NetworkStream, Comparison, TokenReplicatePropertiesMetaData); } else { Console.Out.WriteLine(NetworkStream.GetName(TokenReplicatePropertiesMetaData.ObjectNameIndex)); } } else { CurrentFrameTokens.Add(Token); } } } InMainWindow.SetCurrentStreamSelection(NetworkStream, AllFrames, false); InMainWindow.ShowProgress(false); // Stats for profiling. double ParseTime = (DateTime.UtcNow - StartTime).TotalSeconds; Console.WriteLine("Parsing {0} MBytes in stream took {1} seconds", ParserStream.Length / 1024 / 1024, ParseTime); // Empty stream will have 0 frames and proper name table. Shouldn't happen as we only // write out stream in engine if there are any events. return(NetworkStream); }
public string[] ToActorPerformanceString(NetworkStream NetworkStream, string ActorFilter, string PropertyFilter, string RPCFilter) { var Details = new List <string>(); UniqueItemTracker <UniqueActor, TokenReplicateActor> UniqueActors = new UniqueItemTracker <UniqueActor, TokenReplicateActor>(); foreach (TokenBase Token in Tokens) { TokenReplicateActor ActorToken = Token as TokenReplicateActor; if (ActorToken == null) { continue; } UniqueActors.AddItem(ActorToken, NetworkStream.GetClassNameIndex(ActorToken.ActorNameIndex)); } var ActorDetailList = UniqueActors.UniqueItems.OrderByDescending(s => s.Value.TimeInMS).ToList(); Int32 NumActors = 0; long NumSentBytes = 0; float TotalMS = 0.0f; foreach (var UniqueActor in ActorDetailList) { NumActors += UniqueActor.Value.Count; TotalMS += UniqueActor.Value.TimeInMS; var PropertyDetailList = UniqueActor.Value.Properties.UniqueItems.OrderByDescending(s => s.Value.SizeBits).ToList(); foreach (var Property in PropertyDetailList) { NumSentBytes += (Property.Value.SizeBits + 7) / 8; } } Details.Add("Total Actors : " + NumActors.ToString()); Details.Add("Total MS : " + string.Format("{0:0.00}", TotalMS)); Details.Add("Sent Bytes : " + NumSentBytes.ToString()); foreach (var UniqueActor in ActorDetailList) { long NumActorBytes = (UniqueActor.Value.SizeBits + 7) / 8; string ActorStr = string.Format("{0,-34} : {1:0.00} ({2,4}) ({3,2})", NetworkStream.GetName(UniqueActor.Key), UniqueActor.Value.TimeInMS, NumActorBytes, UniqueActor.Value.Count); Details.Add(ActorStr); var PropertyDetailList = UniqueActor.Value.Properties.UniqueItems.OrderByDescending(s => s.Value.SizeBits).ToList(); foreach (var Property in PropertyDetailList) { long NumPropBytes = (Property.Value.SizeBits + 7) / 8; string PropName = NetworkStream.GetName(Property.Key); string PropStr = string.Format("{0,-22} : {1,4} ({2,2})", PropName, NumPropBytes, Property.Value.Count); Details.Add(" " + PropStr); } Details.Add("-----------------------------------"); } return(Details.ToArray()); }
/** * Returns whether the token matches/ passes based on the passed in filters. * * @param ActorFilter Actor filter to match against * @param PropertyFilter Property filter to match against * @param RPCFilter RPC filter to match against * * @return true if it matches, false otherwise */ public override bool MatchesFilters(FilterValues InFilterValues) { return(base.MatchesFilters(InFilterValues) && (InFilterValues.ActorFilter.Length == 0 || NetworkStream.GetName(ObjectNameIndex).ToUpperInvariant().Contains(InFilterValues.ActorFilter.ToUpperInvariant()))); }
/** * Returns whether the token matches/ passes based on the passed in filters. * * @param ActorFilter Actor filter to match against * @param PropertyFilter Property filter to match against * @param RPCFilter RPC filter to match against * * @return true if it matches, false otherwise */ public override bool MatchesFilters(FilterValues InFilterValues) { bool ContainsMatchingProperty = false || (Properties.Count == 0 && InFilterValues.PropertyFilter.Length == 0); foreach (var Property in Properties) { if (Property.MatchesFilters(InFilterValues)) { ContainsMatchingProperty = true; break; } } return(base.MatchesFilters(InFilterValues) && (InFilterValues.ActorFilter.Length == 0 || NetworkStream.GetName(ActorNameIndex).ToUpperInvariant().Contains(InFilterValues.ActorFilter.ToUpperInvariant())) && ContainsMatchingProperty); }