diff options
author | Andreas Gampe <agampe@google.com> | 2018-07-09 13:33:59 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2018-07-09 17:35:59 -0700 |
commit | c18c2d0b9dad09c20018a3002f02d343576ac134 (patch) | |
tree | 49f4cc904344ee329d867931a49b26c68607cbe0 /perfprofd | |
parent | f854eb868a7682135f36f3a0bf8ed462ef464501 (diff) | |
download | extras-c18c2d0b9dad09c20018a3002f02d343576ac134.tar.gz |
Perfprofd: Update python script to produce a config proto
Bug: 110555909
Test: mmma system/extras/perfprofd/scripts
Test: manual
Change-Id: I3cbeb217852fae2eabf4176dafc30e73f6623d30
Diffstat (limited to 'perfprofd')
-rw-r--r-- | perfprofd/scripts/Android.bp | 18 | ||||
-rw-r--r-- | perfprofd/scripts/perf_config_proto.py | 213 |
2 files changed, 172 insertions, 59 deletions
diff --git a/perfprofd/scripts/Android.bp b/perfprofd/scripts/Android.bp index 1cd755cf..93aed1c8 100644 --- a/perfprofd/scripts/Android.bp +++ b/perfprofd/scripts/Android.bp @@ -69,3 +69,21 @@ python_binary_host { "simpleperf-inferno", ], } + +python_binary_host { + name: "perf_config_proto", + defaults: ["perfprofd_python_default"], + main: "perf_config_proto.py", + srcs: [ + "perf_config_proto.py", + ":perfprofd_config_proto", + ], + libs: [ + // Soong won't add "libprotobuf-python" to the dependencies if + // filegroup contains .proto files. So add it here explicitly. + "libprotobuf-python", + ], + proto: { + canonical_path_from_root: false, + }, +} diff --git a/perfprofd/scripts/perf_config_proto.py b/perfprofd/scripts/perf_config_proto.py index c94910f8..52614ceb 100644 --- a/perfprofd/scripts/perf_config_proto.py +++ b/perfprofd/scripts/perf_config_proto.py @@ -19,77 +19,172 @@ # Generate with: # aprotoc -I=system/extras/perfprofd --python_out=system/extras/perfprofd/scripts \ # system/extras/perfprofd/binder_interface/perfprofd_config.proto -import perfprofd_config_pb2 +# +# Note: it is necessary to do a '*' import to not have to jump through hoops +# with reflective instantiation. +from perfprofd_config_pb2 import * + +# Necessary for introspection. +from google.protobuf.descriptor import FieldDescriptor import sys -config_options = [ - ('collection_interval_in_s', 'u'), - ('use_fixed_seed', 'u'), - ('main_loop_iterations', 'u'), - ('destination_directory', 's'), - ('config_directory', 's'), - ('perf_path', 's'), - ('sampling_period', 'u'), - ('sample_duration_in_s', 'u'), - ('only_debug_build', 'b'), - ('hardwire_cpus', 'b'), - ('hardwire_cpus_max_duration_in_s', 'u'), - ('max_unprocessed_profiles', 'u'), - ('stack_profile', 'b'), - ('collect_cpu_utilization', 'b'), - ('collect_charging_state', 'b'), - ('collect_booting', 'b'), - ('collect_camera_active', 'b'), - ('process', 'i'), - ('use_elf_symbolizer', 'b'), - ('send_to_dropbox', 'b'), -] +PROTO_FIELD_TYPE_NAMES = { + FieldDescriptor.TYPE_DOUBLE: "double", + FieldDescriptor.TYPE_FLOAT: "float", + FieldDescriptor.TYPE_INT64: "int64", + FieldDescriptor.TYPE_UINT64: "uint64", + FieldDescriptor.TYPE_INT32: "int32", + FieldDescriptor.TYPE_FIXED64: "fixed64", + FieldDescriptor.TYPE_FIXED32: "fixed32", + FieldDescriptor.TYPE_BOOL: "bool", + FieldDescriptor.TYPE_STRING: "string", + FieldDescriptor.TYPE_GROUP: "group", + FieldDescriptor.TYPE_MESSAGE: "message", + FieldDescriptor.TYPE_BYTES: "bytes", + FieldDescriptor.TYPE_UINT32: "uint32", + FieldDescriptor.TYPE_ENUM: "enum", + FieldDescriptor.TYPE_SFIXED32: "sfixed32", + FieldDescriptor.TYPE_SFIXED64: "sfixed64", + FieldDescriptor.TYPE_SINT32: "sint32", + FieldDescriptor.TYPE_SINT64: "sint64", +} +def get_type_string(proto_field_type): + if proto_field_type in PROTO_FIELD_TYPE_NAMES: + return PROTO_FIELD_TYPE_NAMES[proto_field_type] + return "unknown type" -def collect_and_write(filename): - config = perfprofd_config_pb2.ProfilingConfig() - - for (option, option_type) in config_options: - input = raw_input('%s(%s): ' % (option, option_type)) - if input == '': - # Skip this argument. - continue - elif input == '!': - # Special-case input, end argument collection. - break - # Now do some actual parsing work. - if option_type == 'u' or option_type == 'i': - option_val = int(input) - elif option_type == 'b': - if input == '1' or input == 't' or input == 'true': - option_val = True - elif input == '0' or input == 'f' or input == 'false': - option_val = False - else: - assert False, 'Unknown boolean %s' % input +def read_message(msg_descriptor, indent): + istr = ' ' * indent + print('%s%s' % (istr, msg_descriptor.name)) + # Create an instance + instance = globals()[msg_descriptor.name]() + + # Fill fields. + + primitive_fields = [None] + message_fields = [None] + for field in msg_descriptor.fields: + if field.type == FieldDescriptor.TYPE_MESSAGE: + message_fields.append(field) else: - assert False, 'Unknown type %s' % type - setattr(config, option, option_val) + primitive_fields.append(field) + + def table_loop(fields, field_fn): + while True: + # Print selection table + maxlen = len(str(len(fields) - 1)) + def pad_index(key): + while len(key) < maxlen: + key = ' ' + key + return key - f = open(filename, "wb") - f.write(config.SerializeToString()) - f.close() + for i in xrange(1, len(fields)): + print('%s%s: %s' % (istr, pad_index(str(i)), fields[i].name)) + print('%s%s: done' % (istr, pad_index('0'))) + print('%s%s: end' % (istr, pad_index('!'))) + + sel = raw_input('%s ? ' % (istr)) + if sel == '!': + # Special-case input, end argument collection. + return False + + try: + sel_int = int(sel) + if sel_int == 0: + return True + + if sel_int > 0 and sel_int < len(fields): + field = fields[sel_int] + if not field_fn(field): + return False + else: + print('Not a valid input (%d)!' % (sel_int)) + continue + except: + print('Not a valid input! (%s, %s)' % (sel, str(sys.exc_info()[0]))) + continue + +# # 1) Non-message-type fields. Assume they are not repeated. + if len(primitive_fields) > 1: + print('%s(Primitives)' % (istr)) + + def primitive_fn(field): + input = raw_input('%s -> %s (%s): ' % (istr, field.name, get_type_string(field.type))) + if input == '': + # Skip this field + return True + if input == '!': + # Special-case input, end argument collection. + return False + + # Simplification: assume ints or bools or strings, but not floats + if field.type == FieldDescriptor.TYPE_BOOL: + input = input.lower() + set_val = True if input == 'y' or input == 'true' or input == '1' else False + elif field.type == FieldDescriptor.TYPE_STRING: + set_val = input + else: + try: + set_val = int(input) + except: + print('Could not parse input as integer!') + return True + setattr(instance, field.name, set_val) + return True + + if not table_loop(primitive_fields, primitive_fn): + return (instance, False) + + # 2) Message-type fields. These may be repeated. + if len(message_fields) > 1: + print('%s(Nested messages)' % (istr)) + + def message_fn(field): + sub_msg, cont = read_message(field.message_type, indent + 4) + if sub_msg is not None: + if field.label == FieldDescriptor.LABEL_REPEATED: + # Repeated field, use extend. + getattr(instance, field.name).extend([sub_msg]) + else: + # Singular field, copy into. + getattr(instance, field.name).CopyFrom(sub_msg) + return cont + + if not table_loop(message_fields, message_fn): + return (instance, False) + + return (instance, True) + + +def collect_and_write(filename): + config, _ = read_message(ProfilingConfig.DESCRIPTOR, 0) + + if config is not None: + with open(filename, "wb") as f: + f.write(config.SerializeToString()) def read_and_print(filename): - config = perfprofd_config_pb2.ProfilingConfig() + config = ProfilingConfig() - f = open(filename, "rb") - config.ParseFromString(f.read()) - f.close() + with open(filename, "rb") as f: + config.ParseFromString(f.read()) print config -if sys.argv[1] == 'read': - read_and_print(sys.argv[2]) -elif sys.argv[1] == 'write': - collect_and_write(sys.argv[2]) -else: - print 'Usage: python perf_config_proto.py (read|write) filename' +def print_usage(): + print('Usage: python perf_config_proto.py (read|write) filename') + + +if __name__ == "__main__": + if len(sys.argv) < 3: + print_usage() + elif sys.argv[1] == 'read': + read_and_print(sys.argv[2]) + elif sys.argv[1] == 'write': + collect_and_write(sys.argv[2]) + else: + print_usage() |