Skip to content

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:

  1. Obfuscating code that doesn't need to be obfuscated (UIs, Rendering, etc.).
  2. Poorly written code (lack of value caching, redundant operations, etc.).
  3. 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:

lua
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 = 1

After Optimization:

lua
local myTable = a.b.c.d.e.f.g

myTable x = 1
myTable y = 2
myTable z = 1

While 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.Wait intervals.
  • 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/__newindex methods.
  • Loops/therads that run repeatedly and use short wait intervals.
  • 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:

lua
RunService.RenderStepped:Connect(LPH_NO_VIRTUALIZE(function(delta)
	......
end))
lua
Citizen.CreateThread(LPH_NO_VIRTUALIZE(function(...)
	while true do
		......
	end
end))
lua
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:

lua
-- 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))
lua
-- 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!