Server Performance Monitor, Plethora of Performance Improvements

This commit is contained in:
Ceikry
2021-12-19 03:06:17 +00:00
parent b4f3224287
commit 6af8b79126
14 changed files with 1018 additions and 851 deletions
+132
View File
@@ -0,0 +1,132 @@
package gui
import java.awt.*
import javax.swing.JPanel
/**
* @author Rodrigo, Maritaria
* @author Ceikry (rewrote into Kotlin, adapted for specific use case)
*/
class GraphView() : JPanel() {
private val values: MutableList<Int> = ArrayList(10)
fun setValues(newValues: Collection<Int>) {
values.clear()
addValues(newValues)
}
fun addValues(newValues: Collection<Int>) {
if(values.size > 200) values.removeFirst()
values.addAll(newValues)
updateUI()
}
override fun paintComponent(graphics: Graphics) {
super.paintComponent(graphics)
if (graphics !is Graphics2D) {
graphics.drawString("Graphics is not Graphics2D, unable to render", 0, 0)
return
}
val g: Graphics2D = graphics
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
val length: Int = values.size
val width: Int = width
val height: Int = height
val maxScore: Double = maxScore
val minScore: Double = minScore
val scoreRange: Double = maxScore - minScore
// draw white background
g.color = Color.WHITE
g.fillRect(
padding + labelPadding,
padding,
width - (2 * padding) - labelPadding,
height - (2 * padding) - labelPadding
)
g.color = Color.BLACK
val fontMetrics: FontMetrics = g.fontMetrics
val fontHeight: Int = fontMetrics.height
// create hatch marks and grid lines for y axis.
for (i in 0 until numberYDivisions + 1) {
val x1: Int = padding + labelPadding
val x2: Int = pointWidth + padding + labelPadding
val y: Int =
height - (((i * (height - (padding * 2) - labelPadding)) / numberYDivisions) + padding + labelPadding)
if (length > 0) {
g.color = gridColor
g.drawLine(padding + labelPadding + 1 + pointWidth, y, width - padding, y)
g.color = Color.BLACK
val tickValue: Int = (minScore + ((scoreRange * i) / numberYDivisions)).toInt()
val yLabel: String = tickValue.toString() + ""
val labelWidth: Int = fontMetrics.stringWidth(yLabel)
g.drawString(yLabel, x1 - labelWidth - 5, y + (fontHeight / 2) - 3)
}
g.drawLine(x1, y, x2, y)
}
// create x and y axes
g.drawLine(padding + labelPadding, height - padding - labelPadding, padding + labelPadding, padding)
g.drawLine(
padding + labelPadding,
height - padding - labelPadding,
width - padding,
height - padding - labelPadding
)
val oldStroke: Stroke = g.stroke
g.color = lineColor
g.stroke = graphStroke
val xScale: Double = (width.toDouble() - (2 * padding) - labelPadding) / (length - 1)
val yScale: Double = (height.toDouble() - (2 * padding) - labelPadding) / scoreRange
val graphPoints: MutableList<Point> = ArrayList(length)
for (i in 0 until length) {
val x1: Int = ((i * xScale) + padding + labelPadding).toInt()
val y1: Int = ((maxScore - values.get(i)) * yScale + padding).toInt()
graphPoints.add(Point(x1, y1))
}
for (i in 0 until graphPoints.size - 1) {
val x1: Int = graphPoints[i].x
val y1: Int = graphPoints[i].y
val x2: Int = graphPoints[i + 1].x
val y2: Int = graphPoints[i + 1].y
if(y2 != 0) {
g.drawLine(x1, y1, x2, y2)
}
}
val drawDots: Boolean = width > (length * pointWidth)
if (drawDots) {
g.stroke = oldStroke
g.color = pointColor
for (graphPoint: Point in graphPoints) {
val x: Int = graphPoint.x - pointWidth / 2
val y: Int = graphPoint.y - pointWidth / 2
g.fillOval(x, y, pointWidth, pointWidth)
}
}
}
private val minScore: Double
get() = values.stream().min { obj: Int, integer: Int? -> obj.compareTo((integer)!!) }.orElse(0)
.toDouble()
private val maxScore: Double
get() {
return values.stream().max { obj: Int, integer: Int? -> obj.compareTo((integer)!!) }.orElse(0)
.toDouble()
}
companion object {
private const val padding: Int = 25
private const val labelPadding: Int = 25
private const val pointWidth: Int = 4
private const val numberYDivisions: Int = 10
private val lineColor: Color = Color(44, 102, 230, 180)
private val pointColor: Color = Color(100, 100, 100, 180)
private val gridColor: Color = Color(200, 200, 200, 200)
private val graphStroke: Stroke = BasicStroke(2f)
}
init {
preferredSize = Dimension(padding * 2 + 300, padding * 2 + 200)
}
}
+10
View File
@@ -0,0 +1,10 @@
package gui
sealed class GuiEvent {
class UpdatePulseCount(val amount: Int) : GuiEvent()
class UpdateTickTime(val time: Long) : GuiEvent()
class UpdateQueuedPackets(val amount: Int) : GuiEvent()
class AddDebugMessage(val message: String) : GuiEvent()
class AddDefaultMessage(val message: String) : GuiEvent()
class AddAIPMessage(val message: String): GuiEvent()
}
+171
View File
@@ -0,0 +1,171 @@
package gui
import rs09.game.system.SystemLogger
import rs09.game.world.GameWorld
import java.awt.BorderLayout
import java.awt.Component
import java.awt.Dimension
import javax.swing.*
import javax.swing.border.Border
object ServerMonitor : JFrame("Server Monitor"){
val eventQueue = ArrayList<GuiEvent>()
val pulseCount = JLabel("0")
val tickTime = JLabel("0")
val queuedPackets = JLabel("0")
val pulseList = JTextArea("")
val debugLog = JTextArea("")
val defaultLog = JTextArea("")
val AIPlog = JTextArea("")
val tickTimeGraph = GraphView()
val pulseCountGraph = GraphView()
val packetQueueGraph = GraphView()
init {
isVisible = false
layout = BorderLayout()
size = Dimension(800,640)
preferredSize = Dimension(800,640)
minimumSize = Dimension(800,640)
isResizable = false
val tabs = JTabbedPane()
tabs.addTab("Overview", constructOverviewTab())
tabs.addTab("Graphs", constructGraphsTab())
add(tabs)
pack()
}
private fun constructGraphsTab(): JPanel {
val graphPanel = JPanel()
graphPanel.placeAt(0,10,800,590)
val tickTimeBorder = BorderFactory.createTitledBorder("Tick Time")
val pulseCountBorder = BorderFactory.createTitledBorder("Pulse Count")
val packetQueueBorder = BorderFactory.createTitledBorder("Queued Packets")
tickTimeGraph.placeAt(0, 20, 300, 200)
tickTimeGraph.border = tickTimeBorder
pulseCountGraph.placeAt(300,20,300,200)
pulseCountGraph.border = pulseCountBorder
packetQueueGraph.placeAt(0,220,300,200)
packetQueueGraph.border = packetQueueBorder
graphPanel.add(tickTimeGraph)
graphPanel.add(pulseCountGraph)
graphPanel.add(packetQueueGraph)
return graphPanel
}
private fun constructOverviewTab(): JPanel {
val overviewPanel = JPanel(null)
overviewPanel.placeAt(0,10,800,590)
val pulseLabel = JLabel("Pulse Count: ")
pulseLabel.placeAt(0,20,100,10)
pulseCount.placeAt(150,20,100,10)
val tickLabel = JLabel("Tick Time: ")
tickLabel.placeAt(0,35,100,10)
tickTime.placeAt(150,35,100,10)
val packetLabel = JLabel("Queued Packets: ")
packetLabel.placeAt(0,50,200,10)
queuedPackets.placeAt(150, 50, 100, 10)
val scrollPane = JScrollPane(pulseList)
scrollPane.placeAt(400,10,390,275)
val border = BorderFactory.createTitledBorder("Pulses")
scrollPane.border = border
overviewPanel.add(pulseLabel)
overviewPanel.add(pulseCount)
overviewPanel.add(tickLabel)
overviewPanel.add(tickTime)
overviewPanel.add(packetLabel)
overviewPanel.add(queuedPackets)
overviewPanel.add(scrollPane)
val logPane = constructLogPane()
logPane.placeAt(0,280,800,300)
overviewPanel.add(logPane)
return overviewPanel
}
private fun constructLogPane() : JTabbedPane {
val logPane = JTabbedPane()
debugLog.isEditable = false
val debugPanel = JPanel(BorderLayout())
val debugScrollpane = JScrollPane(debugLog)
debugScrollpane.placeAt(0,300,800,300)
debugPanel.add(debugScrollpane, BorderLayout.CENTER)
defaultLog.isEditable = false
val defaultPanel = JPanel(BorderLayout())
val defaultScrollpane = JScrollPane(defaultLog)
defaultScrollpane.placeAt(0,300,800,300)
defaultPanel.add(defaultScrollpane, BorderLayout.CENTER)
AIPlog.isEditable = false
val AIPPanel = JPanel(BorderLayout())
val AIPscrollpane = JScrollPane(AIPlog)
AIPscrollpane.placeAt(0,300,800,300)
AIPPanel.add(AIPscrollpane, BorderLayout.CENTER)
logPane.addTab("Default",defaultPanel)
logPane.addTab("Debug",debugPanel)
logPane.addTab("AIP",AIPPanel)
return logPane
}
private fun Component.placeAt(x: Int, y: Int, width: Int, height: Int){
this.setBounds(x,y,width,height)
}
fun open() {
isVisible = true
Thread() {
while (true) {
SwingUtilities.invokeLater {
val removeList = ArrayList<GuiEvent>()
eventQueue.toTypedArray().forEach { event ->
when (event) {
is GuiEvent.UpdatePulseCount -> {
pulseCount.text = event.amount.toString()
pulseCountGraph.addValues(intArrayOf(event.amount).toList())
}
is GuiEvent.UpdateTickTime -> {
tickTime.text = event.time.toString() + "ms"
tickTimeGraph.addValues(intArrayOf(event.time.toInt()).toList())
}
is GuiEvent.AddDefaultMessage -> defaultLog.text = defaultLog.text + event.message + "\n"
is GuiEvent.AddAIPMessage -> AIPlog.text = AIPlog.text + event.message + "\n"
is GuiEvent.AddDebugMessage -> debugLog.text = debugLog.text + event.message + "\n"
is GuiEvent.UpdateQueuedPackets -> {
queuedPackets.text = event.amount.toString()
packetQueueGraph.addValues(intArrayOf(event.amount).toList())
}
}
removeList.add(event)
}
pulseList.text = GameWorld.Pulser.TASKS.toArray().filterNotNull().map { it.javaClass.simpleName + "\n" }
.filter { it.replace("\n", "").isNotEmpty() }.sorted().joinToString("")
eventQueue.removeAll(removeList)
repaint()
}
Thread.sleep(600L)
}
}.start()
}
}