ボア収縮器はGraalVMを飼いならす



最近、Javaの世界で多くの興味深いことが起こっています。そのようなイベントの1つは、GraalVMの最初の製品対応バージョンのリリースでした。



個人的には、Graalは私にとって長い間偽りのない興味の源であり、私はこの分野のレポートと最新のニュースを注意深くフォローしています。ある時、クリス・タリンガーの報告見ました。その中で、Chrisは、Twitterが機械学習アルゴリズムを使用してGraalを調整することにより、パフォーマンスを大幅に向上させる方法について語っています。そんなことを自分でやってみたいという強い思いがありました。この記事では、最終的に何が起こったのかを共有したいと思います。  



実験



実験を実装するには、次のものが必要でした。



  1. 新鮮なGraalVM CommunityEdition。この記事の執筆時点では、20.2.0です。
  2. 負荷テスト専用のクラウド環境
  3. メトリックを収集するためのNewRelic
  4. テスト負荷ジェネレータ
  5. MLアルゴリズム自体を実装するためのPythonプログラムと一連のスクリプト


,



A=((A1A2..。..。An

f((バツ1バツ2..。..。バツn .



:



f=1/meAn((CPUUtlzAton



, .

, :



-Dgraal.MaximumInliningSize -Dgraal.TrivialInliningSize  -Dgraal.SmallCompiledLowLevelGraphSize


. ,

.



.

:



  1. 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




— .



BayesianOptimization.



.



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.




All Articles