GcObject CreateRootObject() { GcObject rootObject = GcObject.CreateGcObject(rootCount); rootObject.TypeSizeStackTraceId = GetOrCreateGcType("<root>"); GcObject unknownObject = GcObject.CreateGcObject(0); unknownObject.TypeSizeStackTraceId = GetOrCreateGcType("<unknown type>"); for (int i = 0; i < rootCount; i++) { if (roots[i] == null) { roots[i] = idToObject[rootIDs[i]]; if (roots[i] == null) { roots[i] = unknownObject; } } roots[i].parent = null; roots[i].InterestLevel = InterestLevel.Interesting; rootObject.SetReference(i, roots[i]); } // patch up any unresolved forward references by making them point to "unknownObject" foreach (ForwardReference head in addressToForwardReferences.Values) { for (ForwardReference forwardReference = head; forwardReference != null; forwardReference = forwardReference.next) { forwardReference.source.SetReference(forwardReference.referenceNumber, unknownObject); } } addressToForwardReferences.Clear(); return(rootObject); }
void CreateForwardReference(ulong targetAddress, GcObject source, int referenceNumber) { ForwardReference nextForwardReference; addressToForwardReferences.TryGetValue(targetAddress, out nextForwardReference); addressToForwardReferences[targetAddress] = new ForwardReference(source, referenceNumber, nextForwardReference); }
// Check whether we have a parent object interested in this one private bool CheckForParentMarkingDescendant(GcObject gcObject) { GcObject parentObject = gcObject.parent; if (parentObject == null) { return(false); } switch (parentObject.interestLevel & InterestLevel.InterestingChildren) { // Parent says it wants to show children case InterestLevel.InterestingChildren: gcObject.interestLevel |= InterestLevel.Display; return(true); // Parent is not interesting - check its parent case InterestLevel.Ignore: if (CheckForParentMarkingDescendant(parentObject)) { gcObject.interestLevel |= InterestLevel.Display; return(true); } else { return(false); } default: return(false); } }
void AssignLevels(GcObject rootObject) { // We use a breadth first traversal of the object graph. // To do this, we make use of a queue of objects still to process. GcObject head, tail; // Initialize head = rootObject; tail = rootObject; rootObject.level = 0; // Loop while (head != null) { if (head.references != null) { int nextLevel = head.level + 1; foreach (GcObject refObject in head.references) { if (refObject.level > nextLevel) { refObject.parent = head; refObject.level = nextLevel; tail.next = refObject; tail = refObject; } } } head = head.next; } }
private GcObject[] GrowHintTable(GcObject[] hintTable) { GcObject[] newHintTable = new GcObject[hintTable.Length * 2]; for (int i = 0; i < hintTable.Length; i++) { newHintTable[i] = hintTable[i]; } return(newHintTable); }
internal void GrowMasterTable() { GcObject[][] newmasterTable = new GcObject[masterTable.Length * 2][]; for (int i = 0; i < masterTable.Length; i++) { newmasterTable[i] = masterTable[i]; } masterTable = newmasterTable; }
internal GcObject CreateAndEnterObject(ulong objectID, int typeSizeStackTraceId, int numberOfReferences, ulong[] references) { GcObject o = CreateObject(typeSizeStackTraceId, numberOfReferences, references); idToObject[objectID] = o; FillInForwardReferences(objectID, o); return(o); }
internal ObjectGraph() { // // TODO: Add constructor logic here // idToObject = new Hashtable(); typeNameToGcType = new Hashtable(); hintTable = new GcObject[10]; unknownType = GetOrCreateGcType("<unknown type>"); }
internal void CalculateTreeSize(GcObject rootObject) { nextHintIndex = 0; MarkObject(rootObject); rootObject.treeSize = 0; for (int i = 0; i < nextHintIndex; i++) { rootObject.treeSize += hintTable[i].size; } }
internal override void SetReference(int referenceNumber, GcObject target) { switch (referenceNumber) { case 0: reference0 = target; break; case 1: reference1 = target; break; default: Debug.Assert(referenceNumber == 0); break; } }
private void MarkDescendants(GcObject gcObject) { foreach (GcObject refObject in gcObject.References) { if (refObject.InterestLevel == InterestLevel.Ignore) { refObject.InterestLevel |= InterestLevel.Display; MarkDescendants(refObject); } } }
internal void GrowRoots() { GcObject[] newRoots = new GcObject[roots.Length * 2]; ulong[] newRootIDs = new ulong[roots.Length * 2]; for (int i = 0; i < roots.Length; i++) { newRoots[i] = roots[i]; newRootIDs[i] = rootIDs[i]; } roots = newRoots; rootIDs = newRootIDs; }
internal GcObject GetOrCreateObject(int objectID) { GcObject o = (GcObject)idToObject[objectID]; if (o == null) { o = new GcObject(objectID); idToObject[objectID] = o; o.type = unknownType; } return(o); }
internal GcObject[] LookupReferences(int count, int[] refIDs) { if (count == 0) { return(null); } GcObject[] result = new GcObject[count]; for (int i = 0; i < count; i++) { result[i] = GetOrCreateObject(refIDs[i]); } return(result); }
void FillInForwardReferences(ulong address, GcObject target) { ForwardReference forwardReference; if (addressToForwardReferences.TryGetValue(address, out forwardReference)) { while (forwardReference != null) { forwardReference.source.SetReference(forwardReference.referenceNumber, target); forwardReference = forwardReference.next; } } addressToForwardReferences.Remove(address); }
internal void AssignInterestLevelToObject(ulong id, GcObject gcObject, BuildTypeGraphOptions options, FilterForm filterForm, bool isRoot) { bool isInteresting = gcObject.Type(this).interestLevel == InterestLevel.Interesting && filterForm.IsInterestingAddress(id); if (isInteresting && filterForm.signatureFilters.Length != 0) { string signature = SignatureOfObject(id, gcObject, BuildTypeGraphOptions.LumpBySignature); isInteresting = filterForm.IsInterestingTypeName(gcObject.Type(this).name, signature, readNewLog.finalizableTypes.ContainsKey(gcObject.Type(this).typeID)); } if (isInteresting) { gcObject.InterestLevel = InterestLevel.Interesting; if (!isRoot) { gcObject.InterestLevel |= filterForm.InterestLevelForParentsAndChildren(); } } else { gcObject.InterestLevel = InterestLevel.Ignore; } // Check if this is an interesting object, and we are supposed to mark its ancestors if ((gcObject.InterestLevel & InterestLevel.InterestingParents) == InterestLevel.InterestingParents) { for (GcObject parentObject = gcObject.parent; parentObject != null; parentObject = parentObject.parent) { // As long as we find uninteresting objects, mark them for display // When we find an interesting object, we stop, because either it // will itself mark its parents, or it isn't interested in them (and we // respect that despite the interest of the current object, somewhat arbitrarily). if ((parentObject.InterestLevel & InterestLevel.InterestingParents) == InterestLevel.Ignore) { parentObject.InterestLevel |= InterestLevel.Display; } else { break; } } } // It's tempting here to mark the descendants as well, but they may be reached via // long reference paths, when there are shorter ones that were deemed uninteresting // Instead, we look whether our parent objects are interesting and want to show their // descendants, but we have to do that in a separate pass. }
void AssignLevel(GcObject parent, GcObject thisObject, int level) { if (thisObject.level > level) { thisObject.level = level; thisObject.parent = parent; if (thisObject.references != null) { foreach (GcObject refObject in thisObject.references) { AssignLevel(thisObject, refObject, level + 1); } } } }
internal void AddRootObject(GcObject rootObject, ulong rootID) { if (roots == null) { roots = new GcObject[initialRootCount]; rootIDs = new ulong[initialRootCount]; } if (roots.Length < rootCount + 1) { GrowRoots(); } rootIDs[rootCount] = rootID; roots[rootCount] = rootObject; rootCount++; }
internal Vertex FindVertex(ulong id, GcObject gcObject, Graph graph, BuildTypeGraphOptions options) { Vertex vertex = gcObject.vertex; if (vertex != null) { return(vertex); } string signature = SignatureOfObject(id, gcObject, options); vertex = graph.FindOrCreateVertex(gcObject.Type(this).name, signature, null); gcObject.vertex = vertex; return(vertex); }
internal GcObject this[ulong objectID] { get { int lowBits = (int)(objectID & lowAddressMask); int highBits = (int)(objectID >> lowAddressBits); if (highBits >= masterTable.Length) { return(null); } GcObject[] subTable = masterTable[highBits]; if (subTable == null) { return(null); } int bucket = lowBits >> bucketBits; lowBits = (lowBits >> alignBits) & idMask; GcObject o = subTable[bucket]; while (o != null && o.Id != lowBits) { o = o.nextInHash; } return(o); } set { int lowBits = (int)(objectID & lowAddressMask); int highBits = (int)(objectID >> lowAddressBits); while (highBits >= masterTable.Length) { GrowMasterTable(); } GcObject[] subTable = masterTable[highBits]; if (subTable == null) { masterTable[highBits] = subTable = new GcObject[1 << (lowAddressBits - bucketBits)]; } int bucket = lowBits >> bucketBits; lowBits = (lowBits >> alignBits) & idMask; value.Id = lowBits; value.nextInHash = subTable[bucket]; subTable[bucket] = value; } }
internal void PrintStackTrace(ulong[] path) { System.Console.WriteLine("<StackTrace>"); if ((path != null) && (path.Length > 0)) { GcObject tempGcObject = idToObject[path[path.Length - 1]]; Console.WriteLine("<!-- "); int[] stacktrace = readNewLog.stacktraceTable.IndexToStacktrace(tempGcObject.TypeSizeStackTraceId); for (int i = stacktrace.Length - 1; i >= 2; i--) { System.Console.WriteLine("{0} <-", readNewLog.funcName[stacktrace[i]]); } Console.WriteLine("-->"); } System.Console.WriteLine("</StackTrace>"); }
internal void PrintGCRoot(ulong[] path) { Console.WriteLine("<GcRoot>"); Console.WriteLine("<!-- "); for (int j = 0; j < path.Length; j++) { GcObject temp = idToObject[path[j]]; if (temp != null) { System.Console.WriteLine("{0}, {1:X} ->", temp.Type(this).name, path[j]); } //else // System.Console.WriteLine("{0}, n/a ->", path[j]); } Console.WriteLine("-->"); Console.WriteLine("</GcRoot>"); }
private void AssignInterestLevels() { foreach (GcType gcType in typeNameToGcType.Values) { // Otherwise figure which the interesting types are. gcType.interestLevel = FilterForm.InterestLevelOfTypeName(gcType.name); } foreach (GcObject gcObject in idToObject.Values) { // The initial interest level in objects is the one of their type gcObject.interestLevel = gcObject.type.interestLevel; } foreach (GcObject gcObject in idToObject.Values) { // Check if this is an interesting object, and we are supposed to mark its ancestors if ((gcObject.interestLevel & InterestLevel.InterestingParents) == InterestLevel.InterestingParents) { for (GcObject parentObject = gcObject.parent; parentObject != null; parentObject = parentObject.parent) { // As long as we find uninteresting object, mark them for display // When we find an interesting object, we stop, because either it // will itself mark its parents, or it isn't interested in them (and we // respect that despite the interest of the current object, somewhat arbitrarily). if ((parentObject.interestLevel & InterestLevel.InterestingParents) == InterestLevel.Ignore) { parentObject.interestLevel |= InterestLevel.Display; } else { break; } } } // Check if this object should be displayed because one of its ancestors // is interesting, and it says its descendents are interesting as well if ((gcObject.interestLevel & (InterestLevel.Interesting | InterestLevel.Display)) == InterestLevel.Ignore) { CheckForParentMarkingDescendant(gcObject); } } }
public IEnumerator <KeyValuePair <ulong, GcObject> > GetEnumerator() { for (int i = 0; i < masterTable.Length; i++) { GcObject[] subTable = masterTable[i]; if (subTable == null) { continue; } for (int j = 0; j < subTable.Length; j++) { for (GcObject gcObject = subTable[j]; gcObject != null; gcObject = gcObject.nextInHash) { yield return(new KeyValuePair <ulong, GcObject>(((ulong)i << lowAddressBits) + ((ulong)j << bucketBits) + ((ulong)gcObject.Id << alignBits), gcObject)); } } } }
private void MarkObject(GcObject o) { if (o.hint < nextHintIndex && hintTable[o.hint] == o) { return; } if (nextHintIndex >= hintTable.Length) { hintTable = GrowHintTable(hintTable); } o.hint = nextHintIndex++; hintTable[o.hint] = o; if (o.references != null) { foreach (GcObject refObject in o.references) { MarkObject(refObject); } } }
internal GcObject CreateObject(int typeSizeStackTraceId, int numberOfReferences, ulong[] references) { GcObject o = GcObject.CreateGcObject(numberOfReferences); o.TypeSizeStackTraceId = typeSizeStackTraceId; for (int i = 0; i < numberOfReferences; i++) { GcObject target = idToObject[references[i]]; if (target != null) { o.SetReference(i, target); } else { CreateForwardReference(references[i], o, i); } } empty = false; return(o); }
internal Graph BuildTypeGraph1() { Graph graph = new Graph(this); graph.graphType = Graph.GraphType.HeapGraph; GcType rootType = GetOrCreateGcType("<root>"); GcObject rootObject = GetOrCreateObject(0); rootObject.type = rootType; rootObject.references = roots; foreach (GcObject gcObject in idToObject.Values) { rootObject.size += gcObject.size; if (gcObject.references != null) { Vertex fromVertex = graph.FindOrCreateVertex(gcObject.type.name, null); foreach (GcObject toObject in gcObject.references) { Vertex toVertex = graph.FindOrCreateVertex(toObject.type.name, null); graph.FindOrCreateEdge(fromVertex, toVertex); } } } CalculateWeightsNonTransitive(graph); foreach (Vertex v in graph.vertices.Values) { v.active = true; } graph.BottomVertex.active = false; return(graph); }
void AssignParents(GcObject rootObject) { // We use a breadth first traversal of the object graph. // To do this, we make use of a queue of objects still to process. // Initialize Queue <GcObject> 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 = head; queue.Enqueue(refObject); } } } }
internal override void SetReference(int referenceNumber, GcObject target) { Debug.Assert(referenceNumber == 0); reference0 = target; }
internal Graph BuildTypeGraph() { if (graph == null || FilterForm.filterVersion != graphFilterVersion) { graph = new Graph(this); graph.graphType = Graph.GraphType.HeapGraph; graphFilterVersion = FilterForm.filterVersion; } else { foreach (Vertex v in graph.vertices.Values) { if (v.weightHistory == null) { v.weightHistory = new int[1]; } else { int[] weightHistory = v.weightHistory; if (weightHistory.Length < historyDepth) { v.weightHistory = new int[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 = v.count = 0; foreach (Edge e in v.outgoingEdges.Values) { e.weight = 0; } } } GcType rootType = GetOrCreateGcType("<root>"); GcObject rootObject = GetOrCreateObject(0); rootObject.type = rootType; rootObject.references = roots; foreach (GcObject gcObject in idToObject.Values) { gcObject.level = int.MaxValue; gcObject.vertex = null; } AssignLevel(null, rootObject, 0); 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) { 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); } } 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 int[1]; } } foreach (Vertex v in graph.vertices.Values) { v.active = true; } graph.BottomVertex.active = false; return(graph); }