def create_snapshots(): traceback_limit = 2 raw_traces = [ (10, (('a.py', 2), ('b.py', 4))), (10, (('a.py', 2), ('b.py', 4))), (10, (('a.py', 2), ('b.py', 4))), (2, (('a.py', 5), ('b.py', 4))), (66, (('b.py', 1),)), (7, (('<unknown>', 0),)), ] snapshot = tracemalloc.Snapshot(raw_traces, traceback_limit) raw_traces2 = [ (10, (('a.py', 2), ('b.py', 4))), (10, (('a.py', 2), ('b.py', 4))), (10, (('a.py', 2), ('b.py', 4))), (2, (('a.py', 5), ('b.py', 4))), (5000, (('a.py', 5), ('b.py', 4))), (400, (('c.py', 578),)), ] snapshot2 = tracemalloc.Snapshot(raw_traces2, traceback_limit) return (snapshot, snapshot2)
def create_snapshots(): traceback_limit = 2 # _tracemalloc._get_traces() returns a list of (domain, size, # traceback_frames) tuples. traceback_frames is a tuple of (filename, # line_number) tuples. raw_traces = [ (0, 10, (('a.py', 2), ('b.py', 4))), (0, 10, (('a.py', 2), ('b.py', 4))), (0, 10, (('a.py', 2), ('b.py', 4))), (1, 2, (('a.py', 5), ('b.py', 4))), (2, 66, (('b.py', 1),)), (3, 7, (('<unknown>', 0),)), ] snapshot = tracemalloc.Snapshot(raw_traces, traceback_limit) raw_traces2 = [ (0, 10, (('a.py', 2), ('b.py', 4))), (0, 10, (('a.py', 2), ('b.py', 4))), (0, 10, (('a.py', 2), ('b.py', 4))), (2, 2, (('a.py', 5), ('b.py', 4))), (2, 5000, (('a.py', 5), ('b.py', 4))), (4, 400, (('c.py', 578),)), ] snapshot2 = tracemalloc.Snapshot(raw_traces2, traceback_limit) return (snapshot, snapshot2)
def create_snapshots(): traceback_limit = 2 raw_traces = [(0, 10, (('a.py', 2), ('b.py', 4))), (0, 10, (('a.py', 2), ('b.py', 4))), (0, 10, (('a.py', 2), ('b.py', 4))), (1, 2, (('a.py', 5), ('b.py', 4))), (2, 66, (('b.py', 1), )), (3, 7, (('<unknown>', 0), ))] snapshot = tracemalloc.Snapshot(raw_traces, traceback_limit) raw_traces2 = [(0, 10, (('a.py', 2), ('b.py', 4))), (0, 10, (('a.py', 2), ('b.py', 4))), (0, 10, (('a.py', 2), ('b.py', 4))), (2, 2, (('a.py', 5), ('b.py', 4))), (2, 5000, (('a.py', 5), ('b.py', 4))), (4, 400, (('c.py', 578), ))] snapshot2 = tracemalloc.Snapshot(raw_traces2, traceback_limit) return snapshot, snapshot2
def test_ppprof_memory_exporter(): if sys.version_info.major <= 3 and sys.version_info.minor < 6: # Python before 3.6 does not support domain traces = [ (45, (("<unknown>", 0), )), (64, (("<stdin>", 1), )), (8224, (("<unknown>", 0), )), (144, (("<unknown>", 0), )), (32, (("<unknown>", 0), )), (32, (("<stdin>", 1), )), (24, (("<unknown>", 0), )), ] elif sys.version_info.major <= 3 and sys.version_info.minor < 9: # Python before 3.9 does not support number of frames traces = [ (0, 45, (("<unknown>", 0), )), (0, 64, (("<stdin>", 1), )), (0, 8224, (("<unknown>", 0), )), (0, 144, (("<unknown>", 0), )), (0, 32, (("<unknown>", 0), )), (0, 32, (("<stdin>", 1), )), (0, 24, (("<unknown>", 0), )), ] else: traces = [ (0, 45, (("<unknown>", 0), ), 1), (0, 64, (("<stdin>", 1), ), 1), (0, 8224, (("<unknown>", 0), ), 1), (0, 144, (("<unknown>", 0), ), 1), (0, 32, (("<unknown>", 0), ), 1), (0, 32, (("<stdin>", 1), ), 1), (0, 24, (("<unknown>", 0), ), 1), ] events = { memory.MemorySampleEvent: [ memory.MemorySampleEvent(timestamp=1, snapshot=tracemalloc.Snapshot(traces, 1), sampling_pct=10), memory.MemorySampleEvent(timestamp=2, snapshot=tracemalloc.Snapshot(traces, 1), sampling_pct=10), ], } exp = pprof.PprofExporter() exp._get_program_name = mock.Mock() exp._get_program_name.return_value = "bonjour" if stack.FEATURES["stack-exceptions"]: assert """sample_type { type: 5 unit: 6 } sample_type { type: 7 unit: 8 } sample_type { type: 9 unit: 8 } sample_type { type: 10 unit: 6 } sample_type { type: 11 unit: 6 } sample_type { type: 12 unit: 8 } sample_type { type: 13 unit: 6 } sample_type { type: 14 unit: 8 } sample_type { type: 15 unit: 6 } sample_type { type: 16 unit: 6 } sample_type { type: 17 unit: 18 } sample { location_id: 1 value: 0 value: 0 value: 0 value: 0 value: 0 value: 0 value: 0 value: 0 value: 0 value: 100 value: 169380 } sample { location_id: 2 value: 0 value: 0 value: 0 value: 0 value: 0 value: 0 value: 0 value: 0 value: 0 value: 40 value: 1920 } mapping { id: 1 filename: 20 } location { id: 1 line { function_id: 1 } } location { id: 2 line { function_id: 2 line: 1 } } function { id: 1 name: 1 filename: 2 } function { id: 2 name: 3 filename: 4 } string_table: "" string_table: "<unknown>:0" string_table: "<unknown>" string_table: "<stdin>:1" string_table: "<stdin>" string_table: "cpu-samples" string_table: "count" string_table: "cpu-time" string_table: "nanoseconds" string_table: "wall-time" string_table: "uncaught-exceptions" string_table: "lock-acquire" string_table: "lock-acquire-wait" string_table: "lock-release" string_table: "lock-release-hold" string_table: "exception-samples" string_table: "alloc-samples" string_table: "alloc-space" string_table: "bytes" string_table: "time" string_table: "bonjour" time_nanos: 1 duration_nanos: 1 period_type { type: 19 unit: 8 } """ == str(exp.export(events, 1, 2))
def export(self, events, start_time_ns, end_time_ns): """Convert events to pprof format. :param events: The event dictionary from a `ddtrace.profiling.recorder.Recorder`. :param start_time_ns: The start time of recording. :param end_time_ns: The end time of recording. :return: A protobuf Profile object. """ program_name = self._get_program_name() sum_period = 0 nb_event = 0 converter = _PprofConverter() # Handle StackSampleEvent stack_events = [] for event in events.get(stack.StackSampleEvent, []): stack_events.append(event) sum_period += event.sampling_period nb_event += 1 for (thread_id, thread_name, frames, nframes), stack_events in self._group_stack_events(stack_events): converter.convert_stack_event(thread_id, thread_name, frames, nframes, list(stack_events)) # Handle Lock events for event_class, convert_fn in ( (threading.LockAcquireEvent, converter.convert_lock_acquire_event), (threading.LockReleaseEvent, converter.convert_lock_release_event), ): lock_events = events.get(event_class, []) sampling_sum_pct = sum(event.sampling_pct for event in lock_events) if lock_events: sampling_ratio_avg = sampling_sum_pct / (len(lock_events) * 100.0) for (lock_name, thread_id, thread_name, frames, nframes), l_events in self._group_lock_events( lock_events ): convert_fn(lock_name, thread_id, thread_name, frames, nframes, list(l_events), sampling_ratio_avg) # Handle UncaughtExceptionEvent for ((thread_id, thread_name, frames, nframes, exc_type_name), ue_events,) in self._group_exception_events( events.get(exceptions.UncaughtExceptionEvent, []) ): converter.convert_uncaught_exception_event( thread_id, thread_name, frames, nframes, exc_type_name, list(ue_events) ) sample_types = ( ("cpu-samples", "count"), ("cpu-time", "nanoseconds"), ("wall-time", "nanoseconds"), ("uncaught-exceptions", "count"), ("lock-acquire", "count"), ("lock-acquire-wait", "nanoseconds"), ("lock-release", "count"), ("lock-release-hold", "nanoseconds"), ) # Handle StackExceptionSampleEvent if stack.FEATURES["stack-exceptions"]: sample_types += (("exception-samples", "count"),) for (thread_id, thread_name, frames, nframes, exc_type_name), se_events in self._group_exception_events( events.get(stack.StackExceptionSampleEvent, []) ): converter.convert_stack_exception_event( thread_id, thread_name, frames, nframes, exc_type_name, list(se_events) ) if tracemalloc: sample_types += ( ("alloc-samples", "count"), ("alloc-space", "bytes"), ) # Handle MemorySampleEvent # Merge all the memory snapshots traces = [] traceback_limit = None sampling_pct_sum = 0 nb_events = 0 for event in events.get(memory.MemorySampleEvent, []): sampling_pct_sum += event.sampling_pct nb_events += 1 traces.extend(event.snapshot.traces._traces) # Assume they are all the same traceback_limit = event.snapshot.traceback_limit # Ignore period for memory events are it's not a time-based sampling if nb_events: sampling_ratio_avg = sampling_pct_sum / (nb_events * 100.0) # convert percentage to ratio for stats in tracemalloc.Snapshot(traces, traceback_limit).statistics("traceback"): converter.convert_memory_event(stats, sampling_ratio_avg) # Compute some metadata if nb_event: period = int(sum_period / nb_event) else: period = None duration_ns = end_time_ns - start_time_ns return converter._build_profile( start_time_ns=start_time_ns, duration_ns=duration_ns, period=period, sample_types=sample_types, program_name=program_name, )