blob: d090fcc2d1c241aabd9e858fdde6d791cebb6967 [file] [log] [blame]
#! /usr/bin/env python3
#
# Copyright 2023, 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.
import argparse
from collections import defaultdict
import os
def process_dirty_entries(entries, with_sort):
mark_counts = defaultdict(int)
dirty_image_objects = []
union = set()
for v in entries.values():
union = union.union(v)
for obj in union:
str_marker = ''
marker = 0
# Sort marker is uint32_t, where Nth bit is set if Nth process has this object dirty.
for idx, v in enumerate(entries.values()):
if obj in v:
str_marker += chr(ord('A') + idx)
marker = (marker << 1) | 1
else:
str_marker += '_'
marker = marker << 1
if with_sort:
dirty_image_objects.append(obj + ' ' + str(marker) + '\n')
else:
dirty_image_objects.append(obj + '\n')
mark_counts[str_marker] += 1
return (dirty_image_objects, mark_counts)
def main():
parser = argparse.ArgumentParser(
description=(
'Create dirty-image-objects file from specified imgdiag output files.'
),
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument(
'imgdiag_files',
nargs='+',
help='imgdiag files to use.',
)
parser.add_argument(
'--sort-objects',
action=argparse.BooleanOptionalAction,
default=True,
help='Use object sorting.',
)
parser.add_argument(
'--output-filename',
default='dirty-image-objects.txt',
help='Output file for dirty image objects.',
)
parser.add_argument(
'--print-stats',
action=argparse.BooleanOptionalAction,
default=False,
help='Print dirty object stats.',
)
args = parser.parse_args()
entries = dict()
for path in args.imgdiag_files:
with open(path) as f:
lines = f.readlines()
prefix = 'dirty_obj: '
lines = [l.strip().removeprefix(prefix) for l in lines if prefix in l]
entries[path] = set(lines)
if args.sort_objects and len(entries) > 32:
print(
'WARNING: too many processes for sorting, using top 32 by number of'
' dirty objects.'
)
entries_list = sorted(
list(entries.items()), reverse=True, key=lambda x: len(x[1])
)
entries_list = entries_list[0:32]
entries = {k: v for (k, v) in entries_list}
print('Using processes:')
for k, v in sorted(entries.items(), key=lambda x: len(x[1])):
print(f'{k}: {len(v)}')
print()
dirty_image_objects, mark_counts = process_dirty_entries(
entries=entries, with_sort=args.sort_objects
)
with open(args.output_filename, 'w') as f:
f.writelines(dirty_image_objects)
if args.print_stats:
mark_counts = sorted(
list(mark_counts.items()), key=lambda x: x[1], reverse=True
)
for i, path in enumerate(entries.keys()):
print(path, chr(ord('A') + i))
total_count = 0
for marker, count in mark_counts:
print(marker, count)
total_count += count
print('total: ', total_count)
if __name__ == '__main__':
main()