comp.lang.ada
 help / color / mirror / Atom feed
From: "Jeff Creem" <jeff@thecreems.com>
Subject: Re: Optimization Question -- Follow up on using the stream read (and write) procedures directly
Date: Fri, 26 Jan 2001 11:30:54 -0500
Date: 2001-01-26T11:30:54-05:00	[thread overview]
Message-ID: <t739enmlcvuo2d@corp.supernews.com> (raw)
In-Reply-To: 3A6F663E.C84B94D8@acm.org

A few days ago there was a discussion about using the direct read procedures
which are
part of the stream packages rather than the 'read/'write attributes to read
in large chunks of
data.

This got me thinking about what the best way might be to this in a general
sense so I thought
I'd put this approach out as a strawman before really making a package out
of it with a little more
robust error checking on the validity of the types the user uses.


In any case, at first glance this approach (when it can be used) appears to
be up to 30 times faster
than 'read (for all of the reasons discussed a few days ago) on a 350 Pent
II Win 95 machine.


My least favorite part of the approach is the unchecked_conversion of access
types.


So in any case, here is a partial package and test program.....Any comments?



with Ada.Streams;

generic

  type Element_Type is private;
  type Array_Index_Type is range <>;
  type Block_Array_Type is array (Array_Index_Type) of Element_Type;


package Stream_Utilities is

  --
  -- This procedure attempts to read Item'length elements from
  -- the stream. If fewer than Item'length elements are read, then
  -- Last will return < Item'last. This procedure assumes that
  -- the elements being read are present in the stream in a format
  -- identical to the layout of the elements in the Block_Array_Type.
  --
  --
  procedure Block_Read
    (Stream : access Ada.Streams.Root_Stream_Type'Class;
     Item   : access Block_Array_Type;
     Last   : out Array_Index_Type);

end Stream_Utilities;




with Ada.Streams;
with Unchecked_Conversion;
use Ada.Streams;

package body Stream_Utilities is


   --
   -- There are essentially two approaches that immediately
   -- come to mind to read a block of data efficiently.
   -- The first is to the the standard stream read utilities
   -- to read the data into an array of Stream_Elements followed
   -- by an unchecked_conversion to our actual output data type.
   --
   -- The second, potentially more evil approach is to used
   -- aliased types to essentially overlay what appears to be
   -- a stream element array on top of the memory where our
   -- actual data is. The first approach makes me feel better
   -- than the second, however, even though we know that not
   -- every instance of an unchecked_conversion really always
   -- causes a true copy, I found that in this instance
   -- at least with GNAT 3.12 under solaris we did end up
   -- copying the data
   --
   procedure Block_Read (
         Stream : access Ada.Streams.Root_Stream_Type'Class;
         Item   : access Block_Array_Type;
         Last   :    out Array_Index_Type                    ) is

      --
      -- Create a named access type to the block array type
      -- so we can create an unchecked conversion.
      --
      type Access_Block_Data is access all Block_Array_Type;

      --
      -- Create a constrained subtype of stream elements to
      -- "hold" the data returned from the stream
      --
      subtype Proper_Sized_Stream_Element_Type is
         Stream_Element_Array(1 .. Item.all'Size / Stream_Element'Size);

      --
      -- And finally, create a named access type to this
      -- constrained array.
      --
      type Access_Proper_Sized_Stream_Element_Type is access
