
حدثت الكثير من الأشياء المثيرة للاهتمام في عالم جافا مؤخرًا. كان أحد هذه الأحداث هو إطلاق أول نسخة جاهزة للإنتاج من Graal VM.
شخصيًا ، لطالما كان Graal مصدرًا لاهتمام غير مقنع بالنسبة لي ، وأنا أتابع عن كثب التقارير وآخر الأخبار في هذا المجال. ذات مرة ، رأيت تقرير كريس تالينجر. في ذلك ، يتحدث كريس عن كيفية تمكن 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.