diff --git a/Gems/Atom/Feature/Common/Assets/Scripts/performance_metrics/timestamp_aggregator.py b/Gems/Atom/Feature/Common/Assets/Scripts/performance_metrics/timestamp_aggregator.py deleted file mode 100644 index 72d186bf86..0000000000 --- a/Gems/Atom/Feature/Common/Assets/Scripts/performance_metrics/timestamp_aggregator.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python -""" -Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. - -SPDX-License-Identifier: Apache-2.0 OR MIT -""" - -from genericpath import isdir -from argparse import ArgumentParser -import json -from pathlib import Path -import time - -# this allows us to add additional data if necessary, e.g. frame_test_timestamps.json -is_timestamp_file = lambda file: file.name.startswith('frame') and file.name.endswith('_timestamps.json') -ns_to_ms = lambda time: time / 1e6 - -def main(logs_dir): - frame_count = 0 - frame_time_total = 0 - frame_time_max = 0 - pass_stats = {} - - print(f'Analyzing frame timestamp logs in {logs_dir}') - - # go through files in alphabetical order (remove sorted() if not necessary) - for file in sorted(logs_dir.iterdir(), key=lambda file: len(file.name)): - if file.is_dir() or not is_timestamp_file(file): - continue - - data = json.loads(file.read_text()) - entries = data['ClassData']['timestampEntries'] - - frame_time = 0 - for entry in entries: - name = entry['passName'] - time_ns = entry['timestampResultInNanoseconds'] - pass_entry = pass_stats.get(name, {'max': 0, 'total': 0}) - - pass_entry['max'] = max(time_ns, pass_entry['max']) - pass_entry['total'] += time_ns - pass_stats[name] = pass_entry - - frame_time += time_ns - frame_time_total += frame_time - - frame_name = file.name.split('_')[0] - print(f'- Total time for frame {frame_name}: {ns_to_ms(frame_time)}ms') - - frame_time_max = max(frame_time, frame_time_max) - frame_count += 1 - - if frame_count < 1: - print(f'No logs were found in {base_dir}') - exit(1) - - frame_avg = frame_time_total / frame_count - print(f'Avg time across {frame_count} frames: {ns_to_ms(frame_avg)}ms') - print(f'Max frame time: {ns_to_ms(frame_time_max)}ms') - print('Pass statistics:') - for name, stat in pass_stats.items(): - avg_ms = ns_to_ms(stat['total'] / frame_count) - max_ms = ns_to_ms(stat['max']) - print(f'- {name}: {avg_ms}ms avg, {max_ms}ms max') - -if __name__ == '__main__': - parser = ArgumentParser(description='Gathers statistics from a group of pass timestamp logs') - parser.add_argument('path', help='Path to the directory containing the pass timestamp logs') - args = parser.parse_args() - - base_dir = Path(args.path) - if not base_dir.exists(): - raise FileNotFoundError('Invalid path provided') - main(base_dir) diff --git a/Tools/LyTestTools/ly_test_tools/mars/filebeat_client.py b/Tools/LyTestTools/ly_test_tools/mars/filebeat_client.py new file mode 100644 index 0000000000..a1e3cf67e2 --- /dev/null +++ b/Tools/LyTestTools/ly_test_tools/mars/filebeat_client.py @@ -0,0 +1,67 @@ +""" +Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution. + +SPDX-License-Identifier: Apache-2.0 OR MIT +""" + +import datetime +import json +import socket + + +class FilebeatExn(Exception): + pass + + +class FilebeatClient(object): + def __init__(self, logger, host="127.0.0.1", port=9000, timeout=20): + self._logger = logger.getChild("filebeat_client") + self._filebeat_host = host + self._filebeat_port = port + self._socket_timeout = timeout + self._socket = None + + self._open_socket() + + def send_event(self, payload, index, timestamp=None, pipeline="filebeat"): + if timestamp is None: + timestamp = datetime.datetime.utcnow().timestamp() + + event = { + "index": index, + "timestamp": timestamp, + "pipeline": pipeline, + "payload": json.dumps(payload) + } + + # Serialise event, add new line and encode as UTF-8 before sending to Filebeat. + data = json.dumps(event, sort_keys=True) + "\n" + data = data.encode() + + self._logger.debug(f"-> {data}") + self._send_data(data) + + def _open_socket(self): + self._logger.info(f"Connecting to Filebeat on {self._filebeat_host}:{self._filebeat_port}") + + self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._socket.settimeout(self._socket_timeout) + + try: + self._socket.connect((self._filebeat_host, self._filebeat_port)) + except (ConnectionError, socket.timeout): + raise FilebeatExn("Failed to connect to Filebeat") from None + + def _send_data(self, data): + total_sent = 0 + + while total_sent < len(data): + try: + sent = self._socket.send(data[total_sent:]) + except BrokenPipeError: + self._logger.debug("Filebeat socket closed by peer") + self._socket.close() + self._open_socket() + total_sent = 0 + else: + total_sent = total_sent + sent