private void SlowTimerCallback(object state) { try { int start = m_timerTickStart; GameTimer timer = m_currentTimer; if (timer == null) { return; } StringBuilder str = new StringBuilder("=== Timer already took ", 1024); str.Append(GetTickCount() - start).Append("ms\n"); str.Append(timer.ToString()); str.Append("\n\n"); str.Append("Timer thread:\n"); str.Append(Util.FormatStackTrace(Util.GetThreadStack(m_timeThread))); string packetStacks = PacketHandler.PacketProcessor.GetConnectionThreadpoolStacks(); if (packetStacks.Length > 0) { str.Append("\n\nPackethandler threads:\n"); str.Append(packetStacks); } str.Append("\n\nNPC update thread:\n"); str.Append(Util.FormatStackTrace(WorldMgr.GetNpcUpdateStacktrace())); str.Append("\n\nRelocation thread:\n"); str.Append(Util.FormatStackTrace(WorldMgr.GetRelocateRegionsStacktrace())); str.Append("\n\n"); lock (m_delayLog) { m_delayLog.Write(str.ToString()); m_delayLog.Flush(); } } catch (Exception e) { if (log.IsWarnEnabled) { log.Warn("collecting/writing timer delays", e); } } }
/// <summary> /// print out some periodic information on server statistics /// </summary> /// <param name="state"></param> public static void PrintStats(object state) { try { //Don't enable this line unless you have memory issues and //need more details in memory usage //GC.Collect(); long newTick = DateTime.Now.Ticks; long time = newTick - m_lastMeasureTick; m_lastMeasureTick = newTick; time /= 10000000L; if (time < 1) { log.Warn("Time has not changed since last call of PrintStats"); time = 1; // prevent division by zero? } long inRate = (Statistics.BytesIn - m_lastBytesIn) / time; long outRate = (Statistics.BytesOut - m_lastBytesOut) / time; long inPckRate = (Statistics.PacketsIn - m_lastPacketsIn) / time; long outPckRate = (Statistics.PacketsOut - m_lastPacketsOut) / time; m_lastBytesIn = Statistics.BytesIn; m_lastBytesOut = Statistics.BytesOut; m_lastPacketsIn = Statistics.PacketsIn; m_lastPacketsOut = Statistics.PacketsOut; // Get threadpool info int iocpCurrent, iocpMin, iocpMax; int poolCurrent, poolMin, poolMax; ThreadPool.GetAvailableThreads(out poolCurrent, out iocpCurrent); ThreadPool.GetMinThreads(out poolMin, out iocpMin); ThreadPool.GetMaxThreads(out poolMax, out iocpMax); int globalHandlers = GameEventMgr.NumGlobalHandlers; int objectHandlers = GameEventMgr.NumObjectHandlers; if (log.IsInfoEnabled) { StringBuilder stats = new StringBuilder(256) .Append("-stats- Mem=").Append(GC.GetTotalMemory(false) / 1024 / 1024).Append("MB") .Append(" Clients=").Append(GameServer.Instance.ClientCount) .Append(" Down=").Append(inRate / 1024).Append("kb/s (").Append(Statistics.BytesIn / 1024 / 1024).Append("MB)") .Append(" Up=").Append(outRate / 1024).Append("kb/s (").Append(Statistics.BytesOut / 1024 / 1024).Append("MB)") .Append(" In=").Append(inPckRate).Append("pck/s (").Append(Statistics.PacketsIn / 1000).Append("K)") .Append(" Out=").Append(outPckRate).Append("pck/s (").Append(Statistics.PacketsOut / 1000).Append("K)") .AppendFormat(" Pool={0}/{1}({2})", poolCurrent, poolMax, poolMin) .AppendFormat(" IOCP={0}/{1}({2})", iocpCurrent, iocpMax, iocpMin) .AppendFormat(" GH/OH={0}/{1}", globalHandlers, objectHandlers); lock (m_timerStatsByMgr.SyncRoot) { foreach (GameTimer.TimeManager mgr in WorldMgr.GetRegionTimeManagers()) { TimerStats ts = (TimerStats)m_timerStatsByMgr[mgr]; if (ts == null) { ts = new TimerStats(); m_timerStatsByMgr.Add(mgr, ts); } long curInvoked = mgr.InvokedCount; long invoked = curInvoked - ts.InvokedCount; stats.Append(" ").Append(mgr.Name).Append('=').Append(invoked / time).Append("t/s (") .Append(mgr.ActiveTimers).Append(')'); ts.InvokedCount = curInvoked; } } if (m_systemCpuUsedCounter != null) { stats.Append(" CPU=").Append(m_systemCpuUsedCounter.NextValue().ToString("0.0")).Append('%'); } if (m_processCpuUsedCounter != null) { stats.Append(" DOL=").Append(m_processCpuUsedCounter.NextValue().ToString("0.0")).Append('%'); } if (m_memoryPages != null) { stats.Append(" pg/s=").Append(m_memoryPages.NextValue().ToString("0.0")); } if (m_physycalDisk != null) { stats.Append(" dsk/s=").Append(m_physycalDisk.NextValue().ToString("0.0")); } log.Info(stats); } if (log.IsFatalEnabled) { lock (m_timerStatsByMgr.SyncRoot) { foreach (GameTimer.TimeManager mgr in WorldMgr.GetRegionTimeManagers()) { TimerStats ts = (TimerStats)m_timerStatsByMgr[mgr]; if (ts == null) { continue; } long curTick = mgr.CurrentTime; if (ts.Time == curTick) { log.FatalFormat("{0} stopped ticking; timer stacktrace:\n{1}\n", mgr.Name, Util.FormatStackTrace(mgr.GetStacktrace())); log.FatalFormat("NPC update stacktrace:\n{0}\n", Util.FormatStackTrace(WorldMgr.GetWorldUpdateStacktrace())); log.FatalFormat("Relocate() stacktrace:\n{0}\n", Util.FormatStackTrace(WorldMgr.GetRelocateRegionsStacktrace())); log.FatalFormat("Packethandlers stacktraces:\n{0}\n", PacketProcessor.GetConnectionThreadpoolStacks()); } ts.Time = curTick; } } } } catch (Exception e) { log.Error("stats Log callback", e); } finally { lock (typeof(StatPrint)) { if (m_timer != null) { m_timer.Change(ServerProperties.Properties.STATPRINT_FREQUENCY, 0); } } } }