Beispiel #1
0
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,
        )