예제 #1
0
def _test_memory_ignore(ignore):
    r = recorder.Recorder()
    # Start a stack collector so it allocates memory
    with stack.StackCollector(r) as sc:
        r = recorder.Recorder()
        c = memory.MemoryCollector(r, ignore_profiler=ignore, capture_pct=100)
        with c as mc:
            while not r.events[memory.MemorySampleEvent]:
                _ = _alloc()
                # Allow gevent to switch to the memory collector thread
                time.sleep(0)
    sc.join()
    mc.join()
    events = r.events[memory.MemorySampleEvent]
    files = {
        frame.filename
        for event in events for trace in event.snapshot.traces
        for frame in trace.traceback
    }
    return files
예제 #2
0
def test_before_flush_failure(caplog):
    def call_me():
        raise Exception("LOL")

    r = recorder.Recorder()
    s = scheduler.Scheduler(r, [exporter.NullExporter()], before_flush=call_me)
    r.push_events([event.Event()] * 10)
    s.flush()
    assert caplog.record_tuples == [
        (("ddtrace.profiling.scheduler", logging.ERROR, "Scheduler before_flush hook failed"))
    ]
예제 #3
0
def test_patch():
    r = recorder.Recorder()
    lock = threading.Lock
    collector = collector_threading.LockCollector(r)
    collector.start()
    assert lock == collector.original
    # wrapt makes this true
    assert lock == threading.Lock
    collector.stop()
    assert lock == threading.Lock
    assert collector.original == threading.Lock
예제 #4
0
def test_before_flush():
    x = {}

    def call_me():
        x["OK"] = True

    r = recorder.Recorder()
    s = scheduler.Scheduler(r, [exporter.NullExporter()], before_flush=call_me)
    r.push_events([event.Event()] * 10)
    s.flush()
    assert x["OK"]
def _test_restart(collector, **kwargs):
    r = recorder.Recorder()
    c = collector(r, **kwargs)
    c.start()
    c.stop()
    c.join()
    c.start()
    with pytest.raises(RuntimeError):
        c.start()
    c.stop()
    c.join()
예제 #6
0
def test_collect_truncate():
    r = recorder.Recorder()
    c = stack.StackCollector(r, nframes=5)
    c.start()
    func1()
    while not r.events[stack.StackSampleEvent]:
        pass
    c.stop()
    e = r.events[stack.StackSampleEvent][0]
    assert e.nframes > c.nframes
    assert len(e.frames) == c.nframes
예제 #7
0
def test_new_interval():
    r = recorder.Recorder()
    c = stack.StackCollector(r, max_time_usage_pct=2)
    new_interval = c._compute_new_interval(1000000)
    assert new_interval == 0.049
    new_interval = c._compute_new_interval(2000000)
    assert new_interval == 0.098
    c = stack.StackCollector(r, max_time_usage_pct=10)
    new_interval = c._compute_new_interval(200000)
    assert new_interval == 0.01
    new_interval = c._compute_new_interval(1)
    assert new_interval == c.min_interval_time
예제 #8
0
def _test_collector_collect(collector, event_type, fn=None, **kwargs):
    r = recorder.Recorder()
    c = collector(r, **kwargs)
    c.start()
    thread_id = c._worker.ident
    while not r.events[event_type]:
        if fn is not None:
            _ = fn()
        # Sleep so gevent can switch to the other thread
        time.sleep(0)
    c.stop()
    assert len(r.events[event_type]) >= 1
    return r, c, thread_id
예제 #9
0
def test_filter_remove():
    r = recorder.Recorder()

    def filter_all(events):
        return []

    r.add_event_filter(event.Event, filter_all)
    r.push_event(event.Event())
    assert len(r.events[event.Event]) == 0

    r.remove_event_filter(event.Event, filter_all)
    r.push_event(event.Event())
    assert len(r.events[event.Event]) == 1
