</motto<

>>

/chapter</ii<Optimointi>>

Perinteisen skalaarikoneen ohjelmaa optimoitaessa siit{ pyrit{{n
poistamaan kaikki tarpeettomat laskutoimitukset.  /ii<Vektoriprosessori>n
k{yt|n optimointi edellytt{{ my|s laskentaj{rjestyksen
huomioonottamista: ohjelmasta on mahdollisuuksien mukaan poistettava
vektoroinnin est{v{t riippuvuudet. Ohjelman vektoroituvuudesta
riippuen vektoriprosessorin antama lis{teho voi vaihdella hyvin
huomattavasti, joten ohjelman optimointiin kannattaa usein uhrata
hiukan aikaa. Erityisesti uutta ohjelmaa kirjoitettaessa kannattaa
mietti{, miten sen saisi vektoroitumaan mahdollisimman hyvin.

Vektoriprosessorin teho riippuu hyvin voimakkaasti suoritettavan koodin
yksityiskohdista.  Siksi ohjelman optimoinnilla saatetaan saada
h{mm{stytt{vi{ muutoksia CPU-ajassa.  Yksiprosessorisella koneella
oleellisinta on saada aikaan mahdollisimman paljon vektoroitua koodia.
Moniprosessorikoneella ohjelmaa voidaan lis{ksi rinnakkaistaa.  On
kuitenkin muistettava, ett{ sama ohjelma rinnakkaistettuna vie aina
enemm{n CPU-aikaa kuin vastaava yksiprosessorikoodi.  Silti
rinnakkaistamisesta on hy|ty{, sill{ se parantaa ohjelman l{pimenoaikaa
ja my|s koneen kokonaiskapasiteettia.

Ratkaisevan t{rke{{ ohjelman tehokkuuden kannalta on oikean
algoritmin valinta. Ongelma voidaan usein ratkaista monella
eri menetelm{ll{, joiden tehokkuudessa on huomattavia eroja.
Useimpia perusoperaatioita (yht{l|ryhm{n ratkaisu, determinantin
laskeminen, m{{r{tyn integraalin laskeminen, ...) varten
on olemassa hyvi{ ja tehokkaita aliohjelmia. Niit{ ei yleens{
kannata tehd{ itse. Jos teht{v{{n l|ytyy rutiini koneen valmistajan
oamasta kirjastosta (Crayll{ </sc/ii<scilib>>ist{), k{yt{ sit{, sill{
se on parhaiten optimoitu kyseiselle laitteistolle. 
Toinen vaihtoehto on k{ytt{{ jonkin tunnetun kirjaston
(</sc/ii<nag>>, </sc/ii<imsl>>, ...) rutiineja. Niiden etuna on siirrett{vyys 
my|s muille laitteistoille. 

Toinen t{rke{ asia on t{ysin tarpeettoman laskennan karsiminen.
Tietokoneaikaa haaskataan suuria m{{ri{ matriisien k{{ntelyyn,
vaikka kysymyksess{ on usein vain lineaarisen yht{l|ryhm{n ratkaiseminen.

Tyypillisesti 20/% ohjelmakoodista kuluttaa 80/% CPU-ajasta.
(Joidenkin mielest{ luvut ovat 10/% ja 90/%.)
Oleellista onkin etsi{ n{m{ aikaa viev{t osat; optimoinnissa
kannattaa keskitty{ vain niihin, sill{ harvoin suoritettavien osien
optimoinnilla ei ole mit{{n merkityst{ tehokkuuden kannalta.


/section<Optimoinnin vaiheet>

Ennenkuin rupeat virittelem{{n ohjelmaa, tarkista aivan aluksi
seuraavat asiat:

1) Tutki, lasketaanko ohjelmassa vain se mit{ tarvitaan.

2) Selvit{, voisiko osan ohjelmasta korvata valmiiden
kirjastoaliohjelmien kutsuilla.  Ellet ole numeriikan ja
ohjelmoinnin ammattilainen, {l{ kuvittele, ett{ pystyt itse
kirjoittamaan parempaa ja tehokkaampaa koodia. 

T{m{n j{lkeen voit sitten jatkaa oman ohjelmakoodisi
parantelua:

/iii<suorituskyvyn mittaaminen>
1) Ensimm{iseksi on aina syyt{ selvitt{{, miss{ ohjelma kuluttaa eniten
aikaa. Suorituskyvyn mittaamiseen on Crayll{ k{ytett{viss{ useita
ty|kaluja: </tt flowtrace>, </tt prof>, </tt hpm> ja </tt perftrace>.
N{it{ kaikkia k{sitell{{n seuraavassa tarkemmin.

/iii<vektoroituvuus>
2) Kun tied{t, miss{ ohjelma viett{{ aikansa, tutki, kuinka hyvin
k{{nt{j{ on onnistunut vektoroimaan n{m{ osat. T{m{n saa k{tevimmin
n{kyviin k{{nt{j{n optiolla </tt -em>.

3) T{rkein asia on saada eniten aikaa kuluttavat silmukat
vektoroitumaan mahdollisimman hyvin. Keskity aluksi nimenomaan
vektoroituvuuden parantamiseen.

4) Kun koodi vektoroituu niin hyvin kuin mahdollista, tutki
muut tehokkuuteen vaikuttavat asiat: muistikonfliktit,
silmukoiden sis{ll{ oleva tarpeeton tavara jne. N{ist{
asioista on esimerkkej{ luvussa /ref<17.8>.

5) Palaa askeleeseen 1. Optimoinnin j{lkeen on mahdollista, ett{
jokin toinen koodin kohta muodostuu nyt pullonkaulaksi.
[l{ kuitenkaan iteroi loputtomiin, sill{ seuraavilla kierroksilla
joudut todenn{k|isesti tekem{{n yh{ enemm{n ty|t{ yh{
pienemm{n tehon lis{yksen saavuttamiseksi.


/section</ii<Flowtrace>>

Yksinkertaisin tapa on k{{nt{{ ohjelma k{ytt{en optiota </tt -ef>
(/ii<flowtrace>), jolloin </tt stdout>-tiedostoon tulee tilasto
seuraavista asioista:

/beginitems

/entry Paljonko cpu-aikaa on k{ytetty kussakin aliohjelmassa;
       kokonaisaika, prosenttiosuus koko ajasta ja keskim{{r{inen aika
       (kokonaisaika//kutsujen lukum{{r{).
/entry Aliohjelmakutsujen lukum{{r{.
/entry Puumainen esitys aliohjelmakutsuista.

/enditems

Raportointi voidaan rajoittaa vain tiettyihin
aliohjelmiin k{{nt{j{n direktiiveill{; </tt cdir/$ /ii<flow>> asettaa
raportoinnin p{{lle, </tt cdir/$ /ii<noflow>> ottaa pois p{{lt{.


Seuraavassa on esimerkki flowtracen k{yt|st{ ja sen
antamasta tulostuksesta.  Esimerkiss{ k{{nnet{{n,
linkitet{{n ja suoritetaan ohjelma </tt nb.f>.  Flowtracen
raportti tulee tiedostoon (</tt stdout>). 

</font/tt = cmtt8 at 8truept/baselineskip=10truept/hsize=7.2truein
/beginverbatim

cft77 -ef nb.f
segldr -o nb nb.o
./nb > nb.out
cat nb.out
 F L O W T R A C E  --  Alphabetized summary                          Page   1

    Routine            Time executing  Called  Average T
  15 ANTIB           0.042   (  0.10%)   6001            > @00003712a Called by EQC
   8 AS7                 >   (  0.00%)      1            > @00002023a Called by PLANET
   2 DAYNUM              >   (  0.00%)      1            > @00004412a Called by EPHEM
  12 DOUT            0.216   (  0.53%)   6001            > @00003372a Called by INTEG
   1 EPHEM               >   (  0.00%)      1            > @00000050a Called by
  14 EQC             0.234   (  0.57%)   6001            > @00003600a Called by DOUT
   6 GREGOR              >   (  0.00%)     31            > Called by MOON TELL   
     @00004477a                                                             3    28
   3 INIT                >   (  0.00%)      1            > @00000123a Called by EPHEM
  11 INTEG          17.634   ( 43.24%)      1       17.634 @00003072a Called by AS7
   9 INTINI              >   (  0.00%)      1            > @00002115a Called by AS7
   4 MOON            0.208   (  0.51%)      1        0.208 @00000451a Called by EPHEM
   5 MOONEF         18.674   ( 45.79%)  48024            > @00000645a Called by MOON
   7 PLANET              >   (  0.00%)      1            > @00001771a Called by EPHEM
  13 PRECES          1.007   (  2.47%)  60010            > @00003453a Called by DOUT
  16 RADEC           2.736   (  6.71%)  54009            > @00003761a Called by EQC
  10 START           0.020   (  0.05%)      1        0.020 @00002445a Called by AS7
  17 TELL            0.006   (  0.02%)      1        0.006 @00004225a Called by PLANET
 * * * TOTAL        40.779     180087 Total calls

 F L O W T R A C E  --  Calling tree                                  Page   2

      1   EPHEM    00000050a
      2     DAYNUM   00004412a
      3     INIT     00000123a
      4     MOON     00000451a
      5       MOONEF   00000645a
      6       GREGOR   00004477a
      7     PLANET   00001771a
      8       AS7      00002023a
      9         INTINI   00002115a
     10         START    00002445a
     11         INTEG    00003072a
     12           DOUT     00003372a
     13             PRECES   00003453a
     14             EQC      00003600a
     15               ANTIB    00003712a
     16               RADEC    00003761a
     17       TELL     00004225a
     18         GREGOR   00004477a
/endverbatim>

Kuten raportista n{kyy, esimerkkiohjelmassa toteutuu varsin
hyvin mainittu 10/%--90/% s{{nt|.  Ohjelmassa on kaksi
aliohjelmaa, </tt INTEG> ja </tt MOONEF>, joissa k{ytet{{n
l{hes 90/% koko cpu-ajasta.  Aliohjelmaa </tt INTEG>
kutsutaan kerran ja se kuluttaa 17.634 sekuntia kun taas
</tt MOONEF> kuluttaa joka kutsulla alle 0.001 sekuntia,
mutta sit{ kutsutaan </tt 48024> kertaa, joten
kokonais/-ajaksi tulee 18.674 sekuntia. 

Flowtrace voidaan tehd{ my|s C-kieliselle ohjelmalle. Ohjelma
k{{nnet{{n ja linkitet{{n seuraavasti:

</copymode
      cc -cF prog.c
      segldr -o prog prog.o
>

J{ljitys hidastaa ohjelmaa huomattavasti, joten {l{ k{yt{ </tt f>-optiota
normaaliajoissa.


/section</ii<prof>>

Ohjelmalla </tt /ii<prof>> voidaan tutkia suoritettavaa
ohjelmaa tarkemmin kuin aliohjelmatasolla.  Tietyn
valittavissa olevan ajan v{lein suoritettavasta ohjelmasta
rekister|id{{n suoritettava k{sky.  Osoitteet kootaan
paketeiksi /iii<paketti>(/ii<bucket>), joiden koko on my|s
valittavissa.  Tulosteena saatavasta raportista n{hd{{n
montako k{sky{ kustakin paketista on suoritettu. 

Ohjelma </tt prof> tutkii ymp{rist|muuttujia, joista muuttujalla
</tt /ii<PROF/_WPB>> (words per bucket) asetetaan paketin koko ja
muuttujalla </tt /ii<PROF/_RATE>>
asetetaan aikav{li, jolla ohjelman suoritus keskeytet{{n.

Muuttujan </tt PROF/_WPB> oletusarvo on 100 (oktaali). Usein on
syyt{ pienent{{ muuttujan arvoa. Pienin mahdollinen arvo on 1.
Muuttujan </tt PROF/_RATE> oletus/-arvo on 512 mikrosekuntia.

K{ytett{ess{ </tt prof>:ia, </sc fortran>-ohjelma tulee
k{{nt{{ </tt D>-optiolla (debug), jolla saadaan aikaan
symbolitaulu.  Vaihtoehtoisesti voidaan linkitys suorittaa
k{ytt{en </tt segldr>:n optiota </tt -g>.  Samalla on syyt{
ottaa k{{nn|slista, koska </tt prof> raportoi konek{skyjen
osoitteita eik{ l{hdekielisen ohjelman k{skyj{. 

Linkitysvaiheessa otetaan mukaan </tt prof>-kirjasto.

Suorituksen aikana </tt prof> kirjoittaa raportin muodostamiseen
tarvittavat tiedot nykyhakemiston
tiedostoon </tt /ii<prof.data>>. Suorituksen j{lkeen saadaan raportti
komennolla </tt prof>. Optiolla </tt -s> saadaan raporttiin
aliohjelmakohtaiset summatiedot.

Esimerkki (Bourne shell):

</copymode
     PROF/_WPB=10
     export PROF/_WPB
     cft77 -esgD nb.f
     segldr -lprof nb.o
     .//a.out /gt nb.out
     prof -s /gt nb.prof
>

T{m{ tuottaa tiedostoon </tt nb.prof> seuraavanlaisen tilaston:

</font/tt = cmtt8 at 8truept/baselineskip=10truept/hsize=7.2truein
/catcode`/[=12
/catcode`/]=12
/beginverbatim

Profile of a.out from prof.data
Start address = 0a
End address   = 1241150a
Bucket size   = 012 words
Monitor rate  = 512 mics

   Label Address  Bucket   Secs [ Hits] (  ptime%) (  rtime%)

   INTEG   3044a
       +     22a   3066a   0.02 [   39] (  0.047%) (  0.049%)
       +     34a   3100a   0.88 [ 1725] (  2.094%) (  2.171%)
       +     46a   3112a   2.32 [ 4527] (  5.496%) (  5.696%) *
       +     60a   3124a   1.28 [ 2493] (  3.027%) (  3.137%)
       +     72a   3136a   5.31 [10368] ( 12.588%) ( 13.046%) ***
       +    104a   3150a   1.79 [ 3490] (  4.237%) (  4.391%) *
       +    116a   3162a   0.09 [  178] (  0.216%) (  0.224%)
       +    130a   3174a   0.34 [  669] (  0.812%) (  0.842%)
       +    142a   3206a   0.12 [  238] (  0.289%) (  0.299%)
       +    154a   3220a   0.02 [   36] (  0.044%) (  0.045%)
       +    166a   3232a   0.10 [  193] (  0.234%) (  0.243%)
       +    200a   3244a   0.35 [  689] (  0.837%) (  0.867%)
       +    212a   3256a   0.07 [  144] (  0.175%) (  0.181%)
       +    224a   3270a   0.04 [   77] (  0.093%) (  0.097%)
       +    236a   3302a   2.75 [ 5369] (  6.518%) (  6.756%) *
       +    250a   3314a   1.88 [ 3664] (  4.448%) (  4.610%) *
       +    262a   3326a   0.01 [   10] (  0.012%) (  0.013%)
       +    274a   3340a   0.01 [   15] (  0.018%) (  0.019%)
-------- ------- ------- ------  -----   --------   --------
Subtotal                  17.37 [33924] ( 41.187%) ( 42.687%) **********
-------- ------- ------- ------  -----   --------   --------
 P Total                  42.17 [82366] (100.000%) (103.641%) *************************
/endverbatim>

K{ytett{ess{ C-shelli{ esimerkin kaksi ensimm{ist{ rivi{ korvataan
rivill{:

</copymode
      setenv PROF/_WPB 10
>

Esimerkiss{ on tulostettu vain yhden aliohjelman (</tt
INTEG>) tiedot.  Kuten n{kyy, tuloste ei ole kovin
havainnollinen.  Jos haluaa saada selville, mill{ </sc fortran>in
k{skyrivill{ ohjelma k{ytt{{ eniten aikaa, on verrattava
t{m{n raportin antamia osoitteita k{{nn|slistassa oleviin
osoitteisiin. 

Ensin on etsitt{v{ /ii<assembler>kielisest{ k{{nn|slistasta
k{sky, jonka osoite on esimerkiksi </tt 72a>. 
Assemblerkielisess{ k{{nn|slistassa on aina rivin lopussa
numero, joka viittaa </sc fortran>-kielisen k{{nn|slistan
rivinumeroon.  N{in voi j{ljitt{{ sen ohjelman osan, yleens{
silmukan, jossa k{ytet{{n pajon aikaa.  Menetelm{ on
kuitenkin ty|l{s; pienenkin ohjelman assemblerkielinen
k{{nn|slista on useita sivuja pitk{. 

Sarakkeiden </tt ptime> ja </tt rtime> ero on siin{, ett{
</tt rtime>:n lukuihin on otettu mukaan kaikki mit{ </tt
prof> on mitannut, </tt ptime> on ehk{ kuvaavampi, koska
siit{ on karsittu pois kaikki mik{ ei kuulu suoritettavaan
ohjelmaan. 

Seuraavassa esimerkiss{ k{{nnet{{n C-kielinen ohjelma, siten ett{
saadaan </tt prof> mukaan:

</copymode
      cc -cS prog.c
      as -l prog.l -g prog.o prog.s
      segldr -g -l prof prog.o
>


/section<hpm>

Ohjelman suorituskyky{ voi mitata my|s k{ytt{en laitteistoon liitetty{
monitorointij{rjestelm{{ (</tt /ii<hpm>> eli hardware performance monitor).
Se antaa kuitenkin tiedot vain </bf koko> ohjelman tasolla.

Etuna on, ett{ ohjelmaa ei tarvitse erikseen k{{nt{{ mill{{n erityisill{
optioilla. Mit{ tahansa ja mill{ kielell{ tahansa kirjoitettua ohjelmaa
voi mitata k{ytt{en </tt hpm>-komentoa. Komennon optiolla </tt -g>
ilmoitetaan, mit{ nelj{st{ monitorista halutaan k{ytt{{; optio </tt -g>
voi saada arvon </tt 0>, </tt 1>, </tt 2> tai </tt 3>.

Esimerkkin{ suoritetaan </tt nb>-ohjelma, ja halutaan kaikki raportit.
Ohjelma on siis suoritettava nelj{ kertaa. Raportti menee
perusvirheilmoitustiedostoon (</tt stderr>).

</font/tt = cmtt8 %%at 8truept
/baselineskip=10truept/hsize=7.2truein
/beginverbatim

hpm -g0 ./nb >nb.out 2>nb.hpm
hpm -g1 ./nb >nb.out 2>>nb.hpm
hpm -g2 ./nb >nb.out 2>>nb.hpm
hpm -g2 ./nb >nb.out 2>>nb.hpm
cat nb.hpm
   STOP              in EPHEM
Group 0:  CP executing :      4041929588
Instructions           :      1739843823
CP holding issue       :      1821264779
Inst.buffer fetches    :         5430235
I/O memory references  :        23365604
CPU memory references  :       474473009
Floating-point adds    :       410173164
Floating-point mults   :       317814634
Floating-point recips  :         7850712
Floating ops/CPU second: 1.820513e+07
 hpmdump: cannot write hpm pipe
   STOP              in EPHEM
Group 1:  CP executing :      4041790919
Hold issue- semaphores :               2
Hold issue- shared reg :           14061
Hold issue- A reg/f.u. :       238789619
Hold issue- S reg/f.u. :       748243689
Hold issue- V regs     :       540495785
Hold issue- V func.unit:       385206002
Hold issue- scalar mem :           96133
Hold issue- block mem  :        37322125
 hpmdump: cannot write hpm pipe
   STOP              in EPHEM
Group 2:  CP executing :      4041878712
Inst. buffer fetches   :         5431472
Scalar memory refs     :        45364580
Scalar memory conflicts:           67996
I/O memory refs        :        24245336
I/O memory conflicts   :         4570809
Block memory refs      :       429082558
Block memory conflicts :        57878801
Vector memory refs     :       400517469
 hpmdump: cannot write hpm pipe
   STOP              in EPHEM
Group 3:  CP executing :      4039598365
000-017 instructions   :       123610765
020-137 instructions   :      1536242673
140-157, 175 instructs :        27861439
160-174 instructions   :        27144617
176, 177 instructions  :        24984891
Vector int./log. ops   :       426624328
Vector floating ops    :       531433790
Vector memory refs     :       400517469
Floating ops/CPU second: 1.315561e+07
    (vector only)
 hpmdump: cannot write hpm pipe
/endverbatim>


/section<perftrace>

Vastaava ty|kaluohjelma kuin </tt hpm> on </tt /ii<perftrace>>. Se on
vain tarkempi ja sill{ saa aliohjelmatasoisen raportin.
Sen k{ytt| vaatii ohjelman k{{nn|ksen </tt f>-optiolla vastaavasti kuin
</tt flowtrace>.

Linkityksess{ otetaan mukaan kirjasto </tt perf>. Lis{ksi linkitt{j{n
(</tt segldr>:n) optiolla </tt -D> annetaan direktiivi </tt set=group:n>.
Direktiivill{ kerrotaan mit{ </tt hpm>-monitoria k{ytet{{n; </tt n> voi
olla </tt 0, 1, 2 tai 3>.

Seuraavassa on esimerkki perftracen raportista.
Raportissa on ensin muutamien eniten k{ytettyjen aliohjelmien tiedot, sen
j{lkeen koko ohjelman tiedot ja lopuksi yhteenveto kaikista aliohjelmista.
(Listauksesta on tilanpuutteen vuoksi j{tetty pois pari saraketta.)

</font/tt = cmtt8 at 8truept
/baselineskip=10truept/hsize=7.2truein
/leftskip-5mm
/beginverbatim

cft77 -ef nb.f
segldr -lperf -Dset=group:0 nb.o
./a.out >nb.out
cat nb.out
P E R F T R A C E -- Performance Monitor tracing routine: Group= 0, Maxsub=  15, Percent= ***, Filter=  -7

 MOONEF     Rank =    1    Executing =  41.16%   Accounted CP =      1966356726  Times called =    48024
           Order =    5  Accumulated =  41.16%    CPU seconds =     19.66356726  Average time = 0.41E-03

Description                           Million per second           Number
-----------                           ------------------           ------
Instructions Issued                  MIPS =   51.27            1008155717   1.95 Average CP per instruction
Clock periods holding issue                                     637795594  32.44% of CP holding issue
Instruction Buffer Fetches                     0.22               4334223
I/O memory references                          1.07              21068718  20.43% of total references
CPU memory references                          4.17              82060088   0.19  Memory references per FLOP
Floating point add operations                  9.14             179649358  40.73% of total FLOPS
Floating point multiply operations            13.24             260313142  59.01% of total FLOPS
Floating point reciprocal operations           0.06               1152576   0.26% of total FLOPS
Total floating point operations    MFLOPS =   22.43             441115076  59.95% of program FLOPS
--------------------------------------------------------------------------------------------------------
P E R F T R A C E -- Performance Monitor tracing routine: Group= 0, Maxsub=  15, Percent= ***, Filter=  -7

Whole program (including all routines)   Accounted CP =      4777922166  CPU seconds =     47.77922166

Description                           Million per second           Number
-----------                           ------------------           ------
Instructions Issued                  MIPS =   40.27            1923832789   2.48 Average CP per instruction
Clock periods holding issue                                    2144631279  44.89% of CP holding issue
Instruction Buffer Fetches                     0.23              11208815
I/O memory references                          0.86              40987366   6.94% of total references
CPU memory references                         11.50             549558679   0.75  Memory references per FLOP
Floating point add operations                  8.58             410173155  55.74% of total FLOPS
Floating point multiply operations             6.65             317816667  43.19% of total FLOPS
Floating point reciprocal operations           0.16               7850710   1.07% of total FLOPS
Total floating point operations    MFLOPS =   15.40             735840532 100.00% of program FLOPS
----------------------------------------------------------------------------------------------------------
********* Group 0 - Condensed output for all routines *********

Rank Order  Name    Times   Time in  Average Execute Accum      Adds    Mults  Recip    FLOPS  
                    called  seconds  Time    Percent Percent                                   

   1    5 MOONEF      48024 1.97E+01 4.09E-04  41.16  41.16  1.80E+08 2.60E+08 1.15E+06 4.41E+08
   2   11 INTEG           1 1.77E+01 1.77E+01  37.09  78.25  2.14E+08 3.77E+07 5.36E+06 2.57E+08
   3   16 RADEC       54009 3.85E+00 7.13E-05   8.06  86.31  1.11E+07 1.37E+07 1.31E+06 2.62E+07
   4   13 PRECES      60010 2.25E+00 3.75E-05   4.71  91.02  4.98E+06 5.76E+06 0.00E+00 1.07E+07
   5   12 DOUT         6001 1.55E+00 2.58E-04   3.24  94.27  1.86E+05 0.00E+00 0.00E+00 1.86E+05
   6   14 EQC          6001 1.46E+00 2.43E-04   3.05  97.32  2.00E+00 0.00E+00 0.00E+00 2.00E+00
   7    4 MOON            1 1.09E+00 1.09E+00   2.28  99.59  1.44E+05 4.84E+04 5.00E+00 1.93E+05
   8   15 ANTIB        6001 1.67E-01 2.78E-05   0.35  99.94  1.71E+05 1.95E+05 6.00E+03 3.72E+05
   9   10 START           1 2.03E-02 2.03E-02   0.04  99.98  6.14E+04 1.01E+05 1.93E+04 1.82E+05
  10   17 TELL            1 6.80E-03 6.80E-03   0.01 100.00  1.71E+02 3.09E+03 0.00E+00 3.26E+03
  11    6 GREGOR         31 7.80E-04 2.52E-05   0.00 100.00  5.27E+02 1.86E+02 0.00E+00 7.13E+02
  12    8 AS7             1 3.41E-04 3.41E-04   0.00 100.00  0.00E+00 1.12E+02 0.00E+00 1.12E+02
  13    9 INTINI          1 2.61E-04 2.61E-04   0.00 100.00  1.73E+03 1.62E+03 4.36E+02 3.79E+03
  14    1 EPHEM           1 1.03E-04 1.03E-04   0.00 100.00  0.00E+00 0.00E+00 0.00E+00 0.00E+00
  15    7 PLANET          1 6.15E-05 6.15E-05   0.00 100.00  0.00E+00 0.00E+00 0.00E+00 0.00E+00
  16    3 INIT            1 3.37E-05 3.37E-05   0.00 100.00  0.00E+00 0.00E+00 0.00E+00 0.00E+00
  17    2 DAYNUM          1 2.43E-05 2.43E-05   0.00 100.00  1.20E+01 4.00E+00 0.00E+00 1.60E+01
------------------------------------------------------------------------------------------------
   0    0 PROGRAM         1 2.43E-05 2.43E-05 100.00 100.00  4.10E+08 3.18E+08 7.85E+06 7.36E+08

    Notes:
        Assumed trace overhead = 300-600 CP per call
        Clock period =   1.00E-08 seconds
        One user division = 3 multiplies and 1 reciprocal
/endverbatim>


/section</ii<second>>

Jos haluat j{ljitt{{ jotain aivan tietty{ ohjelman kohtaa,
voit sijoittaa ohjelmaasi funktion </tt second()>
kutsuja; se palauttaa arvonaan kuluneen CPU-ajan.
T{t{ voi k{ytt{{ my|s tuotantoajoissa, kunhan pit{{
huolen siit{, ett{ </tt second>ia ei kutsuta liian monta kertaa.


/section</ii<Vektoroituvuus>>

Seuraavaksi on tutkittava, onko k{{nt{j{ onnistunut vektoroimaan
kriittiset silmukat. Seuraavassa esimerkiss{ tiedostossa </tt esim.f>
oleva aliohjelma (N:n kappaleen ohjelman </tt nb.f>
integrointirutiini) on k{{nnetty komennolla

</copymode
         cft77 -em esim.f
>

jolloin syntyy tiedosto </tt esim.l>. T{st{ tiedostosta
n{kyy, mitk{ silmukat on vektoroitu (</tt V> tai </tt Vs>)
ja mitk{ ovat skalaarikoodia (</tt S>): Seuraavassa on
tiedoston listaus hieman lyhenneltyn{ (mm. muuttujien m{{rittelyt
on poistettu):

</font/tt = cmtt8 at 8truept/baselineskip=10truept/hsize=7.2truein
/leftskip-5mm
/hsize7.2in
/beginverbatim

INTEG     PAGE     1             Cray FORTRAN CFT77 3.0X265   04/18/89 13:40:59     06/06/89 09:46:57
(-C CRAY-XEA,noema,cigs,vpop -e  Bmpqrs -d ADISacfghjoxz -o full,nozeroinc -i 46 -a stack -t 00 )           

      1      1.                         subroutine  INTEG (d1,h,d2,outp, integs)
    ...     ...

     56     56.                         today=1
     57     57.                         p=mmm
     58     58.                         count=0
     59     59.                         etime=d2+h/4.0
     60     60.                         otime=d1
     61     61.                         clock=epoch+(mmm+1)*h
     62     62.                   c
     63     63.                   c  integration loop begins here
     64     64.                   c
     65     65.                    10   continue
     66     66. S---------------<          do 23 nu=0,order-1
     67     67. :   S-----------<             do 22 k=1,3
     68     68. :   :   S-------<                do 21 i=1,maxobj
     69     69. :   :   S                           sum=0.0
     70     70. :   :   :   V---<                   do 20 j=0,nu
     71     71. :   :   :   V                          if (p-j .ge. -mmm) then
     72     72. :   :   :   V                             indx= p-j
     73     73. :   :   :   V                          else
     74     74. :   :   :   V                             indx= p-j+order
     75     75. :   :   :   V                          endif
     76     76. :   :   :   V                          sum=sum+sbinc(nu,j)*accel(indx,k,i,swap)
     77     77. :   :   :   V--->  20               continue
     78     78. :   :   S                           adiff(nu,k,i)=sum
     79     79. :   :   S------->  21            continue
     80     80. :   S----------->  22         continue
     81     81. S--------------->  23      continue
     82     82.                   c
     83     83.                   c
     84     84.     S-----------<          do 32 k=1,3
     85     85.     :   S-------<             do 31 i=1,maxobj
     86     86.     :   S                        sum=0.0
     87     87.     :   :   Vs--<                do 30 j=0,order-1
     88     88.     :   :   Vs                      sum=sum+dd(j)*adiff(j,k,i)
     89     89.     :   :   Vs-->  30            continue
     90     90.     :   S                        xdiff(k,i)=xdiff(k,i)+h*h*sum
     91     91.     :   S                        coord(k,i)=coord(k,i)+xdiff(k,i)
     92     92.     :   S------->  31         continue
     93     93.     S----------->  32      continue
     94     94.                   c
     95     95.                   c  check if it is time to store results
     96     96.                   c
     97     97.                            if (clock .ge. otime) then
     98     98.                               call dout (clock)
     99     99.                               otime=otime+outp
    100    100.                            endif
    101    101.                   c
    102    102.         S-------<          do 41 i=1,maxobj
    103    103.         :   S---<             do 40 j=i+1,maxobj
    104    104.         :   S                    x0=coord(1,i)-coord(1,j)
    105    105.         :   S                    x1=coord(2,i)-coord(2,j)
    106    106.         :   S                    x2=coord(3,i)-coord(3,j)
    107    107.         :   S                    distnc(i,j)=sqrt(x0*x0+x1*x1+x2*x2)
    108    108.         :   S                    distnc(j,i)=distnc(i,j)
    109    109.         :   S--->  40         continue
    110    110.         S------->  41      continue
    111    111.                   c
    112    112.                   c
    113    113.                            if (p .eq. mmm) then
    114    114.                               p= -mmm
    115    115.                            else
    116    116.                               p= p+1
    117    117.                            endif
    118    118.                            count=count+1
    119    119.                   c
    120    120.                   c
    121    121.     S-----------<          do 52 k=1,3
    122    122.     :   S-------<             do 51 i=1,maxobj
    123    123.     :   S                        sum=0.0
    124    124.     :   :   S---<                do 50 j=1,maxobj
    125    125.     :   :   S                       if (j .ne. i .and. mass(j) .ne. 0.0) then
    126    126.     :   :   S                           sum=sum+(coord(k,j)-coord(k,i))/
    127    127.     :   :   S          .                        (distnc(i,j)**3)*mass(j)
    128    128.     :   :   S                       endif
    129    129.     :   :   S--->  50            continue
    130    130.     :   S                        accel(p,k,i,swap)=gravit*sum
    131    131.     :   S------->  51         continue
    132    132.     S----------->  52      continue
    133    133.                            clock=clock+h
    134    134.                         if (clock .le. etime) goto 10
    135    135.                   c
    136    136.                   c  ready
    137    137.                   c
    138    138.                         integs=count
    139    139.                         return
    140    140.                         end
    
                                        V E C T O R I Z A T I O N   I N F O R M A T I O N                  
                                        -------------------------------------------------                  

 *** *** Loop starting at line 70 was vectorized
 *** *** Loop starting at line 87 was a short vector loop
 *** *** Loop starting at line 103 was not vectorized because
         a recurrence was found on DISTNC at line 107
 *** *** Loop starting at line 124 was not vectorized because
         the loop used a subscript that is conditionally incremented - deferred implementation

/endverbatim>


Ellei jokin silmukka ole vektoroitunut, on mietitt{v{, voiko
vektorointia est{v{t rakenteet poistaa tai siirt{{ silmukan
ulkopuolelle kohtuullisella vaivalla.  Vektoroinnin est{v{t
mm.  I//O-lauseet, aliohjelma- ja funktiokutsut (ei koske
</sc fortran>in intrinsic-funktioita ja lausefunktioita), 
</tt return>, </tt stop>, aritmeettiset </tt if>-lauseet, 
</tt goto> -lauseet taaksep{in, </tt goto> -lauseet silmukan
ulkopuolelta silmukan p{{tt{v{{n osoitteeseen sek{
muuttujien v{liset riippuvuudet, jotka vaativat, ett{
silmukan kukin kierros on suoritettava valmiiksi ennen
seuraavan aloittamista. 


/section</ii<Optimointi>vihjeit{>

Seuraavassa on tiivistelm{ asioista, joilla voi olla
vaikutusta ohjelman tehokkuuteen.  P{{s{{nt|isesti hyv{n
ohjel/-mointi/-tavan mukainen siististi ja selke{sti
kirjoitettu ohjelma on my|s tehokkaampi kuin tyypillinen
rotanpes{/-ohjelma.  Tosin jotkut optimoinnin edellytt{m{t
rakenteet ovat kauniin ohjel/-mointi/-tyylin vastaisia;
n{iss{k{{n tapauksissa ohjelman luettavuudesta ja
yksin/-kertaisuudesta ei saisi liikaa tinki{.  Koko ajan on
syyt{ pit{{ mieless{, ett{ vain muutaman kerran
suoritettavien ohjelman osien optimointi ei korvaa
muutost|ihin k{ytetty{ aikaa.  T{rkeint{ on huolehtia
nimenomaan sisimpien silmukoiden ja niiss{ esiintyvien
muuttujien k{yt|n tehokkuudesta. 


</bf Vektoroinnin est{v{t /ii<riippuvuudet>>

Jos silmukassa esiintyy vektoroinnin est{vi{ riippuvuuksia,
on syyt{ tutkia, voiko riippuvuudet poistaa j{rjestelem{ll{
lauseita uudelleen tai jakamalla silmukka useampaan
pienemp{{n silmukkaan, joista vain joihinkin j{{
haitallisia riippuvuuksia:

</copymode
    do 1 i=2,n                      do 1 i=2,n
       a(i)=a(i-1)+c(i)                a(i)=a(i-1)+c(i)
       b(i)=a(i)*c(i-1)      =/gt  1  continue
 1  continue                        do 2 i=2,n
                                       b(i)=a(i)*c(i-1)
                                 2  continue
>

</bf /ii<Aliohjelmakutsut>>

Jos silmukassa esiintyy aliohjelmakutsuja, olettaa k{{nt{j{
aina, ett{ niill{ on sivuvaikutuksia. Vain /ii<assembler>illa
(</sc/ii<CAL>>) on mahdollista kirjoittaa aliohjelmia, joita voi
vektorointia est{m{tt{ kutsua silmukan sis{lt{.
Aliohjelmakutsun voi korvata kirjoittamalla sen tilalle
aliohjelman koodin (/ii<in-lining>):

</copymode
    do i=1,n                        do i=1,n
       a(i)=f(x(i))                    a(i)=sin(sqrt(x(i)))
 1  continue                 =/gt  1  continue
    ...
    real function f(x)
    f=sin(sqrt(x))
    end
>

Toinen mahdollisuus on siirt{{ koko silmukka aliohjelman sis{{n.
Jos kyseess{ on funktiokutsu, voi funktion my|s korvata
lausefunktiolla (ellei se ole kovin pitk{):

</copymode
    f(x)=sin(sqrt(x))
    ...
    do 1 i=1,n
       a(i)=f(x(i))
 1  continue
>

</bf Moninkertaiset silmukat>

Crayn k{{nt{j{ vektoroi vain sisimpi{ silmukoita.
Moninkertaisia silmukoita voi yritt{{ optimoida mm.
seuraavilla tavoilla:

1) Pyrit{{n sijoittamaan sisimm{ksi sellainen silmukka, jossa
ei ole vahingollisia riippuvuuksia:

/page
</copymode
    do 1 i=1,n                    do 1 j=1,n
    do 1 j=1,n               =/gt   do 1 i=1,n
       a(i,j)=a(i,j-1)+b(j)          a(i,j)=a(i,j-1)+b(j)
 1  continue                   1  continue
>

2) Jos sisin silmukka on hyvin lyhyt, se kannattaa kirjoittaa
auki (/ii<loop unrolling>):

</copymode
    do 1 i=1,n                    do 1 i=1,n
    do 1 j=1,3               =/gt      x(i,1)=x(i,1)+dx(i,1)
       x(i,j)=x(i,j)+dx(i,j)         x(i,2)=x(i,3)+dx(i,2)
 1  continue                         x(i,2)=x(i,3)+dx(i,3)
                               1  continue
>

3) Mik{li t{m{n j{lkeen on viel{ valinnan varaa, sijoitetaan
pisin silmukka sisimm{ksi, koska silmukan alustus vie aina
jonkin verran aikaa.

</bf Skalaarit>

Jos silmukassa p{ivitet{{n skalaarimuuttujaa, voi seurauksena
olla vektoroinnin est{v{ riippuvuus. Tilanteesta voi selvit{
korvaamalla skalaarin taulukolla:

</copymode
    do 1 j=1,m                    do 1 i=1,m
       s=1                           s(i)=1
       do 2 i=1,n              1  continue
          s=s*c              =/gt   do 2 j=1,m
          a(i)=a(i)+s             do 2 i=1,n
 2     continue                      s(j)=s(j)*c
 1  continue                         a(i)=a(i)+s(j)
                               2  continue
>


</bf Muistiviittaukset>

Virtuaalimuistikoneissa on eduksi, jos per{kk{iset /ii<muistiviittaukset>
kohdistuvat toisiaan mahdollisimman l{hell{ oleviin muistipaikkoihin,
jolloin sivutuskeskeytykset v{henev{t. Reaalimuistikoneessa
muistiviittausten et{isyyksill{ ei ole merkityst{. Crayn
muistin rakenteesta sen sijaan aiheutuu muunlaisia mieless{
pidett{vi{ asioita.

X-MP:n /ii<muisti> on jaettu siten, ett{ per{kk{iset osoitteet ovat
eri /ii<muistilohko>issa (/ii<memory bank>). Muistiviite varaa lohkon
aina 8 kellojakson ajaksi. Uusi muistihaku voidaan kuitenkin
aloittaa jo seuraavalla kellojaksolla, jos se kohdistuu eri
lohkoon. Mik{li viittaukset tapahtuvat muistipaikkoihin,
joiden et{isyys on lohkojen m{{r{n (32) monikerta, ne osuvat
aina samaan lohkoon, ja suoritusaika voi kasvaa jopa 8-kertaiseksi.
My|s 8:n ja 4:n mittaisia askeleita olisi syyt{ v{ltt{{.
Er{s keino selviyty{ tilanteesta on taulukoiden dimensioiden
muuttaminen niin, ettei niiss{ esiinny 32:n monikertoja:

</copymode
    real x(64,1000)               real x(65,1000)
    do 1 i=1,64                   do i=1,64
    do 1 j=1,1000            =/gt   do j=1,1000
       x(i,j)=...                    x(i,j)=...
 1  continue                   1  continue
>

Muita mahdollisuuksia ovat taulukon dimensioiden j{rjestyksen
muuttaminen tai sis{kk{isten silmukoiden j{rjestyksen vaihtaminen
(edellytt{en, ettei t{m{ aiheuta muita ongelmia).

</bf I//O>

Formatoitu /ii<I//O> on huomattavasti hitaampaa kuin formatoimaton.
Jos tiedosto on tarkoitettu vain ohjelman luettavaksi, {l{
turhaan tulosta sit{ formatoidussa muodossa.
I//O-lauseen muuttujaluettelossa oleva silmukka kyll{kin
vektoroituu, mutta aiheuttaa monta erillist{ I//O-pyynt|{.
Tehokkaampaa on kirjoittaa tilalle pelkk{ taulukon nimi
(mik{li mahdollista), jolloin selvit{{n yhdell{ pyynn|ll{.

</copymode
    real a(10)
    ...
    write(1,10)(a(i),i=1,10) =/gt  write(1) a
 10 format(10F9.5)
>

Mik{li ohjelma kuluttaa huomattavan osan ajastaan I//O:n
p{{ttymisen odottamiseen, kannattaa mietti{ asynkronisen
I//O:n mahdollisuutta.


</bf Sekalaista>/nl

/iii<kokonaislukujen laskutoimitukset>
[l{ k{yt{ 64 bitin kokonaislukuja, ellei se ole v{ltt{m{t|nt{.
Crayss{ kokonaislukujen kerto- ja jakolaskut hoidetaan
paloittelemalla luvut ensin useammaksi liukuluvuksi,
suorittamalla niille liukulukuoperaatioita ja palauttamalla
tulos taas kokonaisluvuksi. 64-bittisen kokonaisluvun
k{sittely on monimutkaisempaa ja siis hitaampaa kuin
46-bittisen.


