mirror of
https://github.com/littlefs-project/littlefs.git
synced 2025-10-18 00:33:09 +08:00
Added perfbd.py and block device performance sampling in bench-runner
Based loosely on Linux's perf tool, perfbd.py uses trace output with backtraces to aggregate and show the block device usage of all functions in a program, propagating block devices operation cost up the backtrace for each operation. This combined with --trace-period and --trace-freq for sampling/filtering trace events allow the bench-runner to very efficiently record the general cost of block device operations with very little overhead. Adopted this as the default side-effect of make bench, replacing cycle-based performance measurements which are less important for littlefs.
This commit is contained in:
@@ -15,7 +15,6 @@
|
||||
import collections as co
|
||||
import csv
|
||||
import difflib
|
||||
import glob
|
||||
import itertools as it
|
||||
import math as m
|
||||
import os
|
||||
@@ -24,7 +23,6 @@ import shlex
|
||||
import subprocess as sp
|
||||
|
||||
|
||||
OBJ_PATHS = ['*.o']
|
||||
NM_TOOL = ['nm']
|
||||
NM_TYPES = 'dDbB'
|
||||
OBJDUMP_TOOL = ['objdump']
|
||||
@@ -126,16 +124,16 @@ class DataResult(co.namedtuple('DataResult', [
|
||||
self.size + other.size)
|
||||
|
||||
|
||||
def openio(path, mode='r'):
|
||||
def openio(path, mode='r', buffering=-1):
|
||||
if path == '-':
|
||||
if mode == 'r':
|
||||
return os.fdopen(os.dup(sys.stdin.fileno()), 'r')
|
||||
return os.fdopen(os.dup(sys.stdin.fileno()), mode, buffering)
|
||||
else:
|
||||
return os.fdopen(os.dup(sys.stdout.fileno()), 'w')
|
||||
return os.fdopen(os.dup(sys.stdout.fileno()), mode, buffering)
|
||||
else:
|
||||
return open(path, mode)
|
||||
return open(path, mode, buffering)
|
||||
|
||||
def collect(paths, *,
|
||||
def collect(obj_paths, *,
|
||||
nm_tool=NM_TOOL,
|
||||
nm_types=NM_TYPES,
|
||||
objdump_tool=OBJDUMP_TOOL,
|
||||
@@ -147,17 +145,17 @@ def collect(paths, *,
|
||||
' (?P<type>[%s])' % re.escape(nm_types) +
|
||||
' (?P<func>.+?)$')
|
||||
line_pattern = re.compile(
|
||||
'^\s+(?P<no>[0-9]+)\s+'
|
||||
'(?:(?P<dir>[0-9]+)\s+)?'
|
||||
'.*\s+'
|
||||
'(?P<path>[^\s]+)$')
|
||||
'^\s+(?P<no>[0-9]+)'
|
||||
'(?:\s+(?P<dir>[0-9]+))?'
|
||||
'\s+.*'
|
||||
'\s+(?P<path>[^\s]+)$')
|
||||
info_pattern = re.compile(
|
||||
'^(?:.*(?P<tag>DW_TAG_[a-z_]+).*'
|
||||
'|^.*DW_AT_name.*:\s*(?P<name>[^:\s]+)\s*'
|
||||
'|^.*DW_AT_decl_file.*:\s*(?P<file>[0-9]+)\s*)$')
|
||||
'|.*DW_AT_name.*:\s*(?P<name>[^:\s]+)\s*'
|
||||
'|.*DW_AT_decl_file.*:\s*(?P<file>[0-9]+)\s*)$')
|
||||
|
||||
results = []
|
||||
for path in paths:
|
||||
for path in obj_paths:
|
||||
# guess the source, if we have debug-info we'll replace this later
|
||||
file = re.sub('(\.o)?$', '.c', path, 1)
|
||||
|
||||
@@ -520,20 +518,7 @@ def main(obj_paths, *,
|
||||
**args):
|
||||
# find sizes
|
||||
if not args.get('use', None):
|
||||
# find .o files
|
||||
paths = []
|
||||
for path in obj_paths:
|
||||
if os.path.isdir(path):
|
||||
path = path + '/*.o'
|
||||
|
||||
for path in glob.glob(path):
|
||||
paths.append(path)
|
||||
|
||||
if not paths:
|
||||
print("error: no .o files found in %r?" % obj_paths)
|
||||
sys.exit(-1)
|
||||
|
||||
results = collect(paths, **args)
|
||||
results = collect(obj_paths, **args)
|
||||
else:
|
||||
results = []
|
||||
with openio(args['use']) as f:
|
||||
@@ -613,9 +598,7 @@ if __name__ == "__main__":
|
||||
parser.add_argument(
|
||||
'obj_paths',
|
||||
nargs='*',
|
||||
default=OBJ_PATHS,
|
||||
help="Description of where to find *.o files. May be a directory "
|
||||
"or a list of paths. Defaults to %r." % OBJ_PATHS)
|
||||
help="Input *.o files.")
|
||||
parser.add_argument(
|
||||
'-v', '--verbose',
|
||||
action='store_true',
|
||||
|
Reference in New Issue
Block a user