예제 #10
0
def test_collect_once():
    r = recorder.Recorder()
    s = stack.StackCollector(r)
    # Start the collector as we need to have a start time set
    with s:
        all_events = s.collect()
    assert len(all_events) == 2
    e = all_events[0][0]
    assert e.thread_id > 0
    assert e.thread_name == "MainThread"
    assert len(e.frames) >= 1
    assert e.frames[0][0].endswith(".py")
    assert e.frames[0][1] > 0
    assert isinstance(e.frames[0][2], str)
예제 #11
0
def test_collect_truncate():
    r = recorder.Recorder()
    c = stack.StackCollector(r, nframes=5)
    c.start()
    func1()
    while not r.events[stack.StackSampleEvent]:
        pass
    c.stop()
    for e in r.events[stack.StackSampleEvent]:
        if e.thread_name == "MainThread":
            assert len(e.frames) <= c.nframes
            break
    else:
        pytest.fail("Unable to find the main thread")
예제 #12
0
def test_collect_once():
    r = recorder.Recorder()
    s = stack.StackCollector(r)
    s._init()
    all_events = s._collect()
    assert len(all_events) == 2
    e = all_events[0][0]
    assert e.thread_id > 0
    # Thread name is None with gevent
    assert isinstance(e.thread_name, (str, type(None)))
    assert len(e.frames) >= 1
    assert e.frames[0][0].endswith(".py")
    assert e.frames[0][1] > 0
    assert isinstance(e.frames[0][2], str)
예제 #13
0
def test_lock_gevent_tasks():
    r = recorder.Recorder()

    def play_with_lock():
        lock = threading.Lock()
        lock.acquire()
        lock.release()

    with collector_threading.LockCollector(r, capture_pct=100):
        t = threading.Thread(name="foobar", target=play_with_lock)
        t.start()
        t.join()

    assert len(r.events[collector_threading.LockAcquireEvent]) >= 1
    assert len(r.events[collector_threading.LockReleaseEvent]) >= 1

    for event in r.events[collector_threading.LockAcquireEvent]:
        if event.lock_name == "test_threading.py:199":
            assert event.thread_id == nogevent.main_thread_id
            assert event.wait_time_ns >= 0
            assert event.task_id == t.ident
            assert event.task_name == "foobar"
            # It's called through pytest so I'm sure it's gonna be that long, right?
            assert len(event.frames) > 3
            assert event.nframes > 3
            assert event.frames[0] == (__file__, 200, "play_with_lock")
            assert event.sampling_pct == 100
            assert event.task_id == t.ident
            assert event.task_name == "foobar"
            break
    else:
        pytest.fail("Lock event not found")

    for event in r.events[collector_threading.LockReleaseEvent]:
        if event.lock_name == "test_threading.py:199":
            assert event.thread_id == nogevent.main_thread_id
            assert event.locked_for_ns >= 0.1
            assert event.task_id == t.ident
            assert event.task_name == "foobar"
            # It's called through pytest so I'm sure it's gonna be that long, right?
            assert len(event.frames) > 3
            assert event.nframes > 3
            assert event.frames[0] == (__file__, 201, "play_with_lock")
            assert event.sampling_pct == 100
            assert event.task_id == t.ident
            assert event.task_name == "foobar"
            break
    else:
        pytest.fail("Lock event not found")
예제 #14
0
def test_stress_threads():
    NB_THREADS = 20

    threads = []
    for i in range(NB_THREADS):
        t = threading.Thread(target=_f0)  # noqa: E149,F821
        t.start()
        threads.append(t)

    s = stack.StackCollector(recorder=recorder.Recorder())
    number = 10000
    with s:
        exectime = timeit.timeit(s.collect, number=number)
    print("%.3f ms per call" % (1000.0 * exectime / number))
    for t in threads:
        t.join()
예제 #15
0
def test_lock_acquire_events():
    r = recorder.Recorder()
    with collector_threading.LockCollector(r, capture_pct=100):
        lock = threading.Lock()
        lock.acquire()
    assert len(r.events[collector_threading.LockAcquireEvent]) == 1
    assert len(r.events[collector_threading.LockReleaseEvent]) == 0
    event = r.events[collector_threading.LockAcquireEvent][0]
    assert event.lock_name == "test_threading.py:59"
    assert event.thread_id == _thread.get_ident()
    assert event.wait_time_ns > 0
    # It's called through pytest so I'm sure it's gonna be that long, right?
    assert len(event.frames) > 3
    assert event.nframes > 3
    assert event.frames[0] == (__file__, 60, "test_lock_acquire_events")
    assert event.sampling_pct == 100
