def testValidProfile(self): output_dir = test.get_temp_dir() run_metadata = config_pb2.RunMetadata() node1 = step_stats_pb2.NodeExecStats(node_name='Add/123', op_start_rel_micros=3, op_end_rel_micros=5, all_end_rel_micros=4) run_metadata = config_pb2.RunMetadata() device1 = run_metadata.step_stats.dev_stats.add() device1.device = 'deviceA' device1.node_stats.extend([node1]) graph = test.mock.MagicMock() op1 = test.mock.MagicMock() op1.name = 'Add/123' op1.traceback = [('a/b/file1', 10, 'apply_op', 'abc'), ('a/c/file2', 12, 'my_op', 'def')] op1.type = 'add' graph.get_operations.return_value = [op1] expected_proto = """sample_type { type: 5 unit: 5 } sample_type { type: 6 unit: 7 } sample_type { type: 8 unit: 7 } sample { value: 1 value: 4 value: 2 label { key: 1 str: 2 } label { key: 3 str: 4 } } string_table: "" string_table: "node_name" string_table: "Add/123" string_table: "op_type" string_table: "add" string_table: "count" string_table: "all_time" string_table: "nanoseconds" string_table: "op_time" string_table: "Device 1 of 1: deviceA" comment: 9 """ # Test with protos profiles = pprof_profiler.get_profiles(graph, run_metadata) self.assertEquals(1, len(profiles)) self.assertTrue('deviceA' in profiles) self.assertEquals(expected_proto, str(profiles['deviceA'])) # Test with files profile_files = pprof_profiler.profile(graph, run_metadata, output_dir) self.assertEquals(1, len(profile_files)) with gzip.open(profile_files[0]) as profile_file: profile_contents = profile_file.read() profile = profile_pb2.Profile() profile.ParseFromString(profile_contents) self.assertEquals(expected_proto, str(profile))
def _get_pprof_proto(self, profile_datum_generator): """Returns profile data in pprof proto format. Args: profile_datum_generator: Generator outputting `ProfileDatum` objects. Returns: A proto in pprof format. """ pprof_profile = profile_pb2.Profile() samples = Samples(self._string_table) for datum in profile_datum_generator: if not datum.traceback: continue stack_frame = datum.traceback[-1] after_apply_op = False location_ids = [] # We add locations from stack trace in bottom-up order. for stack_frame_index in reversed(range(len(datum.traceback) - 1)): prev_stack_frame = stack_frame stack_frame = datum.traceback[stack_frame_index] # Call at current frame calls function at previous frame. prev_file_path = prev_stack_frame[0] prev_function = prev_stack_frame[2] prev_function_start_line = -1 curr_file_path = stack_frame[0] curr_line_number = stack_frame[1] # Skip all calls up to apply_op since they are the same for all ops. if not after_apply_op: if prev_function == 'apply_op': after_apply_op = True continue location_index = self._locations.index_of( curr_file_path, curr_line_number, prev_function, prev_file_path, prev_function_start_line) location_ids.append(location_index) samples.add(datum, location_ids) sample_type_description = 'count' sample_type = pprof_profile.sample_type.add() sample_type.type = self._string_table.index_of(sample_type_description) sample_type.unit = self._string_table.index_of('count') sample_type_description = 'all_time' sample_type = pprof_profile.sample_type.add() sample_type.type = self._string_table.index_of(sample_type_description) sample_type.unit = self._string_table.index_of('nanoseconds') sample_type_description = 'op_time' sample_type = pprof_profile.sample_type.add() sample_type.type = self._string_table.index_of(sample_type_description) sample_type.unit = self._string_table.index_of('nanoseconds') pprof_profile.string_table.extend(self._string_table.string_table()) pprof_profile.sample.extend(samples.get_sample_protos()) pprof_profile.function.extend(self._functions.function_protos()) pprof_profile.location.extend(self._locations.location_protos()) return pprof_profile