MODULE WMPerfMonTabSystem;
IMPORT
Plugins := WMPerfMonPlugins, Perf := WMPerfMonComponents,
Machine, Heaps, Kernel, Commands, Streams, Dates, Strings, UpTime,
WMComponents, WMStandardComponents;
TYPE
SystemTab* = OBJECT(WMComponents.VisualComponent)
VAR
clockrate : LONGINT;
gcCurrentRun : Perf.Indicator;
line1, line2 : Perf.Indicator;
cpuClockrate : Perf.Indicator;
milliTimer : Kernel.MilliTimer;
lastTimestamp : HUGEINT;
lastGcCyclesAllRuns : HUGEINT;
lastNgc : LONGINT;
started : BOOLEAN;
startBtn : WMStandardComponents.Button;
elapsed : Perf.Indicator;
format : ARRAY 32 OF CHAR;
timeLabel, uptimeLabel : Perf.Indicator;
w : Streams.StringWriter;
unloadBtn : WMStandardComponents.Button;
timer : Kernel.Timer;
alive, dead : BOOLEAN;
PROCEDURE EstimateClockRate() : LONGINT;
CONST Tries = 10;
VAR
try : LONGINT; done : BOOLEAN; clockrate : LONGINT;
string, nbr : ARRAY 128 OF CHAR;
BEGIN
cpuClockrate.SetCaption(" CPU clock rate estimation...");
try := 1; done := FALSE; clockrate := -1;
WHILE ~done & (try <= Tries) DO
IF Plugins.EstimateCpuClockrate(clockrate) THEN
done := TRUE;
END;
INC(try);
END;
IF done THEN
string := " CPU clock rate is ";
Strings.IntToStr(clockrate, nbr); Strings.Append(string, nbr);
Strings.Append(string, "MHz (estimated)");
cpuClockrate.SetCaption(string);
ELSE
cpuClockrate.SetCaption(" CPU clock rate estimation failed");
END;
RETURN clockrate;
END EstimateClockRate;
PROCEDURE HandleGcButton(sender, data : ANY);
VAR
string, nbr : ARRAY 128 OF CHAR;
lastGcCyclesTot : HUGEINT;
w : Streams.StringWriter;
BEGIN
IF clockrate = -1 THEN clockrate := EstimateClockRate(); END;
lastGcCyclesTot := Heaps.NgcCyclesAllRuns;
Kernel.GC;
string := " Last run: ";
IF clockrate # -1 THEN
Plugins.MsToString(Plugins.CyclesToMs(Heaps.NgcCyclesLastRun, clockrate), nbr);
ELSE
nbr := "Clockrate unkown";
END;
Strings.Append(string, nbr);
gcCurrentRun.SetCaption(string);
NEW(w, 128);
w.String("GC Runs: "); w.Int(Heaps.Ngc, 0); w.String(" GC Total Time: ");
Plugins.MsToString(Plugins.CyclesToMs(Heaps.NgcCyclesAllRuns, clockrate), nbr); w.String(nbr);
w.String(" GC longest run: ");
Plugins.MsToString(Plugins.CyclesToMs(Heaps.NgcCyclesMax, clockrate), nbr); w.String(nbr);
w.Get(string);
line1.SetCaption(string);
w.Reset;
w.String("Mark phase: "); w.Int(Heaps.Nmarked, 0); w.String(" blocks marked in ");
Plugins.MsToString(Plugins.CyclesToMs(Heaps.NgcCyclesMark, clockrate), nbr); w.String(nbr);
w.String(" ("); w.Int(Heaps.Nmark, 0); w.String(" calls to Heaps.Mark)");
w.Get(string);
line2.SetCaption(string);
END HandleGcButton;
PROCEDURE HandleDetectButton(sender, data : ANY);
BEGIN
clockrate := EstimateClockRate();
END HandleDetectButton;
PROCEDURE HandleTimerButton(sender, data : ANY);
VAR string, nbr : ARRAY 128 OF CHAR; msTicks, msTimestamp, msGc, msDiff : LONGINT;
BEGIN
IF clockrate = -1 THEN clockrate := EstimateClockRate(); END;
IF started THEN
started := FALSE; startBtn.caption.SetAOC("Start");
string := " Time elapsed: ";
msTicks := Kernel.Elapsed(milliTimer);
msTimestamp := Plugins.CyclesToMs(Machine.GetTimer() - lastTimestamp, clockrate);
Plugins.MsToString(msTicks, nbr);
Strings.Append(string, nbr); Strings.Append(string, " (Ticks), ");
Plugins.MsToString(msTimestamp ,nbr);
Strings.Append(string, nbr); Strings.Append(string, " (Timestamps), ");
Strings.Append(string, "TimeDiff: ");
msDiff := msTimestamp - msTicks; IF msDiff < 0 THEN msDiff := -msDiff; END;
Plugins.MsToString(msDiff, nbr);
Strings.Append(string, nbr);
Strings.Append(string, ", GC Time: ");
msGc := Plugins.CyclesToMs(Heaps.NgcCyclesAllRuns - lastGcCyclesAllRuns, clockrate);
Plugins.MsToString(msGc, nbr); Strings.Append(string, nbr);
Strings.Append(string, ", GC Runs: ");
Strings.IntToStr(Heaps.Ngc - lastNgc, nbr); Strings.Append(string, nbr);
elapsed.SetCaption(string);
ELSE
started := TRUE; startBtn.caption.SetAOC("Stop");
Kernel.SetTimer(milliTimer, 0);
lastTimestamp := Machine.GetTimer();
lastGcCyclesAllRuns := Heaps.NgcCyclesAllRuns;
lastNgc := Heaps.Ngc;
elapsed.SetCaption(" Timer is running...");
END;
END HandleTimerButton;
PROCEDURE HandleUnloadButton(sender, data : ANY);
VAR msg : ARRAY 128 OF CHAR; res : LONGINT;
BEGIN
Commands.Call("SystemTools.FreeDownTo WMPerfMonPlugins", {}, res, msg);
END HandleUnloadButton;
PROCEDURE CreateSysinfoPanel() : WMStandardComponents.Panel;
VAR
panel, line : WMStandardComponents.Panel; label : WMStandardComponents.Label;
caption : ARRAY 128 OF CHAR;
PROCEDURE AppendBoolean(VAR string : ARRAY OF CHAR; value : BOOLEAN);
BEGIN
IF value THEN
Strings.Append(string, "Yes");
ELSE
Strings.Append(string, "No");
END;
END AppendBoolean;
BEGIN
panel := Perf.NewGroupPanel("System Information", WMComponents.AlignTop, 100);
line := Perf.NewPanel(WMComponents.AlignTop, 0, Perf.LineHeight); panel.AddContent(line);
label := Perf.NewLabel("Version:", WMComponents.AlignLeft, 100, 0); line.AddContent(label);
label := Perf.NewLabel(Machine.version, WMComponents.AlignClient, 0, 0); line.AddContent(label);
line := Perf.NewPanel(WMComponents.AlignTop, 0, Perf.LineHeight); panel.AddContent(line);
label := Perf.NewLabel("System Time:", WMComponents.AlignLeft, 100, 0); line.AddContent(label);
timeLabel := Perf.NewIndicator("--", WMComponents.AlignClient, 0, 0); line.AddContent(timeLabel);
line := Perf.NewPanel(WMComponents.AlignTop, 0, Perf.LineHeight); panel.AddContent(line);
label := Perf.NewLabel("Start Time: ", WMComponents.AlignLeft, 100, 0); line.AddContent(label);
Strings.FormatDateTime(format, UpTime.GetStartTime(), caption);
label := Perf.NewLabel(caption, WMComponents.AlignLeft, 210, 0); line.AddContent(label);
uptimeLabel := Perf.NewIndicator("--", WMComponents.AlignClient, 0, 0); line.AddContent(uptimeLabel);
line := Perf.NewPanel(WMComponents.AlignTop, 0, Perf.LineHeight); panel.AddContent(line);
label := Perf.NewLabel("Capabilities:", WMComponents.AlignLeft, 100, 0); line.AddContent(label);
caption := "MMX: "; AppendBoolean(caption, Machine.MMX IN Machine.features);
Strings.Append(caption, ", SSE: "); AppendBoolean(caption, Machine.SSESupport);
Strings.Append(caption, ", SSE2: "); AppendBoolean(caption, Machine.SSE2Support);
label := Perf.NewLabel(caption, WMComponents.AlignClient, 0, 0); line.AddContent(label);
RETURN panel;
END CreateSysinfoPanel;
PROCEDURE CreateGcStatisticsPanel() : WMStandardComponents.Panel;
VAR panel : WMStandardComponents.Panel; line : WMStandardComponents.Panel;
BEGIN
panel := Perf.NewGroupPanel("Garbage Collector", WMComponents.AlignTop, 80);
line := Perf.NewPanel(WMComponents.AlignTop, 0, 20); panel.AddContent(line);
line.AddContent(Perf.NewButton("Run GC", HandleGcButton));
gcCurrentRun := Perf.NewIndicator("", WMComponents.AlignClient, 0, 0);
line.AddContent(gcCurrentRun);
line1 := Perf.NewIndicator("", WMComponents.AlignTop, 0, 20); panel.AddContent(line1);
line2 := Perf.NewIndicator("", WMComponents.AlignTop, 0, 20); panel.AddContent(line2);
RETURN panel;
END CreateGcStatisticsPanel;
PROCEDURE CreateCPUClockratePanel() : WMStandardComponents.Panel;
VAR panel : WMStandardComponents.Panel;
BEGIN
panel := Perf.NewGroupPanel("CPU Clockrate", WMComponents.AlignTop, 45);
panel.AddContent(Perf.NewButton("Detect", HandleDetectButton));
cpuClockrate := Perf.NewIndicator(" Press button to detect CPU clockrate", WMComponents.AlignClient, 0, 0);
panel.AddContent(cpuClockrate);
RETURN panel;
END CreateCPUClockratePanel;
PROCEDURE CreateTimerPanel() : WMStandardComponents.Panel;
VAR panel : WMStandardComponents.Panel;
BEGIN
panel := Perf.NewGroupPanel("Timers", WMComponents.AlignTop, 45);
startBtn := Perf.NewButton("Start", HandleTimerButton); panel.AddContent(startBtn);
elapsed := Perf.NewIndicator(" Press button to start time...", WMComponents.AlignClient, 0, 0); panel.AddContent(elapsed);
RETURN panel;
END CreateTimerPanel;
PROCEDURE CreateUnloadPanel() : WMStandardComponents.Panel;
VAR panel : WMStandardComponents.Panel;
BEGIN
panel := Perf.NewGroupPanel("Performance Monitoring", WMComponents.AlignTop, 45);
unloadBtn := Perf.NewButton("Unload", HandleUnloadButton); panel.AddContent(unloadBtn);
panel.AddContent(Perf.NewLabel(" Window close button just closes GUI. This closes all.", WMComponents.AlignClient, 0, 0));
RETURN panel;
END CreateUnloadPanel;
PROCEDURE UpdateTime;
VAR caption : ARRAY 64 OF CHAR;
BEGIN
Strings.FormatDateTime(format, Dates.Now(), caption);
timeLabel.SetCaption(caption);
w.Reset;
w.String(" (Uptime: "); UpTime.ToStream(w); w.Char(")");
w.Get(caption);
uptimeLabel.SetCaption(caption);
END UpdateTime;
PROCEDURE Finalize*;
BEGIN
alive := FALSE;
timer.Wakeup;
BEGIN {EXCLUSIVE} AWAIT(dead); END;
Finalize^;
END Finalize;
PROCEDURE &Init*;
BEGIN
Init^;
SetNameAsString(StrSystemTab);
NEW(timer); alive := TRUE; dead := FALSE;
NEW(w, 64);
format := "hh:nn:ss, wwww, mmmm d, yyyy";
clockrate := -1;
AddContent(CreateSysinfoPanel());
AddContent(CreateCPUClockratePanel());
AddContent(CreateGcStatisticsPanel());
AddContent(CreateTimerPanel());
AddContent(CreateUnloadPanel());
END Init;
BEGIN {ACTIVE}
WHILE alive DO
IF visible.Get() THEN UpdateTime; END;
timer.Sleep(500);
END;
BEGIN {EXCLUSIVE} dead := TRUE; END;
END SystemTab;
VAR
StrSystemTab : Strings.String;
BEGIN
StrSystemTab := Strings.NewString("SystemTab");
END WMPerfMonTabSystem.