[HELP] Using Microprofiler To Pinpoint Major Lag Spikes

Hello developers, I have a game that recently has been subjected to several lag spike issues. I have received countless reports and yet have little to no avail in investigating the cause.

Apologies for the slightly off-topic placement, for some reason I’m locked from posting on the platform & engine topics.

The Problem

I have used multiple opinions from experienced and trusted sources, and the best I can come up with is this screenshot here with the Microprofiler.

There seems to be some kind of “Physics” and “runJob” stalling going on causing the frame drops and server crashing.

For physics I am unsure as how to this would be possible as almost everything in my game runs as CanCollide false and Anchored true and is Tweened to whatever destination it has. Seldom does anything interact with actual physics.

As for “worker runJob”
I read a post in which Clonetrooper1019 states

To my understanding, its just the label given to the C++ backend worker threads, and isn’t specific to the problem you’re observing here. In terms of what the scope actually breaks down to, your problem seems to be that a lot of collision detections are going off at once.

And for that case, there are only about 4 scripts that actually listen to the .Touched event, and even so do not fire often or even at the time of the lag spikes.

Scripts run optimally and nothing goes above 2% activity or over the rate of 45 per second on uncommon occasions.

I could really use the help, my community and I would greatly appreciate it, thanks! :grin:

1 Like

When it’s unanchored doesn’t it rely on physics then :thinking: and not to mention your moving it aswell…

2 Likes

A typo whoops, I fixed it.

Also TweenService, if I’m not mistaken, operates so that the tweened part does not interact with physics. Or at least that is what I have experienced thus far with anchored and noncollideable objects.

Take a screen shot of all of the client memory.

Does your game use MeshParts? if so, try setting the collision fidelity for some of the more complex meshes to either Hull or Box and see if you can still reproduce the problem. This is what was happening in my game pre-release. I was going mad trying to figure out the cause of the lag spikes, scanning every line of code in the game. Then I changed all the meshes to Hull and it resolved itself.

2 Likes

It varies from Studio to actual Player, but I have never witnessed it go above 600 MB.

1 Like

It does use quite a bit of MeshParts yes. I’d say 90% of the time I make sure to use Box fidelity but I will triple check.

I’ll keep you posted, thanks.

1 Like

If you use quite a bit of MeshParts and already have many of them set to either Box or Hull, I think your problems might be less physics related and more rendering related. Try turning on Network Streaming (if that’s an option) and see how much that affects performance. I was having problems with rendering causing frame drops on mobile devices and ended up setting up my own custom chunk-loading system for my game to fix the problem. Also having RenderFidelity set to Automatic helps a ton too.

2 Likes

With the MicroProfiler, it always seems to be a game of pure chance. If you read the quote, it prefaces with to my understanding. There’s simply not enough raw information on the MicroProfiler to adequately use it to pinpoint performance issues, at all. You just have to assume based on what a label reads and take a shot in the dark while attempting to address areas of performance.

That being said, going off of the largest bars in your game, it seems that you will need to look into optimising the following (completely best guesses, I have no clue what I’m talking about):

  • Scene, Shadows: Relates to the lighting engine. Are you using ShadowMap?
  • runJob: Loops in the scheduler. This can be from while, for or RunService-bound loops.
  • Physics: Anything simulated by the physics engine. That’s all non-anchored parts, if I recall correctly. There may be other criteria to meet, though I doubt it.
  • gameStepped: Seems that Stepped needs to complete a lot of operations.
  • Stepped: Ditto. ^
  • Humanoid: Humanoids by nature are very expensive. Try reducing the cost of humanoids through various actions like disabling state types you do not need for humanoids.

Really though? Optimise, optimise, optimise. But do not micro-optimise and waste your time. Pass some small operations to the client and use the server as a medium to transfer data to other clients for rendering or whatever (provided input is checked).

By the way: if you’re doing tweens, absolutely stay away from the server if you aren’t doing so already. It’s easier on you to write it but more taxing on performance to carry it out. If a tween needs to be done, get the server to pass data to all clients and have the clients run the tweens.

2 Likes

Thank you for the detailed reply!

I am using ShadowMap lighting, it looks very nice though noticing the Scene bar I figure that it’s costly. Is this true? I would hope not as I can’t see myself switching back to Voxel or Compatibility as ShadowMap truly completes the game aesthetically.

As for Humanoids & Tweening, I have a lot of humanoids but 75% of them perform animations only and act as nothing else.

I did not know Tweening was so costly to the server. :thinking: I did a stress test when I was testing Tweening vs Humanoid:MoveTo() for pathing and tweening the characters cut the lag in half.

I feel the method for tweening you mention sounds like it could be more bad than good at least for my game.
Just one of the things that move are enemies, and they walk down a long path marked with nodes to reach the end. Sometimes they can be ‘Stunned’ which halts their pathing for a time, or sometimes other things will stop them very, very frequently. Sometimes there are up to 100 or more of these enemies. Would this not be more costly to be firing to all clients?

1 Like

If you’re already using Tweening to move them around, maybe it wouldn’t be so hard to convert your NPCs to non-Humanoid NPCs? Just a thought. For some reason, Humanoids cause huge amounts of physics lag. I also had this problem before.

