comp.lang.ada
 help / color / mirror / Atom feed
* Tasks unleashed
@ 2003-05-01 14:01 Jano
  2003-05-01 15:40 ` Stephen Leake
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Jano @ 2003-05-01 14:01 UTC (permalink / raw)


Hello again,

now my question is referred to the use of task types through access 
types.

I seem to remember from a distant conversation that every task allocated 
takes a small amount of memory, amongst other things, to provide 
satisfactory results for 'Callable attribute.

Sometimes I'd like to have a task type that, when some activity is 
needed, is created and forgotten. For example, it takes an access 
constraint and from that point on is completely independent.

A related aspect is that I don't know if Unchecked_deallocation is to be 
performed on tasks. See the following example:

------8<---------

with Ada.Unchecked_deallocation;

procedure test is

   task type tt is
      entry The_end;
   end tt;

   task body tt is
   begin
      accept The_end do
         null;
      end The_end;
      -- delay 1.0;
   end tt;

   type att is access all tt;

   x : att;

   procedure Free is new Ada.Unchecked_deallocation (tt, att);

begin
   loop		-- for N in 1 .. 100 loop
      x := new tt;
      x.The_end;
      Free (x);
   end loop;
end;

------8<---------

It illustrates various points that come to my mind:

*) It eats quickly all my memory (Gnat 3.15p)

*) You can't be sure that the task is terminated when free is tried (and 
no exception is raised in that case).

*) Free seems to do nothing (gnatmem reports 0 deallocations using a 
closed loop of 100 iterations).

In any case, the memory thing forces to use pools of reusable tasks, 
it's my main and crucial conclusion.

Even if Free for tasks were not to free resources, it seems reasonable 
that it could instruct the runtime that that task will not be referenced 
again, so it should leave a 0 memory footprint after termination? But 
now I'm making things up, I can't find right now specific comments in 
the ARM about task access types.

Could someone comment on these things? Behave differently other 
compilers? I'm a fool to try these things or simply an ignorant?

I should say that I have an innate instinct to try to resolve things the 
way others see distinctly are not to be tried :)

Now that there is an ongoing discussion about people not knowing Ada 
using it for large new developments, think about it: I have some fair 
experience, several years of exposure (but only one fairly sized project 
behind me), and I'm still trying these twisted things. What could do a 
complete ignorant :) My other glorious idea yesterday was to free a 
protected type from inside one of its own procedures. I did it, but 
decided not to carry on (nothing seemed immediately wrong, though)... 
What things could arise from that?

-- 
-------------------------
Jano
402450.at.cepsz.unizar.es
-------------------------



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Tasks unleashed
  2003-05-01 14:01 Tasks unleashed Jano
@ 2003-05-01 15:40 ` Stephen Leake
  2003-05-01 16:14 ` Robert A Duff
  2003-05-02  1:14 ` tmoran
  2 siblings, 0 replies; 9+ messages in thread
From: Stephen Leake @ 2003-05-01 15:40 UTC (permalink / raw)


Jano <nono@celes.unizar.es> writes:

> I seem to remember from a distant conversation that every task allocated 
> takes a small amount of memory, amongst other things, to provide 
> satisfactory results for 'Callable attribute.

yes.
> <snip>
> 
> In any case, the memory thing forces to use pools of reusable tasks, 
> it's my main and crucial conclusion.

Yes, this is the recommended approach. It's faster, also.

-- 
-- Stephe



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Tasks unleashed
  2003-05-01 14:01 Tasks unleashed Jano
  2003-05-01 15:40 ` Stephen Leake
@ 2003-05-01 16:14 ` Robert A Duff
  2003-05-01 16:30   ` Jano
  2003-05-02  1:14 ` tmoran
  2 siblings, 1 reply; 9+ messages in thread
From: Robert A Duff @ 2003-05-01 16:14 UTC (permalink / raw)


Jano <nono@celes.unizar.es> writes:

> I seem to remember from a distant conversation that every task allocated 
> takes a small amount of memory, amongst other things, to provide 
> satisfactory results for 'Callable attribute.

Yes, an implementation cannot reclaim all the storage for a task when it
terminates, if there is some way to name the task.  As you say,
'Callable has to return False (rather than referring to freed memory).
Similarly, an entry call must raise Tasking_Error (rather than
crashing).

However, a clever implementation can reclaim all but one word of
storage.

> Sometimes I'd like to have a task type that, when some activity is 
> needed, is created and forgotten. For example, it takes an access 
> constraint and from that point on is completely independent.
> 
> A related aspect is that I don't know if Unchecked_deallocation is to be 
> performed on tasks.

Read RM-13.11.2 (or AARM, if you want underlying reasons).  Your task
below has no discriminants, so it's OK to U_D it.