예제 #16
0
def test_lock_release_events():
    r = recorder.Recorder()
    with collector_threading.ThreadingLockCollector(r, capture_pct=100):
        lock = threading.Lock()
        lock.acquire()
        lock.release()
    assert len(r.events[collector_threading.ThreadingLockAcquireEvent]) == 1
    assert len(r.events[collector_threading.ThreadingLockReleaseEvent]) == 1
    event = r.events[collector_threading.ThreadingLockReleaseEvent][0]
    assert event.lock_name == "test_threading.py:178"
    assert event.thread_id == nogevent.thread_get_ident()
    assert event.locked_for_ns >= 0.1
    # It's called through pytest so I'm sure it's gonna be that long, right?
    assert len(event.frames) > 3
    assert event.nframes > 3
    assert event.frames[0] == (__file__, 180, "test_lock_release_events")
    assert event.sampling_pct == 100
예제 #17
0
def test_collect_once():
    r = recorder.Recorder()
    s = stack.StackCollector(r)
    s._init()
    all_events = s.collect()
    assert len(all_events) == 2
    stack_events = all_events[0]
    for e in stack_events:
        if e.thread_name == "MainThread":
            assert e.thread_id > 0
            assert len(e.frames) >= 1
            assert e.frames[0][0].endswith(".py")
            assert e.frames[0][1] > 0
            assert isinstance(e.frames[0][2], str)
            break
    else:
        pytest.fail("Unable to find MainThread")
예제 #18
0
def test_stress_threads_run_as_thread():
    NB_THREADS = 40

    threads = []
    for i in range(NB_THREADS):
        t = threading.Thread(target=_f0)  # noqa: E149,F821
        t.start()
        threads.append(t)

    r = recorder.Recorder()
    s = stack.StackCollector(recorder=r)
    # This mainly check nothing bad happens when we collect a lot of threads and store the result in the Recorder
    with s:
        time.sleep(3)
    assert r.events[stack.StackSampleEvent]
    for t in threads:
        t.join()
예제 #19
0
    def __attrs_post_init__(self):
        r = self._recorder = recorder.Recorder(
            max_events={
                # Allow to store up to 10 threads for 60 seconds at 100 Hz
                stack.StackSampleEvent:
                10 * 60 * 100,
                stack.StackExceptionSampleEvent:
                10 * 60 * 100,
                # This can generate one event every 0.1s if 100% are taken — though we take 5% by default.
                # = (60 seconds / 0.1 seconds)
                memory.MemorySampleEvent:
                int(60 / 0.1),
                # (default buffer size / interval) * export interval
                memalloc.MemoryAllocSampleEvent:
                int((memalloc.MemoryCollector._DEFAULT_MAX_EVENTS /
                     memalloc.MemoryCollector._DEFAULT_INTERVAL) * 60),
                # Do not limit the heap sample size as the number of events is relative to allocated memory anyway
                memalloc.MemoryHeapSampleEvent:
                None,
            },
            default_max_events=int(
                os.environ.get("DD_PROFILING_MAX_EVENTS",
                               recorder.Recorder._DEFAULT_MAX_EVENTS)),
        )

        if formats.asbool(os.environ.get("DD_PROFILING_MEMALLOC", "true")):
            mem_collector = memalloc.MemoryCollector(r)
        else:
            mem_collector = memory.MemoryCollector(r)

        self._collectors = [
            stack.StackCollector(r, tracer=self.tracer),
            mem_collector,
            threading.LockCollector(r, tracer=self.tracer),
        ]

        exporters = self._build_default_exporters(self.tracer, self.url,
                                                  self.tags, self.service,
                                                  self.env, self.version)

        if exporters:
            self._scheduler = scheduler.Scheduler(
                recorder=r,
                exporters=exporters,
                before_flush=self._collectors_snapshot)
