aboutsummaryrefslogtreecommitdiff
path: root/it_IT.ISO8859-15/articles/vm-design/article.sgml
blob: 55493ee1c27b51cf5988dbd6f9b063dcc3804f72 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
<!--
     The FreeBSD Italian Documentation Project

     $FreeBSD$
     Original revision: 1.14
-->

<!DOCTYPE article PUBLIC "-//FreeBSD//DTD DocBook V4.1-Based Extension//EN" [
<!ENTITY % articles.ent PUBLIC "-//FreeBSD//ENTITIES DocBook FreeBSD Articles Entity Set//EN">
%articles.ent;
]>

<article lang="it">
  <articleinfo>
    <title>Elementi di progettazione del sistema di VM di FreeBSD</title>

    <authorgroup>
      <author>
        <firstname>Matthew</firstname>

        <surname>Dillon</surname>

        <affiliation>
          <address>
            <email>dillon@apollo.backplane.com</email>
          </address>
        </affiliation>
      </author>
    </authorgroup>

    <legalnotice id="trademarks" role="trademarks">
      &tm-attrib.freebsd;
      &tm-attrib.linux;
      &tm-attrib.microsoft;
      &tm-attrib.opengroup;
      &tm-attrib.general;
    </legalnotice>

    <abstract>
      <para>Il titolo &egrave; in realt&agrave; solo un modo complicato per dire
        che cercher&ograve; di descrivere l'intera enchilada della memoria
        virtuale (VM), sperando di farlo in una maniera che chiunque possa
        seguire.
        Nell'ultimo anno mi sono concentrato su un certo numero di sottosistemi
        principali del kernel in FreeBSD, trovando quelli della VM (la memoria
        virtuale) e dello Swap i pi&ugrave; interessanti, e considerando quello
        di NFS <quote>un lavoretto necessario</quote>.
        Ho riscritto solo piccole porzioni di quel codice.  Nell'arena
        della VM la sola grossa riscrittura che ho affrontato &egrave; stata
        quella del sottosistema di swap.
        La maggior parte del mio lavoro &egrave; stato di pulizia e
        mantenimento, con solo alcune moderate riscritture di codice e
        nessuna correzione rilevante a livello algoritmico nel sottosistema
        della VM.  Il nocciolo della base teorica del sottosistema
        rimane immutato ed un bel po' del merito per gli sforzi di
        modernizzazione negli ultimi anni appartiene a John Dyson e David
        Greenman.  Poich&eacute; non sono uno storico come Kirk non
        tenter&ograve; di marcare tutte le varie caratteristiche con i nomi
        delle relative persone, perch&eacute; sbaglierei
        invariabilmente.</para>

      &trans.it.surrender;
    </abstract>

    <legalnotice>
      <para>Questo articolo &egrave; stato pubblicato in origine nel numero di
        gennaio 2000 di <ulink
          url="http://www.daemonnews.org/">DaemonNews</ulink>.
        Questa versione dell'articolo pu&ograve; includere aggiornamenti da
        parte di Matt e di altri autori per riflettere i cambiamenti
        nell'implementazione della VM di FreeBSD.</para>
    </legalnotice>
  </articleinfo>

  <sect1>
    <title>Introduzione</title>

    <para>Prima di andare avanti con la descrizione del progetto effettivo
      della VM spendiamo un po' di tempo sulla necessit&agrave; di mantenere
      e modernizzare una qualunque base di codice longeva.
      Nel mondo della programmazione, gli algoritmi tendono ad essere pi&ugrave;
      importanti del codice ed &egrave; dovuto alle radici accademiche
      di BSD che si &egrave; prestata grande attenzione alla progettazione
      algoritmica sin dal principio.
      Una maggiore attenzione al design in genere conduce ad una base di codice
      flessibile e pulita che pu&ograve; essere modificata abbastanza
      semplicemente, estesa, o rimpiazzata nel tempo.
      Mentre BSD viene considerato un sistema operativo <quote>vecchio</quote>
      da alcune persone, quelli di noi che lavorano su di esso tendono
      a considerarlo come una base di codice <quote>matura</quote>
      che ha vari componenti modificati, estesi, o rimpiazzati con codice
      moderno.  Questa si &egrave; evoluta, e FreeBSD &egrave; all'avanguardia,
      non importa quanto possa essere vecchio qualche pezzo di codice.
      Questa &egrave; una distinzione importante da fare ed una di quelle che
      sfortunatamente sfuggono alla maggior parte delle persone.  Il pi&ugrave;
      grande errore che un programmatore possa fare &egrave; non imparare
      dalla storia, e questo &egrave; precisamente l'errore che molti sistemi
      operativi moderni hanno commesso.  &windowsnt; &egrave; il miglior esempio
      di questo, e le conseguenze sono state disastrose.  Anche Linux commette
      questo errore a un certo livello&mdash;abbastanza perch&eacute; noi
      appassionati di BSD possiamo scherzarci su ogni tanto, comunque.
      Il problema di Linux &egrave; semplicemente la mancanza di esperienza e
      di una storia con la quale confrontare le idee, un problema che sta
      venendo affrontato rapidamente dalla comunit&agrave; Linux nello stesso
      modo in cui &egrave; stato affrontato da quella BSD&mdash;con il continuo
      sviluppo di codice.  La gente di &windowsnt;, d'altro canto, fa
      ripetutamente gli stessi errori risolti da &unix; decadi fa e poi impiega
      anni nel risolverli.  E poi li rifanno, ancora, e ancora.
      Soffrono di un preoccupante caso di <quote>non &egrave; stato progettato
        qui</quote> e di <quote>abbiamo sempre ragione perch&eacute; il nostro
        dipartimento marketing dice cos&igrave;</quote>.  Io ho pochissima
      tolleranza per chiunque non impari dalla storia.</para>

    <para>La maggior parte dell'apparente complessit&agrave; di progettazione di
      FreeBSD, specialmente nel sottosistema VM/Swap, &egrave; una conseguenza
      diretta dell'aver dovuto risolvere importanti problemi di prestazioni
      legati a varie condizioni.  Questi problemi non sono dovuti a cattivi
      progetti algoritmici ma sorgono invece da fattori ambientali.
      In ogni paragone diretto tra piattaforme, questi problemi
      diventano pi&ugrave; evidenti quando le risorse di sistema cominciano ad
      essere stressate.
      Mentre descrivo il sottosistema VM/Swap di FreeBSD il lettore
      dovrebbe sempre tenere a mente almeno due punti.  Primo, l'aspetto
      pi&ugrave; importante nel design prestazionale &egrave; ci&ograve; che
      &egrave; noto come <quote>Ottimizzazione del Percorso Critico</quote>.
      Accade spesso che le ottimizzazioni prestazionali aggiungano
      un po di impurit&agrave; al codice per far migliorare il percorso critico.
      Secondo, un progetto solido e generalizzato, funziona meglio di
      un progetto pesantemente ottimizzato, alla lunga.  Mentre un progetto
      generale pu&ograve; alla fin fine essere pi&ugrave; lento di un sistema
      pesantemente ottimizzato quando vengono implementati inizialmente, il
      progetto generalizzato tende ad essere pi&ugrave; semplice da adattare
      alle condizioni variabili mentre quello pesantemente ottimizzato finisce
      per dover essere gettato via.  Ogni base di codice che dovr&agrave;
      sopravvivere ed essere mantenibile per anni deve dunque essere progettata
      con attenzione fin dall'inizio anche se questo pu&ograve; portare a
      piccoli peggioramenti nelle prestazioni.
      Vent'anni fa c'era ancora gente che sosteneva che programmare in assembly
      era meglio che programmare in linguaggi di alto livello, perch&eacute;
      si poteva produrre codice che era dieci volte pi&ugrave; veloce.  Oggi,
      la fallacia di tale argomento &egrave; ovvia&mdash;cos&igrave; come i
      paralleli con il design algoritmico e la generalizzazione del
      codice.</para>
  </sect1>

  <sect1>
    <title>Oggetti VM</title>

    <para>Il modo migliore per iniziare a descrivere il sistema di VM di FreeBSD
      &egrave; guardandolo dalla prospettiva di un processo a livello
      utente.  Ogni processo utente vede uno spazio di indirizzamento della VM
      singolo, privato e contiguo, contenente molti tipi di oggetti di memoria.
      Questi oggetti hanno varie caratteristiche.
      Il codice del programma e i dati del programma sono effettivamente
      un singolo file mappato in memoria (il file binario che &egrave; stato
      eseguito), ma il codice di programma &egrave; di sola lettura mentre i
      dati del programma sono copy-on-write <footnote>
        <para>I dati copy on write sono dati che vengono copiati solo al momento
          della loro effettiva modifica</para>
      </footnote>.  Il BSS del programma &egrave; solamente una zona di memoria
      allocata e riempita con degli zero su richiesta, detta in inglese
      <quote>demand zero page fill</quote>.
      Nello spazio di indirizzamento possono essere mappati anche file
      arbitrari, che &egrave; in effetti il meccanismo con il quale funzionano
      le librerie condivise.  Tali mappature possono richiedere modifiche per
      rimanere private rispetto al processo che le ha effettuate.
      La chiamata di sistema fork aggiunge una dimensione completamente nuova
      al problema della gestione della VM in cima alla complessit&agrave;
      gi&agrave; data.</para>

    <para>Una pagina di dati di un programma (che &egrave; una basilare pagina
      copy-on-write) illustra questa complessit&agrave;.  Un programma binario
      contiene una sezione di dati preinizializzati che viene inizialmente
      mappata direttamente in memoria dal file del programma.
      Quando un programma viene caricato nello spazio di memoria virtuale di un
      processo, questa area viene inizialmente copiata e mappata in memoria dal
      binario del programma stesso, permettendo al sistema della VM di
      liberare/riusare la pagina in seguito e poi ricaricarla dal binario.
      Nel momento in cui un processo modifica questi dati, comunque, il
      sistema della VM deve mantenere una copia privata della pagina per quel
      processo.  Poich&eacute; la copia privata &egrave; stata modificata, il
      sistema della VM non pu&ograve; pi&ugrave; liberarlo, poich&eacute; non ci
      sarebbe pi&ugrave; nessuna possibilit&agrave; di recuperarlo in
      seguito.</para>

    <para>Noterai immediatamente che quella che in origine era soltanto
      una semplice mappatura di un file &egrave; diventata qualcosa di
      pi&ugrave; complesso.
      I dati possono essere modificati pagina per pagina
      mentre una mappatura di file coinvolge molte pagine alla volta.
      La complessit&agrave; aumenta ancora quando un processo esegue una fork.
      Quando un processo esegue una fork, il risultato sono due
      processi&mdash;ognuno con il proprio spazio di indirizzamento privato,
      inclusa ogni modifica fatta dal processo originale prima della chiamata a
      <function>fork()</function>.  Sarebbe stupido per un sistema di VM creare
      una copia completa dei dati al momento della <function>fork()</function>
      perch&eacute; &egrave; abbastanza probabile che almeno uno dei due
      processi avr&agrave; bisogno soltanto di leggere da una certa pagina da
      quel momento in poi, permettendo di continuare ad usare la
      pagina originale.  Quella che era una pagina privata viene di nuovo
      resa una copy-on-write, poich&eacute; ogni processo (padre e figlio) si
      aspetta che i propri cambiamenti rimangano privati per loro e non abbiano
      effetti sugli altri.</para>

    <para>FreeBSD gestisce tutto ci&ograve; con un modello a strati di oggetti
      VM.  Il file binario originale del programma risulta come lo strato di
      Oggetti VM pi&ugrave; basso.
      Un livello copy-on-write viene messo sopra questo per mantenere quelle
      pagine che sono state copiate dal file originale.
      Se il programma modifica una pagina di dati appartenente al file originale
      il sistema dell VM prende un page fault <footnote>
        <para>Un page fault, o <quote>mancanza di pagina</quote>,
          corrisponde ad una mancanza di una determinata pagina di memoria a un
          certo livello, ed alla necessit&agrave; di copiarla da un livello
          pi&ugrave; lento.  Ad esempio se una pagina di memoria &egrave; stata
          spostata dalla memoria fisica allo spazio di swap su disco, e viene
          richiamata, si genera un page fault e la pagina viene di nuovo copiata
          in ram.</para>
      </footnote> e fa una copia della pagina nel livello pi&ugrave; alto.
      Quando un processo effettua una fork, vengono aggiunti altri livelli di
      Oggetti VM.  Tutto questo potrebbe avere un po' pi&ugrave; senso con un
      semplice esempio.
      Una <function>fork()</function> &egrave; un'operazione comune per ogni
      sistema *BSD, dunque questo esempio prender&agrave; in considerazione un
      programma che viene avviato ed esegue una fork.  Quando il processo viene
      avviato, il sistema della VM crea uno starto di oggetti, chiamiamolo
      A:</para>

    <mediaobject>
      <imageobject>
        <imagedata fileref="fig1" format="EPS">
      </imageobject>

      <textobject>
        <literallayout class="monospaced">+---------------+