>... See the following example:
> 
> ------8<---------
> 
> with Ada.Unchecked_deallocation;
> 
> procedure test is
> 
>    task type tt is
>       entry The_end;
>    end tt;
> 
>    task body tt is
>    begin
>       accept The_end do
>          null;
>       end The_end;
>       -- delay 1.0;
>    end tt;
> 
>    type att is access all tt;
> 
>    x : att;
> 
>    procedure Free is new Ada.Unchecked_deallocation (tt, att);
> 
> begin
>    loop		-- for N in 1 .. 100 loop
>       x := new tt;
>       x.The_end;
>       Free (x);
>    end loop;
> end;
> 
> ------8<---------
> 
> It illustrates various points that come to my mind:
> 
> *) It eats quickly all my memory (Gnat 3.15p)

The RM has no requirements about freeing memory.  13.11.2(17) is
"Implementation Advice", not because it's unimportant, but because we
didn't know how to formalize it.

Nonetheless, I would consider it a bug to fail to free a task that is
both terminated and U_D'ed.  What happens if you put a "delay" in the
loop?

> *) You can't be sure that the task is terminated when free is tried (and 
> no exception is raised in that case).
> 
> *) Free seems to do nothing (gnatmem reports 0 deallocations using a 
> closed loop of 100 iterations).
> 
> In any case, the memory thing forces to use pools of reusable tasks, 
> it's my main and crucial conclusion.

That may be more efficient on some systems (if creating and destroying
tasks is slow, perhaps because it does system calls), but you shouldn't
*have* to do that, IMHO.  On one of our (SofCheck's) embedded targets,
we use that method internally anyway, so it wouldn't make much speed
difference.

> Even if Free for tasks were not to free resources, it seems reasonable 
> that it could instruct the runtime that that task will not be referenced 
> again, so it should leave a 0 memory footprint after termination? But 
> now I'm making things up, I can't find right now specific comments in 
> the ARM about task access types.

Yes, I think Free for a non-terminated task should mark the task as
freed, so storage gets reclaimed on termination.  But there is no such
formal requirement in the RM.  How could there be?

> Could someone comment on these things? Behave differently other 
> compilers? I'm a fool to try these things or simply an ignorant?
> 
> I should say that I have an innate instinct to try to resolve things the 
> way others see distinctly are not to be tried :)
> 
> Now that there is an ongoing discussion about people not knowing Ada 
> using it for large new developments, think about it: I have some fair 
> experience, several years of exposure (but only one fairly sized project 
> behind me), and I'm still trying these twisted things. What could do a 
> complete ignorant :) My other glorious idea yesterday was to free a 
> protected type from inside one of its own procedures. I did it, but 
> decided not to carry on (nothing seemed immediately wrong, though)... 
> What things could arise from that?

Bad things.  ;-)

- Bob



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Tasks unleashed
  2003-05-01 16:14 ` Robert A Duff
@ 2003-05-01 16:30   ` Jano
  0 siblings, 0 replies; 9+ messages in thread
From: Jano @ 2003-05-01 16:30 UTC (permalink / raw)


Robert A Duff dice...

> Nonetheless, I would consider it a bug to fail to free a task that is
> both terminated and U_D'ed.  What happens if you put a "delay" in the
> loop?

Increasingly consumed memory. I have put a 0.1 delay.

> > What things could arise from that?
> 
> Bad things.  ;-)

I'm doomed... XD

-- 
-------------------------
Jano
402450.at.cepsz.unizar.es
-------------------------



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Tasks unleashed
  2003-05-01 14:01 Tasks unleashed Jano
  2003-05-01 15:40 ` Stephen Leake
  2003-05-01 16:14 ` Robert A Duff
@ 2003-05-02  1:14 ` tmoran
  2003-05-02 11:21   ` Jano
  2 siblings, 1 reply; 9+ messages in thread
From: tmoran @ 2003-05-02  1:14 UTC (permalink / raw)


>In any case, the memory thing forces to use pools of reusable tasks,
>it's my main and crucial conclusion.

  Have you considered a protected Buffer of work to do and a fixed pool of
tasks which queue on an entry waiting for the Buffer to have some work to
do (or instructions to quit)?  Then you needn't create or destroy the
worker tasks.



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Tasks unleashed
  2003-05-02  1:14 ` tmoran
@ 2003-05-02 11:21   ` Jano
  2003-05-02 23:52     ` tmoran
  2003-05-11  5:35     ` Craig Carey
  0 siblings, 2 replies; 9+ messages in thread
From: Jano @ 2003-05-02 11:21 UTC (permalink / raw)


tmoran@acm.org dice...
> >In any case, the memory thing forces to use pools of reusable tasks,
> >it's my main and crucial conclusion.
> 
>   Have you considered a protected Buffer of work to do and a fixed pool of
> tasks which queue on an entry waiting for the Buffer to have some work to
> do (or instructions to quit)?  Then you needn't create or destroy the
> worker tasks.

That's exactly what I'm doing :) but sometimes the "fixed" compromise 
bugs me. ITOH, normally is better to have a upper bound for things, I 
think.