See here: NPCs Causing FPS Drops

1 Like

But how would I use animations if I removed the humanoids?

I know there’s lerping and such but I would have to revamp almost everything and CFraming animations is ridiculously tedious.

Again, most of my post is based off of assumptions. I have absolutely no clue what I’m talking about, but hopefully something I said has some relevance and could potentially see improvements if picked away at. I just read the labels and made as best a guess I could.

I would assume that it is costly, considering that ShadowMap has significantly more to render especially with shadows and the control you’re given over them. I’m talking about the properties of Lighting and the ability to cast shadows from BaseParts.

That being said, ShadowMap itself probably isn’t expensive since I’ve seen games running fine with it - the expensive is probably correlated to what it needs to calculate before rendering shadows. Note how I said shadows can be rendered by BaseParts earlier - that means factoring in unions and MeshParts.

ShadowMap is in fairly early release, so I wouldn’t expect it to be the most performant lighting option available. It could be optimised down the road, but for now, developers need to help themselves to this optimisation by also ensuring that the lighting engine isn’t rendering too much at once. Don’t underestimate the engine though; it’s very quick but sometimes an intensive game can hamper performance.

Humanoids are still expensive on the backend. Just having a humanoid itself already brings the backend expenses of a humanoid to the table. One commonly known method of bringing down the expense of humanoids is by disabling their state types.

Yeah. Tweening on the server is generally a bad idea, as is any kind of aesthetic handling on the server’s end. Tweens have to set a property’s value over time and work in tandem with any events related to changing properties. I myself tween on the server, but if you compare tweening on the server and the client in a full game environment, you’ll notice the server’s tween is choppy.

Remotes can take up to 60 KB/second and clients can handle a lot of operations. The bottleneck is only the time it takes to make a trip from the server to the client, their own device specifications and their network. Clients are capable of handling a lot - typically inconsequential things while the server handles crucial tasks that can affect game play.

Firing to all clients would hardly have much of a cost, surprisingly. The only cost you’re going to get is sending data from the server to clients. The data you send is probably only worth a few bytes - remote limits sit at a full 60 KB. Assuming you only send a single byte of data, that’s around 1.7x10-4 % of your sending limit, which is very small.

I don’t know how to do such a thing first-hand, but can’t you fetch the animation data and then CFrame the parts accordingly? I’m not entirely sure, but this sounds like something someone must’ve made a script for by now.

I just know that Humanoids are super physics heavy and 100+ (like you were saying you have) will cause immense lag problems if all within close proximity of each other. I was having problems with only 15-20 being close to each other & had to scrap an entire game not too long ago.

Unfortunately, you can’t break down an uploaded animation into its keyframes and poses, which means that getting CFrame data and applying it to limbs is not possible. The best way to reuse animations with humanoids is to use an AnimationController, though they’ve supposedly given some developers grief when it comes to replication. Don’t think that’d be much of an issue in this case though.

Ah, yes. I forgot about AnimationControllers tbh since I’ve never had a real use for them in any of my games. I feel AnimationControllers would be a much better solution than keeping every drawback that Humanoids have in them just for the sole purpose of animations.

Which humanoid state costs the least?

And which method would ensure it remains that way.

			hum:SetStateEnabled(Enum.HumanoidStateType.RunningNoPhysics,true)
			hum:SetStateEnabled(Enum.HumanoidStateType.FallingDown,false)
			hum:SetStateEnabled(Enum.HumanoidStateType.Running,false)
			hum:SetStateEnabled(Enum.HumanoidStateType.Climbing,false)
			hum:SetStateEnabled(Enum.HumanoidStateType.Ragdoll,false)
			hum:SetStateEnabled(Enum.HumanoidStateType.GettingUp,false)
			hum:SetStateEnabled(Enum.HumanoidStateType.Jumping,false)
			hum:SetStateEnabled(Enum.HumanoidStateType.Landed,false)
			hum:SetStateEnabled(Enum.HumanoidStateType.Flying,false)
			hum:SetStateEnabled(Enum.HumanoidStateType.Freefall,false)
			hum:SetStateEnabled(Enum.HumanoidStateType.Seated,false)
			hum:SetStateEnabled(Enum.HumanoidStateType.PlatformStanding,false)
			hum:SetStateEnabled(Enum.HumanoidStateType.Dead,false)
			hum:SetStateEnabled(Enum.HumanoidStateType.Swimming,false)
			hum:SetStateEnabled(Enum.HumanoidStateType.Physics,false)

or

enemy.Humanoid.StateChanged:connect(function(s)
	if s ~= Enum.HumanoidStateType.RunningNoPhysics then -- or whichever statetype is the most efficient
		enemy.Humanoid:SetStateEnabled(s,false)
	end
end)
1 Like

What’s the interval in ms between each line in ur screenshot

There is none it’s not a loop it’s just a block of code that assigns some things. Humanoid:SetStateEnabled() makes it so they cannot change to that state, though I’m not sure if it always works.
I had a case where it switched back to a state that I kept disabling. This was a long time ago though so I might’ve done something wrong.

1 Like

No like in your first screen shot zoom out to like 12ms in the micro profiler and take the screen shot again

1 Like