| #!/usr/bin/env python |
| # |
| # Copyright (C) 2016 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| """Analyze dm_verity trace""" |
| import collections |
| import math |
| import os |
| import re |
| import string |
| import sys |
| |
| RE_VERITY = r'.+\s+([0-9]+\.[0-9]+):\s+block_verity_msg:\s+(\S+)\s+([0-9]+)\,([0-9]+)\s+([0-9]+)\s+([0-9]+)' |
| |
| def get_average_and_std_dev(l): |
| sum_io = 0.0 |
| sum_verity = 0.0 |
| sum_total = 0.0 |
| N = len(l) |
| sum_blocks = 0.0 |
| for e in l: |
| sum_io += e.io_latency |
| sum_verity += e.verity_latency |
| sum_total += e.total_latency |
| sum_blocks += e.size |
| average_io = sum_io / N |
| average_verity = sum_verity / N |
| average_total = sum_total / N |
| var_io = 0.0 |
| var_verity = 0.0 |
| var_total = 0.0 |
| for e in l: |
| var_io += (e.io_latency - average_io)**2 |
| var_verity += (e.verity_latency - average_verity)**2 |
| var_total += (e.total_latency - average_total)**2 |
| sigma_io = math.sqrt(var_io / N) |
| sigma_verity = math.sqrt(var_verity / N) |
| sigma_total = math.sqrt(var_total / N) |
| return (average_io, sigma_io, sum_io), (average_verity, sigma_verity, sum_verity), \ |
| (average_total, sigma_total, sum_total), sum_blocks |
| |
| |
| class Event: |
| def __init__(self, start_time, block_num, size): |
| self.block_num = block_num |
| self.start_time = start_time |
| self.io_end_time = 0 |
| self.finish_time = 0 |
| self.size = size |
| self.total_latency = 0 |
| self.io_latency = 0 |
| self.verity_latency = 0 |
| |
| def set_io_end_time(self, io_end_time): |
| self.io_end_time = io_end_time |
| self.io_latency = io_end_time - self.start_time |
| |
| def set_finish_time(self, finish_time): |
| self.finish_time = finish_time |
| self.verity_latency = finish_time - self.io_end_time |
| self.total_latency = finish_time - self.start_time |
| |
| class VerityTrace: |
| def __init__(self): |
| self.reads = [] # all events in start time |
| self.block_size_vs_reads_histogram = {} # key: size, value: list of events |
| self.recents = {} # not finished, key: block_nr, value: event |
| self.re = re.compile(RE_VERITY) |
| |
| def handle_line(self, line): |
| match = self.re.match(line) |
| if not match: |
| return |
| time = int(float(match.group(1))*1000000) #us |
| step = match.group(2) |
| block_nr = int(match.group(5)) |
| size = int(match.group(6)) |
| recent_key = block_nr * 1000 + size |
| if step == "map": |
| event = Event(time, block_nr, size) |
| self.recents[recent_key] = event |
| self.reads.append(event) |
| per_size_list = self.block_size_vs_reads_histogram.get(size) |
| if not per_size_list: |
| per_size_list = [] |
| self.block_size_vs_reads_histogram[size] = per_size_list |
| per_size_list.append(event) |
| elif step == "end_io": |
| event = self.recents[recent_key] |
| event.set_io_end_time(time) |
| elif step == "finish_io": |
| event = self.recents[recent_key] |
| event.set_finish_time(time) |
| del self.recents[recent_key] |
| |
| def dump_list(self, msg, l): |
| io, verity, total, blocks = get_average_and_std_dev(l) |
| print msg, "counts:", len(l), "io latency:", io[0], io[1], io[2], "verity latency:", \ |
| verity[0], verity[1], verity[2], "total:", total[0], total[1], total[2] |
| return io, verity, total, blocks |
| |
| def dump(self): |
| print "Numbers: average (us), stddev (us), total (us)" |
| io, verity, total, blocks = self.dump_list ("total,", self.reads) |
| io_latency_per_1024KB = io[2] / blocks * (1024 / 4) |
| verity_latency_per_1024KB = verity[2] / blocks * (1024 / 4) |
| total_latency_per_1024KB = io_latency_per_1024KB + verity_latency_per_1024KB |
| print "Average latency for 1024KB (us), IO:", io_latency_per_1024KB, \ |
| "Verity:", verity_latency_per_1024KB, "Total:", total_latency_per_1024KB |
| sizes = sorted(self.block_size_vs_reads_histogram.keys()) |
| print "Latency per read size" |
| for s in sizes: |
| self.dump_list ("size " + str(s), self.block_size_vs_reads_histogram[s]) |
| |
| def main(argv): |
| if (len(argv) < 2): |
| print "check_io_trace.py filename" |
| return |
| filename = argv[1] |
| trace = VerityTrace() |
| with open(filename) as f: |
| for l in f: |
| trace.handle_line(l) |
| trace.dump() |
| |
| if __name__ == '__main__': |
| main(sys.argv) |