Esempio n. 1
0
    def __init__(self, environment=dict()):
        """
        :param environment: dependency container dictionary for the current profiler
        :param sampling_interval: (required inside environment) delay between profile reports in datetime.timedelta
        :param killswitch_filepath: (required inside environment) filepath pointing to the killswitch file. This path
            gets checked every time the profiler samples; the profiler is immediately stopped if this file exists.
        :param collector: (required inside environment) collector object to handle sample processing
        :param initial_sampling_interval: (required inside environment) Initial delay signal sampler takes for starting
        to sample
        :param profiler_thread_name: (required inside environment) Thread name used for running the
        report_orchestration_scheduler
        """
        self.timer = environment.get("timer")
        self.sampler = environment.get("sampler") or Sampler(
            environment=environment)

        self.scheduler = Scheduler(
            command=self._profiling_command,
            delay_provider=lambda: AgentConfiguration.get().sampling_interval,
            initial_delay=environment["initial_sampling_interval"],
            thread_name=environment["profiler_thread_name"])
        self.collector = environment["collector"]
        self.profiler_disabler = environment["profiler_disabler"]
        self.is_profiling_in_progress = False
        self._first_execution = True
 def around(self):
     self.ready_queue = Queue()
     self.done_queue = Queue()
     self.scheduler = Scheduler(self.running_test_process,
                                thread_name="test_thread")
     self.scheduler.start()
     self.ready_queue.get(TEST_TIMEOUT_SECONDS)
     yield
     self.done_queue.put(True)
     self.scheduler.stop()
        def test_exception_not_propagated_from_scheduled_thread(self):
            self.exception_thrown = False

            def throw_exception():
                self.exception_thrown = True
                raise Exception("testing")

            scheduler = \
                Scheduler(command=throw_exception, thread_name="test_thread")
            scheduler.start()
            scheduler._thread.join()

            assert self.exception_thrown
        def around(self):
            self.ready_queue = Queue()
            self.done_queue = Queue()

            def running_test_process():
                self.ready_queue.put(True)
                return self.done_queue.get(TEST_TIMEOUT_SECONDS)

            self.scheduler = \
                Scheduler(running_test_process, thread_name="test_thread")
            self.scheduler.start()
            self.ready_queue.get(TEST_TIMEOUT_SECONDS)
            # finish first execution by pushing into done_queue
            # the scheduler should go into wait
            self.done_queue.put(True)

            # then pause
            self.scheduler.pause(block=True)
            yield
            self.scheduler.stop()
    class TestStart:
        @pytest.fixture(autouse=True)
        def around(self):
            self.ready_queue = Queue()
            self.done_queue = Queue()
            self.scheduler = Scheduler(self.running_test_process,
                                       thread_name="test_thread")
            self.scheduler.start()
            self.ready_queue.get(TEST_TIMEOUT_SECONDS)
            yield
            self.done_queue.put(True)
            self.scheduler.stop()

        def running_test_process(self):
            self.ready_queue.put(True)
            self.done_queue.get(TEST_TIMEOUT_SECONDS)

        def test_function_run_on_new_thread(self):
            assert (self.scheduler.is_running())
            assert (self.scheduler._thread.name == "test_thread")
    class TestStop:
        @before
        def before(self):
            self.scheduler = Scheduler(lambda: True, thread_name="test_thread")
            self.scheduler.start()
            # Make sure thread is alive
            assert (self.scheduler.is_running())

        def test_thread_terminates_when_called_stop(self):
            self.scheduler.stop()
            assert (not self.scheduler.is_running())
    class TestPauseAndResume:
        @pytest.fixture(autouse=True)
        def around(self):
            self.ready_queue = Queue()
            self.done_queue = Queue()

            def running_test_process():
                self.ready_queue.put(True)
                return self.done_queue.get(TEST_TIMEOUT_SECONDS)

            self.scheduler = \
                Scheduler(running_test_process, thread_name="test_thread")
            self.scheduler.start()
            self.ready_queue.get(TEST_TIMEOUT_SECONDS)
            # finish first execution by pushing into done_queue
            # the scheduler should go into wait
            self.done_queue.put(True)

            # then pause
            self.scheduler.pause(block=True)
            yield
            self.scheduler.stop()

        def test_pause_when_scheduler_is_paused(self):
            assert (self.scheduler.is_running())
            assert (self.scheduler.is_paused())

        def test_resume_when_scheduler_is_running(self):
            self.scheduler.resume(block=True)
            assert (self.scheduler.is_running())
            assert (not self.scheduler.is_paused())
        def test_exception_not_thrown_when_stop_is_called_before_starting(
                self):
            scheduler = Scheduler(lambda: True, thread_name="test_thread")

            scheduler.stop()
 def before(self):
     self.scheduler = Scheduler(lambda: True, thread_name="test_thread")
     self.scheduler.start()
     # Make sure thread is alive
     assert (self.scheduler.is_running())