-- 
-------------------------
Jano
402450.at.cepsz.unizar.es
-------------------------



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Tasks unleashed
  2003-05-02 11:21   ` Jano
@ 2003-05-02 23:52     ` tmoran
  2003-05-11  5:35     ` Craig Carey
  1 sibling, 0 replies; 9+ messages in thread
From: tmoran @ 2003-05-02 23:52 UTC (permalink / raw)


> >   Have you considered a protected Buffer of work to do and a fixed pool of
> > tasks which queue on an entry waiting for the Buffer to have some work to
> > ...
> That's exactly what I'm doing :) but sometimes the "fixed" compromise
> bugs me. ITOH, normally is better to have a upper bound for things, I
> think.

  You could make a hybrid.  An array of (initially null) pointers to
tasks, and, if Buffers can't service a client in a reasonable length of
time, you start up a "new" task.  Then your fixed limit is buffer'length +
task_array'length, but if the program actually only needs a few tasks, or
is sufficiently patient, you will only start up a small number of tasks.
Of course if your program desperately needs a large number of tasks early
in execution, but not later, you'll have to depend on virtual memory to
move those, now superfluous, tasks out of RAM.  If the program really has
phases like that, perhaps it should be split into two programs to be run
sequentially.



^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Tasks unleashed
  2003-05-02 11:21   ` Jano
  2003-05-02 23:52     ` tmoran
@ 2003-05-11  5:35     ` Craig Carey
  2003-05-11 15:35       ` Pascal Obry
  1 sibling, 1 reply; 9+ messages in thread
From: Craig Carey @ 2003-05-11  5:35 UTC (permalink / raw)


On Fri, 2 May 2003 13:21:13 +0200, Jano <nono@celes.unizar.es> wrote:

>tmoran@acm.org dice...
>> >In any case, the memory thing forces to use pools of reusable tasks,
>> >it's my main and crucial conclusion.
>> 
>>   Have you considered a protected Buffer of work to do and a fixed pool of
>> tasks which queue on an entry waiting for the Buffer to have some work to
>> do (or instructions to quit)?  Then you needn't create or destroy the
>> worker tasks.
>
>That's exactly what I'm doing :) but sometimes the "fixed" compromise 
>bugs me. ITOH, normally is better to have a upper bound for things, I 
>think.


The problem of Ada tasks leaking memory, is 100% absent if the program is
written well enough and either of the 2 compilers named here, are used (in
Windows).

Recovering the memory of a task silently fails if the task was not
 finished.

** Test 1: the memory leak is completely absent:
   for K in 1 .. 20_000 loop  -- N=20,000
      X := new A.Tt;
      N := N + 1;
      X.The_End;
      delay 1.0E-30;    --  [1]
      Free (X);         --  [2]
   end loop;

ObjectAda: 596K for both N=1,000 and N=200,000
GNAT 3.15: 760K, for both N=1,000 and N=200,000

1024 / 200,000 < 1, so no memory was being leaked for each deallocated
 task (in Windows 2000, OA 7.2.2, GNAT 3.15p).

** Test 2: Lines "[1]" and "[2]" are swapped. Now the large memory leak of
the test program is confirmed.

ObjectAda: 47.8MB, N=20,000
GNAT 3.15: 20.7MB, N=20,000,  "-largs --stack=0x40000,0x8000".


Craig Carey ; Ada 95 mailing lists htp://www.ijs.co.nz/ada_95.htm





^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: Tasks unleashed
  2003-05-11  5:35     ` Craig Carey
@ 2003-05-11 15:35       ` Pascal Obry
  0 siblings, 0 replies; 9+ messages in thread
From: Pascal Obry @ 2003-05-11 15:35 UTC (permalink / raw)



Craig Carey <research@ijs.co.nz> writes:

> Recovering the memory of a task silently fails if the task was not
>  finished.
> 
> ** Test 1: the memory leak is completely absent:
>    for K in 1 .. 20_000 loop  -- N=20,000
>       X := new A.Tt;
>       N := N + 1;
>       X.The_End;
>       delay 1.0E-30;    --  [1]
>       Free (X);         --  [2]
>    end loop;

[1] is not right here. The delay could still not be enough. What I usually do
is loop until 'Terminated is true.

Something like: (not compiled)

    for K in 1 .. 20_000 loop  -- N=20,000
       X := new A.Tt;
       N := N + 1;
       X.The_End;

       loop
          exit when X'Terminated;
          delay 1.0E-30;    --  [1]
       end loop;

       Free (X);         --  [2]
    end loop;     

Pascal.

-- 

--|------------------------------------------------------
--| Pascal Obry                           Team-Ada Member
--| 45, rue Gabriel Peri - 78114 Magny Les Hameaux FRANCE
--|------------------------------------------------------
--|         http://perso.wanadoo.fr/pascal.obry
--| "The best way to travel is by means of imagination"
--|
--| gpg --keyserver wwwkeys.pgp.net --recv-key C1082595



^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2003-05-11 15:35 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-05-01 14:01 Tasks unleashed Jano
2003-05-01 15:40 ` Stephen Leake
2003-05-01 16:14 ` Robert A Duff
2003-05-01 16:30   ` Jano
2003-05-02  1:14 ` tmoran
2003-05-02 11:21   ` Jano
2003-05-02 23:52     ` tmoran
2003-05-11  5:35     ` Craig Carey
2003-05-11 15:35       ` Pascal Obry

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