Back to community

Profiling FiveM Lua: from 8ms to 0.3ms by ditching one library

176 rep732 views1 min read

Long post, bear with me. Real numbers from a production server, not synthetic.

Setup

96-slot RP server, ~70 concurrent at peak, 110 resources running. Average frametime: 8.2ms, with peaks at 22ms during gunfights.

The investigation

I started with the obvious: resmon, find the worst offenders, optimize them.

Resmon showed nothing pathological — top resource was at 1.4ms. So either lots of small things, or resmon was lying.

I built a custom profiler that wraps every Citizen.CreateThread, every AddEventHandler, and every RegisterNetEvent to measure their actual wall-clock cost over a 60s window.

What I found

A "lightweight UI library" we'd been using for tooltips was registering 47 different event handlers across 12 resources. Each handler was tiny (~0.1ms), but they all chained into a central dispatch event that ran a string-comparison loop on every fire.

Net cost: 5.8ms per frame spread across 47 invisible handlers.

The fix

Replaced the entire library with 80 lines of custom code that uses stateBags + a single dispatcher.

Results

MetricBeforeAfter
Avg frametime8.2ms0.4ms
99p frametime22ms1.8ms
Crashes/week30

Lessons

  1. Resmon lies about cumulative cost across libraries
  2. Aggregate string comparisons in event handlers are deadly at scale
  3. Sometimes the right answer is "rip it out and write 80 lines yourself"

Will publish the profiler tool next week if there's interest.

88 4 commentsSign in to vote

Comments (4)

Sign in to leave a comment.
  • YES on the profiler. We need this. I'll happily test it.

    7 points
    • nyx

      Working on it. Coming next week with proper docs.

  • The "string-comparison dispatcher" pattern is the single most common perf killer I see. It's a footgun that grows with the codebase.

    5 points
  • Great writeup. I always tell people that resmon is a starting point, not a verdict.

    1 points