2024-07-11 19:32:12 +02:00
Highcharts . setOptions ( {
chart : {
animation : false
} ,
plotOptions : {
series : {
animation : false
}
}
} ) ;
2024-07-11 19:29:14 +02:00
var colors = Highcharts . getOptions ( ) . colors ;
function getLineChartOptions ( title , description , unit , maxY = null ) {
return {
chart : {
type : 'line' ,
backgroundColor : null , // Set background to transparent
style : {
color : '#FFFFFF'
} ,
zooming : {
type : 'x'
}
} ,
title : {
text : title ,
style : {
color : '#FFFFFF' ,
fontSize : '16px'
}
} ,
subtitle : {
text : description ,
style : {
color : '#FFFFFF' ,
fontSize : '12px'
}
} ,
xAxis : {
lineColor : '#FFFFFF' ,
tickColor : '#FFFFFF' ,
labels : {
enabled : false
}
} ,
yAxis : {
title : {
text : null
} ,
labels : {
formatter : function ( ) {
return this . value . toFixed ( 2 ) + ' ' + unit ;
} ,
style : {
color : '#FFFFFF'
}
} ,
gridLineColor : 'rgba(255, 255, 255, 0.1)' ,
max : maxY
} ,
legend : {
align : 'center' ,
verticalAlign : 'bottom' ,
itemStyle : {
color : '#FFFFFF'
}
} ,
tooltip : {
shared : false ,
pointFormat : '<span style="color:{series.color}">{series.name}</span>: <b>{point.y:.2f} ' + unit + '</b><br/>' , // Include unit in tooltip
backgroundColor : '#1E1E1E' ,
borderColor : '#FFFFFF' ,
style : {
color : '#FFFFFF'
}
} ,
plotOptions : {
line : {
marker : {
enabled : false ,
symbol : 'circle' ,
lineColor : null ,
radius : 1.5 ,
states : {
hover : {
enabled : true ,
}
}
} ,
lineWidth : 1 ,
animation : false
}
} ,
credits : {
enabled : false
} ,
series : [ ] ,
exporting : {
buttons : {
contextButton : {
menuItems : [
'viewFullscreen' ,
'printChart' ,
'separator' ,
'downloadPNG' ,
'downloadJPEG' ,
'downloadPDF' ,
'downloadSVG' ,
'separator' ,
'downloadCSV' ,
'downloadXLS'
]
}
}
}
} ;
}
function getBarChartOptions ( title , unit , maxY = null ) {
return {
chart : {
type : 'bar' ,
backgroundColor : null , // Set background to transparent
style : {
color : '#FFFFFF'
}
} ,
title : {
text : title ,
style : {
color : '#FFFFFF' ,
fontSize : '16px'
}
} ,
xAxis : {
categories : [ ] ,
title : {
text : null
} ,
labels : {
style : {
color : '#FFFFFF'
}
}
} ,
yAxis : {
min : 0 ,
max : maxY ,
title : {
text : unit ,
align : 'high' ,
style : {
color : '#FFFFFF'
}
} ,
labels : {
overflow : 'justify' ,
style : {
color : '#FFFFFF'
} ,
formatter : function ( ) {
return this . value . toFixed ( 2 ) + ' ' + unit ;
}
} ,
gridLineColor : 'rgba(255, 255, 255, 0.1)'
} ,
tooltip : {
valueSuffix : ' ' + unit ,
backgroundColor : '#1E1E1E' ,
borderColor : '#FFFFFF' ,
style : {
color : '#FFFFFF'
} ,
formatter : function ( ) {
return '<b>' + this . point . category + '</b>: ' + this . y . toFixed ( 2 ) + ' ' + unit ;
}
} ,
plotOptions : {
bar : {
dataLabels : {
enabled : true ,
style : {
color : '#FFFFFF'
} ,
formatter : function ( ) {
return this . y . toFixed ( 2 ) + ' ' + unit ;
}
}
}
} ,
legend : {
enabled : false , // Disable legend
} ,
credits : {
enabled : false
} ,
series : [ ]
} ;
}
function createChart ( chartId , title , description , unit , dataArrays , maxY = null ) {
var options = getLineChartOptions ( title , description , unit , maxY ) ;
options . series = dataArrays . map ( function ( dataArray , index ) {
return { name : dataArray . label , data : dataArray . data , color : colors [ index % colors . length ] } ;
} ) ;
Highcharts . chart ( chartId , options ) ;
}
function createBarChart ( chartId , title , unit , categories , data , colors , maxY = null ) {
var options = getBarChartOptions ( title , unit , maxY ) ;
options . xAxis . categories = categories ;
options . series = [ {
name : title ,
data : data ,
colorByPoint : true ,
colors : colors
} ] ;
Highcharts . chart ( chartId , options ) ;
}
function calculateAverage ( data ) {
const sum = data . reduce ( ( acc , value ) => acc + value , 0 ) ;
return sum / data . length ;
}
function calculatePercentile ( data , percentile ) {
data . sort ( ( a , b ) => a - b ) ;
const index = Math . ceil ( percentile / 100 * data . length ) - 1 ;
return data [ index ] ;
}
// Create line charts
createChart ( 'fpsChart' , 'FPS' , 'More is better' , 'fps' , fpsDataArrays ) ;
createChart ( 'frameTimeChart' , 'Frametime' , 'Less is better' , 'ms' , frameTimeDataArrays ) ;
createChart ( 'cpuLoadChart' , 'CPU Load' , '' , '%' , cpuLoadDataArrays , 100 ) ;
createChart ( 'gpuLoadChart' , 'GPU Load' , '' , '%' , gpuLoadDataArrays , 100 ) ;
createChart ( 'cpuTempChart' , 'CPU Temperature' , '' , '°C' , cpuTempDataArrays ) ;
createChart ( 'gpuTempChart' , 'GPU Temperature' , '' , '°C' , gpuTempDataArrays ) ;
createChart ( 'gpuCoreClockChart' , 'GPU Core Clock' , '' , 'MHz' , gpuCoreClockDataArrays ) ;
createChart ( 'gpuMemClockChart' , 'GPU Memory Clock' , '' , 'MHz' , gpuMemClockDataArrays ) ;
createChart ( 'gpuVRAMUsedChart' , 'GPU VRAM Usage' , '' , '%' , gpuVRAMUsedDataArrays , 100 ) ;
createChart ( 'gpuPowerChart' , 'GPU Power' , '' , 'W' , gpuPowerDataArrays ) ;
createChart ( 'ramUsedChart' , 'RAM Usage' , '' , 'GB' , ramUsedDataArrays ) ;
createChart ( 'swapUsedChart' , 'SWAP Usage' , '' , 'GB' , swapUsedDataArrays ) ;
// Calculate average CPU and GPU load
var cpuLoadAverages = cpuLoadDataArrays . map ( function ( dataArray ) {
return calculateAverage ( dataArray . data ) ;
} ) ;
var gpuLoadAverages = gpuLoadDataArrays . map ( function ( dataArray ) {
return calculateAverage ( dataArray . data ) ;
} ) ;
// Create bar charts for average CPU and GPU load
createBarChart ( 'cpuLoadSummaryChart' , 'Average CPU Load' , '%' , cpuLoadDataArrays . map ( function ( dataArray ) { return dataArray . label ; } ) , cpuLoadAverages , colors , 100 ) ;
createBarChart ( 'gpuLoadSummaryChart' , 'Average GPU Load' , '%' , gpuLoadDataArrays . map ( function ( dataArray ) { return dataArray . label ; } ) , gpuLoadAverages , colors , 100 ) ;
// Calculate and render min, max, and average FPS
var categories = [ ] ;
var minFPSData = [ ] ;
var avgFPSData = [ ] ;
var maxFPSData = [ ] ;
fpsDataArrays . forEach ( function ( dataArray ) {
var minFPS = calculatePercentile ( dataArray . data , 1 ) ;
var avgFPS = calculateAverage ( dataArray . data ) ;
var maxFPS = calculatePercentile ( dataArray . data , 97 ) ;
categories . push ( dataArray . label ) ;
minFPSData . push ( minFPS ) ;
avgFPSData . push ( avgFPS ) ;
maxFPSData . push ( maxFPS ) ;
} ) ;
Highcharts . chart ( 'minMaxAvgChart' , {
chart : {
type : 'bar' ,
backgroundColor : null
} ,
title : {
text : 'Min/Avg/Max FPS' ,
style : {
color : '#FFFFFF' ,
fontSize : '16px'
}
} ,
subtitle : {
text : 'More is better' ,
style : {
color : '#FFFFFF'
}
} ,
xAxis : {
categories : categories ,
title : {
text : null
} ,
labels : {
style : {
color : '#FFFFFF'
}
}
} ,
yAxis : {
min : 0 ,
title : {
text : 'FPS' ,
align : 'high' ,
style : {
color : '#FFFFFF'
}
} ,
labels : {
overflow : 'justify' ,
style : {
color : '#FFFFFF'
}
} ,
gridLineColor : 'rgba(255, 255, 255, 0.1)'
} ,
tooltip : {
valueSuffix : ' FPS' ,
backgroundColor : '#1E1E1E' ,
borderColor : '#FFFFFF' ,
style : {
color : '#FFFFFF'
} ,
formatter : function ( ) {
return '<b>' + this . series . name + '</b>: ' + this . y . toFixed ( 2 ) + ' FPS' ;
}
} ,
plotOptions : {
bar : {
dataLabels : {
enabled : true ,
style : {
color : '#FFFFFF'
} ,
formatter : function ( ) {
return this . y . toFixed ( 2 ) + ' fps' ;
}
}
}
} ,
legend : {
reversed : true ,
itemStyle : {
color : '#FFFFFF'
}
} ,
credits : {
enabled : false
} ,
series : [ {
name : '97th' ,
data : maxFPSData ,
color : '#00FF00'
} , {
name : 'AVG' ,
data : avgFPSData ,
color : '#0000FF'
} , {
name : '1%' ,
data : minFPSData ,
color : '#FF0000'
} ]
} ) ;
// Calculate average FPS for each filename
var avgFPSData = fpsDataArrays . map ( function ( dataArray ) {
return calculateAverage ( dataArray . data ) ;
} ) ;
// Calculate FPS as a percentage of the first element
var firstFPS = avgFPSData [ 0 ] ;
var percentageFPSData = avgFPSData . map ( function ( fps ) {
return ( fps / firstFPS ) * 100 ;
} ) ;
// Create bar chart for FPS percentage
Highcharts . chart ( 'avgChart' , {
chart : {
type : 'bar' ,
backgroundColor : null
} ,
title : {
text : 'Average FPS in %' ,
style : {
color : '#FFFFFF' ,
fontSize : '16px'
}
} ,
xAxis : {
categories : fpsDataArrays . map ( function ( dataArray ) { return dataArray . label ; } ) ,
title : {
text : null
} ,
labels : {
style : {
color : '#FFFFFF'
}
}
} ,
yAxis : {
min : 0 ,
title : {
text : 'Percentage (%)' ,
align : 'high' ,
style : {
color : '#FFFFFF'
}
} ,
labels : {
overflow : 'justify' ,
style : {
color : '#FFFFFF'
}
} ,
gridLineColor : 'rgba(255, 255, 255, 0.1)'
} ,
tooltip : {
valueSuffix : ' %' ,
backgroundColor : '#1E1E1E' ,
borderColor : '#FFFFFF' ,
style : {
color : '#FFFFFF'
} ,
formatter : function ( ) {
return '<b>' + this . point . category + '</b>: ' + this . y . toFixed ( 2 ) + ' %' ;
}
} ,
plotOptions : {
bar : {
dataLabels : {
enabled : true ,
style : {
color : '#FFFFFF'
} ,
formatter : function ( ) {
return this . y . toFixed ( 2 ) + ' %' ;
}
}
}
} ,
legend : {
enabled : false
} ,
credits : {
enabled : false
} ,
series : [ {
name : 'FPS Percentage' ,
data : percentageFPSData ,
colorByPoint : true ,
colors : colors
} ]
} ) ;
function calculateSpikes ( data , threshold ) {
if ( data . length < 6 ) {
throw new Error ( "Data length must be greater than or equal to 6." ) ;
}
let spikeCount = 0 ;
// Helper function to calculate the moving average with a minimum of 6 points
function movingAverage ( arr , index ) {
const windowSize = Math . max ( 6 , Math . ceil ( arr . length * 0.05 ) ) ; // 5 % of the data
const halfWindowSize = Math . floor ( windowSize / 2 ) ;
const start = Math . max ( 0 , index - halfWindowSize ) ;
const end = Math . min ( arr . length - 1 , index + halfWindowSize ) ;
const actualWindowSize = end - start + 1 ;
let sum = 0 ;
for ( let i = start ; i <= end ; i ++ ) {
sum += arr [ i ] ;
}
return sum / actualWindowSize ;
}
for ( let i = 0 ; i < data . length ; i ++ ) {
const currentPoint = data [ i ] ;
const movingAvg = movingAverage ( data , i ) ;
const change = Math . abs ( currentPoint - movingAvg ) / movingAvg * 100 ;
if ( change > threshold ) {
spikeCount ++ ;
}
}
return ( spikeCount / data . length ) * 100 ;
}
function updateSpikesChart ( threshold ) {
document . getElementById ( 'spikeThresholdValue' ) . innerText = threshold + '%' ;
var spikePercentages = fpsDataArrays . map ( function ( dataArray ) {
return calculateSpikes ( dataArray . data , threshold ) ;
} ) ;
Highcharts . chart ( 'spikesChart' , {
chart : {
type : 'bar' ,
backgroundColor : null
} ,
title : {
text : 'FPS Spikes' ,
style : {
color : '#FFFFFF' ,
fontSize : '16px'
}
} ,
subtitle : {
text : 'Less is better' ,
style : {
color : '#FFFFFF' ,
fontSize : '12px'
}
} ,
xAxis : {
categories : categories ,
title : {
text : null
} ,
labels : {
style : {
color : '#FFFFFF'
}
}
} ,
yAxis : {
min : 0 ,
title : {
text : 'Percentage (%)' ,
align : 'high' ,
style : {
color : '#FFFFFF'
}
} ,
labels : {
overflow : 'justify' ,
style : {
color : '#FFFFFF'
}
} ,
gridLineColor : 'rgba(255, 255, 255, 0.1)'
} ,
tooltip : {
valueSuffix : ' %' ,
backgroundColor : '#1E1E1E' ,
borderColor : '#FFFFFF' ,
style : {
color : '#FFFFFF'
} ,
formatter : function ( ) {
return '<b>' + this . point . category + '</b>: ' + this . y . toFixed ( 2 ) + ' %' ;
}
} ,
plotOptions : {
bar : {
dataLabels : {
enabled : true ,
style : {
color : '#FFFFFF'
} ,
formatter : function ( ) {
return this . y . toFixed ( 2 ) + ' %' ;
}
}
}
} ,
legend : {
enabled : false
} ,
credits : {
enabled : false
} ,
series : [ {
name : 'Spike Percentage' ,
data : spikePercentages ,
colorByPoint : true ,
colors : colors
} ]
} ) ;
}
// Initial render of spikes chart
updateSpikesChart ( document . getElementById ( 'spikeThreshold' ) . value ) ;