From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,FREEMAIL_FROM autolearn=unavailable autolearn_force=no version=3.4.4 X-Received: by 10.58.32.167 with SMTP id k7mr23089vei.41.1377879402760; Fri, 30 Aug 2013 09:16:42 -0700 (PDT) X-Received: by 10.49.12.47 with SMTP id v15mr23832qeb.39.1377879402669; Fri, 30 Aug 2013 09:16:42 -0700 (PDT) Path: border1.nntp.dca3.giganews.com!border2.nntp.dca3.giganews.com!border4.nntp.dca.giganews.com!border2.nntp.dca.giganews.com!nntp.giganews.com!news-out.readnews.com!transit3.readnews.com!news.glorb.com!fx3no6204935qab.0!news-out.google.com!he10ni3964qab.0!nntp.google.com!fx3no6204932qab.0!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail Newsgroups: comp.lang.ada Date: Fri, 30 Aug 2013 09:16:42 -0700 (PDT) In-Reply-To: Complaints-To: groups-abuse@google.com Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=190.56.253.144; posting-account=H6rJXAoAAACK-5bKQx7qSDO6HkCJTM3b NNTP-Posting-Host: 190.56.253.144 References: User-Agent: G2/1.0 MIME-Version: 1.0 Message-ID: Subject: Re: Anonymous access types are evil, why? From: Gerhard Rummel Injection-Date: Fri, 30 Aug 2013 16:16:42 +0000 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable X-Original-Bytes: 24090 Xref: number.nntp.dca.giganews.com comp.lang.ada:183228 Date: 2013-08-30T09:16:42-07:00 List-Id: Am Mittwoch, 28. August 2013 05:49:56 UTC-6 schrieb ake.ragna...@gmail.com: > Consider the following application that uses anonymous access types and a= llocates Controlled objects on the heap using two different ways. One way t= akes 60 times longer than the other: >=20 > .... >=20 >=20 >=20 > What are the conclusions we can draw? >=20 > 1. Perhaps one conclusion would be that when using anonymous access types= then indirect assignment should be preferred over direct assignment. (see = Models.B.Direct_Assignment and Models.B.Indirect_Assignment). >=20 > 2. Avoid anonymous access types. Prefer named access types and 'Unchecked= _Access. >=20 >=20 >=20 > Is there anybody who can explain why direct assignment takes approximatel= y 60 times longer than indirect assignment? >=20 >=20 >=20 > Best regards, >=20 > =C5ke Ragnar Dahlgren I think there is a problem with the implementation of Controlled Types in gnat2012, and NOT with anonymous access types: if you change the declaratio= n of A_Type to a not controlled record there is nearly no difference in run= time: To show that I have declared three versions of your A_Type (in Models= .A): as a record, a tagged record and as derived from Ada.Finalization.Cont= rolled. Then I declared six versions of your B_Type, with anonymous and nam= ed access variables of each of the three types. Additionally, I cleaned up = the heap before the direct or indirect assignments. The output of the Main program is now: Output: Heap clean up before assignment: TRUE MODELS.B.TYPE_WITH_RECORD_ACCESS_TYPE, Duration (direct assignment): 0.0= 05783000 MODELS.B.TYPE_WITH_RECORD_ACCESS_TYPE, Duration (indirect assignment): 0.0= 02435000 MODELS.B.TYPE_WITH_ANONYMOUS_RECORD_ACCESS_TYPE, Duration (direct assignmen= t): 0.002283000 MODELS.B.TYPE_WITH_ANONYMOUS_RECORD_ACCESS_TYPE, Duration (indirect assignm= ent): 0.002263000 MODELS.B.TYPE_WITH_TAGGED_RECORD_ACCESS_TYPE, Duration (direct assignment):= 0.002298000 MODELS.B.TYPE_WITH_TAGGED_RECORD_ACCESS_TYPE, Duration (indirect assignment= ): 0.002263000 MODELS.B.TYPE_WITH_ANONYMOUS_TAGGED_RECORD_ACCESS_TYPE, Duration (direct as= signment): 0.002304000 MODELS.B.TYPE_WITH_ANONYMOUS_TAGGED_RECORD_ACCESS_TYPE, Duration (indirect = assignment): 0.002553000 MODELS.B.TYPE_WITH_CONTROLLED_ACCESS_TYPE, Duration (direct assignment): = 0.005504000 MODELS.B.TYPE_WITH_CONTROLLED_ACCESS_TYPE, Duration (indirect assignment): = 0.005505000 MODELS.B.TYPE_WITH_ANONYMOUS_CONTROLLED_ACCESS_TYPE, Duration (direct assig= nment): 0.010914000 MODELS.B.TYPE_WITH_ANONYMOUS_CONTROLLED_ACCESS_TYPE, Duration (indirect ass= ignment): 0.005706000 As you can see, the quotient of the runtimes of the two methods of assignme= nts is now a factor less than two, if your A_Type is Controlled and more th= an two, if your A_Type is a simple record instead of a Controlled type. Things are much worse for Controlled types when you don't clean up the heap= before the assignments: Output: Heap clean up before assignment: FALSE MODELS.B.TYPE_WITH_RECORD_ACCESS_TYPE, Duration (direct assignment): 0.0= 66929000 MODELS.B.TYPE_WITH_RECORD_ACCESS_TYPE, Duration (indirect assignment): 0.0= 63081000 MODELS.B.TYPE_WITH_ANONYMOUS_RECORD_ACCESS_TYPE, Duration (direct assignmen= t): 0.063031000 MODELS.B.TYPE_WITH_ANONYMOUS_RECORD_ACCESS_TYPE, Duration (indirect assignm= ent): 0.062613000 MODELS.B.TYPE_WITH_TAGGED_RECORD_ACCESS_TYPE, Duration (direct assignment):= 0.062416000 MODELS.B.TYPE_WITH_TAGGED_RECORD_ACCESS_TYPE, Duration (indirect assignment= ): 0.062329000 MODELS.B.TYPE_WITH_ANONYMOUS_TAGGED_RECORD_ACCESS_TYPE, Duration (direct as= signment): 0.061632000 MODELS.B.TYPE_WITH_ANONYMOUS_TAGGED_RECORD_ACCESS_TYPE, Duration (indirect = assignment): 0.062526000 MODELS.B.TYPE_WITH_CONTROLLED_ACCESS_TYPE, Duration (direct assignment): = 0.064492000 MODELS.B.TYPE_WITH_CONTROLLED_ACCESS_TYPE, Duration (indirect assignment): = 0.064068000 MODELS.B.TYPE_WITH_ANONYMOUS_CONTROLLED_ACCESS_TYPE, Duration (direct assig= nment): 11.441936000 MODELS.B.TYPE_WITH_ANONYMOUS_CONTROLLED_ACCESS_TYPE, Duration (indirect ass= ignment): 0.063594000 In the last four lines you can see that the runtimes for the two methods of= assignments are nearly equal for a B_Type with a named access type variabl= e of a Controlled type and very different for anonymous access type variabl= es. I think there is no important performance difference between anonymous and = named access variables if you clean up the heap before assigning new values= to them. But there is a problem with the finalization of Controlled type v= ariables on the heap, perhaps due to their implementation in gnat 2012. The code of the program: with Ada.Text_IO; with Models.B; procedure Main is Number_Of_Times : constant Positive :=3D 40000; begin for B in reverse Boolean range False .. True loop declare RT : Models.B.Type_With_Record_Access_Type; ART : Models.B.Type_With_Anonymous_Record_Access_Type; TRT : Models.B.Type_With_Tagged_Record_Access_Type; ATRT : Models.B.Type_With_Anonymous_Tagged_Record_Access_Type; CT : Models.B.Type_With_Controlled_Access_Type; ACT : Models.B.Type_With_Anonymous_Controlled_Access_Type; begin Models.B.With_Heap_Cleaning :=3D B; Ada.Text_IO.Put_Line (Item =3D> "Heap clean up before assignment: " & Boolean'Image (Models.B.With_Heap_Cleaning) ); RT.Measure_Time (Number_Of_Times =3D> Number_Of_Times); ART.Measure_Time (Number_Of_Times =3D> Number_Of_Times); TRT.Measure_Time (Number_Of_Times =3D> Number_Of_Times); ATRT.Measure_Time (Number_Of_Times =3D> Number_Of_Times); CT.Measure_Time (Number_Of_Times =3D> Number_Of_Times); ACT.Measure_Time (Number_Of_Times =3D> Number_Of_Times); Ada.Text_IO.New_Line; end; end loop; end Main; package Models is end Models; with Ada.Finalization; with Ada.Unchecked_Deallocation; package Models.A is type Record_Type is record Asdf : Integer; qwer : String (1 .. 8000); end record; type Record_Access_Type is access all Record_Type; procedure Delete is new Ada.Unchecked_Deallocation (Object =3D> Record_Type, Name =3D> Record_Access_Type); type Tagged_Record_Type is tagged record Asdf : Integer; qwer : String (1 .. 8000); end record; type Tagged_Record_Access_Type is access all Tagged_Record_Type; procedure Delete is new Ada.Unchecked_Deallocation (Object =3D> Tagged_Record_Type, Name =3D> Tagged_Record_Access_Type); type Controlled_Type is new Ada.Finalization.Controlled with record Asdf : Integer; qwer : String (1 .. 8000); end record; type Controlled_Access_Type is access all Controlled_Type; procedure Delete is new Ada.Unchecked_Deallocation (Object =3D> Controlled_Type, Name =3D> Controlled_Access_Type); end Models.A; with Ada.Finalization, Models.A; package Models.B is With_Heap_Cleaning : Boolean :=3D False; type Type_With_Access_Type is abstract new Ada.Finalization.Controlled with private; overriding procedure Finalize (Item : in out Type_With_Access_Type) with Inline; function Type_Name (Item : Type_With_Access_Type'Class) return String with Inline; procedure Cleanup (Item : in out Type_With_Access_Type) is abstract; procedure Direct_Assignment (Item : in out Type_With_Access_Type) is abstract; procedure Indirect_Assignment (Item : in out Type_With_Access_Type) is abstract; procedure Measure_Time (Item : in out Type_With_Access_Type'Class; Number_Of_Times : Natural ); ------------------------------------------------------------------------= ---- type Type_With_Record_Access_Type is new Type_With_Access_Type with priv= ate; overriding procedure Adjust (Item : in out Type_With_Record_Access_Type) with Inlin= e; overriding procedure Cleanup (Item : in out Type_With_Record_Access_Type); overriding procedure Direct_Assignment (Item : in out Type_With_Record_Access_Type) with Inline; overriding procedure Indirect_Assignment (Item : in out Type_With_Record_Access_Typ= e) with Inline; ------------------------------------------------------------------------= ---- type Type_With_Anonymous_Record_Access_Type is new Type_With_Access_Type with private; overriding procedure Adjust (Item : in out Type_With_Anonymous_Record_Access_Type) with Inline; overriding procedure Cleanup (Item : in out Type_With_Anonymous_Record_Access_Type)= ; overriding procedure Direct_Assignment (Item : in out Type_With_Anonymous_Record_Access_Type) with Inline; overriding procedure Indirect_Assignment (Item : in out Type_With_Anonymous_Record_Access_Type) with Inline; ------------------------------------------------------------------------= ---- type Type_With_Tagged_Record_Access_Type is new Type_With_Access_Type with private; overriding procedure Adjust (Item : in out Type_With_Tagged_Record_Access_Type) with Inline; overriding procedure Cleanup (Item : in out Type_With_Tagged_Record_Access_Type); overriding procedure Direct_Assignment (Item : in out Type_With_Tagged_Record_Access_Type) with Inline; overriding procedure Indirect_Assignment (Item : in out Type_With_Tagged_Record_Access_Type) with Inline; ------------------------------------------------------------------------= ---- type Type_With_Anonymous_Tagged_Record_Access_Type is new Type_With_Access_Type with private; overriding procedure Adjust (Item : in out Type_With_Anonymous_Tagged_Record_Access_Type) with Inl= ine; overriding procedure Cleanup (Item : in out Type_With_Anonymous_Tagged_Record_Access_Type); overriding procedure Direct_Assignment (Item : in out Type_With_Anonymous_Tagged_Record_Access_Type) with Inl= ine; overriding procedure Indirect_Assignment (Item : in out Type_With_Anonymous_Tagged_Record_Access_Type) with Inl= ine; ------------------------------------------------------------------------= ---- type Type_With_Controlled_Access_Type is new Type_With_Access_Type with private; overriding procedure Adjust (Item : in out Type_With_Controlled_Access_Type) with Inline; overriding procedure Cleanup (Item : in out Type_With_Controlled_Access_Type); overriding procedure Direct_Assignment (Item : in out Type_With_Controlled_Access_Type) with Inline; overriding procedure Indirect_Assignment (Item : in out Type_With_Controlled_Access_Type) with Inline; ------------------------------------------------------------------------= ---- type Type_With_Anonymous_Controlled_Access_Type is new Type_With_Access_= Type with private; overriding procedure Adjust (Item : in out Type_With_Anonymous_Controlled_Access_Ty= pe) with Inline; overriding procedure Cleanup (Item : in out Type_With_Anonymous_Controlled_Access_Type); overriding procedure Direct_Assignment (Item : in out Type_With_Anonymous_Controlled_Access_Type) with Inline= ; overriding procedure Indirect_Assignment (Item : in out Type_With_Anonymous_Controlled_Access_Type) with Inline= ; private type Type_With_Access_Type is abstract new Ada.Finalization.Controlled with null record; type Type_With_Record_Access_Type is new Type_With_Access_Type with reco= rd A : Models.A.Record_Access_Type; end record; type Type_With_Anonymous_Record_Access_Type is new Type_With_Access_Type with record A : access Models.A.Record_Type; end record; type Type_With_Tagged_Record_Access_Type is new Type_With_Access_Type with record A : Models.A.Tagged_Record_Access_Type; end record; type Type_With_Anonymous_Tagged_Record_Access_Type is new Type_With_Access_Type with record A : access Models.A.Tagged_Record_Type; end record; type Type_With_Controlled_Access_Type is new Type_With_Access_Type with record A : Models.A.Controlled_Access_Type; end record; type Type_With_Anonymous_Controlled_Access_Type is new Type_With_Access_= Type with record A : access Models.A.Controlled_Type; end record; end Models.B; with Ada.Real_Time; with Ada.Tags; with Ada.Text_IO; package body Models.B is overriding procedure Finalize (Item : in out Type_With_Access_Type) is begin Type_With_Access_Type'Class (Item).Cleanup; end Finalize; function Type_Name (Item : Type_With_Access_Type'Class) return String is begin return Ada.Tags.External_Tag (T =3D> Item'Tag); end Type_Name; procedure Measure_Time (Item : in out Type_With_Access_Type'Class; Number_Of_Times : Natural ) is Start_Time_Stamp : Ada.Real_Time.Time; End_Time_Stamp : Ada.Real_Time.Time; begin Start_Time_Stamp :=3D Ada.Real_Time.Clock; for I in 1 .. Number_Of_Times loop Item.Direct_Assignment; end loop; End_Time_Stamp :=3D Ada.Real_Time.Clock; declare use type Ada.Real_Time.Time; Total_Time : constant Duration :=3D Ada.Real_Time.To_Duration (End_Time_Stamp - Start_Time_Stam= p); begin Ada.Text_IO.Put_Line (Item.Type_Name & ", Duration (direct assignment): " & Total_Time'Img ); end; Start_Time_Stamp :=3D Ada.Real_Time.Clock; for I in 1 .. Number_Of_Times loop Item.Indirect_Assignment; end loop; End_Time_Stamp :=3D Ada.Real_Time.Clock; declare use type Ada.Real_Time.Time; Total_Time : constant Duration :=3D Ada.Real_Time.To_Duration (End_Time_Stamp - Start_Time_Stam= p); begin Ada.Text_IO.Put_Line (Item.Type_Name & ", Duration (indirect assignment): " & Total_Time'Img ); end; end Measure_Time; ------------------------------------------------------------------------= ---- overriding procedure Adjust (Item : in out Type_With_Record_Access_Type) is use Models.A; begin if Item.A /=3D null then Item.A :=3D new Models.A.Record_Type'(Item.A.all); end if; end Adjust; overriding procedure Cleanup (Item : in out Type_With_Record_Access_Type) is use Models.A; X : Models.A.Record_Access_Type :=3D Item.A; begin Item.A :=3D null; if X /=3D null then Delete (X); end if; end Cleanup; overriding procedure Direct_Assignment (Item : in out Type_With_Record_Access_Type)= is use Models.A; begin if With_Heap_Cleaning then Item.Cleanup; end if; Item.A :=3D new Models.A.Record_Type; end Direct_Assignment; overriding procedure Indirect_Assignment (Item : in out Type_With_Record_Access_Typ= e) is use Models.A; begin if With_Heap_Cleaning then Item.Cleanup; end if; declare A : constant Models.A.Record_Access_Type :=3D new Models.A.Record_= Type; begin Item.A :=3D A; end; end Indirect_Assignment; ------------------------------------------------------------------------= --- overriding procedure Adjust (Item : in out Type_With_Anonymous_Record_Access_Type) is use Models.A; begin if Item.A /=3D null then Item.A :=3D new Models.A.Record_Type'(Item.A.all); end if; end Adjust; overriding procedure Cleanup (Item : in out Type_With_Anonymous_Record_Access_Type) is use Models.A; X : Models.A.Record_Access_Type :=3D Item.A; begin Item.A :=3D null; if X /=3D null then Delete (X); end if; end Cleanup; overriding procedure Direct_Assignment (Item : in out Type_With_Anonymous_Record_Access_Type) is use Models.A; begin if With_Heap_Cleaning then Item.Cleanup; end if; Item.A :=3D new Models.A.Record_Type; end Direct_Assignment; overriding procedure Indirect_Assignment (Item : in out Type_With_Anonymous_Record_Access_Type) is use Models.A; begin if With_Heap_Cleaning then Item.Cleanup; end if; declare A : constant Models.A.Record_Access_Type :=3D new Models.A.Record_= Type; begin Item.A :=3D A; end; end Indirect_Assignment; ------------------------------------------------------------------------= --- overriding procedure Adjust (Item : in out Type_With_Tagged_Record_Access_Type) is use Models.A; begin if Item.A /=3D null then Item.A :=3D new Models.A.Tagged_Record_Type'(Item.A.all); end if; end Adjust; overriding procedure Cleanup (Item : in out Type_With_Tagged_Record_Access_Type) is use Models.A; X : Models.A.Tagged_Record_Access_Type :=3D Item.A; begin Item.A :=3D null; if X /=3D null then Delete (X); end if; end Cleanup; overriding procedure Direct_Assignment (Item : in out Type_With_Tagged_Record_Access_Type) is use Models.A; begin if With_Heap_Cleaning then Item.Cleanup; end if; Item.A :=3D new Models.A.Tagged_Record_Type; end Direct_Assignment; overriding procedure Indirect_Assignment (Item : in out Type_With_Tagged_Record_Access_Type) is use Models.A; begin if With_Heap_Cleaning then Item.Cleanup; end if; declare A : constant Models.A.Tagged_Record_Access_Type :=3D new Models.A.Tagged_Record_Type; begin Item.A :=3D A; end; end Indirect_Assignment; ------------------------------------------------------------------------= --- overriding procedure Adjust (Item : in out Type_With_Anonymous_Tagged_Record_Access_Type) is use Models.A; begin if Item.A /=3D null then Item.A :=3D new Models.A.Tagged_Record_Type'(Item.A.all); end if; end Adjust; overriding procedure Cleanup (Item : in out Type_With_Anonymous_Tagged_Record_Access_Type) is use Models.A; X : Models.A.Tagged_Record_Access_Type :=3D Item.A; begin Item.A :=3D null; if X /=3D null then Delete (X); end if; end Cleanup; overriding procedure Direct_Assignment (Item : in out Type_With_Anonymous_Tagged_Record_Access_Type) is use Models.A; begin if With_Heap_Cleaning then Item.Cleanup; end if; Item.A :=3D new Models.A.Tagged_Record_Type; end Direct_Assignment; overriding procedure Indirect_Assignment (Item : in out Type_With_Anonymous_Tagged_Record_Access_Type) is use Models.A; begin if With_Heap_Cleaning then Item.Cleanup; end if; declare A : constant Models.A.Tagged_Record_Access_Type :=3D new Models.A.Tagged_Record_Type; begin Item.A :=3D A; end; end Indirect_Assignment; ------------------------------------------------------------------------= --- overriding procedure Adjust (Item : in out Type_With_Controlled_Access_Type) is use Models.A; begin if Item.A /=3D null then Item.A :=3D new Models.A.Controlled_Type'(Item.A.all); end if; end Adjust; overriding procedure Cleanup (Item : in out Type_With_Controlled_Access_Type) is use Models.A; X : Models.A.Controlled_Access_Type :=3D Item.A; begin Item.A :=3D null; if X /=3D null then Delete (X); end if; end Cleanup; overriding procedure Direct_Assignment (Item : in out Type_With_Controlled_Access_T= ype) is use Models.A; begin if With_Heap_Cleaning then Item.Cleanup; end if; Item.A :=3D new Models.A.Controlled_Type; end Direct_Assignment; overriding procedure Indirect_Assignment (Item : in out Type_With_Controlled_Access_Type) is use Models.A; begin if With_Heap_Cleaning then Item.Cleanup; end if; declare A : constant Models.A.Controlled_Access_Type :=3D new Models.A.Controlled_Type; begin Item.A :=3D A; end; end Indirect_Assignment; ------------------------------------------------------------------------= --- overriding procedure Adjust (Item : in out Type_With_Anonymous_Controlled_Access_Ty= pe) is use Models.A; begin if Item.A /=3D null then Item.A :=3D new Models.A.Controlled_Type'(Item.A.all); end if; end Adjust; overriding procedure Cleanup (Item : in out Type_With_Anonymous_Controlled_Access_Type) is use Models.A; X : Models.A.Controlled_Access_Type :=3D Item.A; begin Item.A :=3D null; if X /=3D null then Delete (X); end if; end Cleanup; overriding procedure Direct_Assignment (Item : in out Type_With_Anonymous_Controlled_Access_Type) is use Models.A; begin if With_Heap_Cleaning then Item.Cleanup; end if; Item.A :=3D new Models.A.Controlled_Type; end Direct_Assignment; overriding procedure Indirect_Assignment (Item : in out Type_With_Anonymous_Controlled_Access_Type) is use Models.A; begin if With_Heap_Cleaning then Item.Cleanup; end if; declare A : constant Models.A.Controlled_Access_Type :=3D new Models.A.Controlled_Type; begin Item.A :=3D A; end; end Indirect_Assignment; end Models.B;