1 //====== Copyright Valve Corporation, All rights reserved. ==================== 2 // 3 // Some public types for communicating detailed connection stats 4 // 5 //============================================================================= 6 7 #ifndef STEAMNETWORKING_STATS_H 8 #define STEAMNETWORKING_STATS_H 9 #ifdef _WIN32 10 #pragma once 11 #endif 12 13 #include <steam/steamnetworkingtypes.h> 14 #include "steamnetworkingsockets_internal.h" 15 16 #pragma pack(push) 17 #pragma pack(8) 18 19 namespace SteamNetworkingSocketsLib { 20 21 struct SteamDatagramLinkStats; 22 struct SteamDatagramLinkLifetimeStats; 23 struct SteamDatagramLinkInstantaneousStats; 24 struct SteamNetworkingDetailedConnectionStatus; 25 26 /// Instantaneous statistics for a link between two hosts. 27 struct SteamDatagramLinkInstantaneousStats 28 { 29 30 /// Data rates 31 float m_flOutPacketsPerSec; 32 float m_flOutBytesPerSec; 33 float m_flInPacketsPerSec; 34 float m_flInBytesPerSec; 35 36 /// Smoothed ping. This will be -1 if we don't have any idea! 37 int m_nPingMS; 38 39 /// 0...1, estimated number of packets that were sent to us, but we failed to receive. 40 /// <0 if we haven't received any sequenced packets and so we don't have any way to estimate this. 41 float m_flPacketsDroppedPct; 42 43 /// Packets received with a sequence number abnormality, other than basic packet loss. (Duplicated, out of order, lurch.) 44 /// <0 if we haven't received any sequenced packets and so we don't have any way to estimate this. 45 float m_flPacketsWeirdSequenceNumberPct; 46 47 /// Peak jitter 48 int m_usecMaxJitter; 49 50 /// Current sending rate, this can be low at connection start until the slow start 51 /// ramps it up. It's adjusted as packets are lost and congestion is encountered during 52 /// the connection 53 int m_nSendRate; 54 55 /// How many pending bytes are waiting to be sent. This is data that is currently waiting 56 /// to be sent and in outgoing buffers. If this is zero, then the connection is idle 57 /// and all pending data has been sent. Note that in case of packet loss any pending 58 /// reliable data might be re-sent. This does not include data that has been sent and is 59 /// waiting for acknowledgment. 60 int m_nPendingBytes; 61 62 /// Reset all values to zero / unknown status 63 void Clear(); 64 }; 65 66 /// Counts of ping times by bucket 67 struct PingHistogram 68 { 69 int m_n25, m_n50, m_n75, m_n100, m_n125, m_n150, m_n200, m_n300, m_nMax; 70 ResetPingHistogram71 void Reset() { memset( this, 0, sizeof(*this) ); } 72 AddSamplePingHistogram73 void AddSample( int nPingMS ) 74 { 75 76 // Update histogram using hand-rolled sort-of-binary-search, optimized 77 // for the expectation that most pings will be reasonable 78 if ( nPingMS <= 100 ) 79 { 80 if ( nPingMS <= 50 ) 81 { 82 if ( nPingMS <= 25 ) 83 ++m_n25; 84 else 85 ++m_n50; 86 } 87 else 88 { 89 if ( nPingMS <= 75 ) 90 ++m_n75; 91 else 92 ++m_n100; 93 } 94 } 95 else 96 { 97 if ( nPingMS <= 150 ) 98 { 99 if ( nPingMS <= 125 ) 100 ++m_n125; 101 else 102 ++m_n150; 103 } 104 else 105 { 106 if ( nPingMS <= 200 ) 107 ++m_n200; 108 else if ( nPingMS <= 300 ) 109 ++m_n300; 110 else 111 ++m_nMax; 112 } 113 } 114 } 115 TotalCountPingHistogram116 inline int TotalCount() const 117 { 118 return m_n25 + m_n50 + m_n75 + m_n100 + m_n125 + m_n150 + m_n200 + m_n300 + m_nMax; 119 } 120 }; 121 122 /// Count of quality measurement intervals by bucket 123 struct QualityHistogram 124 { 125 int m_n100, m_n99, m_n97, m_n95, m_n90, m_n75, m_n50, m_n1, m_nDead; 126 ResetQualityHistogram127 void Reset() { memset( this, 0, sizeof(*this) ); } 128 TotalCountQualityHistogram129 inline int TotalCount() const 130 { 131 return m_n100 + m_n99 + m_n97 + m_n95 + m_n90 + m_n75 + m_n50 + m_n1 + m_nDead; 132 } 133 }; 134 135 /// Counts of jitter values by bucket 136 struct JitterHistogram 137 { ResetJitterHistogram138 void Reset() { memset( this, 0, sizeof(*this) ); } 139 140 int m_nNegligible; // <1ms 141 int m_n1; // 1--2ms 142 int m_n2; // 2--5ms 143 int m_n5; // 5--10ms 144 int m_n10; // 10--20ms 145 int m_n20; // 20ms or more 146 AddSampleJitterHistogram147 void AddSample( SteamNetworkingMicroseconds usecJitter ) 148 { 149 150 // Add to histogram 151 if ( usecJitter < 1000 ) 152 ++m_nNegligible; 153 else if ( usecJitter < 2000 ) 154 ++m_n1; 155 else if ( usecJitter < 5000 ) 156 ++m_n2; 157 else if ( usecJitter < 10000 ) 158 ++m_n5; 159 else if ( usecJitter < 20000 ) 160 ++m_n10; 161 else 162 ++m_n20; 163 } 164 TotalCountJitterHistogram165 inline int TotalCount() const 166 { 167 return m_nNegligible + m_n1 + m_n2 + m_n5 + m_n10 + m_n20; 168 } 169 }; 170 171 /// Stats for the lifetime of a connection. 172 /// Should match CMsgSteamDatagramLinkLifetimeStats 173 struct SteamDatagramLinkLifetimeStats 174 { 175 /// Reset all values to zero / unknown status 176 void Clear(); 177 178 int m_nConnectedSeconds; // -1 if we don't track it 179 180 // 181 // Lifetime counters. 182 // NOTE: Average packet loss, etc can be deduced from this. 183 // 184 int64 m_nPacketsSent; 185 int64 m_nBytesSent; 186 int64 m_nPacketsRecv; // total number of packets received, some of which might not have had a sequence number. Don't use this number to try to estimate lifetime packet loss, use m_nPacketsRecvSequenced 187 int64 m_nBytesRecv; 188 int64 m_nPktsRecvSequenced; // packets that we received that had a sequence number. 189 int64 m_nPktsRecvDropped; 190 int64 m_nPktsRecvOutOfOrder; 191 int64 m_nPktsRecvDuplicate; 192 int64 m_nPktsRecvSequenceNumberLurch; 193 194 // SNP message counters 195 int64 m_nMessagesSentReliable; 196 int64 m_nMessagesSentUnreliable; 197 int64 m_nMessagesRecvReliable; 198 int64 m_nMessagesRecvUnreliable; 199 200 // Ping distribution 201 PingHistogram m_pingHistogram; 202 203 // Distribution. 204 // NOTE: Some of these might be -1 if we didn't have enough data to make a meaningful estimate! 205 // It takes fewer samples to make an estimate of the median than the 98th percentile! 206 short m_nPingNtile5th; // 5% of ping samples were <= Nms 207 short m_nPingNtile50th; // 50% of ping samples were <= Nms 208 short m_nPingNtile75th; // 70% of ping samples were <= Nms 209 short m_nPingNtile95th; // 95% of ping samples were <= Nms 210 short m_nPingNtile98th; // 98% of ping samples were <= Nms 211 short m__pad1; 212 213 214 // 215 // Connection quality distribution 216 // 217 QualityHistogram m_qualityHistogram; 218 219 // Distribution. Some might be -1, see above for why. 220 short m_nQualityNtile2nd; // 2% of measurement intervals had quality <= N% 221 short m_nQualityNtile5th; // 5% of measurement intervals had quality <= N% 222 short m_nQualityNtile25th; // 25% of measurement intervals had quality <= N% 223 short m_nQualityNtile50th; // 50% of measurement intervals had quality <= N% 224 225 // Jitter histogram 226 JitterHistogram m_jitterHistogram; 227 228 // 229 // Connection transmit speed histogram 230 // 231 int m_nTXSpeedMax; // Max speed we hit 232 233 int m_nTXSpeedHistogram16; // Speed at kb/s 234 int m_nTXSpeedHistogram32; 235 int m_nTXSpeedHistogram64; 236 int m_nTXSpeedHistogram128; 237 int m_nTXSpeedHistogram256; 238 int m_nTXSpeedHistogram512; 239 int m_nTXSpeedHistogram1024; 240 int m_nTXSpeedHistogramMax; TXSpeedHistogramTotalCountSteamDatagramLinkLifetimeStats241 inline int TXSpeedHistogramTotalCount() const 242 { 243 return m_nTXSpeedHistogram16 244 + m_nTXSpeedHistogram32 245 + m_nTXSpeedHistogram64 246 + m_nTXSpeedHistogram128 247 + m_nTXSpeedHistogram256 248 + m_nTXSpeedHistogram512 249 + m_nTXSpeedHistogram1024 250 + m_nTXSpeedHistogramMax; 251 } 252 253 // Distribution. Some might be -1, see above for why. 254 int m_nTXSpeedNtile5th; // 5% of transmit samples were <= N kb/s 255 int m_nTXSpeedNtile50th; // 50% of transmit samples were <= N kb/s 256 int m_nTXSpeedNtile75th; // 75% of transmit samples were <= N kb/s 257 int m_nTXSpeedNtile95th; // 95% of transmit samples were <= N kb/s 258 int m_nTXSpeedNtile98th; // 98% of transmit samples were <= N kb/s 259 260 // 261 // Connection receive speed histogram 262 // 263 int m_nRXSpeedMax; // Max speed we hit that formed the histogram 264 265 int m_nRXSpeedHistogram16; // Speed at kb/s 266 int m_nRXSpeedHistogram32; 267 int m_nRXSpeedHistogram64; 268 int m_nRXSpeedHistogram128; 269 int m_nRXSpeedHistogram256; 270 int m_nRXSpeedHistogram512; 271 int m_nRXSpeedHistogram1024; 272 int m_nRXSpeedHistogramMax; RXSpeedHistogramTotalCountSteamDatagramLinkLifetimeStats273 inline int RXSpeedHistogramTotalCount() const 274 { 275 return m_nRXSpeedHistogram16 276 + m_nRXSpeedHistogram32 277 + m_nRXSpeedHistogram64 278 + m_nRXSpeedHistogram128 279 + m_nRXSpeedHistogram256 280 + m_nRXSpeedHistogram512 281 + m_nRXSpeedHistogram1024 282 + m_nRXSpeedHistogramMax; 283 } 284 285 // Distribution. Some might be -1, see above for why. 286 int m_nRXSpeedNtile5th; // 5% of transmit samples were <= N kb/s 287 int m_nRXSpeedNtile50th; // 50% of transmit samples were <= N kb/s 288 int m_nRXSpeedNtile75th; // 75% of transmit samples were <= N kb/s 289 int m_nRXSpeedNtile95th; // 95% of transmit samples were <= N kb/s 290 int m_nRXSpeedNtile98th; // 98% of transmit samples were <= N kb/s 291 292 }; 293 294 /// Link stats. Pretty much everything you might possibly want to know about the connection 295 struct SteamDatagramLinkStats 296 { 297 298 /// Latest instantaneous stats, calculated locally 299 SteamDatagramLinkInstantaneousStats m_latest; 300 301 /// Peak values for each instantaneous stat 302 //SteamDatagramLinkInstantaneousStats m_peak; 303 304 /// Lifetime stats, calculated locally 305 SteamDatagramLinkLifetimeStats m_lifetime; 306 307 /// Latest instantaneous stats received from remote host. 308 /// (E.g. "sent" means they are reporting what they sent.) 309 SteamDatagramLinkInstantaneousStats m_latestRemote; 310 311 /// How many seconds ago did we receive m_latestRemote? 312 /// This will be <0 if the data is not valid! 313 float m_flAgeLatestRemote; 314 315 /// Latest lifetime stats received from remote host. 316 SteamDatagramLinkLifetimeStats m_lifetimeRemote; 317 318 /// How many seconds ago did we receive the lifetime stats? 319 /// This will be <0 if the data is not valid! 320 float m_flAgeLifetimeRemote; 321 322 /// Reset everything to unknown/initial state. 323 void Clear(); 324 }; 325 326 /// Describe detailed state of current connection 327 struct SteamNetworkingDetailedConnectionStatus 328 { 329 /// Basic connection info 330 SteamNetConnectionInfo_t m_info; 331 332 /// What kind of transport us being used? 333 ESteamNetTransportKind m_eTransportKind; 334 335 /// Do we have a valid network configuration? We cannot do anything without this. 336 ESteamNetworkingAvailability m_eAvailNetworkConfig; 337 338 // /// Does it look like we have a connection to the Internet at all? 339 // EAvailability m_eAvailInternet; 340 341 /// Successful communication with a box on the routing network. 342 /// This will be marked as failed if there is a general internet 343 /// connection. 344 ESteamNetworkingAvailability m_eAvailAnyRouterCommunication; 345 346 /// End-to-end communication with the remote host. 347 //ESteamNetworkingAvailability m_eAvailEndToEnd; 348 349 /// Stats for end-to-end link to the gameserver 350 SteamDatagramLinkStats m_statsEndToEnd; 351 352 /// Currently selected front router, if any. 353 /// Note that PoP ID can be found in the SteamNetConnectionInfo_t 354 char m_szPrimaryRouterName[64]; 355 SteamNetworkingIPAddr m_addrPrimaryRouter; 356 357 /// Stats for "front" link to current router 358 SteamDatagramLinkStats m_statsPrimaryRouter; 359 360 /// Back ping time as reported by primary. 361 /// (The front ping is in m_statsPrimaryRouter, 362 /// and usually the front ping plus the back ping should 363 /// approximately equal the end-to-end ping) 364 int m_nPrimaryRouterBackPing; 365 366 /// Currently selected back router, if any 367 SteamNetworkingPOPID m_idBackupRouterCluster; 368 char m_szBackupRouterName[64]; 369 SteamNetworkingIPAddr m_addrBackupRouter; 370 371 /// Ping times to backup router, if any 372 int m_nBackupRouterFrontPing, m_nBackupRouterBackPing; 373 374 /// Clear everything to an unknown state 375 void Clear(); 376 377 /// Print into a buffer. 378 /// 0 = OK 379 /// >1 = buffer was null or too small (in which case truncation happened). 380 /// Pass a buffer of at least N bytes. 381 int Print( char *pszBuf, int cbBuf ); 382 }; 383 384 #pragma pack(pop) 385 386 } // namespace SteamNetworkingSocketsLib 387 388 #endif // STEAMNETWORKING_STATS_H 389