1-- Usage: test_stream_performance <big_file>
2-- Produces .tmp files that are copies of <big_file>.
3--
4-- Example of output with GNAT GPL 2008 / Win32:
5--
6--  xxx'Write / xxx'Read (Stream attributes)......... 9.282530042 seconds
7--  Workarounds with Stream_Element_Array buffer:
8--    copy........................................... 0.444120412 seconds
9--    overlay (read), unchecked_conversion (write)... 0.156874407 seconds
10--    overlay........................................ 0.150155676 seconds
11--  Factor (Copy)    20.900930898
12--  Factor (Overlay) 61.819374993
13
14--  Buffer size in bits..... 8192
15--  SE Buffer size in bits.. 8192
16
17--  File size in megabytes..... 2.46367E+01
18
19with Ada.Calendar;                      use Ada.Calendar;
20with Ada.Text_IO;
21with Ada.Streams.Stream_IO;             use Ada.Streams.Stream_IO;
22with Ada.Command_Line;                  use Ada.Command_Line;
23with Ada.Unchecked_Conversion;
24with Interfaces;                        use Interfaces;
25
26procedure Test_Stream_Performance is
27
28  f_in, f_out: Ada.Streams.Stream_IO.File_Type;
29
30  type Buffer is array(Natural range <>) of Unsigned_8;
31
32  ------------------------------------------------
33  -- 1) Stream attributes - xxx'Read, xxx'Write --
34  ------------------------------------------------
35
36  -- NB: usually we would just have: Buffer'Read(Stream(f_in), b);
37  -- Here we care about end of file.
38  --
39  procedure Read_Attribute( b: out Buffer; last_read: out Natural ) is
40    idx: constant Positive_Count:= Index(f_in);
41    siz: constant Positive_Count:= Size(f_in);
42  begin
43    if End_Of_File(f_in) then
44      last_read:= b'First-1;
45    else
46      last_read:= Natural'Min(b'First+Natural(siz-idx),b'Last);
47      Buffer'Read(Stream(f_in), b(b'First .. last_read));
48    end if;
49  end Read_Attribute;
50
51  procedure Write_Attribute( b: in Buffer ) is
52  begin
53    Buffer'Write(Stream(f_out), b);
54  end Write_Attribute;
55
56  ---------------------------------------------
57  -- 2) The Stream_Element_Array workarounds --
58  ---------------------------------------------
59
60  procedure Read_SE_Copy( b: out Buffer; last_read: out Natural ) is
61    use Ada.Streams;
62    First     : constant Stream_Element_Offset:= Stream_Element_Offset(b'First);
63    Last      :          Stream_Element_Offset:= Stream_Element_Offset(b'Last);
64    SE_Buffer : Stream_Element_Array (First..Last);
65  begin
66    Read(Stream(f_in).all, SE_Buffer, Last);
67    for i in First..Last loop
68      b(Natural(i)):= Unsigned_8(SE_Buffer(i));
69    end loop;
70    last_read:= Natural(Last);
71  end Read_SE_Copy;
72
73  procedure Write_SE_Copy( b: in Buffer ) is
74    use Ada.Streams;
75    First     : constant Stream_Element_Offset:= Stream_Element_Offset(b'First);
76    Last      : constant Stream_Element_Offset:= Stream_Element_Offset(b'Last);
77    SE_Buffer : Stream_Element_Array (First..Last);
78  begin
79    for i in SE_Buffer'Range loop
80      SE_Buffer(i):= Stream_Element(b(Natural(i)));
81    end loop;
82    Write(Stream(f_out).all, SE_Buffer);
83  end Write_SE_Copy;
84
85  -- Overlay idea by Jeff Carter
86
87  procedure Read_SE_Overlay( b: out Buffer; last_read: out Natural ) is
88    use Ada.Streams;
89    Last: Stream_Element_Offset;
90    SE_Buffer : Stream_Element_Array (1..b'Length);
91    for SE_Buffer'Address use b'Address;
92    pragma Import (Ada, SE_Buffer);
93  begin
94    Read(Stream(f_in).all, SE_Buffer, Last);
95    last_read:= b'First + Natural(Last) - 1;
96  end Read_SE_Overlay;
97
98  procedure Write_SE_Overlay( b: in Buffer ) is
99    use Ada.Streams;
100    SE_Buffer : Stream_Element_Array (1..b'Length);
101    for SE_Buffer'Address use b'Address;
102    pragma Import (Ada, SE_Buffer);
103  begin
104    Write(Stream(f_out).all, SE_Buffer);
105  end Write_SE_Overlay;
106
107  -- Using Unchecked_Conversion
108
109  procedure Write_SE_UC( b: in Buffer ) is
110    subtype My_SEA is Ada.Streams.Stream_Element_Array(1..b'Length);
111    function To_SEA is new Ada.Unchecked_Conversion(Buffer, My_SEA);
112    use Ada.Streams;
113  begin
114    Write(Stream(f_out).all, To_SEA(b));
115  end Write_SE_UC;
116
117  ----------
118  -- Test --
119  ----------
120
121  function name return String is
122  begin
123    return Argument(1);
124  end name;
125
126  generic
127    label: String;
128    with procedure Read( b: out Buffer; last_read: out Natural  );
129    with procedure Write( b: in Buffer  );
130  procedure Test(bytes: Positive);
131
132  procedure Test(bytes: Positive) is
133    b: Buffer(1..bytes);
134    l: Natural;
135  begin
136    Open(f_in, In_File, name);
137    Create(f_out, Out_File, name & "_$$$_" & label & ".tmp");
138    while not End_Of_File(f_in) loop
139      Read(b,l);
140      Write(b(1..l));
141    end loop;
142    Close(f_out);
143    Close(f_in);
144  end Test;
145
146  procedure Test_Attribute is new Test("Attribute", Read_Attribute, Write_Attribute);
147  procedure Test_SE_Copy is new Test("SE_Copy", Read_SE_Copy, Write_SE_Copy);
148  procedure Test_SE_Overlay is new Test("SE_Overlay", Read_SE_Overlay, Write_SE_Overlay);
149  procedure Test_SE_UC is new Test("SE_UC", Read_SE_Overlay, Write_SE_UC);
150
151  use Ada.Text_IO;
152
153  procedure All_Tests(buffer_bytes: Positive) is
154    T0, T1, T2, T3, T4: Time;
155  begin
156    T0:= Clock;
157    Test_Attribute(buffer_bytes);
158    T1:= Clock;
159    Test_SE_Copy(buffer_bytes);
160    T2:= Clock;
161    Test_SE_UC(buffer_bytes);
162    T3:= Clock;
163    Test_SE_Overlay(buffer_bytes);
164    T4:= Clock;
165    Put_Line("xxx'Write / xxx'Read (Stream attributes)........." & Duration'Image(T1-T0) & " seconds");
166    Put_Line("Workarounds with Stream_Element_Array buffer:");
167    Put_Line("  copy (byte buffer from/to SE buffer)..........." & Duration'Image(T2-T1) & " seconds");
168    Put_Line("  overlay (read), unchecked_conversion (write)..." & Duration'Image(T3-T2) & " seconds");
169    Put_Line("  overlay (read and write)......................." & Duration'Image(T4-T3) & " seconds");
170    Put_Line("Factor (Copy)   " & Duration'Image((T1-T0)/(T2-T1)));
171    Put_Line("Factor (UC)     " & Duration'Image((T1-T0)/(T3-T2)));
172    Put_Line("Factor (Overlay)" & Duration'Image((T1-T0)/(T4-T3)));
173    New_Line;
174    Put_Line("Buffer size in bytes....." & Integer'Image(buffer_bytes));
175    Open(f_in, In_File, name);
176    Put_Line("File size in megabytes....." & Float'Image(Float(Size(f_in))/(1024.0*1024.0)));
177    Close(f_in);
178  end All_Tests;
179
180begin
181  if Argument_Count=0 then
182    Put_Line(" Usage: test_stream_performance <big_file>");
183    Put_Line(" Produces .tmp files that are copies of <big_file>.");
184    return;
185  end if;
186  All_Tests(1024); -- 1 KB
187  All_Tests(32 * 1024); -- 32 KB
188  All_Tests(64 * 1024); -- 64 KB
189  All_Tests(128 * 1024); -- 128 KB
190  All_Tests(256 * 1024); -- 256 KB
191  All_Tests(1024 * 1024); -- 1 MB
192end Test_Stream_Performance;
193