Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/codspeed.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: CodSpeed

on:
push:
branches:
- "main"
pull_request:
workflow_dispatch:

permissions:
contents: read
id-token: write

jobs:
benchmarks:
name: Run benchmarks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

- name: Set up Python 3.10
uses: actions/setup-python@v6
with:
python-version: "3.10"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pytest-codspeed
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi

- name: Run benchmarks
uses: CodSpeedHQ/action@v4.5.1
with:
mode: simulation
run: pytest benchmarks/ --codspeed
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
*.log
*.claude
*CLAUDE.md
*.log
*.log
.codspeed/
.pytest_cache/
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# DLSS Updater

[![CodeQL](https://github.com/Recol/DLSS-Updater/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/Recol/DLSS-Updater/actions?query=workflow%3ACodeQL)
[![CodSpeed](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/Recol/DLSS-Updater?utm_source=badge)
![Version](./version.svg)
![Downloads](https://img.shields.io/badge/Downloads-57414-blue)
[![Buy Me A Coffee](https://img.shields.io/badge/Buy%20Me%20A%20Coffee-donate-yellow.svg)](https://buymeacoffee.com/decouk)
Expand Down
Empty file added benchmarks/__init__.py
Empty file.
150 changes: 150 additions & 0 deletions benchmarks/test_scanner_performance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
"""
Performance benchmarks for the scanner module.
Tests directory traversal and DLL detection performance.
"""
import pytest
from pathlib import Path
import tempfile
import os


@pytest.fixture
def temp_game_directory():
"""Create a temporary directory structure simulating a game directory"""
with tempfile.TemporaryDirectory() as tmpdir:
base = Path(tmpdir)

# Create a typical game directory structure
game_dirs = [
base / "Game1" / "bin",
base / "Game1" / "Engine" / "Binaries" / "Win64",
base / "Game2" / "x64",
base / "Game3" / "Game" / "Binaries",
]

for game_dir in game_dirs:
game_dir.mkdir(parents=True, exist_ok=True)

# Create some dummy DLL files
(game_dir / "nvngx_dlss.dll").touch()
(game_dir / "nvngx_dlssg.dll").touch()
(game_dir / "libxess.dll").touch()
(game_dir / "ffx_fsr2_api_x64.dll").touch()

# Create some other files to make scanning more realistic
(game_dir / "game.exe").touch()
(game_dir / "config.ini").touch()
(game_dir / "readme.txt").touch()

yield base


def test_path_traversal_performance(benchmark, temp_game_directory):
"""Benchmark directory traversal performance"""
def traverse_directory():
dll_count = 0
for root, dirs, files in os.walk(temp_game_directory):
# Skip common directories that should be excluded
dirs[:] = [d for d in dirs if d not in {'__pycache__', '.git', 'cache'}]

for file in files:
if file.lower().endswith('.dll'):
dll_count += 1
return dll_count

result = benchmark(traverse_directory)
assert result > 0 # Should find at least some DLLs
Comment thread Dismissed


def test_dll_name_filtering(benchmark):
"""Benchmark DLL name filtering performance"""
dll_names = {
'nvngx_dlss.dll', 'nvngx_dlssg.dll', 'nvngx_dlssd.dll',
'libxess.dll', 'ffx_fsr2_api_x64.dll', 'ffx_fsr2_api_dx12_x64.dll',
'amd_fidelityfx_dx12.dll', 'amd_fidelityfx_vk.dll'
}

# Simulate checking many file names
test_files = [
'nvngx_dlss.dll', 'game.exe', 'config.dll', 'nvngx_dlssg.dll',
'random.dll', 'libxess.dll', 'texture.dat', 'ffx_fsr2_api_x64.dll'
] * 100 # Multiply to make the benchmark more meaningful

def filter_dll_names():
matched = []
dll_names_lower = frozenset(d.lower() for d in dll_names)
for filename in test_files:
if filename.lower() in dll_names_lower:
matched.append(filename)
return len(matched)

result = benchmark(filter_dll_names)
assert result > 0
Comment thread Dismissed


def test_path_manipulation(benchmark):
"""Benchmark path manipulation operations"""
test_paths = [
"/path/to/game/bin/nvngx_dlss.dll",
"C:\\Games\\Steam\\steamapps\\common\\GameName\\Engine\\Binaries\\Win64\\nvngx_dlss.dll",
"/mnt/games/GOG/GameTitle/x64/libxess.dll",
] * 100

def extract_game_names():
game_names = []
for path_str in test_paths:
path = Path(path_str)
# Simple game name extraction logic
parts = path.parts
for i, part in enumerate(parts):
if part.lower() in {'common', 'steamapps', 'games', 'gog'}:
if i + 1 < len(parts):
game_names.append(parts[i + 1])
break
return len(game_names)

result = benchmark(extract_game_names)
assert result > 0
Comment thread Dismissed


def test_file_extension_check(benchmark):
"""Benchmark file extension checking performance"""
test_files = [
"nvngx_dlss.dll", "game.exe", "config.ini", "texture.dds",
"shader.hlsl", "nvngx_dlssg.dll", "readme.txt", "libxess.dll"
] * 200

def check_dll_extensions():
dll_files = []
for filename in test_files:
if filename.lower().endswith('.dll'):
dll_files.append(filename)
return len(dll_files)

result = benchmark(check_dll_extensions)
assert result > 0
Comment thread Dismissed


def test_set_membership_check(benchmark):
"""Benchmark set membership checking for skip directories"""
skip_dirs = frozenset({
'__pycache__', '.git', '.svn', '.hg', 'node_modules',
'logs', 'log', 'saves', 'save', 'screenshots', 'crash',
'crashdumps', 'dumps', 'temp', 'tmp', 'cache', '.cache',
'shader_cache', 'shadercache', 'gpucache', 'webcache'
})

test_dirs = [
'bin', 'cache', 'Engine', '__pycache__', 'Binaries',
'logs', 'x64', 'temp', 'Win64', 'shader_cache'
] * 150

def check_skip_dirs():
to_scan = []
for dirname in test_dirs:
if dirname.lower() not in skip_dirs:
to_scan.append(dirname)
return len(to_scan)

result = benchmark(check_skip_dirs)
assert result >= 0
Comment thread Dismissed
164 changes: 164 additions & 0 deletions benchmarks/test_utils_performance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
"""
Performance benchmarks for utility functions.
Tests string operations, path handling, and data processing.
"""
import pytest
from pathlib import Path


def test_string_comparison_performance(benchmark):
"""Benchmark case-insensitive string comparisons"""
game_names = ["warframe", "cyberpunk2077", "3dmark", "portal2", "halflife2"] * 50
blacklist = {"warframe", "3dmark", "benchmark"}

def check_blacklist():
matches = []
for name in game_names:
if any(bl in name.lower() for bl in blacklist):
matches.append(name)
return len(matches)

result = benchmark(check_blacklist)
assert result > 0
Comment thread Dismissed


def test_version_string_parsing(benchmark):
"""Benchmark version string parsing"""
version_strings = [
"3.10.4.0", "2.5.1.0", "4.0.2.0", "1.2.3.4",
"10.20.30.40", "0.1.2.3", "99.99.99.99"
] * 100

def parse_versions():
parsed = []
for version in version_strings:
parts = version.split('.')
# Convert to tuple of integers for comparison
version_tuple = tuple(int(p) for p in parts)
parsed.append(version_tuple)
return len(parsed)

result = benchmark(parse_versions)
assert result == len(version_strings)
Comment thread Dismissed


def test_path_normalization(benchmark):
"""Benchmark path normalization"""
paths = [
"C:\\Games\\Steam\\steamapps\\common\\Game\\bin\\nvngx_dlss.dll",
"/home/user/games/game1/lib/libxess.dll",
"D:\\Program Files\\Epic Games\\GameName\\Engine\\Binaries\\Win64\\nvngx_dlss.dll",
"/mnt/storage/games/GOG/Game2/x64/ffx_fsr2_api_x64.dll"
] * 100

def normalize_paths():
normalized = []
for path_str in paths:
# Normalize path separators and case
path = Path(path_str)
normalized.append(str(path.as_posix()))
return len(normalized)

result = benchmark(normalize_paths)
assert result == len(paths)
Comment thread Dismissed


def test_file_size_calculation(benchmark):
"""Benchmark file size calculations"""
file_sizes = [
1024 * 500, # 500 KB
1024 * 1024 * 2, # 2 MB
1024 * 1024 * 50, # 50 MB
1024 * 100, # 100 KB
] * 200

def format_file_sizes():
formatted = []
for size in file_sizes:
# Convert to human-readable format
if size < 1024:
formatted.append(f"{size} B")
elif size < 1024 * 1024:
formatted.append(f"{size / 1024:.2f} KB")
else:
formatted.append(f"{size / (1024 * 1024):.2f} MB")
return len(formatted)

result = benchmark(format_file_sizes)
assert result == len(file_sizes)
Comment thread Dismissed


def test_dll_type_mapping(benchmark):
"""Benchmark DLL type identification"""
dll_names = [
"nvngx_dlss.dll", "nvngx_dlssg.dll", "nvngx_dlssd.dll",
"libxess.dll", "ffx_fsr2_api_x64.dll", "ffx_fsr2_api_dx12_x64.dll",
"amd_fidelityfx_dx12.dll", "unknown.dll"
] * 150

dll_type_map = {
'nvngx_dlss.dll': 'DLSS',
'nvngx_dlssg.dll': 'DLSS Frame Generation',
'nvngx_dlssd.dll': 'DLSS Ray Reconstruction',
'libxess.dll': 'XeSS',
'ffx_fsr2_api_x64.dll': 'FSR 2',
'ffx_fsr2_api_dx12_x64.dll': 'FSR 2',
'amd_fidelityfx_dx12.dll': 'FidelityFX',
}

def identify_dll_types():
types = []
for dll_name in dll_names:
dll_type= dll_type_map.get(dll_name.lower(), 'Unknown')
types.append(dll_type)
return len(types)

result = benchmark(identify_dll_types)
assert result == len(dll_names)
Comment thread Dismissed


def test_list_filtering_performance(benchmark):
"""Benchmark filtering large lists"""
# Simulate filtering a large list of detected files
all_files = []
for i in range(1000):
all_files.extend([
f"game{i}.exe",
f"nvngx_dlss_{i}.dll",
f"config{i}.ini",
f"libxess_{i}.dll",
f"texture{i}.dds"
])

def filter_dll_files():
dll_files = [f for f in all_files if f.endswith('.dll')]
return len(dll_files)

result = benchmark(filter_dll_files)
assert result > 0
Comment thread Dismissed


def test_dictionary_lookup_performance(benchmark):
"""Benchmark dictionary lookups for launcher paths"""
launcher_paths = {
'steam': 'C:\\Program Files\\Steam',
'epic': 'C:\\Program Files\\Epic Games',
'gog': 'C:\\GOG Games',
'ubisoft': 'C:\\Program Files\\Ubisoft',
'ea': 'C:\\Program Files\\EA Games',
'xbox': 'C:\\Program Files\\Xbox Games',
'battlenet': 'C:\\Program Files\\Battle.net'
}

queries = ['steam', 'epic', 'gog', 'unknown', 'ubisoft', 'ea'] * 200

def lookup_paths():
found = []
for launcher in queries:
path = launcher_paths.get(launcher)
if path:
found.append(path)
return len(found)

result = benchmark(lookup_paths)
assert result > 0
Comment thread Dismissed
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ aiosqlite>=0.22.0
aiofiles>=25.1.0
scandir-rs>=2.9.3; platform_system == "Windows"
winloop>=0.1.7; platform_system == "Windows"
pytest-codspeed>=4.2.0
Loading