|       A       |
+---------------+</literallayout>
      </textobject>

      <textobject>
        <phrase>Un'immagine</phrase>
      </textobject>
    </mediaobject>

    <para>A rappresenta il file&mdash;le pagine possono essere
      spostate dentro e fuori dal mezzo fisico del file se necessario.
      Copiare il file dal disco &egrave; sensato per un programma,
      ma di certo non vogliamo effettuare il page out <footnote>
        <para>La copia dalla memoria al disco, l'opposto del page in, la
          mappatura in memoria.</para>
      </footnote> e sovrascrivere l'eseguibile.
      Il sistema della VM crea dunque un secondo livello, B, che verr&agrave;
      copiato fisicamente dallo spazio di swap:</para>

    <mediaobject>
      <imageobject>
        <imagedata fileref="fig2" format="EPS">
      </imageobject>

      <textobject>
        <literallayout class="monospaced">+---------------+
|       B       |
+---------------+
|       A       |
+---------------+</literallayout>
      </textobject>
    </mediaobject>

    <para>Dopo questo, nella prima scrittura verso una pagina, viene creata una
      nuova pagina in B, ed il suo contenuto viene inizializzato con i dati di
      A.  Tutte le pagine in B possono essere spostate da e verso un dispositivo
      di swap.  Quando il programma esegue la fork, il sistema della VM crea
      due nuovi livelli di oggetti&mdash;C1 per il padre e C2 per il
      figlio&mdash;che restano sopra a B:</para>

    <mediaobject>
      <imageobject>
        <imagedata fileref="fig3" format="EPS">
      </imageobject>

      <textobject>
        <literallayout class="monospaced">+-------+-------+
