Skip to content

⚡ Optimize Citra config updates to single-pass parsing#28

Open
Ven0m0 wants to merge 4 commits intomainfrom
perf-citra-config-update-8098694276299336411
Open

⚡ Optimize Citra config updates to single-pass parsing#28
Ven0m0 wants to merge 4 commits intomainfrom
perf-citra-config-update-8098694276299336411

Conversation

@Ven0m0
Copy link
Owner

@Ven0m0 Ven0m0 commented Feb 5, 2026

💡 What:

  • Replaced the SetKey function (which performed a full regex scan and replace for each key update) with a new UpdateConfig function.
  • UpdateConfig parses the configuration file line-by-line in a single pass, updating values from an associative array map.
  • Refactored ApplyPreset to batch all key updates into a map and call UpdateConfig once.
  • Removed unused SetKey and RegExEscape helper functions.

🎯 Why:

  • The previous implementation had O(K * N) complexity, where K is the number of keys to update and N is the file size. For ApplyPreset, this meant scanning the full qt-config.ini file 8-10 times sequentially.
  • The new implementation has O(N) complexity, scanning the file only once regardless of the number of keys updated.

📊 Measured Improvement:

  • Theoretical Analysis: Reduced algorithmic complexity from O(K * N) to O(N).
  • Benchmark: Runtime benchmarking was skipped due to environment limitations, but the algorithmic improvement is definitive.

PR created automatically by Jules for task 8098694276299336411 started by @Ven0m0

…of O(K*N) sequential regex replacements.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@google-labs-jules
Copy link

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI review requested due to automatic review settings February 5, 2026 07:03
@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@gemini-code-assist
Copy link

Summary of Changes

Hello @Ven0m0, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly optimizes the process of updating Citra configuration files. The previous method involved iterating through the entire configuration file for each individual setting change, leading to quadratic time complexity. The new implementation introduces a single-pass parsing mechanism that processes all desired updates simultaneously, drastically reducing the computational overhead and improving the responsiveness of configuration management, particularly when applying game-specific presets.

Highlights

  • Performance Optimization: Replaced the inefficient O(K * N) SetKey function with a new UpdateConfig function that offers O(N) complexity for configuration updates. This significantly improves performance by parsing the configuration file in a single pass.
  • New UpdateConfig Function: Introduced UpdateConfig which processes configuration updates line-by-line, efficiently updating existing keys and appending new ones from a batch of changes.
  • Refactored ApplyPreset: The ApplyPreset function was refactored to collect all configuration changes into an associative array and then apply them in a single call to the new UpdateConfig function, rather than making multiple sequential updates.
  • Code Cleanup: Removed the unused SetKey and RegExEscape helper functions, simplifying the codebase.
Changelog
  • Other/Citra_mods/Citra_3DS_Manager.ahk
    • Added a new UpdateConfig function to handle configuration file updates in a single pass, accepting content and an associative array of updates.
    • Removed the RegExEscape helper function as it is no longer needed.
    • Removed the SetKey function, which was replaced by the new UpdateConfig approach.
    • Modified the ApplyPreset function to collect all configuration changes into an updates map and then call UpdateConfig once to apply them.
Activity
  • PR created automatically by Jules for task 8098694276299336411, initiated by @Ven0m0.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a significant performance optimization by refactoring the configuration update logic. Instead of repeatedly scanning the configuration file for each key, the new UpdateConfig function processes the file in a single pass, which is a great improvement from O(K*N) to O(N) complexity. The changes in ApplyPreset to batch updates are clean and effectively leverage the new function. I have one minor suggestion to improve the robustness of the new parsing logic.

