def before(self): codeguru_client_builder = CodeGuruClientBuilder( environment={"aws_session": boto3.session.Session()}) self.client_stubber = Stubber(codeguru_client_builder.codeguru_client) self.clear_lambda_specific_environment_variables_for_test_run() profile_encoder = MagicMock(name="profile_encoder", spec=ProfileEncoder) profile_encoder.encode.side_effect = lambda **args: args[ "output_stream"].write(b"test-profile-encoder-output") self.environment = { "profiling_group_name": profiling_group_name, "profile_encoder": profile_encoder, "codeguru_profiler_builder": codeguru_client_builder, "agent_metadata": AgentMetadata(fleet_info=DefaultFleetInfo()), "reporting_interval": timedelta(minutes=13), "sampling_interval": timedelta(seconds=13), "minimum_time_reporting": timedelta(minutes=13), "max_stack_depth": 1300 } default_config = AgentConfiguration( should_profile=True, sampling_interval=self.environment["sampling_interval"], reporting_interval=self.environment["reporting_interval"], minimum_time_reporting=self.environment["minimum_time_reporting"]) self.environment["agent_config_merger"] = AgentConfigurationMerger( default_config) self.subject = SdkReporter(environment=self.environment) self.subject.setup()
def before(self): self.profiler = Profiler( profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME, environment_override={ 'initial_sampling_interval': timedelta(), 'agent_metadata': AgentMetadata(fleet_info=DefaultFleetInfo()) }) self.client_stubber = Stubber( self.profiler._profiler_runner.collector.reporter. codeguru_client_builder.codeguru_client) report_expected_params = { 'agentProfile': ANY, 'contentType': 'application/json', 'profilingGroupName': DUMMY_TEST_PROFILING_GROUP_NAME } self.client_stubber.add_response( 'configure_agent', {'configuration': { 'shouldProfile': True, 'periodInSeconds': 100 }}) self.client_stubber.add_response('post_agent_profile', {}, report_expected_params) yield self.profiler.stop()
def before(self): now_millis = int(time.time()) * 1000 five_minutes_ago_millis = now_millis - (5 * 60 * 1000) sample = Sample( stacks=[[Frame(MY_PROFILING_GROUP_NAME_FOR_INTEG_TESTS)]], attempted_sample_threads_count=1, seen_threads_count=1) self.profile = Profile(MY_PROFILING_GROUP_NAME_FOR_INTEG_TESTS, 1.0, 1.0, five_minutes_ago_millis) # FIXME: Remove adding the end time manually below after feature fully support self.profile.end = now_millis self.profile.add(sample) self.environment = { "should_profile": True, "profiling_group_name": MY_PROFILING_GROUP_NAME_FOR_INTEG_TESTS, "aws_session": boto3.session.Session(), "reporting_interval": timedelta(minutes=13), "sampling_interval": timedelta(seconds=1), "minimum_time_reporting": timedelta(minutes=6), "max_stack_depth": 2345, "cpu_limit_percentage": 29, "agent_metadata": AgentMetadata(fleet_info=DefaultFleetInfo()) } self.environment["codeguru_profiler_builder"] = CodeGuruClientBuilder( self.environment) self.agent_config = AgentConfiguration( should_profile=True, sampling_interval=self.environment["sampling_interval"], reporting_interval=self.environment["reporting_interval"], minimum_time_reporting=self.environment["minimum_time_reporting"], max_stack_depth=self.environment["max_stack_depth"], cpu_limit_percentage=self.environment["cpu_limit_percentage"])
def before(self): self.timer = Timer() self.profiler = Profiler( profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME, environment_override={ "timer": self.timer, "cpu_limit_percentage": 40, "sampling_interval": timedelta(seconds=0.01), 'agent_metadata': AgentMetadata(fleet_info=DefaultFleetInfo()) }, ) yield self.profiler.stop()
def _setup_final_environment(self, environment, environment_override): environment.update(environment_override) # set additional parameters if needed (costly default init or depend on other parameters) if environment.get('initial_sampling_interval') is None: environment['initial_sampling_interval'] = datetime.timedelta( seconds=SystemRandom().uniform(0, AgentConfiguration.get().sampling_interval.total_seconds())) environment['excluded_threads'] = \ frozenset({environment['profiler_thread_name']}.union(environment['excluded_threads'])) # TODO delay metadata lookup until we need it environment['agent_metadata'] = environment.get('agent_metadata') or AgentMetadata() environment['collector'] = environment.get('collector') or self._select_collector(environment) environment["profiler_disabler"] = environment.get('profiler_disabler') or ProfilerDisabler(environment) return UnmodifiableDict(environment)
def _create_lambda_profiler(profiling_group_name, region_name, environment_override, context, env=os.environ): """ Calls build_profiler module to create the profiler object. If we fail to create it we return a no-op profiler so that we don't even go through this method again. """ from codeguru_profiler_agent.profiler_builder import build_profiler from codeguru_profiler_agent.agent_metadata.agent_metadata import AgentMetadata from codeguru_profiler_agent.agent_metadata.aws_lambda import AWSLambda override = {'agent_metadata': AgentMetadata(AWSLambda.look_up_metadata(context))} override.update(environment_override) profiler = build_profiler(pg_name=profiling_group_name, region_name=region_name, override=override, env=env) if profiler is None: return _EmptyProfiler() return profiler
def before(self): temporary_directory = tempfile.mkdtemp() self.temp_filepath = str( Path(temporary_directory, 'test_profiler_stops_after_killswitch_was_detected')) self.profiler = Profiler( profiling_group_name="test-application", environment_override={ "cpu_limit_percentage": None, "killswitch_filepath": self.temp_filepath, "sampling_interval": timedelta(seconds=0.1), 'agent_metadata': AgentMetadata(fleet_info=DefaultFleetInfo()) }) yield shutil.rmtree(temporary_directory) self.profiler.stop()
def test_it_samples_and_saves_a_profile_to_a_file(self): with \ patch( "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration.is_under_min_reporting_time", return_value=False): file_prefix = str(Path(self.temporary_directory, FILE_PREFIX)) test_start_time = time_utils.current_milli_time() profiler = Profiler( profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME, environment_override={ "initial_sampling_interval": timedelta(), "reporting_mode": "file", "file_prefix": file_prefix, 'agent_metadata': AgentMetadata(fleet_info=DefaultFleetInfo()) }) try: profiler.start() finally: profiler.stop() test_end_time = time_utils.current_milli_time() resulting_profile_path = str( Path(self.temporary_directory, os.listdir(self.temporary_directory)[0])) with (open(resulting_profile_path)) as profiling_result_file: resulting_json = json.loads(profiling_result_file.read()) self.assert_valid_agent_metadata(resulting_json["agentMetadata"]) assert test_start_time <= resulting_json[ "start"] <= resulting_json["end"] <= test_end_time assert frames_in_callgraph_are_in_expected_order( resulting_json["callgraph"], "test.help_utils:HelperThreadRunner:dummy_parent_method", "test.help_utils:HelperThreadRunner:dummy_method")
[Frame("bottom"), Frame("middle"), Frame("different_top")], [Frame("bottom"), Frame("middle")]], attempted_sample_threads_count=10, seen_threads_count=15)) profile.end = end_time profile.set_overhead_ms(timedelta(milliseconds=256)) if platform.system() == "Windows": # In Windows, as time.process stays constant if no cpu time was used (https://bugs.python.org/issue37859), we # would need to manually override the cpu_time_seconds to ensure the test runs as expected profile.cpu_time_seconds = 0.123 return profile agent_metadata = AgentMetadata(fleet_info=AWSEC2Instance( host_name="testHostName", host_type="testHostType")) environment = {"timer": Timer(), "agent_metadata": agent_metadata} class TestSdkProfileEncoder: def before(self): self.profile = example_profile() self.output_stream = io.BytesIO() self.subject = \ ProfileEncoder(gzip=False, environment=environment) self.decoded_json_result = self.decoded_json_result.__get__(self) self._decoded_json_result = None def decoded_json_result(self): if not self._decoded_json_result:
def test_live_profiling(self): with \ patch( "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration.is_under_min_reporting_time", return_value=False), \ patch( "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration._is_reporting_interval_smaller_than_minimum_allowed", return_value=False): profiler = Profiler( profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME, region_name='eu-west-2', environment_override={ "initial_sampling_interval": timedelta(), "sampling_interval": timedelta(seconds=1), "reporting_interval": timedelta(seconds=2), 'agent_metadata': AgentMetadata(fleet_info=DefaultFleetInfo()) }) client = profiler._profiler_runner.collector.reporter.codeguru_client_builder.codeguru_client aggregator = profiler._profiler_runner.collector assert AgentConfiguration.get().sampling_interval == timedelta( seconds=1) assert AgentConfiguration.get().reporting_interval == timedelta( seconds=2) with \ patch.object(client, "post_agent_profile", wraps=client.post_agent_profile) as wrapped_post_agent_profile, \ patch.object(client, "configure_agent", wraps=client.configure_agent) as wrapped_configure_agent, \ patch.object(aggregator, "add", wraps=aggregator.add) as wrapped_add, \ patch( "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration.is_under_min_reporting_time", return_value=False), \ patch( "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration._is_reporting_interval_smaller_than_minimum_allowed", return_value=False): wrapped_configure_agent.return_value = { "configuration": { "agentParameters": { "SamplingIntervalInMilliseconds": "100", "MinimumTimeForReportingInMilliseconds": "1000", "MaxStackDepth": "1000", "MemoryUsageLimitPercent": "29" }, "periodInSeconds": 2, "shouldProfile": True } } try: start_status = profiler.start() assert start_status assert profiler.is_running() time.sleep(3) finally: profiler.stop() assert wrapped_add.call_count >= 3 assert wrapped_post_agent_profile.call_count >= 1 assert wrapped_configure_agent.call_count >= 1 assert AgentConfiguration.get().sampling_interval == timedelta( seconds=1) assert AgentConfiguration.get( ).reporting_interval == timedelta(seconds=2)
def test_it_returns_default_agent_metadata(self): subject = AgentMetadata() assert subject.agent_info == AgentInfo.default_agent_info() assert subject.fleet_info is not None assert subject.runtime_version[0] == "3"
def test_live_profiling(self): with \ patch( "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration.is_under_min_reporting_time", return_value=False), \ patch( "codeguru_profiler_agent.sdk_reporter.sdk_reporter.SdkReporter.check_create_pg_called_during_submit_profile", return_value=False), \ patch( "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration._is_reporting_interval_smaller_than_minimum_allowed", return_value=False): profiler = Profiler( profiling_group_name=DUMMY_TEST_PROFILING_GROUP_NAME, region_name='eu-west-2', environment_override={ "initial_sampling_interval": timedelta(), "sampling_interval": timedelta(seconds=1), "reporting_interval": timedelta(seconds=2), 'agent_metadata': AgentMetadata(fleet_info=DefaultFleetInfo()) }) client = profiler._profiler_runner.collector.reporter.codeguru_client_builder.codeguru_client aggregator = profiler._profiler_runner.collector assert AgentConfiguration.get().sampling_interval == timedelta( seconds=1) assert AgentConfiguration.get().reporting_interval == timedelta( seconds=2) with \ patch.object(client, "post_agent_profile", wraps=client.post_agent_profile) as wrapped_post_agent_profile, \ patch.object(client, "configure_agent", wraps=client.configure_agent) as wrapped_configure_agent, \ patch.object(aggregator, "add", wraps=aggregator.add) as wrapped_add, \ patch( "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration.is_under_min_reporting_time", return_value=False), \ patch( "codeguru_profiler_agent.reporter.agent_configuration.AgentConfiguration._is_reporting_interval_smaller_than_minimum_allowed", return_value=False): wrapped_configure_agent.return_value = { "configuration": { "agentParameters": { "SamplingIntervalInMilliseconds": "100", "MinimumTimeForReportingInMilliseconds": "1000", "MaxStackDepth": "1000", "MemoryUsageLimitPercent": "29" }, "periodInSeconds": 2, "shouldProfile": True } } try: start_status = profiler.start() assert start_status assert profiler.is_running() time.sleep(4) finally: profiler.stop() # We should see at least 2 samples in 4 seconds as the sequence should happen in the order of # initial delay (1 second) # After 1 second, no flush -> sample # After 2 seconds, it attempt to flush (possibly succeed) -> sample/ no sample # After 3 seconds, it attempt to flush (must succeed if it did not flush before) -> no sample/ sample # After 4 seconds, no flush -> sample (if profiler has not stopped yet) assert wrapped_add.call_count >= 2 assert wrapped_post_agent_profile.call_count >= 1 assert wrapped_configure_agent.call_count >= 1 assert AgentConfiguration.get().sampling_interval == timedelta( seconds=1) assert AgentConfiguration.get( ).reporting_interval == timedelta(seconds=2)