|   C1  |   C2  |
+-------+-------+
|       B       |
+---------------+
|       A       |
+---------------+</literallayout>
      </textobject>
    </mediaobject>

    <para>In questo caso, supponiamo che una pagina in B venga modificata dal
      processo genitore.  Il processo subir&agrave; un fault di copy-on-write e
      duplicher&agrave; la pagina in C1, lasciando la pagina originale in B
      intatta.
      Ora, supponiamo che la stessa pagina in B venga modificata dal processo
      figlio.  Il processo subir&agrave; un fault di copy-on-write e
      duplicher&agrave; la pagina in C2.
      La pagina originale in B &egrave; ora completamente nascosta poich&eacute;
      sia C1 che C2 hanno una copia e B potrebbe teoricamente essere distrutta
      (se non rappresenta un <quote>vero</quote> file).
      Comunque, questo tipo di ottimizzazione non &egrave; triviale da
      realizzare perch&eacute; &egrave; di grana molto fine.
      FreeBSD non effettua questa ottimizzazione.
      Ora, supponiamo (come &egrave; spesso il caso) che
      il processo figlio effettui una <function>exec()</function>.  Il suo
      attuale spazio di indirizzamento &egrave; in genere rimpiazzato da un
      nuovo spazio di indirizzamento rappresentante il nuovo file.
      In questo caso il livello C2 viene distrutto:</para>

    <mediaobject>
      <imageobject>
        <imagedata fileref="fig4" format="EPS">
      </imageobject>

      <textobject>
        <literallayout class="monospaced">+-------+
