logfilereader: Fix RAM parser issues (#82)
* Create size helper * Replace fixed RAM units with size helper * Rename CommonErrors to CommonError Enum names should be singular * Apply black formatting
This commit is contained in:
parent
9669556a39
commit
72fd725a94
2 changed files with 83 additions and 24 deletions
|
@ -3,9 +3,10 @@ from enum import IntEnum, auto
|
|||
from typing import Optional, Union
|
||||
|
||||
from robocop_ng.helpers.disabled_ids import is_build_id_valid
|
||||
from robocop_ng.helpers.size import Size
|
||||
|
||||
|
||||
class CommonErrors(IntEnum):
|
||||
class CommonError(IntEnum):
|
||||
SHADER_CACHE_COLLISION = auto()
|
||||
DUMP_HASH = auto()
|
||||
SHADER_CACHE_CORRUPTION = auto()
|
||||
|
@ -209,24 +210,29 @@ class LogAnalyser:
|
|||
self._hardware_info[setting] = cpu_match.group(1).rstrip()
|
||||
|
||||
case "ram":
|
||||
sizes = "|".join(Size.names())
|
||||
ram_match = re.search(
|
||||
r"RAM: Total ([\d.]+) (MiB|GB) ; Available ([\d.]+) (MiB|GB)",
|
||||
rf"RAM: Total ([\d.]+) ({sizes}) ; Available ([\d.]+) ({sizes})",
|
||||
self._log_text,
|
||||
re.MULTILINE,
|
||||
)
|
||||
if ram_match is not None:
|
||||
try:
|
||||
dest_unit = Size.MiB
|
||||
|
||||
ram_available = float(ram_match.group(3))
|
||||
if ram_match.group(4) == "GB":
|
||||
ram_available *= 1024
|
||||
ram_available = Size.from_name(ram_match.group(4)).convert(
|
||||
ram_available, dest_unit
|
||||
)
|
||||
|
||||
ram_total = float(ram_match.group(1))
|
||||
if ram_match.group(2) == "GB":
|
||||
ram_total *= 1024
|
||||
ram_total = Size.from_name(ram_match.group(2)).convert(
|
||||
ram_total, dest_unit
|
||||
)
|
||||
|
||||
self._hardware_info[
|
||||
setting
|
||||
] = f"{ram_available}/{ram_total} MiB"
|
||||
] = f"{ram_available:.0f}/{ram_total:.0f} {dest_unit.name}"
|
||||
except ValueError:
|
||||
# ram_match.group(1) or ram_match.group(3) couldn't be parsed as a float.
|
||||
self._hardware_info[setting] = "Error"
|
||||
|
@ -500,36 +506,36 @@ class LogAnalyser:
|
|||
def __get_notes(self):
|
||||
for common_error in self.get_common_errors():
|
||||
match common_error:
|
||||
case CommonErrors.SHADER_CACHE_COLLISION:
|
||||
case CommonError.SHADER_CACHE_COLLISION:
|
||||
self._notes.append(
|
||||
"⚠️ Cache collision detected. Investigate possible shader cache issues"
|
||||
)
|
||||
case CommonErrors.SHADER_CACHE_CORRUPTION:
|
||||
case CommonError.SHADER_CACHE_CORRUPTION:
|
||||
self._notes.append(
|
||||
"⚠️ Cache corruption detected. Investigate possible shader cache issues"
|
||||
)
|
||||
case CommonErrors.DUMP_HASH:
|
||||
case CommonError.DUMP_HASH:
|
||||
self._notes.append(
|
||||
"⚠️ Dump error detected. Investigate possible bad game/firmware dump issues"
|
||||
)
|
||||
case CommonErrors.UPDATE_KEYS:
|
||||
case CommonError.UPDATE_KEYS:
|
||||
self._notes.append(
|
||||
"⚠️ Keys or firmware out of date, consider updating them"
|
||||
)
|
||||
case CommonErrors.FILE_PERMISSIONS:
|
||||
case CommonError.FILE_PERMISSIONS:
|
||||
self._notes.append(
|
||||
"⚠️ File permission error. Consider deleting save directory and allowing Ryujinx to make a new one"
|
||||
)
|
||||
case CommonErrors.FILE_NOT_FOUND:
|
||||
case CommonError.FILE_NOT_FOUND:
|
||||
self._notes.append(
|
||||
"⚠️ Save not found error. Consider starting game without a save file or using a new save file⚠️ Save not found error. Consider starting game without a save file or using a new save file"
|
||||
)
|
||||
case CommonErrors.MISSING_SERVICES:
|
||||
case CommonError.MISSING_SERVICES:
|
||||
if self._settings["ignore_missing_services"] == "False":
|
||||
self._notes.append(
|
||||
"⚠️ Consider enabling `Ignore Missing Services` in Ryujinx settings"
|
||||
)
|
||||
case CommonErrors.VULKAN_OUT_OF_MEMORY:
|
||||
case CommonError.VULKAN_OUT_OF_MEMORY:
|
||||
if self._settings["texture_recompression"] == "Disabled":
|
||||
self._notes.append(
|
||||
"⚠️ Consider enabling `Texture Recompression` in Ryujinx settings"
|
||||
|
@ -591,11 +597,11 @@ class LogAnalyser:
|
|||
def get_last_error(self) -> Optional[list[str]]:
|
||||
return self._log_errors[-1] if len(self._log_errors) > 0 else None
|
||||
|
||||
def get_common_errors(self) -> list[CommonErrors]:
|
||||
def get_common_errors(self) -> list[CommonError]:
|
||||
errors = []
|
||||
|
||||
if self.contains_errors(["Cache collision found"], self._log_errors):
|
||||
errors.append(CommonErrors.SHADER_CACHE_COLLISION)
|
||||
errors.append(CommonError.SHADER_CACHE_COLLISION)
|
||||
if self.contains_errors(
|
||||
[
|
||||
"ResultFsInvalidIvfcHash",
|
||||
|
@ -603,7 +609,7 @@ class LogAnalyser:
|
|||
],
|
||||
self._log_errors,
|
||||
):
|
||||
errors.append(CommonErrors.DUMP_HASH)
|
||||
errors.append(CommonError.DUMP_HASH)
|
||||
if self.contains_errors(
|
||||
[
|
||||
"Ryujinx.Graphics.Gpu.Shader.ShaderCache.Initialize()",
|
||||
|
@ -612,17 +618,17 @@ class LogAnalyser:
|
|||
],
|
||||
self._log_errors,
|
||||
):
|
||||
errors.append(CommonErrors.SHADER_CACHE_CORRUPTION)
|
||||
errors.append(CommonError.SHADER_CACHE_CORRUPTION)
|
||||
if self.contains_errors(["MissingKeyException"], self._log_errors):
|
||||
errors.append(CommonErrors.UPDATE_KEYS)
|
||||
errors.append(CommonError.UPDATE_KEYS)
|
||||
if self.contains_errors(["ResultFsPermissionDenied"], self._log_errors):
|
||||
errors.append(CommonErrors.FILE_PERMISSIONS)
|
||||
errors.append(CommonError.FILE_PERMISSIONS)
|
||||
if self.contains_errors(["ResultFsTargetNotFound"], self._log_errors):
|
||||
errors.append(CommonErrors.FILE_NOT_FOUND)
|
||||
errors.append(CommonError.FILE_NOT_FOUND)
|
||||
if self.contains_errors(["ServiceNotImplementedException"], self._log_errors):
|
||||
errors.append(CommonErrors.MISSING_SERVICES)
|
||||
errors.append(CommonError.MISSING_SERVICES)
|
||||
if self.contains_errors(["ErrorOutOfDeviceMemory"], self._log_errors):
|
||||
errors.append(CommonErrors.VULKAN_OUT_OF_MEMORY)
|
||||
errors.append(CommonError.VULKAN_OUT_OF_MEMORY)
|
||||
|
||||
return errors
|
||||
|
||||
|
|
53
robocop_ng/helpers/size.py
Normal file
53
robocop_ng/helpers/size.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
from enum import IntEnum, auto
|
||||
from typing import Self
|
||||
|
||||
|
||||
class Size(IntEnum):
|
||||
KB = auto()
|
||||
KiB = auto()
|
||||
MB = auto()
|
||||
MiB = auto()
|
||||
GB = auto()
|
||||
GiB = auto()
|
||||
|
||||
@classmethod
|
||||
def names(cls) -> list[str]:
|
||||
return [size.name for size in cls]
|
||||
|
||||
@classmethod
|
||||
def from_name(cls, name: str) -> Self:
|
||||
for size in cls:
|
||||
if size.name.lower() == name.lower():
|
||||
return size
|
||||
raise ValueError(f"No matching member found for: {name}")
|
||||
|
||||
@property
|
||||
def _is_si_unit(self) -> bool:
|
||||
return self.value % 2 != 0
|
||||
|
||||
@property
|
||||
def _unit_value(self) -> int:
|
||||
return self.value // 2 + (1 if self._is_si_unit else 0)
|
||||
|
||||
@property
|
||||
def _base_factor(self) -> int:
|
||||
return 10**3 if self._is_si_unit else 2**10
|
||||
|
||||
@property
|
||||
def _byte_factor(self) -> int:
|
||||
return (
|
||||
10 ** (3 * self._unit_value)
|
||||
if self._is_si_unit
|
||||
else 2 ** (10 * self._unit_value)
|
||||
)
|
||||
|
||||
def convert(self, value: float, fmt: Self) -> float:
|
||||
if self == fmt:
|
||||
return value
|
||||
if self._is_si_unit == fmt._is_si_unit:
|
||||
if self < fmt:
|
||||
return value / self._base_factor ** (fmt._unit_value - self._unit_value)
|
||||
else:
|
||||
return value * self._base_factor ** (self._unit_value - fmt._unit_value)
|
||||
else:
|
||||
return value * (self._byte_factor / fmt._byte_factor)
|
Loading…
Reference in a new issue