mmgc-graphviz
author Benjamin Smedberg <benjamin@smedbergs.us>
Sun, 20 Apr 2008 21:43:09 -0400
changeset 42 53c5098cb79e0223016b6901194a89d913f235fb
parent 34 ec1155ba48ec7f8f8b0c2e5f35f619d0ea4e95e3
permissions -rw-r--r--
Updates and imports

diff --git a/MMgc/GC.cpp b/MMgc/GC.cpp
--- a/MMgc/GC.cpp
+++ b/MMgc/GC.cpp
@@ -274,6 +274,9 @@ namespace MMgc
 #else
 		  disableThreadCheck(false)
 #endif
+#ifdef MMGC_GRAPHVIZ
+		  , m_gvFile(NULL)
+#endif
 	{
 		// sanity check for all our types
 		GCAssert (sizeof(int8) == 1);
@@ -346,6 +349,10 @@ namespace MMgc
 
 	GC::~GC()
 	{
+#ifdef MMGC_GRAPHVIZ
+		StopGraphing();
+#endif
+
 		// Force all objects to be destroyed
 		destroying = true;
 		ClearMarks();
@@ -539,7 +546,19 @@ namespace MMgc
 				cb->enterExclusiveGCNoLock();
 		}
 
+#ifdef MMGC_GRAPHVIZ
+		if (m_gvFile) {
+			fprintf(m_gvFile, "digraph C%d {\n", sweeps);
+			fprintf(m_gvFile, "    node [shape=box];\n");
+		}
+#endif
+
 		CollectImpl();
+
+#ifdef MMGC_GRAPHVIZ
+		if (m_gvFile)
+			fprintf(m_gvFile, "}\n");
+#endif
 
 #ifdef MMGC_THREADSAFE
 		m_lock.Acquire();
@@ -597,6 +616,46 @@ namespace MMgc
 #endif
 	}
 
