implement basic version of the instruction profiler plugin

this is entirely based on the earlier implementation in the iprof
module made by @hzzhang
features/iprof_plugin
Joran Honig 6 years ago
parent 42ebc3bd51
commit 0f27e06e0c
  1. 89
      mythril/laser/ethereum/plugins/implementations/instruction_profiler_plugin.py

@ -2,6 +2,30 @@ from mythril.laser.ethereum.svm import LaserEVM
from mythril.laser.ethereum.plugins.plugin import LaserPlugin from mythril.laser.ethereum.plugins.plugin import LaserPlugin
from mythril.laser.ethereum.state.global_state import GlobalState from mythril.laser.ethereum.state.global_state import GlobalState
from collections import namedtuple
from datetime import datetime
from typing import Dict, List, Tuple
# Type annotations:
# start_time: datetime
# end_time: datetime
_InstrExecRecord = namedtuple("_InstrExecRecord", ["start_time", "end_time"])
# Type annotations:
# total_time: float
# total_nr: float
# min_time: float
# max_time: float
_InstrExecStatistic = namedtuple(
"_InstrExecStatistic", ["total_time", "total_nr", "min_time", "max_time"]
)
# Map the instruction opcode to its records if all execution times
_InstrExecRecords = Dict[str, List[_InstrExecRecord]]
# Map the instruction opcode to the statistic of its execution times
_InstrExecStatistics = Dict[str, _InstrExecStatistic]
class InstructionProfilerPlugin(LaserPlugin): class InstructionProfilerPlugin(LaserPlugin):
""" Instruction profiler plugin """ Instruction profiler plugin
@ -10,10 +34,73 @@ class InstructionProfilerPlugin(LaserPlugin):
It does so by measuring the frequency and duration of each operation execution It does so by measuring the frequency and duration of each operation execution
""" """
def __init__(self):
self.records = dict()
def record(self, op: int, start_time: datetime, end_time: datetime):
try:
self.records[op].append(_InstrExecRecord(start_time, end_time))
except KeyError:
self.records[op] = [_InstrExecRecord(start_time, end_time)]
def _make_stats(self) -> Tuple[float, _InstrExecStatistics]:
periods = {
op: list(
map(lambda r: r.end_time.timestamp() - r.start_time.timestamp(), rs)
)
for op, rs in self.records.items()
}
stats = dict()
total_time = 0
for _, (op, times) in enumerate(periods.items()):
stat = _InstrExecStatistic(
total_time=sum(times),
total_nr=len(times),
min_time=min(times),
max_time=max(times),
)
total_time += stat.total_time
stats[op] = stat
return total_time, stats
def __str__(self):
total, stats = self._make_stats()
s = "Total: {} s\n".format(total)
for op in sorted(stats):
stat = stats[op]
s += "[{:12s}] {:>8.4f} %, nr {:>6}, total {:>8.4f} s, avg {:>8.4f} s, min {:>8.4f} s, max {:>8.4f} s\n".format(
op,
stat.total_time * 100 / total,
stat.total_nr,
stat.total_time,
stat.total_time / stat.total_nr,
stat.min_time,
stat.max_time,
)
return s
def initialize(self, symbolic_vm: LaserEVM): def initialize(self, symbolic_vm: LaserEVM):
"""Initializes the instruction profiler """Initializes the instruction profiler
Introduces hooks that measure the duration of each execution and the name of the instruction being executed Introduces hooks that measure the duration of each execution and the name of the instruction being executed
:param symbolic_vm: The virtual machine to initialize the plugin for :param symbolic_vm: The virtual machine to initialize the plugin for
""" """
pass
@symbolic_vm.register_instruction_evaluate_wrapper
def introduce_wrap(evaluate):
def evaluate(*args, **kwargs):
start_time = datetime.now()
try:
evaluate(*args, **kwargs)
finally:
end_time = datetime.now()
self.record(op=args[0], start_time=start_time, end_time=end_time)
return evaluate

Loading…
Cancel
Save