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