232 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
		
		
			
		
	
	
			232 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Haxe
		
	
	
	
	
	
|  | /* | ||
|  |  * Copyright (C)2005-2019 Haxe Foundation | ||
|  |  * | ||
|  |  * Permission is hereby granted, free of charge, to any person obtaining a | ||
|  |  * copy of this software and associated documentation files (the "Software"), | ||
|  |  * to deal in the Software without restriction, including without limitation | ||
|  |  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
|  |  * and/or sell copies of the Software, and to permit persons to whom the | ||
|  |  * Software is furnished to do so, subject to the following conditions: | ||
|  |  * | ||
|  |  * The above copyright notice and this permission notice shall be included in | ||
|  |  * all copies or substantial portions of the Software. | ||
|  |  * | ||
|  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
|  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
|  |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
|  |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
|  |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
|  |  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
|  |  * DEALINGS IN THE SOFTWARE. | ||
|  |  */ | ||
|  | 
 | ||
|  | package hl; | ||
|  | 
 | ||
|  | typedef Symbol = hl.Abstract<"hl_symbol">; | ||
|  | 
 | ||
|  | enum TrackKind { | ||
|  | 	Alloc; | ||
|  | 	Cast; | ||
|  | 	DynField; | ||
|  | 	DynCall; | ||
|  | } | ||
|  | 
 | ||