line := A_LoopField
pos := InStr(line, "=")
if (pos > 1){
keyCandidate := RTrim(SubStr(line, 1, pos-1))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using RTrim here only removes whitespace from the right side of the key. If a key in the configuration file has leading whitespace (e.g., key = value), it will be parsed incorrectly as " key", and the update for "key" will be missed. Using Trim instead will handle both leading and trailing whitespace, making the parsing more robust to formatting variations in the config file.

       keyCandidate := Trim(SubStr(line, 1, pos-1))

…stall.

- Removed `--version=1.1.37.02` from `autohotkey.portable` install as it is no longer available in Chocolatey repos.
- Removed `--version=2.0.19` from `autohotkey` install for consistency and to prevent similar future failures.
- This allows the workflow to install the latest available versions.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR optimizes the Citra configuration update mechanism by replacing a multi-scan approach with a single-pass parser. The previous implementation scanned the config file once for each key update (O(K*N) complexity), while the new implementation parses the file once regardless of the number of keys being updated (O(N) complexity).

Changes:

  • Replaced SetKey and RegExEscape functions with a new UpdateConfig function that performs single-pass parsing
  • Refactored ApplyPreset to build an updates map and apply all changes in one operation
  • Removed unused helper functions

Comment on lines +65 to +70
keyCandidate := RTrim(SubStr(line, 1, pos-1))
if (remaining.HasKey(keyCandidate)){
val := remaining[keyCandidate]
line := keyCandidate "=" val
remaining.Delete(keyCandidate)
}
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation is inconsistent in this block. Lines 65, 67, 68, and 69 use extra spaces instead of the standard 2-space indentation pattern used throughout the file. This should be corrected to match the surrounding code's indentation style.

Suggested change
keyCandidate := RTrim(SubStr(line, 1, pos-1))
if (remaining.HasKey(keyCandidate)){
val := remaining[keyCandidate]
line := keyCandidate "=" val
remaining.Delete(keyCandidate)
}
keyCandidate := RTrim(SubStr(line, 1, pos-1))
if (remaining.HasKey(keyCandidate)){
val := remaining[keyCandidate]
line := keyCandidate "=" val
remaining.Delete(keyCandidate)
}

Copilot uses AI. Check for mistakes.
Comment on lines +67 to +68
val := remaining[keyCandidate]
line := keyCandidate "=" val
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value retrieved from the updates map is not trimmed before being written to the config line. While the key is trimmed using RTrim on line 65, the value could potentially have leading or trailing whitespace that should be handled consistently. Consider whether values should also be trimmed, or if this is intentional to preserve exact values from the updates map.

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +72
Loop, Parse, content, `n, `r
{
line := A_LoopField
pos := InStr(line, "=")
if (pos > 1){
keyCandidate := RTrim(SubStr(line, 1, pos-1))
if (remaining.HasKey(keyCandidate)){
val := remaining[keyCandidate]
line := keyCandidate "=" val
remaining.Delete(keyCandidate)
}
}
newContent .= line "`n"
Copy link

Copilot AI Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Loop Parse delimiter n with r stripped will normalize line endings to LF only (Unix-style), but the function then appends "n" (LF) to each line. This means the output will have LF line endings regardless of what the input file had. If the original qt-config.ini uses CRLF line endings (Windows standard), this changes the file format. Consider preserving the original line ending style or explicitly using CRLF ("r`n") for Windows compatibility, as specified in the repository's coding guidelines.

Copilot uses AI. Check for mistakes.
Ven0m0 and others added 2 commits February 5, 2026 07:09
…2 compiler is missing.

- The `autohotkey` (v2) Chocolatey package does not consistently include `Compiler\Ahk2Exe.exe` in the expected location.
- Added a check: if `$compilerV2` path does not exist, fallback to `$compilerV1` (which is installed via `autohotkey.portable` and includes `Ahk2Exe`).
- `Ahk2Exe` is capable of compiling v2 scripts (or syntax checking them) even if it comes from the v1 package, as long as the v2 interpreter is present (which it is).

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
…package.

- The hardcoded path to `Ahk2Exe.exe` in the `autohotkey.portable` package caused failures when the file was not found.
- Added a `Get-ChildItem` search to dynamically find `Ahk2Exe.exe` within the package directory.
- This ensures the correct path is used even if the package structure changes (e.g., version updates).
- Maintained fallback logic for v2 compiler to use the discovered v1 compiler if necessary.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
@openhands-ai
Copy link

openhands-ai bot commented Feb 5, 2026

Looks like there are a few issues preventing this PR from being merged!

  • GitHub Actions are failing:
    • AHK Lint & Format

If you'd like me to help, just leave a comment, like

@OpenHands please fix the failing actions on PR #28 at branch `perf-citra-config-update-8098694276299336411`

Feel free to include any additional details that might help me get this PR into a better state.

You can manage your notification settings

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant