Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
RuntimeMetrics.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "RuntimeMetrics.h"
7
8#include <sstream>
9
10namespace
11{
12 uint32 const SLOW_WORLD_UPDATE_THRESHOLD_MS = 100;
13 uint32 const SLOW_MAP_UPDATE_WAIT_THRESHOLD_MS = 100;
14
15 bool StoreMax(std::atomic<uint32>& target, uint32 value)
16 {
17 uint32 current = target.load(std::memory_order_relaxed);
18 while (current < value &&
19 !target.compare_exchange_weak(current, value, std::memory_order_relaxed, std::memory_order_relaxed))
20 {
21 }
22
23 return current < value;
24 }
25}
26
27namespace Skyfire
28{
29namespace Diagnostics
30{
33
36
39
42
45
48
50 {
51 _sampleCount.store(0, std::memory_order_relaxed);
52 _slowSamples.store(0, std::memory_order_relaxed);
53 _total.store(0, std::memory_order_relaxed);
54 _last.store(0, std::memory_order_relaxed);
55 _maximum.store(0, std::memory_order_relaxed);
56 }
57
59 {
60 _sampleCount.fetch_add(1, std::memory_order_relaxed);
61 if (slowThresholdMs && value >= slowThresholdMs)
62 _slowSamples.fetch_add(1, std::memory_order_relaxed);
63
64 _total.fetch_add(value, std::memory_order_relaxed);
65 _last.store(value, std::memory_order_relaxed);
66 StoreMax(_maximum, value);
67 }
68
70 {
71 RuntimeSampleSnapshot snapshot;
72 snapshot.SampleCount = _sampleCount.load(std::memory_order_relaxed);
73 snapshot.SlowSamples = _slowSamples.load(std::memory_order_relaxed);
74 snapshot.Last = _last.load(std::memory_order_relaxed);
75 snapshot.Maximum = _maximum.load(std::memory_order_relaxed);
76
77 uint64 const total = _total.load(std::memory_order_relaxed);
78 snapshot.Average = snapshot.SampleCount ? static_cast<uint32>(total / snapshot.SampleCount) : 0;
79
80 return snapshot;
81 }
82
102
104 {
105 _worldUpdate.Reset();
106 _mapUpdatePasses.Reset();
107 _mapUpdateWait.Reset();
108 _mapUpdateScheduled.store(0, std::memory_order_relaxed);
109 _mapUpdateCompleted.store(0, std::memory_order_relaxed);
110 _mapUpdateScheduleFailures.store(0, std::memory_order_relaxed);
111 _mapUpdatePending.store(0, std::memory_order_relaxed);
112 _mapUpdatePendingHighWater.store(0, std::memory_order_relaxed);
113 _worldSessionPacketsQueued.store(0, std::memory_order_relaxed);
114 _worldSessionPacketsProcessed.store(0, std::memory_order_relaxed);
115 _worldSessionQueueDepth.store(0, std::memory_order_relaxed);
116 _worldSessionQueueDepthHighWater.store(0, std::memory_order_relaxed);
117 _worldSessionQueueDepthHighWaterEvents.store(0, std::memory_order_relaxed);
118 _spellCastFailures.store(0, std::memory_order_relaxed);
119 _spellCastLastSpellId.store(0, std::memory_order_relaxed);
120 _spellCastLastFailure.store(0, std::memory_order_relaxed);
121 _spellCastLastCustomError.store(0, std::memory_order_relaxed);
122 _spellCastLastOpcode.store(0, std::memory_order_relaxed);
123 }
124
126 {
127 _worldUpdate.Record(diffMs, SLOW_WORLD_UPDATE_THRESHOLD_MS);
128 }
129
131 {
132 _mapUpdatePasses.Record(mapCount);
133 }
134
136 {
137 _mapUpdateScheduled.fetch_add(1, std::memory_order_relaxed);
138 _mapUpdatePending.store(pendingRequests, std::memory_order_relaxed);
139 StoreMax(_mapUpdatePendingHighWater, pendingRequests);
140 }
141
143 {
144 _mapUpdateCompleted.fetch_add(1, std::memory_order_relaxed);
145 _mapUpdatePending.store(pendingRequests, std::memory_order_relaxed);
146 }
147
149 {
150 _mapUpdateScheduleFailures.fetch_add(1, std::memory_order_relaxed);
151 _mapUpdatePending.store(pendingRequests, std::memory_order_relaxed);
152 }
153
155 {
156 _mapUpdateWait.Record(waitMs, SLOW_MAP_UPDATE_WAIT_THRESHOLD_MS);
157 }
158
160 {
161 _worldSessionPacketsQueued.fetch_add(1, std::memory_order_relaxed);
162 _worldSessionQueueDepth.store(queueDepth, std::memory_order_relaxed);
163 if (StoreMax(_worldSessionQueueDepthHighWater, queueDepth))
164 _worldSessionQueueDepthHighWaterEvents.fetch_add(1, std::memory_order_relaxed);
165 }
166
168 {
169 _worldSessionPacketsProcessed.fetch_add(1, std::memory_order_relaxed);
170 _worldSessionQueueDepth.store(queueDepth, std::memory_order_relaxed);
171 }
172
173 void RuntimeMetrics::RecordSpellCastFailure(uint32 spellId, uint32 failure, uint32 customError, uint32 opcode)
174 {
175 _spellCastFailures.fetch_add(1, std::memory_order_relaxed);
176 _spellCastLastSpellId.store(spellId, std::memory_order_relaxed);
177 _spellCastLastFailure.store(failure, std::memory_order_relaxed);
178 _spellCastLastCustomError.store(customError, std::memory_order_relaxed);
179 _spellCastLastOpcode.store(opcode, std::memory_order_relaxed);
180 }
181
183 {
184 RuntimeMetricsSnapshot snapshot;
185 snapshot.WorldUpdate = _worldUpdate.Snapshot();
186 snapshot.MapUpdatePasses = _mapUpdatePasses.Snapshot();
187 snapshot.MapUpdater.Scheduled = _mapUpdateScheduled.load(std::memory_order_relaxed);
188 snapshot.MapUpdater.Completed = _mapUpdateCompleted.load(std::memory_order_relaxed);
189 snapshot.MapUpdater.ScheduleFailures = _mapUpdateScheduleFailures.load(std::memory_order_relaxed);
190 snapshot.MapUpdater.Pending = _mapUpdatePending.load(std::memory_order_relaxed);
191 snapshot.MapUpdater.PendingHighWater = _mapUpdatePendingHighWater.load(std::memory_order_relaxed);
192 snapshot.MapUpdater.Wait = _mapUpdateWait.Snapshot();
193 snapshot.WorldSession.PacketsQueued = _worldSessionPacketsQueued.load(std::memory_order_relaxed);
194 snapshot.WorldSession.PacketsProcessed = _worldSessionPacketsProcessed.load(std::memory_order_relaxed);
195 snapshot.WorldSession.QueueDepth = _worldSessionQueueDepth.load(std::memory_order_relaxed);
196 snapshot.WorldSession.QueueDepthHighWater = _worldSessionQueueDepthHighWater.load(std::memory_order_relaxed);
197 snapshot.WorldSession.QueueDepthHighWaterEvents = _worldSessionQueueDepthHighWaterEvents.load(std::memory_order_relaxed);
198 snapshot.SpellCast.Failures = _spellCastFailures.load(std::memory_order_relaxed);
199 snapshot.SpellCast.LastSpellId = _spellCastLastSpellId.load(std::memory_order_relaxed);
200 snapshot.SpellCast.LastFailure = _spellCastLastFailure.load(std::memory_order_relaxed);
201 snapshot.SpellCast.LastCustomError = _spellCastLastCustomError.load(std::memory_order_relaxed);
202 snapshot.SpellCast.LastOpcode = _spellCastLastOpcode.load(std::memory_order_relaxed);
203
204 return snapshot;
205 }
206
208 {
209 static RuntimeMetrics metrics;
210 return metrics;
211 }
212
213 std::vector<std::string> FormatRuntimeMetricLines(RuntimeMetricsSnapshot const& snapshot)
214 {
215 std::vector<std::string> lines;
216 lines.reserve(4);
217
218 std::ostringstream worldLine;
219 worldLine << "Runtime metrics - World update: samples " << snapshot.WorldUpdate.SampleCount
220 << ", last " << snapshot.WorldUpdate.Last << " ms"
221 << ", avg " << snapshot.WorldUpdate.Average << " ms"
222 << ", max " << snapshot.WorldUpdate.Maximum << " ms"
223 << ", slow " << snapshot.WorldUpdate.SlowSamples
224 << " (>=" << SLOW_WORLD_UPDATE_THRESHOLD_MS << " ms)";
225 lines.push_back(worldLine.str());
226
227 std::ostringstream mapLine;
228 mapLine << "Runtime metrics - Map updater: scheduled " << snapshot.MapUpdater.Scheduled
229 << ", completed " << snapshot.MapUpdater.Completed
230 << ", pending " << snapshot.MapUpdater.Pending
231 << ", high-water " << snapshot.MapUpdater.PendingHighWater
232 << ", failures " << snapshot.MapUpdater.ScheduleFailures
233 << ", waits " << snapshot.MapUpdater.Wait.SampleCount
234 << ", wait avg " << snapshot.MapUpdater.Wait.Average << " ms"
235 << ", wait max " << snapshot.MapUpdater.Wait.Maximum << " ms"
236 << ", slow waits " << snapshot.MapUpdater.Wait.SlowSamples
237 << " (>=" << SLOW_MAP_UPDATE_WAIT_THRESHOLD_MS << " ms)"
238 << ", map pass avg " << snapshot.MapUpdatePasses.Average
239 << ", map pass max " << snapshot.MapUpdatePasses.Maximum;
240 lines.push_back(mapLine.str());
241
242 std::ostringstream packetLine;
243 packetLine << "Runtime metrics - Packet queue: queued " << snapshot.WorldSession.PacketsQueued
244 << ", processed " << snapshot.WorldSession.PacketsProcessed
245 << ", depth " << snapshot.WorldSession.QueueDepth
246 << ", high-water " << snapshot.WorldSession.QueueDepthHighWater
247 << ", high-water events " << snapshot.WorldSession.QueueDepthHighWaterEvents;
248 lines.push_back(packetLine.str());
249
250 std::ostringstream spellLine;
251 spellLine << "Runtime metrics - Spell cast failures: count " << snapshot.SpellCast.Failures
252 << ", last spell " << snapshot.SpellCast.LastSpellId
253 << ", result " << snapshot.SpellCast.LastFailure
254 << ", custom " << snapshot.SpellCast.LastCustomError
255 << ", opcode " << snapshot.SpellCast.LastOpcode;
256 lines.push_back(spellLine.str());
257
258 return lines;
259 }
260}
261}
std::uint32_t uint32
Definition Define.h:77
std::uint64_t uint64
Definition Define.h:76
void Record(uint32 value, uint32 slowThresholdMs=0)
std::atomic< uint64 > _spellCastFailures
std::atomic< uint32 > _spellCastLastFailure
void RecordWorldSessionPacketQueued(uint32 queueDepth)
std::atomic< uint32 > _worldSessionQueueDepthHighWater
std::atomic< uint32 > _worldSessionQueueDepth
std::atomic< uint32 > _spellCastLastCustomError
void RecordMapUpdateScheduleFailed(uint32 pendingRequests)
void RecordSpellCastFailure(uint32 spellId, uint32 failure, uint32 customError, uint32 opcode)
std::atomic< uint64 > _mapUpdateScheduled
void RecordWorldSessionPacketProcessed(uint32 queueDepth)
std::atomic< uint64 > _mapUpdateScheduleFailures
std::atomic< uint32 > _mapUpdatePending
void RecordMapUpdateScheduled(uint32 pendingRequests)
std::atomic< uint64 > _mapUpdateCompleted
RuntimeMetricsSnapshot Snapshot() const
std::atomic< uint64 > _worldSessionQueueDepthHighWaterEvents
std::atomic< uint64 > _worldSessionPacketsQueued
std::atomic< uint32 > _spellCastLastOpcode
std::atomic< uint64 > _worldSessionPacketsProcessed
std::atomic< uint32 > _mapUpdatePendingHighWater
void RecordMapUpdateCompleted(uint32 pendingRequests)
std::atomic< uint32 > _spellCastLastSpellId
RuntimeMetrics & GetRuntimeMetrics()
std::vector< std::string > FormatRuntimeMetricLines(RuntimeMetricsSnapshot const &snapshot)