Profiler Analyzer
Record a FiveM profile with profiler record and saveJSON, then read time per resource, worst frames, hitches, a flame graph and findings with fixes.
Por enquanto, esta documentação está em inglês.
The Profiler Analyzer reads the JSON file the built-in FiveM profiler saves and turns it into a report you can act on: which resources eat your frame or tick time, which frames were the worst and what ran in them, which events and threads are heavy, when hitches happened, and plain advice on what to fix. It works for both server and client recordings and runs entirely in your browser.
What it is for
resmon tells you a resource averages 0.8 ms, but not why, not when, and not what it looked like in the frame where the game stuttered. The profiler records all of that, but its raw output is hard to read. Use this tool when:
- Players report lag or rubber banding and you need to know which resource is responsible.
- The server console prints hitch warnings and you want to know whether a script caused them.
- You changed a resource and want proof that it got faster (the Compare tab).
- You want to share a short, readable summary with a script’s developer.
How to record a profile
FiveM has a profiler built in on both sides. It records every resource tick and event handler with microsecond timing, including escrowed resources. The How to record card next to the drop zone has the same commands with copy buttons for Server console and Client F8.
Server (txAdmin Live Console or the FXServer window)
profiler record 1200
profiler status
profiler saveJSON lag.jsonprofiler record 1200records 1200 ticks. The server runs 20 ticks per second, so that is one minute. Use600for a quick look.profiler statusshows whether it is still recording. It stops by itself.profiler saveJSON lag.jsonwrites the file next to yourserver.cfgwith txAdmin, or wherever FXServer was started.
Record while the server is busy. Problems that only show with players online will not show on an empty server.
Client (F8 console)
profiler record 1000
profiler status
profiler saveJSON lag.jsonStand where the game feels bad and do the laggy thing while it records. 1000 frames is 8-16 seconds depending on your FPS. The file ends up in %localappdata%\FiveM\FiveM.app\citizen\lag.json.
Client recordings store a small screenshot per frame, so they get big fast. Files of a few hundred MB are fine here.
Other profiler commands
| Command | What it does |
|---|---|
profiler record start / profiler record stop |
Record until you stop it |
profiler resource myresource 300 |
Records Lua function calls of one resource (* for all). Slower, but shows which function is heavy |
profiler view |
Opens the raw trace in Chrome DevTools for a manual look |
profiler save name |
Writes a binary file this tool cannot read. Use saveJSON |
Quick start
- Record a profile as above.
- Drop the
.jsonon the page, or press Choose a file. A gzipped.json.gzworks too. - Read the verdict at the top, then the Findings tab.
- Click the worst bars on the timeline to see exactly what ran in those frames.
No file handy? Try a sample loads a made-up server recording so you can look around. Its resource names are invented.
The report
File bar
Shows the file name, size, number of events and how long it took to read. Buttons:
| Button | What you get |
|---|---|
| Copy for Discord | A short summary that fits in one Discord message (2000 characters) |
| Report .md | <file>-report.md, the full report as Markdown |
| Timeline .png | <file>-timeline.png, a picture of the current timeline |
| Open another | Load a different file. You can also drop a new file anywhere on the page |
Verdict
A one-line status (Healthy, Some pressure, Struggling or Overloaded), a title and a sentence explaining it. Read as shows whether the file was detected as a Server or Client recording and why; switch it if the guess is wrong.
The card on the right shows:
- Scripts per tick (or frame), average: the big number.
- p95 / p99: how bad the slow ticks or frames get.
- Worst tick / frame: click it to open that frame.
- FPS, avg / 1% low on the client, or Tick interval, p99 on the server.
- Hitches, and how many of them came from scripts.
- Recorded (ticks or frames) and Length.
Timeline
One bar per tick or frame. Two views:
- Script time: what resources spent in each frame or tick.
- Tick interval (server) or Frame time (client): the time between two ticks or frames for the whole server or game.
Amber and red mark the budgets below, and guide lines show 50 ms (a whole tick) or 60 and 30 FPS. Hover a bar for the numbers and the top three resources in it. Click a bar to open that frame. Drag to zoom, Ctrl + scroll to zoom, Shift + scroll to pan. Under the chart, Worst ticks / frames lists the eight worst with their time in the recording.
When you select a resource in the Resources tab, its own time is drawn in white on top of the timeline.
Frame detail
Opens under the timeline when you click a bar or a worst-frame button. It shows:
- Scripts, Resource Manager Tick, and Until next tick (server) or Frame time with the FPS pace (client), marked heavy, over budget or hitch when they are.
- A flame chart of exactly what ran in that frame, in order, left to right. Colours mark the type: frame, resource tick, event handler, thread or function. Hover a block for its duration, start and file lines. Click a block to zoom in, Whole tick / frame to zoom out.
- On client recordings, the screenshot the game took at the end of that frame.
- Heaviest resources in this frame: click one to open it in Resources.
Use the arrows to step to the previous or next frame.
Tabs
Findings
Rules that read the numbers and point at problems, grouped as Fix first, Worth fixing and Good to know (filter with the buttons at the top). Each finding lists the evidence and a concrete fix, with Open resource and buttons that jump to the frames involved. They cover:
- Scripts taking a big part of every tick or frame.
- A resource running code every frame (the
Wait(0)loop pattern). - Heavy event handlers and heavy NUI callbacks.
- Events that fire constantly or very often.
- Spikes that repeat on a timer, and one-off big spikes.
- Resources that run many small threads.
- Hitches caused by scripts, and hitches not caused by scripts (streaming, the host, garbage collection).
- Resources with no detail (JS and C#), Lua memory that keeps growing, short recordings and unclosed scopes.
If nothing stands out you get Nothing stands out, with the tip to record during the laggy moment or on the other side (client vs server).
Resources
A sortable table of every resource:
| Column | Meaning |
|---|---|
| Share | Share of all script time in the recording |
| Avg | Average ms per frame or tick over the whole recording, the same thing resmon shows |
| Worst | Most time spent in a single frame or tick |
| Events | Time spent in event handlers |
| Calls | Number of calls |
| Active | Share of frames or ticks where it ran |
Times are exclusive: when resource A triggers an event in resource B, B’s handler counts for B, not twice. Filter by name; the table shows 60 rows until you press Show all.
Click a resource to open its detail: average, p95, worst and total time, Its worst ticks / frames, What triggered it (every tick, or which events, with calls, average, worst and total), Threads, handlers and functions with file and line numbers, and the Lua heap at the start and end when the file has it.
Flame graph
The whole recording merged by call path. The wider a block, the more total time it took. Hover for total, per tick or frame, share of all, self time and calls. Click a block to zoom in and use the path at the top to go back. Highlight a name marks every block that matches a resource or file and shows how much time the matches take in total.
Compare
Did your fix work? The loaded file is before. Drop a second recording taken after your change, ideally the same length and in the same spot, on Drop the “after” profile. You get:
- A summary: scripts per tick or frame (average and 99th percentile), worst tick or frame, average FPS on the client and hitches per minute, each marked better, worse or about the same.
- Per resource, average ms per tick / frame with before, after and the change. Green means less time after the change.
Numbers are per tick or frame, so two recordings of different length still line up. A warning shows if you compare a client recording with a server one. Remove after clears the second file.
Budgets
| Client | Server | |
|---|---|---|
| Frame or tick | 16.7 ms at 60 FPS | 50 ms (20 ticks per second) |
| Scripts get heavy at | 4 ms per frame | 25 ms per tick |
| Hitch | a frame over 50 ms | ticks over 150 ms apart (the console’s hitch warning) |
| One resource worth a look | 0.1 ms per frame, heavy from 0.5 ms | 0.5 ms per tick, heavy from 2 ms |
Script time is what resources spent in a frame or tick. Frame time and tick interval cover everything. When the gap is big but script time is small, the stall came from somewhere else, and the findings say so instead of blaming a script.
Examples
The most common finding is a loop that runs every frame even when it has nothing to do:
-- runs every frame, all the time
CreateThread(function()
while true do
Wait(0)
local coords = GetEntityCoords(PlayerPedId())
if #(coords - shopCoords) < 2.0 then
DrawMarker(2, shopCoords.x, shopCoords.y, shopCoords.z, 0, 0, 0, 0, 0, 0, 0.3, 0.3, 0.3, 255, 255, 255, 150, false, true, 2, false, nil, nil, false)
end
end
end)-- only runs every frame while the player is close
CreateThread(function()
while true do
local sleep = 1000
local coords = GetEntityCoords(PlayerPedId())
if #(coords - shopCoords) < 10.0 then
sleep = 0
DrawMarker(2, shopCoords.x, shopCoords.y, shopCoords.z, 0, 0, 0, 0, 0, 0, 0.3, 0.3, 0.3, 255, 255, 255, 150, false, true, 2, false, nil, nil, false)
end
Wait(sleep)
end
end)Record again after a change like this and drop both files into Compare.
Tips
- Record on the side where the problem is. Client FPS drops need a client recording; server hitch warnings need a server one.
- Record for long enough to catch the problem. A short recording gets a Short recording note.
- For a resource that shows as heavy but has no named threads, run
profiler resource <name> 300for function-level detail. - The profiler adds a little overhead itself, so absolute numbers run slightly high. Compare recordings made the same way.
Limitations
- The file never leaves your browser. There is no upload and no shared leaderboard.
- Only Lua threads and handlers get names. JS and C# resources show up as a total per resource.
- Files from
profiler save(binary) cannot be read; useprofiler saveJSON. - The sample file is synthetic, not a real server.
Related tools
- Server Status Checker to check the server from outside while you debug.
- FXServer artifacts in case the hitches come from a known broken server build.
- fxmanifest Generator when a finding points at how a resource is set up.
