最近,Java世界发生了很多有趣的事情。其中一个事件是发布了第一个可用于生产的Graal VM版本。
就我个人而言,Graal长期以来一直引起我的兴趣,我一直密切关注该领域的报道和最新消息。有一次我看到了克里斯·塔林格( Chris Talinger)的一份报告。克里斯在其中讨论了Twitter如何通过使用机器学习算法调整Graal来获得显着的性能提升。我强烈希望自己尝试类似的事情。在本文中,我想分享最后发生的事情。
实验
为了实施实验,我需要:
- 新鲜的Graal VM社区版。在撰写本文时,它是20.2.0
- 用于负载测试的专用云环境
- NewRelic用于收集指标
- 测试负载生成器
- 一个Python程序和一组脚本来实现ML算法本身
,
:
, .
, :
-Dgraal.MaximumInliningSize -Dgraal.TrivialInliningSize -Dgraal.SmallCompiledLowLevelGraphSize
. ,
.
.
:
- JVM
.
Twitter . .
,
. , .
NewRelic
NewRelic REST API APP_ID API_KEY.
APP_ID — . APM.
API_KEY NewRelic.
:
{
"metric_data": {
"from": "time",
"to": "time",
"metrics_not_found": "string",
"metrics_found": "string",
"metrics": [
{
"name": "string",
"timeslices": [
{
"from": "time",
"to": "time",
"values": "hash"
}
]
}
]
}
}
:
def request_metrics(params):
app_id = "APP_ID"
url = "https://api.newrelic.com/v2/applications/"+ app_id + "/metrics/data.json"
headers = {'X-Api-Key':"API_KEY"}
response = requests.get(url, headers=headers, params=params)
return response.json()
CPU Utilzation params :
params = {
'names[]': "CPU/User/Utilization",
'values[]': "percent",
'from': timerange[0],
'to': timerange[1],
'raw': "false"
}
timerange .
def get_timeslices(response_json, value_name):
metrics = response_json['metric_data']['metrics'][0]
timeslices = metrics['timeslices']
values = []
for t in timeslices:
values.append(t['values'][value_name])
return values
— .
.
def objective_function(maximumInliningSize, trivialInliningSize, smallCompiledLowLevelGraphSize):
update_config(int(maximumInliningSize), int(trivialInliningSize), int(smallCompiledLowLevelGraphSize))
timerange = do_test()
data = get_results(timerange)
return calculate(data)
_updateconfig , . _dotest .
JVM . , .
calculate :
value = 1 / (mean(filtered_data))
pbounds = {
'maximumInliningSize': (200, 500),
'trivialInliningSize': (10, 25),
'smallCompiledLowLevelGraphSize': (200, 650)
}
,
optimizer.probe(
params={"maximumInliningSize": 300.0,
"trivialInliningSize": 10.0,
"smallCompiledLowLevelGraphSize": 300.0},
lazy=True,
)
def autotune():
pbounds = {
'maximumInliningSize': (200, 500),
'trivialInliningSize': (10, 25),
'smallCompiledLowLevelGraphSize': (200, 650)
}
optimizer = BayesianOptimization(
f=objective_function,
pbounds=pbounds,
random_state=1,
)
optimizer.probe(
params={"maximumInliningSize": 300.0,
"trivialInliningSize": 10.0,
"smallCompiledLowLevelGraphSize": 300.0},
lazy=True,
)
optimizer.maximize(
init_points=2,
n_iter=10,
)
print(optimizer.max)
_objectivefunction 12
, . , .
:
for i, res in enumerate(optimizer.res):
print("Iteration {}: \n\t{}".format(i, res))
.
Iteration 0:
{'target': 0.02612330198537095, 'params': {'maximumInliningSize': 300.0, 'smallCompiledLowLevelGraphSize': 300.0, 'trivialInliningSize': 10.0}}
Iteration 1:
{'target': 0.02666666666666667, 'params': {'maximumInliningSize': 325.1066014107722, 'smallCompiledLowLevelGraphSize': 524.1460220489712, 'trivialInliningSize': 10.001715622260173}}
...
.
, CPU Utilization Graal
:
.
CPU 4-5%.
CPU , proof of concept
.
2 Java Graal 2 . Graal JVM , Scala Kotlin.