예제 #20
0
def test_stress_threads():
    NB_THREADS = 10

    threads = []
    for i in range(NB_THREADS):
        t = threading.Thread(target=_f0)  # noqa: E149,F821
        t.start()
        threads.append(t)

    s = stack.StackCollector(recorder=recorder.Recorder())
    # Make sure that the collector thread does not interfere with the test
    s.MIN_INTERVAL_TIME = 60
    number = 20000
    s._init()
    exectime = timeit.timeit(s.collect, number=number)
    # Threads are fake threads with gevent, so result is actually for one thread, not NB_THREADS
    print("%.3f ms per call" % (1000.0 * exectime / number))
    for t in threads:
        t.join()
예제 #21
0
def test_memory_collector_ignore_profiler(ignore_profiler):
    r = recorder.Recorder()
    mc = memalloc.MemoryCollector(r, ignore_profiler=ignore_profiler)
    with mc:
        object()
        # Make sure we collect at least once
        mc.periodic()

    ok = False
    for event in r.events[memalloc.MemoryAllocSampleEvent]:
        for frame in event.frames:
            if ignore_profiler:
                assert frame[0] != _periodic.__file__
            elif frame[0] == _periodic.__file__:
                ok = True
                break

    if not ignore_profiler:
        assert ok
def test_with_override():
    seen = {"seen": False}

    def myhook(exctype, value, traceback):
        seen["seen"] = True

    sys.excepthook = myhook
    r = recorder.Recorder()
    c = exceptions.UncaughtExceptionCollector(r)
    c.start()
    sys.excepthook(ValueError, ValueError(), None)
    c.stop()
    assert seen["seen"]
    seen["seen"] = False
    sys.excepthook(ValueError, ValueError(), None)
    assert seen["seen"]
    events = r.events[exceptions.UncaughtExceptionEvent]
    assert len(events) == 1
    _check_event(events[0])
예제 #23
0
def test_exception_collection():
    r = recorder.Recorder()
    c = stack.StackCollector(r)
    with c:
        try:
            raise ValueError("hello")
        except Exception:
            nogevent.sleep(1)

    exception_events = r.events[stack.StackExceptionSampleEvent]
    assert len(exception_events) >= 1
    e = exception_events[0]
    assert e.timestamp > 0
    assert e.sampling_period > 0
    assert e.thread_id == nogevent.thread_get_ident()
    assert e.thread_name == "MainThread"
    assert e.frames == [(__file__, 321, "test_exception_collection")]
    assert e.nframes == 1
    assert e.exc_type == ValueError
예제 #24
0
def test_memory_collector_ignore_profiler(ignore_profiler):
    r = recorder.Recorder()
    mc = memalloc.MemoryCollector(r, ignore_profiler=ignore_profiler)
    with mc:
        thread_id = mc._worker.ident
        object()
        # Make sure we collect at least once
        mc.periodic()

    ok = False
    for event in r.events[memalloc.MemoryAllocSampleEvent]:
        if ignore_profiler:
            assert event.thread_id != thread_id
        elif event.thread_id == thread_id:
            ok = True
            break

    if not ignore_profiler:
        assert ok
예제 #25
0
def test_wrapper():
    r = recorder.Recorder()
    collector = collector_threading.LockCollector(r)
    with collector:

        class Foobar(object):
            lock_class = threading.Lock

            def __init__(self):
                lock = self.lock_class()
                assert lock.acquire()
                lock.release()

        # Try to access the attribute
        lock = Foobar.lock_class()
        assert lock.acquire()
        lock.release()

        # Try this way too
        Foobar()
예제 #26
0
def test_heap_collector():
    heap_sample_size = 1024
    r = recorder.Recorder()
    mc = memalloc.MemoryCollector(r, heap_sample_size=heap_sample_size)
    with mc:
        keep_me = _allocate_1k()
        events = mc.snapshot()

    assert len(events) == 1
    assert len(events[0]) >= 1

    del keep_me

    for event in events[0]:
        assert 0 < len(event.frames) <= mc.max_nframe
        assert event.nframes >= len(event.frames)
        assert event.sample_size == heap_sample_size
        assert len(event.frames) >= 1
        assert event.size > 0
        assert event.thread_id > 0
        assert isinstance(event.thread_name, str)
