-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[monitors] Add ConstMonitor which tracks constant arguments to functions
- Loading branch information
Showing
5 changed files
with
131 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
// Copyright 2024 Wizard Authors. All rights reserved. | ||
// See LICENSE for details of Apache 2.0 license. | ||
|
||
// Implements a simple monitor that counts the number of iterations of each loop. | ||
def monitor_ = MonitorRegistry.add( | ||
"const", "Tracks constants in various places in the program.", | ||
FuncArgsMonitor.new()); | ||
def filter = monitor_.options.addAlias( | ||
monitor_.options.newDeclFilterOption("filter", "apply constant tracking to selected functions"), | ||
"f"); | ||
var funcArgs = true; | ||
// XXX: trace loads/stores to memory, get/set of globals | ||
var entries: List<FuncArgsEntry>; | ||
|
||
class FuncArgsMonitor extends Monitor { | ||
def onParse(m: Module) { | ||
ModuleInstrumenter.new(m).forEachFuncFiltered(filter.val, instrument); | ||
} | ||
|
||
def onFinish(i: Instance, r: Result) { | ||
if (MonitorOptions.CSV.val) reportCsv(out); | ||
else report(out); | ||
} | ||
|
||
private def instrument(mm: ModuleInstrumenter, func: FuncDecl) { | ||
if (funcArgs) { | ||
var probe = FuncArgsEntry.new(mm.module, func); | ||
entries = List.new(probe, entries); | ||
Instrumentation.insertLocalProbe(mm.module, func.func_index, 0, probe); | ||
} | ||
|
||
} | ||
} | ||
|
||
def report(out: TraceBuilder) { | ||
for (l = Lists.reverse(entries); l != null; l = l.tail) { | ||
var entry = l.head; | ||
if (entry.count == 0) continue; | ||
out.beginColor(Color.FUNC) | ||
.put1("func %q:", entry.func.render(entry.module.names, _)) | ||
.beginColor(Color.COUNT) | ||
.put1(" %d", entry.count) | ||
.endColors() | ||
.puts(": ("); | ||
for (i < entry.consts.length) { | ||
var v = entry.consts[i]; | ||
if (i > 0) out.csp(); | ||
if (v == NON_CONST_VALUE) out.puts("?"); | ||
else out.beginColor(Color.VALUE).putv(v).endColors(); | ||
} | ||
out.puts(")").ln(); | ||
} | ||
} | ||
def reportCsv(out: TraceBuilder) { | ||
out.puts("func,count,args").ln(); | ||
for (l = Lists.reverse(entries); l != null; l = l.tail) { | ||
var entry = l.head; | ||
if (entry.count == 0) continue; | ||
out.put1("%q", entry.func.render(entry.module.names, _)) | ||
.put1(",%d,", entry.count) | ||
.puts("("); | ||
for (i < entry.consts.length) { | ||
var v = entry.consts[i]; | ||
if (i > 0) out.sp(); | ||
if (v == NON_CONST_VALUE) out.puts("?"); | ||
else out.putv(v); | ||
} | ||
out.puts(")").ln(); | ||
} | ||
} | ||
|
||
var NON_CONST_VALUE = Value.Ref(Object.new()); // nothing will compare equal to this value. | ||
|
||
// Records constants for function arguments. | ||
private class FuncArgsEntry(module: Module, func: FuncDecl) extends Probe { | ||
var count = 0uL; | ||
def consts = Array<Value>.new(func.sig.params.length); | ||
def fire(loc: DynamicLoc) -> Resumption { | ||
var accessor = loc.frame.getFrameAccessor(); | ||
if (count++ != 0) { | ||
// n'th invocation; check if any argument is different. | ||
for (i < consts.length) { | ||
var prev = consts[i]; | ||
var got = accessor.getLocal(i); | ||
if (prev != got) consts[i] = NON_CONST_VALUE; | ||
} | ||
} else { | ||
// first invocation. | ||
for (i < consts.length) consts[i] = accessor.getLocal(i); | ||
} | ||
return Resumption.Continue; | ||
} | ||
} | ||
|
||
private class ConstEntry { | ||
var count = 0uL; | ||
var const: Value; | ||
|
||
def add(v: Value) { | ||
if (count++ != 0 && const != v) const = NON_CONST_VALUE; | ||
else return void(const = v); | ||
|
||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
(module | ||
(func $main (export "main") | ||
(call $start) | ||
) | ||
(func $start (export "_start") | ||
(call $foo (i32.const 0) (i32.const 1)) | ||
(call $foo (i32.const 0) (i32.const 2)) | ||
) | ||
(func $foo (param i32 i32) | ||
) | ||
) |