From: Eric Hughes on
On Mar 29, 7:51 am, kongra <kon...(a)gmail.com> wrote:
> Start_T := Ada.Real_Time.Clock;
> for K in 1 .. 10 loop
> for I in 1 .. 10_000_000 loop
> Val := Val + I;
> end loop;
> end loop;
> End_T := Ada.Real_Time.Clock;

I have a question about this piece of the program. Because the middle
uses only variables 'K', 'I', and 'Val', and the side-effects of
modifying these variables are entirely local, and because there's no
inter-dependency of these variables upon either the first or last
statements, aren't the following reorderings legal for code
generation? To wit:

Long_Statement ;
Start_T := Ada.Real_Time.Clock ;
End_T := Ada.Real_Time.Clock ;

Start_T := Ada.Real_Time.Clock ;
End_T := Ada.Real_Time.Clock ;
Long_Statement ;

Irrelevant to the quirks mentioned earlier, isn't it legal operation
for the interval to come out zero? It seems that for known-correct
operation for all possible compilers you'd need to manually serialize
these operations in the order desired.

Eric
From: Robert A Duff on
Eric Hughes <eric.eh9(a)gmail.com> writes:

> On Mar 29, 7:51 am, kongra <kon...(a)gmail.com> wrote:
>> Start_T := Ada.Real_Time.Clock;
>> for K in 1 .. 10 loop
>> for I in 1 .. 10_000_000 loop
>> Val := Val + I;
>> end loop;
>> end loop;
>> End_T := Ada.Real_Time.Clock;
>
> I have a question about this piece of the program. Because the middle
> uses only variables 'K', 'I', and 'Val', and the side-effects of
> modifying these variables are entirely local, and because there's no
> inter-dependency of these variables upon either the first or last
> statements, aren't the following reorderings legal for code
> generation? To wit:
>
> Long_Statement ;
> Start_T := Ada.Real_Time.Clock ;
> End_T := Ada.Real_Time.Clock ;
>
> Start_T := Ada.Real_Time.Clock ;
> End_T := Ada.Real_Time.Clock ;
> Long_Statement ;
>
> Irrelevant to the quirks mentioned earlier, isn't it legal operation
> for the interval to come out zero?

Yes.

For example, I can calculate the final value of Val with pencil and
paper, so I guess I could teach an optimizer to do it at compile time.
;-)

>...It seems that for known-correct
> operation for all possible compilers you'd need to manually serialize
> these operations in the order desired.

The only thing that's guaranteed is I/O behavior, so you have to do some
I/O. And you should inspect the generated machine code to see if you're
measuring what you think you're measuring. In other words, this sort of
thing is pretty much outside the language definition. Also, it might be
better to measure using outside tools, like the Unix 'time' command, or
perhaps a stopwatch.

- Bob
From: Eric Hughes on
On Mar 30, 12:59 pm, Robert A Duff <bobd...(a)shell01.TheWorld.com>
wrote:
> The only thing that's guaranteed is I/O behavior, so you have to do some
> I/O.

Only? You can also count on task termination, no? Example code
below.

Eric


with Ada.Real_Time ;
with Ada.Text_IO ;
procedure Foo
is
Val : Natural := 0 ;
Start_T, End_T : Ada.Real_Time.Time ;
use Ada.Real_Time ;
begin
declare
task Start_Timer ;
task body Start_Timer is begin
Start_T := Ada.Real_Time.Clock ;
end ;
begin
null ;
end ;

declare
task Compute ;
task body Compute is begin
for K in 1 .. 10 loop
for I in 1 .. 10_000 loop
Val := Val + I * I ;
end loop;
end loop;
end ;
begin
null ;
end ;

declare
task End_Timer ;
task body End_Timer is begin
End_T := Ada.Real_Time.Clock ;
end ;
begin
null ;
end ;

Ada.Text_IO.Put_Line( Natural'Image( Val ) ) ;
Ada.Text_IO.Put_Line( Duration'Image( To_Duration( End_T -
Start_T ) ) ) ;

end Foo ;
From: Robert A Duff on
Eric Hughes <eric.eh9(a)gmail.com> writes:

> On Mar 30, 12:59 pm, Robert A Duff <bobd...(a)shell01.TheWorld.com>
> wrote:
>> The only thing that's guaranteed is I/O behavior, so you have to do some
>> I/O.
>
> Only? You can also count on task termination, no?

Insofar as it affects I/O, yes. And I suppose you can count on
termination of the program as a whole (that is, if all tasks
terminate, then so should the program).

>...Example code
> below.
>
> Eric
>
>
> with Ada.Real_Time ;
> with Ada.Text_IO ;
> procedure Foo
> is
> Val : Natural := 0 ;

Better make that modular, or this conversion gets confused by the
overflow issue. Oh, never mind, I see you reduced the counts,
and (if I can do that in my head correctly) it won't overflow. ;-)

> Start_T, End_T : Ada.Real_Time.Time ;
> use Ada.Real_Time ;
> begin
> declare
> task Start_Timer ;
> task body Start_Timer is begin
> Start_T := Ada.Real_Time.Clock ;
> end ;
> begin
> null ;
> end ;
>
> declare
> task Compute ;
> task body Compute is begin
> for K in 1 .. 10 loop
> for I in 1 .. 10_000 loop
> Val := Val + I * I ;
> end loop;
> end loop;
> end ;
> begin
> null ;
> end ;
>
> declare
> task End_Timer ;
> task body End_Timer is begin
> End_T := Ada.Real_Time.Clock ;
> end ;
> begin
> null ;
> end ;
>
> Ada.Text_IO.Put_Line( Natural'Image( Val ) ) ;
> Ada.Text_IO.Put_Line( Duration'Image( To_Duration( End_T -
> Start_T ) ) ) ;
>
> end Foo ;

I don't see any language rule that would prevent moving the calculation
of Val before or after the Start_Timer or End_Timer tasks, since they
don't use that value. Or in parallel with them. Or at compile time.

I'm not claiming that real compilers do these transformations
in practise, nor implying that they "should".

I suppose you could reasonably argue that the Clock in Start_Timer must
happen before the one in End_Timer (since a calculation based on those
values is printed out). So I guess it would be wrong to print
a negative time span.

Meaningful benchmarking is hard! ;-)

- Bob
 | 
Pages: 1
Prev: Text_IO from a stream
Next: ANN: Some updates