Skip to content

fix(threads): remove runaway nThreads migration and show resolved Au…#313

Merged
dishit-wednesday merged 4 commits into
mainfrom
fix-threads-resetting-auto-error2
Apr 21, 2026
Merged

fix(threads): remove runaway nThreads migration and show resolved Au…#313
dishit-wednesday merged 4 commits into
mainfrom
fix-threads-resetting-auto-error2

Conversation

@dishit-wednesday

Copy link
Copy Markdown
Collaborator

…to count

migratePersistedState was resetting any explicit nThreads=4 back to Auto on every app open, silently overriding the user's choice. Deleted the unguarded migration block.

Also resolves the Auto sentinel to its actual hardware thread count (cores <= 4 ? cores : floor(cores * 0.8)) so the settings slider shows "Auto (4)" instead of just "Auto".

Summary

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (code change that neither fixes a bug nor adds a feature)
  • Chore (build process, CI, dependency updates, etc.)

Screenshots / Screen Recordings

Android

Before After

iOS

Before After

Checklist

General

  • My code follows the project's coding style and conventions
  • I have performed a self-review of my code
  • I have added/updated comments where the logic isn't self-evident
  • My changes generate no new warnings or errors

Testing

  • I have tested on Android (physical device or emulator)
  • I have tested on iOS (physical device or simulator)
  • I have tested in light mode and dark mode
  • Existing tests pass locally (npm test)
  • I have added tests that prove my fix is effective or my feature works

React Native Specific

  • No new native module without corresponding platform implementation (Android + iOS)
  • New native modules are added to the Xcode project build target (project.pbxproj)
  • No hardcoded pixel values — uses SPACING / TYPOGRAPHY constants from the theme
  • Styles use useThemedStyles pattern (not inline or static StyleSheet.create)
  • Animations/gestures work smoothly on both platforms
  • Large lists use FlatList / FlashList (not .map() inside ScrollView)
  • No unnecessary re-renders introduced (check with React DevTools Profiler if unsure)

Performance & Models

  • Downloads / long-running tasks report progress to the UI
  • File paths are resolved correctly on both platforms (no hardcoded / vs \\)
  • Large files (models, assets) are not committed to the repository

Security

  • No secrets, API keys, or credentials are included in the code
  • User input is validated/sanitized where applicable

Related Issues

Additional Notes

…to count

migratePersistedState was resetting any explicit nThreads=4 back to Auto
on every app open, silently overriding the user's choice. Deleted the
unguarded migration block.

Also resolves the Auto sentinel to its actual hardware thread count
(cores <= 4 ? cores : floor(cores * 0.8)) so the settings slider shows
"Auto (4)" instead of just "Auto".

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

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

Copy link
Copy Markdown
Contributor

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 updates the application to display the resolved thread count when the CPU Threads setting is set to 'Auto'. It introduces state management and an effect within the useTextGenerationAdvanced hook to fetch this value from the hardware service, along with corresponding updates to the test suite. Review feedback focuses on optimizing performance and reliability by caching the static hardware information, implementing a cancellation flag for the asynchronous state update to prevent memory leaks, and fixing a logic inconsistency between the display label and the slider's fallback values.

import { useAppStore } from '../stores';
import { CacheType, INFERENCE_BACKENDS } from '../types';
import { hardwareService } from '../services/hardware';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

To avoid a visible flicker from "Auto" to "Auto (N)" on every mount of the settings screen, and to prevent redundant asynchronous calls to fetch the hardware core count (which is static for the device), consider caching the resolved thread count in a module-level variable.

Suggested change
let cachedRecommendedThreads: number | null = null;

Comment on lines +36 to +41
const [resolvedThreadCount, setResolvedThreadCount] = useState<number | null>(null);

useEffect(() => {
if (settings?.nThreads !== 0) return;
hardwareService.getRecommendedThreadCount().then(setResolvedThreadCount);
}, [settings?.nThreads]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Initialize the state with the cached value and update the cache once the recommended thread count is resolved. To prevent state updates on unmounted components or race conditions from stale renders, use a cancellation flag within the useEffect as per repository guidelines. The cache update itself can remain 'fire-and-forget' to ensure the value is available for future mounts even if the current one is cancelled.

  const [resolvedThreadCount, setResolvedThreadCount] = useState<number | null>(cachedRecommendedThreads);

  useEffect(() => {
    let isCancelled = false;
    if (settings?.nThreads !== 0 || resolvedThreadCount !== null) return;
    hardwareService.getRecommendedThreadCount().then(count => {
      cachedRecommendedThreads = count;
      if (isCancelled) return;
      setResolvedThreadCount(count);
    });
    return () => {
      isCancelled = true;
    };
  }, [settings?.nThreads, resolvedThreadCount]);
References
  1. When handling asynchronous operations in useEffect that update state, ensure to use a cancellation flag to prevent state updates on unmounted components.
  2. A 'fire-and-forget' asynchronous call is an acceptable pattern for a best-effort fallback to update a cache.

Comment thread src/hooks/useTextGenerationAdvanced.ts Outdated
const cpuThreadsDisplayValue = settings?.nThreads === 0 ? 'Auto' : String(settings?.nThreads ?? 6);
const cpuThreadsDisplayValue = settings?.nThreads === 0
? (resolvedThreadCount != null ? `Auto (${resolvedThreadCount})` : 'Auto')
: String(settings?.nThreads ?? 6);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The fallback value 6 is inconsistent with the fallback logic used for cpuThreadsSliderValue (which defaults to 1). If settings.nThreads is missing or invalid, the UI will show "6" while the slider remains at the minimum position of "1". Using cpuThreadsSliderValue as the fallback ensures the label and slider stay in sync.

Suggested change
: String(settings?.nThreads ?? 6);
: String(cpuThreadsSliderValue);

@codecov

codecov Bot commented Apr 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.89%. Comparing base (1caade1) to head (101b4f0).
⚠️ Report is 12 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #313      +/-   ##
==========================================
+ Coverage   83.85%   83.89%   +0.03%     
==========================================
  Files         224      224              
  Lines       11478    11481       +3     
  Branches     3145     3146       +1     
==========================================
+ Hits         9625     9632       +7     
+ Misses       1070     1069       -1     
+ Partials      783      780       -3     
Files with missing lines Coverage Δ
src/hooks/useTextGenerationAdvanced.ts 94.11% <100.00%> (+1.01%) ⬆️
src/stores/appStore.ts 94.17% <ø> (+1.79%) ⬆️

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

dishit-wednesday and others added 3 commits April 21, 2026 14:23
When nThreads is undefined, the display value fell back to "6" while
the slider sat at 1. Both now use cpuThreadsSliderValue as the source
of truth, keeping label and slider in sync.

Co-authored-by: Dishit <hanmadishit74@gmail.com>
Co-authored-by: Dishit hanmadishit74@gmail.com
Co-authored-by: Dishit hanmadishit74@gmail.com
@sonarqubecloud

Copy link
Copy Markdown

@dishit-wednesday dishit-wednesday merged commit d5f50a6 into main Apr 21, 2026
5 checks passed
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