Skip to content
Snippets Groups Projects
Commit 22fcb484 authored by Björn Vonheiden's avatar Björn Vonheiden
Browse files

Enable setting threshold for trend slope

This enables be more dynamic with evaluations.
For lower loads the trend slope should be smaller.
parent 3fba1f58
No related branches found
No related tags found
1 merge request!74Make Benchmark Trend Slop Threshold configureable
...@@ -136,6 +136,11 @@ def benchmark_parser(description): ...@@ -136,6 +136,11 @@ def benchmark_parser(description):
metavar='<strategy>', metavar='<strategy>',
default=os.environ.get('SEARCH_STRATEGY', 'default'), default=os.environ.get('SEARCH_STRATEGY', 'default'),
help='The benchmarking search strategy. Can be set to default, linear-search or binary-search') help='The benchmarking search strategy. Can be set to default, linear-search or binary-search')
parser.add_argument('--threshold',
type=int,
metavar='<threshold>',
default=os.environ.get('THRESHOLD', 2000),
help='The threshold the trend search strategies use to determine that a load could be handled.')
return parser return parser
......
...@@ -2,7 +2,7 @@ from sklearn.linear_model import LinearRegression ...@@ -2,7 +2,7 @@ from sklearn.linear_model import LinearRegression
import pandas as pd import pandas as pd
import os import os
def compute(directory, filename, warmup_sec, threshold): def compute(directory, filename, warmup_sec):
df = pd.read_csv(os.path.join(directory, filename)) df = pd.read_csv(os.path.join(directory, filename))
input = df input = df
input['sec_start'] = input.loc[0:, 'timestamp'] - input.iloc[0]['timestamp'] input['sec_start'] = input.loc[0:, 'timestamp'] - input.iloc[0]['timestamp']
...@@ -16,4 +16,4 @@ def compute(directory, filename, warmup_sec, threshold): ...@@ -16,4 +16,4 @@ def compute(directory, filename, warmup_sec, threshold):
trend_slope = linear_regressor.coef_[0][0] trend_slope = linear_regressor.coef_[0][0]
return trend_slope return trend_slope
\ No newline at end of file
...@@ -18,5 +18,6 @@ class ExperimentConfig: ...@@ -18,5 +18,6 @@ class ExperimentConfig:
configurations: dict configurations: dict
domain_restriction_strategy: object domain_restriction_strategy: object
search_strategy: object search_strategy: object
threshold: int
subexperiment_executor: object subexperiment_executor: object
subexperiment_evaluator: object subexperiment_evaluator: object
...@@ -7,8 +7,9 @@ def binary_search(config, dim_value, lower, upper, subexperiment_counter): ...@@ -7,8 +7,9 @@ def binary_search(config, dim_value, lower, upper, subexperiment_counter):
print(f"Run subexperiment {subexperiment_counter} with config {dim_value} {config.replicass[lower]}") print(f"Run subexperiment {subexperiment_counter} with config {dim_value} {config.replicass[lower]}")
subexperiment_config = SubexperimentConfig(config.use_case, config.exp_id, subexperiment_counter, dim_value, config.replicass[lower], config.partitions, config.cpu_limit, config.memory_limit, config.execution_minutes, config.prometheus_base_url, config.reset, config.namespace, config.result_path, config.configurations) subexperiment_config = SubexperimentConfig(config.use_case, config.exp_id, subexperiment_counter, dim_value, config.replicass[lower], config.partitions, config.cpu_limit, config.memory_limit, config.execution_minutes, config.prometheus_base_url, config.reset, config.namespace, config.result_path, config.configurations)
config.subexperiment_executor.execute(subexperiment_config) config.subexperiment_executor.execute(subexperiment_config)
result = config.subexperiment_evaluator.execute(subexperiment_config) success = config.subexperiment_evaluator.execute(subexperiment_config,
if result==1: # successful, the upper neighbor is assumed to also has been successful config.threshold)
if success: # successful, the upper neighbor is assumed to also has been successful
return (lower, subexperiment_counter+1) return (lower, subexperiment_counter+1)
else: # not successful else: # not successful
return (lower+1, subexperiment_counter) return (lower+1, subexperiment_counter)
...@@ -16,15 +17,17 @@ def binary_search(config, dim_value, lower, upper, subexperiment_counter): ...@@ -16,15 +17,17 @@ def binary_search(config, dim_value, lower, upper, subexperiment_counter):
print(f"Run subexperiment {subexperiment_counter} with config {dim_value} {config.replicass[lower]}") print(f"Run subexperiment {subexperiment_counter} with config {dim_value} {config.replicass[lower]}")
subexperiment_config = SubexperimentConfig(config.use_case, config.exp_id, subexperiment_counter, dim_value, config.replicass[lower], config.partitions, config.cpu_limit, config.memory_limit, config.execution_minutes, config.prometheus_base_url, config.reset, config.namespace, config.result_path, config.configurations) subexperiment_config = SubexperimentConfig(config.use_case, config.exp_id, subexperiment_counter, dim_value, config.replicass[lower], config.partitions, config.cpu_limit, config.memory_limit, config.execution_minutes, config.prometheus_base_url, config.reset, config.namespace, config.result_path, config.configurations)
config.subexperiment_executor.execute(subexperiment_config) config.subexperiment_executor.execute(subexperiment_config)
result = config.subexperiment_evaluator.execute(subexperiment_config) success = config.subexperiment_evaluator.execute(subexperiment_config,
if result==1: # minimal instances found config.threshold)
if success: # minimal instances found
return (lower, subexperiment_counter) return (lower, subexperiment_counter)
else: # not successful, check if lower+1 instances are sufficient else: # not successful, check if lower+1 instances are sufficient
print(f"Run subexperiment {subexperiment_counter} with config {dim_value} {config.replicass[upper]}") print(f"Run subexperiment {subexperiment_counter} with config {dim_value} {config.replicass[upper]}")
subexperiment_config = SubexperimentConfig(config.use_case, config.exp_id, subexperiment_counter, dim_value, config.replicass[upper], config.partitions, config.cpu_limit, config.memory_limit, config.execution_minutes, config.prometheus_base_url, config.reset, config.namespace, config.result_path, config.configurations) subexperiment_config = SubexperimentConfig(config.use_case, config.exp_id, subexperiment_counter, dim_value, config.replicass[upper], config.partitions, config.cpu_limit, config.memory_limit, config.execution_minutes, config.prometheus_base_url, config.reset, config.namespace, config.result_path, config.configurations)
config.subexperiment_executor.execute(subexperiment_config) config.subexperiment_executor.execute(subexperiment_config)
result = config.subexperiment_evaluator.execute(subexperiment_config) success = config.subexperiment_evaluator.execute(subexperiment_config,
if result == 1: # minimal instances found config.threshold)
if success: # minimal instances found
return (upper, subexperiment_counter) return (upper, subexperiment_counter)
else: else:
return (upper+1, subexperiment_counter) return (upper+1, subexperiment_counter)
...@@ -34,8 +37,9 @@ def binary_search(config, dim_value, lower, upper, subexperiment_counter): ...@@ -34,8 +37,9 @@ def binary_search(config, dim_value, lower, upper, subexperiment_counter):
print(f"Run subexperiment {subexperiment_counter} with config {dim_value} {config.replicass[mid]}") print(f"Run subexperiment {subexperiment_counter} with config {dim_value} {config.replicass[mid]}")
subexperiment_config = SubexperimentConfig(config.use_case, config.exp_id, subexperiment_counter, dim_value, config.replicass[mid], config.partitions, config.cpu_limit, config.memory_limit, config.execution_minutes, config.prometheus_base_url, config.reset, config.namespace, config.result_path, config.configurations) subexperiment_config = SubexperimentConfig(config.use_case, config.exp_id, subexperiment_counter, dim_value, config.replicass[mid], config.partitions, config.cpu_limit, config.memory_limit, config.execution_minutes, config.prometheus_base_url, config.reset, config.namespace, config.result_path, config.configurations)
config.subexperiment_executor.execute(subexperiment_config) config.subexperiment_executor.execute(subexperiment_config)
result = config.subexperiment_evaluator.execute(subexperiment_config) success = config.subexperiment_evaluator.execute(subexperiment_config,
if result == 1: # success -> search in (lower, mid-1) config.threshold)
if success: # success -> search in (lower, mid-1)
return binary_search(config, dim_value, lower, mid-1, subexperiment_counter+1) return binary_search(config, dim_value, lower, mid-1, subexperiment_counter+1)
else: # not success -> search in (mid+1, upper) else: # not success -> search in (mid+1, upper)
return binary_search(config, dim_value, mid+1, upper, subexperiment_counter+1) return binary_search(config, dim_value, mid+1, upper, subexperiment_counter+1)
......
...@@ -2,23 +2,30 @@ ...@@ -2,23 +2,30 @@
import os import os
from strategies.strategies.config import SubexperimentConfig from strategies.strategies.config import SubexperimentConfig
def execute(config, dim_value_index, lower_replicas_bound_index, subexperiment_counter): def execute(config, dim_value_index, lower_replicas_bound_index, subexperiment_counter):
new_lower_replicas_bound_index=lower_replicas_bound_index new_lower_replicas_bound_index = lower_replicas_bound_index
new_lower_replicas_bound_found=False new_lower_replicas_bound_found = False
subexperiments_total=len(config.dim_values)*len(config.replicass) subexperiments_total = len(config.dim_values) * len(config.replicass)
while lower_replicas_bound_index < len(config.replicass): while lower_replicas_bound_index < len(config.replicass):
subexperiment_counter+=1 subexperiment_counter += 1
dim_value=config.dim_values[dim_value_index] dim_value = config.dim_values[dim_value_index]
replicas=config.replicass[lower_replicas_bound_index] replicas = config.replicass[lower_replicas_bound_index]
print(f"Run subexperiment {subexperiment_counter} of {subexperiments_total} with dimension value {dim_value} and {replicas} replicas.") print(
f"Run subexperiment {subexperiment_counter} of {subexperiments_total} with dimension value {dim_value} and {replicas} replicas.")
subexperiment_config = SubexperimentConfig(config.use_case, config.exp_id, subexperiment_counter, dim_value, replicas, config.partitions, config.cpu_limit, config.memory_limit, config.execution_minutes, config.prometheus_base_url, config.reset, config.namespace, config.result_path, config.configurations) subexperiment_config = SubexperimentConfig(
config.use_case, config.exp_id, subexperiment_counter, dim_value,
replicas, config.partitions, config.cpu_limit, config.memory_limit,
config.execution_minutes, config.prometheus_base_url, config.reset,
config.namespace, config.result_path, config.configurations)
config.subexperiment_executor.execute(subexperiment_config) config.subexperiment_executor.execute(subexperiment_config)
result = config.subexperiment_evaluator.execute(subexperiment_config) == 1 success = config.subexperiment_evaluator.execute(subexperiment_config,
if result == 1 and not new_lower_replicas_bound_found: config.threshold)
if success and not new_lower_replicas_bound_found:
new_lower_replicas_bound_found = True new_lower_replicas_bound_found = True
new_lower_replicas_bound_index = lower_replicas_bound_index new_lower_replicas_bound_index = lower_replicas_bound_index
lower_replicas_bound_index+=1 lower_replicas_bound_index += 1
return (new_lower_replicas_bound_index, subexperiment_counter) return (new_lower_replicas_bound_index, subexperiment_counter)
...@@ -14,8 +14,9 @@ def execute(config, dim_value_index, lower_replicas_bound_index, subexperiment_c ...@@ -14,8 +14,9 @@ def execute(config, dim_value_index, lower_replicas_bound_index, subexperiment_c
subexperiment_config = SubexperimentConfig(config.use_case, config.exp_id, subexperiment_counter, dim_value, replicas, config.partitions, config.cpu_limit, config.memory_limit, config.execution_minutes, config.prometheus_base_url, config.reset, config.namespace, config.result_path, config.configurations) subexperiment_config = SubexperimentConfig(config.use_case, config.exp_id, subexperiment_counter, dim_value, replicas, config.partitions, config.cpu_limit, config.memory_limit, config.execution_minutes, config.prometheus_base_url, config.reset, config.namespace, config.result_path, config.configurations)
config.subexperiment_executor.execute(subexperiment_config) config.subexperiment_executor.execute(subexperiment_config)
result = config.subexperiment_evaluator.execute(subexperiment_config) success = config.subexperiment_evaluator.execute(subexperiment_config,
if result == 1: config.threshold)
if success:
return (lower_replicas_bound_index, subexperiment_counter) return (lower_replicas_bound_index, subexperiment_counter)
else: else:
lower_replicas_bound_index+=1 lower_replicas_bound_index+=1
......
import lib.trend_slope_computer as trend_slope_computer import lib.trend_slope_computer as trend_slope_computer
import logging import logging
import os import os
import sys
THRESHOLD = 2000
WARMUP_SEC = 60 WARMUP_SEC = 60
def execute(config): def execute(config, threshold):
"""
Check the trend slope of the totallag of the subexperiment if it comes below
the threshold.
:param config: Configuration of the subexperiment.
:param threshold: The threshold the trendslope need to come below.
"""
cwd = f'{os.getcwd()}/{config.result_path}' cwd = f'{os.getcwd()}/{config.result_path}'
file = f"exp{config.exp_id}_uc{config.use_case}_{config.dim_value}_{config.replicas}_totallag.csv" file = f"exp{config.exp_id}_uc{config.use_case}_{config.dim_value}_{config.replicas}_totallag.csv"
try: try:
trend_slope = trend_slope_computer.compute(cwd, file, WARMUP_SEC, THRESHOLD) trend_slope = trend_slope_computer.compute(cwd, file, WARMUP_SEC)
except Exception as e: except Exception as e:
err_msg = 'Computing trend slope failed' err_msg = 'Computing trend slope failed'
print(err_msg) print(err_msg)
logging.exception(err_msg) logging.exception(err_msg)
print('Mark this subexperiment as not successful and continue benchmark') print('Mark this subexperiment as not successful and continue benchmark')
return 0 return False
print(f"Trend Slope: {trend_slope}") print(f"Trend Slope: {trend_slope}")
success = 0 if trend_slope > THRESHOLD else 1
return success return trend_slope < threshold
...@@ -31,8 +31,8 @@ def load_variables(): ...@@ -31,8 +31,8 @@ def load_variables():
def main(uc, loads, instances_list, partitions, cpu_limit, memory_limit, def main(uc, loads, instances_list, partitions, cpu_limit, memory_limit,
duration, domain_restriction, search_strategy, prometheus_base_url, duration, domain_restriction, search_strategy, threshold,
reset, namespace, result_path, configurations): prometheus_base_url, reset, namespace, result_path, configurations):
print( print(
f"Domain restriction of search space activated: {domain_restriction}") f"Domain restriction of search space activated: {domain_restriction}")
...@@ -107,6 +107,7 @@ def main(uc, loads, instances_list, partitions, cpu_limit, memory_limit, ...@@ -107,6 +107,7 @@ def main(uc, loads, instances_list, partitions, cpu_limit, memory_limit,
result_path=result_path, result_path=result_path,
domain_restriction_strategy=domain_restriction_strategy, domain_restriction_strategy=domain_restriction_strategy,
search_strategy=search_strategy_method, search_strategy=search_strategy_method,
threshold=threshold,
subexperiment_executor=subexperiment_executor, subexperiment_executor=subexperiment_executor,
subexperiment_evaluator=subexperiment_evaluator) subexperiment_evaluator=subexperiment_evaluator)
...@@ -119,10 +120,11 @@ if __name__ == '__main__': ...@@ -119,10 +120,11 @@ if __name__ == '__main__':
args = load_variables() args = load_variables()
if args.reset_only: if args.reset_only:
print('Only reset the cluster') print('Only reset the cluster')
run_uc.main(None, None, None, None, None, None, None, None, run_uc.main(None, None, None, None, None, None, None, None, None,
None, None, args.namespace, None, None, reset_only=True) None, args.namespace, None, None, reset_only=True)
else: else:
main(args.uc, args.loads, args.instances_list, args.partitions, main(args.uc, args.loads, args.instances_list, args.partitions,
args.cpu_limit, args.memory_limit, args.duration, args.cpu_limit, args.memory_limit, args.duration,
args.domain_restriction, args.search_strategy, args.prometheus, args.domain_restriction, args.search_strategy,
args.reset, args.namespace, args.path, args.configurations) args.threshold, args.prometheus, args.reset, args.namespace,
args.path, args.configurations)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment