Bläddra i källkod

Improve memory dump tool readability (#626)

Leonardo 1 år sedan
förälder
incheckning
0f5cc0b005
2 ändrade filer med 115 tillägg och 10 borttagningar
  1. 111 10
      other/memory/Memory.hx
  2. 4 0
      other/memory/TType.hx

+ 111 - 10
other/memory/Memory.hx

@@ -57,7 +57,7 @@ class Stats {
 				}
 				tpath.push(tstr);
 			}
-			mem.log(i.count + " count, " + Memory.MB(i.mem) + " " + tpath.join(" > "));
+			mem.log(Memory.withColor(i.count + " count, " + Memory.MB(i.mem) + " ", 33) + tpath.join(${Memory.withColor(' > ', 36)}));
 		}
 		if( withSum )
 			mem.log("Total: "+totCount+" count, "+Memory.MB(totMem));
@@ -71,6 +71,12 @@ enum FieldsMode {
 	None;
 }
 
+enum FilterMode {
+	None;
+	Intersect;	// Will display only blocks present in all memories
+	Unique;		// Will display only blocks not present in other memories
+}
+
 class Memory {
 
 	public var memoryDump : sys.io.FileInput;
@@ -81,6 +87,11 @@ class Memory {
 
 	public var types : Array<TType>;
 
+	var otherMems : Array<Memory>;
+	var filterMode: FilterMode = None;
+
+	var memFile : String;
+
 	var privateData : Int;
 	var markData : Int;
 
@@ -95,6 +106,7 @@ class Memory {
 	var typesPointers : Array<Pointer>;
 	var closuresPointers : Array<Pointer>;
 	var blocks : Array<Block>;
+	var filteredBlocks : Array<Block> = [];
 	var baseTypes : Array<{ t : HLType, p : Pointer }>;
 	var all : Block;
 
@@ -164,6 +176,7 @@ class Memory {
 	}
 
 	function loadMemory( arg : String ) {
+		memFile = arg;
 		memoryDump = sys.io.File.read(arg);
 		if( memoryDump.read(3).toString() != "HMD" )
 			throw "Invalid memory dump file";
@@ -243,16 +256,22 @@ class Memory {
 	function printStats() {
 		var pagesSize = 0, reserved = 0;
 		var used = 0, gc = 0;
+		var fUsed = 0;
 		for( p in pages ) {
 			pagesSize += p.size;
 			reserved += p.reserved;
 		}
 		for( b in blocks )
 			used += b.size;
+		for (b in filteredBlocks)
+			fUsed += b.size;
+		log(withColor("--- " + memFile + " ---", 36));
 		log(pages.length + " pages, " + MB(pagesSize) + " memory");
 		log(roots.length + " roots, "+ stacks.length + " stacks");
 		log(code.types.length + " types, " + closuresPointers.length + " closures");
 		log(blocks.length + " live blocks " + MB(used) + " used, " + MB(pagesSize - used - reserved) + " free, "+MB(privateData + markData)+" gc");
+		if (filterMode != None)
+			log(filteredBlocks.length + " blocks in filter " + MB(fUsed) + " used");
 	}
 
 	function getTypeNull( t : TType ) {
@@ -625,7 +644,7 @@ class Memory {
 
 	function printByType() {
 		var ctx = new Stats(this);
-		for( b in blocks )
+		for( b in filteredBlocks )
 			ctx.add(b.type, b.size);
 		ctx.print();
 	}
@@ -656,7 +675,7 @@ class Memory {
 		inline function isVirtualField(t) { t >>>= 24; return t == 1 || t == 2; }
 
 		var ctx = new Stats(this);
-		for( b in blocks )
+		for( b in filteredBlocks )
 			if( b.type != null && b.type.match(lt) ) {
 				var tl = [];
 				var owner = b.owner;
@@ -711,7 +730,7 @@ class Memory {
 		var ctx = new Stats(this);
 		Block.MARK_UID++;
 		var mark = [];
-		for( b in blocks )
+		for( b in filteredBlocks )
 			if( b.type == t )
 				visitRec(b,ctx,[],mark);
 		while( mark.length > 0 ) {
@@ -744,7 +763,7 @@ class Memory {
 		}
 
 		var ctx = new Stats(this);
-		for( b in blocks )
+		for( b in filteredBlocks )
 			if( b.type == lt )
 				for( b in b.getParents() )
 					ctx.addPath([if( b.type == null ) 0 else b.type.tid], 0);
@@ -765,7 +784,7 @@ class Memory {
 
 		var ctx = new Stats(this);
 		var mark = new Map();
-		for( b in blocks )
+		for( b in filteredBlocks )
 			if( b.type == lt ) {
 				function addRec(tl:Array<Int>,b:Block, k:Int) {
 					if( k < 0 ) return;
@@ -775,7 +794,7 @@ class Memory {
 					tl.push(b.type == null ? 0 : b.type.tid);
 					ctx.addPath(tl, b.size);
 					if( b.subs != null ) {
-						k--;
+							k--;
 						for( s in b.subs )
 							addRec(tl.copy(),s.b, k);
 					}
@@ -785,6 +804,43 @@ class Memory {
 		ctx.print();
 	}
 
+	public function setFilterMode(m: FilterMode) {
+		filterMode = m;
+		switch( m ) {
+		case None:
+			filteredBlocks = blocks.copy();
+		default:
+			filteredBlocks = [];
+			var progress = 0;
+			for( b in blocks ) {
+				progress++;
+				if( displayProgress && progress % 1000 == 0 )
+					Sys.print((Std.int((progress / blocks.length) * 1000.0) / 10) + "%  \r");
+				if( !isBlockIgnored(b, m) )
+					filteredBlocks.push(b);
+			}
+			if( displayProgress )
+				Sys.print("       \r");
+		}
+	}
+	public function isBlockIgnored(b: Block, m: FilterMode) {
+		switch( m ) {
+		case None:
+			return false;
+		case Intersect:
+			for( m in otherMems ) {
+				if( m.pointerBlock.get(b.addr ) == null )
+					return true;
+			}
+		case Unique:
+			for( m in otherMems ) {
+				if( m.pointerBlock.get(b.addr ) != null )
+					return true;
+			}
+		}
+		return false;
+	}
+
 	public function log(msg:String) {
 		Sys.println(msg);
 	}
@@ -813,8 +869,11 @@ class Memory {
 		return args;
 	}
 
+	static var useColor = false;
 	static function main() {
 		var m = new Memory();
+		var others: Array<Memory> = [];
+		var filterMode: FilterMode = None;
 
 		//hl.Gc.dumpMemory(); Sys.command("cp memory.hl test.hl");
 
@@ -827,12 +886,22 @@ class Memory {
 				m.loadBytecode(arg);
 				continue;
 			}
+			if( arg == "-c" || arg == "--color" ) {
+				useColor = true;
+				continue;
+			}
 			if( arg == "--args" ) {
 				m.displayProgress = false;
 				break;
 			}
-			memory = arg;
-			m.loadMemory(arg);
+			if (memory == null) {
+				memory = arg;
+				m.loadMemory(arg);
+			} else {
+				var m2 = new Memory();
+				m2.loadMemory(arg);
+				others.push(m2);
+			}
 		}
 		if( code != null && memory == null ) {
 			var dir = new haxe.io.Path(code).dir;
@@ -842,10 +911,16 @@ class Memory {
 		}
 
 		m.check();
+		for (m2 in others) {
+			m2.code = m.code;
+			m2.check();
+		}
+		m.otherMems = [for (i in others) i];
+		m.setFilterMode(filterMode);
 
 		var stdin = Sys.stdin();
 		while( true ) {
-			Sys.print("> ");
+			Sys.print(withColor("> ", 31));
 			var args = parseArgs(args.length > 0 ? args.shift() : stdin.readLine());
 			var cmd = args.shift();
 			switch( cmd ) {
@@ -887,6 +962,25 @@ class Memory {
 				case mode:
 					Sys.println("Unknown fields mode " + mode);
 				}
+			case "filter":
+				switch( args.shift() ) {
+				case "none":
+					filterMode = None;
+				case "intersect":
+					filterMode = Intersect;
+				case "unique":
+					filterMode = Unique;
+				case mode:
+					Sys.println("Unknown filter mode " + mode);
+				}
+				m.setFilterMode(filterMode);
+			case "nextDump":
+				others.push(m);
+				m = others.shift();
+				m.otherMems = [for (i in others) i];
+				m.setFilterMode(filterMode);
+				var ostr = others.length > 0 ? (" (others are " + others.map(m -> m.memFile) + ")") : "";
+				Sys.println("Using dump " + m.memFile + ostr);
 			case "lines":
 				var v = args.shift();
 				if( v != null )
@@ -900,4 +994,11 @@ class Memory {
 		}
 	}
 
+	// A list of ansi colors is available at
+	// https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#8-16-colors
+	public static function withColor(str: String, ansiCol: Int) {
+		if (!useColor)
+			return str;
+		return "\x1B[" + ansiCol + "m" + str + "\x1B[0m";
+	}
 }

+ 4 - 0
other/memory/TType.hx

@@ -172,8 +172,12 @@ class TType {
 
 	public function toString() {
 		switch( t ) {
+		case HAbstract("roots"):
+			return Memory.withColor("roots", 32);
 		case HAbstract(p):
 			return p;
+		case HFun(_), HMethod(_):
+			return 'Function(${t.toString()})';
 		default:
 			return t.toString();
 		}