diff --git a/main.py b/main.py index 6df2154..d2a512a 100755 --- a/main.py +++ b/main.py @@ -274,6 +274,27 @@ async def get_cpu_core_info(self): "core_types": {}, } + async def get_cpu_topology_for_ui(self): + """获取CPU拓扑信息(供前端核心选择UI使用)""" + try: + return cpuManager.get_cpu_topology_for_ui() + except Exception as e: + logger.error(f"获取CPU拓扑信息失败: {e}", exc_info=True) + return { + "cores": [], + "core_types": [], + "is_heterogeneous": False, + } + + async def set_cpu_online_list(self, online_list: list): + """按逻辑核心列表设置CPU在线状态""" + try: + logger.info(f"设置CPU在线列表: {online_list}") + return cpuManager.set_cpu_online_list(online_list) + except Exception as e: + logger.error(f"设置CPU在线列表失败: {e}", exc_info=True) + return False + async def receive_suspendEvent(self): try: return True diff --git a/py_modules/cpu.py b/py_modules/cpu.py index 11a2e12..a14f826 100755 --- a/py_modules/cpu.py +++ b/py_modules/cpu.py @@ -1839,6 +1839,103 @@ def _get_core_type_freq_range( return (min_freq if min_freq > 0 else 0, max_freq if max_freq > 0 else 0) + def set_cpu_online_list(self, online_list: List[int]) -> bool: + """按指定的逻辑核心列表设置在线状态 + + Args: + online_list: 需要在线的逻辑核心ID列表 + + Returns: + bool: True如果设置成功,否则False + """ + try: + online_set = set(online_list) + # cpu0 always stays online + online_set.add(0) + + if len(online_set) == 0: + logger.error("set_cpu_online_list: online_list is empty") + return False + + all_logical_ids = self.cpu_topology.get_all_logical_ids() + logger.info( + f"set_cpu_online_list: online={sorted(online_set)}, " + f"total={len(all_logical_ids)}" + ) + + for logical_id in all_logical_ids: + if logical_id in online_set: + self.online_cpu(logical_id) + else: + self.offline_cpu(logical_id) + + self.enable_cpu_num = len(online_set) + return True + except Exception: + logger.error( + "Failed to set CPU online list", exc_info=True + ) + return False + + def get_cpu_topology_for_ui(self) -> Dict: + """返回前端核心选择 UI 所需的拓扑数据 + + Returns: + Dict: { + "cores": [{ + "logical_id": int, + "core_id": int, + "core_type": str, + "is_smt_thread": bool, + "can_offline": bool + }, ...], + "core_types": [str, ...], + "is_heterogeneous": bool + } + """ + result = { + "cores": [], + "core_types": [], + "is_heterogeneous": self.is_heterogeneous_cpu(), + } + + if not self.cpu_topology: + return result + + logical_by_core = self.cpu_topology.get_logical_ids_by_physical_core() + + core_type_mapping = {} + if hasattr(self, "hw_analysis") and self.hw_analysis: + core_type_mapping = self.hw_analysis.get("core_type_mapping", {}) + + core_type_order = list(core_type_mapping.keys()) if core_type_mapping else [] + result["core_types"] = core_type_order + + logical_to_core_type = {} + for core_type, cpu_list in core_type_mapping.items(): + for cpu_id in cpu_list: + logical_to_core_type[cpu_id] = core_type + + primary_threads = set() + for core_id, logical_ids in logical_by_core.items(): + if logical_ids: + primary_threads.add(min(logical_ids)) + + for logical_id, core_info in sorted(self.cpu_topology.cores.items()): + core_type = logical_to_core_type.get(logical_id, "Unknown") + is_smt = logical_id not in primary_threads + can_offline = logical_id != 0 + + result["cores"].append({ + "logical_id": logical_id, + "core_id": core_info.core_id, + "core_type": core_type, + "is_smt_thread": is_smt, + "can_offline": can_offline, + }) + + return result + def get_cpu_core_info(self) -> Dict: """获取CPU核心类型详细信息 diff --git a/src/components/cpu.tsx b/src/components/cpu.tsx index 80b3834..1d955e0 100755 --- a/src/components/cpu.tsx +++ b/src/components/cpu.tsx @@ -4,8 +4,10 @@ import { ToggleField, DropdownItem, ButtonItem, + Focusable, + Field, } from "@decky/ui"; -import { useEffect, useState, FC, useMemo } from "react"; +import { useEffect, useState, FC, useMemo, useCallback } from "react"; import { Settings, Backend, @@ -17,7 +19,8 @@ import { import { localizeStrEnum, localizationManager } from "../i18n"; import { SlowSliderField } from "./SlowSliderField"; import { CustomTDPComponent } from "."; -import { RiArrowDownSFill, RiArrowUpSFill } from "react-icons/ri"; +import { RiArrowDownSFill, RiArrowUpSFill, RiLockFill } from "react-icons/ri"; +import { CPULogicalCoreUI, CPUTopologyForUI } from "../types"; const CPUBoostComponent: FC = () => { const [cpuboost, setCPUBoost] = useState(Settings.appCpuboost()); @@ -728,6 +731,224 @@ const CPURyzenadjUndervoltComponent: FC = () => { ); }; +const CELL_SIZE = 32; +const CELL_GAP = 8; +const CELL_ROW_GAP = 4; + +const CoreCell: FC<{ + key?: React.Key; + core: CPULogicalCoreUI; + isOnline: boolean; + onToggle: (logicalId: number) => void; +}> = ({ core, isOnline, onToggle }) => { + const locked = !core.can_offline && isOnline; + + return ( + // @ts-ignore + { + if (!locked) onToggle(core.logical_id); + }} + noFocusRing={true} + focusClassName="core-cell-focused" + style={{ + width: `${CELL_SIZE}px`, + height: `${CELL_SIZE}px`, + minWidth: `${CELL_SIZE}px`, + flexShrink: 0, + display: "flex", + alignItems: "center", + justifyContent: "center", + borderRadius: "4px", + fontSize: "11px", + fontWeight: "bold", + cursor: locked ? "not-allowed" : "pointer", + border: core.is_smt_thread ? "2px dashed" : "2px solid", + borderColor: locked + ? "rgba(180, 160, 60, 0.8)" + : isOnline + ? "rgba(59, 130, 246, 0.8)" + : "rgba(100, 100, 100, 0.5)", + backgroundColor: locked + ? "rgba(180, 160, 60, 0.25)" + : isOnline + ? "rgba(59, 130, 246, 0.35)" + : "rgba(60, 60, 60, 0.3)", + color: locked ? "#c8b840" : isOnline ? "#e0e0e0" : "#666", + opacity: core.is_smt_thread ? 0.8 : 1, + transition: "all 0.15s ease", + position: "relative", + }} + onClick={() => { + if (!locked) onToggle(core.logical_id); + }} + > + {locked ? : core.logical_id} + + ); +}; + +const CPUCoreSelectionComponent: FC = () => { + const [enabled, setEnabled] = useState( + Settings.appCoreSelectionEnabled() + ); + const topology: CPUTopologyForUI = Backend.data.getCpuTopologyForUI(); + const [selection, setSelection] = useState>(() => { + const saved = Settings.appCpuCoreSelection(); + if (saved.length > 0) return new Set(saved); + return new Set(topology.cores.map((c) => c.logical_id)); + }); + + const refresh = useCallback(() => { + setEnabled(Settings.appCoreSelectionEnabled()); + const saved = Settings.appCpuCoreSelection(); + if (saved.length > 0) { + setSelection(new Set(saved)); + } + }, []); + + useEffect(() => { + PluginManager.listenUpdateComponent( + ComponentName.CPU_CORE_SELECTION, + [ComponentName.CPU_CORE_SELECTION], + (_ComponentName, updateType) => { + if (updateType === UpdateType.UPDATE) { + refresh(); + } + } + ); + }, []); + + const coresByType = useMemo(() => { + const grouped: Record = {}; + + for (const coreType of topology.core_types) { + grouped[coreType] = { primary: [], smt: [] }; + } + if (!grouped["Unknown"]) { + grouped["Unknown"] = { primary: [], smt: [] }; + } + + for (const core of topology.cores) { + const type = core.core_type in grouped ? core.core_type : "Unknown"; + if (core.is_smt_thread) { + grouped[type].smt.push(core); + } else { + grouped[type].primary.push(core); + } + } + + return Object.entries(grouped).filter( + ([_, group]) => group.primary.length > 0 || group.smt.length > 0 + ); + }, [topology]); + + const handleToggle = useCallback( + (logicalId: number) => { + setSelection((prev) => { + const next = new Set(prev); + if (next.has(logicalId)) { + next.delete(logicalId); + next.add(0); + } else { + next.add(logicalId); + } + if (next.size === 0) next.add(0); + const arr = Array.from(next).sort((a, b) => a - b); + Settings.setCpuCoreSelection(arr); + return next; + }); + }, + [] + ); + + if (!topology.cores.length) return null; + + const gridStyle: React.CSSProperties = { + display: "flex", + flexWrap: "wrap", + columnGap: `${CELL_GAP}px`, + rowGap: `${CELL_ROW_GAP}px`, + padding: `${CELL_GAP}px 0`, + }; + + const labelStyle: React.CSSProperties = { + fontSize: "11px", + color: "#888", + marginTop: "8px", + marginBottom: "2px", + }; + + return ( +
+ + { + Settings.setCoreSelectionEnabled(val); + }} + /> + + + {enabled && ( + <> + + + {coresByType.map(([coreType, group]) => ( +
+ {topology.core_types.length > 1 && ( +
{coreType}
+ )} + {/* @ts-ignore */} + + {group.primary.map((core) => ( + + ))} + + {group.smt.length > 0 && ( + <> + {/* @ts-ignore */} + + {group.smt.map((core) => ( + + ))} + + + )} +
+ ))} +
+ + )} +
+ ); +}; + export const CPUComponent: FC<{ isTab?: boolean; }> = ({ isTab = false }) => { @@ -745,6 +966,9 @@ export const CPUComponent: FC<{ const [cpuVendor, setCpuVendor] = useState( Backend.data.getCpuVendor() ); + const [coreSelectionEnabled, setCoreSelectionEnabled] = useState( + Settings.appCoreSelectionEnabled() + ); useEffect(() => { setIsSpportSMT(Settings.appIsSupportSMT()); setCpuVendor(Backend.data.getCpuVendor()); @@ -753,7 +977,7 @@ export const CPUComponent: FC<{ const hide = (ishide: boolean) => { setShow(!ishide); }; - //listen Settings + useEffect(() => { PluginManager.listenUpdateComponent( ComponentName.CPU_ALL, @@ -771,6 +995,15 @@ export const CPUComponent: FC<{ } } ); + PluginManager.listenUpdateComponent( + ComponentName.CPU_NUM, + [ComponentName.CPU_CORE_SELECTION], + (_ComponentName, updateType) => { + if (updateType === UpdateType.UPDATE) { + setCoreSelectionEnabled(Settings.appCoreSelectionEnabled()); + } + } + ); }, []); return (
@@ -798,10 +1031,11 @@ export const CPUComponent: FC<{ {cpuVendor != "GenuineIntel" && !Backend.data.getSupportsNativeTdpLimit() && } - {isSpportSMT && } + {!coreSelectionEnabled && isSpportSMT && } - + {!coreSelectionEnabled && } + diff --git a/src/i18n/bulgarian.json b/src/i18n/bulgarian.json index bc15872..87421cc 100755 --- a/src/i18n/bulgarian.json +++ b/src/i18n/bulgarian.json @@ -103,5 +103,7 @@ "DAYS_AGO": "преди {{days}} дни", "CLICK_TO_CHECK": "Кликнете за проверка на обновления", "SETTINGS_POLLING": "Settings Protection", - "SETTINGS_POLLING_DESC": "Periodically re-apply settings to prevent override by other tools" + "SETTINGS_POLLING_DESC": "Periodically re-apply settings to prevent override by other tools", + "CORE_SELECTION": "Core Selection", + "CORE_SELECTION_DESC": "Select which CPU cores to enable/disable individually. CPU0 cannot be disabled" } \ No newline at end of file diff --git a/src/i18n/english.json b/src/i18n/english.json index d660d27..4367c5b 100755 --- a/src/i18n/english.json +++ b/src/i18n/english.json @@ -107,5 +107,7 @@ "DAYS_AGO": "{{days}} days ago", "CLICK_TO_CHECK": "Click to check for updates", "SETTINGS_POLLING": "Settings Protection", - "SETTINGS_POLLING_DESC": "Periodically re-apply settings to prevent override by other tools" + "SETTINGS_POLLING_DESC": "Periodically re-apply settings to prevent override by other tools", + "CORE_SELECTION": "Core Selection", + "CORE_SELECTION_DESC": "Select which CPU cores to enable/disable individually. CPU0 cannot be disabled" } \ No newline at end of file diff --git a/src/i18n/french.json b/src/i18n/french.json index 87fcc55..cf5cc84 100755 --- a/src/i18n/french.json +++ b/src/i18n/french.json @@ -103,5 +103,7 @@ "DAYS_AGO": "il y a {{days}} jours", "CLICK_TO_CHECK": "Cliquer pour vérifier les mises à jour", "SETTINGS_POLLING": "Protection des paramètres", - "SETTINGS_POLLING_DESC": "Réappliquer périodiquement les paramètres pour empêcher leur remplacement par d'autres outils" + "SETTINGS_POLLING_DESC": "Réappliquer périodiquement les paramètres pour empêcher leur remplacement par d'autres outils", + "CORE_SELECTION": "Sélection des cœurs", + "CORE_SELECTION_DESC": "Activer ou désactiver individuellement les cœurs logiques du CPU. CPU0 ne peut pas être désactivé" } \ No newline at end of file diff --git a/src/i18n/german.json b/src/i18n/german.json index 6ebeefd..77963cb 100755 --- a/src/i18n/german.json +++ b/src/i18n/german.json @@ -103,5 +103,7 @@ "DAYS_AGO": "vor {{days}} Tagen", "CLICK_TO_CHECK": "Klicken um nach Updates zu suchen", "SETTINGS_POLLING": "Einstellungsschutz", - "SETTINGS_POLLING_DESC": "Einstellungen regelmäßig erneut anwenden, um Überschreibung durch andere Tools zu verhindern" + "SETTINGS_POLLING_DESC": "Einstellungen regelmäßig erneut anwenden, um Überschreibung durch andere Tools zu verhindern", + "CORE_SELECTION": "Kernauswahl", + "CORE_SELECTION_DESC": "CPU-Kerne einzeln aktivieren oder deaktivieren. CPU0 kann nicht deaktiviert werden" } \ No newline at end of file diff --git a/src/i18n/italian.json b/src/i18n/italian.json index 50d6b0f..dabcc19 100755 --- a/src/i18n/italian.json +++ b/src/i18n/italian.json @@ -103,5 +103,7 @@ "DAYS_AGO": "{{days}} giorni fa", "CLICK_TO_CHECK": "Clicca per controllare gli aggiornamenti", "SETTINGS_POLLING": "Protezione impostazioni", - "SETTINGS_POLLING_DESC": "Riapplica periodicamente le impostazioni per evitare la sovrascrittura da parte di altri strumenti" + "SETTINGS_POLLING_DESC": "Riapplica periodicamente le impostazioni per evitare la sovrascrittura da parte di altri strumenti", + "CORE_SELECTION": "Selezione Core", + "CORE_SELECTION_DESC": "Attiva o disattiva singolarmente i core logici della CPU. CPU0 non può essere disattivato" } \ No newline at end of file diff --git a/src/i18n/japanese.json b/src/i18n/japanese.json index 9a0e6a3..e2dc29d 100755 --- a/src/i18n/japanese.json +++ b/src/i18n/japanese.json @@ -103,5 +103,7 @@ "DAYS_AGO": "{{days}}日前", "CLICK_TO_CHECK": "クリックして最新版を確認", "SETTINGS_POLLING": "設定保護", - "SETTINGS_POLLING_DESC": "設定を定期的に再適用し、他のツールによる上書きを防止します" + "SETTINGS_POLLING_DESC": "設定を定期的に再適用し、他のツールによる上書きを防止します", + "CORE_SELECTION": "コア選択", + "CORE_SELECTION_DESC": "CPUの論理コアを個別に有効/無効にする。CPU0は無効にできません" } \ No newline at end of file diff --git a/src/i18n/koreana.json b/src/i18n/koreana.json index 4cc063d..197be1f 100755 --- a/src/i18n/koreana.json +++ b/src/i18n/koreana.json @@ -103,5 +103,7 @@ "DAYS_AGO": "{{days}}일 전", "CLICK_TO_CHECK": "클릭하여 최신 버전 확인", "SETTINGS_POLLING": "설정 보호", - "SETTINGS_POLLING_DESC": "설정을 주기적으로 다시 적용하여 다른 도구에 의한 덮어쓰기를 방지합니다" + "SETTINGS_POLLING_DESC": "설정을 주기적으로 다시 적용하여 다른 도구에 의한 덮어쓰기를 방지합니다", + "CORE_SELECTION": "코어 선택", + "CORE_SELECTION_DESC": "CPU 논리 코어를 개별적으로 활성화/비활성화. CPU0은 비활성화할 수 없습니다" } \ No newline at end of file diff --git a/src/i18n/schinese.json b/src/i18n/schinese.json index ced822e..4795243 100755 --- a/src/i18n/schinese.json +++ b/src/i18n/schinese.json @@ -107,5 +107,7 @@ "DAYS_AGO": "{{days}}天前", "CLICK_TO_CHECK": "点击检查最新版本", "SETTINGS_POLLING": "设置保护", - "SETTINGS_POLLING_DESC": "定期重新应用设置,防止被其他工具覆盖" + "SETTINGS_POLLING_DESC": "定期重新应用设置,防止被其他工具覆盖", + "CORE_SELECTION": "核心选择", + "CORE_SELECTION_DESC": "自由选择启用或禁用的CPU逻辑核心。CPU0 无法关闭" } \ No newline at end of file diff --git a/src/i18n/tchinese.json b/src/i18n/tchinese.json index b9bdf6f..751f773 100755 --- a/src/i18n/tchinese.json +++ b/src/i18n/tchinese.json @@ -103,5 +103,7 @@ "DAYS_AGO": "{{days}}天前", "CLICK_TO_CHECK": "點擊檢查最新版本", "SETTINGS_POLLING": "設定保護", - "SETTINGS_POLLING_DESC": "定期重新套用設定,防止被其他工具覆蓋" + "SETTINGS_POLLING_DESC": "定期重新套用設定,防止被其他工具覆蓋", + "CORE_SELECTION": "核心選擇", + "CORE_SELECTION_DESC": "自由選擇啟用或禁用的CPU邏輯核心。CPU0 無法關閉" } \ No newline at end of file diff --git a/src/i18n/thai.json b/src/i18n/thai.json index 3d23a2d..4aba810 100755 --- a/src/i18n/thai.json +++ b/src/i18n/thai.json @@ -103,5 +103,7 @@ "DAYS_AGO": "{{days}} วันที่แล้ว", "CLICK_TO_CHECK": "คลิกเพื่อตรวจสอบอัปเดต", "SETTINGS_POLLING": "Settings Protection", - "SETTINGS_POLLING_DESC": "Periodically re-apply settings to prevent override by other tools" + "SETTINGS_POLLING_DESC": "Periodically re-apply settings to prevent override by other tools", + "CORE_SELECTION": "Core Selection", + "CORE_SELECTION_DESC": "Select which CPU cores to enable/disable individually. CPU0 cannot be disabled" } \ No newline at end of file diff --git a/src/types/cpu.ts b/src/types/cpu.ts index 786568a..2afa7f0 100644 --- a/src/types/cpu.ts +++ b/src/types/cpu.ts @@ -10,4 +10,18 @@ export interface CPUCoreInfo { vendor: string; architecture_summary: string; core_types: Record; -} \ No newline at end of file +} + +export interface CPULogicalCoreUI { + logical_id: number; + core_id: number; + core_type: string; + is_smt_thread: boolean; + can_offline: boolean; +} + +export interface CPUTopologyForUI { + cores: CPULogicalCoreUI[]; + core_types: string[]; + is_heterogeneous: boolean; +} diff --git a/src/util/backend.ts b/src/util/backend.ts index da5903b..87e7468 100755 --- a/src/util/backend.ts +++ b/src/util/backend.ts @@ -12,7 +12,7 @@ import { import { JsonSerializer } from "typescript-json-serializer"; import { callable } from "@decky/api"; import { Logger } from "./logger"; -import { CPUCoreInfo, CPUCoreTypeInfo, FanConfig } from "../types"; +import { CPUCoreInfo, CPUCoreTypeInfo, CPUTopologyForUI, FanConfig } from "../types"; import { getVersionCache, setVersionCache } from "./versionCache"; const serializer = new JsonSerializer(); @@ -96,6 +96,8 @@ export const stopGpuNotify = callable<[], any>("stop_gpu_notify"); export const checkFileExist = callable<[string], boolean>("check_file_exist"); export const supportsNativeGpuSlider = callable<[], boolean>("supports_native_gpu_slider"); export const supportsNativeTdpLimit = callable<[], boolean>("supports_native_tdp_limit"); +export const getCpuTopologyForUI = callable<[], CPUTopologyForUI>("get_cpu_topology_for_ui"); +export const setCpuOnlineList = callable<[number[]], boolean>("set_cpu_online_list"); const defaultCpuCoreInfo: CPUCoreInfo = { @@ -105,6 +107,12 @@ const defaultCpuCoreInfo: CPUCoreInfo = { core_types: {} as Record }; +const defaultCpuTopologyForUI: CPUTopologyForUI = { + cores: [], + core_types: [], + is_heterogeneous: false, +}; + export class BackendData { // 使用 Map 存储数据和状态 @@ -194,7 +202,8 @@ export class BackendData { availableSchedExtSchedulers: [] as string[], currentSchedExtScheduler: "" as string, supportsSMT: false as boolean, - supportsRyzenadjCoall: false as boolean + supportsRyzenadjCoall: false as boolean, + cpuTopologyForUI: defaultCpuTopologyForUI } as const; private getDefaultValue(key: string) { @@ -240,7 +249,8 @@ export class BackendData { schedExtSupport: { callable: supportsSchedExt }, availableSchedExtSchedulers: { callable: getSchedExtList }, currentSchedExtScheduler: { callable: getCurrentSchedExtScheduler }, - supportsRyzenadjCoall: { callable: checkRyzenadjCoall } + supportsRyzenadjCoall: { callable: checkRyzenadjCoall }, + cpuTopologyForUI: { callable: getCpuTopologyForUI } }; // 主初始化方法 @@ -524,6 +534,10 @@ export class Backend { } private static async handleCPUNum(): Promise { + if (Settings.appCoreSelectionEnabled()) { + await Backend.handleCoreSelection(); + return; + } const cpuNum = Settings.appCpuNum(); const smt = Settings.appSmt(); Logger.info(`handleCPUNum: cpuNum = ${cpuNum}, smt = ${smt}`); @@ -533,6 +547,14 @@ export class Backend { } } + private static async handleCoreSelection(): Promise { + const selection = Settings.appCpuCoreSelection(); + Logger.info(`handleCoreSelection: selection = ${JSON.stringify(selection)}`); + if (selection.length > 0) { + await setCpuOnlineList(selection); + } + } + private static async handleCPUBoost(): Promise { const cpuBoost = Settings.appCpuboost(); if (cpuBoost !== undefined) { @@ -826,6 +848,7 @@ export class Backend { [APPLYTYPE.SET_POWER_BATTERY, Backend.handleChargeLimit], [APPLYTYPE.SET_FAN_ALL, Backend.handleFanControl], [APPLYTYPE.SET_FANMODE, Backend.handleFanControl], + [APPLYTYPE.SET_CPU_CORE_SELECTION, Backend.handleCoreSelection], ]); public static resetFanSettings = () => { diff --git a/src/util/enum.ts b/src/util/enum.ts index 0df8fe3..adfe7aa 100755 --- a/src/util/enum.ts +++ b/src/util/enum.ts @@ -40,6 +40,7 @@ export enum APPLYTYPE { SET_CPU_FREQ_CONTROL = "SET_CPU_FREQ_CONTROL", SET_CPU_RYZENADJ_UNDERVOLT = "SET_CPU_RYZENADJ_UNDERVOLT", SET_POWER_BATTERY = "SET_POWER_BATTERY", + SET_CPU_CORE_SELECTION = "SET_CPU_CORE_SELECTION", } export enum ComponentName { @@ -56,6 +57,7 @@ export enum ComponentName { CPU_FREQ_CONTROL = "CPU_FREQ_CONTROL", CPU_SCHED_EXT = "CPU_SCHED_EXT", CPU_RYZENADJ_UNDERVOLT = "CPU_RYZENADJ_UNDERVOLT", + CPU_CORE_SELECTION = "CPU_CORE_SELECTION", EPP_LEVEL_1 = "EPP_LEVEL_1", EPP_LEVEL_2 = "EPP_LEVEL_2", EPP_LEVEL_3 = "EPP_LEVEL_3", diff --git a/src/util/settings.ts b/src/util/settings.ts index 0427134..612becb 100755 --- a/src/util/settings.ts +++ b/src/util/settings.ts @@ -69,6 +69,10 @@ export class AppSetting { ryzenadjUndervoltValue?: number; @JsonProperty() fanControlEnabled?: boolean; + @JsonProperty() + coreSelectionEnabled?: boolean; + @JsonProperty() + cpuCoreSelection?: number[]; constructor() { this.smt = true; @@ -106,6 +110,8 @@ export class AppSetting { this.enableRyzenadjUndervolt = false; this.ryzenadjUndervoltValue = 0; this.fanControlEnabled = false; + this.coreSelectionEnabled = false; + this.cpuCoreSelection = []; } deepCopy(copyTarget: AppSetting) { // this.overwrite=copyTarget.overwrite; @@ -134,6 +140,10 @@ export class AppSetting { this.enableRyzenadjUndervolt = copyTarget.enableRyzenadjUndervolt; this.ryzenadjUndervoltValue = copyTarget.ryzenadjUndervoltValue; this.fanControlEnabled = copyTarget.fanControlEnabled; + this.coreSelectionEnabled = copyTarget.coreSelectionEnabled; + this.cpuCoreSelection = copyTarget.cpuCoreSelection + ? [...copyTarget.cpuCoreSelection] + : []; } } @@ -1352,4 +1362,45 @@ export class Settings { ); } } + + public static appCoreSelectionEnabled(): boolean { + return this.ensureApp().coreSelectionEnabled || false; + } + + public static setCoreSelectionEnabled(enabled: boolean) { + const app = this.ensureApp(); + if (app.coreSelectionEnabled !== enabled) { + app.coreSelectionEnabled = enabled; + if (!enabled) { + app.cpuCoreSelection = []; + } + this.saveSettings(); + Backend.applySettings( + enabled + ? APPLYTYPE.SET_CPU_CORE_SELECTION + : APPLYTYPE.SET_CPUCORE + ); + PluginManager.updateComponent( + ComponentName.CPU_CORE_SELECTION, + UpdateType.UPDATE + ); + PluginManager.updateComponent(ComponentName.CPU_SMT, UpdateType.UPDATE); + PluginManager.updateComponent(ComponentName.CPU_NUM, UpdateType.UPDATE); + } + } + + public static appCpuCoreSelection(): number[] { + return this.ensureApp().cpuCoreSelection || []; + } + + public static setCpuCoreSelection(selection: number[]) { + const app = this.ensureApp(); + app.cpuCoreSelection = selection; + this.saveSettings(); + Backend.applySettings(APPLYTYPE.SET_CPU_CORE_SELECTION); + PluginManager.updateComponent( + ComponentName.CPU_CORE_SELECTION, + UpdateType.UPDATE + ); + } }