最近、Javaの世界で多くの興味深いことが起こっています。そのようなイベントの1つは、GraalVMの最初の製品対応バージョンのリリースでした。
個人的には、Graalは私にとって長い間偽りのない興味の源であり、私はこの分野のレポートと最新のニュースを注意深くフォローしています。ある時、クリス・タリンガーの報告を見ました。その中で、Chrisは、Twitterが機械学習アルゴリズムを使用してGraalを調整することにより、パフォーマンスを大幅に向上させる方法について語っています。そんなことを自分でやってみたいという強い思いがありました。この記事では、最終的に何が起こったのかを共有したいと思います。
実験
実験を実装するには、次のものが必要でした。
- 新鮮なGraalVM CommunityEdition。この記事の執筆時点では、20.2.0です。
- 負荷テスト専用のクラウド環境
- メトリックを収集するためのNewRelic
- テスト負荷ジェネレータ
- MLアルゴリズム自体を実装するためのPythonプログラムと一連のスクリプト
,
:
, .
, :
-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.