@@ -523,6 +523,27 @@ public async Task ProcessThreadWithOptions(InvokerOptions options)
523523 st . duration += Context . InstructionTimer . ElapsedTicks ;
524524 Context . Stats [ ( ushort ) inst . Op ] = st ;
525525 }
526+ else if ( options . CollectStats == StatsDetail . Function )
527+ {
528+ Context . InstructionTimer . Restart ( ) ;
529+ if ( inst . PointerAdvance > 0 )
530+ Context . InstructionPointer += inst . PointerAdvance ;
531+ if ( inst . Nop )
532+ continue ;
533+
534+ if ( inst . IsAsync )
535+ await inst . ExecuteAsync ( Context ) ;
536+ else
537+ inst . Execute ( Context ) ;
538+
539+ Context . InstructionTimer . Stop ( ) ;
540+ Context . steps += inst . Size ;
541+
542+ var st = Context . Stats [ Context . Frame . FuncAddr ] ;
543+ st . count += inst . Size ;
544+ st . duration += Context . InstructionTimer . ElapsedTicks ;
545+ Context . Stats [ Context . Frame . FuncAddr ] = st ;
546+ }
526547 else
527548 {
528549 Context . InstructionTimer . Start ( ) ;
@@ -652,10 +673,10 @@ private void LogPostInstruction(InvokerOptions options, InstructionBase inst)
652673 private void PrintStats ( InvokerOptions options )
653674 {
654675 long procTicks = Context . ProcessTimer . ElapsedTicks ;
655- long totalExecs = options . CollectStats == StatsDetail . Instruction
676+ long totalExecs = options . CollectStats is StatsDetail . Instruction or StatsDetail . Function
656677 ? Context . Stats . Values . Sum ( dc => dc . count )
657678 : Context . steps ;
658- long execTicks = options . CollectStats == StatsDetail . Instruction
679+ long execTicks = options . CollectStats is StatsDetail . Instruction or StatsDetail . Function
659680 ? Context . Stats . Values . Sum ( dc => dc . duration )
660681 : Context . InstructionTimer . ElapsedTicks ;
661682 long overheadTicks = procTicks - execTicks ;
@@ -690,12 +711,32 @@ private void PrintStats(InvokerOptions options)
690711
691712 foreach ( var ( opcode , st ) in orderedStats )
692713 {
693- string label = $ "{ ( ( ByteCode ) opcode ) . GetMnemonic ( ) } ". PadLeft ( totalLabel . Length , ' ' ) ;
694714 TimeSpan instTime = new TimeSpan ( st . duration / 100 ) ; //100ns
695715 double percent = 100.0 * st . duration / execTicks ;
696- string execsLabel = $ "{ st . count } ". PadLeft ( totalInst . Length , ' ' ) ;
716+ int count = ( int ) st . count ;
717+
697718 string percentLabel = $ "{ percent : #0.###} %e". PadLeft ( 8 , ' ' ) ;
698- string instAve = $ "{ instTime . TotalMilliseconds * 1000000.0 / st . count : #0.#} ns/i";
719+ string label ;
720+ string instAve ;
721+ if ( options . CollectStats == StatsDetail . Function )
722+ {
723+ if ( Context . Store [ new FuncAddr ( opcode ) ] is FunctionInstance func )
724+ {
725+ count = func . CallCount ;
726+ label = $ "{ func . ModuleName } [{ func . Index . Value } ]". PadLeft ( totalLabel . Length , ' ' ) ;
727+ instAve = $ "{ instTime . TotalMilliseconds * 1000000.0 / count : #0.#} ns/call";
728+ }
729+ else
730+ {
731+ continue ;
732+ }
733+ }
734+ else
735+ {
736+ label = $ "{ ( ( ByteCode ) opcode ) . GetMnemonic ( ) } ". PadLeft ( totalLabel . Length , ' ' ) ;
737+ instAve = $ "{ instTime . TotalMilliseconds * 1000000.0 / count : #0.#} ns/i";
738+ }
739+ string execsLabel = $ "{ count } ". PadLeft ( totalInst . Length , ' ' ) ;
699740 Console . Error . WriteLine ( $ "{ label } : { execsLabel } | ({ percentLabel } ) { instTime . TotalMilliseconds : #0.000} ms { instAve } ") ;
700741 }
701742 }
0 commit comments