diff --git a/procyon_ai/README.md b/procyon_ai/README.md
new file mode 100644
index 0000000..1c6086c
--- /dev/null
+++ b/procyon_ai/README.md
@@ -0,0 +1,21 @@
+# 3DMark
+
+Runs one of the 3DMark benchmark scenes and reads the Performance Graphics Score result from the output.
+
+## Prerequisites
+
+- Python 3.10+
+- 3DMark Professional Edition installed in default location and activated.
+- Desired benchmarks are downloaded,.
+
+## Options
+
+- `--benchmark` Specifies the benchmark to run.
+
+## Output
+
+report.json
+- `test`: The name of the selected benchmark
+- `score`: 3DMark gpu score
+- `start_time`: number representing a timestamp of the test's start time in milliseconds
+- `end_time`: number representing a timestamp of the test's end time in milliseconds
\ No newline at end of file
diff --git a/procyon_ai/config/ai_computer_vision_openvino_cpu.def b/procyon_ai/config/ai_computer_vision_openvino_cpu.def
new file mode 100644
index 0000000..d85d5bf
--- /dev/null
+++ b/procyon_ai/config/ai_computer_vision_openvino_cpu.def
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_device_type
+ CPU
+
+
+ ai_inference_precision
+ float32
+
+
+
\ No newline at end of file
diff --git a/procyon_ai/config/ai_computer_vision_openvino_gpu.def b/procyon_ai/config/ai_computer_vision_openvino_gpu.def
new file mode 100644
index 0000000..170c84d
--- /dev/null
+++ b/procyon_ai/config/ai_computer_vision_openvino_gpu.def
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_device_type
+ GPU
+
+
+ ai_inference_precision
+ float32
+
+
+
\ No newline at end of file
diff --git a/procyon_ai/config/ai_computer_vision_openvino_npu.def b/procyon_ai/config/ai_computer_vision_openvino_npu.def
new file mode 100644
index 0000000..0362298
--- /dev/null
+++ b/procyon_ai/config/ai_computer_vision_openvino_npu.def
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_device_type
+ NPU
+
+
+ ai_inference_precision
+ float32
+
+
+
\ No newline at end of file
diff --git a/procyon_ai/config/ai_computer_vision_snpe.def b/procyon_ai/config/ai_computer_vision_snpe.def
new file mode 100644
index 0000000..fcaedb2
--- /dev/null
+++ b/procyon_ai/config/ai_computer_vision_snpe.def
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_device_type
+ HTP
+
+
+ ai_inference_precision
+ integer
+
+
+
\ No newline at end of file
diff --git a/procyon_ai/config/ai_computer_vision_tensorrt.def b/procyon_ai/config/ai_computer_vision_tensorrt.def
new file mode 100644
index 0000000..4a0ad09
--- /dev/null
+++ b/procyon_ai/config/ai_computer_vision_tensorrt.def
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_inference_precision
+ float32
+
+
+ ai_device_id
+ cuda:0
+
+
+
\ No newline at end of file
diff --git a/procyon_ai/config/ai_computer_vision_winml_cpu.def b/procyon_ai/config/ai_computer_vision_winml_cpu.def
new file mode 100644
index 0000000..9422ba2
--- /dev/null
+++ b/procyon_ai/config/ai_computer_vision_winml_cpu.def
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_device_type
+ CPU
+
+
+ ai_inference_precision
+ float32
+
+
+ ai_device_id
+
+
+
+
\ No newline at end of file
diff --git a/procyon_ai/config/ai_computer_vision_winml_gpu.def b/procyon_ai/config/ai_computer_vision_winml_gpu.def
new file mode 100644
index 0000000..8d50b27
--- /dev/null
+++ b/procyon_ai/config/ai_computer_vision_winml_gpu.def
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_device_type
+ GPU
+
+
+ ai_inference_precision
+ float32
+
+
+ ai_device_id
+
+
+
+
\ No newline at end of file
diff --git a/procyon_ai/manifest.yaml b/procyon_ai/manifest.yaml
new file mode 100644
index 0000000..80ccc28
--- /dev/null
+++ b/procyon_ai/manifest.yaml
@@ -0,0 +1,17 @@
+friendly_name: "Procyon AI CV"
+executable: "ulprocai.py"
+process_name: "ProcyonCmd.exe"
+disable_presentmon: true
+output_dir: "run"
+options:
+ - name: engine
+ type: select
+ values:
+ - "AMD_CPU"
+ - "AMD_GPU"
+ - "Intel_CPU"
+ - "Intel_GPU"
+ - "Intel_NPU"
+ - "NVIDIA_GPU"
+ - "Qualcomm_HTP"
+ tooltip: Select which configuration to run for Procyon
\ No newline at end of file
diff --git a/procyon_ai/ulprocai.py b/procyon_ai/ulprocai.py
new file mode 100644
index 0000000..ee8b183
--- /dev/null
+++ b/procyon_ai/ulprocai.py
@@ -0,0 +1,154 @@
+"""3DMark test script"""
+from argparse import ArgumentParser
+import logging
+from pathlib import Path
+import subprocess
+import sys
+import time
+import psutil
+from utils import find_score_in_xml, is_process_running, get_install_path
+
+PARENT_DIR = str(Path(sys.path[0], ".."))
+sys.path.append(PARENT_DIR)
+
+from harness_utils.output import (
+ DEFAULT_DATE_FORMAT,
+ DEFAULT_LOGGING_FORMAT,
+ seconds_to_milliseconds,
+ setup_log_directory,
+ write_report_json
+)
+
+#####
+### Globals
+#####
+SCRIPT_DIR = Path(__file__).resolve().parent
+LOG_DIR = SCRIPT_DIR / "run"
+DIR_PROCYON = Path(get_install_path())
+EXECUTABLE = "ProcyonCmd.exe"
+ABS_EXECUTABLE_PATH = DIR_PROCYON / EXECUTABLE
+CONFIG_DIR = SCRIPT_DIR / "config"
+BENCHMARK_CONFIG = {
+ "AMD_CPU": {
+ "config": f"\"{CONFIG_DIR}\\ai_computer_vision_winml_cpu.def\"",
+ "process_name": "WinML.exe",
+ "test_name": "WinML CPU (FLOAT32)"
+ },
+ "AMD_GPU": {
+ "config": f"\"{CONFIG_DIR}\\ai_computer_vision_winml_gpu.def\"",
+ "process_name": "WinML.exe",
+ "test_name": "WinML GPU (FLOAT32)"
+ },
+ "Intel_CPU": {
+ "config": f"\"{CONFIG_DIR}\\ai_computer_vision_openvino_cpu.def\"",
+ "process_name": "OpenVino.exe",
+ "test_name": "Intel OpenVINO CPU (FLOAT32)"
+ },
+ "Intel_GPU": {
+ "config": f"\"{CONFIG_DIR}\\ai_computer_vision_openvino_gpu.def\"",
+ "process_name": "OpenVino.exe",
+ "test_name": "Intel OpenVINO GPU (FLOAT32)"
+ },
+ "Intel_NPU": {
+ "config": f"\"{CONFIG_DIR}\\ai_computer_vision_openvino_npu.def\"",
+ "process_name": "OpenVino.exe",
+ "test_name": "Intel OpenVINO NPU (FLOAT32)"
+ },
+ "NVIDIA_GPU": {
+ "config": f"\"{CONFIG_DIR}\\ai_computer_vision_tensorrt.def\"",
+ "process_name": "TensorRT.exe",
+ "test_name": "NVIDIA TensorRT (FLOAT32)"
+ },
+ "Qualcomm_HTP": {
+ "config": f"\"{CONFIG_DIR}\\ai_computer_vision_snpe.def\"",
+ "process_name": "SNPE.exe",
+ "test_name": "Qualcomm SNPE (INTEGER)"
+ },
+}
+RESULTS_FILENAME = "result.xml"
+REPORT_PATH = LOG_DIR / RESULTS_FILENAME
+
+def setup_logging():
+ """setup logging"""
+ setup_log_directory(LOG_DIR)
+ logging.basicConfig(filename=LOG_DIR / "harness.log",
+ format=DEFAULT_LOGGING_FORMAT,
+ datefmt=DEFAULT_DATE_FORMAT,
+ level=logging.DEBUG)
+ console = logging.StreamHandler()
+ formatter = logging.Formatter(DEFAULT_LOGGING_FORMAT)
+ console.setFormatter(formatter)
+ logging.getLogger('').addHandler(console)
+
+
+def get_arguments():
+ """get arguments"""
+ parser = ArgumentParser()
+ parser.add_argument(
+ "--engine", dest="engine", help="Engine test type", required=True, choices=BENCHMARK_CONFIG.keys())
+ argies = parser.parse_args()
+ return argies
+
+
+def create_procyon_command(test_option):
+ """create command string"""
+ command = f'\"{ABS_EXECUTABLE_PATH}\" --definition={test_option} --export=\"{REPORT_PATH}\"'
+ command = command.rstrip()
+ return command
+
+
+def run_benchmark(process_name, command_to_run):
+ """run the benchmark"""
+ with subprocess.Popen(command_to_run, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) as proc:
+ logging.info("Procyon AI Computer Vision benchmark has started.")
+ start_time = time.time()
+ while True:
+ now = time.time()
+ elapsed = now - start_time
+ if elapsed >= 60: #seconds
+ raise ValueError("BenchMark subprocess did not start in time")
+ process = is_process_running(process_name)
+ if process is not None:
+ process.nice(psutil.HIGH_PRIORITY_CLASS)
+ break
+ time.sleep(0.2)
+ _, _ = proc.communicate() # blocks until 3dmark exits
+ return proc
+
+try:
+ setup_logging()
+ args = get_arguments()
+ option = BENCHMARK_CONFIG[args.engine]["config"]
+ cmd = create_procyon_command(option)
+ logging.info('Starting benchmark!')
+ logging.info(cmd)
+ start_time = time.time()
+ pr = run_benchmark(BENCHMARK_CONFIG[args.engine]["process_name"], cmd)
+
+ if pr.returncode > 0:
+ logging.error("Procyon exited with return code %d", pr.returncode)
+ sys.exit(pr.returncode)
+
+ score = find_score_in_xml()
+ if score is None:
+ logging.error("Could not find overall score!")
+ sys.exit(1)
+
+ end_time = time.time()
+ elapsed_test_time = round(end_time - start_time, 2)
+ logging.info("Benchmark took %.2f seconds", elapsed_test_time)
+ logging.info("Score was %s", score)
+
+ report = {
+ "test": BENCHMARK_CONFIG[args.engine]["test_name"],
+ "unit": "score",
+ "score": score,
+ "start_time": seconds_to_milliseconds(start_time),
+ "end_time": seconds_to_milliseconds(end_time)
+ }
+
+ write_report_json(LOG_DIR, "report.json", report)
+except Exception as e:
+ logging.error("Something went wrong running the benchmark!")
+ logging.exception(e)
+ sys.exit(1)
diff --git a/procyon_ai/utils.py b/procyon_ai/utils.py
new file mode 100644
index 0000000..72b6305
--- /dev/null
+++ b/procyon_ai/utils.py
@@ -0,0 +1,36 @@
+"""3dmark test utils"""
+from pathlib import Path
+import psutil
+import xml.etree.ElementTree as ET
+import winreg
+import re
+
+SCRIPT_DIR = Path(__file__).resolve().parent
+LOG_DIR = SCRIPT_DIR / "run"
+
+def is_process_running(process_name):
+ """check if given process is running"""
+ for process in psutil.process_iter(['pid', 'name']):
+ if process.info['name'] == process_name:
+ return process
+ return None
+
+def find_score_in_xml():
+ """Reads score from local game log"""
+ score_pattern = re.compile(r"(\d+)")
+ cfg = f"{LOG_DIR}\\result.xml"
+ score_value = 0
+ with open(cfg, encoding="utf-8") as file:
+ lines = file.readlines()
+ for line in lines:
+ score_match = score_pattern.search(line)
+ if score_match is not None:
+ score_value = score_match.group(1)
+ return score_value
+
+def get_install_path() -> str:
+ """Gets the path to the Steam installation directory from the SteamPath registry key"""
+ reg_path = r"Software\UL\Procyon"
+ reg_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, reg_path, 0, winreg.KEY_READ)
+ value, _ = winreg.QueryValueEx(reg_key, "InstallDir")
+ return value
\ No newline at end of file
diff --git a/procyon_ai_img_gen/README.md b/procyon_ai_img_gen/README.md
new file mode 100644
index 0000000..1c6086c
--- /dev/null
+++ b/procyon_ai_img_gen/README.md
@@ -0,0 +1,21 @@
+# 3DMark
+
+Runs one of the 3DMark benchmark scenes and reads the Performance Graphics Score result from the output.
+
+## Prerequisites
+
+- Python 3.10+
+- 3DMark Professional Edition installed in default location and activated.
+- Desired benchmarks are downloaded,.
+
+## Options
+
+- `--benchmark` Specifies the benchmark to run.
+
+## Output
+
+report.json
+- `test`: The name of the selected benchmark
+- `score`: 3DMark gpu score
+- `start_time`: number representing a timestamp of the test's start time in milliseconds
+- `end_time`: number representing a timestamp of the test's end time in milliseconds
\ No newline at end of file
diff --git a/procyon_ai_img_gen/config/ai_imagegeneration_sd15fp16_onnxruntime.def b/procyon_ai_img_gen/config/ai_imagegeneration_sd15fp16_onnxruntime.def
new file mode 100644
index 0000000..eb110b6
--- /dev/null
+++ b/procyon_ai_img_gen/config/ai_imagegeneration_sd15fp16_onnxruntime.def
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_engine
+ ort-directml
+
+
+ ai_device_id
+ 0
+
+
+
\ No newline at end of file
diff --git a/procyon_ai_img_gen/config/ai_imagegeneration_sd15fp16_openvino.def b/procyon_ai_img_gen/config/ai_imagegeneration_sd15fp16_openvino.def
new file mode 100644
index 0000000..d30e732
--- /dev/null
+++ b/procyon_ai_img_gen/config/ai_imagegeneration_sd15fp16_openvino.def
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_engine
+ openvino
+
+
+ ai_device_id
+ auto
+
+
+
\ No newline at end of file
diff --git a/procyon_ai_img_gen/config/ai_imagegeneration_sd15fp16_tensorrt.def b/procyon_ai_img_gen/config/ai_imagegeneration_sd15fp16_tensorrt.def
new file mode 100644
index 0000000..f49da59
--- /dev/null
+++ b/procyon_ai_img_gen/config/ai_imagegeneration_sd15fp16_tensorrt.def
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_engine
+ tensorrt
+
+
+ ai_device_id
+ cuda:0
+
+
+
\ No newline at end of file
diff --git a/procyon_ai_img_gen/config/ai_imagegeneration_sd15int8_openvino.def b/procyon_ai_img_gen/config/ai_imagegeneration_sd15int8_openvino.def
new file mode 100644
index 0000000..d369ca4
--- /dev/null
+++ b/procyon_ai_img_gen/config/ai_imagegeneration_sd15int8_openvino.def
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_engine
+ openvino
+
+
+ ai_device_id
+ auto
+
+
+ split_unet
+ false
+
+
+
\ No newline at end of file
diff --git a/procyon_ai_img_gen/config/ai_imagegeneration_sd15int8_tensorrt.def b/procyon_ai_img_gen/config/ai_imagegeneration_sd15int8_tensorrt.def
new file mode 100644
index 0000000..157fafb
--- /dev/null
+++ b/procyon_ai_img_gen/config/ai_imagegeneration_sd15int8_tensorrt.def
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_engine
+ tensorrt
+
+
+ ai_device_id
+ cuda:0
+
+
+ split_unet
+ false
+
+
+
\ No newline at end of file
diff --git a/procyon_ai_img_gen/config/ai_imagegeneration_sdxlfp16_onnxruntime.def b/procyon_ai_img_gen/config/ai_imagegeneration_sdxlfp16_onnxruntime.def
new file mode 100644
index 0000000..17f72e8
--- /dev/null
+++ b/procyon_ai_img_gen/config/ai_imagegeneration_sdxlfp16_onnxruntime.def
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_engine
+ ort-directml
+
+
+ ai_device_id
+ 0
+
+
+
\ No newline at end of file
diff --git a/procyon_ai_img_gen/config/ai_imagegeneration_sdxlfp16_openvino.def b/procyon_ai_img_gen/config/ai_imagegeneration_sdxlfp16_openvino.def
new file mode 100644
index 0000000..a925e1f
--- /dev/null
+++ b/procyon_ai_img_gen/config/ai_imagegeneration_sdxlfp16_openvino.def
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_engine
+ openvino
+
+
+ ai_device_id
+ auto
+
+
+
\ No newline at end of file
diff --git a/procyon_ai_img_gen/config/ai_imagegeneration_sdxlfp16_tensorrt.def b/procyon_ai_img_gen/config/ai_imagegeneration_sdxlfp16_tensorrt.def
new file mode 100644
index 0000000..6e1f6d5
--- /dev/null
+++ b/procyon_ai_img_gen/config/ai_imagegeneration_sdxlfp16_tensorrt.def
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ai_engine
+ tensorrt
+
+
+ ai_device_id
+ cuda:0
+
+
+
\ No newline at end of file
diff --git a/procyon_ai_img_gen/manifest.yaml b/procyon_ai_img_gen/manifest.yaml
new file mode 100644
index 0000000..2abe9c3
--- /dev/null
+++ b/procyon_ai_img_gen/manifest.yaml
@@ -0,0 +1,17 @@
+friendly_name: "Procyon AI Image Generation"
+executable: "ulprocai_img_gen.py"
+process_name: "ProcyonCmd.exe"
+disable_presentmon: true
+output_dir: "run"
+options:
+ - name: engine
+ type: select
+ values:
+ - "AMD_CPU"
+ - "AMD_GPU"
+ - "Intel_CPU"
+ - "Intel_GPU"
+ - "Intel_NPU"
+ - "NVIDIA_GPU"
+ - "Qualcomm_HTP"
+ tooltip: Select which configuration to run for Procyon
\ No newline at end of file
diff --git a/procyon_ai_img_gen/ulprocai_img_gen.py b/procyon_ai_img_gen/ulprocai_img_gen.py
new file mode 100644
index 0000000..59e22d1
--- /dev/null
+++ b/procyon_ai_img_gen/ulprocai_img_gen.py
@@ -0,0 +1,159 @@
+"""3DMark test script"""
+from argparse import ArgumentParser
+import logging
+from pathlib import Path
+import subprocess
+import sys
+import time
+import psutil
+from utils import find_score_in_xml, is_process_running, get_install_path
+
+PARENT_DIR = str(Path(sys.path[0], ".."))
+sys.path.append(PARENT_DIR)
+
+from harness_utils.output import (
+ DEFAULT_DATE_FORMAT,
+ DEFAULT_LOGGING_FORMAT,
+ seconds_to_milliseconds,
+ setup_log_directory,
+ write_report_json
+)
+
+#####
+### Globals
+#####
+SCRIPT_DIR = Path(__file__).resolve().parent
+LOG_DIR = SCRIPT_DIR / "run"
+DIR_PROCYON = Path(get_install_path())
+EXECUTABLE = "ProcyonCmd.exe"
+ABS_EXECUTABLE_PATH = DIR_PROCYON / EXECUTABLE
+CONFIG_DIR = SCRIPT_DIR / "config"
+BENCHMARK_CONFIG = {
+ "AMD_GPU_FP16": {
+ "config": f"\"{CONFIG_DIR}\\ai_imagegeneration_sd15fp16_onnxruntime.def\"",
+ "process_name": "ort-directml.exe",
+ "test_name": "ONNX Stable Diffusion FP16"
+ },
+ "AMD_GPU_XL_FP16": {
+ "config": f"\"{CONFIG_DIR}\\ai_imagegeneration_sdxlfp16_onnxruntime.def\"",
+ "process_name": "ort-directml.exe",
+ "test_name": "ONNX Stable Diffusion FP16 XL"
+ },
+ "Intel_GPU_INT8": {
+ "config": f"\"{CONFIG_DIR}\\ai_imagegeneration_sd15int8_openvino.def\"",
+ "process_name": "OpenVino.exe",
+ "test_name": "Intel OpenVINO Stable Diffusion INT8"
+ },
+ "Intel_GPU_FP16": {
+ "config": f"\"{CONFIG_DIR}\\ai_imagegeneration_sd15fp16_openvino.def\"",
+ "process_name": "OpenVino.exe",
+ "test_name": "Intel OpenVINO Stable Diffusion FP16"
+ },
+ "Intel_GPU_XL_FP16": {
+ "config": f"\"{CONFIG_DIR}\\ai_imagegeneration_sdxlfp16_openvino.def\"",
+ "process_name": "OpenVino.exe",
+ "test_name": "Intel OpenVINO Stable Diffusion FP16 XL"
+ },
+ "NVIDIA_GPU_INT8": {
+ "config": f"\"{CONFIG_DIR}\\ai_imagegeneration_sd15int8_tensorrt.def\"",
+ "process_name": "TensorRT.exe",
+ "test_name": "NVIDIA TensorRT Stable Diffusion INT8"
+ },
+ "NVIDIA_GPU_FP16": {
+ "config": f"\"{CONFIG_DIR}\\ai_imagegeneration_sd15fp16_tensorrt.def\"",
+ "process_name": "TensorRT.exe",
+ "test_name": "NVIDIA TensorRT Stable Diffusion FP16"
+ },
+ "NVIDIA_GPU_XL_FP16": {
+ "config": f"\"{CONFIG_DIR}\\ai_imagegeneration_sdxlfp16_tensorrt.def\"",
+ "process_name": "TensorRT.exe",
+ "test_name": "NVIDIA TensorRT Stable Diffusion FP16 XL"
+ }
+}
+RESULTS_FILENAME = "result.xml"
+REPORT_PATH = LOG_DIR / RESULTS_FILENAME
+
+def setup_logging():
+ """setup logging"""
+ setup_log_directory(LOG_DIR)
+ logging.basicConfig(filename=LOG_DIR / "harness.log",
+ format=DEFAULT_LOGGING_FORMAT,
+ datefmt=DEFAULT_DATE_FORMAT,
+ level=logging.DEBUG)
+ console = logging.StreamHandler()
+ formatter = logging.Formatter(DEFAULT_LOGGING_FORMAT)
+ console.setFormatter(formatter)
+ logging.getLogger('').addHandler(console)
+
+
+def get_arguments():
+ """get arguments"""
+ parser = ArgumentParser()
+ parser.add_argument(
+ "--engine", dest="engine", help="Engine test type", required=True, choices=BENCHMARK_CONFIG.keys())
+ argies = parser.parse_args()
+ return argies
+
+
+def create_procyon_command(test_option):
+ """create command string"""
+ command = f'\"{ABS_EXECUTABLE_PATH}\" --definition={test_option} --export=\"{REPORT_PATH}\"'
+ command = command.rstrip()
+ return command
+
+
+def run_benchmark(process_name, command_to_run):
+ """run the benchmark"""
+ with subprocess.Popen(command_to_run, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) as proc:
+ logging.info("Procyon AI Image Generation benchmark has started.")
+ start_time = time.time()
+ while True:
+ now = time.time()
+ elapsed = now - start_time
+ if elapsed >= 60: #seconds
+ raise ValueError("BenchMark subprocess did not start in time")
+ process = is_process_running(process_name)
+ if process is not None:
+ process.nice(psutil.HIGH_PRIORITY_CLASS)
+ break
+ time.sleep(0.2)
+ _, _ = proc.communicate() # blocks until 3dmark exits
+ return proc
+
+try:
+ setup_logging()
+ args = get_arguments()
+ option = BENCHMARK_CONFIG[args.engine]["config"]
+ cmd = create_procyon_command(option)
+ logging.info('Starting benchmark!')
+ logging.info(cmd)
+ start_time = time.time()
+ pr = run_benchmark(BENCHMARK_CONFIG[args.engine]["process_name"], cmd)
+
+ if pr.returncode > 0:
+ logging.error("Procyon exited with return code %d", pr.returncode)
+ sys.exit(pr.returncode)
+
+ score = find_score_in_xml()
+ if score is None:
+ logging.error("Could not find overall score!")
+ sys.exit(1)
+
+ end_time = time.time()
+ elapsed_test_time = round(end_time - start_time, 2)
+ logging.info("Benchmark took %.2f seconds", elapsed_test_time)
+ logging.info("Score was %s", score)
+
+ report = {
+ "test": BENCHMARK_CONFIG[args.engine]["test_name"],
+ "unit": "score",
+ "score": score,
+ "start_time": seconds_to_milliseconds(start_time),
+ "end_time": seconds_to_milliseconds(end_time)
+ }
+
+ write_report_json(LOG_DIR, "report.json", report)
+except Exception as e:
+ logging.error("Something went wrong running the benchmark!")
+ logging.exception(e)
+ sys.exit(1)
diff --git a/procyon_ai_img_gen/utils.py b/procyon_ai_img_gen/utils.py
new file mode 100644
index 0000000..642fd19
--- /dev/null
+++ b/procyon_ai_img_gen/utils.py
@@ -0,0 +1,36 @@
+"""3dmark test utils"""
+from pathlib import Path
+import psutil
+import xml.etree.ElementTree as ET
+import winreg
+import re
+
+SCRIPT_DIR = Path(__file__).resolve().parent
+LOG_DIR = SCRIPT_DIR / "run"
+
+def is_process_running(process_name):
+ """check if given process is running"""
+ for process in psutil.process_iter(['pid', 'name']):
+ if process.info['name'] == process_name:
+ return process
+ return None
+
+def find_score_in_xml():
+ """Reads score from local game log"""
+ score_pattern = re.compile(r"(\d+)")
+ cfg = f"{LOG_DIR}\\result.xml"
+ score_value = 0
+ with open(cfg, encoding="utf-8") as file:
+ lines = file.readlines()
+ for line in lines:
+ score_match = score_pattern.search(line)
+ if score_match is not None:
+ score_value = score_match.group(1)
+ return score_value
+
+def get_install_path() -> str:
+ """Gets the path to the Steam installation directory from the SteamPath registry key"""
+ reg_path = r"Software\UL\Procyon"
+ reg_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, reg_path, 0, winreg.KEY_READ)
+ value, _ = winreg.QueryValueEx(reg_key, "InstallDir")
+ return value
\ No newline at end of file