126 lines
5.1 KiB
Python
Executable File
126 lines
5.1 KiB
Python
Executable File
#! /usr/bin/python
|
|
|
|
# Copyright (C) 2019 Apple Inc. All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
|
|
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
# THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
import re
|
|
import sys
|
|
|
|
icStatRecord = re.compile(r" +(\w+)\(([^,]+), ([^)]+)\)([^:]*): (\d+)")
|
|
getByIdPrefix = "OperationGetById"
|
|
putByIdPrefix = "OperationPutById"
|
|
|
|
|
|
class ICStats:
|
|
def __init__(self):
|
|
self.combinedRecords = {}
|
|
self.slowGetById = {}
|
|
self.slowPutById = {}
|
|
self.totalSlowGetById = 0
|
|
self.totalSlowPutById = 0
|
|
|
|
def parse(self, file):
|
|
for line in file:
|
|
match = re.match(icStatRecord, line)
|
|
if match:
|
|
operation = match.group(1)
|
|
base = match.group(2)
|
|
property = match.group(3)
|
|
location = match.group(4).strip()
|
|
count = int(match.group(5))
|
|
recordKey = (operation, base, property, location)
|
|
|
|
if recordKey not in self.combinedRecords:
|
|
self.combinedRecords[recordKey] = count
|
|
else:
|
|
self.combinedRecords[recordKey] += count
|
|
|
|
if operation.startswith(getByIdPrefix):
|
|
self.totalSlowGetById += count
|
|
|
|
slowGetByIdKey = (base, property)
|
|
if slowGetByIdKey not in self.slowGetById:
|
|
self.slowGetById[slowGetByIdKey] = count
|
|
else:
|
|
self.slowGetById[slowGetByIdKey] += count
|
|
|
|
elif operation.startswith(putByIdPrefix):
|
|
self.totalSlowPutById += count
|
|
|
|
slowPutByIdKey = (base, property)
|
|
if slowPutByIdKey not in self.slowPutById:
|
|
self.slowPutById[slowPutByIdKey] = count
|
|
else:
|
|
self.slowPutById[slowPutByIdKey] += count
|
|
|
|
def dumpStats(self):
|
|
print("Total Slow getById = {0:>13,d}".format(self.totalSlowGetById))
|
|
print("Total Slow putById = {0:>13,d}".format(self.totalSlowPutById))
|
|
|
|
print("Operation Base Property Location Count % tot")
|
|
print("----------------------------------- -------------------- ------------------------------------ ------------ --------- slow")
|
|
|
|
keys = sorted(self.combinedRecords.keys(), key=lambda t: self.combinedRecords[t], reverse=True)
|
|
for key in keys:
|
|
count = self.combinedRecords[key]
|
|
operation = key[0]
|
|
base = key[1]
|
|
property = key[2]
|
|
|
|
if operation.startswith(getByIdPrefix):
|
|
slowPercent = " {0:>4.1f}%".format(float(self.slowGetById[(base, property)] * 100) / float(self.totalSlowGetById))
|
|
elif operation.startswith(putByIdPrefix):
|
|
slowPercent = " {0:>4.1f}%".format(float(self.slowPutById[(base, property)] * 100) / float(self.totalSlowPutById))
|
|
else:
|
|
slowPercent = ""
|
|
|
|
if len(property) > 36:
|
|
property = property[0:32] + "..."
|
|
|
|
print("{0:35} {1:20} {2:36} {3:12} {4:>9d}{5}".format(operation[0:34], base, property, key[3], count, slowPercent))
|
|
|
|
|
|
def usage():
|
|
print("Usage: {0} [ic-stats-file]".format(sys.argv[0]))
|
|
print(" Where <ic-stats-file> is the results of using the useICStats option.")
|
|
exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) > 1:
|
|
if sys.argv[1] == "-h" or sys.argv[1].lower() == "--help" or sys.argv[1] == "-?":
|
|
usage()
|
|
try:
|
|
file = open(sys.argv[1], "r")
|
|
except IOError as e:
|
|
print("Couldn't open {0}, {1}".format(sys.argv[1], e.strerror))
|
|
usage()
|
|
except:
|
|
print("Unexpected error:", sys.exc_info()[0])
|
|
usage()
|
|
else:
|
|
file = sys.stdin
|
|
|
|
icStats = ICStats()
|
|
icStats.parse(file)
|
|
icStats.dumpStats()
|