|
|
|
|
|
|
|
|
|
""" |
|
Functionality of swapping optimizer tensors to/from (NVMe) storage devices. |
|
""" |
|
|
|
import os |
|
import argparse |
|
|
|
READ_SPEED = 'read_speed' |
|
WRITE_SPEED = 'write_speed' |
|
|
|
PERF_METRICS = [READ_SPEED, WRITE_SPEED] |
|
|
|
METRIC_SEARCH = {READ_SPEED: 'E2E Read Speed', WRITE_SPEED: 'E2E Write Speed'} |
|
|
|
|
|
def parse_arguments(): |
|
parser = argparse.ArgumentParser() |
|
|
|
parser.add_argument('--log_dir', type=str, required=True, help='Folder of statistics logs') |
|
|
|
parser.add_argument('--metric', |
|
type=str, |
|
required=True, |
|
help='Performance metric to report: [read_speed|write_speed]') |
|
|
|
args = parser.parse_args() |
|
print(f'args = {args}') |
|
|
|
return args |
|
|
|
|
|
def extract_value(key, file): |
|
INVALID_PREFIXES = ["ds"] |
|
for p in INVALID_PREFIXES: |
|
if key.startswith(p): |
|
return key |
|
try: |
|
if key[0] in ['t', 'd', 'p']: |
|
return int(key[1:]) |
|
if key.startswith("bs"): |
|
if key.endswith('K'): |
|
v = key[2:].split('K') |
|
return int(v[0]) * 1024 |
|
elif key.endswith('M'): |
|
v = key[2:].split('M') |
|
return int(v[0]) * 1024 * 1024 |
|
else: |
|
return int(key[2:]) |
|
except: |
|
print(f"{file}: extract_value fails on {key}") |
|
return None |
|
|
|
return key |
|
|
|
|
|
def get_file_key(file): |
|
f, _ = os.path.splitext(os.path.basename(file)) |
|
fields = f.split('_') |
|
values = [extract_value(k, file) for k in fields] |
|
return tuple(values) |
|
|
|
|
|
def get_thread_count(file): |
|
f, _ = os.path.splitext(os.path.basename(file)) |
|
fields = f.split('_') |
|
for key in fields: |
|
if key[0] == 't': |
|
return int(key[1:]) |
|
return 1 |
|
|
|
|
|
""" |
|
Extract performance metric from log file. |
|
Sample file lines are: |
|
Task Read Latency = 0.031647682189941406 sec |
|
Task Read Speed = 12.342926020792527 GB/sec |
|
E2E Read Latency = 0.031697988510131836 sec |
|
E2E Read Speed = 12.323337169333062 GB/sec |
|
|
|
For the above sample, -metric = "read_speed" corresponds to "E2E Read Speed", and 12.32 will be returned |
|
""" |
|
|
|
|
|
def get_metric(file, metric): |
|
thread_count = get_thread_count(file) |
|
with open(file) as f: |
|
for line in f.readlines(): |
|
if line.startswith(METRIC_SEARCH[metric]): |
|
if metric in [READ_SPEED, WRITE_SPEED]: |
|
fields = line.split() |
|
return float(fields[-2]) |
|
else: |
|
fields = line.split('=') |
|
return float(fields[-1]) |
|
|
|
return None |
|
|
|
|
|
def validate_args(args): |
|
if not args.metric in PERF_METRICS: |
|
print(f'{args.metric} is not a valid performance metrics') |
|
return False |
|
|
|
if not os.path.isdir(args.log_dir): |
|
print(f'{args.log_dir} folder is not existent') |
|
return False |
|
|
|
return True |
|
|
|
|
|
def get_results(log_files, metric): |
|
results = {} |
|
for f in log_files: |
|
file_key = get_file_key(f) |
|
value = get_metric(f, metric) |
|
results[file_key] = value |
|
|
|
return results |
|
|
|
|
|
def get_sorted_results(log_dir, metric): |
|
log_files = [f for f in os.listdir(log_dir) if os.path.isfile(os.path.join(log_dir, f))] |
|
|
|
log_files_path = [os.path.join(log_dir, f) for f in log_files] |
|
results = get_results(log_files_path, metric) |
|
result_keys = list(results.keys()) |
|
sorted_keys = sorted(result_keys) |
|
return sorted_keys, results |
|
|
|
|
|
def main(): |
|
print("Parsing aio statistics") |
|
args = parse_arguments() |
|
|
|
if not validate_args(args): |
|
quit() |
|
|
|
sorted_keys, results = get_sorted_results(args.log_dir, args.metric) |
|
for k in sorted_keys: |
|
print(f'{k} = {results[k]}') |
|
|
|
|
|
if __name__ == "__main__": |
|
main() |
|
|