def test_is_sstbf_configured(): class SYS: def __init__(self, configured): self.sst_bf_configured = configured def refresh_stats(self): return with mock.patch("pwr.get_system", return_value=SYS(True)) as mock_get_system: assert sstbf.is_sstbf_configured() mock_get_system.assert_called_once() with mock.patch("pwr.get_system", return_value=SYS(False)) as mock_get_system: assert not sstbf.is_sstbf_configured() mock_get_system.assert_called_once() with mock.patch("pwr.get_system", return_value=None) as mock_get_system: assert not sstbf.is_sstbf_configured() mock_get_system.assert_called_once() with mock.patch("pwr.get_system", return_value=[]) as mock_get_system: assert not sstbf.is_sstbf_configured() mock_get_system.assert_called_once() with mock.patch("pwr.get_system", side_effect=IOError('Test')) as mock_get_system: assert not sstbf.is_sstbf_configured() mock_get_system.assert_called_once()
def event_handler(self): """ Handles config_changed event """ # rate limiting last_cfg_change_ts = 0 min_time_diff = 1 / common.RATE_LIMIT while not self.stop_event.is_set(): if common.CONFIG_STORE.is_config_changed(): time_diff = time.time() - last_cfg_change_ts if time_diff < min_time_diff: log.info("Rate Limiter, sleeping " \ + str(round((min_time_diff - time_diff) * 1000)) + "ms...") time.sleep(min_time_diff - time_diff) log.info("Configuration changed, processing new config...") result = cache_ops.configure_rdt() if result != 0: log.error("Failed to apply RDT configuration!") break if caps.sstcp_enabled() and not sstbf.is_sstbf_configured(): result = power.configure_power() if result != 0: log.error( "Failed to apply Power Profiles configuration!") break last_cfg_change_ts = time.time() log.info("New configuration processed")
def func_wrapper(*args, **kwargs): if not _get_power_profiles_expert_mode(): raise MethodNotAllowed("Please enable Expert Mode first.") if sstbf.is_sstbf_configured(): raise MethodNotAllowed( "SST-BF configured, please un-configure SST-BF first") return f(*args, **kwargs)
def post(): """ Handles HTTP POST /pools request. Add a new Pool Raises NotFound, BadRequest, InternalError Returns: response, status code """ json_data = request.get_json() # validate pool schema try: schema, resolver = ConfigStore.load_json_schema('add_pool.json') jsonschema.validate(json_data, schema, resolver=resolver) except jsonschema.ValidationError as error: raise BadRequest("Request validation failed - %s" % (str(error))) admission_control_check = json_data.pop('verify', True) and\ ('cores' in json_data or 'power_profile' in json_data) post_data = json_data.copy() post_data['id'] = common.CONFIG_STORE.get_new_pool_id(post_data) if post_data['id'] is None: raise InternalError("New POOL not added, maximum number of POOLS"\ " reached for requested allocation combination") # convert cbm from string to int if 'cbm' in post_data: cbm = post_data['cbm'] if not isinstance(cbm, int): cbm = int(cbm, 16) post_data['cbm'] = cbm # ignore 'power_profile' if SST-BF is enabled if sstbf.is_sstbf_configured(): post_data.pop('power_profile', None) data = deepcopy(common.CONFIG_STORE.get_config()) data['pools'].append(post_data) try: common.CONFIG_STORE.validate(data, admission_control_check) except Exception as ex: raise BadRequest("New POOL not added, " + str(ex)) common.CONFIG_STORE.set_config(data) res = { 'id': post_data['id'], 'message': "New POOL {} added".format(post_data['id']) } return res, 201
def get(): """ Handles HTTP GET /caps/sstbf request. Retrieve SST-BF capabilities details Returns: response, status code """ res = { 'configured': sstbf.is_sstbf_configured(), 'hp_cores': sstbf.get_hp_cores(), 'std_cores': sstbf.get_std_cores() } return res, 200
def configure_power(): """ Configures Power Profiles """ global PREV_PROFILES # we do not configure power profiles is SST-BF is enabled if sstbf.is_sstbf_configured(): PREV_PROFILES = {} return 0 curr_profiles = _get_curr_profiles() if curr_profiles is None: return -1 if not curr_profiles: return 0 # has power profiles configuration changed since last run? if PREV_PROFILES == curr_profiles: return 0 # in case there was a change, find out which profiles has been changed for profile in curr_profiles.values(): if not profile['cores']: continue prev_profile = PREV_PROFILES.get(profile['id'], []) # apply configuration only for changed profiles if prev_profile != profile: log.debug("POWER: Power profile {} configuration...".format( profile['id'])) min_freq = profile.get('min_freq', None) max_freq = profile.get('max_freq', None) epp = profile.get('epp', None) _set_freqs_epp(profile['cores'], min_freq, max_freq, epp) # reset power config for cores with no power profile assigned cores_to_reset = _get_cores_to_reset() if cores_to_reset: reset(cores_to_reset) # save current profiles configuration PREV_PROFILES = curr_profiles return 0
def test_is_sstbf_configured(): class CPU: def __init__(self, configured): self.sst_bf_configured = configured self.core_list = [] def refresh_stats(self, core=None): return with mock.patch("pwr.get_cpus", return_value=[CPU(True), CPU(True)]) as mock_get_cpus: assert sstbf.is_sstbf_configured() mock_get_cpus.assert_called_once() with mock.patch("pwr.get_cpus", return_value=[CPU(True), CPU(False)]) as mock_get_cpus: assert not sstbf.is_sstbf_configured() mock_get_cpus.assert_called_once() with mock.patch("pwr.get_cpus", return_value=[CPU(False), CPU(False)]) as mock_get_cpus: assert not sstbf.is_sstbf_configured() mock_get_cpus.assert_called_once() with mock.patch("pwr.get_cpus", return_value=None) as mock_get_cpus: assert not sstbf.is_sstbf_configured() mock_get_cpus.assert_called_once() with mock.patch("pwr.get_cpus", return_value=[]) as mock_get_cpus: assert not sstbf.is_sstbf_configured() mock_get_cpus.assert_called_once() with mock.patch("pwr.get_cpus", side_effect=IOError('Test')) as mock_get_cpus: assert not sstbf.is_sstbf_configured() mock_get_cpus.assert_called_once()
def _do_admission_control_check(): """ Admission control check is done if - SST-BF is not configured """ return not sstbf.is_sstbf_configured()
def run(self): """ Runs main loop. """ # process/validate already loaded config file try: common.CONFIG_STORE.process_config() except Exception as ex: log.error("Invalid config file... ") log.error(ex) return log.debug("Cores controlled: {}".\ format(common.CONFIG_STORE.get_pool_attr('cores', None))) data = common.CONFIG_STORE.get_config() for pool in data['pools']: log.debug("Pool: {}/{} Cores: {}, Apps: {}".format(pool.get('name'),\ pool.get('id'), pool.get('cores'), pool.get('apps'))) # set initial SST-BF configuration if caps.sstbf_enabled(): result = sstbf.init_sstbf() if result != 0: log.error( "Failed to apply initial SST-BF configuration, terminating..." ) return log.info("SST-BF enabled, {}configured.".\ format("not " if not sstbf.is_sstbf_configured() else "")) log.info("SST-BF HP cores: {}".format(sstbf.get_hp_cores())) log.info("SST-BF STD cores: {}".format(sstbf.get_std_cores())) else: log.info("SST-BF not enabled") # set initial SST-CP configuration if SST-BF is not configured if caps.sstcp_enabled(): if sstbf.is_sstbf_configured(): log.info( "Power Profiles/SST-CP enabled, not configured, SST-BF is configured" ) else: log.info("Power Profiles/SST-CP enabled.") # set initial POWER configuration result = power.configure_power() if result != 0: log.error("Failed to apply initial Power Profiles configuration,"\ " terminating...") return else: log.info("Power Profiles/EPP not enabled") # set initial RDT configuration log.info("Configuring RDT") # Configure MBA CTRL if caps.mba_supported(): result = common.PQOS_API.enable_mba_bw( common.CONFIG_STORE.get_mba_ctrl_enabled()) if result != 0: log.error( "libpqos MBA CTRL initialization failed, Terminating...") return log.info("RDT MBA CTRL %sabled"\ % ("en" if common.PQOS_API.is_mba_bw_enabled() else "dis")) result = cache_ops.configure_rdt() if result != 0: log.error( "Failed to apply initial RDT configuration, terminating...") return # set CTRL+C sig handler signal.signal(signal.SIGINT, self.signal_handler) self.event_handler() log.info("Terminating...")
def put(pool_id): # pylint: disable=too-many-branches """ Handles HTTP PUT /pools/<pool_id> request. Modifies a Pool Raises NotFound, BadRequest Parameters: pool_id: Id of pool Returns: response, status code """ def check_alloc_tech(pool_id, json_data): if 'cbm' in json_data: if not caps.cat_supported(): raise BadRequest("System does not support CAT!") if pool_id > common.PQOS_API.get_max_cos_id([common.CAT_CAP]): raise BadRequest( "Pool {} does not support CAT".format(pool_id)) if 'mba' in json_data: if not caps.mba_supported(): raise BadRequest("System does not support MBA!") if pool_id > common.PQOS_API.get_max_cos_id([common.MBA_CAP]): raise BadRequest( "Pool {} does not support MBA".format(pool_id)) json_data = request.get_json() # validate app schema try: schema, resolver = ConfigStore.load_json_schema('modify_pool.json') jsonschema.validate(json_data, schema, resolver=resolver) except jsonschema.ValidationError as error: raise BadRequest("Request validation failed - %s" % (str(error))) admission_control_check = json_data.pop('verify', True) and\ ('cores' in json_data or 'power_profile' in json_data) data = deepcopy(common.CONFIG_STORE.get_config()) if 'pools' not in data: raise NotFound("No pools in config file") for pool in data['pools']: if pool['id'] != int(pool_id): continue check_alloc_tech(int(pool_id), json_data) # set new cbm if 'cbm' in json_data: cbm = json_data['cbm'] if not isinstance(cbm, int): cbm = int(cbm, 16) pool['cbm'] = cbm # set new mba if 'mba' in json_data: pool['mba'] = json_data['mba'] # set new cores if 'cores' in json_data: pool['cores'] = json_data['cores'] if 'apps' in pool and pool['apps']: for app_id in pool['apps']: for app in data['apps']: if app['id'] != app_id or 'cores' not in app: continue if not set(app['cores']).issubset(pool['cores']): app.pop('cores') # set new name if 'name' in json_data: pool['name'] = json_data['name'] # set new power profile # ignore 'power_profile' if SST-BF is enabled if 'power_profile' in json_data and not sstbf.is_sstbf_configured( ): pool['power_profile'] = json_data['power_profile'] try: common.CONFIG_STORE.validate(data, admission_control_check) except Exception as ex: raise BadRequest("POOL " + str(pool_id) + " not updated, " + str(ex)) common.CONFIG_STORE.set_config(data) res = {'message': "POOL " + str(pool_id) + " updated"} return res, 200 raise NotFound("POOL " + str(pool_id) + " not found in config")
def run(self, args): """ Runs main loop. Parameters: args: command line arguments """ # load config file try: common.CONFIG_STORE.from_file(args.config) except IOError as ex: log.error("Error reading from config file {}... ".format(args.config)) log.error(ex) return except Exception as ex: log.error("Invalid config file {}... ".format(args.config)) log.error(ex) return log.debug("Cores controlled: {}".\ format(common.CONFIG_STORE.get_pool_attr('cores', None))) data = common.CONFIG_STORE.get_config() for pool in data['pools']: log.debug("Pool: {}/{} Cores: {}, Apps: {}".format(pool.get('name'),\ pool.get('id'), pool.get('cores'), pool.get('apps'))) # set initial SST-BF configuration if caps.sstbf_enabled(): result = sstbf.init_sstbf() if result != 0: log.error("Failed to apply initial SST-BF configuration, terminating...") return log.info("SST-BF enabled, {}configured.".\ format("not " if not sstbf.is_sstbf_configured() else "")) log.info("SST-BF HP cores: {}".format(sstbf.get_hp_cores())) log.info("SST-BF STD cores: {}".format(sstbf.get_std_cores())) else: log.info("SST-BF not enabled") # set initial SST-CP configuration if SST-BF is not configured if caps.sstcp_enabled(): if sstbf.is_sstbf_configured(): log.info("Power Profiles/SST-CP enabled, not configured, SST-BF is configured") else: log.info("Power Profiles/SST-CP enabled.") # set initial POWER configuration result = power.configure_power() if result != 0: log.error("Failed to apply initial Power Profiles configuration,"\ " terminating...") return else: log.info("Power Profiles/EPP not enabled") # set initial RDT configuration log.info("Configuring RDT") result = cache_ops.configure_rdt() if result != 0: log.error("Failed to apply initial RDT configuration, terminating...") return # set CTRL+C sig handler signal.signal(signal.SIGINT, self.signal_handler) self.event_handler() log.info("Terminating...")