|   C1  |
+-------+-------+
|       B       |
+---------------+
|       A       |
+---------------+</literallayout>
      </textobject>
    </mediaobject>

    <para>In questo caso, il numero di figli di B scende a uno, e tutti gli
      accessi a B avvengono attraverso C1.  Ci&ograve; significa che B e C1
      possono collassare insieme in un singolo strato.
      Ogni pagina in B che esista anche in C1 viene cancellata da
      B durante il crollo.  Dunque, anche se l'ottimizzazione nel passo
      precedente non era stata effettuata, possiamo recuperare le pagine morte
      quando il processo esce o esegue una <function>exec()</function>.</para>

    <para>Questo modello crea un bel po' di problemi potenziali.  Il primo
      &egrave; che ci si potrebbe ritrovare con una pila abbastanza profonda di
      Oggetti VM incolonnati che costerebbe memoria e tempo per la ricerca
      quando accadesse un fault.  Pu&ograve; verificarsi un ingrandimento della
      pila quando un processo esegue una fork dopo l'altra (che sia il padre o
      il figlio).  Il secondo problema &egrave; che potremmo ritrovarci con
      pagine morte, inaccessibili nella profondit&agrave; della pila degli
      Oggetti VM.  Nel nostro ultimo esempio se sia il padre che il figlio
      modificano la stessa pagina, entrambi hanno una loro copia della pagina e
      la pagina originale in B non &egrave; pi&ugrave; accessibile
      da nessuno.  Quella pagina in B pu&ograve; essere liberata.</para>

    <para>FreeBSD risolve il problema della profondit&agrave; dei livelli con
      un'ottimizzazione speciale detta <quote>All Shadowed Case</quote> (caso
      dell'oscuramento totale).
      Questo caso accade se C1 o C2 subiscono sufficienti COW fault (COW
      &egrave; l'acronimo che sta per copy on write) da oscurare completamente
      tutte le pagine in B.
      Ponimo che C1 abbia raggiunto questo livello.  C1 pu&ograve; ora
      scavalcare B del tutto, dunque invece di avere C1->B->A e C2->B->A adesso
      abbiamo C1->A e C2->B->A.
      ma si noti cos'altro &egrave; accaduto&mdash;ora B ha solo un riferimento
      (C2), dunque possiamo far collassare B e C2 insieme.
      Il risultato finale &egrave; che B viene cancellato
      interamente e abbiamo C1->A e C2->A.  Spesso accade che B contenga un
      grosso numero di pagine e ne' C1 ne' C2 riescano a oscurarlo
      completamente.  Se eseguiamo una nuova fork e creiamo un insieme di
      livelli D, comunque, &egrave; molto pi&ugrave; probabile che uno dei
      livelli D sia eventualmente in grado di oscurare completamente l'insieme
      di dati pi&ugrave; piccolo rappresentato da C1 o C2.  La stessa
      ottimizzazione funzioner&agrave; in ogni punto nel grafico ed il
      risultato di ci&ograve; &egrave; che anche su una macchina con
      moltissime fork le pile degli Oggetti VM tendono a non superare una
      profondit&agrave; di 4.  Ci&ograve; &egrave; vero sia per il padre che per
      il figlio ed &egrave; vero nel caso sia il padre a eseguire la fork ma
      anche se &egrave; il figlio a eseguire fork in cascata.</para>

    <para>Il problema della pagina morta esiste ancora nel caso C1 o C2 non
      oscurino completamente B.  A causa delle altre ottimizzazioni questa
      eventualit&agrave;
      non rappresenta un grosso problema e quindi permettiamo semplicemente
      alle pagine di essere morte.  Se il sistema si trovasse con poca memoria
      le manderebbe in swap, consumando un po' di swap, ma cos&igrave;
      &egrave;.</para>

    <para>Il vantaggio del modello ad Oggetti VM &egrave; che
      <function>fork()</function> &egrave; estremamente veloce, poich&eacute;
      non deve aver luogo nessuna copia di dati effettiva.  Lo svantaggio
      &egrave; che &egrave; possibile costruire un meccanismo a livelli di
      Oggetti VM relativamente complesso che rallenterebbe la gestione dei page
      fault, e consumerebbe memoria gestendo le strutture degli Oggetti VM.
      Le ottimizazioni realizzate da FreeBSD danno prova di ridurre
      i problemi abbastanza da poter essere ignorati, non lasciando
      nessuno svantaggio reale.</para>
  </sect1>

  <sect1>
    <title>Livelli di SWAP</title>

    <para>Le pagine di dati private sono inizialmente o pagine
      copy-on-write o pagine zero-fill.
      Quando avviene un cambiamento, e dunque una copia, l'oggetto di copia
      originale (in genere un file) non pu&ograve; pi&ugrave; essere utilizzato
      per salvare la copia quando il sistema della VM ha bisogno di
      riutilizzarla per altri scopi.  A questo punto entra in gioco lo SWAP.  Lo
      SWAP viene allocato per creare spazio dove salvare memoria che altrimenti
      non sarebbe disponibile.  FreeBSD alloca la struttura di gestione di
      un Oggetto VM solo quando &egrave; veramente necessario.
      Ad ogni modo, la struttura di gestione dello swap ha avuto storicamente
      dei problemi.</para>

    <para>Su FreeBSD 3.X la gestione della struttura di swap prealloca un
      array che contiene l'intero oggetto che necessita di subire
      swap&mdash;anche se solo poche pagine di quell'oggetto sono effettivamente
      swappate questo crea una frammentazione della memoria del kernel quando
      vengono mappati oggetti grandi, o processi con grandi dimensioni
      all'esecuzione (large runsizes, RSS).  Inoltre, per poter tenere traccia
      dello spazio di swap, viene mantenuta una <quote>lista dei buchi</quote>
      nella memoria del kernel, ed anche questa tende ad essere pesantemente
      frammentata.  Poich&eacute; la <quote>lista dei buchi</quote> &egrave; una
      lista lineare, l'allocazione di swap e la liberazione hanno prestazioni
      non ottimali O(n) per ogni pagina.
      Questo richiede anche che avvengano allocazioni di memoria
      durante il processo di liberazione dello swap, e questo crea
      problemi di deadlock, blocchi senza uscita, dovuti a scarsa memoria.
      Il problema &egrave; ancor pi&ugrave; esacerbato dai buchi creati a causa
      dell'algoritmo di interleaving.
      Inoltre il blocco di swap pu&ograve; divenire frammentato molto facilmente
      causando un'allocazione non contigua.  Anche la memoria del Kernel deve
      essere allocata al volo per le strutture aggiuntive di gestione dello
      swap quando avviene uno swapout.  &Egrave; evidente che c'era molto spazio
      per dei miglioramenti.</para>

    <para>Per FreeBSD 4.X, ho completamente riscritto il sottosistema di swap.
      Con questa riscrittura, le strutture di gestione dello swap vengono
      allocate attraverso una tabella di hash invece che con un array lineare
      fornendo una dimensione di allocazione fissata e una granularit&agrave;
      molto maggiore.
      Invece di usare una lista lineare collegata per tenere traccia delle
      riserve di spazio di swap, essa usa una mappa di bit di blocchi di swap
      organizzata in una struttura ad albero radicato con riferimenti allo
      spazio libero nelle strutture nei nodi dell'albero.  Ci&ograve; rende in
      effetti l'operazione di allocazione e liberazione delle risorse
      un'operazione O(1).
      L'intera mappa di bit dell'albero radicato viene anche preallocata in modo
      da evitare l'allocazione di memoria kernel durante le operazioni di swap
      critiche nei momenti in cui la memoria disponibile &egrave; ridotta.
      Dopo tutto, il sistema tende a fare uso dello swap quando ha poca memoria
      quindi dovremmo evitare di allocare memoria per il kernel in quei momenti
      per poter evitare potenziali deadlock.  Infine, per ridurre la
      frammentazione l'albero radicato &egrave; in grado di allocare grandi
      spezzoni contigui in una volta, saltando i pezzetti frammentati.
      Non ho ancora compiuto il passo finale di avere un <quote>puntatore di
        supportoall'allocazione</quote> che scorra su una porzione di swap nel
      momento in cui vengano effettuate delle allocazioni, in modo da garantire
      ancor di pi&ugrave; le allocazioni contigue o almeno una localit&agrave;
      nel riferimento, ma ho assicurato che un'aggiunta simile possa essere
      effettuata.</para>
  </sect1>

  <sect1>
    <title>Quando liberare una pagina</title>

    <para>Poich&eacute; il sistema della VM usa tutta la memoria disponibile
      per il caching del disco, in genere ci sono pochissime pagine veramente
      libere.  Il sistema della VM dipende dalla possibilit&agrave; di
      scegliere in maniera appropriata le pagine che non sono in uso per
      riusarle in nuove allocazioni.  Selezionare le pagine ottimali da liberare
      &egrave; forse la funzione singola pi&ugrave; importante che possa essere
      eseguita da una VM perch&eacute; se si effettua una selezione non
      accurata, il sistema della VM pu&ograve; essere forzato a recuperare
      pagine dal disco in modo non necessari, degradando seriamente le
      prestazioni del sistema.</para>

    <para>Quanto sovraccarico siamo disposti a sopportare nel percorso critico
      per evitare di liberare la pagina sbagliata?  Ogni scelta sbagliata che
      facciamo ci coster&agrave; centinaia di migliaia di cicli di CPU ed uno
      stallo percettibile nei processi coinvolti, dunque permettiamo un
      sovraccarico significativo in modo da poter avere la certezza che la
      pagina scelta sia quella giusta.
      Questo &egrave; il motivo per cui FreeBSD tende ad avere prestazioni
      migliori di altri sistemi quando le risorse di memoria vengono
      stressate.</para>

    <para>L'algoritmo di determinazione della pagina da liberare
      &egrave; costruito su una storia di uso delle pagine di memoria.
      Per acquisire tale storia, il sistema si avvantaggia di una
      caratteristica della maggior parte dell'hardware moderno, il bit che
      indica l'attivit&agrave; di una pagina (page-used bit).</para>

    <para>In qualsiasi caso, il page-used bit viene azzerato e in un momento
      seguente il sistema della VM passa di nuovo sulla pagina e vede che il
      page-used bit &egrave; stato di nuovo attivato.  Questo indica che la
      pagina viene ancora usata attivamente.
      Il bit ancora disattivato &egrave; un indice che quella pagina non viene
      usata attivamente.
      Controllando questo bit periodicamente, viene sviluppata una storia
      d'uso (in forma di contatore) per la pagina fisica.  Quando il sistema
      della VM avr&agrave; bisogno di liberare delle pagine, controllare questa
      storia diventa la pietra angolare nella determinazione del candidato
      migliore come pagina da riutilizzare.</para>

    <sidebar>
      <title>E se l'hardware non ha un page-used bit?</title>

      <para>Per quelle piattaforme che non hanno questa caratteristica, il
        sistema in effetti emula un page-used bit.  Esso elimina la mappatura di
        una pagina, o la protegge, forzando un page fault se c'&egrave; un
        accesso successivo alla pagina.
        Quando avviene il page fault, il sistema segnala semplicemente
        la pagina come usata e la sprotegge in maniera che possa essere usata.
        Mentre prendere tale page fault solo per determinare se una pagina
        &egrave; in uso pu&ograve; apparire una scelta costosa, in realt&agrave;
        essa lo &egrave; molto meno che riusare la pagina per altri scopi, per
        dover poi scoprire che un processo ne aveva ancora bisogno e dovere
        andare a cercarla di nuovo su disco.</para>
    </sidebar>

    <para>FreeBSD fa uso di parecchie code per le pagine per raffinare
      ulteriormente la selezione delle pagine da riutilizzare, come anche per
      determinare quando le pagine sporche devono essere spostate dalla memoria
      e immagazzinate da qualche parte.  Poich&eacute; le tabelle delle pagine
      sono entit&agrave; dinamiche in FreeBSD, non costa praticamente nulla
      eliminare la mappatura di una pagina dallo spazio di indirizzamento di un
      qualsiasi processo che la stia usando.  Quando una pagina candidata
      &egrave; stata scelta sulla base del contatore d'uso, questo &egrave;
      esattamente quello che viene fatto.
      Il sistema deve effettuare una distinzione tra pagine pulite che
      possono essere teoricamente liberate in qualsiasi momento, e pagine
      sporche che devono prima essere scritte (salvate) per poter essere
      riutilizzabili.
      Quando una pagina candidata viene trovata viene spostata nella coda
      delle pagine inattive, se &egrave; una pagina sporca, o nella coda di
      cache se &egrave; pulita.
      Un algoritmo separato basato su un rapporto sporche/pulite
      determina quando le pagine sporche nella coda inattiva devono essere
      scritte su disco.  Una volta che &egrave; stato fatto questo, le pagine
      ormai salvate vengono spostate dalla coda delle inattive alla coda di
      cache.  A questo punto, le pagine nella coda di cache possono ancora
      essere riattivate da un VM fault ad un costo relativamente basso.
      Ad ogni modo, le pagine nella coda di cache vengono considerate
      <quote>immediatamente liberabili</quote> e verranno riutilizzate con un
      metodo LRU (least-recently used <footnote>
        <para>Usate meno recentemente.  Le pagine che non vengono usate da molto
          tempo probabilmente non saranno necessarie a breve, e possono essere
          liberate.</para>
      </footnote>) quando il sistema avr&agrave; bisogno di allocare nuova
      memoria.</para>

    <para>&Egrave; importante notare che il sistema della VM di FreeBSD tenta
      di separare pagine pulite e sporche per l'espressa ragione di evitare
      scritture non necessarie di pagine sporche (che divorano banda di I/O), e
      non sposta le pagine tra le varie code gratuitamente quando il
      sottosistema non viene stressato.  Questo &egrave; il motivo per cui
      dando un <command>systat -vm</command> vedrai sistemi con contatori della
      coda di cache bassi e contatori della coda delle pagine attive molto alti.
      Quando il sistema della VM diviene maggiormente stressato, esso fa un
      grande sforzo per mantenere le varie code delle pagine ai livelli
      determinati come pi&ugrave; efficenti.
      Per anni &egrave; circolata la leggenda urbana che Linux facesse un lavoro
      migliore di FreeBSD nell'evitare gli swapout, ma in pratica questo non
      &egrave; vero.  Quello che stava effettivamente accadendo era che FreeBSD
      stava salvando le pagine inutilizzate proattivamente per fare spazio
      mentre Linux stava mantendendo le pagine inutilizzate lasciando meno
      memoria disponibile per la cache e le pagine dei processi.
      Non so se questo sia vero ancora oggi.</para>
  </sect1>

  <sect1>
    <title>Pre-Faulting e Ottimizzazioni di Azzeramento</title>

    <para>Subire un VM fault non &egrave; costoso se la pagina sottostante
      &egrave; gi&agrave; nella memoria fisica e deve solo essere mappata di
      nuovo nel processo, ma pu&ograve; divenire costoso nel caso se ne
      subiscano un bel po' su base regolare.  Un buon esempio di ci&ograve; si
      ha eseguendo un programma come &man.ls.1; o &man.ps.1; ripetutamente.
      Se il binario del programma &egrave; mappato in memoria ma non nella
      tabella delle pagine, allora tutte le pagine che verranno accedute dal
      programmma dovranno generare un page fault ogni volta che il programma
      viene eseguito.
      Ci&ograve; non &egrave; necessario quando le pagine in questione sono
      gi&agrave; nella cache della VM, quindi FreeBSD tenter&agrave; di
      pre-popolare le tabelle delle pagine di un processo con quelle pagine che
      sono gi&agrave; nella VM Cache.  Una cosa che FreeBSD non fa ancora
      &egrave; effettuare il pre-copy-on-write di alcune pagine nel caso di una
      chiamata a exec.
      Ad esempio, se esegui il programma &man.ls.1; mentre stai eseguendo
      <command>vmstat 1</command> noterai che subisce sempre un certo numero
      di page fault, anche eseguendolo ancora e ancora.  Questi sono
      zero-fill fault, legati alla necessit&agrave; di azzerare memoria,
      non program code fault, legati alla copia dell'eseguibile in memoria
      (che erano gi&agrave; stati gestiti come pre-fault).
      Pre-copiare le pagine all'exec o alla fork &egrave; un'area che potrebbe
      essere soggetta a maggior studio.</para>

    <para>Una larga percentuale dei page fault che accadono &egrave; composta di
      zero-fill fault.  In genere &egrave; possibile notare questo fatto
      osservando l'output di <command>vmstat -s</command>.
      Questi accadono quando un processo accede a pagine nell'area del BSS.
      Ci si aspetta che l'area del BSS sia composta inizialmente da zeri
      ma il sistema della VM non si preoccupa di allocare nessuna memoria
      finch&eacute; il processo non ne ha effettivamente bisogno.
      Quindi nel momento in cui accade un fault il sistema della VM non
      deve solo allocare una nuova pagina, ma deve anche azzerarla.
      Per ottimizzare l'operazione di azzeramento, il sistema della VM
      ha la capacit&agrave; di pre-azzerare le pagine e segnalarle come tali,
      e di richiedere pagine pre-azzerate quando avvengono zero-fill fault.
      Il pre-azzeramento avviene quando la CPU &egrave; inutilizzata ma il
      numero di pagine che vengono pre-azzerate dal sistema &egrave; limitato
      per evitare di spazzare via la cache della memoria.  Questo &egrave; un
      eccellente esempio di complessit&agrave; aggiunta al sistema della VM per
      ottimizare il percorso critico.</para>
  </sect1>

  <sect1>
    <title>Ottimizzazioni della Tabella delle Pagine </title>

    <para>Le ottimizzazioni alla tabella delle pagine costituiscono
      La parte pi&ugrave; controversa nel design della VM di FreeBSD ed ha
      mostrato un po' di affanno con l'avvento di un uso pesante di
      <function>mmap()</function>.
      Penso che questa sia una caratteristiche della maggior parte dei
      BSD anche se non sono sicuro di quando &egrave; stata introdotta
      la prima volta.  Ci sono due ottimizzazioni maggiori.  La prima &egrave;
      che le tabelle della pagine hardware non contengono uno stato persistente
      ma possono essere gettate via in qualsiasi momento con un sovraccarico di
      gestione minimo.
      La seconda &egrave; che ogni pagina attiva nel sistema ha una struttura di
      controllo <literal>pv_entry</literal> che &egrave; integrata con la
      struttura <literal>vm_page</literal>.  FreeBSD pu&ograve; semplicemente
      operare attraverso quelle mappature di cui &egrave; certa l'esistenza,
      mentre Linux deve controllare tutte le tabelle delle pagine che
      <emphasis>potrebbero</emphasis> contenere una mappatura specifica per
      vedere se lo stanno effettivamente facendo, il che pu&ograve; portare ad
      un sovraccarico computazionale O(n^2) in alcune situazioni.
      &Egrave; per questo che FreeBSD tende a fare scelte migliori su quale
      pagina riutilizzare o mandare in swap quando la memoria &egrave; messa
      sotto sforzo, fornendo una miglior performance sotto carico.  Comunque,
      FreeBSD richiede una messa a punto del kernel per accomodare situazioni
      che richiedano grandi spazi di indirizzamento condivisi, come quelli che
      possono essere necessari in un sistema di news perch&eacute; potrebbe
      esaurire il numero di struct <literal>pv_entry</literal>.</para>

    <para>Sia Linux che FreeBSD necessitano di lavoro in quest'area.
      FreeBSD sta cercando di massimizzare il vantaggio di avere un modello di
      mappatura attiva potenzialmente poco denso (non tutti i processi hanno
      bisogno di mappare tutte le pagine di una libreria condivisa, ad esempio),
      mentre linux sta cercando di semplificare i suoi algoritmi.  FreeBSD
      generalmente ha dei vantaggi prestazionali al costo di un piccolo spreco
      di memoria in pi&ugrave;, ma FreeBSD crolla nel caso in cui un grosso file
      sia condiviso massivamente da centinaia di processi.
      Linux, d'altro canto, crolla nel caso in cui molti processi mappino a
      macchia di leopardo la stessa libreria condivisa e gira in maniera non
      ottimale anche quando cerca di determinare se una pagina deve essere
      riutilizzata o no.</para>
  </sect1>

  <sect1>
    <title>Colorazione delle Pagine</title>

    <para>Concluderemo con le ottimizzazioni di colorazione delle pagine.
      La colorazione delle pagine &egrave; un'ottimizzazione prestazionale
      progettata per assicurare che gli accessi a pagine contigue nella memoria
      virtuale facciano il miglior uso della cache del processore.  Nei
      tempi antichi (cio&egrave; pi&ugrave; di 10 anni fa) le cache dei
      processori tendevano a mapparela memoria virtuale invece della memoria
      fisica.  Questo conduceva ad un numero enorme di problemi inclusa la
      necessit&agrave; di ripulire la cache ad ogni cambio di contesto, in
      alcuni casi, e problemi con l'aliasing dei dati nella cache.
      Le cache dei processori moderni mappano la memoria fisica proprio per
      risolvere questi problemi.
      Questo significa che due pagine vicine nello spazio di indirizzamento
      dei processi possono non corrispondere a due pagine vicine nella cache.
      In effetti, se non si &egrave; attenti pagine affiancate nella memoria
      virtuale possono finire con l'occupare la stessa pagina nella cache del
      processore&mdash;portando all'eliminazione prematura di dati
      immagazzinabili in cache e riducendo le prestazioni della cache.
      Ci&ograve; &egrave; vero anche con cache set-associative <footnote>
        <para>set-associative sta per associative all'interno di un insieme, in
          quanto c'&egrave; un insieme di blocchi della cache nei quale puo
          essere mappato un elemento della memoria fisica.</para>
      </footnote> a molte vie (anche se l'effetto viene in qualche maniera
      mitigato).</para>

    <para>Il codice di allocazione della memoria di FreeBSD implementa
      le ottimizizzazioni di colorazione delle pagine, ci&ograve; significa che
      il codice di allocazione della memoria cercher&agrave; di trovare delle
      pagine libere che siano vicine dal punto di vista della cache.
      Ad esempio, se la pagina 16 della memoria fisica &egrave; assegnata
      alla pagina 0 della memoria virtuale di un processo e la cache pu&ograve;
      contenere 4 pagine, il codice di colorazione delle pagine non
      assegner&agrave; la pagina 20 di memoria fisica alla pagina 1 di
      quella virtuale.
      Invece, gli assegner&agrave; la pagina 21 della memoria fisica.
      Il codice di colorazione delle pagine cerca di evitare l'assegnazione
      della pagina 20 perch&eacute; questa verrebbe mappata sopra lo stesso
      blocco di memoria cache della pagina 16 e ci&ograve; causerrebbe un uso
      non ottimale della cache.
      Questo codice aggiunge una complessit&agrave; significativa
      al sottosistema di allocazione memoria della VM, come si pu&ograve; ben
      immaginare, ma il gioco vale ben pi&ugrave; della candela.  La colorazione
      delle pagine rende la memoria virtuale deterministica quanto la memoria
      fisica per quel che riguarda le prestazioni della cache.</para>
  </sect1>

  <sect1>
    <title>Conclusione</title>

    <para>La memoria virtuale nei sistemi operativi moderni deve affrontare
      molti problemi differenti efficientemente e per molti diversi tipi di uso.
      L'approccio modulare ed algoritmico che BSD ha storicamente seguito ci
      permette di studiare e comprendere l'implementazione attuale cosi come di
      poter rimpiazzare in maniera relativamente pulita grosse sezioni di
      codice.  Ci sono stati un gran numero di miglioramenti al sistema della
      VM di FreeBSD negli ultimi anni, ed il lavoro prosegue.</para>
  </sect1>

  <sect1>
    <title>Sessione Bonus di Domande e Risposte di Allen Briggs
      <email>briggs@ninthwonder.com</email></title>

    <qandaset>
      <qandaentry>
        <question>
          <para>Cos'&egrave; <quote>l'algoritmo di interleaving</quote> a cui
            fai riferimento nell'elenco delle debolezze della gestione dello
            swap in FreeBSD 3.X ?</para>
        </question>

        <answer>
          <para>FreeBSD usa un intervallo tra zone di swap fissato, con un
            valore predefinito di 4.  Questo significa che FreeBSD riserva
            spazio per quattro aree di swap anche se ne hai una sola o due o
            tre.  Poich&eacute; lo swap &egrave; intervallato lo spazio di
            indirizzamento lineare che rappresenta le <quote>quattro aree di
              swap</quote> verr&agrave; frammentato se non si possiedono
            veramente quattro aree di swap.  Ad esempio, se hai due aree di
            swap A e B la rappresentazione dello spazio di FreeBSD per
            quell'area di swap verr&agrave; interrotta in blocchi di 16
            pagine:</para>

          <literallayout>A B C D A B C D A B C D A B C D</literallayout>

          <para>FreeBSD 3.X usa una <quote>lista sequenziale delle
            regioni libere </quote> per registrare le aree di swap libere.
            L'idea &egrave; che grandi blocchi di spazio libero e lineare
            possano essere rappresentati con un nodo singolo
            (<filename>kern/subr_rlist.c</filename>).
            Ma a causa della frammentazione la lista sequenziale risulta
            assurdamente frammentata.
            Nell'esempio precedente, uno spazio di swap completamente non
            allocato far&agrave; si che A e B siano mostrati come
            <quote>liberi</quote> e C e D come <quote>totalmente
              allocati</quote>.  Ogni sequenza A-B richiede un nodo per essere
            registrato perch&eacute; C e D sono buchi, dunquei nodi di lista non
            possono essere combinati con la sequenza A-B seguente.</para>

          <para>Perch&eacute; organizziamo lo spazio in intervalli invece di
            appiccicare semplicemente le area di swap e facciamo qualcosa di
            pi&ugrave; carino?  Perch&eacute; &egrave; molto pi&ugrave; semplice
            allocare strisce lineari di uno spazio di indirizzamento ed ottenere
            il risultato gi&agrave; ripartito tra dischi multipli piuttosto che
            cercare di spostare questa complicazione altrove.</para>

          <para>La frammentazione causa altri problemi.  Essendoci una lista
            lineare nella serie 3.X, ed avendo una tale quantit&agrave; di
            frammentazione implicita, l'allocazione e la liberazione dello swap
            finisce per essere un algoritmo O(N) invece di uno O(1).
            Combinalo con altri fattori (attivit&agrave; di swap pesante)
            e comincerai a trovarti con livelli di overhead come O(N^2) e
            O(N^3), e ci&ograve; &egrave; male.  Il sistema dela serie 3.X
            pu&ograve; anche avere necessit&agrave; di allocare KVM durante
            un'operazione di swap per creare un nuovo nodo lista, il che
            pu&ograve; portare ad un deadlock se il sistema sta cercando di
            liberare pagine nella memoria fisica in un momento di
            scarsit&agrave; di memoria.</para>

          <para>Nella serie 4.X non usiamo una lista sequenziale.  Invece usiamo
            un albero radicato e mappe di bit di blocchi di swap piuttosto che
            nodi lista.
            Ci prendiamo il peso di preallocare tutte le mappe di bit richieste
            per l'intera area di swap ma ci&ograve; finisce per consumare meno
            memoria grazie all'uso di una mappa di bit (un bit per blocco)
            invece di una lista collegata di nodi.  L'uso di un albero radicato
            invece di una lista sequenziale ci fornisce una performance quasi
            O(1) qualunque sia il livello di frammentazione dell'albero.</para>
        </answer>
      </qandaentry>

      <qandaentry>
        <question>
          <para>Non ho capito questo:</para>

          <blockquote>
            <para>&Egrave; importante notare che il sistema della VM di FreeBSD
              tenta di separare pagine pulite e sporche per l'espressa ragione di
              evitare scritture non necessarie di pagine sporche (che divorano
              banda di I/O), e non sposta le pagine tra le varie code
              gratuitamente se il sottosistema non viene stressato.  Questo
              &egrave; il motivo per cui dando un <command>systat -vm</command>
              vedrai sistemi con contatori della coda di cache bassi e contatori
              della coda delle pagine attive molto alti.</para>
          </blockquote>

          <para>Come entra in relazione la separazione delle pagine pulite e
            sporche (inattive) con la situazione nella quale vediamo contatori
            bassi per la coda di cache e valori alti per la coda delle pagine
            attive in <command>systat -vm</command>?  I dati di systat derivano
            da una fusione delle pagine attive e sporche per la coda delle
            pagine attive?</para>
        </question>

        <answer>
          <para>Si, questo pu&ograve; confondere.  La relazione &egrave;
            <quote>obiettivo</quote> contro <quote>realt&agrave;</quote>.  Il
            nostro obiettivo &egrave; separare le pagine ma la realt&agrave;
            &egrave; che se non siamo in crisi di memoria, non abbiamo bisogno
            di farlo.</para>

          <para>Questo significa che FreeBSD non cercher&agrave; troppo di
            separare le pagine sporche (coda inattiva) da quelle pulite
            (code della cache), ne cercher&agrave; di disattivare le pagine
            (coda pagine attive -> coda pagine inattive) quando il sistema non
            &egrave; sotto sforzo, anche se non vengono effettivamente
            usate.</para>
        </answer>
      </qandaentry>

      <qandaentry>
        <question>
          <para> Nell'esempio di &man.ls.1; / <command>vmstat 1</command>,
            alcuni dei page fault non potrebbero essere data page faults
            (COW da file eseguibili a pagine private)?  Cio&egrave;, io mi
            aspetterei che i page fault fossero degli zero-fill e dei dati di
            programma.  O si implica che FreeBSD effettui il pre-COW per i dati
            di programma?</para>
        </question>

        <answer>
          <para>Un fault COW pu&ograve; essere o legato a uno zero-fill o a dati
            di programma.
            Il meccanismo &egrave; lo stesso in entrambi i casi poich&eacute;
            i dati di programma da copiare sono quasi certamente gi&agrave;
            presenti nella cache.  E infatti li tratto insieme.  FreeBSD non
            effettua preventivamentela copia dei dati di programma o lo
            zero-fill, <emphasis>effettua</emphasis> la mappatura preventiva
            delle pagine che sono presenti nella sua cache.</para>
        </answer>
      </qandaentry>

      <qandaentry>
        <question>
          <para>Nella sezione sull'ottimizzazione della tabella delle pagine,
            potresti fornire maggiori dettagli su <literal>pv_entry</literal> e
            <literal>vm_page</literal> (forse vm_page dovrebbe essere
            <literal>vm_pmap</literal>&mdash;come in 4.4, cf. pp. 180-181 di
            McKusick, Bostic, Karel, Quarterman)?  Specificamente, che tipo di
            operazioni/reazioni richiederebbero la scansione delle
            mappature?</para>

          <para>Come funziona Linux nel caso in cui FreeBSD fallisce
            (la condivisione di un grosso file mappato tra molti
            processi)?</para>
        </question>

        <answer>
          <para>Una <literal>vm_page</literal> rappresenta una tupla
            (oggetto,indice#).
            Una <literal>pv_entry</literal> rappresenta una voce nella tabella
            delle pagine hardware (pte).  Se hai cinque processi che condividono
            la stessa pagina fisica, e tre delle tabelle delle pagine di questi
            processi mappano effettivamente la pagina, questa pagina
            verr&agrave; rappresentata da una struttura
            <literal>vm_page</literal> singola e da tre strutture
            <literal>pv_entry</literal>.</para>

          <para>Le strutture <literal>pv_entry</literal> rappresentano solo
            le pagine mappate dalla MMU (una <literal>pv_entry</literal>
            rappresenta un pte).  Ci&ograve; significa che &egrave; necessario
            rimuovere tutti i riferimenti hardware a <literal>vm_page</literal>
            (in modo da poter riutilizzare la pagina per qualcos'altro,
            effettuare il page out, ripulirla, sporcarla,  e cos&igrave; via)
            possiamo semplicemente scansionare la lista collegata di
            <literal>pv_entry</literal> associate con quella
            <literal>vm_page</literal> per rimuovere o modificare i pte
            dalla loro tabella delle pagine.</para>

          <para>Sotto Linux non c'&egrave; una lista collegata del genere.  Per
            poter rimuovere tutte le mappature della tabella delle pagine
            hardware per una <literal>vm_page</literal> linux deve indicizzare
            ogni oggetto VM che <emphasis>potrebbe</emphasis> aver mappato la
            pagina.  Ad esempio, se si hanno 50 processi che mappano la stessa
            libreria condivisa e si vuole liberarsi della pagina X in quella
            libreria, sar&agrave; necessario cercare nella tabella delle pagine
            per ognuno dei 50 processi anche se solo 10 di essi ha
            effettivamente mappato la pagina.  Cos&igrave; Linux sta barattando
            la semplicit&agrave; del design con le prestazioni.  Molti algoritmi
            per la VM che sono O(1) o (piccolo N) in FreeBSD finiscono per
            diventare O(N), O(N^2), o anche peggio in Linux.
            Poich&eacute; i pte che rappresentano una particolare pagina in un
            oggetto tendono ad essere allo stesso offset in tutte le tabelle
            delle pagine nelle quali sono mappati, la riduzione del numero di
            accessi alla tabela delle pagine allo stesso offset eviter&agrave;
            che la la linea di cache L1 per quell'offset venga cancellata,
            portando ad una performance migliore.</para>

          <para>FreeBSD ha aggiunto complessit&agrave; (lo schema
            <literal>pv_entry</literal>) in modo da incrementare le prestazioni
            (per limitare gli accessi alla tabella delle pagine
            <emphasis>solo</emphasis> a quelle pte che necessitino di essere
            modificate).</para>

          <para>Ma FreeBSD ha un problema di scalabilit&agrave; che linux non ha
            nell'avere un numero limitato di strutture
            <literal>pv_entry</literal> e questo provoca problemi quando si
            hanno condivisioni massicce di dati.  In questo caso c'&egrave; la
            possibilit&agrave; che finiscano le strutture
            <literal>pv_entry</literal> anche se c'&egrave; ancora una grande
            quantit&agrave; di memoria disponibile.
            Questo pu&ograve; essere risolto abbastanza facilmente
            aumentando il numero di struttre <literal>pv_entry</literal> nella
            configurazione del kernel, ma c'&egrave; veramente bisogno di
            trovare un modo migliore di farlo.</para>

          <para>Riguardo il sovrapprezzo in memoria di una tabella delle pagine
            rispetto allo schema delle <literal>pv_entry</literal>: Linux usa
            tabelle delle pagine <quote>permanenti</quote> che non vengono
            liberate, ma non necessita una <literal>pv_entry</literal> per ogni
            pte potenzialmente mappato.
            FreeBSD usa tabelle delle pagine <quote>throw away</quote>,
            eliminabili, ma aggiunge una struttura <literal>pv_entry</literal>
            per ogni pte effettivamente mappato.  Credo che l'utilizzo della
            memoria finisca per essere pi&ugrave; o meno lo stesso, fornendo a
            FreeBSD un vantaggio algoritmico con la capacit&agrave; di
            eliminare completamente le tabelle delle pagine con un
            sovraccarico prestazionale minimo.</para>
        </answer>
      </qandaentry>

      <qandaentry>
        <question>
          <para>Infine, nella sezione sulla colorazione delle pagine, potrebbe
            esser d'aiuto avere qualche descrizione in pi&ugrave; di quello che
            intendi.  Non sono riuscito a seguire molto bene.</para>
        </question>

        <answer>
          <para>Sai come funziona una memoria cache hardware L1?  Spiego:
            Considera una macchina con 16MB di memoria principale ma solo 128K
            di cache L1.  In genere il modo in cui funziona la cache &egrave;
            che ogni blocco da 128K di memoria principale usa gli
            <emphasis>stessi</emphasis> 128K di cache.
            Se si accede all'offset 0 della memoria principale e poi al 128K su
            pu&ograve; finire per cancellarei dati che si erano messi nella
            cache dall'offset 0!</para>

          <para>Ora, sto semplificando di molto.  Ci&ograve; che ho appena
            descritto &egrave; quella che viene detta memoria cache a
            <quote>corrispondenza diretta</quote>, o direct mapped.
            La maggior parte delle cache moderne sono quelle che
            vengono dette set-associative a 2 o 4 vie.
            L'associativit&agrave; di questo tipo permette di accedere fino ad N
            regioni di memoria differenti che si sovrappongano sulla stessa
            cache senza distruggere i dati preventivamente immagazzinati.
            Ma solo N.</para>

          <para>Dunque se ho una cache set associativa a 4 vie posso accedere
            agli offset 0, 128K, 256K 384K ed essere ancora in grado di
            accedere all'offset 0 ritrovandolo nella cache L1.  Se poi accedessi
            all'offset 512K, ad ogni modo, uno degli oggetti dato immagazzinati
            precedentemente verrebbero cancellati dalla cache.</para>

          <para>&Egrave; estremamente importante &hellip;
            <emphasis>estremamente</emphasis> importante che la maggior parte
            degli accessi del processore alla memoria vengano dalla cache L1,
            poich&eacute; la cache L1 opera alla stessa frequenza del
            processore.  Nel momento in cui si ha un miss <footnote>
              <para>Un miss nella cache &egrave; equivalente a un page fault per
                la memoria fisica, ed allo stesso modo implica un accesso a
                dispositivi molto pi&ugrave; lenti, da L1 a L2 come da RAM a
                disco.</para>
            </footnote> nella cache L1 si deveandare a cercare nella cache L2 o
            nella memoria principale, il processore andr&agrave; in stallo, e
            potenzialmente potr&agrave; sedersi a girarsi i pollici per un tempo
            equivalente a <emphasis>centinaia</emphasis> di istruzioni
            attendendo che la lettura dalla memoria principale venga
            completata.  La memoria principale (la RAM che metti nel tuo
            computer) &egrave; <emphasis>lenta</emphasis>, se comparata alla
            velocit&agrave; del nucleo di un moderno processore.</para>

          <para>Ok, ora parliamo della colorazione dele pagine:
            tutte le moderne cache sono del tipo noto come cache
            <emphasis>fisiche</emphasis>.  Esse memorizzano indirizzi di memoria
            fisica, non indirizzi di memoria virtual.  Ci&ograve; permette alla
            cache di rimanere anche nel momento in cui ci sia un cambio di
            contesto tra processi, e ci&ograve; &egrave; molto
            importante.</para>

          <para>Ma nel mondo &unix; devi lavorare con spazi di indirizzamento
            virtuali, non con spazi di indirizzamento fisici.  Ogni programma
            che scrivi vedr&agrave; lo spazio di indirizzamento virtuale
            assegnatogli.  Le effettive pagine <emphasis>fisiche</emphasis>
            nascoste sotto quello spazio di indirizzi virtuali
            non saranno necessariamente contigue fisicamente! In effetti,
            potresti avere due pagine affiancate nello spazio di
            indirizzamento del processo cge finiscono per trovarsi agli
            offset 0 e 128K nella memoria <emphasis>fisica</emphasis>.</para>

          <para>Un programma normalmente assume che due pagine
            affiancate verranno poste in cache in maniera ottimale.
            Cio&egrave;, che possa accedere agli oggetti dato in
            entrambe le pagine senza che esse si cancellino a vicenda le
            rispettiva informazioni in cache.
            Ma ci&ograve; &egrave; vero solo se le pagine fisiche sottostanti lo
            spazio di indirizzo virtuale sono contigue (per quel che riguarda
            la cache).</para>

          <para>Questo &egrave; ci&ograve; che viene fatto dalla colorazione
            delle pagine.
            Invece di assegnare pagine fisiche <emphasis>casuali</emphasis> agli
            indirizzi virtuali, che potrebbe causare prestazioni non ottimali
            della cache, la colorazione dele pagine assegna pagine fisiche
            <emphasis>ragionevolmente contigue</emphasis>.
            Dunque i programmi possono essere scritti assumendo che
            le caratteristiche per lo spazio di indirizzamento virtuale del
            programma della cache hardware sottostante siano uguali a come
            sarebbero state se avessero usato lo spazio di indirizzamento
            fisico.</para>

          <para>Si note ho detto <quote>ragionevolmente</quote> contigue invece
            che semplicemente <quote>contigue</quote>.  Dal punto di vista di
            una cache di 128K a corrispondenza diretta, l'indirizzo fisico 0
            &egrave; lo stesso che l'indirizzo fisico 128K.
            Dunque due agine affiancate nello spzio di indirizzamento virtuale
            potrebbero finire per essere all'offset 128K e al 132K nella memoria
            fisica, ma potrebbero trovarsi tranquillamente anche agli offset
            128K e 4K della memoria fisica e mantenera comunque le stesse
            caratteristiche prestazionali nei riguardi della cache.  Dunque la
            colorazione delle pagine <emphasis>non</emphasis> deveassegnare
            pagine di memoria fisica veramente contigue a pagine di memoria
            virtuale contigue, deve solo assicurarsi che siano assegnate pagine
            contigue dal punto di vista delle prestazioni/operazioni della
            cache.</para>
        </answer>
      </qandaentry>
    </qandaset>
  </sect1>
</article>

<!--
     Local Variables:
     mode: sgml
     sgml-indent-data: t
     sgml-omittag: nil
     sgml-always-quote-attributes: t
     End:
-->