internal Graph(object graphSource) { this.graphSource = graphSource; vertices = new Dictionary<string, Vertex>(); topVertex = FindOrCreateVertex("<root>", null, null); bottomVertex = FindOrCreateVertex("<bottom>", null, null); }
internal void BuildAllocationTrace(Graph graph, int stackTraceIndex, int typeIndex, ulong size, Vertex[] typeVertex, Vertex[] funcVertex, ref Vertex[] vertexStack, FilterForm filterForm) { int stackPtr = BuildVertexStack(stackTraceIndex, funcVertex, ref vertexStack, 2); Vertex toVertex = graph.TopVertex; Vertex fromVertex; Edge edge; if ((typeVertex[typeIndex].interestLevel & InterestLevel.Interesting) == InterestLevel.Interesting && ReadNewLog.InterestingCallStack(vertexStack, stackPtr, filterForm)) { vertexStack[stackPtr] = typeVertex[typeIndex]; stackPtr++; stackPtr = ReadNewLog.FilterVertices(vertexStack, stackPtr); stackPtr = Vertex.SqueezeOutRepetitions(vertexStack, stackPtr); for (int i = 0; i < stackPtr; i++) { fromVertex = toVertex; toVertex = vertexStack[i]; edge = graph.FindOrCreateEdge(fromVertex, toVertex); edge.AddWeight(size); } fromVertex = toVertex; toVertex = graph.BottomVertex; edge = graph.FindOrCreateEdge(fromVertex, toVertex); edge.AddWeight(size); } }
internal Vertex FindOrCreateVertex(string name, string signature, string module) { string nameSignatureModule = NameSignatureModule(name, signature, module); Vertex vertex; if (!vertices.TryGetValue(nameSignatureModule, out vertex)) { vertex = new Vertex(name, signature, module, this); vertices[nameSignatureModule] = vertex; } return vertex; }
public int SelectedVertexCount(out Vertex selectedVertex) { int selectedCount = 0; selectedVertex = null; foreach (Vertex v in graph.vertices.Values) { if (v.selected) { selectedCount++; selectedVertex = v; } } return selectedCount; }
internal int BuildVertexStack(int stackTraceIndex, Vertex[] funcVertex, ref Vertex[] vertexStack, int skipCount) { int[] stackTrace = readNewLog.stacktraceTable.IndexToStacktrace(stackTraceIndex); while (vertexStack.Length < stackTrace.Length + 3) { vertexStack = new Vertex[vertexStack.Length*2]; } for (int i = skipCount; i < stackTrace.Length; i++) { vertexStack[i-skipCount] = funcVertex[stackTrace[i]]; } return stackTrace.Length - skipCount; }
internal Graph BuildTypeGraph(int allocatedAfterTickIndex, int allocatedBeforeTickIndex, BuildTypeGraphOptions options, FilterForm filterForm) { Graph graph; if (filterForm.filterVersion != 0 || options != BuildTypeGraphOptions.LumpBySignature || allocatedAfterTickIndex > 0 || allocatedBeforeTickIndex < int.MaxValue) { graph = new Graph(this, Graph.GraphType.HeapGraph); graph.previousGraphTickIndex = allocatedAfterTickIndex; } else { Graph previousGraph = cachedGraph; if (previousGraph != null && previousGraph.graphSource == this) { return(previousGraph); } cachedGraph = graph = new Graph(this, Graph.GraphType.HeapGraph); if (previousGraph != null) { graph.previousGraphTickIndex = ((ObjectGraph)previousGraph.graphSource).tickIndex; foreach (Vertex v in previousGraph.vertices.Values) { Vertex newV = graph.FindOrCreateVertex(v.name, v.signature, v.moduleName); if (v.weightHistory == null) { newV.weightHistory = new ulong[1]; } else { ulong[] weightHistory = v.weightHistory; newV.weightHistory = new ulong[Math.Min(weightHistory.Length + 1, historyDepth)]; for (int i = v.weightHistory.Length - 1; i > 0; i--) { newV.weightHistory[i] = weightHistory[i - 1]; } } newV.weightHistory[0] = v.weight; } } } graph.typeGraphOptions = options; graph.filterVersion = filterForm.filterVersion; if (graph.previousGraphTickIndex < graph.allocatedAfterTickIndex) { graph.previousGraphTickIndex = graph.allocatedAfterTickIndex; } graph.allocatedAfterTickIndex = allocatedAfterTickIndex; graph.allocatedBeforeTickIndex = allocatedBeforeTickIndex; GcObject rootObject = CreateRootObject(); for (int i = 0; i < rootCount; i++) { roots[i].InterestLevel = InterestLevel.Ignore; } foreach (GcObject gcObject in idToObject.Values) { gcObject.parent = null; gcObject.vertex = null; gcObject.InterestLevel = InterestLevel.Ignore; } AssignParents(rootObject); int index = 0; foreach (GcType gcType in typeIdToGcType.Values) { gcType.index = index++; } GcType[] gcTypes = new GcType[index]; typeHintTable = new int[index]; foreach (GcType gcType in typeIdToGcType.Values) { gcTypes[gcType.index] = gcType; } AssignInterestLevelsToTypes(options, filterForm); for (int i = 0; i < rootCount; i++) { AssignInterestLevelToObject(rootIDs[i], roots[i], options, filterForm, true); } foreach (KeyValuePair <ulong, GcObject> keyValuePair in idToObject) { GcObject gcObject = keyValuePair.Value; if (gcObject.AllocTickIndex > allocatedAfterTickIndex && gcObject.AllocTickIndex < allocatedBeforeTickIndex) { AssignInterestLevelToObject(keyValuePair.Key, gcObject, options, filterForm, false); } else { gcObject.InterestLevel = InterestLevel.Ignore; } } foreach (GcObject gcObject in idToObject.Values) { if (gcObject.InterestLevel == InterestLevel.Ignore) { CheckForParentMarkingDescendant(gcObject); } } FindVertex(0, rootObject, graph, options); for (int i = 0; i < rootCount; i++) { roots[i].vertex = null; FindVertex(rootIDs[i], roots[i], graph, options); } foreach (KeyValuePair <ulong, GcObject> keyValuePair in idToObject) { ulong id = keyValuePair.Key; GcObject gcObject = keyValuePair.Value; if (gcObject.parent == null || (gcObject.InterestLevel & (InterestLevel.Interesting | InterestLevel.Display)) == InterestLevel.Ignore) { continue; } FindVertex(id, gcObject, graph, options); } Vertex[] pathFromRoot = new Vertex[32]; foreach (GcObject gcObject in idToObject.Values) { if (gcObject.parent == null || (gcObject.InterestLevel & (InterestLevel.Interesting | InterestLevel.Display)) == InterestLevel.Ignore || gcObject.AllocTickIndex <= allocatedAfterTickIndex || gcObject.AllocTickIndex >= allocatedBeforeTickIndex) { continue; } int levels = 0; for (GcObject pathObject = gcObject; pathObject != null; pathObject = pathObject.parent) { if (pathObject.vertex != null) { levels++; } } while (pathFromRoot.Length < levels + 1) { pathFromRoot = new Vertex[pathFromRoot.Length * 2]; } int level = levels; for (GcObject pathObject = gcObject; pathObject != null; pathObject = pathObject.parent) { if (pathObject.vertex != null) { level--; pathFromRoot[level] = pathObject.vertex; } } levels = Vertex.SqueezeOutRepetitions(pathFromRoot, levels); for (int j = 0; j < levels - 1; j++) { Vertex fromVertex = pathFromRoot[j]; Vertex toVertex = pathFromRoot[j + 1]; Edge edge = graph.FindOrCreateEdge(fromVertex, toVertex); edge.AddWeight(gcObject.Size(this)); } Vertex thisVertex = pathFromRoot[levels - 1]; thisVertex.basicWeight += gcObject.Size(this); thisVertex.count += 1; } foreach (Vertex v in graph.vertices.Values) { if (v.weight < v.outgoingWeight) { v.weight = v.outgoingWeight; } if (v.weight < v.incomingWeight) { v.weight = v.incomingWeight; } if (v.weightHistory == null) { v.weightHistory = new ulong[1]; } } foreach (Vertex v in graph.vertices.Values) { v.active = true; } graph.BottomVertex.active = false; return(graph); }
private void activateOutgoing(Vertex v) { if (v.active) return; v.active = true; foreach (Edge e in v.outgoingEdges.Values) activateOutgoing(e.ToVertex); }
internal static int FilterVertices(Vertex[] vertexStack, int stackPtr) { bool display = false; for (int i = 0; i < stackPtr; i++) { Vertex vertex = vertexStack[i]; switch (vertex.interestLevel & InterestLevel.InterestingChildren) { case InterestLevel.Ignore: if (display) vertex.interestLevel |= InterestLevel.Display; break; case InterestLevel.InterestingChildren: display = true; break; default: display = false; break; } } display = false; for (int i = stackPtr-1; i >= 0; i--) { Vertex vertex = vertexStack[i]; switch (vertex.interestLevel & InterestLevel.InterestingParents) { case InterestLevel.Ignore: if (display) vertex.interestLevel |= InterestLevel.Display; break; case InterestLevel.InterestingParents: display = true; break; default: display = false; break; } } int newStackPtr = 0; for (int i = 0; i < stackPtr; i++) { Vertex vertex = vertexStack[i]; if ((vertex.interestLevel & (InterestLevel.Display|InterestLevel.Interesting)) != InterestLevel.Ignore) { vertexStack[newStackPtr++] = vertex; vertex.interestLevel &= ~InterestLevel.Display; } } return newStackPtr; }
internal Graph BuildHandleAllocationGraph(FilterForm filterForm) { Vertex[] funcVertex = new Vertex[1]; Vertex[] vertexStack = new Vertex[1]; Graph graph = new Graph(this); graph.graphType = Graph.GraphType.HandleAllocationGraph; BuildFuncVertices(graph, ref funcVertex, filterForm); for (int i = 0; i < typeSizeStacktraceToCount.Length; i++) { if (typeSizeStacktraceToCount[i] > 0) { int[] stacktrace = readNewLog.stacktraceTable.IndexToStacktrace(i); uint count = (uint)typeSizeStacktraceToCount[i]; BuildHandleAllocationTrace(graph, i, count, funcVertex, ref vertexStack, filterForm); } } foreach (Vertex v in graph.vertices.Values) v.active = true; graph.BottomVertex.active = false; return graph; }
internal void AddFunctionVertex(int funcId, string functionName, string signature, Graph graph, ref Vertex[] funcVertex, FilterForm filterForm) { EnsureVertexCapacity(funcId, ref funcVertex); int moduleId = funcModule[funcId]; string moduleName = null; if (moduleId >= 0) moduleName = modBasicName[moduleId]; funcVertex[funcId] = graph.FindOrCreateVertex(functionName, signature, moduleName); funcVertex[funcId].interestLevel = filterForm.InterestLevelOfMethodName(functionName, signature); }
internal void BuildFuncVertices(Graph graph, ref Vertex[] funcVertex, FilterForm filterForm) { for (int i = 0; i < readNewLog.funcName.Length; i++) { string name = readNewLog.funcName[i]; string signature = readNewLog.funcSignature[i]; if (name == null) name = string.Format("???? function {0}", i); if (signature == null) signature = "( ???????? )"; readNewLog.AddFunctionVertex(i, name, signature, graph, ref funcVertex, filterForm); } }
internal Graph BuildClassGraph(FilterForm filterForm) { Vertex[] funcVertex = new Vertex[1]; Vertex[] vertexStack = new Vertex[1]; Graph graph = new Graph(this); graph.graphType = Graph.GraphType.ClassGraph; BuildFuncVertices(graph, ref funcVertex, filterForm); foreach (FunctionDescriptor fd in functionList) { BuildClassTrace(graph, fd.funcCallStack, fd.functionId, fd.funcSize, funcVertex, ref vertexStack, filterForm); } foreach (Vertex v in graph.vertices.Values) v.active = true; graph.BottomVertex.active = false; return graph; }
static void EnsureVertexCapacity(int id, ref Vertex[] vertexArray) { Debug.Assert(id >= 0); if (id < vertexArray.Length) return; int newLength = vertexArray.Length*2; if (newLength <= id) newLength = id + 1; Vertex[] newVertexArray = new Vertex[newLength]; Array.Copy(vertexArray, 0, newVertexArray, 0, vertexArray.Length); vertexArray = newVertexArray; }
void BuildModuleTrace(Graph graph, int stackTraceIndex, int modIndex, ulong size, Vertex[] funcVertex, Vertex[] modVertex, ref Vertex[] vertexStack, FilterForm filterForm) { int functionsToSkip = FunctionsInSameModule(modIndex, stackTraceIndex); int stackPtr = BuildVertexStack(stackTraceIndex, funcVertex, ref vertexStack, 0) - functionsToSkip; Vertex toVertex = graph.TopVertex; Vertex fromVertex; Edge edge; if (ReadNewLog.InterestingCallStack(vertexStack, stackPtr, filterForm)) { vertexStack[stackPtr] = modVertex[modIndex]; stackPtr++; stackPtr = ReadNewLog.FilterVertices(vertexStack, stackPtr); stackPtr = Vertex.SqueezeOutRepetitions(vertexStack, stackPtr); for (int i = 0; i < stackPtr; i++) { fromVertex = toVertex; toVertex = vertexStack[i]; edge = graph.FindOrCreateEdge(fromVertex, toVertex); edge.AddWeight(size); } fromVertex = toVertex; toVertex = graph.BottomVertex; edge = graph.FindOrCreateEdge(fromVertex, toVertex); edge.AddWeight(size); } }
private void activateIncoming(Vertex v) { if (v.active) return; v.active = true; foreach (Edge e in v.incomingEdges.Values) activateIncoming(e.FromVertex); }
private void AppendVertexHeader(StringBuilder sb, Vertex v, int indent) { for (int i = 0; i < indent; i++) sb.Append(" "); string signature = v.signature != null ? v.signature : ""; sb.AppendFormat("{0} {1}:\t{2}\r\n", v.name, signature, v.weightString); if (NonEmptyWeightHistory(v)) { for (int i = 0; i < indent; i++) sb.Append(" "); sb.Append(" Previous allocations (newest to oldest): "); for (int i = 0; i < v.weightHistory.Length; i++) { sb.Append(formatWeight(v.weightHistory[i])); sb.Append(", "); } sb.Append("\r\n"); } }
private Dictionary <GcObject, ulong> objectToId; // reverse mapping from gc objects to their addresses internal void WriteVertexPaths(int allocatedAfterTickIndex, int allocatedBeforeTickIndex, string typeName) { BuildTypeGraph(new FilterForm()); if (objectToId == null) { objectToId = new Dictionary <GcObject, ulong>(); // initialize the reverse mapping foreach (KeyValuePair <ulong, GcObject> keyValuePair in idToObject) { objectToId[keyValuePair.Value] = keyValuePair.Key; } } ulong[][] idsFromRoot = new ulong[1][]; Vertex[] pathFromRoot = new Vertex[32]; int counter = 0; foreach (GcObject gcObject in idToObject.Values) { if (gcObject.Type(this).name.CompareTo(typeName) != 0) { continue; } if (gcObject.AllocTickIndex <= allocatedAfterTickIndex || gcObject.AllocTickIndex >= allocatedBeforeTickIndex) { continue; } ulong[][] _idsFromRoot = idsFromRoot; if (_idsFromRoot.Length <= counter) { idsFromRoot = new ulong[counter + 1][]; for (int i = 0; i < _idsFromRoot.Length; i++) { idsFromRoot[i] = _idsFromRoot[i]; } } int levels = 0; for (GcObject pathObject = gcObject; pathObject != null; pathObject = pathObject.parent) { if (pathObject.vertex != null) { levels++; } } while (pathFromRoot.Length < levels + 1) { pathFromRoot = new Vertex[pathFromRoot.Length * 2]; } int level = levels; //System.Console.WriteLine("{0} -- {1}:", counter, gcObject.id); for (GcObject pathObject = gcObject; pathObject != null; pathObject = pathObject.parent) { if (pathObject.vertex != null) { level--; pathFromRoot[level] = pathObject.vertex; pathObject.vertex.id = 0; objectToId.TryGetValue(pathObject, out pathObject.vertex.id); } } levels = Vertex.SqueezeOutRepetitions(pathFromRoot, levels); idsFromRoot[counter] = new ulong[levels]; for (int i = 0; i < levels; i++) { //System.Console.Write("{0}, {1} ->", pathFromRoot[i].name, pathFromRoot[i].id); idsFromRoot[counter][i] = pathFromRoot[i].id; } //System.Console.WriteLine("---------------------------------------"); counter++; } Console.WriteLine("<TotalAllocations>{0}</TotalAllocations>", idsFromRoot.Length); Console.WriteLine("</Difference>"); Console.WriteLine("</Summary>"); Console.WriteLine("<PossibleCulPrits>"); // Display the reference list and stack trace for 0th object // Find Culprit here. var mismatchedObjects = new List <int>(); var differentCulprits = new List <string>(); for (int j = 1; j < idsFromRoot.Length; j++) { for (int i = 0; i < idsFromRoot[0].Length; i++) { if ((i > idsFromRoot[j].Length) || ((i < idsFromRoot[j].Length) && (idsFromRoot[0][i] != idsFromRoot[j][i]))) { if (i < idsFromRoot[0].Length - 1) { mismatchedObjects.Add(j); } GcObject temp = idToObject[idsFromRoot[0][i - 1]]; if (temp != null) { if (!differentCulprits.Contains(temp.Type(this).name)) { differentCulprits.Add(temp.Type(this).name); if (differentCulprits.Count <= 5) { System.Console.WriteLine("<CulPrit><!--{0}--></CulPrit>", temp.Type(this).name); } } } break; } } } Console.WriteLine("</PossibleCulPrits>"); Console.WriteLine("<FirstObject>"); PrintGCRoot(idsFromRoot[0]); PrintStackTrace(idsFromRoot[0]); Console.WriteLine("</FirstObject>"); Console.WriteLine("<MisMatchedObjects>"); if (mismatchedObjects.Count > 0) { Console.WriteLine(); int limit = (mismatchedObjects.Count > 5) ? 5 : mismatchedObjects.Count; for (int i = 0; i < limit; i++) { Console.WriteLine("<Object>"); PrintGCRoot(idsFromRoot[mismatchedObjects[i]]); PrintStackTrace(idsFromRoot[mismatchedObjects[i]]); Console.WriteLine("</Object>"); } } Console.WriteLine("</MisMatchedObjects>"); }
internal Graph BuildReferenceGraph(Graph orgGraph) { var graph = new Graph(this, Graph.GraphType.ReferenceGraph); Vertex[] pathFromRoot = new Vertex[32]; GcObject rootObject = CreateRootObject(); FindVertex(0, rootObject, graph, BuildTypeGraphOptions.LumpBySignature); rootObject.InterestLevel = InterestLevel.Interesting; foreach (GcObject gcObject in idToObject.Values) { gcObject.parent = null; } // We wish to find all references to certain selected objects, // or, to be precise, all references that keep these objects alive. // To do this, we use a breadth first traversal of the object graph, using // a queue of objects still to process. If we find a reference to one of the // selected objects, we don't actually include this object, but instead // just make note of the reference // Initialize rootObject.parent = null; var foundBeforeMarker = new GcObject(); var queue = new Queue <GcObject>(); queue.Enqueue(rootObject); // Loop while (queue.Count != 0) { GcObject head = queue.Dequeue(); foreach (GcObject refObject in head.References) { if (refObject.parent == null || refObject.parent == foundBeforeMarker) { // this is a reference to either one of the "selected" objects // or just to a new object if (refObject.vertex != null && refObject.vertex.selected && (refObject.InterestLevel & (InterestLevel.Interesting | InterestLevel.Display)) != InterestLevel.Ignore && refObject.AllocTickIndex > orgGraph.allocatedAfterTickIndex && refObject.AllocTickIndex < orgGraph.allocatedBeforeTickIndex) { // add <root> -> ... -> head -> refObject to the reference graph int levels = 0; for (GcObject pathObject = head; pathObject != null; pathObject = pathObject.parent) { levels++; } while (pathFromRoot.Length < levels + 2) { pathFromRoot = new Vertex[pathFromRoot.Length * 2]; } pathFromRoot[levels + 1] = graph.FindOrCreateVertex(refObject.vertex.name, refObject.vertex.signature, refObject.vertex.moduleName); int level = levels; for (GcObject pathObject = head; pathObject != null; pathObject = pathObject.parent) { if ((pathObject.InterestLevel & (InterestLevel.Interesting | InterestLevel.Display)) == InterestLevel.Ignore || pathObject.vertex == null) { pathFromRoot[level] = null; } else { pathFromRoot[level] = graph.FindOrCreateVertex(pathObject.vertex.name, pathObject.vertex.signature, pathObject.vertex.moduleName); } level--; } int nonZeroLevels = 0; for (int j = 0; j <= levels + 1; j++) { if (pathFromRoot[j] != null) { pathFromRoot[nonZeroLevels++] = pathFromRoot[j]; } } levels = Vertex.SqueezeOutRepetitions(pathFromRoot, nonZeroLevels); for (int j = 0; j < levels - 1; j++) { Vertex fromVertex = pathFromRoot[j]; Vertex toVertex = pathFromRoot[j + 1]; Edge edge = graph.FindOrCreateEdge(fromVertex, toVertex); edge.AddWeight(1); } Vertex thisVertex = pathFromRoot[levels - 1]; thisVertex.basicWeight += 1; if (refObject.parent == null) { thisVertex.count += 1; refObject.parent = foundBeforeMarker; } } else { refObject.parent = head; queue.Enqueue(refObject); } } } } foreach (Vertex v in graph.vertices.Values) { if (v.weight < v.outgoingWeight) { v.weight = v.outgoingWeight; } if (v.weight < v.incomingWeight) { v.weight = v.incomingWeight; } if (v.weightHistory == null) { v.weightHistory = new ulong[1]; } } foreach (Vertex v in graph.vertices.Values) { v.active = true; } graph.BottomVertex.active = false; return(graph); }
void BuildClassTrace(Graph graph, int stackTraceIndex, int funcIndex, ulong size, Vertex[] funcVertex, ref Vertex[] vertexStack, FilterForm filterForm) { string className = ClassNameOfFunc(funcIndex); int functionsToSkip = FunctionsInSameClass(className, stackTraceIndex); int stackPtr = BuildVertexStack(stackTraceIndex, funcVertex, ref vertexStack, 0) - functionsToSkip; Vertex toVertex = graph.TopVertex; Vertex fromVertex; Edge edge; if (ReadNewLog.InterestingCallStack(vertexStack, stackPtr, filterForm)) { vertexStack[stackPtr] = graph.FindOrCreateVertex(className, null, null); vertexStack[stackPtr].interestLevel = filterForm.InterestLevelOfMethodName(className, null); stackPtr++; stackPtr = ReadNewLog.FilterVertices(vertexStack, stackPtr); stackPtr = Vertex.SqueezeOutRepetitions(vertexStack, stackPtr); for (int i = 0; i < stackPtr; i++) { fromVertex = toVertex; toVertex = vertexStack[i]; edge = graph.FindOrCreateEdge(fromVertex, toVertex); edge.AddWeight(size); } if (toVertex != graph.TopVertex) { fromVertex = toVertex; toVertex = graph.BottomVertex; edge = graph.FindOrCreateEdge(fromVertex, toVertex); edge.AddWeight(size); } } }
private double Score(Vertex v) { return v.weight*(Diversity(v.incomingEdges) + Diversity(v.outgoingEdges)); }
internal void BuildTypeVertices(Graph graph, ref Vertex[] typeVertex, FilterForm filterForm) { for (int i = 0; i < readNewLog.typeName.Length; i++) { string typeName = readNewLog.typeName[i]; if (typeName == null) typeName = string.Format("???? type {0}", i); readNewLog.AddTypeVertex(i, typeName, graph, ref typeVertex, filterForm); } }
private Vertex CloneVertex(Graph g, Vertex v) { Vertex vn = g.FindOrCreateVertex(v.name, v.signature, v.moduleName); vn.basicName = v.basicName; vn.basicSignature = v.basicSignature; vn.active = true; return vn; }
internal void AddTypeVertex(int typeId, string typeName, Graph graph, ref Vertex[] typeVertex, FilterForm filterForm) { EnsureVertexCapacity(typeId, ref typeVertex); typeVertex[typeId] = graph.FindOrCreateVertex(typeName, null, null); typeVertex[typeId].interestLevel = filterForm.InterestLevelOfTypeName(typeName, null, finalizableTypes.ContainsKey(typeId)); }
private void ZoomVertex(Vertex v, string titlePrefix) { toolTip.Active = false; Graph g; if (graph.graphSource is Graph) { Graph orgGraph = (Graph)graph.graphSource; g = new Graph(orgGraph); v = orgGraph.FindOrCreateVertex(v.name, v.signature, v.moduleName); } else g = new Graph(graph); g.allocatedAfterTickIndex = graph.allocatedAfterTickIndex; g.allocatedBeforeTickIndex = graph.allocatedBeforeTickIndex; Vertex vn = CloneVertex(g, v); vn.count = v.count; if (v.incomingEdges.Count == 0) { if (v != graph.TopVertex) g.FindOrCreateEdge(g.TopVertex, vn).AddWeight(v.weight); } else { foreach (Edge e in v.incomingEdges.Values) { Vertex vin = CloneVertex(g, e.FromVertex); g.FindOrCreateEdge(vin, vn).AddWeight(e.weight); if (vin != g.TopVertex) g.FindOrCreateEdge(g.TopVertex, vin).AddWeight(e.weight); } } if (v.outgoingEdges.Count == 0) { if (v != graph.BottomVertex) g.FindOrCreateEdge(vn, g.BottomVertex).AddWeight(v.weight); } else { foreach (Edge e in v.outgoingEdges.Values) { Vertex von = CloneVertex(g, e.ToVertex); g.FindOrCreateEdge(vn, von).AddWeight(e.weight); if (von != g.BottomVertex) g.FindOrCreateEdge(von, g.BottomVertex).AddWeight(e.weight); } } g.BottomVertex.active = false; g.graphType = graph.graphType; g.typeGraphOptions = graph.typeGraphOptions; if (titlePrefix == null) titlePrefix = "Zoom to: "; string title = titlePrefix + v.name + " " + (v.signature != null? v.signature : ""); GraphViewForm graphViewForm = new GraphViewForm(g, title); graphViewForm.Visible = true; }
internal int BuildAssemblyVertices(Graph graph, ref Vertex[] typeVertex, FilterForm filterForm) { int count = 0; foreach(string c in readNewLog.assemblies.Keys) { readNewLog.AddTypeVertex(count++, c, graph, ref typeVertex, filterForm); } return count; }
void PaintVertex(Vertex v, Graphics g, Brush penBrush, Pen pen) { Rectangle r = v.rectangle; v.selectionRectangle = r; g.DrawRectangle(pen, r); if (v.selected) { using (SolidBrush selectBrush = new SolidBrush(Color.Aqua)) g.FillRectangle(selectBrush, r); } RectangleF stringRect; int lineCount = 2; if (v.signature != null) lineCount = 3; if (r.Height > fontHeight*lineCount) stringRect = new RectangleF(r.X,r.Y,r.Width,fontHeight); else { stringRect = new RectangleF(r.X,r.Y+r.Height+3,r.Width,fontHeight); // for these very narrow rectangle, start the selection rectangle 5 pixels above // the actual rectangle, so people can hit it more easily. Even though they could click // on the text below, which not everybody tries... const int vTolerance = 5; v.selectionRectangle = new Rectangle(r.X, r.Y - vTolerance, r.Width, vTolerance + r.Height + 3 + fontHeight*lineCount); } if (v.weightHistory != null) { int alpha = 200; int previousHeight = r.Height; for (int i = 0; i < v.weightHistory.Length; i++) { alpha = alpha*2/3; ulong weight = v.weightHistory[i]; int height = (int)((float)r.Height/v.weight*weight); if (height < previousHeight) { Color color = Color.FromArgb(alpha, Color.Red); using (Brush brush = new SolidBrush(color)) { g.FillRectangle(brush, r.X, r.Y+height, r.Width, previousHeight - height); } } else { Color color = Color.FromArgb(alpha, Color.Green); using (Brush brush = new SolidBrush(color)) { g.FillRectangle(brush, r.X, r.Y+previousHeight, r.Width, height - previousHeight); } } previousHeight = height; } } g.DrawString(v.basicName, font, penBrush, stringRect); stringRect.Y += fontHeight; if (v.signature != null) { g.DrawString(v.basicSignature, font, penBrush, stringRect); stringRect.Y += fontHeight; int width = (int)g.MeasureString(v.basicSignature, font).Width; if (stringRect.Width < width) v.signatureCurtated = true; } g.DrawString(v.weightString, font, penBrush, stringRect); }
internal static bool InterestingCallStack(Vertex[] vertexStack, int stackPtr, FilterForm filterForm) { if (stackPtr == 0) return filterForm.methodFilters.Length == 0; if ((vertexStack[stackPtr-1].interestLevel & InterestLevel.Interesting) == InterestLevel.Interesting) return true; for (int i = stackPtr-2; i >= 0; i--) { switch (vertexStack[i].interestLevel & InterestLevel.InterestingChildren) { case InterestLevel.Ignore: break; case InterestLevel.InterestingChildren: return true; default: return false; } } return false; }
internal void BuildCallTrace(Graph graph, int stackTraceIndex, Vertex[] funcVertex, ref Vertex[] vertexStack, int count, FilterForm filterForm) { int stackPtr = BuildVertexStack(stackTraceIndex, funcVertex, ref vertexStack, 0); Vertex toVertex = graph.TopVertex; Vertex fromVertex; Edge edge; if (ReadNewLog.InterestingCallStack(vertexStack, stackPtr, filterForm)) { stackPtr = ReadNewLog.FilterVertices(vertexStack, stackPtr); stackPtr = Vertex.SqueezeOutRepetitions(vertexStack, stackPtr); for (int i = 0; i < stackPtr; i++) { fromVertex = toVertex; toVertex = vertexStack[i]; edge = graph.FindOrCreateEdge(fromVertex, toVertex); edge.AddWeight((uint)count); } } }
internal Graph BuildAssemblyGraph(FilterForm filterForm) { Vertex[] assemblyVertex = new Vertex[1]; Vertex[] funcVertex = new Vertex[1]; Vertex[] typeVertex = new Vertex[1]; Vertex[] vertexStack = new Vertex[1]; Graph graph = new Graph(this); graph.graphType = Graph.GraphType.AssemblyGraph; int count = BuildAssemblyVertices(graph, ref assemblyVertex, filterForm); BuildTypeVertices(graph, ref typeVertex, filterForm); BuildFuncVertices(graph, ref funcVertex, filterForm); for(int i = 0; i < count; i++) { Vertex v = (Vertex)assemblyVertex[i], tv = null; string c = v.name; int stackid = readNewLog.assemblies[c]; if(stackid < 0) { int[] stacktrace = readNewLog.stacktraceTable.IndexToStacktrace(-stackid); tv = typeVertex[stacktrace[0]]; } BuildAssemblyTrace(graph, stackid, v, tv, funcVertex, ref vertexStack); } foreach (Vertex v in graph.vertices.Values) { v.active = true; } graph.BottomVertex.active = false; return graph; }
void BuildFuncVertices(Graph graph, ref Vertex[] funcVertex, FilterForm filterForm) { for (int i = 0; i < readNewLog.funcName.Length; i++) { string name = readNewLog.funcName[i]; string signature = readNewLog.funcSignature[i]; if (name != null && signature != null) readNewLog.AddFunctionVertex(i, name, signature, graph, ref funcVertex, filterForm); } }
void BuildModVertices(Graph graph, ref Vertex[] modVertex, FilterForm filterForm) { for (int i = 0; i < readNewLog.modBasicName.Length; i++) { string basicName = readNewLog.modBasicName[i]; string fullName = readNewLog.modFullName[i]; if (basicName != null && fullName != null) { readNewLog.AddFunctionVertex(i, basicName, fullName, graph, ref modVertex, filterForm); modVertex[i].basicName = basicName; modVertex[i].basicSignature = fullName; } } }
internal void BuildHandleAllocationTrace(Graph graph, int stackTraceIndex, uint count, Vertex[] funcVertex, ref Vertex[] vertexStack, FilterForm filterForm) { int stackPtr = BuildVertexStack(stackTraceIndex, funcVertex, ref vertexStack, 0); Vertex handleVertex = graph.FindOrCreateVertex("Handle", null, null); handleVertex.interestLevel = InterestLevel.Interesting; Vertex toVertex = graph.TopVertex; Vertex fromVertex; Edge edge; if (ReadNewLog.InterestingCallStack(vertexStack, stackPtr, filterForm)) { vertexStack[stackPtr] = handleVertex; stackPtr++; stackPtr = ReadNewLog.FilterVertices(vertexStack, stackPtr); stackPtr = Vertex.SqueezeOutRepetitions(vertexStack, stackPtr); for (int i = 0; i < stackPtr; i++) { fromVertex = toVertex; toVertex = vertexStack[i]; edge = graph.FindOrCreateEdge(fromVertex, toVertex); edge.AddWeight(count); } fromVertex = toVertex; toVertex = graph.BottomVertex; edge = graph.FindOrCreateEdge(fromVertex, toVertex); edge.AddWeight(count); } }
internal void BuildAssemblyTrace(Graph graph, int stackTraceIndex, Vertex assembly, Vertex typeVertex, Vertex[] funcVertex, ref Vertex[] vertexStack) { int stackPtr = BuildVertexStack(Math.Abs(stackTraceIndex), funcVertex, ref vertexStack, stackTraceIndex < 0 ? 2 : 0); Vertex toVertex = graph.TopVertex; Vertex fromVertex; Edge edge; if(typeVertex != null) { vertexStack[stackPtr++] = typeVertex; } vertexStack[stackPtr++] = assembly; stackPtr = ReadNewLog.FilterVertices(vertexStack, stackPtr); stackPtr = Vertex.SqueezeOutRepetitions(vertexStack, stackPtr); for (int i = 0; i < stackPtr; i++) { fromVertex = toVertex; toVertex = vertexStack[i]; edge = graph.FindOrCreateEdge(fromVertex, toVertex); edge.AddWeight(1); } fromVertex = toVertex; toVertex = graph.BottomVertex; edge = graph.FindOrCreateEdge(fromVertex, toVertex); edge.AddWeight(1); }
internal Graph BuildTypeGraph(int allocatedAfterTickIndex, int allocatedBeforeTickIndex, BuildTypeGraphOptions options) { if (graph == null || FilterForm.filterVersion != graphFilterVersion || allocatedAfterTickIndex >= 0 || allocatedBeforeTickIndex < int.MaxValue) { graph = new Graph(this); graph.graphType = Graph.GraphType.HeapGraph; graphFilterVersion = FilterForm.filterVersion; graph.previousGraphTickIndex = allocatedAfterTickIndex; } else { ObjectGraph previousGraph = (ObjectGraph)graph.graphSource; graph.previousGraphTickIndex = previousGraph.tickIndex; graph.graphSource = this; foreach (Vertex v in graph.vertices.Values) { if (v.weightHistory == null) { v.weightHistory = new uint[1]; } else { uint[] weightHistory = v.weightHistory; if (weightHistory.Length < historyDepth) { v.weightHistory = new uint[weightHistory.Length + 1]; } for (int i = v.weightHistory.Length - 1; i > 0; i--) { v.weightHistory[i] = weightHistory[i - 1]; } } v.weightHistory[0] = v.weight; v.weight = v.incomingWeight = v.outgoingWeight = v.basicWeight = 0; v.count = 0; foreach (Edge e in v.outgoingEdges.Values) { e.weight = 0; } } } if (graph.previousGraphTickIndex < graph.allocatedAfterTickIndex) { graph.previousGraphTickIndex = graph.allocatedAfterTickIndex; } graph.allocatedAfterTickIndex = allocatedAfterTickIndex; graph.allocatedBeforeTickIndex = allocatedBeforeTickIndex; GcType rootType = GetOrCreateGcType("<root>", 0); GcObject rootObject = GetOrCreateObject(0); rootObject.type = rootType; rootObject.references = roots; foreach (GcObject gcObject in idToObject.Values) { gcObject.level = int.MaxValue; gcObject.vertex = null; } AssignLevels(rootObject); AssignInterestLevels(); int index = 0; foreach (GcType gcType in typeNameToGcType.Values) { gcType.index = index++; } GcType[] gcTypes = new GcType[index]; typeHintTable = new int[index]; foreach (GcType gcType in typeNameToGcType.Values) { gcTypes[gcType.index] = gcType; } Vertex[] pathFromRoot = new Vertex[32]; foreach (GcObject gcObject in idToObject.Values) { if (gcObject.level == int.MaxValue || (gcObject.interestLevel & (InterestLevel.Interesting | InterestLevel.Display)) == InterestLevel.Ignore || gcObject.allocTickIndex <= allocatedAfterTickIndex || gcObject.allocTickIndex >= allocatedBeforeTickIndex) { continue; } while (pathFromRoot.Length < gcObject.level + 1) { pathFromRoot = new Vertex[pathFromRoot.Length * 2]; } for (GcObject pathObject = gcObject; pathObject != null; pathObject = pathObject.parent) { if ((pathObject.interestLevel & (InterestLevel.Interesting | InterestLevel.Display)) == InterestLevel.Ignore) { pathFromRoot[pathObject.level] = null; } else { pathFromRoot[pathObject.level] = FindVertex(pathObject, graph, options); } } int levels = 0; for (int i = 0; i <= gcObject.level; i++) { if (pathFromRoot[i] != null) { pathFromRoot[levels++] = pathFromRoot[i]; } } levels = Vertex.SqueezeOutRepetitions(pathFromRoot, levels); for (int i = 0; i < levels - 1; i++) { Vertex fromVertex = pathFromRoot[i]; Vertex toVertex = pathFromRoot[i + 1]; Edge edge = graph.FindOrCreateEdge(fromVertex, toVertex); edge.AddWeight(gcObject.size); } Vertex thisVertex = pathFromRoot[levels - 1]; thisVertex.basicWeight += gcObject.size; thisVertex.count += 1; } foreach (Vertex v in graph.vertices.Values) { if (v.weight < v.outgoingWeight) { v.weight = v.outgoingWeight; } if (v.weight < v.incomingWeight) { v.weight = v.incomingWeight; } if (v.weightHistory == null) { v.weightHistory = new uint[1]; } } foreach (Vertex v in graph.vertices.Values) { v.active = true; } graph.BottomVertex.active = false; return(graph); }