예제 #27
0
def test_exception_collection():
    r = recorder.Recorder()
    c = stack.StackCollector(r)
    c.start()
    try:
        raise ValueError("hello")
    except Exception:
        sleep(1)
    c.stop()

    exception_events = r.events[stack.StackExceptionSampleEvent]
    assert len(exception_events) >= 1
    e = exception_events[0]
    assert e.timestamp > 0
    assert e.sampling_period > 0
    if not TESTING_GEVENT:
        assert e.thread_id == _thread.get_ident()
        assert e.thread_name == "MainThread"
    assert e.frames == [(__file__, 209, "test_exception_collection")]
    assert e.nframes == 1
    assert e.exc_type == ValueError
예제 #28
0
    def __attrs_post_init__(self):
        r = recorder.Recorder(
            max_events={
                # Allow to store up to 10 threads for 60 seconds at 100 Hz
                stack.StackSampleEvent:
                10 * 60 * 100,
                stack.StackExceptionSampleEvent:
                10 * 60 * 100,
                # This can generate one event every 0.1s if 100% are taken — though we take 5% by default.
                # = (60 seconds / 0.1 seconds)
                memory.MemorySampleEvent:
                int(60 / 0.1),
                # (default buffer size / interval) * export interval
                memalloc.MemoryAllocSampleEvent:
                int((64 / 0.5) * 60),
            },
            default_max_events=int(
                os.environ.get("DD_PROFILING_MAX_EVENTS",
                               recorder.Recorder._DEFAULT_MAX_EVENTS)),
        )

        if formats.asbool(os.environ.get("DD_PROFILING_MEMALLOC", "false")):
            mem_collector = memalloc.MemoryCollector(r)
        else:
            mem_collector = memory.MemoryCollector(r)

        self._collectors = [
            stack.StackCollector(r, tracer=self.tracer),
            mem_collector,
            exceptions.UncaughtExceptionCollector(r),
            threading.LockCollector(r),
        ]

        exporters = self._build_default_exporters(self.service, self.env,
                                                  self.version)

        if exporters:
            self._scheduler = scheduler.Scheduler(recorder=r,
                                                  exporters=exporters)
예제 #29
0
def test_exception_collection_trace(tracer):
    r = recorder.Recorder()
    c = stack.StackCollector(r, tracer=tracer)
    with c:
        with tracer.trace("test123") as span:
            try:
                raise ValueError("hello")
            except Exception:
                nogevent.sleep(1)

    exception_events = r.events[stack.StackExceptionSampleEvent]
    assert len(exception_events) >= 1
    e = exception_events[0]
    assert e.timestamp > 0
    assert e.sampling_period > 0
    assert e.thread_id == nogevent.thread_get_ident()
    assert e.thread_name == "MainThread"
    assert e.frames == [(__file__, 344, "test_exception_collection_trace")]
    assert e.nframes == 1
    assert e.exc_type == ValueError
    assert e.span_id == span.span_id
    assert e.trace_id == span.trace_id
예제 #30
0
def test_collect_once():
    r = recorder.Recorder()
    s = stack.StackCollector(r)
    s._init()
    all_events = s.collect()
    assert len(all_events) == 2
    stack_events = all_events[0]
    for e in stack_events:
        if e.thread_name == "MainThread":
            if TESTING_GEVENT and stack.FEATURES["gevent-tasks"]:
                assert e.task_id > 0
                assert e.task_name == e.thread_name
            else:
                assert e.task_id is None
                assert e.task_name is None
            assert e.thread_id > 0
            assert len(e.frames) >= 1
            assert e.frames[0][0].endswith(".py")
            assert e.frames[0][1] > 0
            assert isinstance(e.frames[0][2], str)
            break
    else:
        pytest.fail("Unable to find MainThread")