Esempio n. 10
0
class ProfilerRunner:
    """
    ProfilerRunner instantiates and orchestrates all components required for running the profiler.
    It implements and checks the kill switch and cpu limit every time before it samples.
    This class should only be accessed by Profiler for controlling and monitoring the profiler.

    NOTE: If CPU usage exceed CPU limit, profiler will be terminated immediately without any attempt to flush
    the existing data.
    NOTE: Memory limit check is implemented in LocalAggregator
    """
    def __init__(self, environment=dict()):
        """
        :param environment: dependency container dictionary for the current profiler
        :param sampling_interval: (required inside environment) delay between profile reports in datetime.timedelta
        :param killswitch_filepath: (required inside environment) filepath pointing to the killswitch file. This path
            gets checked every time the profiler samples; the profiler is immediately stopped if this file exists.
        :param collector: (required inside environment) collector object to handle sample processing
        :param initial_sampling_interval: (required inside environment) Initial delay signal sampler takes for starting
        to sample
        :param profiler_thread_name: (required inside environment) Thread name used for running the
        report_orchestration_scheduler
        """
        self.timer = environment.get("timer")
        self.sampler = environment.get("sampler") or Sampler(
            environment=environment)

        self.scheduler = Scheduler(
            command=self._profiling_command,
            delay_provider=lambda: AgentConfiguration.get().sampling_interval,
            initial_delay=environment["initial_sampling_interval"],
            thread_name=environment["profiler_thread_name"])
        self.collector = environment["collector"]
        self.profiler_disabler = environment["profiler_disabler"]
        self.is_profiling_in_progress = False
        self._first_execution = True

    def start(self):
        """
        Start running the profiler.
        Note: Profiler will not start if killswitch file exists.

        :return: True if the profiler was started successfully; False otherwise.
        """
        if self.profiler_disabler.should_stop_profiling():
            logger.info("Profiler will not start.")
            return False
        self.scheduler.start()
        return True

    def _refresh_configuration(self):
        self.collector.refresh_configuration()
        self.is_profiling_in_progress = AgentConfiguration.get().should_profile
        if self.is_profiling_in_progress:
            self.scheduler.update_delay_provider(
                lambda: AgentConfiguration.get().sampling_interval)
        else:
            # if we should not profile we can simply wait for the reporting interval and call again at that time.
            self.scheduler.update_delay_provider(
                lambda: AgentConfiguration.get().reporting_interval)

    def _profiling_command(self):
        try:
            if self._first_execution:
                self.collector.setup()
                self._first_execution = False
            return self._run_profiler()
        except:
            logger.info(
                "An unexpected issue caused the profiling command to terminate.",
                exc_info=True)
            return False

    @with_timer("runProfiler")
    def _run_profiler(self):
        if self.profiler_disabler.should_stop_profiling(
                self.collector.profile):
            return False

        if not self.is_profiling_in_progress:
            self._refresh_configuration()

        # after the refresh we may be working on a profile
        if self.is_profiling_in_progress:
            sample = self.sampler.sample()
            self.collector.add(sample)
            if self.collector.flush():
                self.is_profiling_in_progress = False
        return True

    def is_running(self):
        return self.scheduler.is_running()

    def is_paused(self):
        return self.scheduler.is_paused()

    def stop(self):
        """
        Terminate profiler gracefully.
        It terminates the profiling thread and flushes existing profile to the backend.
        """
        self.scheduler.stop()
        self.collector.flush(force=True)
        self.is_profiling_in_progress = False

    def resume(self, block=False):
        """
        Will signal the scheduler that profiling should resume.

        :param block: if True, we will not return from this function before the change is applied, default is False.
        """
        self.collector.profile.resume()
        self.scheduler.resume(block)

    def pause(self, block=False):
        """
        Will signal the scheduler that profiling should pause.

        :param block: if True, we will not return from this function before the change is applied, default is False.
        """
        self.scheduler.pause(block)
        self.collector.profile.pause()