|  | class Result { | ||
|  | 	public var t:hl.Type; | ||
|  | 	public var kind:TrackKind; | ||
|  | 	public var count:Int; | ||
|  | 	public var info:Int; | ||
|  | 	public var stack:Array<String>; | ||
|  | 
 | ||
|  | 	public function new(t, count, info) { | ||
|  | 		this.t = t; | ||
|  | 		this.count = count; | ||
|  | 		this.info = info; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	@:keep public function toString() { | ||
|  | 		return t + "(" + count + ")"; | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | @:hlNative("std") | ||
|  | class Profile { | ||
|  | 	public static var threadBits(get, set):haxe.EnumFlags<TrackKind>; | ||
|  | 	public static var globalBits(get, set):haxe.EnumFlags<TrackKind>; | ||
|  | 
 | ||
|  | 	static var KINDS = null; | ||
|  | 
 | ||
|  | 	public static function getData(sortBySize = false, reset = true) { | ||
|  | 		var old = globalBits; | ||
|  | 		globalBits = new haxe.EnumFlags(); | ||
|  | 		if (buf == null) | ||
|  | 			buf = new hl.Bytes(BUFSIZE * 2); | ||
|  | 		track_lock(true); | ||
|  | 		var maxDepth = 0; | ||
|  | 		var count = track_count(maxDepth); | ||
|  | 		var arr = new hl.NativeArray<Symbol>(maxDepth); | ||
|  | 		var out = []; | ||
|  | 		if (KINDS == null) | ||
|  | 			KINDS = TrackKind.createAll(); | ||
|  | 		for (i in 0...count) { | ||
|  | 			var t:hl.Type = null, count = 0, info = 0; | ||
|  | 			var k = track_entry(i, t, count, info, arr); | ||
|  | 			if (count == 0) | ||
|  | 				continue; | ||
|  | 			var a = new Result(t, count, info); | ||
|  | 			a.kind = KINDS[k]; | ||
|  | 			a.stack = [for (a in arr) resolveSymbol(a)]; | ||
|  | 			out.push(a); | ||
|  | 		} | ||
|  | 		out.sort(function(a1, a2) { | ||
|  | 			if (a1.kind != a2.kind) | ||
|  | 				return a1.kind.getIndex() - a2.kind.getIndex(); | ||
|  | 			if (sortBySize && a1.kind == Alloc) | ||
|  | 				return a2.info - a1.info; | ||
|  | 			return a2.count - a1.count; | ||
|  | 		}); | ||
|  | 		track_lock(false); | ||
|  | 		if (reset) | ||
|  | 			Profile.reset(); | ||
|  | 		globalBits = old; | ||
|  | 		return out; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	public static function dump(fileName = "track.dump", sortBySize = false, reset = true) { | ||
|  | 		var old = globalBits; | ||
|  | 		globalBits = new haxe.EnumFlags(); | ||
|  | 		var f = sys.io.File.write(fileName); | ||
|  | 		var data = getData(sortBySize, reset); | ||
|  | 		var allocCount = 0, allocSize = 0, castCount = 0, dynCount = 0; | ||
|  | 		for (o in data) { | ||
|  | 			switch (o.kind) { | ||
|  | 				case Alloc: | ||
|  | 					allocCount += o.count; | ||
|  | 					allocSize += o.info; | ||
|  | 				case Cast: | ||
|  | 					castCount += o.count; | ||
|  | 				case DynCall, DynField: | ||
|  | 					dynCount += o.count; | ||
|  | 			} | ||
|  | 		} | ||
|  | 		if (data.length == 0) | ||
|  | 			f.writeString("Nothing\n"); | ||
|  | 		if (allocCount > 0) | ||
|  | 			f.writeString(allocCount + " total allocs (" + allocSize + " bytes)\n"); | ||
|  | 		if (castCount > 0) | ||
|  | 			f.writeString(castCount + " total casts\n"); | ||
|  | 		if (dynCount > 0) | ||
|  | 			f.writeString(dynCount + " total dynamic accesses/calls\n"); | ||
|  | 		for (o in data) { | ||
|  | 			var pcount = StringTools.lpad("" + o.count, " ", 5); | ||
|  | 			switch (o.kind) { | ||
|  | 				case Alloc: | ||
|  | 					f.writeString("alloc    " + pcount + " " + o.t + " (" + o.info + " bytes)\n"); | ||
|  | 				case Cast: | ||
|  | 					f.writeString("cast     " + pcount + " " + o.t + "\n"); | ||
|  | 				case DynCall: | ||
|  | 					f.writeString("dyncall  " + pcount + " " + o.t + "." + getFieldName(o.info) + "()\n"); | ||
|  | 				case DynField: | ||
|  | 					f.writeString("dynfield " + pcount + " " + o.t + "." + getFieldName(o.info) + "\n"); | ||
|  | 			} | ||
|  | 			for (s in o.stack) | ||
|  | 				f.writeString("\t\t\t\t" + s + "\n"); | ||
|  | 		} | ||
|  | 		f.close(); | ||
|  | 		globalBits = old; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Reset accumulated tracked data. | ||
|  | 	**/ | ||
|  | 	@:hlNative("std", "track_reset") public static function reset() {} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Restart tracking after being stopped. | ||
|  | 	**/ | ||
|  | 	@:hlNative("std", "track_init") public static function restart() {} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Stop tracking for all threads. | ||
|  | 	**/ | ||
|  | 	public static function stop() { | ||
|  | 		globalBits = new haxe.EnumFlags(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	/** | ||
|  | 		Set maximum stack depth for reports (default = 10) | ||
|  | 	**/ | ||
|  | 	@:hlNative("std", "track_set_depth") public static function setMaxDepth(v:Int) {} | ||
|  | 
 | ||
|  | 	static function get_threadBits() | ||
|  | 		return new haxe.EnumFlags(track_get_bits(true)); | ||
|  | 
 | ||
|  | 	static function set_threadBits(v:haxe.EnumFlags<TrackKind>) { | ||
|  | 		track_set_bits(v.toInt(), true); | ||
|  | 		return v; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static function get_globalBits() | ||
|  | 		return new haxe.EnumFlags(track_get_bits(false)); | ||
|  | 
 | ||
|  | 	static function set_globalBits(v:haxe.EnumFlags<TrackKind>) { | ||
|  | 		track_set_bits(v.toInt(), false); | ||
|  | 		return v; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static var BUFSIZE = 512; | ||
|  | 	static var buf:hl.Bytes; | ||
|  | 
 | ||
|  | 	static function resolveSymbol(s:Symbol) { | ||
|  | 		var size = BUFSIZE; | ||
|  | 		if (buf == null) | ||
|  | 			buf = new hl.Bytes(BUFSIZE * 2); | ||
|  | 		var bytes = resolve_symbol(s, buf, size); | ||
|  | 		if (bytes == null) | ||
|  | 			return "<???>"; | ||
|  | 		return @:privateAccess String.fromUCS2(bytes.sub(0, (size + 1) * 2)); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static function resolve_symbol(s:Symbol, buf:hl.Bytes, bufSize:hl.Ref<Int>):hl.Bytes { | ||
|  | 		return null; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static function track_count(maxDepth:hl.Ref<Int>):Int { | ||
|  | 		return 0; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static function track_entry(id:Int, type:hl.Ref<hl.Type>, count:hl.Ref<Int>, info:hl.Ref<Int>, stack:NativeArray<Symbol>):Int { | ||
|  | 		return 0; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static function track_init():Void {} | ||
|  | 
 | ||
|  | 	static function track_lock(b:Bool):Void {} | ||
|  | 
 | ||
|  | 	static function track_get_bits(thread:Bool):Int { | ||
|  | 		return 0; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	static function track_set_bits(bits:Int, thread:Bool):Void {} | ||
|  | 
 | ||
|  | 	static function __init__() | ||
|  | 		track_init(); | ||
|  | 
 | ||
|  | 	// todo : move later to hl.Bytes | ||
|  | 
 | ||
|  | 	@:hlNative("std", "field_name") | ||
|  | 	public static function getFieldName(hash:Int):Bytes { | ||
|  | 		return null; | ||
|  | 	} | ||
|  | 	 | ||
|  | 	@:hlNative(1.11) | ||
|  | 	static function sys_profile_event( code : Int, data : hl.Bytes, dataLen : Int ) : Void {} | ||
|  | 	public static function event( code : Int, ?data : String ) @:privateAccess { | ||
|  | 		sys_profile_event(code,data == null ? null : data.bytes, data == null ? 0 : (data.length<<1)); | ||
|  | 	} | ||
|  | 	public static function eventBytes( code : Int, data : haxe.io.Bytes ) @:privateAccess { | ||
|  | 		sys_profile_event(code,data == null ? null : data, data == null ? 0 : data.length); | ||
|  | 	} | ||
|  | 	 | ||
|  | } |