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. }
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 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>"); }
internal string SignatureOfObject(ulong id, GcObject gcObject, BuildTypeGraphOptions options) { StringBuilder sb = new StringBuilder(); if (gcObject.parent != null) { switch (options) { case BuildTypeGraphOptions.IndividualObjects: if (gcObject.Type(this).name == "Stack" || gcObject.Type(this).name.StartsWith("Stack, ")) { if (id < (ulong)readNewLog.funcName.Length) { sb.AppendFormat(readNewLog.funcName[id] + " " + readNewLog.funcSignature[id]); } else { sb.AppendFormat("Function id = {0}", id); } } else { sb.AppendFormat("Address = {0}, size = {1:n0} bytes", FormatAddress(id), gcObject.Size(this)); } break; case BuildTypeGraphOptions.LumpBySignature: sb.Append(gcObject.parent.Type(this).name); sb.Append("->"); sb.Append(gcObject.Type(this).name); List <GcObject> references = new List <GcObject>(); foreach (GcObject refObject in gcObject.References) { references.Add(refObject); } if (references.Count > 0) { sb.Append("->("); const int MAXREFTYPECOUNT = 3; List <string> typeNameList = new List <string>(MAXREFTYPECOUNT); string separator = ""; int refTypeCount = 0; for (int i = 0; i < references.Count; i++) { GcObject refObject = references[i]; GcType refType = refObject.Type(this); if (typeHintTable[refType.index] < i && references[typeHintTable[refType.index]].Type(this) == refType) { ; // we already found this type - ignore further occurrences } else { typeHintTable[refType.index] = i; refTypeCount++; if (refTypeCount <= MAXREFTYPECOUNT) { typeNameList.Add(refType.name); } else { break; } } i++; } typeNameList.Sort(); foreach (string typeName in typeNameList) { sb.Append(separator); separator = ","; sb.Append(typeName); } if (refTypeCount > MAXREFTYPECOUNT) { sb.Append(",..."); } sb.Append(")"); } break; default: Debug.Assert(false); break; } } return(sb.ToString()); }
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>"); }