Skip to content
Engine

Runtime

PerformanceService

Live FPS, frame time, memory and ping, a device benchmark, and a quality level that adjusts itself to keep the frame rate up.

ServiceShared

Getting it

local PerformanceService = Engine:GetService("PerformanceService")

Overview

PerformanceService measures how well the game runs and gives you one number to react to: Quality, from 0 (lowest) to 10 (highest) by default. Your own code decides what a quality level means, such as fewer particles, shorter view distance or no shadows on low.

In "Auto" mode a governor watches the frame rate: when it drops below the target it lowers Quality one step, and when there is headroom it raises it again. When the service loads it runs a short micro-benchmark spread over a few frames to estimate how fast the device is, and seeds Quality from that (low, middle or high level) unless you already set it.

Scaling effects with the device
local PerformanceService = Engine:GetService("PerformanceService")

local function applyQuality(level: number)
	rainEmitter.Rate = level * 40
	workspace.Terrain.Decoration = level >= 4
	for _, light in workspace.Lights:GetChildren() do
		light.Shadows = level >= 7
	end
end

applyQuality(PerformanceService.Quality)
PerformanceService:OnQuality(applyQuality)

Quality is most useful on the client, where it reflects the player's device. On the server it follows server heartbeat time.

Quality

Quality / QualityMode

PerformanceService.Quality: number
PerformanceService.QualityMode: "Auto" | "Manual"

Quality is always kept between the configured minimum and maximum. You can only set it while QualityMode is "Manual", for example from a graphics setting in your options menu:

PerformanceService.QualityMode = "Manual"
PerformanceService.Quality = playerChosenLevel

OnQuality

PerformanceService:OnQuality(fn: (level: number) -> ()): Connection

Shortcut for connecting to QualityChanged.

QualityChanged

PerformanceService.QualityChanged: Signal<number>

ConfigureAuto

PerformanceService:ConfigureAuto(config: { targetFps: number?, sampleWindow: number?, hysteresis: number? }?)

Tunes the governor at runtime: the frame rate to hold, how many frames are averaged, and how many FPS of slack around the target before it changes Quality. GetAutoConfig() returns the current values.

Metrics

GetMetrics

PerformanceService:GetMetrics(): Metrics
FieldDescription
FpsAverage frames per second over the sample window.
FrameTimeMsAverage render frame time (client) or heartbeat time (server).
HeartbeatMsAverage time between heartbeats.
MemoryMbTotal memory in use.
PingRound-trip time in ms; on the server, the average over all players.
BudgetsMilliseconds each SchedulerService queue used last frame.

Device tier

GetDeviceTier

PerformanceService:GetDeviceTier(): "Low" | "Mid" | "High"

The tier measured by the benchmark. Returns "Mid" until the first benchmark has finished.

RunMicroBenchmarkAsync

PerformanceService:RunMicroBenchmarkAsync(config: { units: number?, iterationsPerUnit: number?, budgetMs: number? }?): Promise<number>

Runs the benchmark again and resolves with the score in operations per second. It is spread over frames, so it never causes a hitch. Runs once automatically when the service loads.

Budgets

SetBudget

PerformanceService:SetBudget(system: string, msPerFrame: number)

Sets the per-frame budget of the SchedulerService queue named system, creating the queue if it does not exist yet.

GetBudgetQueue

PerformanceService:GetBudgetQueue(system: string): Queue?

BudgetExceeded

PerformanceService.BudgetExceeded: Signal<(system: string, msUsed: number)>

Forwards SchedulerService.BudgetExceeded.

Configuration

Defaults from DefaultConfiguration/Services/PerformanceService13 settings
SettingDefaultWhat it does
DefaultTargetFps60Fps the Auto governor tries to hold .Quality at.
DefaultSampleWindow60Frames averaged into FrameTimeMs/HeartbeatMs/Fps.
DefaultHysteresisFps5Fps of slack around the target before Auto nudges .Quality up or down.
DefaultAutoCheckIntervalSeconds2Seconds between Auto governor re-evaluations.
DefaultQualityMode"Auto""Auto" | "Manual".
DefaultQualityLevel10Boot .Quality, before the first RunMicroBenchmark seeds a tier-based one.
DefaultMinQualityLevel0Lowest .Quality the governor may go to.
DefaultMaxQualityLevel10Highest .Quality the governor may go to.
DefaultMicroBenchmarkUnits100SchedulerService:Spread items RunMicroBenchmark chunks its workload into.
DefaultMicroBenchmarkIterationsPerUnit2000Sin/cos iterations per benchmark unit.
DefaultMicroBenchmarkBudgetMs2Milliseconds per tick RunMicroBenchmark spends before yielding.
DefaultDeviceTierLowMaxScore2000000Ops/sec below this is tier "Low".
DefaultDeviceTierMidMaxScore6000000Ops/sec below this (and above Low) is "Mid"; at or above is "High".

Types

export type DeviceTier = "Low" | "Mid" | "High"
export type QualityMode = "Auto" | "Manual"
export type Metrics
export type AutoConfig = { targetFps: number?, sampleWindow: number?, hysteresis: number? }
export type BenchmarkConfig = { units: number?, iterationsPerUnit: number?, budgetMs: number? }