diff --git a/bali.nimble b/bali.nimble index a4763b0..00baebc 100644 --- a/bali.nimble +++ b/bali.nimble @@ -26,9 +26,8 @@ requires "noise >= 0.1.10" requires "fuzzy >= 0.1.0" requires "yaml >= 2.1.1" requires "https://github.com/xTrayambak/kaleidoscope >= 0.1.1" +requires "https://github.com/ferus-web/nim-gmp >= 0.1.0" taskRequires "fmt", "nph#master" task fmt, "Format code": exec "nph src/ tests/" - -requires "https://github.com/ferus-web/nim-gmp >= 0.1.0" diff --git a/src/balde.nim b/src/balde.nim index 75bb821..ae731ee 100644 --- a/src/balde.nim +++ b/src/balde.nim @@ -90,6 +90,39 @@ proc allocRuntime*(ctx: Input, file: string, ast: AST, repl: bool = false): Runt runtime +proc dumpStatisticsPretty(runtime: Runtime) = + let stats = runtime.dumpStatistics() + + stdout.styledWriteLine(styleBright, "Runtime Statistics", resetStyle) + stdout.styledWriteLine(fgGreen, "Atoms Allocated", resetStyle, ": ", styleBright, $stats.atomsAllocated, resetStyle) + + when defined(nimAllocStats): + stdout.styledWriteLine(fgGreen, "Traced Allocations", resetStyle, ": ", styleBright, $stats.numAllocations, resetStyle) + stdout.styledWriteLine(fgGreen, "Traced Deallocations", resetStyle, ": ", styleBright, $stats.numDeallocations, resetStyle) + else: + stdout.styledWriteLine( + "* ", styleItalic, styleBright, "Cannot show traced allocations/deallocations; compile Balde with ", + resetStyle, fgGreen, "--define:nimAllocStats", resetStyle, + styleItalic, " to see allocation/deallocation statistics." + ) + + stdout.styledWriteLine(fgGreen, "Bytecode Size (KB)", resetStyle, ": ", styleBright, $stats.bytecodeSize, resetStyle) + stdout.styledWriteLine(fgGreen, "Code Breaks Generated", resetStyle, ": ", styleBright, $stats.breaksGenerated, resetStyle) + stdout.styledWriteLine( + fgGreen, "VM State", resetStyle, ": ", + ( + if stats.vmHasHalted: + fgGreen + else: + fgRed + ), + (if stats.vmHasHalted: "Halted" else: "Running"), + resetStyle + ) + stdout.styledWriteLine(fgGreen, "Field Accesses", resetStyle, ": ", styleBright, $stats.fieldAccesses, resetStyle) + stdout.styledWriteLine(fgGreen, "Typeof Calls", resetStyle, ": ", styleBright, $stats.typeofCalls, resetStyle) + stdout.styledWriteLine(fgGreen, "Clauses Generated", resetStyle, ": ", styleBright, $stats.clausesGenerated, resetStyle) + func `%`(t: tuple[str: Option[string], exc: Option[void], ident: Option[string]]): JsonNode = if *t.str: return newJString &t.str @@ -172,6 +205,9 @@ proc execFile(ctx: Input, file: string) {.inline.} = of dmJsonPretty: let serialized = pretty(parseJson(toJson(ast))) # FIXME: this is horribly inefficient but it works echo serialized]# + + if ctx.enabled("dump-statistics"): + runtime.dumpStatisticsPretty() if ctx.enabled("dump-runtime-after-exec"): print runtime @@ -311,6 +347,8 @@ Options: --enable-experiments:;; ... Enable certain experimental features that aren't stable yet. --insert-debug-hooks, -H Insert some debug hooks that expose JavaScript code to the engine's internals. --test262 Insert some functions similar to those found in Test262. + --dump-statistics Dump some diagnostic statistics from the runtime. + --version, -V Output the version of Bali/Balde in the standard output Codegen Flags: --disable-loop-elision Don't attempt to elide loops in the IR generation phase. diff --git a/src/bali/grammar/parser.nim b/src/bali/grammar/parser.nim index dc47ad3..00f26d8 100644 --- a/src/bali/grammar/parser.nim +++ b/src/bali/grammar/parser.nim @@ -1017,7 +1017,6 @@ proc parseStatement*(parser: Parser): Option[Statement] = if not parser.tokenizer.eof(): let next = parser.tokenizer.nextExceptWhitespace() - print next if !next: #[ var args: PositionedArguments diff --git a/src/bali/runtime/bridge.nim b/src/bali/runtime/bridge.nim index 3845677..2c9d624 100644 --- a/src/bali/runtime/bridge.nim +++ b/src/bali/runtime/bridge.nim @@ -1,4 +1,4 @@ -import std/[logging, tables, options, strutils, hashes] +import std/[logging, tables, options, strutils, hashes, importutils] import mirage/runtime/prelude import mirage/ir/generator import bali/runtime/[atom_obj_variant, atom_helpers, types, normalize] @@ -6,6 +6,10 @@ import bali/stdlib/errors import bali/internal/sugar import pretty +privateAccess(Runtime) +privateAccess(PulsarInterpreter) +privateAccess(AllocStats) + proc defineFn*[T]( runtime: Runtime, prototype: typedesc[T], name: string, fn: NativeFunction ) = @@ -44,6 +48,28 @@ proc setProperty*[T]( if typ.proto == hash($prototype): runtime.types[i].members[name] = initAtomOrFunction[NativeFunction](value) +proc dumpStatistics*( + runtime: Runtime +): RuntimeStats = + info "runtime: dumping statistics" + var stats: RuntimeStats + + stats.atomsAllocated = uint(runtime.vm.stack.len) + stats.bytecodeSize = uint(runtime.vm.tokenizer.input.len / 1024) + stats.breaksGenerated = uint(runtime.irHints.breaksGeneratedAt.len) + stats.vmHasHalted = runtime.vm.halt + stats.fieldAccesses = runtime.statFieldAccesses + stats.typeofCalls = runtime.statTypeofCalls + stats.clausesGenerated = uint(runtime.ir.modules.len) + + let allocStats = runtime.allocStatsStart - getAllocStats() + stats.numAllocations = uint(allocStats.allocCount) + stats.numDeallocations = uint(allocStats.deallocCount) + + info "runtime: completed statistics dump" + + stats + proc setProperty*[V: not MAtom, T]( runtime: Runtime, prototype: typedesc[T], name: string, value: V diff --git a/src/bali/runtime/interpreter.nim b/src/bali/runtime/interpreter.nim index 65f8589..fcf188f 100644 --- a/src/bali/runtime/interpreter.nim +++ b/src/bali/runtime/interpreter.nim @@ -11,6 +11,7 @@ import bali/stdlib/prelude import crunchy, pretty privateAccess(PulsarInterpreter) +privateAccess(AllocStats) proc generateIR*( runtime: Runtime, @@ -1004,6 +1005,7 @@ proc generateInternalIR*(runtime: Runtime) = ) proc run*(runtime: Runtime) = + runtime.allocStatsStart = getAllocStats() runtime.test262 = runtime.ast.test262 console.generateStdIR(runtime) math.generateStdIR(runtime) diff --git a/src/bali/runtime/types.nim b/src/bali/runtime/types.nim index 114d2d9..293cf95 100644 --- a/src/bali/runtime/types.nim +++ b/src/bali/runtime/types.nim @@ -78,6 +78,17 @@ type IRHints* = object breaksGeneratedAt*: seq[uint] + RuntimeStats* = object + atomsAllocated*: uint ## How many atoms have been allocated so far? + bytecodeSize*: uint ## How many kilobytes is the bytecode? + breaksGenerated*: uint ## How many breaks did the codegen phase generate? + vmHasHalted*: bool ## Has execution ended? + fieldAccesses*: uint ## How many times has a field-access occurred? + typeofCalls*: uint ## How many times has a typeof call occured? + clausesGenerated*: uint ## How many clauses did the codegen phase generate? + + numAllocations*, numDeallocations*: uint ## How many allocations/deallocations happened during execution? + Runtime* = ref object ast*: AST ir*: IRGenerator @@ -93,6 +104,9 @@ type clauses*: seq[string] test262*: Test262Opts + statFieldAccesses, statTypeofCalls: uint + allocStatsStart*: AllocStats + types*: seq[JSType] proc setExperiment*(opts: var ExperimentOpts, name: string, value: bool): bool = diff --git a/tests/data/factorial.js b/tests/data/factorial.js index 9ae02b3..2d985a3 100644 --- a/tests/data/factorial.js +++ b/tests/data/factorial.js @@ -6,4 +6,4 @@ function fac(n) { return result } -fac(2) +console.log(fac(32))