From a815b18d7d339329d28bd72e7c401cf3e66ec57e Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Sat, 4 Jul 2020 16:39:41 -0500 Subject: [PATCH] added Symbol Probe view --- src/ide/ui.ts | 3 + src/ide/views.ts | 155 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 146 insertions(+), 12 deletions(-) diff --git a/src/ide/ui.ts b/src/ide/ui.ts index 66ad671e..4c3c382b 100644 --- a/src/ide/ui.ts +++ b/src/ide/ui.ts @@ -288,6 +288,9 @@ function refreshWindowList() { addWindowItem("#probelog", "Probe Log", () => { return new Views.ProbeLogView(); }); + addWindowItem("#symbolprobe", "Symbol Profiler", () => { + return new Views.ProbeSymbolView(); + }); /* addWindowItem("#spheatmap", "Stack Probe", () => { return new Views.RasterStackMapView(); diff --git a/src/ide/views.ts b/src/ide/views.ts index 6a94c207..d2d1188c 100644 --- a/src/ide/views.ts +++ b/src/ide/views.ts @@ -546,13 +546,78 @@ export class ListingView extends DisassemblerView implements ProjectView { /// +interface VirtualTextLine { + text : string; + clas? : string; +} + +class VirtualTextScroller { + memorylist; + maindiv : HTMLElement; + getLineAt : (row:number) => VirtualTextLine; + + constructor(parent : HTMLElement) { + var div = document.createElement('div'); + div.setAttribute("class", "memdump"); + parent.appendChild(div); + this.maindiv = div; + } + + create(workspace : HTMLElement, maxRowCount : number, fn : (row:number) => VirtualTextLine) { + this.getLineAt = fn; + this.memorylist = new VirtualList({ + w: $(workspace).width(), + h: $(workspace).height(), + itemHeight: getVisibleEditorLineHeight(), + totalRows: maxRowCount, // TODO? + generatorFn: (row : number) => { + var line = fn(row); + var linediv = document.createElement("div"); + linediv.appendChild(document.createTextNode(line.text)); + if (line.clas != null) linediv.className = line.clas; + return linediv; + } + }); + $(this.maindiv).append(this.memorylist.container); + } + + // TODO: refactor with elsewhere + refresh() { + if (this.memorylist) { + $(this.maindiv).find('[data-index]').each( (i,e) => { + var div = e; + var row = parseInt(div.getAttribute('data-index')); + var oldtext = div.innerText; + var line = this.getLineAt(row); + var newtext = line.text; + if (oldtext != newtext) { + div.innerText = newtext; + if (line.clas != null && !div.classList.contains(line.clas)) { + var oldclasses = Array.from(div.classList); + oldclasses.forEach((c) => div.classList.remove(c)); + div.classList.add('vrow'); + div.classList.add(line.clas); + } + } + }); + } + } +} + +/// + +function ignoreSymbol(sym:string) { + return sym.endsWith('_SIZE__') || sym.endsWith('_LAST__') || sym.endsWith('STACKSIZE__') || sym.endsWith('FILEOFFS__') + || sym.startsWith('l__') || sym.startsWith('s__') || sym.startsWith('.__.'); +} + // TODO: make it use debug state // TODO: make it safe (load/restore state?) +// TODO: refactor w/ VirtualTextLine export class MemoryView implements ProjectView { memorylist; dumplines; maindiv : HTMLElement; - static IGNORE_SYMS = {s__INITIALIZER:true, /* s__GSINIT:true, */ _color_prom:true}; recreateOnResize = true; totalRows = 0x1400; @@ -663,18 +728,15 @@ export class MemoryView implements ProjectView { var nextsym = addr2sym[nextofs]; if (sym) { // ignore certain symbols - if (sym.endsWith('_SIZE__') || sym.endsWith('_LAST__') || sym.endsWith('STACKSIZE__') || sym.endsWith('FILEOFFS__') || sym.startsWith('l__')) + if (ignoreSymbol(sym)) { sym = ''; - if (MemoryView.IGNORE_SYMS[sym]) { - ofs = nextofs; - } else { - while (ofs < nextofs) { - var ofs2 = (ofs + 16) & 0xffff0; - if (ofs2 > nextofs) ofs2 = nextofs; - //if (ofs < 1000) console.log(ofs, ofs2, nextofs, sym); - this.dumplines.push({a:ofs, l:ofs2-ofs, s:sym}); - ofs = ofs2; - } + } + while (ofs < nextofs) { + var ofs2 = (ofs + 16) & 0xffff0; + if (ofs2 > nextofs) ofs2 = nextofs; + //if (ofs < 1000) console.log(ofs, ofs2, nextofs, sym); + this.dumplines.push({a:ofs, l:ofs2-ofs, s:sym}); + ofs = ofs2; } } sym = nextsym; @@ -1207,6 +1269,75 @@ export class ProbeLogView extends ProbeViewBaseBase { /// +export class ProbeSymbolView extends ProbeViewBaseBase { + vlist : VirtualTextScroller; + keys : string[]; + recreateOnResize = true; + dumplines; + + // TODO: auto resize + createDiv(parent : HTMLElement) { + // TODO: what if symbol list changes? + if (platform.debugSymbols && platform.debugSymbols.symbolmap) { + this.keys = Array.from(Object.keys(platform.debugSymbols.symbolmap).filter(sym => !ignoreSymbol(sym))); + } else { + this.keys = ['no symbols defined']; + } + this.vlist = new VirtualTextScroller(parent); + this.vlist.create(parent, this.keys.length, this.getMemoryLineAt.bind(this)); + return this.vlist.maindiv; + } + + getMemoryLineAt(row : number) : VirtualTextLine { + var sym = this.keys[row]; + var line = this.dumplines && this.dumplines[sym]; + function getop(op) { + var n = line[op] | 0; + return lpad(n ? n.toString() : "", 8); + } + var s : string; + var c : string; + if (line != null) { + s = lpad(sym, 35) + + getop(ProbeFlags.MEM_READ) + + getop(ProbeFlags.MEM_WRITE); + if (line[ProbeFlags.EXECUTE]) + c = 'seg_code'; + else if (line[ProbeFlags.IO_READ] || line[ProbeFlags.IO_WRITE]) + c = 'seg_io'; + else + c = 'seg_data'; + } else { + s = lpad(sym, 35); + c = 'seg_unknown'; + } + return {text:s, clas:c}; + } + + refresh() { + this.tick(); + } + + tick() { + // cache each line in frame + this.dumplines = {}; + this.redraw((op,addr,col,row,clk,value) => { + var sym = platform.debugSymbols.addr2symbol[addr]; + if (sym != null) { + var line = this.dumplines[sym]; + if (line == null) { + line = {}; + this.dumplines[sym] = line; + } + line[op] = (line[op] | 0) + 1; + } + }); + this.vlist.refresh(); + } +} + +/// + export class AssetEditorView implements ProjectView, pixed.EditorContext { maindiv : JQuery; cureditordiv : JQuery;