+#define GRAPHVIZ_ROOT_STYLE "style=\"filled\", color=\"#ccddbb\""
+#define GRAPHVIZ_OBJECT_STYLE "style=\"filled\", color=\"#b3cc99\""
+#define GRAPHVIZ_CONSERVATIVE_EDGE_STYLE "color=\"#808080\""
+
+#ifdef MMGC_GRAPHVIZ
+	std::string Quote(const std::string &s)
+	{
+		// XXX BOGUS FIXME - should at least escape quotes and newlines
+		return '"' + s + '"';
+	}
+
+	void GC::GraphNode(const void *obj, const char *style)
+	{
+		if (m_gvFile != NULL && obj != NULL) {
+			if (IsGCMemory(obj)) {
+				std::string label;
+				if (IsFinalized(obj)) {
+					label = ((const GCFinalizedObject *) obj)->GetRepr();
+				} else {
+					label = typeid(*(const GCObject *) obj).name();
+				}
+				label = Quote(label);
+				fprintf(m_gvFile, "    P%p [label=%s, %s];\n",
+						obj, label.c_str(), style);
+			} else {
+				fprintf(m_gvFile, "    P%p [%s];\n", obj, style);
+			}
+		}
+	}
+
+	void GC::GraphEdge(const void *fromObj,
+					   const void *fromField,
+					   const void *toObj,
+					   const char *style)
+	{
+		if (m_gvFile)
+			fprintf(m_gvFile, "    P%p -> P%p [%s];\n", fromObj, toObj, style);
+	}
+#endif
+
 #ifdef _DEBUG
 	void GC::Trace(const void *stackStart/*=NULL*/, size_t stackSize/*=0*/)
 	{
@@ -617,6 +676,16 @@ namespace MMgc
 			GCRoot *r = m_roots;
 			while(r) {
 				GCWorkItem item = r->GetWorkItem();
+#ifdef MMGC_GRAPHVIZ
+				if (m_gvFile) {
+					fprintf(m_gvFile,
+							"    P%p [label=\"root at %p\", %s];\n",
+							item.ptr,
+							item.ptr,
+							GRAPHVIZ_ROOT_STYLE);
+				}
+#endif
+
 				MarkItem(item, work);
 				r = r->next;
 			}
@@ -2290,7 +2359,6 @@ bail:
 #undef ALLOCA_AND_FILL_WITH_SPACES
 #endif
 
-
 	void GC::StartIncrementalMark()
 	{
 		GCAssert(!marking);
@@ -2459,6 +2527,11 @@ bail:
 
 	void GC::MarkItem(GCWorkItem &wi, GCStack<GCWorkItem> &work)
 	{
+#ifdef MMGC_GRAPHVIZ
+		if (wi.IsGCItem())
+			GraphNode(wi.ptr, GRAPHVIZ_OBJECT_STYLE);
+#endif
+
 		size_t size = wi.GetSize();
 		uintptr *p = (uintptr*) wi.ptr;
 
@@ -2545,6 +2618,9 @@ bail:
 				{
 					if(block->alloc->ContainsPointers())
 					{
+#ifdef MMGC_GRAPHVIZ
+						GraphEdge(wi.ptr, p, item, GRAPHVIZ_CONSERVATIVE_EDGE_STYLE);
+#endif
 						// try custom marking
 						if ((bits2 & (GCAlloc::kFinalize<<shift)) != 0
 							&& ((GCFinalizedObject *) GetUserPointer(item))->CustomMark())
@@ -2623,6 +2699,10 @@ bail:
 					size_t usize = b->usableSize;
 					if((b->flags & GCLargeAlloc::kContainsPointers) != 0) 
 					{
+#ifdef MMGC_GRAPHVIZ
+						GraphEdge(wi.ptr, p, item, GRAPHVIZ_CONSERVATIVE_EDGE_STYLE);
+#endif
+
 						// try custom marking
 						if ((b->flags & GCLargeAlloc::kFinalizeFlag) != 0
 							&& ((GCFinalizedObject *) GetUserPointer(item))->CustomMark())
@@ -3239,5 +3319,4 @@ bail:
 	}
 #endif
 
-
 }
diff --git a/MMgc/GC.h b/MMgc/GC.h
--- a/MMgc/GC.h
+++ b/MMgc/GC.h
@@ -38,6 +38,10 @@
 
 #ifndef __GC__
 #define __GC__
+
+#ifdef MMGC_GRAPHVIZ
+#include <typeinfo>
+#endif
 
 #if defined MMGC_IA32
 
@@ -1590,8 +1594,8 @@ private:
 #endif
 #endif
 
-public:
 #ifdef MEMORY_INFO
+	public:
 		void DumpBackPointerChain(void *o);
 
 		// debugging routine that records who marked who, can be used to
@@ -1601,6 +1605,7 @@ public:
 		static void WriteBackPointer(const void *item, const void *container, size_t itemSize);
 #endif
 #ifdef _DEBUG
+	public:
 		// Dump a list of objects that have pointers to the given location.
 		void WhosPointingAtMe(void* me, int recurseDepth=0, int currentDepth=0);
 
@@ -1784,6 +1789,31 @@ public:
 		 * @access Requires(m_lock)
 		 */
 		GCCondition m_condNoRequests;
+#endif
+
+#ifdef MMGC_GRAPHVIZ
+	public:
+		void StartGraphing(const char *filename)
+		{
+			StopGraphing();
+			m_gvFile = fopen(filename, "w");
+		}
+
+		void StopGraphing()
+		{
+			if (m_gvFile)
+				fclose(m_gvFile);
+		}
+
+		void GraphNode(const void *obj, const char *style);
+
+		void GraphEdge(const void *fromObj,
+					   const void *fromField,
+					   const void *toObj,
+					   const char *style);
+
+	private:
+		FILE *m_gvFile;
 #endif
 	};
 
diff --git a/MMgc/GCObject.cpp b/MMgc/GCObject.cpp
--- a/MMgc/GCObject.cpp
+++ b/MMgc/GCObject.cpp
@@ -60,6 +60,19 @@ namespace MMgc
 		GC::GetGC(gcObject)->Free(gcObject);
 	}		
 
+	std::string GCFinalizedObject::GetRepr() const
+	{
+		std::string s;
+		char buf[60];
+		size_t n;
+
+		n = snprintf(buf, 60, "%s at %p",
+							typeid(*this).name(),
+							dynamic_cast<const void *>(this));
+		s.assign(buf, n);
+		return s;
+	}
+
 	void* GCFinalizedObjectOptIn::operator new(size_t size, GC *gc, size_t extra)
 	{
 		return gc->Alloc(size + extra, GC::kContainsPointers|GC::kZero, 4);
diff --git a/MMgc/GCObject.h b/MMgc/GCObject.h
--- a/MMgc/GCObject.h
+++ b/MMgc/GCObject.h
@@ -39,6 +39,7 @@
 #ifndef __GCObject__
 #define __GCObject__
 
+#include <string>
 
 // VC++ wants these declared
 //void *operator new(size_t size);
@@ -126,6 +127,10 @@ namespace MMgc
 		 * nothing and returns false.
 		 */
 		virtual bool CustomMark() { return false; }
+
+#ifdef MMGC_GRAPHVIZ
+		virtual std::string GetRepr() const;
+#endif
 	};
 
 	/**
diff --git a/MMgc/macbuild.h b/MMgc/macbuild.h
--- a/MMgc/macbuild.h
+++ b/MMgc/macbuild.h
@@ -66,6 +66,7 @@
  */
 #ifdef DEBUG
 #define MEMORY_INFO
+#define MMGC_GRAPHVIZ
 #endif
 
 /**