add perf counters in module capa.perf

This commit is contained in:
William Ballenthin
2021-11-05 14:59:22 -06:00
parent 3d068fe3cd
commit 86cab26a69
5 changed files with 38 additions and 0 deletions

View File

@@ -10,6 +10,7 @@ import copy
import collections
from typing import Set, Dict, List, Tuple, Union, Mapping, Iterable
import capa.perf
import capa.rules
import capa.features.common
from capa.features.common import Feature
@@ -125,6 +126,9 @@ class And(Statement):
self.children = children
def evaluate(self, ctx):
capa.perf.counters["evaluate.feature"] += 1
capa.perf.counters["evaluate.feature.and"] += 1
results = [child.evaluate(ctx) for child in self.children]
success = all(results)
return Result(success, self, results)
@@ -138,6 +142,9 @@ class Or(Statement):
self.children = children
def evaluate(self, ctx):
capa.perf.counters["evaluate.feature"] += 1
capa.perf.counters["evaluate.feature.or"] += 1
results = [child.evaluate(ctx) for child in self.children]
success = any(results)
return Result(success, self, results)
@@ -151,6 +158,9 @@ class Not(Statement):
self.child = child
def evaluate(self, ctx):
capa.perf.counters["evaluate.feature"] += 1
capa.perf.counters["evaluate.feature.not"] += 1
results = [self.child.evaluate(ctx)]
success = not results[0]
return Result(success, self, results)
@@ -165,6 +175,9 @@ class Some(Statement):
self.children = children
def evaluate(self, ctx):
capa.perf.counters["evaluate.feature"] += 1
capa.perf.counters["evaluate.feature.some"] += 1
results = [child.evaluate(ctx) for child in self.children]
# note that here we cast the child result as a bool
# because we've overridden `__bool__` above.
@@ -184,6 +197,9 @@ class Range(Statement):
self.max = max if max is not None else (1 << 64 - 1)
def evaluate(self, ctx):
capa.perf.counters["evaluate.feature"] += 1
capa.perf.counters["evaluate.feature.range"] += 1
count = len(ctx.get(self.child, []))
if self.min == 0 and count == 0:
return Result(True, self, [])

View File

@@ -12,6 +12,7 @@ import logging
import collections
from typing import Set, Dict, Union
import capa.perf
import capa.engine
import capa.features
import capa.features.extractors.elf
@@ -97,6 +98,8 @@ class Feature:
return str(self)
def evaluate(self, ctx: Dict["Feature", Set[int]]) -> "capa.engine.Result":
capa.perf.counters["evaluate.feature"] += 1
capa.perf.counters["evaluate.feature." + self.name] += 1
return capa.engine.Result(self in ctx, self, [], locations=ctx.get(self, []))
def freeze_serialize(self):
@@ -141,6 +144,9 @@ class Substring(String):
self.value = value
def evaluate(self, ctx):
capa.perf.counters["evaluate.feature"] += 1
capa.perf.counters["evaluate.feature.substring"] += 1
# mapping from string value to list of locations.
# will unique the locations later on.
matches = collections.defaultdict(list)
@@ -226,6 +232,9 @@ class Regex(String):
)
def evaluate(self, ctx):
capa.perf.counters["evaluate.feature"] += 1
capa.perf.counters["evaluate.feature.regex"] += 1
# mapping from string value to list of locations.
# will unique the locations later on.
matches = collections.defaultdict(list)
@@ -309,6 +318,9 @@ class Bytes(Feature):
self.value = value
def evaluate(self, ctx):
capa.perf.counters["evaluate.feature"] += 1
capa.perf.counters["evaluate.feature.bytes"] += 1
for feature, locations in ctx.items():
if not isinstance(feature, (Bytes,)):
continue

View File

@@ -28,6 +28,7 @@ import colorama
from pefile import PEFormatError
from elftools.common.exceptions import ELFError
import capa.perf
import capa.rules
import capa.engine
import capa.version
@@ -1024,6 +1025,9 @@ def main(argv=None):
meta["analysis"].update(counts)
meta["analysis"]["layout"] = compute_layout(rules, extractor, capabilities)
for (counter, count) in capa.perf.counters.most_common():
logger.debug("perf: counter: %s: %d", counter, count)
if has_file_limitation(rules, capabilities):
# bail if capa encountered file limitation e.g. a packed binary
# do show the output in verbose mode, though.

3
capa/perf.py Normal file
View File

@@ -0,0 +1,3 @@
import collections
counters = collections.Counter()

View File

@@ -27,6 +27,7 @@ from typing import Any, Dict, List, Union, Iterator
import yaml
import ruamel.yaml
import capa.perf
import capa.engine as ceng
import capa.features
import capa.features.file
@@ -620,6 +621,8 @@ class Rule:
yield new_rule
def evaluate(self, features: FeatureSet):
capa.perf.counters["evaluate.feature"] += 1
capa.perf.counters["evaluate.feature.rule"] += 1
return self.statement.evaluate(features)
@classmethod