-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgcb.lua
More file actions
233 lines (194 loc) · 7.3 KB
/
gcb.lua
File metadata and controls
233 lines (194 loc) · 7.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
-- Load version file
require("version")
-- Cache CPU info once at startup
gcb.CpuInfo = gcb.getCPUInfo()
-- Print info on startup
print(string.format("Game Core Bind - Version %d (%s)", gcb.version.Build, gcb.version.GitRev))
print(string.format("CPU: %s", gcb.CpuInfo.name))
print(string.format("CPU: Threads: %d, CCDs: %d", gcb.CpuInfo.threads, gcb.CpuInfo.numCcds))
for i, ccd in ipairs(gcb.CpuInfo.ccds) do
print(string.format(
"CPU: CCD %d - Cores: %d, Threads: %d, X3D: %s, Thread Range: %d-%d",
i - 1, ccd.cores, ccd.threads, tostring(ccd.isX3D), ccd.firstThread, ccd.lastThread
))
end
-- Process Thread binding
gcb.SET_PROCESS_THREADS_SUCCESS = 0
gcb.SET_PROCESS_THREADS_ERROR = 1
gcb.SET_PROCESS_THREADS_PERMISSION_DENIED = 2
function gcb.setProcessThreadsIfDifferent(pid, targetThreads)
local result = gcb.getProcessThreads(pid)
if result.code ~= gcb.PROCESS_GET_THREADS_SUCCESS then
if result.code == gcb.PROCESS_GET_THREADS_PERMISSION_DENIED then
print(string.format("setProcessThreadsIfDifferent: Permission denied for PID %d", pid))
return gcb.SET_PROCESS_THREADS_PERMISSION_DENIED
end
print(string.format("setProcessThreadsIfDifferent: Failed to query threads for PID %d (Code: %d)", pid, result.code))
return gcb.SET_PROCESS_THREADS_ERROR
end
local currentThreads = result.threads
local function listsDiffer(a, b)
if #a ~= #b then return true end
local lookup = {}
for _, v in ipairs(b) do lookup[v] = true end
for _, v in ipairs(a) do if not lookup[v] then return true end end
return false
end
if listsDiffer(targetThreads, currentThreads) then
print("setProcessThreadsIfDifferent: Thread affinity differs, updating...")
print("setProcessThreadsIfDifferent: Current threads: " .. table.concat(currentThreads, ", "))
print("setProcessThreadsIfDifferent: Target threads: " .. table.concat(targetThreads, ", "))
local code = gcb.bindProcessToThreads(pid, targetThreads)
if code == gcb.PROCESS_BIND_PERMISSION_DENIED then
print(string.format("setProcessThreadsIfDifferent: Permission denied for PID %d", pid))
return gcb.SET_PROCESS_THREADS_PERMISSION_DENIED
elseif code ~= gcb.PROCESS_BIND_SUCCESS then
print(string.format("setProcessThreadsIfDifferent: Failed to set affinity for PID %d, code: %d", pid, code))
return gcb.SET_PROCESS_THREADS_ERROR
end
print("setProcessThreadsIfDifferent: Affinity successfully set")
end
return gcb.SET_PROCESS_THREADS_SUCCESS
end
-- Applies thread affinity based on game settings
gcb.CoreBindingMode = {
STANDARD = "STANDARD",
X3D = "X3D",
NON_X3D = "NON-X3D"
}
gcb.SET_GAME_THREADS_SUCCESS = 0
gcb.SET_GAME_THREADS_ERROR = 1
gcb.SET_GAME_THREADS_PERMISSION_DENIED = 2
-- Applies thread affinity for a given process (pid) based on core binding settings.
-- Supports the following modes:
-- - "STANDARD": All threads across all CCDs.
-- - "X3D": Only threads from the X3D CCD.
-- - "NON-X3D": Only threads from the non-X3D CCD.
-- If the requested mode cannot be satisfied (e.g. no X3D CCD present), it falls back to "STANDARD".
function gcb.setGameThreads(pid, settings)
local mode = settings.Mode or gcb.CoreBindingMode.STANDARD
local smt = settings.SMT
local targetThreads = {}
-- Helper to add threads from a CCD
local function addThreadRange(first, last, cores, threads, includeSMT)
local threadsPerCore = threads / cores
for t = first, last do
if includeSMT or ((t - first) % threadsPerCore) == 0 then
table.insert(targetThreads, t)
end
end
end
local matched = false
-- Handle STANDARD mode: use all CCDs with SMT according to setting
if mode == gcb.CoreBindingMode.STANDARD then
for _, ccd in ipairs(gcb.CpuInfo.ccds) do
addThreadRange(ccd.firstThread, ccd.lastThread, ccd.cores, ccd.threads, smt ~= false)
end
matched = true
else
-- Try to find a matching CCD
for _, ccd in ipairs(gcb.CpuInfo.ccds) do
if (mode == gcb.CoreBindingMode.X3D and ccd.isX3D) or
(mode == gcb.CoreBindingMode.NON_X3D and not ccd.isX3D) then
addThreadRange(ccd.firstThread, ccd.lastThread, ccd.cores, ccd.threads, smt ~= false)
matched = true
break
end
end
end
-- Fallback to STANDARD if no suitable CCD was found
if not matched then
print("No suitable CCD found for mode '" .. tostring(mode) .. "', falling back to STANDARD")
for _, ccd in ipairs(gcb.CpuInfo.ccds) do
addThreadRange(ccd.firstThread, ccd.lastThread, ccd.cores, ccd.threads, smt ~= false)
end
end
if #targetThreads == 0 then
print("setGameThreads: No valid threads found, skipping")
return gcb.SET_GAME_THREADS_ERROR
end
local code = gcb.setProcessThreadsIfDifferent(pid, targetThreads)
if code == gcb.SET_PROCESS_THREADS_PERMISSION_DENIED then
return gcb.SET_GAME_THREADS_PERMISSION_DENIED
elseif code == gcb.SET_PROCESS_THREADS_SUCCESS then
return gcb.SET_GAME_THREADS_SUCCESS
else
return gcb.SET_GAME_THREADS_ERROR
end
end
-- Applies game affinity based on settings
gcb.SET_GAME_CPU_AFFINITY_SUCCESS = 0
gcb.SET_GAME_CPU_AFFINITY_ERROR = 1
gcb.SET_GAME_CPU_AFFINITY_PERMISSION_DENIED = 2
function gcb.setGameCpuAffinity(gamePid, gameName)
if not gamePid or not gameName then
print("setGameCpuAffinity: Invalid parameters")
return gcb.SET_GAME_CPU_AFFINITY_ERROR
end
local gameData = gcb.getGame(gameName)
if not gameData then
print("setGameCpuAffinity: No settings found for: " .. gameName)
return gcb.SET_GAME_CPU_AFFINITY_ERROR
end
local binding = gameData["Core-Binding"] or {}
local code = gcb.setGameThreads(gamePid, { Mode = binding.Mode or "STANDARD", SMT = binding.SMT })
if code == gcb.SET_GAME_THREADS_PERMISSION_DENIED then
return gcb.SET_GAME_CPU_AFFINITY_PERMISSION_DENIED
elseif code == gcb.SET_GAME_THREADS_SUCCESS then
return gcb.SET_GAME_CPU_AFFINITY_SUCCESS
else
return gcb.SET_GAME_CPU_AFFINITY_ERROR
end
end
-- Saves monitor states for later restoration
gcb.MonitorStates = {}
function gcb.saveMonitorStates()
gcb.MonitorStates = gcb.getMonitors()
end
function gcb.disableNonPrimaryMonitors()
local monitors = gcb.getMonitors()
for _, m in ipairs(monitors) do
if not m.isPrimary then
gcb.disableMonitor(m.device)
end
end
end
function gcb.enableNonPrimaryMonitors()
for _, m in ipairs(gcb.MonitorStates) do
if not m.isPrimary then
gcb.enableMonitor(m)
end
end
end
-- Custom LUA code file
local customFile = "custom.lua"
local customTimestamp = 0
function gcb.loadCustomLua()
local f = io.open(customFile, "r")
if f then
f:close()
dofile(customFile)
customTimestamp = gcb.getFileTimestamp(customFile)
print("Loaded " .. customFile)
end
end
function gcb.reloadCustomLuaIfChanged()
local ts = gcb.getFileTimestamp(customFile)
if ts > 0 and ts ~= customTimestamp then
print(customFile .. " changed, reloading...")
gcb.loadCustomLua()
end
end
-- Writes current Config table to config.lua
gcb.saveConfig = function()
local file = io.open("config.lua", "w")
if not file then return false end
file:write("-- This file is generated automatically by GCB. Do not edit manually.\n")
file:write("Config = {\n")
for k, v in pairs(Config) do
file:write(string.format(" %s = %s,\n", k, tostring(v)))
end
file:write("}\n")
file:close()
return true
end