Skip to content
Sciumo edited this page Oct 20, 2022 · 6 revisions

cpugraph_50msec

import { h, render } from "preact"
import { signal, Signal } from "preact/signals";
import { Process } from "System/Diagnostics"
import { Dom } from "OneJS/Dom";
import { useEffect, useRef } from "preact/hooks";
import { MeshGenerationContext, Painter2D } from "UnityEngine/UIElements";
import { Color, Vector2 } from "UnityEngine";
import { Style } from "preact/jsx";
import { GetCurrentProcess } from "Process"
import { DateTime, TimeSpan } from "System";
import { ProcessorCount } from "Environment"

export class PerformanceManager {
    /// timeout handle
    id?: number = null;
    /// timeout in milliseconds
    timeout = 1000;
    proc? : Process;

    data: Signal<number[]>;

    lastUsage : number;
    lastTime : number;

    procCount : number;

    constructor( public samples:number = 20 ) {
        this.data = signal<number[]>(new Array<number>(samples).fill(0));
        this.procCount = ProcessorCount;
        log(`proc count: ${this.procCount}`);
    }

    push( elem: number ) {
        // not efficient.
        const data = new Array(...this.data.value);
        data.shift();
        data.push(elem);
        this.data.value = data;
    }
    
    start() {
        if( this.id != null ) return;
        this.proc = GetCurrentProcess();
        if( this.proc != null ){
            this.lastTime = performance.now();  
            this.lastUsage = this.proc.TotalProcessorTime.TotalMilliseconds;
            this.id = setInterval( () => this.onUpdate(), this.timeout );
            return true;
        }else{
            log("GetCurrentProcess returned null");
            return false;
        }
    }

    getCPUUsage() : number {
        if( !this.proc ){
            return 0;
        }
        const p = this.proc;
        p.Refresh();
        var curTime = performance.now();
        var curUsage = p.TotalProcessorTime.TotalMilliseconds;
        var cpuUsedMs = curUsage - this.lastUsage;
        var totalMsPassed = curTime - this.lastTime;
        var cpuUsageTotal = cpuUsedMs / (this.procCount * totalMsPassed);
        this.lastUsage = curUsage;
        this.lastTime = curTime;
        let pct = (cpuUsageTotal * 100.0);
        log( pct );
        return pct;
    }
    stop() {
        if( this.id != null ){
            clearInterval( this.id );
            this.id = null;
            this.proc = null;
        }
    }
    onUpdate() {
        if( this.proc != null){
            this.push(this.getCPUUsage());
        }
    }
}

export const PERFMAN = new PerformanceManager(20);


export function DrawGrid( p2: Painter2D, w: number, h:number ){
    let div = 10;
    p2.strokeColor = Color.gray;
    p2.lineWidth = 1;
    p2.BeginPath();
    p2.MoveTo( new Vector2(0,0) );
    p2.LineTo( new Vector2(0,h) );
    p2.LineTo( new Vector2(w,h) );
    p2.LineTo( new Vector2(w,0) );
    p2.LineTo( new Vector2(0,0) );
    const dh = h/div;
    const dw = w/div;
    for( let ih = dh; ih < h; ih += dh ){
        p2.MoveTo( new Vector2(0,ih) );
        p2.LineTo( new Vector2(w,ih) );
    }
    for( let iw = dw; iw < w; iw += dw ){
        p2.MoveTo( new Vector2(iw,0) );
        p2.LineTo( new Vector2(iw,h) );
    }
    p2.Stroke();
}

interface GraphProps {
    data : Signal<number[]>
    style?: Style
    sample?: number
    minX? : number
    maxX? : number
    grid? : number
    lineWidth? :number;
}

const Graph = (props:GraphProps) => {
    const ref = useRef<Dom>()
    const data = props.data;
    const lw = props.lineWidth | 1;

    useEffect(() => {
        ref.current.ve.generateVisualContent = onGenerateVisualContent
    }, [])

    useEffect(() => {
        ref.current.ve.MarkDirtyRepaint()
    }, [data.value])

    function onGenerateVisualContent(mgc: MeshGenerationContext) {
        const d = data.value;
        var p2 = mgc.painter2D
        var rs = ref.current.ve.resolvedStyle;        
        var w: number = rs.width;
        var h:number = rs.height;
        var dw = w / d.length;
        DrawGrid(p2,w,h);
        p2.BeginPath()
        p2.strokeColor = Color.blue;
        p2.lineWidth = lw;

        for( let i = 0, iw = 0; i < d.length; i++, iw += dw ){
            let dh = h * (1.0 - (d[i] / 100.0));
            if( i == 0 ){
                p2.MoveTo( new Vector2(iw,dh) );
            }else{
                p2.LineTo( new Vector2(iw,dh) );
            }
        }
        p2.Stroke()
    }

    return <div id="graph" ref={ref} style={{...props.style}}>
    </div>
}

const Performance = (props:any) => {
    return (<div style={{...props.style, width: "275px", height: "300px" }} class="bg-white block p-6 rounded-lg shadow-lg max-w-sm">
        <h5 class="text-gray-900 text-xl leading-tight font-medium mb-2">CPU</h5>
        <Graph data={PERFMAN.data} lineWidth={5} style={{width:"100%", height:"100%"}}/>
       </div>)
  }
  
PERFMAN.start();

render(<Performance />, document.body)