blob: 37c22db3c0ed265cf6b06946848ad248a978456c [file] [log] [blame]
#!/usr/bin/env python3
# Copyright (C) 2019 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import json
import hashlib
import sys
from config import DB, PROJECT
from common_utils import req, SCOPES
'''
Uploads the performance metrics of the Perfetto tests to StackDriver and
Firebase.
The expected format of the JSON is as follows:
{
metrics: [
{
'metric': *metric name*,
'value': *metric value*,
'unit': *either s (seconds) or b (bytes)*,
'tags': {
*tag name*: *tag value*,
...
},
'labels': {
*label name*: *label value*,
...
}
},
...
]
}
'''
STACKDRIVER_API = 'https://monitoring.googleapis.com/v3/projects/%s' % PROJECT
SCOPES.append('https://www.googleapis.com/auth/firebase.database')
SCOPES.append('https://www.googleapis.com/auth/userinfo.email')
SCOPES.append('https://www.googleapis.com/auth/monitoring.write')
def sha1(obj):
hasher = hashlib.sha1()
hasher.update(
json.dumps(obj, sort_keys=True, separators=(',', ':')).encode('utf-8'))
return hasher.hexdigest()
def metric_list_to_hash_dict(raw_metrics):
metrics = {}
for metric in raw_metrics:
key = '%s-%s' % (metric['metric'], sha1(metric['tags']))
metrics[key] = metric
return metrics
def create_stackdriver_metrics(ts, metrics):
# Chunk up metrics into 100 element chunks to comply with Stackdriver's
# restrictions on the number of metrics in a request.
metrics_list = list(metrics.values())
metric_chunks = [metrics_list[x:x + 100] for x in range(0, len(metrics), 100)]
desc_chunks = []
for chunk in metric_chunks:
desc = {'timeSeries': []}
for metric in chunk:
metric_name = metric['metric']
desc['timeSeries'] += [{
'metric': {
'type':
'custom.googleapis.com/perfetto-ci/perf/%s' % metric_name,
'labels':
dict(
list(metric.get('tags', {}).items()) +
list(metric.get('labels', {}).items())),
},
'resource': {
'type': 'global'
},
'points': [{
'interval': {
'endTime': ts
},
'value': {
'doubleValue': str(metric['value'])
}
}]
}]
desc_chunks.append(desc)
return desc_chunks
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
'--job-id',
type=str,
required=True,
help='The Perfetto CI job ID to tie this upload to')
parser.add_argument(
'metrics_file', type=str, help='File containing the metrics to upload')
args = parser.parse_args()
with open(args.metrics_file, 'r') as metrics_file:
raw_metrics = json.loads(metrics_file.read())
job = req('GET', '%s/jobs/%s.json' % (DB, args.job_id))
ts = job['time_started']
metrics = metric_list_to_hash_dict(raw_metrics['metrics'])
req('PUT', '%s/perf/%s.json' % (DB, args.job_id), body=metrics)
# Only upload Stackdriver metrics for post-submit runs.
git_ref = job['env'].get('PERFETTO_TEST_GIT_REF')
if git_ref == 'refs/heads/master':
sd_metrics_chunks = create_stackdriver_metrics(ts, metrics)
for sd_metrics in sd_metrics_chunks:
req('POST', STACKDRIVER_API + '/timeSeries', body=sd_metrics)
return 0
if __name__ == '__main__':
sys.exit(main())