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.3 required=5.0 tests=BAYES_00,INVALID_MSGID autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,7d2c8b4487ef2145 X-Google-Attributes: gid103376,public From: ohk@ultra.tfdt-o.nta.no (Ole-Hjalmar Kristensen FOU.TD/DELAB) Subject: Ada Tasking revisited (was: Re: Ada versus Java - Tasking) Date: 1997/01/20 Message-ID: #1/1 X-Deja-AN: 211007779 references: <01bc03ee$594dc520$829d6482@joy.ericsson.se> organization: Telenor Online Public Access newsgroups: comp.lang.ada Date: 1997-01-20T00:00:00+00:00 List-Id: In article <32E2E430.50EF@bix.com> Tom Moran writes: > These task switching times are still pretty horrible though Yes, and Win95 takes (on my P60) over 700 microseconds just to call Ada.Calendar.Clock You can use an Ada compiler that doesn't map tasks to OS threads or, for really fast stuff, use DOS (where the OS doesn't get in the way). Interesting thought. Develop on a workstation, then deploy on DOS for maximum speed! I have run a simple test of the effect of using protected types to reduce task switching. The protected type is introduced as a buffer between the two tasks, and even with a buffer size of 1 leads to a significant reduction in time. My code is a somewhat simplified version of an example which was posted earlier, in that it uses only 2 tasks: with Interfaces; with Ada.Calendar; with Ada.Text_Io; use Ada; procedure Q_Prod_Cons is procedure Time_This is -- Note different size of Data_Block type Data_Block is array (1 .. 4 ) of Interfaces.Unsigned_8; for Data_Block'Component_Size use Interfaces.Unsigned_8'Size; for Data_Block'Size use 4 * Interfaces.Unsigned_8'Size; protected type Buffer is entry Put(X: in Data_Block); entry Get(X: out Data_Block); private Data: Data_Block; Full: Boolean := False; end Buffer; protected body Buffer is entry Put(X: in Data_Block) when not Full is begin Data := X; Full := True; end Put; entry Get(X: out Data_Block) when Full is begin x:= Data; Full := False; end Get; end Buffer; type Buffer_Ptr is access all Buffer; task type Consumer_Agent (Q : access Buffer); task body Consumer_Agent is Local : Data_Block; begin -- Consumer_Agent for I in 1..100000 loop Q.Get(Local); end loop ; end Consumer_Agent; type Consumer_Ptr is access all Consumer_Agent; task type Producer_Agent (Q : access Buffer); task body Producer_Agent is Data : Data_Block := (others => 0); begin -- Producer_Agent for I in 1..100000 loop Q.Put(Data); end loop ; end Producer_Agent; type Producer_Ptr is access all Producer_Agent; Buf: Buffer_Ptr; Consumer : Consumer_Ptr; Producer : Producer_Ptr; begin -- Time_This Buf := new Buffer; Consumer := new Consumer_Agent(Q => Buf); Producer := new Producer_Agent (Q => Buf); end Time_This; Stop : Calendar.Time; Start : Calendar.Time := Calendar.Clock; use type Calendar.Time; begin -- Prod_Cons Time_This; Stop := Calendar.Clock; Text_Io.Put_Line (Duration'Image (Stop - Start) ); end Q_Prod_Cons; The original version, modified to use only 2 tasks, and with 100000 iterations use ca. 23 seconds on my machine, while the above version uses only 15 seconds on average. This is because a thread may execute operations on behalf of another thread while it is executing inside the protected type. With a longer queue, the effect would be even greater, of course. Ole-Hj. Kristensen