蟒蛇驯服Graal VM



最近,Java世界发生了很多有趣的事情。其中一个事件是发布了第一个可用于生产的Graal VM版本。



就我个人而言,Graal长期以来一直引起我的兴趣,我一直密切关注该领域的报道和最新消息。有一次我看到了克里斯·塔林格 Chris Talinger)的一份报告克里斯在其中讨论了Twitter如何通过使用机器学习算法调整Graal来获得显着的性能提升。我强烈希望自己尝试类似的事情。在本文中,我想分享最后发生的事情。  



实验



为了实施实验,我需要:



  1. 新鲜的Graal VM社区版。在撰写本文时,它是20.2.0
  2. 用于负载测试的专用云环境
  3. NewRelic用于收集指标
  4. 测试负载生成器
  5. 一个Python程序和一组脚本来实现ML算法本身


,



A=(a1,a2,..,an)

f(x1,x2,..,xn) .



:



f=1/mean(CPUUtilization)



, .

, :



-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