|
|
DataMuseum.dkPresents historical artifacts from the history of: Rational R1000/400 Tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Rational R1000/400 Tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: B T
Length: 19435 (0x4beb)
Types: TextFile
Names: »B«
└─⟦180fe333a⟧ Bits:30000405 8mm tape, Rational 1000, SW CATALOG, 10_20_0
└─⟦180fe333a⟧ Bits:30000537 8mm tape, Rational 1000, SW Catalog 10_20_0
└─⟦5cb1d1d7f⟧ »DATA«
└─⟦3b1ee7bd8⟧
└─⟦this⟧
with Transport_Name;
with Context;
--
with Calendar;
with Debug_Tools;
with Compilation;
with Direct_Io;
with Disk_Daemon;
with Io;
with Log;
with Profile;
with Scheduler;
with System_Utilities;
with Table_Formatter;
with Time_Utilities;
package body Performance is
-------------------------------------------------------------------------------
-- Constants
The_Unit_To_Demote_And_Promote : constant String :=
Context & ".the_null_procedure";
File_Wait : constant Duration := 10.0;
-------------------------------------------------------------------------------
-- Renaming and Instantiation
package Dd renames Disk_Daemon;
package Su renames System_Utilities;
package Tu renames Time_Utilities;
package Dio is new Direct_Io (Performance_Record);
function "+" (X, Y : Dio.Count) return Dio.Count renames Dio."+";
function "=" (X, Y : Tu.Time) return Boolean renames Tu."=";
-------------------------------------------------------------------------------
function Time_Stamp (Of_Entry : Performance_Record)
return Time_Utilities.Time is
begin
return Of_Entry.The_Time;
end Time_Stamp;
function Disk_Q_Load (Of_Entry : Performance_Record) return Natural is
begin
return Of_Entry.The_Disk_Wait_Load;
end Disk_Q_Load;
function Run_Q_Load (Of_Entry : Performance_Record) return Natural is
begin
return Of_Entry.The_Run_Queue_Load;
end Run_Q_Load;
function Job_Cpu_Time (Of_Entry : Performance_Record) return Duration is
begin
return Of_Entry.The_Demote_Promote_Cpu;
end Job_Cpu_Time;
function Job_Elapsed_Time (Of_Entry : Performance_Record) return Duration is
begin
return Of_Entry.The_Demote_Promote_Elapsed;
end Job_Elapsed_Time;
function Available_Disk_Space
(Of_Entry : Performance_Record) return Natural is
begin
return Of_Entry.The_Unused_Disk_Space;
end Available_Disk_Space;
function Gc_Running (Of_Entry : Performance_Record) return Boolean is
begin
return Of_Entry.The_Gc_Running;
end Gc_Running;
function Active_Sessions (Of_Entry : Performance_Record) return Natural is
begin
return Of_Entry.The_Active_Session_Count;
end Active_Sessions;
function Within_Time_Span
(The_Time, The_Start, The_End : Tu.Time) return Boolean is
use Calendar;
T_Time : Calendar.Time := Tu.Convert_Time (The_Time);
T_Start : Calendar.Time := Tu.Convert_Time (The_Start);
T_End : Calendar.Time := Tu.Convert_Time (The_End);
begin
return T_Time >= T_Start and T_Time <= T_End;
end Within_Time_Span;
function Get_Entries (Starting_At : Time_Utilities.Time;
Ending_At : Time_Utilities.Time;
From_File : String) return Iterator is
The_Current_Record : Performance_Record;
The_Datafile : Dio.File_Type;
File_Index : Dio.Count;
Result : Iterator := Nil;
The_Start_Time : Time_Utilities.Time := Starting_At;
The_End_Time : Time_Utilities.Time := Ending_At;
begin
loop
Open_Datafile:
begin
Dio.Open (The_Datafile, Dio.In_File, From_File);
exit;
exception
when Dio.Use_Error =>
delay File_Wait;
end Open_Datafile;
end loop;
File_Index := Dio.Size (The_Datafile);
for I in reverse 1 .. File_Index loop
Dio.Read (The_Datafile, The_Current_Record, I);
if Within_Time_Span (The_Current_Record.The_Time,
The_Start_Time, The_End_Time) then
Result := Make (The_Current_Record, Result);
end if;
end loop;
Dio.Close (The_Datafile);
return Result;
exception
when Dio.Name_Error =>
Log.Put_Line ("Unable to locate data file '" & From_File & "'",
Profile.Error_Msg);
end Get_Entries;
function Value (Iter : Iterator) return Performance_Record is
begin
return First (Iter);
end Value;
function Done (Iter : Iterator) return Boolean is
begin
return Length (Iter) = 0;
end Done;
procedure Next (Iter : in out Iterator) is
begin
Iter := Rest (Iter);
end Next;
-------------------------------------------------------------------------------
-- Returns the 15 minutes Disk Wait Load
function Disk_Wait_Load return Scheduler.Load_Factor is
The_Last_Sample,
The_Last_Minute,
The_Last_5_Minutes,
The_Last_15_Minutes : Scheduler.Load_Factor;
begin
Scheduler.Get_Disk_Wait_Load (The_Last_Sample, The_Last_Minute,
The_Last_5_Minutes, The_Last_15_Minutes);
return The_Last_15_Minutes;
end Disk_Wait_Load;
-------------------------------------------------------------------------------
-- Returns the 15 minutes Run Queue Load
function Run_Queue_Load return Scheduler.Load_Factor is
The_Last_Sample,
The_Last_Minute,
The_Last_5_Minutes,
The_Last_15_Minutes : Scheduler.Load_Factor;
begin
Scheduler.Get_Run_Queue_Load (The_Last_Sample, The_Last_Minute,
The_Last_5_Minutes, The_Last_15_Minutes);
return The_Last_15_Minutes;
end Run_Queue_Load;
-------------------------------------------------------------------------------
-- Returns the time to demote and promote a null procedure
procedure Demote_Promote (Cpu_Time : out Duration;
Elapsed_Time : out Duration) is
The_Result_Cpu : Duration := Su.Cpu;
The_Result_Elapsed : Duration := Su.Elapsed;
begin
Compilation.Demote (Unit => The_Unit_To_Demote_And_Promote,
Response => "<QUIET>");
Compilation.Make (Unit => The_Unit_To_Demote_And_Promote,
Response => "<QUIET>");
The_Result_Cpu := Su.Cpu - The_Result_Cpu;
The_Result_Elapsed := Su.Elapsed - The_Result_Elapsed;
Cpu_Time := The_Result_Cpu;
Elapsed_Time := The_Result_Elapsed;
end Demote_Promote;
-------------------------------------------------------------------------------
-- Returns the unused disk space in number of 1kB pages
function Unused_Disk_Space return Natural is
The_Space_Unused : Natural := 0;
begin
for Volume in Dd.Volume_Number loop
if Dd.Exists (Volume) then
The_Space_Unused := The_Space_Unused +
Dd.Unused_Capacity (Volume);
end if;
end loop;
return The_Space_Unused;
end Unused_Disk_Space;
-------------------------------------------------------------------------------
-- returns the number of active sessions
function Session_Count return Natural is
Iter : Su.Session_Iterator;
Session_Count : Natural := 0;
begin
Su.Init (Iter);
while not Su.Done (Iter) loop
Session_Count := Session_Count + 1;
Su.Next (Iter);
end loop;
return Session_Count;
end Session_Count;
-------------------------------------------------------------------------------
-- Monitor program
procedure Monitor (Interval : Duration := 15 * 60.0;
Data_File : String := "performance_data") is
The_Datafilename : constant String := Context & "." & Data_File;
The_Datafile : Dio.File_Type;
Dp_Cpu_Time : Duration;
Dp_Elapsed_Time : Duration;
begin
loop
Demote_Promote (Dp_Cpu_Time, Dp_Elapsed_Time);
Open_Datafile:
loop
begin
Dio.Open (The_Datafile, Dio.Out_File, The_Datafilename);
exit Open_Datafile;
exception
when Dio.Use_Error =>
delay File_Wait;
when Dio.Name_Error =>
Dio.Create (The_Datafile, Dio.Out_File,
The_Datafilename);
Dio.Close (The_Datafile);
end;
end loop Open_Datafile;
Dio.Write (The_Datafile,
Performance_Record'
(Tu.Get_Time, Disk_Wait_Load, Run_Queue_Load,
Dp_Cpu_Time, Dp_Elapsed_Time, Unused_Disk_Space,
Dd.Garbage_Collector_Is_Running, Session_Count),
Dio.Size (The_Datafile) + 1);
Dio.Close (The_Datafile);
delay Interval;
end loop;
end Monitor;
-------------------------------------------------------------------------------
-- Report programs
function Image (Load_Factor : Scheduler.Load_Factor) return String is
type Q_Load_Factor is digits 3;
package Fio is new Io.Float_Io (Q_Load_Factor);
The_Image : String (1 .. 5);
F : Q_Load_Factor := Q_Load_Factor (Load_Factor) / 100.0;
begin
Fio.Put (The_Image, F, 2, 0);
return The_Image;
end Image;
procedure Put_Header (Report_Type : String; To_File : Io.File_Type) is
begin
Io.Put_Line (To_File, Time_Utilities.Image (Time_Utilities.Get_Time));
Io.Put_Line (To_File, Report_Type & " generated for " &
Transport_Name.Local_Host_Name ("tcp/ip"));
end Put_Header;
procedure Report (Start_Date : String := "";
End_Date : String := "";
Output : String := "";
Data_File : String := "performance_data") is
package Tf is new Table_Formatter (6, "/");
The_Datafilename : constant String := Context & "." & Data_File;
The_Datafile : Dio.File_Type;
The_Start_Time,
The_End_Time : Tu.Time;
The_Output_File : Io.File_Type;
The_Current_Record,
The_Previous_Record : Performance_Record :=
Performance_Record'(The_Time => Tu.Nil,
The_Disk_Wait_Load => 0,
The_Run_Queue_Load => 0,
The_Demote_Promote_Cpu => 0.0,
The_Demote_Promote_Elapsed => 0.0,
The_Unused_Disk_Space => 0,
The_Gc_Running => False,
The_Active_Session_Count => 0);
Iter : Iterator;
begin
if Start_Date = "" then
The_Start_Time := Tu.Value ("60/01/11 16:15:00");
else
The_Start_Time := Tu.Value (Start_Date);
end if;
if End_Date = "" then
The_End_Time := Tu.Get_Time;
else
The_End_Time := Tu.Value (End_Date);
end if;
Iter := Get_Entries (The_Start_Time, The_End_Time, The_Datafilename);
Tf.Header ("Time", Tf.Right);
Tf.Header ("DWL / RQL", Tf.Right);
Tf.Header ("Disk", Tf.Right);
Tf.Header ("DP: Cpu / Elap", Tf.Right);
Tf.Header ("Users", Tf.Right);
Tf.Header ("GC", Tf.Centered);
The_Previous_Record.The_Unused_Disk_Space := 0;
while not Done (Iter) loop
The_Current_Record := Value (Iter);
if Time_Stamp (The_Previous_Record) /= Tu.Nil then
Tf.Item (Tu.Image (Time_Stamp (The_Current_Record),
Tu.Year_Month_Day, Tu.Military));
Tf.Subitem (Image (Disk_Q_Load (The_Current_Record)));
Tf.Subitem (Image (Run_Q_Load (The_Current_Record)));
Tf.Last_Subitem;
declare
The_Consumed_Space : Integer :=
Available_Disk_Space (The_Previous_Record) -
Available_Disk_Space (The_Current_Record);
begin
if The_Consumed_Space < 0 then
Tf.Item ("0");
else
Tf.Item (Integer'Image (The_Consumed_Space));
end if;
end;
Tf.Subitem (Tu.Image (Tu.Convert
(Job_Cpu_Time (The_Current_Record))));
Tf.Subitem (Tu.Image (Tu.Convert (Job_Elapsed_Time
(The_Current_Record))));
Tf.Last_Subitem;
Tf.Item (Natural'Image (Active_Sessions (The_Current_Record)));
if Gc_Running (The_Current_Record) then
Tf.Item ("*");
else
Tf.Item ("");
end if;
end if;
The_Previous_Record := The_Current_Record;
Next (Iter);
end loop;
if Output /= "" then
Io.Create (The_Output_File, Io.Out_File, Output);
Put_Header ("Detailed Performance Report", The_Output_File);
Io.New_Line (The_Output_File);
Tf.Display (The_Output_File);
Io.Close (The_Output_File);
else
Put_Header ("Detailed Performance Report", Io.Current_Output);
Io.New_Line (Io.Current_Output);
Tf.Display (Io.Current_Output);
end if;
exception
when others =>
Log.Put_Line (Debug_Tools.Get_Exception_Name (True, True),
Profile.Exception_Msg);
end Report;
procedure Weekly_Report (Week_Of : String := ">>MONDAY'S DATE<<";
Start_Time : String := "9:00:00";
End_Time : String := "17:00:00";
Output : String := "";
Weekend_Too : Boolean := False;
Data_File : String := "performance_data") is
use Time_Utilities;
The_Datafilename : constant String := Context & "." & Data_File;
The_Datafile : Dio.File_Type;
Monday, The_Start_Time,
The_End_Time : Tu.Time;
The_Output_File : Io.File_Type;
The_Current_Record : Performance_Record;
package Tf is new Table_Formatter (7);
Iter : Iterator;
begin
Monday := Tu.Value (Week_Of);
if Tu.Day_Of_Week (Monday) /= Tu.Weekday'First then
Io.Put_Line (Week_Of & " is not a Monday.");
return;
end if;
The_Start_Time := Tu.Value (Week_Of & " " & Start_Time);
The_End_Time := Tu.Value (Week_Of & " " & End_Time);
Tf.Header ("Day", Tf.Left);
Tf.Header ("Disk Start", Tf.Right);
Tf.Header ("Disk End", Tf.Right);
Tf.Header ("RunQ Avg", Tf.Right);
Tf.Header ("PD Avg", Tf.Right);
Tf.Header ("Users", Tf.Right);
Tf.Header ("Samples", Tf.Right);
declare
use Calendar;
Disk_Start : Natural := 0;
Disk_End : Natural := 0;
Runq : Scheduler.Load_Factor := 0;
Pd : Duration := 0.0;
Users : Natural := 0;
Start_Time : Tu.Time;
End_Time : Tu.Time;
Item_Count : Natural := 0;
begin
for Day in Tu.Weekday loop
if not Weekend_Too then
exit when Day = 6;
end if;
Iter := Get_Entries (Starting_At => The_Start_Time,
Ending_At => The_End_Time,
From_File => The_Datafilename);
Item_Count := 0;
Runq := 0;
Pd := 0.0;
Users := 0;
while not Done (Iter) loop
The_Current_Record := Value (Iter);
if Item_Count = 0 then
Disk_Start := Available_Disk_Space (The_Current_Record);
Start_Time := Time_Stamp (The_Current_Record);
end if;
Item_Count := Item_Count + 1;
Runq := Runq + Run_Q_Load (The_Current_Record);
Users := Users + Active_Sessions (The_Current_Record);
Disk_End := Available_Disk_Space (The_Current_Record);
End_Time := Time_Stamp (The_Current_Record);
Pd := Pd + Job_Elapsed_Time (The_Current_Record);
Next (Iter);
end loop;
Tf.Item (Tu.Image (Day));
if Item_Count /= 0 then
Runq := Runq / Item_Count;
Pd := Pd / Item_Count;
Users := Users / Item_Count;
Tf.Item (Natural'Image (Disk_Start));
Tf.Item (Natural'Image (Disk_End));
Tf.Item (Image (Runq));
Tf.Item (Tu.Image (Pd));
Tf.Item (Natural'Image (Users));
Tf.Item (Natural'Image (Item_Count));
else
Tf.Item ("NA");
Tf.Item ("NA");
Tf.Item ("NA");
Tf.Item ("NA");
Tf.Item ("NA");
Tf.Item (Natural'Image (Item_Count));
end if;
The_Start_Time := Time_Utilities.Convert_Time
(Time_Utilities.Convert_Time
(The_Start_Time) + (60.0 * 60 * 24));
The_End_Time := Time_Utilities.Convert_Time
(Time_Utilities.Convert_Time (The_End_Time) +
(60.0 * 60 * 24));
end loop;
if Output /= "" then
Io.Create (The_Output_File, Io.Out_File, Output);
Put_Header ("Weekly Machine Report", The_Output_File);
Io.Put_Line (The_Output_File,
"For the week starting on " &
Time_Utilities.Image
(Monday,
Date_Style => Time_Utilities.Expanded,
Contents => Time_Utilities.Date_Only));
Io.New_Line (The_Output_File);
Tf.Display (The_Output_File);
Io.Close (The_Output_File);
else
Put_Header ("Weekly Machine Report", Io.Current_Output);
Io.Put_Line (Io.Current_Output,
"For the week starting on " &
Time_Utilities.Image
(Monday,
Date_Style => Time_Utilities.Expanded,
Contents => Time_Utilities.Date_Only));
Io.New_Line (Io.Current_Output);
Tf.Display (Io.Current_Output);
end if;
exception
when others =>
Log.Put_Line (Debug_Tools.Get_Exception_Name (True, True),
Profile.Exception_Msg);
end;
end Weekly_Report;
end Performance;