joe@petsd.UUCP (Joe Orost) (12/12/84)
<> See announcement in net.lang.ada. ------------------------------CUT HERE------------------------------ #!/bin/sh cat >README <<'------ EOF ------' PERFORMANCE TESTING OF SOME ADA PROGRAMMING CONTRUCTS SRI is developing a packet switched network node, using the Ada programming language, and using the SUN Microsystem processor board as the target hardware, which contains a MC68000. We have run some timing measurements on specially written Ada test programs in order to determine how to optimally use tasking, rendevous, selects, and parameter passing, and also to make an early prediction on the packet-per-second throughput of the system. The test were compiled with the Telesoft Ada Compiler on a Diskless SUN Workstation, running UNIX 4.1c bsd. The workstation was configured with 2 megabytes of local memory, and only a single user was logged in. When the Run command is given to start the Ada program, it takes about 5 seconds for the run-time support environment to be loaded to the diskless sun. Therefore timing is not started until a prompt from the program is answered by the user with a carriage return. Timing is done manually with a stopwatch. The program may optionally turn on printing, to check for deadlock situations, by answering the promt with a 'y' - this of course slows down the program, and these runs should not be used for performance measuring. Most of the timings for each program were repeated 5 times, and the variance in time was seldom more than a second. Timings given are the averages for multiple trials. Following the times below is a summary of the program characteristics and the conclusions drawn from the tests. program cycles seconds ________________________________________ chain2 1000 3.57 chain5 1000 10.15 chain10 1000 19.66 chain20 1000 38.03 idle1 10000 29.46 idle5 - idle10 - idle20 10000 29.93 select2 1000 4.38 select2e 1000 4.38 select20 1000 8.42 select20e 1000 8.33 guard2 1000 4.28 guard2e 1000 4.22 guard20 1000 6.20 guard20e 1000 6.11 guard20t 1000 8.31 guard20et 1000 8.11 chain2n 10000 29.58 chain2pkt 10000 29.77 chain2ptr 10000 29.98 passarrys 10000 29. passarryb 10000 29. passinout 10000 29. moretasks 1000 38. moretasksl 1000 47. moreselct 1000 128. moreselctr 1000 130. order31 100 28. order31r 100 28. order32 compiles without errors, but crashes when run order100 compiles without errors, but crashes when run DESCRIPTION OF TEST PROGRAMS AND RESULTS CHAIN - TO DETERMINE OVERHEAD IN CONTEXTS SWITCHES BETWEEN TASKS Each chain task, within each cycle of the loop, calls an entry in the "next task" in a chain of tasks, the called entry contains a null statement and returns, and the tasks then waits to be called by another task at a similar entry of its own. Thus each task is run in turn dependent on its position in the chain. Chains of length 2, 5, 10, and 20 tasks were compared after 1000 complete cycles around the chain. Times recorded were chain2 1000 3.57 chain5 1000 10.15 chain10 1000 19.66 chain20 1000 38.03 Dividing these times by the number of tasks in each test yields respectively 1.78, 2.03, 1.96, and 1.90; dividing by the number of cycles then indicates that each context switch (rendezvous) costs about 2 millisec. IDLE - DETERMINE WHETHER IDLE TASKS IMPACT PERFORMANCE A chain of length 2 as described above was cycled 10000 times, before the cycles are started, some number of "idle" task are called at an "init" entry and are then left waiting at a "never" entry which will never be called. The timings for 1 and 20 idle task are recorded below idle1 10000 29.46 idle5 - idle10 - idle20 10000 29.93 Within the accuracy of the measurements, there is no difference in the timings, which implies that there is no performance penalty for increasing numbers of tasks waiting on a single entrys. SELECT - DOES THE NUMBER OF SELECT CHOICES MATTER One task calls a single entry of a second task 1000 times, but the second task has a select statement encompassing some number of alternatives. The test was done for 2 and 20 alternatives, with the desired entry being the first one in the select list, and repeated for the desired entry being at the end of the select list. select2 1000 4.38 select2e 1000 4.38 select20 1000 8.42 select20e 1000 8.33 These results show that large select statements are costly. GUARDS - DO GUARDS ON ENTRY STATEMENTS IMPACT PERFORMANCE The select tests above were repeated with boolean guards placed in front of all the entry choices. In some cases, only the guard on the entry which would really be called was true, and all of the other guards were false. In other cases, all of the guards were set to true. guard2 1000 4.28 guard2e 1000 4.22 guard20 1000 6.20 guard20e 1000 6.11 guard20t 1000 8.31 guard20et 1000 8.11 Comparing these results with the previous tests, it appears that the cost of using guards on select entrys is very small. A guard which evaluates to false apparently significantly reduces the overhead of evaluating the guarded select. PARAMETERS - WHAT IS THE IMPACT OF PASSING PARAMETERS IN RENDEVOUS The following chain test were run passing "no" parameters, passing a packet record as a parameter, and passing a pointer to a record. chain2n 10000 29.58 chain2pkt 10000 29.77 chain2ptr 10000 29.98 The results show the there is no measurable cost in using entry parameters. PARAMETER SIZE - DOES SIZE OF THE PASSED PARAMETER MAKE A DIFFERENCE The above test was repeated with a parameters as follows. A "in" small integer array of length 2, an "in" integer array length 32000, and an "in out" integer array length 32000. passarrys 10000 29. passarryb 10000 29. passinout 10000 29. There is no observed cost in using large structures as parameters. TASKS - IS IT BETTER TO HAVE LOTS OF LITTLE TASKS WITH SINGLE ENTRY CHOICES OR FEW BIG TASKS WITH MANY SELECT CHOICES Some of the previous results would imply the use of many tasks. In the "moretasks" tests, a master tasks calls each of 20 slave tasks, each with a single entry. In "moretasksl" each task again has a single entry, but it is embedded in a select statement for fair comparison to the next test. In "moreselct" a master task calls each of the 20 entrys in a single slave task, and the slave task has the 20 entrys embedded in a large select statement. In the "moreselctr" the 20 entrys are listed in the opposite order to which the master calls them. moretasks 1000 38. moretasksl 1000 47. moreselct 1000 128. moreselctr 1000 130. The results suggest to use lots of tasks with few select choices. ORDER - DOES ORDERING OF ENTRY CLAUSES IN A SELECT MATTER The "moreselct" test was modified by increasing the number of entry clauses to 100. However it was discovered that a select statement can only contain a maximum of 31 choices. Then the program was run for 100 cycles. Another test was run calling the entrys in the reverse of the select statement. order31 100 28. order31r 100 28. order32 compiles without errors, but crashes when run order100 compiles without errors, but crashes when run No difference was determined, however if a large select clause were permitted (100 entries) it may have suggested which ordering was optimal. SCHEDTEST - DETERMINE WHETHER THE ADA SCHEDULER MAY STARVE A TASK A slave task with a two entry select statement is used independently by three other tasks. The test is run until the slave has been called 1000 times. Two of the tasks call the first entry, and the third task calls the second slave entry. Each task, and the slave have print statements to help determine which task is running. The order and relative frequency of the tasks printout will show whether any of the task are starved or run more often than the others. When the test was run, it was seen that the three tasks alternately print their rendezous annoucement once each. Thus, none of the tasks were starved, and rescheduling apparently occurs with the frequency of one rendezous. CONCLUSIONS The overhead of a rendevous or task context switch takes 1 - 2 millisecs. The number of idle tasks waiting on uncalled entries, do not impact speed. The number of entrys in a select significantly impacts selection speed. Evaluation of "when" clauses is quick, and when false, prevent the long select evaluation time, speeding the system. Passing parameters in rendezous is quick, and there is not much difference on parameter size or whether "in" or "in out". The ordering of entrys in a select clause in not important. To build an optimized system, use more tasks, each with less number of entries in select clauses, and use guards. CAUTIONS Array index are apparently limited to 32000 elements. Selects may have no more than 31 possible entries. TELESOFT COMPILER LIMITATIONS The Telesoft Ada Compiler that we have used for performing these benchmarks is not a complete implementation of the language. Telesoft is currently in the process of validating their full Ada compiler, and we will then get an update with the full language implemented. Some of the deficiencies of the language, which affected our selection of benchmarks and programming style, are generics, subunits, some pragmas, representation specifications, tasks types, entry families, timed entry calls and the calendar package, and the abort statement. SUGGESTIONS FOR FURTHER ADA BENCHMARK STUDIES Most of the test which we performed were concerned with determining how to optimize task and select statement organization. However, it is important to understand many of the other facilites of the rich language, some of which are not yet implemented in our compiler. Particularly in our application of a real time packet switching node, we should study the performance of representation specifications, low level input/output, the timing facilities, aborts, and interrupt handling. ------ EOF ------ ls -l README cat >chain10.ada <<'------ EOF ------' -- ada tasking tester -- task head is the controller -- tasks link are the chain of tasks -- tasks idle are the standby tasks with text_io; use text_io; procedure test is cycles: integer; printon: boolean; answer: character; task head is entry give; end head; task link2 is entry give; end link2; task link3 is entry give; end link3; task link4 is entry give; end link4; task link5 is entry give; end link5; task link11 is entry give; end link11; task link12 is entry give; end link12; task link13 is entry give; end link13; task link14 is entry give; end link14; task link15 is entry give; end link15; task body head is begin put("do you want printing (y/n)? "); get(answer); put("answer is "); put(answer); put_line(" "); if answer='y' then printon := true; else printon := false; end if; if printon then put_line("printing on"); else put_line("print off"); end if; put("how many cycles? "); -- doesn't work get_line(cycles); cycles := 1000; put_line("started"); for i in 1..cycles loop if printon then put_line("head"); end if; link2.give; accept give do null; end give; end loop; put_line("ended"); end head; task body link2 is begin loop accept give do null; end give; if printon then put_line("link2"); end if; link3.give; end loop; end link2; task body link3 is begin loop accept give do null; end give; if printon then put_line("link3"); end if; link4.give; end loop; end link3; task body link4 is begin loop accept give do null; end give; if printon then put_line("link4"); end if; link5.give; end loop; end link4; task body link5 is begin loop accept give do null; end give; if printon then put_line("link5"); end if; link11.give; end loop; end link5; task body link11 is begin loop accept give do null; end give; if printon then put_line("link11"); end if; link12.give; end loop; end link11; task body link12 is begin loop accept give do null; end give; if printon then put_line("link12"); end if; link13.give; end loop; end link12; task body link13 is begin loop accept give do null; end give; if printon then put_line("link13"); end if; link14.give; end loop; end link13; task body link14 is begin loop accept give do null; end give; if printon then put_line("link14"); end if; link15.give; end loop; end link14; task body link15 is begin loop accept give do null; end give; if printon then put_line("link15"); end if; head.give; end loop; end link15; begin null; end test; ------ EOF ------ ls -l chain10.ada cat >chain2.ada <<'------ EOF ------' -- ada tasking tester -- task head is the controller -- tasks link are the chain of tasks -- tasks idle are the standby tasks with text_io; use text_io; procedure test is cycles: integer; printon: boolean; answer: character; task head is entry give; end head; task link1 is entry give; end link1; task body head is begin put("do you want printing (y/n)? "); get(answer); put("answer is "); put(answer); put_line(" "); if answer='y' then printon := true; else printon := false; end if; if printon then put_line("printing on"); else put_line("print off"); end if; put("how many cycles? "); -- doesn't work get_line(cycles); cycles := 1000; put_line("started"); for i in 1..cycles loop if printon then put_line("head"); end if; link1.give; accept give do null; end give; end loop; put_line("ended"); end head; task body link1 is begin loop accept give do null; end give; if printon then put_line("link1"); end if; head.give; end loop; end link1; begin null; end test; ------ EOF ------ ls -l chain2.ada cat >chain20.ada <<'------ EOF ------' -- ada tasking tester -- task head is the controller -- tasks link are the chain of tasks -- tasks idle are the standby tasks with text_io; use text_io; procedure test is cycles: integer; printon: boolean; answer: character; task head is entry give; end head; task link2 is entry give; end link2; task link3 is entry give; end link3; task link4 is entry give; end link4; task link5 is entry give; end link5; task link11 is entry give; end link11; task link12 is entry give; end link12; task link13 is entry give; end link13; task link14 is entry give; end link14; task link15 is entry give; end link15; task link21 is entry give; end link21; task link22 is entry give; end link22; task link23 is entry give; end link23; task link24 is entry give; end link24; task link25 is entry give; end link25; task link211 is entry give; end link211; task link212 is entry give; end link212; task link213 is entry give; end link213; task link214 is entry give; end link214; task link215 is entry give; end link215; task body head is begin put("do you want printing (y/n)? "); get(answer); put("answer is "); put(answer); put_line(" "); if answer='y' then printon := true; else printon := false; end if; if printon then put_line("printing on"); else put_line("print off"); end if; put("how many cycles? "); -- doesn't work get_line(cycles); cycles := 1000; put_line("started"); for i in 1..cycles loop if printon then put_line("head"); end if; link2.give; accept give do null; end give; end loop; put_line("ended"); end head; task body link2 is begin loop accept give do null; end give; if printon then put_line("link2"); end if; link3.give; end loop; end link2; task body link3 is begin loop accept give do null; end give; if printon then put_line("link3"); end if; link4.give; end loop; end link3; task body link4 is begin loop accept give do null; end give; if printon then put_line("link4"); end if; link5.give; end loop; end link4; task body link5 is begin loop accept give do null; end give; if printon then put_line("link5"); end if; link11.give; end loop; end link5; task body link11 is begin loop accept give do null; end give; if printon then put_line("link11"); end if; link12.give; end loop; end link11; task body link12 is begin loop accept give do null; end give; if printon then put_line("link12"); end if; link13.give; end loop; end link12; task body link13 is begin loop accept give do null; end give; if printon then put_line("link13"); end if; link14.give; end loop; end link13; task body link14 is begin loop accept give do null; end give; if printon then put_line("link14"); end if; link15.give; end loop; end link14; task body link15 is begin loop accept give do null; end give; if printon then put_line("link15"); end if; link21.give; end loop; end link15; task body link21 is begin loop accept give do null; end give; if printon then put_line("link21"); end if; link22.give; end loop; end link21; task body link22 is begin loop accept give do null; end give; if printon then put_line("link22"); end if; link23.give; end loop; end link22; task body link23 is begin loop accept give do null; end give; if printon then put_line("link23"); end if; link24.give; end loop; end link23; task body link24 is begin loop accept give do null; end give; if printon then put_line("link24"); end if; link25.give; end loop; end link24; task body link25 is begin loop accept give do null; end give; if printon then put_line("link25"); end if; link211.give; end loop; end link25; task body link211 is begin loop accept give do null; end give; if printon then put_line("link211"); end if; link212.give; end loop; end link211; task body link212 is begin loop accept give do null; end give; if printon then put_line("link212"); end if; link213.give; end loop; end link212; task body link213 is begin loop accept give do null; end give; if printon then put_line("link213"); end if; link214.give; end loop; end link213; task body link214 is begin loop accept give do null; end give; if printon then put_line("link214"); end if; link215.give; end loop; end link214; task body link215 is begin loop accept give do null; end give; if printon then put_line("link215"); end if; head.give; end loop; end link215; begin null; end test; ------ EOF ------ ls -l chain20.ada cat >chain2n.ada <<'------ EOF ------' -- ada tasking tester -- task head is the controller -- tasks link are the chain of tasks -- tasks idle are the standby tasks with text_io; use text_io; procedure test is cycles: integer; printon: boolean; answer: character; task head is entry give; end head; task link1 is entry give; end link1; task body head is begin put("do you want printing (y/n)? "); get(answer); put("answer is "); put(answer); put_line(" "); if answer='y' then printon := true; else printon := false; end if; if printon then put_line("printing on"); else put_line("print off"); end if; put("how many cycles? "); -- doesn't work get_line(cycles); cycles := 10000; put_line("started"); for i in 1..cycles loop if printon then put_line("head"); end if; link1.give; accept give do null; end give; end loop; put_line("ended"); end head; task body link1 is begin loop accept give do null; end give; if printon then put_line("link1"); end if; head.give; end loop; end link1; begin null; end test; ------ EOF ------ ls -l chain2n.ada cat >chain2pkt.ada <<'------ EOF ------' -- ada tasking tester -- task head is the controller -- tasks link are the chain of tasks -- tasks idle are the standby tasks with text_io; use text_io; procedure test is cycles: integer; printon: boolean; answer: character; type vector is array(integer range <>) of integer; type pkt_type; type pkt_ptr is access pkt_type; type pkt_type is record next: pkt_ptr; header: vector(1..25); data: string(1..50); tailer: vector(1..25); end record; task head is entry give(p:in pkt_type); end head; task link1 is entry give(p:in pkt_type); end link1; task body head is pkt : pkt_type; begin put("do you want printing (y/n)? "); get(answer); put("answer is "); put(answer); put_line(" "); if answer='y' then printon := true; else printon := false; end if; if printon then put_line("printing on"); else put_line("print off"); end if; put("how many cycles? "); -- doesn't work get_line(cycles); cycles := 10000; put_line("started"); for i in 1..cycles loop if printon then put_line("head"); end if; link1.give(pkt); accept give(p:in pkt_type) do null; end give; end loop; put_line("ended"); end head; task body link1 is pkt: pkt_type; begin loop accept give(p:in pkt_type) do null; end give; if printon then put_line("link1"); end if; head.give(pkt); end loop; end link1; begin null; end test; ------ EOF ------ ls -l chain2pkt.ada cat >chain2ptr.ada <<'------ EOF ------' -- ada tasking tester -- task head is the controller -- tasks link are the chain of tasks -- tasks idle are the standby tasks with text_io; use text_io; procedure test is cycles: integer; printon: boolean; answer: character; type vector is array(integer range <>) of integer; type pkt_type; type pkt_ptr is access pkt_type; type pkt_type is record next: pkt_ptr; header: vector(1..25); data: string(1..50); tailer: vector(1..25); end record; task head is entry give(p:in pkt_ptr); end head; task link1 is entry give(p:in pkt_ptr); end link1; task body head is pkt : pkt_ptr; begin pkt := new pkt_type; put("do you want printing (y/n)? "); get(answer); put("answer is "); put(answer); put_line(" "); if answer='y' then printon := true; else printon := false; end if; if printon then put_line("printing on"); else put_line("print off"); end if; put("how many cycles? "); -- doesn't work get_line(cycles); cycles := 10000; put_line("started"); for i in 1..cycles loop if printon then put_line("head"); end if; link1.give(pkt); accept give(p:in pkt_ptr) do null; end give; end loop; put_line("ended"); end head; task body link1 is pkt: pkt_ptr; begin pkt := new pkt_type; loop accept give(p:in pkt_ptr) do null; end give; if printon then put_line("link1"); end if; head.give(pkt); end loop; end link1; begin null; end test; ------ EOF ------ ls -l chain2ptr.ada cat >chain5.ada <<'------ EOF ------' -- ada tasking tester -- task head is the controller -- tasks link are the chain of tasks -- tasks idle are the standby tasks with text_io; use text_io; procedure test is cycles: integer; printon: boolean; answer: character; task head is entry give; end head; task link2 is entry give; end link2; task link3 is entry give; end link3; task link4 is entry give; end link4; task link5 is entry give; end link5; task body head is begin put("do you want printing (y/n)? "); get(answer); put("answer is "); put(answer); put_line(" "); if answer='y' then printon := true; else printon := false; end if; if printon then put_line("printing on"); else put_line("print off"); end if; put("how many cycles? "); -- doesn't work get_line(cycles); cycles := 1000; put_line("started"); for i in 1..cycles loop if printon then put_line("head"); end if; link2.give; accept give do null; end give; end loop; put_line("ended"); end head; task body link2 is begin loop accept give do null; end give; if printon then put_line("link2"); end if; link3.give; end loop; end link2; task body link3 is begin loop accept give do null; end give; if printon then put_line("link3"); end if; link4.give; end loop; end link3; task body link4 is begin loop accept give do null; end give; if printon then put_line("link4"); end if; link5.give; end loop; end link4; task body link5 is begin loop accept give do null; end give; if printon then put_line("link5"); end if; head.give; end loop; end link5; begin null; end test; ------ EOF ------ ls -l chain5.ada cat >guard2.ada <<'------ EOF ------' -- ada tasking tester -- task head is the controller -- tasks link are the chain of tasks -- tasks idle are the standby tasks with text_io; use text_io; procedure test is cycles: integer; printon: boolean; answer: character; g1: boolean := true; g2: boolean := false; task head is entry give; end head; task link1 is entry give; entry s2; end link1; task body head is begin put("do you want printing (y/n)? "); get(answer); put("answer is "); put(answer); put_line(" "); if answer='y' then printon := true; else printon := false; end if; if printon then put_line("printing on"); else put_line("print off"); end if; put("how many cycles? "); -- doesn't work get_line(cycles); cycles := 1000; put_line("started"); for i in 1..cycles loop if printon then put_line("head"); end if; link1.give; accept give do null; end give; end loop; put_line("ended"); end head; task body link1 is begin loop select when g1 => accept give do null; end give; or when g2 => accept s2 do null; end s2; end select; if printon then put_line("link1"); end if; head.give; end loop; end link1; begin null; end test; ------ EOF ------ ls -l guard2.ada cat >guard20.ada <<'------ EOF ------' -- ada tasking tester -- task head is the controller -- tasks link are the chain of tasks -- tasks idle are the standby tasks with text_io; use text_io; procedure test is cycles: integer; printon: boolean; answer: character; g1: boolean := true; g2: boolean := false; g3: boolean := false; g4: boolean := false; g5: boolean := false; g6: boolean := false; g7: boolean := false; g8: boolean := false; g9: boolean := false; g10: boolean := false; g11: boolean := false; g12: boolean := false; g13: boolean := false; g14: boolean := false; g15: boolean := false; g16: boolean := false; g17: boolean := false; g18: boolean := false; g19: boolean := false; g20: boolean := false; task head is entry give; end head; task link1 is entry give; entry s2; entry s3; entry s4; entry s5; entry s6; entry s7; entry s8; entry s9; entry s10; entry s11; entry s12; entry s13; entry s14; entry s15; entry s16; entry s17; entry s18; entry s19; entry s20; end link1; task body head is begin put("do you want printing (y/n)? "); get(answer); put("answer is "); put(answer); put_line(" "); if answer='y' then printon := true; else printon := false; end if; if printon then put_line("printing on"); else put_line("print off"); end if; put("how many cycles? "); -- doesn't work get_line(cycles); cycles := 1000; put_line("started"); for i in 1..cycles loop if printon then put_line("head"); end if; link1.give; accept give do null; end give; end loop; put_line("ended"); end head; task body link1 is begin loop select when g1 => accept give do null; end give; or when g2 => accept s2 do null; end s2; or when g3 => accept s3 do null; end s3; or when g4 => accept s4 do null; end s4; or when g5 => accept s5 do null; end s5; or when g6 => accept s6 do null; end s6; or when g7 => accept s7 do null; end s7; or when g8 => accept s8 do null; end s8; or when g9 => accept s9 do null; end s9; or when g10 => accept s10 do null; end s10; or when g11 => accept s11 do null; end s11; or when g12 => accept s12 do null; end s12; or when g13 => accept s13 do null; end s13; or when g14 => accept s14 do null; end s14; or when g15 => accept s15 do null; end s15; or when g16 => accept s16 do null; end s16; or when g17 => accept s17 do null; end s17; or when g18 => accept s18 do null; end s18; or when g19 => accept s19 do null; end s19; or when g20 => accept s20 do null; end s20; end select; if printon then put_line("link1"); end if; head.give; end loop; end link1; begin null; end test; ------ EOF ------ ls -l guard20.ada cat >guard20e.ada <<'------ EOF ------' -- ada tasking tester -- task head is the controller -- tasks link are the chain of tasks -- tasks idle are the standby tasks with text_io; use text_io; procedure test is cycles: integer; printon: boolean; answer: character; g1: boolean := true; g2: boolean := false; g3: boolean := false; g4: boolean := false; g5: boolean := false; g6: boolean := false; g7: boolean := false; g8: boolean := false; g9: boolean := false; g10: boolean := false; g11: boolean := false; g12: boolean := false; g13: boolean := false; g14: boolean := false; g15: boolean := false; g16: boolean := false; g17: boolean := false; g18: boolean := false; g19: boolean := false; g20: boolean := false; task head is entry give; end head; task link1 is entry give; entry s2; entry s3; entry s4; entry s5; entry s6; entry s7; entry s8; entry s9; entry s10; entry s11; entry s12; entry s13; entry s14; entry s15; entry s16; entry s17; entry s18; entry s19; entry s20; end link1; task body head is begin put("do you want printing (y/n)? "); get(answer); put("answer is "); put(answer); put_line(" "); if answer='y' then printon := true; else printon := false; end if; if printon then put_line("printing on"); else put_line("print off"); end if; put("how many cycles? "); -- doesn't work get_line(cycles); cycles := 1000; put_line("started"); for i in 1..cycles loop if printon then put_line("head"); end if; link1.give; accept give do null; end give; end loop; put_line("ended"); end head; task body link1 is begin loop select when g2 => accept s2 do null; end s2; or when g3 => accept s3 do null; end s3; or when g4 => accept s4 do null; end s4; or when g5 => accept s5 do null; end s5; or when g6 => accept s6 do null; end s6; or when g7 => accept s7 do null; end s7; or when g8 => accept s8 do null; end s8; or when g9 => accept s9 do null; end s9; or when g10 => accept s10 do null; end s10; or when g11 => accept s11 do null; end s11; or when g12 => accept s12 do null; end s12; or when g13 => accept s13 do null; end s13; or when g14 => accept s14 do null; end s14; or when g15 => accept s15 do null; end s15; or when g16 => accept s16 do null; end s16; or when g17 => accept s17 do null; end s17; or when g18 => accept s18 do null; end s18; or when g19 => accept s19 do null; end s19; or when g20 => accept s20 do null; end s20; or when g1 => accept give do null; end give; end select; if printon then put_line("link1"); end if; head.give; end loop; end link1; begin null; end test; ------ EOF ------ ls -l guard20e.ada cat >guard20et.ada <<'------ EOF ------' -- ada tasking tester -- task head is the controller -- tasks link are the chain of tasks -- tasks idle are the standby tasks with text_io; use text_io; procedure test is cycles: integer; printon: boolean; answer: character; g1: boolean := true; g2: boolean := true; g3: boolean := true; g4: boolean := true; g5: boolean := true; g6: boolean := true; g7: boolean := true; g8: boolean := true; g9: boolean := true; g10: boolean := true; g11: boolean := true; g12: boolean := true; g13: boolean := true; g14: boolean := true; g15: boolean := true; g16: boolean := true; g17: boolean := true; g18: boolean := true; g19: boolean := true; g20: boolean := true; task head is entry give; end head; task link1 is entry give; entry s2; entry s3; entry s4; entry s5; entry s6; entry s7; entry s8; entry s9; entry s10; entry s11; entry s12; entry s13; entry s14; entry s15; entry s16; entry s17; entry s18; entry s19; entry s20; end link1; task body head is begin put("do you want printing (y/n)? "); get(answer); put("answer is "); put(answer); put_line(" "); if answer='y' then printon := true; else printon := false; end if; if printon then put_line("printing on"); else put_line("print off"); end if; put("how many cycles? "); -- doesn't work get_line(cycles); cycles := 1000; put_line("started"); for i in 1..cycles loop if printon then put_line("head"); end if; link1.give; accept give do null; end give; end loop; put_line("ended"); end head; task body link1 is begin loop select when g2 => accept s2 do null; end s2; or when g3 => accept s3 do null; end s3; or when g4 => accept s4 do null; end s4; or when g5 => accept s5 do null; end s5; or when g6 => accept s6 do null; end s6; or when g7 => accept s7 do null; end s7; or when g8 => accept s8 do null; end s8; or when g9 => accept s9 do null; end s9; or when g10 => accept s10 do null; end s10; or when g11 => accept s11 do null; end s11; or when g12 => accept s12 do null; end s12; or when g13 => accept s13 do null; end s13; or when g14 => accept s14 do null; end s14; or when g15 => accept s15 do null; end s15; or when g16 => accept s16 do null; end s16; or when g17 => accept s17 do null; end s17; or when g18 => accept s18 do null; end s18; or when g19 => accept s19 do null; end s19; or when g20 => accept s20 do null; end s20; or when g1 => accept give do null; end give; end select; if printon then put_line("link1"); end if; head.give; end loop; end link1; begin null; end test; ------ EOF ------ ls -l guard20et.ada cat >guard20t.ada <<'------ EOF ------' -- ada tasking tester -- task head is the controller -- tasks link are the chain of tasks -- tasks idle are the standby tasks with text_io; use text_io; procedure test is cycles: integer; printon: boolean; answer: character; g1: boolean := true; g2: boolean := true; g3: boolean := true; g4: boolean := true; g5: boolean := true; g6: boolean := true; g7: boolean := true; g8: boolean := true; g9: boolean := true; g10: boolean := true; g11: boolean := true; g12: boolean := true; g13: boolean := true; g14: boolean := true; g15: boolean := true; g16: boolean := true; g17: boolean := true; g18: boolean := true; g19: boolean := true; g20: boolean := true; task head is entry give; end head; task link1 is entry give; entry s2; entry s3; entry s4; entry s5; entry s6; entry s7; entry s8; entry s9; entry s10; entry s11; entry s12; entry s13; entry s14; entry s15; entry s16; entry s17; entry s18; entry s19; entry s20; end link1; task body head is begin put("do you want printing (y/n)? "); get(answer); put("answer is "); put(answer); put_line(" "); if answer='y' then printon := true; else printon := false; end if; if printon then put_line("printing on"); else put_line("print off"); end if; put("how many cycles? "); -- doesn't work get_line(cycles); cycles := 1000; put_line("started"); for i in 1..cycles loop if printon then put_line("head"); end if; link1.give; accept give do null; end give; end loop; put_line("ended"); end head; task body link1 is begin loop select when g1 => accept give do null; end give; or when g2 => accept s2 do null; end s2; or when g3 => accept s3 do null; end s3; or when g4 => accept s4 do null; end s4; or when g5 => accept s5 do null; end s5; or when g6 => accept s6 do null; end s6; or when g7 => accept s7 do null; end s7; or when g8 => accept s8 do null; end s8; or when g9 => accept s9 do null; end s9; or when g10 => accept s10 do null; end s10; or when g11 => accept s11 do null; end s11; or when g12 => accept s12 do null; end s12; or when g13 => accept s13 do null; end s13; or when g14 => accept s14 do null; end s14; or when g15 => accept s15 do null; end s15; or when g16 => accept s16 do null; end s16; or when g17 => accept s17 do null; end s17; or when g18 => accept s18 do null; end s18; or when g19 => accept s19 do null; end s19; or when g20 => accept s20 do null; end s20; end select; if printon then put_line("link1"); end if; head.give; end loop; end link1; begin null; end test; ------ EOF ------ ls -l guard20t.ada cat >guard2e.ada <<'------ EOF ------' -- ada tasking tester -- task head is the controller -- tasks link are the chain of tasks -- tasks idle are the standby tasks with text_io; use text_io; procedure test is cycles: integer; printon: boolean; answer: character; g1: boolean := true; g2: boolean := false; task head is entry give; end head; task link1 is entry give; entry s2; end link1; task body head is begin put("do you want printing (y/n)? "); get(answer); put("answer is "); put(answer); put_line(" "); if answer='y' then printon := true; else printon := false; end if; if printon then put_line("printing on"); else put_line("print off"); end if; put("how many cycles? "); -- doesn't work get_line(cycles); cycles := 1000; put_line("started"); for i in 1..cycles loop if printon then put_line("head"); end if; link1.give; accept give do null; end give; end loop; put_line("ended"); end head; task body link1 is begin loop select when g2 => accept s2 do null; end s2; or when g1 => accept give do null; end give; end select; if printon then put_line("link1"); end if; head.give; end loop; end link1; begin null; end test; ------ EOF ------ ls -l guard2e.ada