Proper_Sized_Stream_Element_Type;


      --
      -- Create a conversion between the block data and the stream data
      --
      function To_Access is
      new Unchecked_Conversion
         (
         Source => Access_Block_Data,
         Target => Access_Proper_Sized_Stream_Element_Type);


      --
      -- Declare an access variable  to the stream data, note that
      -- at this very point we are now creating an overlayed version
      -- of the now aliased input parameter.
      --
      Proper_Sized_Stream_Data : Access_Proper_Sized_Stream_Element_Type :=
        To_Access (Access_Block_Data (Item));

      Local_Last : Stream_Element_Offset;

   begin

      --
      -- Read the data from the stream into our access to
      -- stream element array. Note at this moment we are now also
      -- filling in the Item parameter as well.
      --
      Read(Stream => Stream.all,
         Item   => Proper_Sized_Stream_Data.all,
         Last   => Local_Last);


      --
      -- Calulate the "Last" parameter we are sending back to the
      -- user so they can see it.
      --
      Last := (Item'First - 1) + Array_Index_Type'Base(Local_Last /  (
            Item'Size /
            Stream_Element'Size));

   end Block_Read;


end Stream_Utilities;





with Stream_Utilities;
with Ada.Streams.Stream_Io;
with Text_Io;
with Ada.Calendar;
use type Ada.Calendar.Time;


procedure Si is

   subtype Range_Type is Integer range 1 .. 8192;

   type My_Stream_Data_Type is mod 2**32;
   for My_Stream_Data_Type'Size use 32;



   type My_Array_Type is array (Range_Type) of My_Stream_Data_Type;
   pragma Pack (My_Array_Type);
   for My_Array_Type'Size use 8192*32;


   package Sii is new Stream_Utilities(My_Stream_Data_Type, Range_Type,
      My_Array_Type);


   My_Data : aliased My_Array_Type;
   Last    : Integer;
   File    : Ada.Streams.Stream_Io.File_Type;

   Match : Boolean;

   Repeat_Count : constant := 500;

   Start : Ada.Calendar.Time;
   Stop  : Ada.Calendar.Time;

begin

   --
   -- First, create some stream data
   --
   for I in My_Data'range loop
      My_Data(I) := My_Stream_Data_Type(I);
   end loop;

   Ada.Streams.Stream_Io.Create
      (
      File => File,
      Name => "test_data.bin",
      Mode => Ada.Streams.Stream_Io.Out_File);

   for Repeat in 1 .. Repeat_Count loop

      for I in My_Data'range loop
         My_Data(I) := My_Data(I) + 1;
      end loop;


      My_Array_Type'Write(Ada.Streams.Stream_Io.Stream(File), My_Data);


   end loop;

   Ada.Streams.Stream_Io.Close(File);

   My_Data := (others => 0);


   --
   -- Now, just double check that our block read appears to work
   -- at all.
   --
   Ada.Streams.Stream_Io.Open(
      File => File,
      Name => "test_data.bin",
      Mode => Ada.Streams.Stream_Io.In_File);
   Repeat_Loop :
      for Repeat in 1 .. Repeat_Count loop


      Sii.Block_Read(Ada.Streams.Stream_Io.Stream(File), My_Data'access,
         Last);


      for I in My_Data'range loop
         if My_Data(I) /= My_Stream_Data_Type(I) + My_Stream_Data_Type(
               Repeat) then
            Match := False;
            exit Repeat_Loop;
         end if;
      end loop;
   end loop Repeat_Loop;



   Ada.Streams.Stream_Io.Close(File);

   Text_Io.Put("Last was :");
   Text_Io.Put_Line(Integer'Image(Last));

   Match := True;
   if Match then
      Text_Io.Put_Line("Match");
   else
      Text_Io.Put_Line("No Match");
   end if;


   --
   -- Now, a little benchmarking.
   --
   Ada.Streams.Stream_Io.Open(
      File => File,
      Name => "test_data.bin",
      Mode => Ada.Streams.Stream_Io.In_File);

   Start := Ada.Calendar.Clock;

   for Repeat in 1 .. Repeat_Count loop


      Sii.Block_Read(Ada.Streams.Stream_Io.Stream(File), My_Data'access,
         Last);

   end loop;

   Stop := Ada.Calendar.Clock;

   Text_Io.Put_Line("Block read in " & Duration'Image(Stop - Start));


   Ada.Streams.Stream_Io.Close(File);


   Ada.Streams.Stream_Io.Open(
      File => File,
      Name => "test_data.bin",
      Mode => Ada.Streams.Stream_Io.In_File);

   Start := Ada.Calendar.Clock;

   for Repeat in 1 .. Repeat_Count loop

      My_Array_Type'Read(Ada.Streams.Stream_Io.Stream(File), My_Data);

   end loop;
   Stop := Ada.Calendar.Clock;

   Text_Io.Put_Line("Normal Stream Read  in " & Duration'Image(Stop -
         Start));



   Ada.Streams.Stream_Io.Close(File);


end Si;






  parent reply	other threads:[~2001-01-26 16:30 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2001-01-22  0:05 Optimization Question dvdeug
2001-01-22  1:57 ` Robert Dewar
2001-01-22  3:22   ` dvdeug
2001-01-22  4:05     ` Robert Dewar
2001-01-22  4:06     ` Robert Dewar
2001-01-22 19:04     ` M. Kotiaho
2001-01-22 20:22       ` dvdeug
2001-01-22 15:24   ` Ted Dennison
2001-01-22 16:12     ` Robert Dewar
2001-01-22 16:48       ` Ted Dennison
2001-01-22 16:15     ` Robert Dewar
2001-01-22 15:26   ` Ted Dennison
2001-01-22 16:17     ` Robert Dewar
2001-01-22 16:59       ` Ted Dennison
2001-01-22 22:01 ` Keith Thompson
2001-01-22 22:52   ` dvdeug
2001-01-23  6:46     ` Keith Thompson
     [not found] ` <94ld65$1hs$1@nnrp1.deja.com>
     [not found]   ` <864ryodb1q.fsf@acm.org>
     [not found]     ` <3A6F663E.C84B94D8@acm.org>
2001-01-26 16:30       ` Jeff Creem [this message]
2001-01-26 21:46         ` Optimization Question -- Follow up on using the stream read (and write) procedures directly Florian Weimer
2001-01-27 19:14           ` Jeff Creem
2001-01-28  0:26             ` Robert Dewar
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox