Memory.hx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. import format.hl.Data;
  2. using format.hl.Tools;
  3. import Block;
  4. class Stats {
  5. var mem : Memory;
  6. var byT = new Map();
  7. var allT = [];
  8. public function new(mem) {
  9. this.mem = mem;
  10. }
  11. public function add( t : TType, mem : Int ) {
  12. return addPath([t == null ? 0 : t.tid], mem);
  13. }
  14. public function addPath( tl : Array<Int>, mem : Int ) {
  15. var key = tl.join(" ");
  16. var inf = byT.get(key);
  17. if( inf == null ) {
  18. inf = { tl : tl, count : 0, mem : 0 };
  19. byT.set(key, inf);
  20. allT.push(inf);
  21. }
  22. inf.count++;
  23. inf.mem += mem;
  24. }
  25. public function print() {
  26. allT.sort(function(i1, i2) return i1.mem - i2.mem);
  27. for( i in allT )
  28. mem.log(i.count + " count, " + Memory.MB(i.mem) + " " + [for( tid in i.tl ) mem.types[tid].toString()].join(" > "));
  29. }
  30. }
  31. class Memory {
  32. static inline var PAGE_BITS = 16;
  33. public var memoryDump : sys.io.FileInput;
  34. public var is64 : Bool;
  35. public var bool32 : Bool;
  36. public var ptrBits : Int;
  37. public var types : Array<TType>;
  38. var code : format.hl.Data;
  39. var pages : Array<Page>;
  40. var roots : Array<Pointer>;
  41. var stacks : Array<Stack>;
  42. var typesPointers : Array<Pointer>;
  43. var closuresPointers : Array<Pointer>;
  44. var blocks : Array<Block>;
  45. var baseTypes : Array<{ t : HLType, p : Pointer }>;
  46. var all : Block;
  47. var toProcess : Array<Block>;
  48. var tdynObj : TType;
  49. var tdynObjData : TType;
  50. var pointerBlock : Map<Pointer, Block>;
  51. var pointerType : Map<Pointer, TType>;
  52. var falseCandidates : Array<{ b : Block, f : Block, idx : Int }>;
  53. function new() {
  54. }
  55. public function typeSize( t : HLType ) {
  56. return switch( t ) {
  57. case HVoid: 0;
  58. case HUi8: 1;
  59. case HUi16: 2;
  60. case HI32, HF32: 4;
  61. case HF64: 8;
  62. case HBool:
  63. return bool32 ? 4 : 1;
  64. default:
  65. return is64 ? 8 : 4;
  66. }
  67. }
  68. public function getType( t : HLType, isNull = false ) : TType {
  69. // this is quite slow, but we can't use a Map, maybe try a more per-type specific approach ?
  70. for( t2 in types )
  71. if( t == t2.t )
  72. return t2;
  73. if( isNull )
  74. return null;
  75. throw "Type not found " + t.toString();
  76. return null;
  77. }
  78. function loadBytecode( arg : String ) {
  79. if( code != null ) throw "Duplicate code";
  80. code = new format.hl.Reader(false).read(new haxe.io.BytesInput(sys.io.File.getBytes(arg)));
  81. log(arg + " code loaded");
  82. }
  83. inline function readInt() {
  84. return memoryDump.readInt32();
  85. }
  86. inline function readPointer() : Pointer {
  87. return cast memoryDump.readInt32();
  88. }
  89. public static function MB( v : Float ) {
  90. if( v < 1000 )
  91. return Std.int(v) + "B";
  92. if( v < 1024 * 1000 )
  93. return (Math.round(v * 10 / 1024) / 10)+"KB";
  94. return (Math.round(v * 10 / (1024 * 1024)) / 10)+"MB";
  95. }
  96. function loadMemory( arg : String ) {
  97. memoryDump = sys.io.File.read(arg);
  98. if( memoryDump.read(3).toString() != "HMD" )
  99. throw "Invalid memory dump file";
  100. var version = memoryDump.readByte() - "0".code;
  101. var flags = readInt();
  102. is64 = (flags & 1) != 0;
  103. bool32 = (flags & 2) != 0;
  104. ptrBits = is64 ? 3 : 2;
  105. if( is64 ) throw "64 bit not supported";
  106. // load pages
  107. var count = readInt();
  108. pages = [];
  109. for( i in 0...count ) {
  110. while( true ) {
  111. var addr = readPointer();
  112. if( addr.isNull() ) break;
  113. var p = new Page(this);
  114. p.addr = addr;
  115. p.kind = cast readInt();
  116. p.size = readInt();
  117. p.blockSize = readInt();
  118. p.firstBlock = readInt();
  119. p.maxBlocks = readInt();
  120. p.nextBlock = readInt();
  121. p.dataPosition = memoryDump.tell();
  122. memoryDump.seek(p.size, SeekCur);
  123. var flags = readInt();
  124. if( flags & 1 != 0 )
  125. p.bmp = memoryDump.read((p.maxBlocks + 7) >> 3); // 1 bit per block
  126. if( flags & 2 != 0 )
  127. p.sizes = memoryDump.read(p.maxBlocks); // 1 byte per block
  128. pages.push(p);
  129. }
  130. }
  131. // load roots
  132. roots = [for( i in 0...readInt() ) readPointer()];
  133. // load stacks
  134. stacks = [];
  135. for( i in 0...readInt() ) {
  136. var s = new Stack();
  137. s.base = readPointer();
  138. s.contents = [for( i in 0...readInt() ) readPointer()];
  139. stacks.push(s);
  140. }
  141. // load types
  142. baseTypes = [];
  143. while( true ) {
  144. var tid = readInt();
  145. if( tid < 0 ) break;
  146. var ptr = readPointer();
  147. baseTypes.push({ t : Type.createEnumIndex(HLType, tid), p : ptr });
  148. }
  149. typesPointers = [for( i in 0...readInt() ) readPointer()];
  150. closuresPointers = [for( i in 0...readInt() ) readPointer()];
  151. }
  152. function printStats() {
  153. var totalSize = 0, maxSize = 0;
  154. var used = 0, gc = 0;
  155. for( p in pages ) {
  156. maxSize += p.size;
  157. totalSize += p.size + p.bmp.length;
  158. gc += p.size - (p.maxBlocks - p.firstBlock) * p.blockSize;
  159. gc += p.bmp.length;
  160. }
  161. for( b in blocks )
  162. used += b.getMemSize();
  163. log(pages.length + " pages, " + MB(totalSize) + " memory");
  164. log(roots.length + " roots, "+ stacks.length + " stacks");
  165. log(code.types.length + " types, " + closuresPointers.length + " closures");
  166. log(blocks.length + " live blocks " + MB(used) + " used, " + MB(maxSize - used) + " free, "+MB(gc)+" gc");
  167. }
  168. function getTypeNull( t : TType ) {
  169. if( t.nullWrap != null )
  170. return t.nullWrap;
  171. for( t2 in types )
  172. switch( t2.t ) {
  173. case HNull(base) if( base == t.t ):
  174. t.nullWrap = t2;
  175. return t2;
  176. default:
  177. }
  178. var r = new TType(types.length, HNull(t.t));
  179. t.nullWrap = r;
  180. types.push(r);
  181. return r;
  182. }
  183. function goto( b : Block ) {
  184. b.page.goto(b.bid);
  185. }
  186. function check() {
  187. if( code == null ) throw "Missing .hl file";
  188. if( memoryDump == null ) throw "Missing .dump file";
  189. if( code.types.length != this.typesPointers.length ) throw "Types count mismatch";
  190. pointerType = new Map();
  191. var cid = 0;
  192. types = [for( i in 0...code.types.length ) new TType(i, code.types[i])];
  193. for( i in 0...typesPointers.length ) {
  194. pointerType.set(typesPointers[i], types[i]);
  195. switch( code.types[i] ) {
  196. case HFun(f):
  197. var tid = types.length;
  198. var args = f.args.copy();
  199. var clparam = args.shift();
  200. if( clparam == null ) {
  201. cid++;
  202. continue;
  203. }
  204. switch( clparam ) {
  205. case HEnum(p) if( p.name == "" ):
  206. p.name = '<closure$i context>';
  207. default:
  208. }
  209. var ct = new TType(tid, HFun({ args : args, ret : f.ret }), clparam);
  210. types.push(ct);
  211. pointerType.set(closuresPointers[cid++], ct);
  212. default:
  213. }
  214. }
  215. for( b in baseTypes ) {
  216. var t = getType(b.t, true);
  217. if( t == null ) {
  218. t = new TType(types.length, b.t);
  219. types.push(t);
  220. }
  221. pointerType.set(b.p, t);
  222. }
  223. blocks = [];
  224. var pageMem = new Map();
  225. var progress = 0;
  226. pointerBlock = new Map();
  227. for( p in pages ) {
  228. progress++;
  229. if( progress % 100 == 0 )
  230. Sys.print((Std.int(progress * 1000 / pages.length) / 10) + "% \r");
  231. var bid = p.firstBlock;
  232. while( bid < p.maxBlocks ) {
  233. if( !p.isLiveBlock(bid) ) {
  234. bid++;
  235. continue;
  236. }
  237. var sz = p.getBlockSize(bid);
  238. var b = new Block();
  239. b.page = p;
  240. b.bid = bid;
  241. // NoPtr page can also have a type ptr
  242. goto(b);
  243. b.type = pointerType.get(readPointer());
  244. if( b.type != null && b.type.hasPtr && p.kind == PNoPtr )
  245. b.type = null; // false positive
  246. if( b.type != null && !b.type.isDyn )
  247. b.type = getTypeNull(b.type);
  248. if( b.type != null )
  249. b.typeKind = KHeader;
  250. blocks.push(b);
  251. pointerBlock.set(b.getPointer(), b);
  252. bid += sz;
  253. }
  254. for( i in 0...(p.size >> PAGE_BITS) )
  255. pageMem.set(p.addr.offset(i << PAGE_BITS), p);
  256. }
  257. printStats();
  258. // look in roots (higher ownership priority)
  259. all = new Block();
  260. var broot = new Block();
  261. broot.type = new TType(types.length, HAbstract("roots"));
  262. types.push(broot.type);
  263. broot.depth = 0;
  264. broot.addParent(all);
  265. var rid = 0;
  266. for( g in code.globals ) {
  267. if( !g.isPtr() ) continue;
  268. var r = roots[rid++];
  269. var b = pointerBlock.get(r);
  270. if( b == null ) continue;
  271. b.addParent(broot);
  272. if( b.type == null ) {
  273. b.type = getType(g);
  274. b.typeKind = KRoot;
  275. }
  276. }
  277. var tvoid = getType(HVoid);
  278. for( t in types )
  279. t.buildTypes(this, tvoid);
  280. tdynObj = getType(HDynObj);
  281. tdynObjData = new TType(types.length, HAbstract("dynobjdata"));
  282. types.push(tdynObjData);
  283. toProcess = blocks.copy();
  284. falseCandidates = [];
  285. while( toProcess.length > 0 )
  286. buildHierarchy();
  287. // look in stacks (low priority of ownership)
  288. var tstacks = new TType(types.length, HAbstract("stack"));
  289. var bstacks = [];
  290. types.push(tstacks);
  291. for( s in stacks ) {
  292. var bstack = new Block();
  293. bstack.depth = 10000;
  294. bstack.type = tstacks;
  295. bstack.addParent(all);
  296. bstacks.push(bstack);
  297. for( r in s.contents ) {
  298. var b = pointerBlock.get(r);
  299. if( b != null )
  300. b.addParent(bstack);
  301. }
  302. }
  303. for( f in falseCandidates )
  304. if( f.f.owner == null ) {
  305. f.f.addParent(f.b);
  306. f.b.type.falsePositive++;
  307. f.b.type.falsePositiveIndexes[f.idx]++;
  308. }
  309. // assign depths
  310. Sys.println("Computing depths...");
  311. broot.markDepth();
  312. for( b in bstacks ) b.markDepth();
  313. var changed = -1;
  314. while( changed != 0 ) {
  315. changed = 0;
  316. for( b in blocks ) {
  317. var minD = -1;
  318. if( b.parents == null ) {
  319. if( b.owner != null && b.owner.depth >= 0 )
  320. minD = b.owner.depth;
  321. } else {
  322. for( p in b.parents )
  323. if( p.depth >= 0 && (minD < 0 || p.depth < minD) )
  324. minD = p.depth;
  325. }
  326. if( minD >= 0 ) {
  327. minD++;
  328. if( b.depth < 0 || b.depth > minD ) {
  329. b.depth = minD;
  330. changed++;
  331. }
  332. }
  333. }
  334. }
  335. for( b in blocks )
  336. b.finalize();
  337. var unk = 0, unkMem = 0, unRef = 0;
  338. for( b in blocks ) {
  339. if( b.owner == null ) {
  340. unRef++;
  341. if( unRef < 100 )
  342. log(" "+b.getPointer().toString() + " is not referenced");
  343. continue;
  344. }
  345. if( b.type != null ) continue;
  346. var o = b.owner;
  347. while( o != null && o.type == null )
  348. o = o.owner;
  349. if( o != null )
  350. switch( o.type.t ) {
  351. case HAbstract(_):
  352. b.type = o.type; // data inside this
  353. b.typeKind = KAbstractData;
  354. continue;
  355. default:
  356. }
  357. unk++;
  358. unkMem += b.getMemSize();
  359. }
  360. var falseCount = 0;
  361. for( t in types )
  362. falseCount += t.falsePositive;
  363. log("Hierarchy built, "+unk+" unknown ("+MB(unkMem)+"), "+falseCount+" false positives, "+unRef+" unreferenced");
  364. }
  365. function printFalsePositives( ?typeStr : String ) {
  366. var falses = [for( t in types ) if( t.falsePositive > 0 && (typeStr == null || t.toString().indexOf(typeStr) >= 0) ) t];
  367. falses.sort(function(t1, t2) return t1.falsePositive - t2.falsePositive);
  368. for( f in falses )
  369. log(f.falsePositive+" count " + f + " "+f.falsePositiveIndexes+"\n "+f.fields);
  370. }
  371. function printUnknown() {
  372. var byT = new Map();
  373. for( b in blocks ) {
  374. if( b.type != null ) continue;
  375. var o = b;
  376. while( o != null && o.type == null )
  377. o = o.owner;
  378. var t = o == null ? null : o.type;
  379. var tid = t == null ? -1 : t.tid;
  380. var inf = byT.get(tid);
  381. if( inf == null ) {
  382. inf = { t : t, count : 0, mem : 0 };
  383. byT.set(tid, inf);
  384. }
  385. inf.count++;
  386. inf.mem += b.getMemSize();
  387. }
  388. var all = [for( k in byT ) k];
  389. all.sort(function(i1, i2) return i1.count - i2.count);
  390. for( a in all )
  391. log("Unknown "+a.count + " count, " + MB(a.mem)+" "+(a.t == null ? "" : a.t.toString()));
  392. }
  393. function buildHierarchy() {
  394. var progress = 0;
  395. var blocks = toProcess;
  396. toProcess = [];
  397. for( b in blocks )
  398. b.removeChildren();
  399. for( b in blocks ) {
  400. progress++;
  401. if( progress % 10000 == 0 )
  402. Sys.print((Std.int(progress * 1000.0 / blocks.length) / 10) + "% \r");
  403. if( b.page.kind == PNoPtr )
  404. continue;
  405. if( b.type != null && !b.type.hasPtr )
  406. switch(b.type.t) {
  407. case HFun(_):
  408. default:
  409. log(" Scanning "+b.type+" "+b.getPointer().toString());
  410. }
  411. goto(b);
  412. var fields = null;
  413. var start = 0;
  414. var ptrTags = null;
  415. if( b.type != null ) {
  416. fields = b.type.fields;
  417. ptrTags = b.type.ptrTags;
  418. // enum
  419. if( b.type.constructs != null ) {
  420. start++;
  421. fields = b.type.constructs[readInt()];
  422. if( is64 ) readInt(); // skip, not a pointer anyway
  423. }
  424. }
  425. for( i in start...(b.getMemSize() >> ptrBits) ) {
  426. var r = readPointer();
  427. //if( ptrTags != null && ((ptrTags.get(i >> 5) >>> (i & 31)) & 1) == 0 ) continue;
  428. var bs = pointerBlock.get(r);
  429. if( bs == null ) continue;
  430. var ft = fields != null ? fields[i] : null;
  431. if( b.type == tdynObj && (i == 1 || i == 2 || i == 3) ) {
  432. if( bs.typeKind != KHeader && (bs.typeKind != null || bs.type != null) )
  433. trace(bs.typeKind, bs.type);
  434. else {
  435. bs.type = tdynObjData;
  436. bs.typeKind = KDynObjData;
  437. }
  438. }
  439. if( ft != null && !ft.t.isPtr() ) {
  440. falseCandidates.push({ b : b, f:bs, idx : i });
  441. continue;
  442. }
  443. bs.addParent(b);
  444. if( bs.type == null && ft != null ) {
  445. if( ft.t.isDynamic() ) {
  446. trace(b.typeKind, b.getPointer().toString(), b.type.toString(), ft.toString());
  447. continue;
  448. }
  449. bs.type = ft;
  450. bs.typeKind = KInferred(b.type, b.typeKind);
  451. if( bs.subs != null )
  452. toProcess.push(bs);
  453. }
  454. }
  455. }
  456. }
  457. function printByType() {
  458. var ctx = new Stats(this);
  459. for( b in blocks )
  460. ctx.add(b.type, b.getMemSize());
  461. ctx.print();
  462. }
  463. function locate( tstr : String, up = 0 ) {
  464. var lt = null;
  465. for( t in types )
  466. if( t.t.toString() == tstr ) {
  467. lt = t;
  468. break;
  469. }
  470. if( lt == null ) {
  471. log("Type not found");
  472. return;
  473. }
  474. var ctx = new Stats(this);
  475. for( b in blocks )
  476. if( b.type == lt ) {
  477. var tl = [];
  478. var owner = b.owner;
  479. if( owner != null ) {
  480. var ol = [owner];
  481. tl.push(owner.type == null ? 0 : owner.type.tid);
  482. var k : Int = up;
  483. while( owner.owner != null && k-- > 0 && ol.indexOf(owner.owner) < 0 && owner.owner != all ) {
  484. var prev = owner;
  485. owner = owner.owner;
  486. ol.push(owner);
  487. tl.unshift(owner.type == null ? 0 : owner.type.tid);
  488. }
  489. }
  490. ctx.addPath(tl, b.getMemSize());
  491. }
  492. ctx.print();
  493. }
  494. function parents( tstr : String, up = 0 ) {
  495. var lt = null;
  496. for( t in types )
  497. if( t.t.toString() == tstr ) {
  498. lt = t;
  499. break;
  500. }
  501. if( lt == null ) {
  502. log("Type not found");
  503. return;
  504. }
  505. var ctx = new Stats(this);
  506. for( b in blocks )
  507. if( b.type == lt )
  508. for( b in b.getParents() )
  509. ctx.addPath([if( b.type == null ) 0 else b.type.tid], 0);
  510. ctx.print();
  511. }
  512. function subs( tstr : String, down = 0 ) {
  513. var lt = null;
  514. for( t in types )
  515. if( t.t.toString() == tstr ) {
  516. lt = t;
  517. break;
  518. }
  519. if( lt == null ) {
  520. log("Type not found");
  521. return;
  522. }
  523. var ctx = new Stats(this);
  524. var mark = new Map();
  525. for( b in blocks )
  526. if( b.type == lt ) {
  527. function addRec(tl:Array<Int>,b:Block, k:Int) {
  528. if( k < 0 ) return;
  529. if( mark.exists(b) )
  530. return;
  531. mark.set(b, true);
  532. tl.push(b.type == null ? 0 : b.type.tid);
  533. ctx.addPath(tl, b.getMemSize());
  534. if( b.subs != null ) {
  535. k--;
  536. for( s in b.subs )
  537. addRec(tl.copy(),s, k);
  538. }
  539. }
  540. addRec([], b, down);
  541. }
  542. ctx.print();
  543. }
  544. function printPartition() {
  545. var part = sys.io.File.write("part.txt",false);
  546. for( p in pages ) {
  547. var bid = p.firstBlock;
  548. part.writeString(p.addr.toString()+ " [" + p.blockSize+"]");
  549. while( bid < p.maxBlocks ) {
  550. if( !p.isLiveBlock(bid) ) {
  551. part.writeByte(".".code);
  552. bid++;
  553. continue;
  554. }
  555. var sz = p.getBlockSize(bid);
  556. for( i in 0...sz ) part.writeByte("#".code);
  557. bid += sz;
  558. }
  559. part.writeByte("\n".code);
  560. }
  561. part.close();
  562. log("Partition saved in part.txt");
  563. }
  564. public function log(msg:String) {
  565. Sys.println(msg);
  566. }
  567. static inline var BMP_BITS = 5;
  568. function makeBitmap() {
  569. // VMMap.exe tool can also be used to show address space fragmentation in realtime
  570. // although it will not be able to show GC fragmentation
  571. var totalMem = 2 * 1024. * 1024. * 1024.; // GB of memory
  572. var sizeReal = Math.ceil(Math.sqrt(totalMem / (1 << BMP_BITS)));
  573. var size = 1, bits = 1;
  574. while( size < sizeReal ) {
  575. size <<= 1;
  576. bits++;
  577. }
  578. var bytes = haxe.io.Bytes.alloc(size * size * 4);
  579. var bmp : hl.BytesAccess<Int> = (bytes : hl.Bytes);
  580. for( i in 0...size * size )
  581. bmp[i] = 0xFF000000;
  582. for( p in pages ) {
  583. var index = p.addr.shift(BMP_BITS);
  584. // reserved
  585. for( i in 0...(p.size >> BMP_BITS) )
  586. bmp[index+i] = 0xFF808080;
  587. for( i in 0...((p.firstBlock * p.blockSize) >> BMP_BITS) )
  588. bmp[index + i] = 0xFFFFFF00; // YELLOW = GC MEMORY
  589. }
  590. for( b in blocks ) {
  591. var index = b.getPointer().shift(BMP_BITS);
  592. var color = b.page.memHasPtr() ? 0xFFFF0000 : 0xFF00FF00; // GREEN = data / RED = objects
  593. for( i in 0...b.getMemSize() >> BMP_BITS )
  594. bmp[index + i] = color;
  595. }
  596. var f = sys.io.File.write("bitmap.png");
  597. new format.png.Writer(f).write(format.png.Tools.build32BGRA(size, size, bytes));
  598. f.close();
  599. }
  600. function printPages() {
  601. var perBlockSize = new Map();
  602. for( p in pages ) {
  603. var inf = perBlockSize.get(p.blockSize);
  604. if( inf == null ) {
  605. inf = {
  606. blockSize : p.blockSize,
  607. count : 0,
  608. mem : 0.,
  609. kinds : [],
  610. blocks : [],
  611. };
  612. perBlockSize.set(p.blockSize, inf);
  613. }
  614. inf.count++;
  615. inf.mem += p.size;
  616. inf.kinds[cast p.kind]++;
  617. }
  618. for( b in blocks ) {
  619. var inf = perBlockSize.get(b.page.blockSize);
  620. inf.blocks[cast b.page.kind]++;
  621. }
  622. var all = Lambda.array(perBlockSize);
  623. all.sort(function(i1, i2) return i1.blockSize - i2.blockSize);
  624. log("Kinds = [Dyn,Raw,NoPtr,Finalizer]");
  625. for( i in all )
  626. log('BlockSize ${i.blockSize} : ${i.count} pages, ${Std.int(i.mem/1024)} KB, kinds = ${i.kinds}, blocks = ${i.blocks}');
  627. }
  628. static function main() {
  629. var m = new Memory();
  630. //hl.Gc.dumpMemory(); Sys.command("cp memory.hl test.hl");
  631. var args = Sys.args();
  632. while( args.length > 0 ) {
  633. var arg = args.shift();
  634. if( StringTools.endsWith(arg, ".hl") ) {
  635. m.loadBytecode(arg);
  636. continue;
  637. }
  638. m.loadMemory(arg);
  639. }
  640. m.check();
  641. var stdin = Sys.stdin();
  642. while( true ) {
  643. Sys.print("> ");
  644. var args = ~/ +/g.split(StringTools.trim(stdin.readLine()));
  645. var cmd = args.shift();
  646. switch( cmd ) {
  647. case "exit", "quit", "q":
  648. break;
  649. case "types":
  650. m.printByType();
  651. case "stats":
  652. m.printStats();
  653. case "false":
  654. m.printFalsePositives(args.shift());
  655. case "unknown":
  656. m.printUnknown();
  657. case "locate":
  658. m.locate(args.shift(), Std.parseInt(args.shift()));
  659. case "parents":
  660. m.parents(args.shift());
  661. case "subs":
  662. m.subs(args.shift(), Std.parseInt(args.shift()));
  663. case "part":
  664. m.printPartition();
  665. case "bitmap":
  666. m.makeBitmap();
  667. case "pages":
  668. m.printPages();
  669. default:
  670. Sys.println("Unknown command " + cmd);
  671. }
  672. }
  673. }
  674. }