Performance
Obfuscation has an unavoidable impact on performance. However, there are many solutions that Luraph offers that can help boost performance and run smoothly.
Choose an Accurate Target Version
Specifying a Target Version setting instead of using Universal can help improve performance. Certain optimizations are applied when specific versions are selected and can improve loading time and runtime performance by noticeable amounts. Universal is the slowest version and does not apply as many optimizations.
Don't know what version to select? See our setting documentation!
Disable Line Information
You can disable Luraph's built-in error handling by checking the Disable Line Information box when obfuscating (or setting DISABLE_LINE_INFORMATION to true). This means that your script won't show line information on errors, but will run much faster. If you have already tested your script on Luraph and don't feel you would benefit from line information, you should check this setting. Disabling line information also lowers file size. Please note that we do not guarantee support for scripts using this setting since errors become much more difficult to analyze!
Disable GC Fixes
Using the Enable GC Fixes setting can cause severe performance loss. Unless your script has a strict dependence on the __gc metamethod or depends on precise garbage collection behavior, this option should always be disabled.
For more information on when to use Enable GC Fixes, read our setting documentation.
Optimize Code
Code optimization is extremely important when dealing with obfuscation. Most of the time, poor code performance is caused by unoptimized code. There are usually three scenarios:
- Obfuscating code that doesn't need to be obfuscated (UIs, Rendering, etc.).
- Poorly written code (lack of value caching, redundant operations, etc.).
- Obfuscating code that runs very frequently.
Redundant Obfuscation
Not all code needs to be obfuscated. Large libraries that deal with unimportant code (such as UI libraries, physics calculations, and other 2D/3D rendering & drawing) should usually be left unobfuscated. To exclude certain code from obfuscation, use the LPH_NO_VIRTUALIZE macro. This macro will still hide variable names and any comments and also greatly improve performance. To learn more about this macro, read our macro documentation.
Unoptimized Code
Due to the nature of obfuscation, poorly written code has a much greater impact on performance than it does when it is unobfuscated. Even if your script runs fine when unobfuscated, if it is poorly written it may have a much greater impact on performance.
Analyzing your code for redundancies and potential areas of optimization will greatly improve performance and lower file size. See how the following code can be optimized:
Before Optimization:
a.b.c.d.e.f.g.x = 1
a.b.c.d.e.f.g.y = 2
a.b.c.d.e.f.g.z = 1After Optimization:
local myTable = a.b.c.d.e.f.g
myTable x = 1
myTable y = 2
myTable z = 1While this optimization may not have a noticeable impact on raw source, it will greatly improve obfuscation performance. Optimizations that may seem like micro-optimizations may have a much larger impact when obfuscated due to the nature of Luraph's VM. Since Luraph is emulating Lua, one instruction may turn into dozens depending on the operation. Optimizing your code to have fewer instructions is always better.
Frequently Ran Code
Code that runs frequently (e.g. per game tick, render frame, or otherwise multiple times per second) may cause application freezes, drop FPS, reduce throughput, and increase latency even if optimized properly. But, most of the time obfuscation is not necessary on these functions. LPH_NO_VIRTUALIZE can be applied to code that runs frequently to prevent it from being obfuscated and run at full speed. However, it is up to your choice if you wish to have any code unobfuscated and only code that does not need security (such as rendering/drawing loops or intensive hash/math calculations) use this macro.
Common culprits of decreased performance:
- Any code that involves rendering/drawing per frame.
- Functions that are called/invoked repeatedly per frame.
- Loops that run repeatedly or multiple times per second.
- Large amounts of code that run frequently or repeatedly.
FiveM:
- Large amounts of threads created by
Citizen.CreateThread. - Loops/threads that run repeatedly and use short
Citizen.Waitintervals. - Event handlers that are invoked frequently.
Roblox:
- Connections to RunService events (RenderStepped, Heartbeat, etc.).
- Connections to UserInputService events (InputChanged, etc.).
- Hooks to Instance's
__index/__namecall/__newindexmethods. - Loops/therads that run repeatedly and use short
waitintervals. - Hooks to functions that are called frequently.
Improving Performance with Macros
Using LPH_NO_VIRTUALIZE (or LPH_JIT/LPH_JIT_MAX) around frequently-ran code can greatly improve performance (and maintain security when used properly). Here are some examples of using these macros:
RunService.RenderStepped:Connect(LPH_NO_VIRTUALIZE(function(delta)
......
end))Citizen.CreateThread(LPH_NO_VIRTUALIZE(function(...)
while true do
......
end
end))hookmetamethod(game, "__namecall", LPH_NO_VIRTUALIZE(function(self, ...)
......
end))If you are using LPH_NO_VIRTUALIZE on an event handler and want to obfuscate a certain event to maintain security, you can externally define it:
-- The method hook will be devirtualized to execute all events at normal speed.
-- The contents of handleKick will remain obfuscated for security.
-- Only access to 'Kick' will run obfuscated code.
local function handleKick()
......
end
hookmetamethod(game, "___index", LPH_NO_VIRTUALIZE(function(self, key)
if key == "Kick" then
return handleKick()
end
return oldIndex(self, ...)
end))-- The contents of runSecurityChecks will remain obfuscated for security.
-- Everything after runSecurityChecks() will execute at normal speed.
local function runSecurityChecks()
end
AddEventHandler("runEveryFrame", LPH_NO_VIRTUALIZE(function()
runSecurityChecks()
......
end))For more information on our macros, read our macro documentation!