This file is indexed.

/usr/share/doc/HOWTO/fr-html/Parallel-Processing-HOWTO.html is in doc-linux-fr-html 2013.01-3.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

   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
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473
4474
4475
4476
4477
4478
4479
4480
4481
4482
4483
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
4571
4572
4573
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588
4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
4633
4634
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
4889
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
4947
4948
4949
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961
4962
4963
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
5016
5017
5018
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
5033
5034
5035
5036
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
5142
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
5321
5322
5323
5324
5325
5326
5327
5328
5329
5330
5331
5332
5333
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
5350
5351
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
  PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Le traitement en parallèle sous Linux</title><link rel="stylesheet" type="text/css" href="style.css"/><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"/><meta name="description" content="Le traitement en parallèle (Parallel Processing) se réfère à l'idée d'accélérer l'exécution d'un programme en divisant celui-ci en plusieurs fragments pouvant être exécutés simultanément, chacun sur son propre processeur, un programme exécuté sur N processeurs pouvant alors fonctionner N fois plus vite qu'il le ferait en utilisant un seul processeur. Ce document traite des quatre approches de base du traitement en parallèle accessibles aux utilisateurs de Linux : les systèmes Linux SMP, les grappes (cluster) de systèmes Linux mis en réseau, l'exécution en parallèle avec utilisation des instructions multimédia (ex : MMX), et l'utilisation des processeurs secondaires embarqués dans une machine fonctionnant sous Linux."/></head><body><div xml:lang="fr" class="article"><div class="titlepage"><div><div><h2 class="title"><a id="d0e1"/>Le traitement en parallèle sous Linux</h2></div><div><h3 class="subtitle"><em>
      Version française du <span class="foreignphrase"><em class="foreignphrase">Parallel Processing HOWTO</em></span>
   </em></h3></div><div><div class="author"><h3 class="author"><span class="firstname">Hank</span> <span class="surname">Dietz</span></h3><code class="email">&lt;<a class="email" href="mailto:hankd CHEZ engr POINT uky POINT edu">hankd CHEZ engr POINT uky POINT edu</a>&gt;</code></div></div><div><p class="othercredit"><span class="contrib">Adaptation française</span> : <span class="firstname">Dominique</span> <span class="surname">van den Broeck</span></p></div><div><p class="othercredit"><span class="contrib">Relecture de la version française</span> : <span class="firstname">Isabelle</span> <span class="surname">Hurbain</span></p></div><div><p class="othercredit"><span class="contrib">Préparation de la publication de la v.f.</span> : <span class="firstname">Jean-Philippe</span> <span class="surname">Guérard</span></p></div><div><p class="releaseinfo">Version : 980105.fr.1.1</p></div><div><p class="pubdate">4 septembre 2005</p></div><div><div class="revhistory"><table summary="Historique des versions"><tr><th align="left" valign="top" colspan="3"><strong>Historique des versions</strong></th></tr><tr><td align="left">Version 980105.fr.1.1</td><td align="left">2005-09-04</td><td align="left">DV</td></tr><tr><td align="left" colspan="3">Quelques améliorations mineures de la version 
          française</td></tr><tr><td align="left">Version 980105.fr.1.0</td><td align="left">2004-09-13</td><td align="left">DV, IH, JPG</td></tr><tr><td align="left" colspan="3">Première traduction française</td></tr><tr><td align="left">Version 980105</td><td align="left">1998-01-05</td><td align="left">HGD</td></tr><tr><td align="left" colspan="3">Version originale</td></tr></table></div></div><div><div class="abstract"><p class="title"><strong>Résumé</strong></p><p>

Le <span class="emphasis"><em>traitement en parallèle</em></span> 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Parallel Processing</em></span></span> »</span>) se 
réfère à l'idée d'accélérer l'exécution d'un programme en divisant 
celui-ci en plusieurs fragments pouvant être exécutés simultanément, 
chacun sur son propre processeur, un programme exécuté sur 
<span class="emphasis"><em>N</em></span> processeurs pouvant alors fonctionner 
<span class="emphasis"><em>N</em></span> fois plus vite qu'il le ferait en utilisant un 
seul processeur. Ce document traite des quatre approches de base du 
traitement en parallèle accessibles aux utilisateurs de Linux : les 
systèmes Linux SMP, les grappes 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">cluster</em></span></span> »</span>) de systèmes 
Linux mis en réseau, l'exécution en parallèle avec utilisation des 
instructions multimédia (ex : MMX), et l'utilisation des 
processeurs secondaires embarqués dans une machine fonctionnant sous 
Linux.

</p></div></div></div><hr/></div><div class="toc"><p><strong>Table des matières</strong></p><dl class="toc"><dt><span class="sect1"><a href="#d0e107">1. Introduction</a></span></dt><dd><dl><dt><span class="sect2"><a href="#d0e146">1.1. Le traitement en parallèle correspond-il à mes besoins ?</a></span></dt><dt><span class="sect2"><a href="#d0e187">1.2. Terminologie</a></span></dt><dt><span class="sect2"><a href="#d0e531">1.3. Algorithme d'exemple</a></span></dt><dt><span class="sect2"><a href="#d0e562">1.4. Structure du document</a></span></dt><dt><span class="sect2"><a href="#d0e623">1.5. Note du traducteur</a></span></dt></dl></dd><dt><span class="sect1"><a href="#d0e674">2. Linux sur SMP</a></span></dt><dd><dl><dt><span class="sect2"><a href="#d0e747">2.1. L'électronique SMP</a></span></dt><dt><span class="sect2"><a href="#d0e825">2.2. Introduction à la programmation en mémoire partagée</a></span></dt><dt><span class="sect2"><a href="#d0e1306">2.3. bb_threads</a></span></dt><dt><span class="sect2"><a href="#d0e1444">2.4. LinuxThreads</a></span></dt><dt><span class="sect2"><a href="#d0e1536">2.5. La mémoire partagée de System V</a></span></dt><dt><span class="sect2"><a href="#d0e1629">2.6. Projection mémoire (<span class="foreignphrase"><em class="foreignphrase">Memory Map Call</em></span>)</a></span></dt></dl></dd><dt><span class="sect1"><a href="#d0e1665">3. <span class="foreignphrase"><em class="foreignphrase">Clusters</em></span> de systèmes Linux</a></span></dt><dd><dl><dt><span class="sect2"><a href="#d0e1687">3.1. Pourquoi un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> ?</a></span></dt><dt><span class="sect2"><a href="#d0e1803">3.2. Le matériel réseau</a></span></dt><dt><span class="sect2"><a href="#d0e3450">3.3. Interface Logicielle Réseau</a></span></dt><dt><span class="sect2"><a href="#d0e3641">3.4. PVM (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Parallel Virtual Machine</em></span></span> »</span>)</a></span></dt><dt><span class="sect2"><a href="#d0e3711">3.5. MPI (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Message Passing Interface</em></span></span> »</span>)</a></span></dt><dt><span class="sect2"><a href="#d0e3886">3.6. AFAPI (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Aggregate Function API</em></span></span> »</span>)</a></span></dt><dt><span class="sect2"><a href="#d0e3935">3.7. Autres bibliothèques de gestion de <span class="foreignphrase"><em class="foreignphrase">clusters</em></span></a></span></dt><dt><span class="sect2"><a href="#d0e4013">3.8. Références générales aux <span class="foreignphrase"><em class="foreignphrase">clusters</em></span></a></span></dt></dl></dd><dt><span class="sect1"><a href="#d0e4298">4. SIMD <span class="foreignphrase"><em class="foreignphrase">Within A Register</em></span> : SWAR (Ex : utilisation de MMX)</a></span></dt><dd><dl><dt><span class="sect2"><a href="#d0e4360">4.1. Quels usages pour le SWAR ?</a></span></dt><dt><span class="sect2"><a href="#d0e4421">4.2. Introduction à la programmation SWAR</a></span></dt><dt><span class="sect2"><a href="#d0e4828">4.3. SWAR MMX sous Linux</a></span></dt></dl></dd><dt><span class="sect1"><a href="#d0e4903">5. Processeurs auxiliaires des machines Linux</a></span></dt><dd><dl><dt><span class="sect2"><a href="#d0e4908">5.1. Un PC Linux est une bonne station d'accueil</a></span></dt><dt><span class="sect2"><a href="#d0e4932">5.2. Avez-vous essayé le DSP ?</a></span></dt><dt><span class="sect2"><a href="#d0e5001">5.3. Calcul à l'aide des FPGA et circuits logiques reconfigurables</a></span></dt></dl></dd><dt><span class="sect1"><a href="#d0e5039">6. D'intérêt général</a></span></dt><dd><dl><dt><span class="sect2"><a href="#d0e5044">6.1. Compilateurs et langages de programmation</a></span></dt><dt><span class="sect2"><a href="#d0e5371">6.2. Question de performance</a></span></dt><dt><span class="sect2"><a href="#d0e5412">6.3. Conclusion — C'est fini !</a></span></dt></dl></dd></dl></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title"><a id="d0e107"/>1. Introduction</h2></div></div></div><p>

L'<span class="emphasis"><em>exécution en parallèle</em></span> 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Parallel Processing</em></span></span> »</span>) se 
rapporte à l'idée d'accélérer l'exécution d'un programme en le divisant 
en plusieurs fragments pouvant être exécutés simultanément, chacun sur 
son propre processeur. Un programme exécuté sur <span class="emphasis"><em>N</em></span> 
processeurs pourrait alors fonctionner <span class="emphasis"><em>N</em></span> fois plus 
vite qu'il ne le ferait en utilisant un seul processeur.

</p><p>

Traditionnellement, les processeurs multiples sont fournis avec un 
<span class="quote">« <span class="quote">ordinateur en parallèle</span> »</span> spécialement conçu. De ce fait, 
Linux gère désormais les systèmes <span class="emphasis"><em>SMP</em></span> (souvent 
vendus en tant que <span class="quote">« <span class="quote">serveurs</span> »</span>) dans lesquels plusieurs 
processeurs partagent le même bus et la même mémoire au sein d'un même 
ordinateur. Il est également possible à un groupe d'ordinateurs (par 
exemple un groupe de PC fonctionnant chacun avec Linux) d'être 
interconnectés par un réseau pour former un ensemble de traitement en 
parallèle (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">cluster</em></span></span> »</span>). La 
troisième alternative pour l'exécution parallèle sous Linux est 
l'utilisation du jeu d'instructions multimédias étendu (MultiMedia 
Extend : MMX) pour agir en parallèle sur des vecteurs de données 
entières. Il est enfin possible d'utiliser un système Linux comme 
<span class="quote">« <span class="quote">hôte</span> »</span> hébergeant un moteur de calcul en parallèle 
<span class="emphasis"><em>dédié</em></span>. Toutes ces approches sont traitées en détails 
dans ce document.

</p><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e146"/>1.1. Le traitement en parallèle correspond-il à mes besoins ?</h3></div></div></div><p>
Bien que l'emploi de multiples processeurs puisse accélérer nombre
d'opérations, la plupart des applications ne peuvent encore tirer
profit du traitement en parallèle. A la base, le traitement en
parallèle est approprié si :
</p><p>

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
Votre application est suffisamment parallélisée pour faire bon
usage de multiples processeurs. C'est, en partie, une question
d'identification des différentes portions du programme pouvant
être exécutées indépendamment et simultanément sur des processeurs
séparés, mais vous découvrirez aussi que certaines choses qui
<span class="emphasis"><em>peuvent</em></span> être exécutées en parallèle
ralentissent le traitement si elles sont exécutées en parallèle
sur un système particulier. Par exemple, un programme qui
s'exécute en quatre secondes sur une machine unique pourrait
être capable de n'occuper qu'une seconde du temps de chacune
de quatre machines, mais n'apportera pourtant aucun gain de
temps s'il faut trois secondes ou plus à ces machines pour
coordonner leurs actions.

</p></li><li class="listitem"><p>

Soit l'application qui vous intéresse en particulier a été
<span class="emphasis"><em>parallélisée</em></span>, c'est-à-dire réécrite
pour tirer profit du traitement en parallèle, soit vous comptez
produire au moins un peu de code original qui le fasse.

</p></li><li class="listitem"><p>

Vous êtes intéressé par la recherche de nouvelles solutions impliquant 
un traitement en parallèle, ou au moins souhaitez vous familiariser 
avec. Le traitement en parallèle sous Linux n'est pas forcément 
difficile, mais ce n'est pas une notion familière à beaucoup 
d'utilisateurs, et il n'existe pas de livre intitulé <span class="quote">« <span class="quote">Le 
<span class="foreignphrase"><em class="foreignphrase">Parallel Processing</em></span> pour les 
nuls</span> »</span>, en tout cas pas encore. Ce guide est un bon point de 
départ, mais il ne contient pas l'intégralité de ce que vous devez 
connaître.

</p></li></ul></div><p>

</p><p>

La bonne nouvelle, c'est que si tout ce qui vient d'être dit est vrai, 
vous découvrirez cependant que le traitement en parallèle sous Linux 
peut apporter les performances d'un supercalculateur à des programmes 
effectuant des opérations complexes ou travaillant sur de très grandes 
quantités de données. Mais en plus, cela peut être fait en utilisant du 
matériel peu onéreux et que vous possédez sûrement déjà. Avec çà, il 
reste aisé d'utiliser un système de traitement en parallèle sous Linux à 
d'autres choses lorsqu'il n'est pas en train d'accomplir un traitement 
en parallèle.

</p><p>

Si le traitement en parallèle ne correspond <span class="emphasis"><em>pas</em></span> à 
vos besoins, mais que vous souhaitez tout de même améliorer sensiblement 
les performances de votre machine, il reste des choses que vous pouvez 
faire. Par exemple, vous pouvez améliorer les performances d'un 
programme séquentiel en remplaçant votre processeur par un plus rapide, 
en ajoutant de la mémoire, en remplaçant un disque IDE par un 
<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">fast wide SCSI</em></span></span> »</span>, et cætera. 
Si c'est ce qui vous intéresse, sautez directement à la section 6.2, 
sinon poursuivez votre lecture.

</p></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e187"/>1.2. Terminologie</h3></div></div></div><p>

Bien que le traitement en parallèle ait été utilisé pendant de 
nombreuses années par de nombreux systèmes, il reste étranger à la 
plupart des utilisateurs. Aussi, avant de traiter des différentes 
alternatives, il est important de se familiariser avec une poignée de 
termes usuels :

</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">SIMD :</span></dt><dd><p>

SIMD (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Single Instruction stream, Multiple Data stream</em></span></span> »</span>, ou
<span class="quote">« <span class="quote">Un seul flot d'instruction, plusieurs flots de données</span> »</span>),
fait référence à un modèle d'exécution en parallèle dans
lequel tous les processeurs traitent la même opération à
la fois, mais où chaque processeur est autorisé à agir sur
sa propre donnée. Ce modèle convient naturellement au concept
où l'on applique le même traitement sur chaque élément d'un
tableau, et est ainsi souvent associé à la manipulation de
vecteurs ou de tableaux. Toutes les opérations étant
implicitement synchronisées, les interactions entre processeurs
SIMD tendent à être facilement et efficacement mises en œuvre.

</p></dd><dt><span class="term">MIMD :</span></dt><dd><p>

MIMD (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Multiple Instruction stream, Multiple Data stream</em></span></span> »</span>,
ou <span class="quote">« <span class="quote">Plusieurs flots d'instructions, plusieurs flots de données</span> »</span>),
se rapporte au modèle d'exécution en parallèle dans lequel chaque
processeur agit essentiellement seul. C'est le modèle qui convient
le mieux à la décomposition d'un programme pour une exécution en
parallèle sur une base fonctionnelle. Par exemple, une processeur
peut mettre à jour une base de données pendant qu'un autre produit
l'affichage graphique de la nouvelle entrée. C'est un modèle plus
flexible que l'exécution en SIMD, mais qui s'accomplit au risque
d'un cauchemar pour le débogueur, les <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">race conditions</em></span></span> »</span>
ou <span class="quote">« <span class="quote">accès concurrents</span> »</span>, dans lesquels un programme peut planter
de façon intermittente à cause des différences de minutage entre
les opérations des différents processeurs lorsque celles d'un de ces
processeurs sont réorganisées en fonction de celles d'un autre.

</p></dd><dt><span class="term">SPMD :</span></dt><dd><p>

SPMD (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Single Program, Multiple Data</em></span></span> »</span>),
ou <span class="quote">« <span class="quote">Un seul programme, plusieurs données</span> »</span>, est une version
restreinte du MIMD dans laquelle tous les processeurs
exécutent le même programme. Contrairement au SIMD, chaque
processeur peut suivre un chemin différent dans le programme.

</p></dd><dt><span class="term">Bande passante :</span></dt><dd><p>

La bande passante 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">bandwidth</em></span></span> »</span>) d'un système 
de communication correspond à la quantité maximum de données que l'on 
peut transmettre en une unité de temps… une fois que la 
transmission de données a commencé. La bande passante des connexions 
série est souvent mesurée en <span class="emphasis"><em>bauds</em></span> ou en 
<span class="emphasis"><em>bits par seconde (b/s)</em></span>, ce qui correspond en 
général à huit fois ou dix fois le nombre d'<span class="emphasis"><em>octets par 
secondes (O/s ou B/s</em></span>, B = 
<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Byte</em></span></span> »</span> = 
<span class="quote">« <span class="quote">Octet</span> »</span>). Par exemple, un modem à 1200 bauds (N.D.T. : 
comme celui du Minitel) peut transférer environ 120 octets à la seconde 
(B/s), tandis qu'une connexion réseau ATM à 155 Mb/s est environ 
130 000 fois plus rapide, en transférant environ 17 Mo/s. Une bande 
passante élevée permet un transfert efficace de larges blocs de données 
entre processeurs.

</p></dd><dt><span class="term">Latence :</span></dt><dd><p>

La latence d'un système de communication représente le temps minimum 
nécessaire pour la transmission d'un objet, en incluant toutes les 
données <span class="quote">« <span class="quote">forfaitaires</span> »</span> logicielles pour l'émission et la 
réception (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">overhead</em></span></span> »</span>). Le 
temps de latence est très important dans les traitements en parallèle 
car il détermine la <span class="emphasis"><em>granularité</em></span>, la 
durée minimum d'exécution d'un segment de code pour gagner en vitesse 
d'exécution grâce au traitement en parallèle. Concrètement, si un 
segment de code s'exécute en moins de temps qu'il n'en faut pour 
transmettre son résultat (ce délai-ci formant la latence), exécuter ce 
segment en série plutôt qu'en parallèle sera plus rapide puisqu'il n'y 
aura pas de délai de transmission.

</p></dd><dt><span class="term">Envoi de messages (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Message passing</em></span></span> »</span>) :</span></dt><dd><p>

Les envois de message sont un modèle d'interaction entre les différents 
processeurs d'un système parallèle. En général, un message est construit 
logiciellement sur un processeur et envoyé via une interconnexion réseau 
à un autre processeur. Bien que le surcoût en temps 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">overhead</em></span></span> »</span>) engendré par la 
gestion de chaque message (ce délai formant la latence) soit élevé, 
typiquement, il n'y a que peu de restrictions quant à la quantité 
d'informations que ce message peut contenir. Ainsi, l'envoi de messages 
peut assurer une bande passante élevée en apportant une méthode efficace 
pour transmettre de grandes quantités d'informations d'un processeur à 
un autre. En revanche, afin de réduire les besoins en coûteuses 
opérations d'envoi de message, les structures de données à l'intérieur 
d'un programme doivent être réparties à travers tous les processeurs de 
façon à ce que la plupart des données référencées par chaque processeur 
se trouve dans sa mémoire locale… Cette tâche porte le nom de 
<span class="quote">« <span class="quote">répartition des données</span> »</span> (<span class="quote">« <span class="quote"><span class="emphasis"><em>data 
layout</em></span></span> »</span>).

</p></dd><dt><span class="term">Mémoire partagée :</span></dt><dd><p>

La mémoire partagée est elle aussi un modèle d'interaction entre les 
processeurs d'un système parallèle. Les systèmes comme les machines 
biprocesseurs Pentium faisant fonctionner Linux partagent 
<span class="emphasis"><em>physiquement</em></span> la même mémoire entre tous leurs 
processeurs, si bien qu'une valeur écrite par un processeur est 
directement accessible par un autre processeur. A l'inverse, la mémoire 
partagée <span class="emphasis"><em>logiquement</em></span> peut être implémentée sur les 
systèmes où chaque processeur dispose d'une mémoire qui lui est propre, 
en convertissant chaque référence à une zone non locale de la mémoire en 
une communication inter-processeur appropriée. Cette implémentation de 
la mémoire partagée est généralement considérée comme étant plus facile 
à utiliser que les files de messages. La mémoire partagée physiquement 
peut présenter à la fois une bande passante élevée et des temps de 
latence très bas, mais seulement lorsque les différents processeurs 
n'essaient pas d'accéder au bus simultanément. Ainsi, le modèle de 
répartition des données peut avoir une sérieuse influence sur les 
performances, et les effets de cache et autres peuvent rendre très 
difficile la détermination du meilleur modèle.

</p></dd><dt><span class="term">Fonctions d'agrégation (<span class="foreignphrase"><em class="foreignphrase">Aggregate Functions</em></span>) :</span></dt><dd><p>

Dans le modèle des files de messages comme dans celui de la mémoire 
partagée, une communication est initiée par un processeur seul. Par 
contraste, une fonction d'agrégation est un modèle implicitement 
parallèle dans lequel tous les processeurs d'un groupe agissent 
ensemble. Le cas le plus simple est celui des <span class="emphasis"><em>barrières de 
synchronisation</em></span>, dans lequel chaque processeur se met en 
attente jusqu'à ce que le groupe entier ait atteint la barrière. Si 
chaque processeur émet une donnée en atteignant une barrière, il est 
possible de demander à l'électronique responsable des communications 
d'émettre en retour une valeur à chaque processeur, valeur qui pourrait 
être fonction des données collectées sur tous les processeurs. Par 
exemple, la valeur de retour pourrait être la réponse à la question 
<span class="quote">« <span class="quote">Est-ce qu'un processeur a trouvé la réponse ?</span> »</span> ou 
pourrait être la somme d'une valeur propre à chaque processeur. Les 
temps de latence peuvent être bas, mais la bande passante a tendance à 
être basse elle aussi. Traditionnellement, ce modèle est surtout utilisé 
pour contrôler l'exécution en parallèle, plutôt que pour distribuer les 
données.

</p></dd><dt><span class="term">Communication collective :</span></dt><dd><p>

C'est un autre nom pour les fonctions d'agrégation, utilisé le plus 
souvent en référence à celles qui sont construites en utilisant de 
multiples opérations d'envoi de message.

</p></dd><dt><span class="term">SMP :</span></dt><dd><p>

SMP (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Symmetric 
Multi-Processor</em></span></span> »</span>) se rapporte au concept d'un 
groupe de processeurs travaillant ensemble en tant qu'homologues, si 
bien que chaque partie d'un travail peut être effectuée de la même façon 
par n'importe quel processeur de ce groupe. Typiquement, le SMP implique 
la combinaison du MIMD et de la mémoire partagée. Dans l'univers IA32, 
SMP signifie souvent <span class="quote">« <span class="quote">compatible MPS</span> »</span> 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Intel MultiProcessor 
Specification</em></span></span> »</span>). À l'avenir, cela pourrait 
signifier 
<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Slot 2</em></span></span> »</span></p></dd><dt><span class="term">SWAR :</span></dt><dd><p>

SWAR (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">SIMD Within A 
Register</em></span></span> »</span>, ou <span class="quote">« <span class="quote">SIMD à l'intérieur d'un 
registre</span> »</span>) est un terme générique qui désigne le concept 
consistant à partitionner un registre en plusieurs champs entiers et à 
effectuer des opérations sur toute la largeur du registre pour faire du 
calcul en parallèle SIMD sur tous les champs à la fois. En considérant 
une machine avec des registres longs de <span class="emphasis"><em>k</em></span> bits (et 
donc autant pour les chemins de données, et les unités des fonctions), 
on sait depuis longtemps que les opérations sur les registres ordinaires 
peuvent fonctionner comme des opérations parallèle SIMD sur 
<span class="emphasis"><em>n</em></span> champs de <span class="emphasis"><em>k/n</em></span> bits. Bien que ce 
type de parallélisme puisse être mis en œuvre en utilisant les 
registres entiers et les instructions ordinaires, plusieurs modèles 
récents de microprocesseurs intègrent des instructions spécialisées pour 
améliorer les performances de cette technique pour des tâches orientées 
multimédia. En plus du <span class="emphasis"><em>MMX</em></span> 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">MultiMedia eXtension</em></span></span> »</span>) 
d'Intel/AMD/Cyrix, il existe : <span class="emphasis"><em>MAX</em></span> 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">MultimediA eXtension</em></span></span> »</span>) sur 
l'Alpha de Digital, <span class="emphasis"><em>MAX</em></span> 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Multimedia Acceleration 
eXtension</em></span></span> »</span>) sur le PA-RISC de Hewlett-Packard, 
<span class="emphasis"><em>MDMX</em></span> (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Digital Media 
eXtension</em></span></span> »</span>, prononcé <span class="quote">« <span class="quote">Mad Max</span> »</span>) 
sur MIPS, et <span class="emphasis"><em>VIS</em></span> (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Visual 
Instruction Set</em></span></span> »</span>) sur le SPARC V9 de Sun. En 
dehors des trois constructeurs qui ont adopté le MMX, tous ces jeux 
d'instructions sont comparables, mais incompatibles entre eux.

</p></dd><dt><span class="term">Processeur auxiliaires, dédiés. (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Attached Processors</em></span></span> »</span>) :</span></dt><dd><p>

Les processeurs auxiliaires sont essentiellement des calculateurs dédiés 
à une tâche particulière, reliés à un système <span class="emphasis"><em>hôte</em></span> 
et servant à accélérer certains types de calculs. Par exemple, de 
nombreuses cartes vidéo et son pour PC embarquent des processeurs dédiés 
conçus pour accélérer respectivement les opérations graphiques et le 
<span class="emphasis"><em>DSP</em></span> audio (DSP : <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Digital 
Signal Processing</em></span></span> »</span>, soit <span class="quote">« <span class="quote">Traitement 
Numérique du Signal</span> »</span>). Il existe aussi une large variété de 
<span class="emphasis"><em>processeurs de tableaux</em></span> 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">array processors</em></span></span> »</span>), nommés 
ainsi car ils sont conçus pour accélérer les opérations arithmétiques 
sur les tableaux. À dire vrai, un certain nombre de supercalculateurs 
commerciaux sont en réalité formés de processeurs dédiés rattachés à des 
stations de travail hôtes.

</p></dd><dt><span class="term">RAID :</span></dt><dd><p>

RAID (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Redundant Array of Inexpensive 
Disks</em></span></span> »</span>, soit <span class="quote">« <span class="quote">Batterie Redondante de 
Disques Peu Coûteux</span> »</span>) est une technologie simple servant à 
améliorer tant la bande passante que la fiabilité des accès disque. Même 
si le RAID se décline en plusieurs variantes, toutes ont en commun deux 
concepts-clés : D'abord, chaque bloc de données est 
<span class="emphasis"><em>découpé</em></span> en segments distribués à un groupe de 
<span class="emphasis"><em>n+k</em></span> disques de façon à ce que chaque disque n'ait à 
lire que <span class="emphasis"><em>1/n</em></span>ième de la donnée… offrant ainsi 
<span class="emphasis"><em>n</em></span> fois la bande passante d'un seul disque. Ensuite, 
des données redondantes sont écrites pour que les données puissent être 
recouvrées si un des disques vient à défaillir. C'est important car 
autrement, si l'un des <span class="emphasis"><em>n+k</em></span> disques tombait en 
panne, le système de fichiers entier pourrait être perdu. Il existe une 
bonne présentation du système RAID sur <a class="ulink" href="http://www.dpt.com/uraiddoc.html" target="_top">http://www.dpt.com/uraiddoc.html</a>, ainsi que des informations 
concernant le RAID pour Linux sur <a class="ulink" href="http://linas.org/linux/raid.html" target="_top">http://linas.org/linux/raid.html</a>. Hormis la prise en charge du 
matériel RAID spécialisé, Linux gère aussi le RAID logiciel 0, 1, 4 et 5 
à travers plusieurs disques hébergés sur un système Linux unique. 
Reportez-vous aux Software RAID mini-HOWTO et Multi-Disk System Tuning 
mini-HOWTO pour plus de détails. Le RAID au travers de plusieurs disques 
<span class="emphasis"><em>sur plusieurs machines en clusters</em></span> n'est pas 
directement pris en charge.

</p></dd><dt><span class="term">IA32 :</span></dt><dd><p>

L'IA32 (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Intel 
Architecture</em></span></span> »</span>, 32 bits) n'a rien à voir avec le 
traitement en parallèle, mais se réfère à la classe de processeurs dont 
les instructions sont compatibles avec celles de l'Intel 386. 
Concrètement, tout processeur Intel x86 après le 286 est compatible avec 
le modèle de mémoire <span class="quote">« <span class="quote">à plat<a href="#ftn.d0e493" class="footnote" id="d0e493"><sup class="footnote">[1]</sup></a></span> »</span> qui caractérise l'IA32. AMD et Cyrix font eux 
aussi une multitude de processeurs compatibles IA32. Comme Linux a 
évolué principalement sur des processeurs IA32 et que c'est là qu'est 
centré le marché de la grande consommation, il est commode d'utiliser le 
terme IA32 pour distinguer ce type de processeur des PowerPC, Alpha, 
PA-RISC, MIPS, SPARC, et cætera. La future IA64 (64 bits avec EPIC, 
<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Explicitly Parallel Instruction 
Computing</em></span></span> »</span>) va certainement compliquer les 
choses, mais la production de Merced, le premier processeur IA64, n'est 
pas envisagée avant 1999.

</p></dd><dt><span class="term">Produits du commerce :</span></dt><dd><p>

Depuis la mort de plusieurs fabricants de supercalculateurs en parallèle,
les solutions commerciales toutes faites et prêtes à l'emploi (en 
anglais <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Commercial Off-The-Shelf</em></span></span> »</span>
ou <span class="foreignphrase"><em class="foreignphrase">COTS</em></span>, pour <span class="quote">« <span class="quote">disponibles en 
rayons</span> »</span>) sont couramment considérées comme une nécessité dans le 
monde des systèmes de calcul en parallèle. En étant totalement puriste, les 
seuls moyens de traitement en parallèle disponibles sous forme de 
produits du commerce utilisant des PC sont des choses comme les serveurs 
Windows NT en SMP et les différentes applications Windows utilisant le 
MMX. Être aussi puriste ne mène à rien. L'idée fondamentale de 
l'utilisation de produits du commerce est de réduire les coûts et les 
temps de développement. Ainsi, une manière plus complète et plus utile 
de comprendre l'utilisation de ce type de produit serait de dire que 
la plupart des sous-systèmes tirent profit du marché de masse mais que 
d'autres technologies sont utilisées là où elles servent vraiment. Le 
plus souvent, les produits du commerce pour le traitement en parallèle
sont utilisés au sein d'un groupe de machines 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">cluster</em></span></span> »</span>) dans lequel les 
postes sont des PC courants, mais dont l'interface réseau et les 
logiciels ont été quelque peu <span class="emphasis"><em>personnalisés</em></span>… 
classiquement, fonctionnant sous Linux avec des applications dont le 
code source est libre et disponible (par exemple sous
<span class="foreignphrase"><em class="foreignphrase">copyleft</em></span> ou dans le domaine public), mais 
pas littéralement des produits du commerce.

</p></dd></dl></div></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e531"/>1.3. Algorithme d'exemple</h3></div></div></div><p>
Afin de bien comprendre l'usage des différentes approches de
programmation en parallèle mises en évidence dans ce guide,
il est utile d'étudier cet exemple. Bien qu'un algorithme
simple de traitement en parallèle eût suffi, si l'on en choisit
un qui a déjà été utilisé pour faire la démonstration d'autres
systèmes de programmation parallèle, il devient un peu plus facile
de comparer et mettre en évidence les caractéristiques de ces différentes approches. le livre
de M. J. Quinn, <span class="foreignphrase"><em class="foreignphrase">Parallel Computing Theory And Practice</em></span>
(<span class="quote">« <span class="quote">Théorie et Pratique du Calcul en Parallèle</span> »</span>), seconde édition, édité
par McGraw Hill, New York en 1994, utilise un algorithme parallèle
qui calcule la valeur de Pi pour présenter différents environnements
de programmation sur supercalculateurs parallèles (par exemple, le
<span class="foreignphrase"><em class="foreignphrase">message passing</em></span> du nCube ou la mémoire partagée des Sequent). Dans ce
guide, nous utiliserons le même algorithme.
</p><p>
Cet algorithme calcule la valeur approchée de Pi en faisant la
somme de l'aire située sous <span class="emphasis"><em>x</em></span> au carré. En
tant que programme C purement séquentiel, l'algorithme ressemble à :
</p><p>

</p><pre class="programlisting">
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;

main(int argc, char **argv)
{
  register double largeur, somme;
  register int intervalles, i;

  /* Lit le nombre d'intervalles désiré */
  intervalles = atoi(argv[1]);
  largeur = 1.0 / intervalles;

  /* fait le calcul */
  somme = 0;
  for (i=0; i&lt;intervalles; ++i) {
    register double x = (i + 0.5) * largeur;
    somme += 4.0 / (1.0 + x * x);
  }
  somme *= largeur;

  printf("Estimation de la valeur de pi: %f\n", somme);

  return(0);
}
</pre><p>

</p><p>

En revanche, cet algorithme séquentiel conduit facilement à une 
implémentation <span class="quote">« <span class="quote">parallèle et embarrassante</span> »</span>. L'aire est 
subdivisée en intervalles, et un nombre quelconque de processeurs peut 
faire la somme de l'intervalle qui lui est assigné indépendamment des 
autres, sans nécessité d'interaction entre les processeurs. Une fois que 
les sommes locales ont toutes été calculées, elles sont additionnées 
pour former la somme globale. Cette étape requiert un certain niveau de 
coordination et de communication entre les différents processeurs. 
Enfin, cette somme globale est renvoyée à l'écran par un seul 
processeur, en tant que valeur approximative de Pi.

</p><p>
Dans ce guide, les différentes implémentations parallèles de cet algorithme
apparaissent là ou les différentes méthodes de programmation sont traitées.
</p></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e562"/>1.4. Structure du document</h3></div></div></div><p>
Le reste de ce document est divisé en cinq parties. Les sections
2, 3, 4 et 5 correspondent aux trois différents types de configuration
matérielle pouvant assumer le traitement en parallèle en utilisant
Linux.
</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

La section 2 traite des systèmes Linux sur SMP, lesquels prennent
directement en charge l'exécution MIMD en utilisant la mémoire
partagée, même si les files de messages sont facilement mises en
place, elles aussi. Bien que Linux sache gérer les configurations
SMP jusqu'à 16 processeurs, la plupart des ordinateurs SMP de type PC
sont dotés soit de deux, soit de quatre processeurs identiques.

</p></li><li class="listitem"><p>

La section 3 traite des batteries d'ordinateurs en réseau 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">clusters</em></span></span> »</span>), chaque machine 
fonctionnant sous Linux. Un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> peut 
être utilisé comme un système de traitement en parallèle gérant 
directement l'exécution en MIMD et l'échange de messages, et peut-être 
même aussi la mémoire partagée logique. L'exécution SIMD simulée et la 
communication des fonctions d'agrégation peuvent aussi être prises en 
charge, selon le réseau exploité. Le nombre de processeurs compris dans 
un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> peut s'étendre de deux à 
plusieurs milliers, la principale limitation étant le câblage physique 
du réseau. Dans certains cas, des machines de différents types peuvent 
être mélangées au sein d'un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span>. Par 
exemple, un réseau qui combinerait des Alpha DEC et des Pentium sous 
Linux serait appelé <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> 
<span class="emphasis"><em>hétérogène</em></span>.

</p></li><li class="listitem"><p>

La section 4 traite du SWAR, le <span class="quote">« <span class="quote">SIMD dans un registre</span> »</span>. 
C'est une forme très restrictive d'exécution en parallèle, mais d'un 
autre coté, c'est une possibilité intégrée aux processeurs ordinaires. 
Ces derniers temps, les extensions MMX et autres des processeurs 
modernes ont rendu cette approche encore plus efficace.

</p></li><li class="listitem"><p>

La section 5 traite de l'utilisation de PC sous Linux comme hôtes pour 
des systèmes de calcul parallèle simples. Sous forme de carte 
d'extension ou de boîtiers externes, les processeurs auxiliaires peuvent 
apporter à des systèmes Linux une formidable puissance de traitement 
pour des applications spécifiques. Par exemple, des cartes ISA 
disponibles à peu de frais fournissent de multiples processeurs DSP, 
offrant plusieurs centaines de MégaFLOP aux calculs de grande envergure. 
En revanche, ces cartes ne sont <span class="emphasis"><em>que</em></span> des 
processeurs. Elle n'embarquent généralement pas de système 
d'exploitation, de disque dur, ou de connecteur pour terminal de 
contrôle, et cætera. Pour rendre ces systèmes exploitables, 
l'<span class="quote">« <span class="quote">hôte</span> »</span> Linux doit fournir ces facilités.

</p></li></ul></div><p>

La section finale de ce document couvre les aspects d'intérêt général 
concernant le traitement en parallèle sous Linux, non spécifique à l'une 
des approches listées ci-dessus.

</p><p>

En lisant ce document, gardez à l'esprit que nous n'avons pas tout 
testé, et que beaucoup de choses rapportées dans ce document ont 
toujours <span class="quote">« <span class="quote">un caractère expérimental</span> »</span> (une jolie manière de 
dire que cela ne fonctionne pas tout à fait comme espéré ;-) ). Cela 
dit, le traitement en parallèle sous Linux est désormais exploitable, et 
un groupe incroyablement vaste de personnes travaille à le rendre encore 
meilleur.

</p><p>

L'auteur de la version originale de ce guide est le Dr (Ph.D) Hank 
Dietz, actuellement Professeur Associé de l'<span class="foreignphrase"><em class="foreignphrase">Electrical 
and Computer Engineering</em></span> à l'université de Purdue, West 
Lafayette, IN, 47907-1285. Dietz est propriétaire des droits sur ce 
document, conformément aux règles du <span class="foreignphrase"><em class="foreignphrase">Linux Documentation 
Project</em></span> (LDP). Bien qu'un effort ait été fait pour 
assurer l'exactitude de cette présentation, ni Dietz ni l'Université de 
Purdue ne peuvent être tenus responsables d'éventuels problèmes ou 
erreurs, et l'Université de Purdue n'endosse la responsabilité d'aucun 
produit ou travaux traités dans ce document.

</p></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e623"/>1.5. Note du traducteur</h3></div></div></div><p>

Chers lecteurs, avant de poursuivre la lecture de ce guide, il est 
important de revenir, notament au vu de la date de publication de cette 
version française, sur plusieurs points :

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Le Professeur Henry G. Dietz (dit <span class="quote">« <span class="quote">Hank</span> »</span>), après avoir 
enseigné plusieurs années à l'Université de Purdue et y avoir développé 
la plupart de ce qui forme ce document, <span class="emphasis"><em>mène aujourd'hui ses recherches à 
l'Université du Kentucky</em></span>. Son site personnel se trouve 
désormais ici: <a class="ulink" href="http://aggregate.org/hankd/" target="_top">http://aggregate.org/hankd/</a>. Cela signifie 
également que la plupart des références à l'Université de Purdue sont 
désormais caduques. Toutefois, un certain nombre de ces références ont 
été conservées en l'état dans ce guide, ce lorsque le contenu référencé 
était toujours disponible sur le site de l'Université sans avoir été 
transféré vers le nouveau site. En tout état de cause, dirigez-vous en 
priorité sur le site de l'Université du Kentucky pour tout contact ou 
pour obtenir les informations les plus récentes.

</p></li><li class="listitem"><p>

La totalité des termes, notament techniques, employés dans ce documents 
ont été traduits en français, à quelques exceptions près. C'est par 
exemple le cas du mot 
<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">cluster</em></span></span> »</span>, qui désigne en 
informatique la mise en parallèle de plusieurs machines individuelles et 
coordonnées de manière à les faire agir comme un seul super-ordinateur. 
Le terme français homologue est <span class="quote">« <span class="quote">grappe</span> »</span>. Toutefois, la 
fréquence à laquelle ce mot est employé tant dans ce document (un 
chapitre entier est consacré à ce sujet précis) que dans la communauté 
du traitement en parallèle en général est telle que le terme original a 
été conservé dans la présente version française. Dans le même esprit, la 
notion de <span class="quote">« <span class="quote">bande passante</span> »</span> se retrouve très fréquement tout 
au long de ce guide. C'est à la base un abus de langage, mais la 
popularité de cette formule est également suffisament grande pour la 
conserver en l'état.

</p></li><li class="listitem"><p>

La version originale de ce document a été écrite en 1998, la version 
française est parue en 2004. Il va sans dire qu'au cours d'une aussi 
longue période, le paysage informatique a beaucoup évolué, spécialement 
en ce qui concerne le développement du noyau Linux. Certaines 
technologies réseau (telles que ATM, FireWire, ou Fiber Channel) ou de 
<span class="foreignphrase"><em class="foreignphrase">clustering</em></span> (comme MOSIX), recensées comme 
indisponibles en 1998, ont depuis intégré le noyau, ou sont devenues 
disponibles. En revanche, il est très peu probable qu'une technologie 
connue pour fonctionner sous Linux lors de la rédaction de ce document 
soit devenue inutilisable depuis.

</p></li><li class="listitem"><p>

Plus encore que celui de l'industrie informatique, le paysage du 
<span class="foreignphrase"><em class="foreignphrase">World Wide Web</em></span> s'est transformé de façon 
à rendre la plupart des liens proposés obsolètes. Un effort a été fait 
pour assurer leur mise à jour ou leur remplacement, ainsi que la 
pertinence de leur contenu. En dépit de cela, un certain nombre d'entre eux,
en particulier ceux dont les projets étaient hébergés sur les 
pages personnelles d'étudiants de grandes écoles, n'ont pu être corrigés 
et ont été retirés du document.

</p></li></ul></div><p>

Malgré toutes ces réserves, les techniques couvertes par ce document 
sont suffisament générales pour rester valables au cours du temps et au 
travers des différents modèles de machines, et son contenu présente 
toujours un intérêt à la fois pédagogique et historique, qui restera encore 
longtemps profitable au lecteur. Tout ceci justifie une publication même 
tardive.

</p><p>

Enfin, le traducteur s'est efforcé de rendre le présent document aussi 
correct et fidèle à son original que possible, mais n'est pas 
infaillible. Tout signalement d'un contresens, d'une erreur technique, 
ou tout autre défaut de traduction sera apprécié à sa juste valeur à 
l'adresse suivante :

<code class="email">&lt;<a class="email" href="mailto:dvandenbroeck CHEZ free POINT fr">dvandenbroeck CHEZ free POINT fr</a>&gt;</code>.

</p><p>

Bonne lecture !

</p></div></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title"><a id="d0e674"/>2. Linux sur SMP</h2></div></div></div><p>

Ce document donne un bref aperçu de la manière dont on utilise <a class="ulink" href="http://www.linux.org.uk/SMP/title.html" target="_top">le SMP sous Linux</a> 
pour le traitement en parallèle. L'information la plus à jour concernant 
le SMP sous Linux est fort probablement disponible via la liste de 
diffusion du SMP Linux Project (N.D.T. : en anglais). Envoyez un 
courrier électronique à

<code class="email">&lt;<a class="email" href="mailto:majordomo CHEZ vger POINT rutgers POINT edu">majordomo CHEZ vger POINT rutgers POINT edu</a>&gt;</code>

avec le texte <code class="literal">subscribe linux-smp</code> pour rejoindre la 
liste.

</p><p>

Le SMP sous Linux fonctionne-t-il vraiment ? En juin 1996, j'ai 
fait l'achat d'un bi-Pentium 100MHz flambant neuf. Le système complet et 
assemblé, comprenant les deux processeurs, la carte-mère Asus, 256 
kilo-octets de mémoire cache, 32 méga-octets de RAM, le disque dur d'1.6 
giga-octet, le lecteur de CD-ROM 6X, une carte Stealth 64 et un moniteur 
15'' Acer m'a coûté 1800 dollars. Cela ne fait que quelques centaines de 
dollars de plus qu'un système monoprocesseur. Pour faire fonctionner le 
SMP sous Linux, il a suffi d'installer le Linux monoprocesseur 
d'origine, de recompiler le noyau en décommentant la ligne 
<code class="literal">SMP=1</code> dans le <span class="emphasis"><em>Makefile</em></span> (bien que 
je trouve le fait de mettre <code class="literal">SMP</code> à 
<code class="literal">1</code> un peu ironique ! ;-) ), et d'informer 
<code class="literal">lilo</code> de l'existence du nouveau noyau. Ce système 
présente une stabilité et des performances suffisamment bonnes pour 
qu'il me serve depuis de station de travail principale. Pour résumer, le 
SMP sous Linux, ça fonctionne !

</p><p>

La question qui se présente alors est : existe-t-il suffisamment 
d'API de haut niveau permettant d'écrire et d'exécuter des programmes en 
parallèle et utilisant la mémoire partagée sous Linux SMP ? Courant 
1996, il n'y en avait pas beaucoup. Les choses ont changé. Par exemple, 
il existe désormais une bibliothèque POSIX de gestion des 
<span class="foreignphrase"><em class="foreignphrase">threads</em></span><a href="#ftn.d0e709" class="footnote" id="d0e709"><sup class="footnote">[2]</sup></a> très complète.

</p><p>

Bien que les performances soient moins élevées que celles des mécanismes 
de mémoire partagée natifs, un système Linux sur SMP peut aussi utiliser 
la plupart des logiciels de traitement en parallèle initialement 
développés pour des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> de stations 
de travail en utilisant la communication par 
<span class="foreignphrase"><em class="foreignphrase">socket</em></span>. Les <span class="emphasis"><em>sockets</em></span> 
(voir section 3.3) fonctionnent à l'intérieur d'une machine en SMP, et 
même dans un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> de machines SMP 
reliées en réseau. Cependant, les <span class="foreignphrase"><em class="foreignphrase">sockets</em></span> 
engendrent beaucoup de pertes en temps inutiles pour du SMP. Cela 
complique le problème car Linux SMP n'autorise en général qu'un seul 
processeur à la fois à se trouver dans le noyau et le contrôleur 
d'interruption est réglé de façon à ce que seul le processeur de 
<span class="foreignphrase"><em class="foreignphrase">boot</em></span><a href="#ftn.d0e732" class="footnote" id="d0e732"><sup class="footnote">[3]</sup></a> puisse traiter les interruptions. En dépit de cela, 
l'électronique de communication typique des systèmes SMP est tellement 
meilleure que la plupart des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> en 
réseau que les logiciels pour <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> 
fonctionneront souvent mieux sur du SMP que sur le 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> pour lequel ils ont été conçus.

</p><p>
Le reste de cette section traite de l'électronique contrôlant le SMP,
passe en revue les mécanismes Linux de base partageant de la mémoire
à travers les différents processus d'un programme en parallèle, fait
quelques remarques concernant l'atomicité, la volatilité, les verrous
et les lignes de cache, et donne enfin des références vers d'autres
ressources de traitement en parallèle à mémoire partagée.
</p><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e747"/>2.1. L'électronique SMP</h3></div></div></div><p>

Bien que les systèmes SMP soit répandus depuis de nombreuses années, 
jusque très récemment, chaque machine tendait à implémenter les 
fonctions de base d'une manière suffisamment différente des autres pour 
que leur gestion par le système d'exploitation ne soit pas portable. Les 
choses ont changé avec la <span class="foreignphrase"><em class="foreignphrase">Intel's MultiProcessor 
Specification</em></span> (Spécification MultiProcesseurs d'Intel) 
souvent désignée par <span class="emphasis"><em>MPS</em></span>. La spécification MPS 1.4 
est actuellement disponible sous forme de document PDF sur <a class="ulink" href="http://www.intel.com/design/intarch/MANUALS/242016.htm" target="_top">http://www.intel.com/design/intarch/MANUALS/242016.htm</a><a href="#ftn.d0e759" class="footnote" id="d0e759"><sup class="footnote">[4]</sup></a>,
mais gardez à l'esprit qu'Intel réorganise souvent son site web. Un large 
panel de constructeurs fabrique des systèmes conformes à MPS pouvant 
recevoir jusqu'à quatre processeurs, mais en théorie, MPS admet bien 
plus de processeurs.

</p><p>

Les seuls systèmes non MPS et non IA32 reconnus par Linux SMP sont les 
machines SPARC multiprocesseurs de Sun4m. Linux SMP prend aussi en 
charge la plupart des machines Intel conformes à MPS 1.1 ou 1.4, 
comptant jusqu'à 16 processeurs 486DX, Pentium, Pentium MMX, Pentium Pro 
ou Pentium II. Parmi les processeurs IA32 non pris en charge (N.D.T. : 
par le SMP), on trouve les Intel 386 et 486SX/SLC (l'absence de 
coprocesseur mathématique interfère sur les mécanismes du SMP) et les 
processeurs AMD et Cyrix (qui nécessitent des circuits de gestion du SMP 
différents et qui ne semblent pas être disponibles à l'heure où ce 
document est écrit).

</p><p>
Il est important de bien comprendre que les performances de différents
systèmes conformes à MPS peuvent fortement varier. Comme l'on peut s'y
attendre, une des causes de différence de performance est la vitesse
du processeur : Une horloge plus rapide tend à rendre les systèmes plus
rapides, et un processeur Pentium Pro est plus rapide qu'un Pentium.
En revanche, MPS ne spécifie pas vraiment comment le matériel doit
mettre en œuvre la mémoire partagée, mais seulement comment cette
implémentation doit fonctionner d'un point de vue logiciel. Cela
signifie que les performances dépendent aussi de la façon dont
l'implémentation de la mémoire partagée interagit avec les caractéristiques
de Linux SMP et de vos applications en particulier.
</p><p>
La principale différence entre les systèmes conformes à MPS réside
dans la manière dont ils implémentent l'accès à la mémoire physiquement
partagée.
</p><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e771"/>2.1.1. Chaque processeur possède-t-il sa propre mémoire cache de niveau 2 (L2) ?</h4></div></div></div><p>
Certains systèmes MPS à base de Pentium, et tous les systèmes MPS
Pentium Pro et Pentium II ont des mémoires cache L2 indépendantes
(le cache L2 est embarqué dans le module des Pentium Pro et Pentium II).
Les mémoires caches L2 dissociées sont généralement réputées augmenter
les performances de l'ordinateur, mais les choses ne sont pas si évidentes
sous Linux. La principale complication provient du fait que l'ordonnanceur
de Linux SMP n'essaie pas de maintenir chaque processus sur
le même processeur, concept connu sous le nom d'<span class="emphasis"><em>affinité processeur</em></span>.
Cela pourrait bientôt changer. Un débat a récemment eu lieu sur ce sujet dans la
communauté des développeurs Linux SMP, sous le titre <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">processor
bindings</em></span></span> »</span> (<span class="quote">« <span class="quote">associations de processeurs</span> »</span>). Sans affinité processeur,
des caches L2 séparés peuvent introduire des délais non négligeables
lorsqu'un processus se voit allouer une tranche de temps d'exécution
sur un processeur qui n'est pas le même que celui sur lequel il
s'exécutait juste avant.
</p><p>
Plusieurs systèmes relativement bon marché sont organisés de manière
à ce que deux processeurs Pentium puissent partager la même mémoire
cache L2. La mauvaise nouvelle, c'est que cela crée des conflits à
l'utilisation de ce cache, qui dégradent sérieusement les performances
lorsque plusieurs programmes séquentiels indépendants s'exécutent
simultanément. La bonne nouvelle, c'est que bon nombre de programmes
parallèles pourraient tirer profit de la mémoire cache partagée, car
si les deux processeurs veulent accéder à la même ligne de mémoire
partagée, seul un processeur doit aller la rapatrier dans le cache,
et l'on évite des conflits de bus. Le manque d'affinité processeur
peut aussi s'avérer moins désastreux avec un cache L2 partagé. Ainsi,
pour les programmes parallèles, il n'est pas vraiment certain que
partager la mémoire cache L2 soit si préjudiciable que l'on pourrait
le penser.
</p><p>
À l'usage, notre bi-Pentium à mémoire cache partagée
de 256Ko présente une vaste échelle de performances, dépendantes du
niveau d'activité noyau requis. Au pire, le gain en vitesse
n'atteint qu'un facteur de 1,2. En revanche, nous avons aussi
constaté une accélération de 2,1 fois la vitesse d'origine, ce qui
suggère que les calculs intensifs à base de SPMD tirent vraiment
profit de l'effet d'<span class="quote">« <span class="quote">acquisition partagée</span> »</span> (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">shared fetch</em></span></span> »</span>).
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e797"/>2.1.2. Configuration du bus ?</h4></div></div></div><p>
La première chose à dire est que la plupart des systèmes modernes
relient le processeur à un ou plusieurs bus PCI qui à leur tour
sont <span class="quote">« <span class="quote">pontés</span> »</span> vers un ou plusieurs bus ISA ou EISA. Ces ponts
engendrent des temps de latence, et l'ISA comme l'EISA offrent
généralement des bandes passantes plus réduites que le PCI
(ISA étant le plus lent). C'est pourquoi les disques, cartes vidéos et
autres périphériques de haute performance devraient en principe
être connectés sur un bus PCI.
</p><p>
Bien qu'un système MPS puisse apporter un gain en vitesse honorable
à plusieurs programmes parallèles de calcul intensif même avec un
seul bus PCI, les opérations d'entrées/sorties, elles, ne sont pas
meilleures que sur un système monoprocesseur. Elles sont peut-être même
un peu moins bonnes à cause des conflits de bus entre les processeurs.
Ainsi, si votre objectif est d'accélérer les entrées/sorties, prenez
soin de choisir un système MPS comportant plusieurs bus PCI indépendants
et plusieurs contrôleurs d'entrées/sorties (par exemple : plusieurs
chaînes SCSI). Il vous faudra être prudent, et sûr que Linux
reconnaît tout votre matériel. Gardez aussi à l'esprit le fait que
Linux n'autorise qu'un seul processeur à la fois à entrer en mode
noyau, aussi devrez-vous choisir des contrôleurs qui réduisent au
minimum le temps noyau nécessaire à leurs opérations. Pour atteindre
des performances vraiment très élevées, il se pourrait même qu'il
vous faille envisager d'effectuer vous-même les opérations d'entrée/sortie
de bas niveau directement depuis les processus utilisateurs,
sans appel système… ce n'est pas forcément aussi difficile que
cela en a l'air, et cela permet d'éviter de compromettre la sécurité du
système (voir la section 3.3 pour une description des techniques de
base).
</p><p>
Il est important de remarquer que la relation entre vitesse du bus
et vitesse du processeur est devenue très floue ces dernières années.
Bien que la plupart des systèmes utilisent maintenant la même fréquence
de bus PCI, il n'est pas rare de trouver un processeur rapide apparié
avec un bus lent. L'exemple classique est celui du Pentium 133 qui
utilise en général un bus plus rapide que celui du Pentium 150, produisant
des résultats étranges sur les logiciels bancs de tests (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">benchmarks</em></span></span> »</span>).
Ces effets sont amplifiés sur les systèmes SMP, où il est encore plus
important d'utiliser un bus rapide.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e813"/>2.1.3. Interfoliage de la mémoire et technologie DRAM</h4></div></div></div><p>
L'interfoliage de la mémoire n'a en fait absolument rien à voir
avec le MPS, mais vous verrez souvent cette mention accompagner
les systèmes MPS car ceux-ci sont typiquement gourmands en
bande passante mémoire. Concrètement, l'interfoliage en deux ou
en quatre voies organise la RAM de façon à ce que l'accès à un
bloc de mémoire se fasse au travers de plusieurs bancs de RAM
plutôt qu'un seul. Ceci accélère grandement les accès à la
mémoire, particulièrement en ce qui concerne le chargement et
l'enregistrement du contenu des lignes de cache.
</p><p>
Il faut toutefois souligner que ce fait n'est pas aussi évident
qu'il y parait, car la DRAM EDO et les différentes technologies
mémoire tendent à optimiser ce genre d'opérations. Un excellent
aperçu des différentes technologies DRAM est disponible sur
<a class="ulink" href="http://www.pcguide.com/ref/ram/tech.htm" target="_top">http://www.pcguide.com/ref/ram/tech.htm</a>.
</p><p>
Ainsi, par exemple, mieux vaut-il avoir de la mémoire DRAM EDO
interfoliée à 2 voies, ou de la mémoire SDRAM non interfoliée ?
C'est une très bonne question et la réponse n'est pas simple,
car la mémoire interfoliée comme les technologies DRAM exotiques
ont tendance à être coûteuses. Le même investissement en mémoire
plus ordinaire vous apporte en général une mémoire centrale bien
plus vaste. Même la plus lente des mémoire DRAM reste autrement
plus rapide que la mémoire virtuelle par fichier d'échange…
</p></div></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e825"/>2.2. Introduction à la programmation en mémoire partagée</h3></div></div></div><p>
<span class="foreignphrase"><em class="foreignphrase">Okay</em></span>, donc vous avez décidé que le traitement 
en parallèle sur SMP, c'est génial… Par quoi allez-vous commencer ? Eh bien,
la première étape consiste à en apprendre un peu plus sur le fonctionnement réel
de la communication par mémoire partagée.
</p><p>
A première vue, il suffit qu'un processeur range une valeur en mémoire
et qu'un autre la lise. Malheureusement, ce n'est pas aussi simple.
Par exemple, les relations entre processus et processeurs sont très
floues. En revanche, si nous n'avons pas plus de processus actifs que
de processeurs, les termes sont à peu près interchangeables. Le reste
de cette section résume brièvement les cas de figure typiques qui
peuvent poser de sérieux problèmes, si vous ne les connaissiez pas
déjà : les deux différents modèles utilisés pour déterminer ce qui
est partagé, les problèmes d'atomicité, le concept de volatilité,
les instructions de verrouillage matériel, les effets de la ligne
de cache, et les problèmes posés par l'ordonnanceur de
Linux.
</p><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e835"/>2.2.1. Partage Intégral contre Partage Partiel</h4></div></div></div><p>
Il existe deux modèles fondamentaux couramment utilisés en programmation
en mémoire partagée : le <span class="emphasis"><em>partage intégral</em></span>
et le <span class="emphasis"><em>partage partiel</em></span>. Ces modèles
permettent tous deux aux processeurs de communiquer en chargeant et
rangeant des données depuis et dans la mémoire. La différence réside
dans le fait que le partage intégral place toutes les structures en
mémoire partagée, quand le partage partiel, lui, distingue les structures
qui sont potentiellement partageables et celles qui sont
<span class="emphasis"><em>privées</em></span>, propres à un seul processeur
(et oblige l'utilisateur à classer explicitement ses structures dans l'une
de ces catégories).
</p><p>
Alors quel modèle de partage mémoire faut-il utiliser ? C'est surtout
une affaire de chapelle. Beaucoup de gens aiment le partage intégral
car ils n'ont pas spécialement besoin d'identifier les structures qui
doivent être partagées au moment de leur déclaration. On place simplement
des verrous sur les objets auxquels l'accès peut créer des conflits, pour
s'assurer qu'un seul processeur (ou processus) y accède à un moment donné.
Mais là encore, ce n'est pas aussi simple… aussi beaucoup d'autres
gens préfèrent, eux, le modèle relativement sûr du partage partiel.
</p><div class="sect4"><div class="titlepage"><div><div><h5 class="title"><a id="d0e851"/>2.2.1.1. Partage intégral</h5></div></div></div><p>
Le bon coté du partage intégral est que l'on peut aisément reprendre
un programme séquentiel existant et le convertir progressivement en
programme parallèle en partage intégral. Vous n'avez pas à déterminer
au préalable les données qui doivent être accessibles aux autres
processeurs.
</p><p>
Posé simplement, le principal problème avec le partage intégral vient
du fait qu'une action effectuée par un processeur peut affecter les
autres processeurs. Ce problème ressurgit de deux manières :
</p><p>

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
Plusieurs bibliothèques utilisent des structures de données qui
ne sont tout simplement pas partageables. Par exemple, la convention
UNIX stipule que la plupart des fonctions peuvent renvoyer un code
d'erreur dans une variable appelée <code class="literal">errno</code>.
Si deux processus en partage intégral font des appels divers, ils vont
interférer l'un sur l'autre car ils partagent la même variable
<code class="literal">errno</code>. Bien qu'il existe désormais une
bibliothèque qui règle le problème de cette variable, ce problème se présente toujours
dans la plupart des bibliothèques comme par exemple X-Window qui, à moins de prendre
des précautions très spéciales, ne fonctionnera pas si différents appels sont
passés depuis différents processus en partage intégral.
</p></li><li class="listitem"><p>
En temps normal, un programme qui utilise un pointeur ou un index
défaillant provoque au pire l'arrêt du processus qui contient le code corrompu.
Il peut même générer un fichier <code class="literal">core</code> vous renseignant sur les conditions
dans lesquelles se sont déroulés les événements. En programmation parallèle
à partage intégral, il est fort probable que les accès illégaux provoquent
la <span class="emphasis"><em>fin d'un processus qui n'est pas le fautif</em></span>, rendant
la localisation et la correction de l'erreur quasiment impossibles.
</p></li></ul></div><p>

</p><p>
Aucun de ces deux problèmes n'est courant dans le cas du partage
partiel, car seules sont partagées les structures explicitement marquées
comme telles. De plus, il est trivial que le partage intégral ne peut
fonctionner que si les processeurs exécutent exactement la même image
en mémoire. On ne peut pas utiliser le partage intégral entre des images
de code différentes (c'est-à-dire que vous pourrez travailler en SPMD,
mais pas d'une manière générale en MIMD).
</p><p>

Les supports de programmation en partage intégral existent le plus 
couramment sous la forme de <span class="emphasis"><em>bibliothèques de 
<span class="foreignphrase"><em class="foreignphrase">threads</em></span></em></span>. Les <a class="ulink" href="http://liinwww.ira.uka.de/bibliography/Os/threads.html" target="_top"><span class="foreignphrase"><em class="foreignphrase">threads</em></span></a> 
sont essentiellement des processus <span class="quote">« <span class="quote">allégés</span> »</span> dont 
l'exécution peut ne pas être planifiée comme celle des processus UNIX 
normaux et qui, c'est le plus important, partagent tous la même page 
mémoire. L'adaptation des <a class="ulink" href="http://www.mit.edu:8001/people/proven/IAP_2000/index.html" target="_top">Pthreads</a> 
POSIX a fait l'objet de nombreux efforts. La grande question est : 
ces adaptations parallélisent-elles les 
<span class="foreignphrase"><em class="foreignphrase">threads</em></span> d'un programme en environnement 
Linux SMP (idéalement, en attribuant un processeur à chaque 
<span class="foreignphrase"><em class="foreignphrase">thread</em></span>) ?. L'API POSIX ne l'impose 
pas, et certaines versions comme <span class="emphasis"><em>PCthreads</em></span> semblent 
ne pas implémenter une exécution en parallèle des 
<span class="foreignphrase"><em class="foreignphrase">threads</em></span> : tous les 
<span class="foreignphrase"><em class="foreignphrase">threads</em></span> d'un programme sont conservés à 
l'intérieur d'un seul processus Linux.

</p><p>
La première bibliothèque de <span class="foreignphrase"><em class="foreignphrase">threads</em></span> à avoir pris en charge le parallélisme
sous Linux SMP fut la désormais quelque peu obsolète bibliothèque
<span class="emphasis"><em>bb_thread</em></span>, une toute petite bibliothèque qui utilisait l'appel Linux
<code class="literal">clone()</code> pour donner naissance à de nouveaux
processus Linux, planifiés indépendamment les uns des autres, tous partageant
un même espace d'adressage. Les machines Linux SMP peuvent lancer plusieurs
de ces <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">threads</em></span></span> »</span> car chaque <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">thread</em></span></span> »</span> est un processus Linux à part entière.
L'inconvénient, c'est que l'on ne peut obtenir l'ordonnancement <span class="quote">« <span class="quote">poids-plume</span> »</span>
apportée par les bibliothèques de <span class="foreignphrase"><em class="foreignphrase">threads</em></span> d'autres systèmes
d'exploitation. La bibliothèque utilisait un peu de code assembleur intégré
dans un code source en langage C pour mettre en place un bloc de mémoire pour la
pile de chaque <span class="foreignphrase"><em class="foreignphrase">thread</em></span> et fournir des fonctions d'accès atomiques à un tableau
de verrous (les <span class="emphasis"><em>mutex</em></span>). Sa documentation se résumait à un fichier
<code class="literal">LISEZMOI</code> et à un court programme d'exemple.
</p><p>
Plus récemment, une version de <span class="foreignphrase"><em class="foreignphrase">threads</em></span> POSIX utilisant <code class="literal">clone()</code>
a été développée. Cette bibliothèque,
<a class="ulink" href="http://pauillac.inria.fr/~xleroy/linuxthreads/" target="_top">LinuxThreads</a>,
est clairement la bibliothèque en partage intégral favorite pour l'utilisation
sous Linux SMP. Les <span class="foreignphrase"><em class="foreignphrase">threads</em></span> POSIX sont bien documentés, et les documents
<a class="ulink" href="http://pauillac.inria.fr/~xleroy/linuxthreads/README" target="_top">LinuxThreads README</a>
et <a class="ulink" href="http://pauillac.inria.fr/~xleroy/linuxthreads/faq.html" target="_top">LinuxThreads FAQ</a>
sont vraiment très bien réalisés. A présent, le principal problème est
que les <span class="foreignphrase"><em class="foreignphrase">threads</em></span> POSIX ont encore beaucoup de détails à régler, et que
LinuxThread est toujours un projet en cours d'évolution. D'autre part,
les <span class="foreignphrase"><em class="foreignphrase">threads</em></span> POSIX ont évolué pendant dans leur phase de standardisation,
aussi devrez-vous être prudent pour ne pas développer en suivant une version obsolète du standard.
</p></div><div class="sect4"><div class="titlepage"><div><div><h5 class="title"><a id="d0e974"/>2.2.1.2. Partage Partiel</h5></div></div></div><p>

Le Partage Partiel consiste réellement à <span class="quote">« <span class="quote">ne partager que ce qui 
doit être partagé</span> »</span>. Cette approche est valable pour le MIMD en 
général (et pas simplement le SPMD) à condition de prendre soin 
d'allouer les objets partagés aux mêmes endroits dans le plan mémoire de 
chaque processeur. Plus important encore, le partage partiel facilite 
l'estimation et l'ajustage des performances, le débogage des sources, et 
cætera. Les seuls problèmes sont :

</p><p>

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
Déterminer à l'avance ce qui doit être partagé peut s'avérer difficile.
</p></li><li class="listitem"><p>
L'allocation d'objets dans la mémoire partagée peut en fait se révéler
malaisé, spécialement en ce qui concerne tout ce qui aurait du être déclaré
dans la pile. Par exemple, il peut être nécessaire d'allouer explicitement
des objets partagés dans des segments de mémoire séparés, nécessitant des
routines d'allocation mémoire séparées, et impliquant l'ajout de pointeurs
et d'indirections supplémentaires à chaque référence.
</p></li></ul></div><p>

</p><p>

Actuellement, il existe deux mécanismes similaires permettant aux 
groupes de processus sous Linux de posséder des espaces mémoire 
indépendants, mais de tous partager un unique et relativement étroit 
segment de mémoire. En supposant que vous n'ayez pas bêtement exclu 
l'option <span class="quote">« <span class="quote">System V IPC</span> »</span> lorsque que vous avez configuré 
votre système Linux (N.D.T. : ici à la recompilation du noyau), Linux 
gère un mécanisme très portable devenu célèbre sous le nom de 
<span class="quote">« <span class="quote">mémoire partagée System V</span> »</span>. L'autre alternative est une 
fonction de projection en mémoire dont l'implémentation varie grandement 
selon le système UNIX utilisé : L'appel système 
<code class="literal">mmap</code>. Vous pouvez — et devriez — 
apprendre le fonctionnement de ces primitives au travers des pages du 
manuel (<span class="foreignphrase"><em class="foreignphrase">man pages</em></span>)… mais vous 
trouverez quand même un rapide aperçu de chacune d'elles dans les 
sections 2.5 et 2.6 pour vous aider à démarrer.

</p></div></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e1006"/>2.2.2. Atomicité et ordonnancement</h4></div></div></div><p>
Que vous utilisiez l'un ou l'autre des modèles cités ci-dessus, le
résultat est à peu près le même : vous obtenez un pointeur sur un bloc de
mémoire en lecture/écriture accessible par tous les processus de votre
programme en parallèle. Cela signifie-t-il que je peux laisser mes
programmes accéder aux objets partagés comme s'ils se trouvaient en
mémoire locale ordinaire ? Pas tout à fait…
</p><p>
L'<span class="emphasis"><em>atomicité</em></span> désigne une opération sur
un objet effectuée en une séquence indivisible et ininterruptible.
Malheureusement, les accès à la mémoire partagée n'impliquent pas que
les toutes les opérations sur les données de cette mémoire se fassent
de manière atomique. A moins de prendre des précautions spéciales, seules les
opérations de lecture ou d'écriture s'accomplissant en une seule transaction
sur le bus (c'est-à-dire alignées sur une adresse multiple de 8, 16 ou 32
bits, à l'exclusion des opérations 64 bits ou mal alignées) sont atomiques. Pire encore,
les compilateurs <span class="quote">« <span class="quote">intelligents</span> »</span> comme GCC font souvent des optimisations qui
peuvent éliminer les opérations mémoire nécessaires pour s'assurer que les autres processeurs
puissent voir ce que le processeur concerné a fait. Heureusement, ces problèmes ont tous
deux une solution… en acceptant seulement de ne pas se soucier de la
relation entre l'efficacité des accès mémoire et la taille de la ligne de
cache.
</p><p>
En revanche, avant de traiter de ces différents cas de figure, il est
utile de préciser que tout ceci part du principe que les références à
la mémoire pour chaque processeur se produisent dans l'ordre où elles
ont été programmées. Le Pentium fonctionne de cette manière, mais les
futurs processeurs d'Intel pourraient ne pas le faire. Aussi, quand
vous développerez sur les processeurs à venir, gardez à l'esprit qu'il
pourrait être nécessaire d'encadrer les accès à la mémoire avec des
instructions provoquant l'achèvement de toutes les accès à la mémoire
en suspens, provoquant ainsi leur mise en ordre.
L'instruction <code class="literal">CPUID</code> semble provoquer
cet effet.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e1024"/>2.2.3. Volatilité</h4></div></div></div><p>
Pour éviter que l'optimiseur du GCC ne conserve les valeurs de la
mémoire partagée dans les registres de processeur, tous les objets
en mémoire partagée doivent être déclarés avec l'attribut
<code class="literal">volatile</code>. Tous les accès en lecture ou écriture
ne nécessitant l'accès qu'à un seul mot se feront alors de manière
atomique. Par exemple, en supposant que <span class="emphasis"><em>p</em></span> est un pointeur
sur un entier, et que ce pointeur comme l'entier qu'il pointe se trouvent en
mémoire partagée, la déclaration en C ANSI ressemblera à :
</p><p>

</p><pre class="programlisting">
volatile int * volatile p;
</pre><p>

</p><p>

Dans ce code, le premier <code class="literal">volatile</code> concerne 
l'<code class="literal">int</code> que <code class="literal">p</code> pointe 
éventuellement, quand le second <code class="literal">volatile</code> s'applique 
au pointeur lui-même. Oui, c'est ennuyeux, mais c'est le prix à payer 
pour que GCC puisse faire des optimisations vraiment puissantes. En 
théorie, l'option <code class="literal">-traditional</code> devrait suffire à 
produire du code correct au prix de quelques optimisations, car le 
standard C K&amp;R (N.D.T. : Kernigan &amp; Ritchie) pré norme ANSI 
établit que toutes les variables sont volatiles si elles ne sont pas 
explicitement déclarées comme <code class="literal">register</code>. Ceci étant 
dit, si vos compilations GCC ressemblent à <code class="literal">cc -O6 
…</code>, vous n'aurez réellement besoin de déclarer les 
choses comme étant volatiles qu'aux endroits où c'est nécessaire.

</p><p>
Un rumeur a circulé à propos du fait que les verrous écrits en assembleur
signalés comme modifiant tous les registres du processeur provoquaient de
la part du compilateur GCC l'enregistrement adéquat de toutes les variables en
suspens, évitant ainsi le code compilé <span class="quote">« <span class="quote">inutile</span> »</span> associé aux objets déclarés
<code class="literal">volatile</code>. Cette astuce semble fonctionner pour
les variables globales statiques avec la version 2.7.0 de GCC… En revanche,
ce comportement n'est <span class="emphasis"><em>pas</em></span> une recommandation du standard
C ANSI. Pire encore, d'autres processus n'effectuant que des accès en lecture
pourraient conserver éternellement les valeurs dans des registres, et ainsi
ne <span class="emphasis"><em>jamais</em></span> s'apercevoir que la vraie valeur stockée en
mémoire partagée a en fait changé. En résumé, développez comme vous l'entendez,
mais seules les variables déclarées <code class="literal">volatile</code>
offrent un fonctionnement normal <span class="emphasis"><em>garanti</em></span>.
</p><p>
Notez qu'il est possible de provoquer un accès volatile à une variable
ordinaire en utilisant un transtypage (<span class="quote">« <span class="quote"><span class="emphasis"><em>casting</em></span></span> »</span>) imposant l'attribut
<code class="literal">volatile</code>. Par exemple, un
<code class="literal">int i;</code> ordinaire peut être référencé en tant
que volatile par <code class="literal">*((volatile int *) &amp;i);</code> .
Ainsi, vous pouvez forcer la volatilité et les coûts supplémentaires qu'elle engendre
seulement aux endroits où elle est critique.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e1098"/>2.2.4. Verrous (<span class="foreignphrase"><em class="foreignphrase">Locks</em></span>)</h4></div></div></div><p>

Si vous pensiez que <code class="literal">++i;</code> aurait toujours incrémenté 
une variable <code class="literal">i</code> sans problème, vous allez avoir une 
mauvaise surprise : même codées en une seule instruction, le 
chargement et l'enregistrement du résultat sont deux transactions 
mémoire séparées, et d'autres processeurs peuvent accéder à 
<code class="literal">i</code> entre ces deux transactions. Par exemple, deux 
processus effectuant chacun l'instruction <code class="literal">++i;</code> 
pourraient n'incrémenter la variable <code class="literal">i</code> que d'une 
unité et non deux. Selon le <span class="quote">« <span class="quote">Manuel de l'Architecture et de la 
Programmation</span> »</span> du Pentium d'Intel, le préfixe 
<code class="literal">LOCK</code> peut être employé pour s'assurer que chacune des 
instructions suivantes soit atomique par rapport à l'adresse mémoire à 
laquelle elles accèdent :

</p><p>

</p><pre class="programlisting">
BTS, BTR, BTC                     mem, reg/imm
XCHG                              reg, mem
XCHG                              mem, reg
ADD, OR, ADC, SBB, AND, SUB, XOR  mem, reg/imm
NOT, NEG, INC, DEC                mem
CMPXCHG, XADD
</pre><p>

</p><p>
En revanche, il n'est pas conseillé d'utiliser toutes ces opérations.
Par exemple, <code class="literal">XADD</code> n'existait même pas sur 386,
aussi l'employer en programmation peut poser des problèmes de portabilité.
</p><p>

L'instruction <code class="literal">XCHG</code> engendre <span class="emphasis"><em>toujours</em></span>
un verrou, même sans le préfixe <code class="literal">LOCK</code>, et est ainsi
et indiscutablement l'opération atomique favorite pour construire d'autres opérations
atomiques de plus haut niveau comme les sémaphores et les files d'attente partagées.
Bien sûr, on ne peut pas demander à GCC de générer cette instruction en écrivant
simplement du code C. Il vous faudra à la place écrire un peu de code assembleur en
ligne<a href="#ftn.d0e1148" class="footnote" id="d0e1148"><sup class="footnote">[5]</sup></a>. En prenant un objet volatile 
<span class="emphasis"><em>obj</em></span> et un registre du processeur 
<span class="emphasis"><em>reg</em></span>, tous deux de type <code class="literal">word</code> 
(longs de 16 bits), le code assembleur GCC sera :

</p><pre class="programlisting">
__asm__ __volatile__ ("xchgl %1,%0"
                      :"=r" (reg), "=m" (obj)
                      :"r" (reg), "m" (obj));
</pre><p>

Quelques exemples de programmes assembleur en ligne utilisant des 
opérations bit-à-bit pour réaliser des verrous sont disponibles dans le 
code source de la bibliothèque bb_threads.

</p><p>

Il est toutefois important de se souvenir que faire des transactions 
mémoire atomiques a un coût. Une opération de verrouillage engendre des 
délais supplémentaires assez importants et peut retarder l'activité 
mémoire d'autres processeurs, quand des références ordinaires auraient 
utilisé le cache local. Les meilleures performances s'obtiennent en 
utilisant les opérations atomiques aussi <span class="emphasis"><em>peu</em></span> 
souvent que possible. De plus, ces instructions atomiques IA32 ne sont 
évidement pas portables vers d'autres systèmes.

</p><p>

Il existe plusieurs alternatives permettant aux instructions ordinaires 
d'être utilisées pour mettre en œuvre différents types de 
synchronisation, y compris l'<span class="emphasis"><em>exclusion mutuelle</em></span>, 
qui garantit qu'au plus un seul processeur met à jour un objet partagé 
donné à un moment précis. La plupart des manuels des différents systèmes 
d'exploitation traitent d'au moins une de ces techniques. On trouve un 
très bon exposé sur le sujet dans la quatrième édition des 
<span class="foreignphrase"><em class="foreignphrase">Operating System Concepts</em></span> (Principes des 
Systèmes d'Exploitation), par Abraham Silberschatz et Peter B. Galvin, 
ISBN 0-201-50480-4.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e1178"/>2.2.5. Taille de la ligne de cache</h4></div></div></div><p>

Encore une chose fondamentale concernant l'atomicité et qui peut avoir 
des conséquence dramatiques sur les performances d'un SMP : la 
taille de la ligne de cache. Même si le standard MPS impose que les 
références soient cohérentes quelque soit le cache utilisé, il n'en 
reste pas moins que lorsque qu'un processeur écrit sur une ligne 
particulière de la mémoire, chaque copie en cache de l'ancienne ligne 
doit être invalidée ou mise à jour. Ceci implique que si au moins deux 
processeurs écrivent chacun sur des portions différentes de la ligne de 
cache, cela peut provoquer un trafic important sur le bus et le cache, 
pour au final transférer la ligne depuis le cache vers le cache. Ce 
problème est connu sous le nom de <span class="emphasis"><em>faux partage</em></span> 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">false sharing</em></span></span> »</span>). La 
solution consiste uniquement à <span class="emphasis"><em>organiser les données de telle 
manière que ce que les objets auxquels on accède en parallèle 
proviennent globalement de différentes lignes de cache pour chaque 
processus</em></span>.

</p><p>

Vous pourriez penser que le faux partage n'est pas un problème quand on 
utilise un cache de niveau 2 partagé, mais souvenez-vous qu'il existe 
toujours des caches de niveau 1 séparés. L'organisation du cache et le 
nombre de niveaux séparés peut varier, mais la ligne de cache de premier 
niveau d'un Pentium est longue de 32 octets, et le cache externe typique 
tourne autour de 256 octets. Supposons que les adresses (physiques ou 
logiques) de deux objets soient <span class="emphasis"><em>a</em></span> et 
<span class="emphasis"><em>b</em></span>, et que la taille de la ligne de cache soit 
<span class="emphasis"><em>c</em></span>, que nous admettrons être une puissance de 2. 
Pour être très précis, si

<code class="literal">((int) a) &amp; ˜(c-1)</code> est égal à 
<code class="literal">((int) b) &amp; ˜(c-1)</code>,

alors les deux références se trouvent dans la même ligne de cache. Une 
règle plus simple consiste à dire que si deux objets référencés en 
parallèle sont éloignés d'au moins <span class="emphasis"><em>c</em></span> octets, ils 
devraient se trouver dans des lignes de cache différentes.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e1213"/>2.2.6. Les problèmes de l'ordonnanceur de Linux</h4></div></div></div><p>

Bien que tout l'intérêt d'utiliser de la mémoire partagée pour les 
traitements en parallèle consiste à éviter les délais dus au système 
d'exploitation, ces délais peuvent parfois provenir d'autres choses que 
les communications en elles-mêmes. Nous avons déjà remarqué que le 
nombre de processus que l'on devrait créer doit être inférieur ou égal 
au nombre de processeurs de la machine. Mais comment décide-t-on 
exactement du nombre de processus à créer ?

</p><p>

Pour obtenir les meilleures performances, <span class="emphasis"><em>le nombre de 
processus de votre programme en parallèle doit être égal au nombre de 
processus qui peuvent être exécutés simultanément, chacun sur son 
processeur</em></span>. Par exemple, si un système SMP à quatre 
processeurs héberge un processus très actif pour un autre usage (par 
exemple un serveur <span class="foreignphrase"><em class="foreignphrase">web</em></span>), alors votre 
programme en parallèle ne devra utiliser que trois processus. Vous 
pouvez vous faire une idée générale du nombre de processus actifs 
exécutés sur votre système en consultant la <span class="quote">« <span class="quote">charge 
système moyenne</span> »</span> (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">load 
average</em></span></span> »</span>) mise en évidence par la commande 
<code class="literal">uptime</code>.

</p><p>

Vous pouvez en outre <span class="quote">« <span class="quote">pousser</span> »</span> la priorité de vos processus 
de votre programme parallèle en utilisant, par exemple, la commande 
<code class="literal">renice</code> ou l'appel système <code class="literal">nice()</code>. 
Vous devez être privilégié<a href="#ftn.d0e1247" class="footnote" id="d0e1247"><sup class="footnote">[6]</sup></a> pour augmenter la priorité d'un processus. L'idée 
consiste simplement à éjecter les autres programmes des autres 
processeurs pour que votre programme puisse être exécuté sur tous les 
processeurs simultanément. Ceci peut être effectué de manière un peu 
plus explicite en utilisant la version prototype de Linux SMP disponible 
sur <a class="ulink" href="http://www.fsmlabs.com/products/openrtlinux/" target="_top">http://www.fsmlabs.com/products/openrtlinux/</a> et qui 
propose un ordonnanceur en temps réel (N.D.T. : il existe désormais un 
guide consacré à RTLinux, accessible en ligne : <a class="ulink" href="http://www.traduc.org/docs/howto/lecture/RTLinux-HOWTO.html" target="_top">RTLinux 
HOWTO</a>).

</p><p>

Si vous n'êtes pas le seul utilisateur employant votre système SMP comme 
une machine en parallèle, il se peut que vous entriez en conflit avec 
les autres programmes en parallèle essayant de s'exécuter simultanément. 
La solution standard est l'<span class="emphasis"><em>ordonnancement de groupe</em></span> 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">gang scheduling</em></span></span> »</span>), 
c'est-à-dire la manipulation de la priorité d'ordonnancement de façon à 
ce que seuls les processus d'un seul programme en parallèle s'exécutent 
à un moment donné. Il est bon de rappeler, en revanche, que multiplier 
les parallélismes tend à réduire les retours et que l'activité de 
l'ordonnanceur introduit des délais supplémentaires. Ainsi, par exemple, 
il sera sûrement préférable, pour une machine à quatre processeurs, 
d'exécuter deux programmes contenant chacun deux processus, plutôt que 
d'ordonnancer en groupe deux programmes de quatre processus chacun.

</p><p>

Il y a encore une chose dont il faut tenir compte. Supposons que vous 
développiez un programme sur une machine très sollicitée le jour, mais 
disponible à cent pour cent pendant la nuit pour le traitement en 
parallèle. Il vous faudra écrire et tester votre code dans les 
conditions réelles, donc avec tous ses processus lancés, même en sachant 
que des tests de jour risquent d'être lents. Ils seront en fait 
<span class="emphasis"><em>très</em></span> lents si certains de vos processus sont en 
état d'<span class="emphasis"><em>attente active</em></span> (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">busy 
waiting</em></span></span> »</span>)<a href="#ftn.d0e1280" class="footnote" id="d0e1280"><sup class="footnote">[7]</sup></a>, guettant le changement de certaines valeurs en 
mémoire partagée, changement censé être provoqué par d'autres processus 
qui ne sont pas exécutés (sur d'autres processeurs) au même moment. Ce 
même problème apparaît lorsque l'on développe et que l'on teste un 
programme sur un système monoprocesseur.

</p><p>

La solution consiste à intégrer des appels système à votre code là où il 
peut se mettre en boucle en attendant une action d'un autre processeur, 
pour que Linux puisse donner une chance de s'exécuter à un autre 
processus. J'utilise pour cela une macro en langage C, appelons-la 
<code class="literal">IDLE_ME</code> (N.D.T. : 
<code class="literal">MetsMoiEnAttente</code>) : pour faire un simple test, 
compilez votre programme par

<span class="quote">« <span class="quote"><code class="literal">cc -DIDLE_ME=usleep(1);…</code></span> »</span>.

Pour produire un exécutable définitif, utilisez

<span class="quote">« <span class="quote"><code class="literal">cc -DIDLE_ME={}…</code></span> »</span>.

L'appel <code class="literal">usleep(1)</code> réclame une pause d'une 
microseconde, qui a pour effet de permettre à l'ordonnanceur de Linux de 
choisir un nouveau processus à exécuter sur ce processeur. Si le nombre 
de processus dépasse le nombre de processeurs disponibles, il n'est pas 
rare de voir des programmes s'exécuter dix fois plus rapidement avec 
<code class="literal">usleep(1)</code> que sans.

</p></div></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e1306"/>2.3. bb_threads</h3></div></div></div><p>

La bibliothèque bb_threads (<span class="foreignphrase"><em class="foreignphrase">"Bare Bones" 
threads</em></span>) est une bibliothèque remarquablement simple qui 
fait la démonstration de l'utilisation de l'appel système Linux 
<code class="literal">clone()</code>. Le fichier <code class="literal">tar.gz</code> 
n'occupe que 7 ko ! Bien que cette bibliothèque ait été rendue 
pour l'essentiel obsolète par la bibliothèque LinuxThreads, traitée dans 
la section 2.4, bb_threads reste utilisable, et est suffisamment simple 
et peu encombrante pour former une bonne introduction à la gestion des 
<span class="foreignphrase"><em class="foreignphrase">threads</em></span> sous Linux. Il est beaucoup moins 
effrayant de se lancer dans la lecture de ce code source que dans celui 
de LinuxThreads. En résumé, la bibliothèque bb_threads forme un bon 
point de départ, mais n'est pas vraiment adaptée à la réalisation de 
grands projets.

</p><p>

La structure de base des programmes utilisant la bibliothèque bb_threads 
est la suivante :

</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>

Lancez le programme en tant que processus unique.

</p></li><li class="listitem"><p>

Il vous faudra estimer l'espace maximum dans la pile qui sera nécessaire 
à chaque <span class="foreignphrase"><em class="foreignphrase">thread</em></span>. Prévoir large est 
relativement sage (c'est à çà que sert la mémoire virtuelle ;-), mais 
souvenez-vous que <span class="emphasis"><em>toutes</em></span> les piles proviennent d'un 
seul espace d'adressage virtuel, aussi voir trop grand n'est pas une 
idée formidable. La démo suggère 64Ko. Cette taille est fixée à 
<span class="emphasis"><em>b</em></span> octets par 
<code class="literal">bb_threads_stacksize(b)</code>.

</p></li><li class="listitem"><p>

L'étape suivante consiste à initialiser tous les verrous dont vous aurez 
besoin. Le mécanisme de verrouillage intégré à cette bibliothèque 
numérote les verrous de 0 à <code class="literal">MAX_MUTEXES</code>, et 
initialise un verrou <span class="emphasis"><em>i</em></span> par 
<code class="literal">bb_threads_mutexcreate(i)</code>.

</p></li><li class="listitem"><p>

La création d'un nouveau <span class="foreignphrase"><em class="foreignphrase">thread</em></span> 
s'effectue en appelant une routine de la bibliothèque recevant en 
arguments la fonction que le nouveau 
<span class="foreignphrase"><em class="foreignphrase">thread</em></span> doit exécuter, et les arguments 
qui doivent lui être transmis. Pour démarrer un nouveau 
<span class="foreignphrase"><em class="foreignphrase">thread</em></span> exécutant la fonction 
<span class="emphasis"><em>f</em></span> de type <code class="literal">void</code> et attendant un 
argument <span class="emphasis"><em>arg</em></span>, l'appel ressemblera à 
<code class="literal">bb_threads_newthread (f, &amp;arg)</code>, où 
<span class="emphasis"><em>f</em></span> devra être déclaré comme suit :

</p><pre class="programlisting">
void f (void *arg, size_t dummy)
</pre><p>

Si vous avez besoin de passer plus d'un argument à votre fonction, 
utilisez un pointeur sur une structure contenant les valeurs à 
transmettre.

</p></li><li class="listitem"><p>

Lancement du code en parallèle, en prenant soin d'utiliser 
<code class="literal">bb_threads_lock(n)</code> et 
<code class="literal">bb_threads_unlock(n)</code><span class="emphasis"><em>n</em></span> est un 
entier indiquant le verrou à utiliser. Notez que les opérations de 
verrouillage et déverrouillage sont des opérations de blocage<a href="#ftn.d0e1399" class="footnote" id="d0e1399"><sup class="footnote">[8]</sup></a> très primaires et utilisant des instructions 
atomiques de verrouillage du bus, lesquelles peuvent causer des 
interférences d'accès à la mémoire, et qui n'essaient en aucun cas 
d'agir <span class="quote">« <span class="quote">proprement</span> »</span>.

Le programme de démonstration fourni avec bb_threads n'utilisait pas 
correctement les verrous pour empêcher <code class="literal">printf()</code> 
d'être exécuté depuis les fonctions <code class="literal">fnn</code> et 
<code class="literal">main</code>, et à cause de cela, la démo ne fonctionne pas 
toujours. Je ne dis pas cela pour démolir la démo, mais plutôt pour bien 
mettre en évidence le fait que ce travail comporte <span class="emphasis"><em>beaucoup de 
pièges</em></span>. Ceci dit, utiliser LinuxThreads ne se révèle que 
légèrement plus facile.

</p></li><li class="listitem"><p>

Lorsqu'un <span class="foreignphrase"><em class="foreignphrase">thread</em></span> exécute 
<code class="literal">return</code>, il détruit le processus… mais la pile 
locale n'est pas automatiquement désallouée. Pour être plus précis, 
Linux ne gère pas la désallocation, et l'espace mémoire n'est pas 
automatiquement rendu à la liste d'espace libre de 
<code class="literal">malloc()</code>. Aussi, le processus parent doit-il 
récupérer l'espace mémoire de chaque processus fils mort par 
<code class="literal">bb_threads_cleanup(wait(NULL))</code>.

</p></li></ol></div><p>

Le programme suivant, écrit en langage C, utilise l'algorithme traité 
dans la section 1.3 pour calculer la valeur de Pi en utilisant deux 
<span class="foreignphrase"><em class="foreignphrase">threads</em></span> bb_threads.

</p><pre class="programlisting">
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/wait.h&gt;
#include "bb_threads.h"

volatile double pi = 0.0;
volatile int intervalles;
volatile int pids[2];      /* Numéros de processus Unix des threads */

void
do_pi(void *data, size_t len)
{
  register double largeur, sommelocale;
  register int i;
  register int iproc = (getpid() != pids[0]);

  /* Fixe la largeur des intervalles */
  largeur = 1.0 / intervalles;

  /* Effectue les calculs locaux */
  sommelocale = 0;
  for (i=iproc; i&lt;intervalles; i+=2) {
    register double x = (i + 0.5) * largeur;
    sommelocale += 4.0 / (1.0 + x * x);
  }
  sommelocale *= largeur;

  /* Obtention des permissions, mise à jour de Pi, et déverrouillage */
  bb_threads_lock(0);
  pi += sommelocale;
  bb_threads_unlock(0);
}

int
main(int argc, char **argv)
{
  /* Récupère le nombre d'intervalles */
  intervalles = atoi(argv[1]);

  /* Fixe la taille de la pile, et crée le verrou */
  bb_threads_stacksize(65536);
  bb_threads_mutexcreate(0);

  /* crée deux threads ... */
  pids[0] = bb_threads_newthread(do_pi, NULL);
  pids[1] = bb_threads_newthread(do_pi, NULL);

  /* nettoie derrière les deux threads */
  /* (forme ainsi une barrière de synchro) */

  bb_threads_cleanup(wait(NULL));
  bb_threads_cleanup(wait(NULL));

  /* Affiche le résultat */
  printf("Estimation de la valeur de Pi: %f\n", pi);

  /* Sortie avec code de SUCCES */
  exit(0);
}
</pre></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e1444"/>2.4. LinuxThreads</h3></div></div></div><p>

LinuxThreads (<a class="ulink" href="http://pauillac.inria.fr/~xleroy/linuxthreads/" target="_top">http://pauillac.inria.fr/~xleroy/linuxthreads/</a>) est une 
implémentation assez complète et bien construite en accord avec le 
standard de <span class="foreignphrase"><em class="foreignphrase">threads</em></span> POSIX 1003.1c. 
Contrairement aux autres adaptations d'implémentations de 
<span class="foreignphrase"><em class="foreignphrase">threads</em></span> POSIX, LinuxThreads utilise 
également l'appel <code class="literal">clone()</code> du noyau Linux, déjà 
employé par bb_threads. La compatibilité POSIX implique qu'il est 
relativement aisé de faire l'adaptation de certaines applications 
provenant d'autres systèmes, et différents tutoriels et leur support 
sont disponibles. Bref, c'est incontestablement la bibliothèque à 
utiliser pour développer des applications 
<span class="foreignphrase"><em class="foreignphrase">multi-threads</em></span> à grande échelle sous 
Linux.

</p><p>

La structure de base d'un programme utilisant LinuxThreads suit ce 
modèle :

</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>

Lancement du programme en tant que processus unique.

</p></li><li class="listitem"><p>

Initialisation de tous les verrous dont vous aurez besoin.
Contrairement aux verrous de bb_threads qui sont identifiés par
des numéros, les verrous POSIX sont déclarés comme des variables de
type <code class="literal">pthread_mutex_t lock</code>.
Utilisez <code class="literal">pthread_mutex_init(&amp;lock,val)</code>
pour initialiser chacun des verrous que vous utiliserez.

</p></li><li class="listitem"><p>

Comme avec bb_threads, la création d'un nouveau 
<span class="foreignphrase"><em class="foreignphrase">thread</em></span> se fait par l'appel d'une fonction 
de la bibliothèque admettant des arguments spécifiant à leur tour la 
fonction que le nouveau <span class="foreignphrase"><em class="foreignphrase">thread</em></span> doit 
exécuter et les arguments que celle-ci reçoit. Cependant, POSIX impose à 
l'utilisateur la déclaration d'une variable de type 
<code class="literal">pthread_t</code> pour identifier chaque 
<span class="foreignphrase"><em class="foreignphrase">thread</em></span>. Pour créer un 
<span class="foreignphrase"><em class="foreignphrase">thread</em></span> <code class="literal">pthread_t 
thread</code> exécutant la fonction <code class="literal">f()</code>, on 
appelle <code class="literal">pthread_create(&amp;thread,NULL,f,&amp;arg)</code>.

</p></li><li class="listitem"><p>

Lancement de la partie parallèle du programme, en prenant soin d'utiliser

<code class="literal">pthread_mutex_lock(&amp;lock)</code> et

<code class="literal">pthread_mutex_unlock(&amp;lock)</code>

comme il se doit.

</p></li><li class="listitem"><p>

Utilisation de <code class="literal">pthread_join(thread,&amp;retval)</code>
après chaque <span class="foreignphrase"><em class="foreignphrase">thread</em></span> pour tout nettoyer.

</p></li><li class="listitem"><p>

Utilisation de <code class="literal">-D_REENTRANT</code> à la compilation de votre 
programme en C.

</p></li></ol></div><p>

Voici l'exemple du calcul de Pi en parallèle, s'appuyant sur 
LinuxThreads. L'algorithme de la section 1.3 est utilisé et, comme pour 
l'exemple de bb_threads, deux <span class="foreignphrase"><em class="foreignphrase">threads</em></span> 
s'exécutent en parallèle.

</p><pre class="programlisting">
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include "pthread.h"

volatile double pi = 0.0;    /* Approximation de pi (partagée) */
pthread_mutex_t pi_lock;     /* Verrou de la variable ci-dessous */
volatile double intervalles; /* Combien d'intervalles ? */

void *
process(void *arg)
{
  register double largeur, sommelocale;
  register int i;
  register int iproc = (*((char *) arg) - '0');

  /* Fixe la largeur */
  largeur = 1.0 / intervalles;

  /* Fais les calculs locaux */
  sommelocale = 0;
  for (i=iproc; i&lt;intervalles; i+=2) {
    register double x = (i + 0.5) * largeur;
    sommelocale += 4.0 / (1.0 + x * x);
  }
  sommelocale *= largeur;

  /* Verrouille la variable pi en vue d'une mise à jour,
     effectue la mise à jour, puis déverrouille Pi. */

  pthread_mutex_lock(&amp;pi_lock);
  pi += sommelocale;
  pthread_mutex_unlock(&amp;pi_lock);

  return(NULL);
}

int
main(int argc, char **argv)
{
  pthread_t thread0, thread1;
  void * retval;

  /* Récupère le nombre d'intervalles */
  intervalles = atoi(argv[1]);

  /* Initialise un verrou sur pi */
  pthread_mutex_init(&amp;pi_lock, NULL);

  /* Crée les deux threads */
  if (pthread_create(&amp;thread0, NULL, process, "0") ||
      pthread_create(&amp;thread1, NULL, process, "1")) {
    fprintf(stderr, "%s: Création des threads impossible\n", argv[0]);
    exit(1);
  }

  /* « Joint » (détruit) les deux threads */
  if (pthread_join(thread0, &amp;retval) ||
      pthread_join(thread1, &amp;retval)) {
    fprintf(stderr, "%s: Erreur à la fusion des threads\n", argv[0]);
    exit(1);
  }

  /* Affiche le résultat */
  printf("Estimation de la valeur de Pi: %f\n", pi);

  /* Sortie */
  exit(0);
}
</pre></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e1536"/>2.5. La mémoire partagée de System V</h3></div></div></div><p>

La gestion des IPC (<span class="foreignphrase"><em class="foreignphrase">Inter-Process 
Communication</em></span>) System V s'effectue au travers d'un 
certain nombre d'appels système fournissant les mécanismes des files de 
message, des sémaphores et de la mémoire partagée. Bien sûr, ces 
mécanismes ont été initialement conçus pour permettre à plusieurs 
processus de communiquer au sein d'un système monoprocesseur. Cela 
signifie néanmoins que ces mécanismes devraient aussi fonctionner dans 
un système Linux SMP, quelque soit le nombre de processeurs.

</p><p>

Avant d'aller plus loin dans l'utilisation de ces appels, il est 
important de comprendre que même s'il existe des appels IPC System V 
pour des choses comme les sémaphores et la transmission de messages, 
vous ne les utiliserez probablement pas. Pourquoi ? Parce ces 
fonctions sont généralement lentes et sérialisées sous Linux SMP. 
Inutile de s'étendre.

</p><p>

La marche à suivre standard pour créer un groupe de processus partageant 
l'accès à un segment de mémoire partagée est la suivante.

</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>

Lancement du programme en tant que processus unique.

</p></li><li class="listitem"><p>

En temps normal, chaque instance de votre programme en parallèle devra 
avoir son propre segment de mémoire partagée, aussi vous faudra-t-il 
appeler <code class="literal">shmget()</code> pour créer un nouveau segment de la 
taille souhaitée. Mais d'autre part, cet appel peut être utilisé pour 
récupérer l'identifiant d'un segment de mémoire partagée déjà existant. 
Dans les deux cas, la valeur de retour est soit l'identifiant du segment 
de mémoire partagée, soit -1 en cas d'erreur. Par exemple, pour créer un 
segment de mémoire partagée long de <span class="emphasis"><em>b</em></span> octets, on 
passe un appel ressemblant à

<code class="literal">shmid = shmget(IPC_PRIVATE, b, (IPC_CREAT | 0666))</code>.

</p></li><li class="listitem"><p>

L'étape suivante consiste à attacher ce segment de mémoire partagée au 
processus, c'est-à-dire l'ajouter à son plan mémoire. Même si l'appel 
<code class="literal">shmat()</code> permet au programmeur de spécifier l'adresse 
virtuelle à laquelle le segment doit apparaître, cette adresse doit être 
alignée sur une page (plus précisément être un multiple de la taille 
d'une page renvoyée par <code class="literal">getpagesize()</code>, correspondant 
à 4096 octets), et recouvrera (prendra le pas sur) tout segment de 
mémoire s'y trouvant déjà. Ainsi est-il plus sage de laisser le système 
choisir une adresse. Dans les deux cas, la valeur de retour est un 
pointeur sur l'adresse virtuelle de base du segment fraîchement installé 
dans le plan mémoire. L'instruction correspondante est la 
suivante :

<code class="literal">shmptr = shmat(shmid, 0, 0)</code>.

Remarquez que vous pouvez allouer toutes vos variables statiques dans ce 
segment de mémoire partagée en déclarant simplement vos variables 
partagées comme étant les membres d'une structure de type 
<code class="literal">struct</code>, et en déclarant <span class="emphasis"><em>shmptr</em></span> 
comme étant un pointeur vers ce type de données. Avec cette technique, 
une variable partagée <span class="emphasis"><em>x</em></span> serait accessible par 
<span class="emphasis"><em>shmptr</em></span><code class="literal">-&gt;</code><span class="emphasis"><em>x</em></span>.

</p></li><li class="listitem"><p>

Comme ce segment de mémoire partagée doit être détruit quand le
dernier processus à y accéder prend fin ou s'en détache, il nous
faut appeler <code class="literal">shmctl()</code> pour configurer
cette action par défaut. Le code correspondant ressemble à
<code class="literal">shmctl(shmid, IPC_RMID, 0)</code>.

</p></li><li class="listitem"><p>

Utiliser l'appel Linux <code class="literal">fork()</code><a href="#ftn.d0e1606" class="footnote" id="d0e1606"><sup class="footnote">[9]</sup></a> pour créer le nombre désiré de processus. 
Chacun d'eux héritera du segment de mémoire partagée.

</p></li><li class="listitem"><p>

Lorsqu'un processus a fini d'utiliser un segment de mémoire
partagée, il doit s'en détacher. On accomplit cela par un
<code class="literal">shmdt(shmptr)</code>.

</p></li></ol></div><p>

Même avec si peu d'appels système, une fois le segment de mémoire 
partagée établi, tout changement effectué par un processeur sur une 
valeur se trouvant dans cet espace sera automatiquement visible par les 
autres processus. Plus important, chaque opération de communication sera 
exonérée du coût d'un appel système.

</p><p>

Ci-après, un exemple de programme en langage C utilisant les segments de 
mémoire partagée System V. Il calcule Pi, en utilisant les algorithmes 
de la section 1.3.

</p><pre class="programlisting">
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;fcntl.h&gt;
#include &lt;sys/ipc.h&gt;
#include &lt;sys/shm.h&gt;

volatile struct shared { double pi; int lock; } * partage;

inline extern int xchg(register int reg,
volatile int * volatile obj)
{
  /* Instruction atomique d'échange */
__asm__ __volatile__ ("xchgl %1,%0"
                      :"=r" (reg), "=m" (*obj)
                      :"r" (reg), "m" (*obj));
  return(reg);
}

main(int argc, char **argv)
{
  register double largeur, sommelocale;
  register int intervalles, i;
  register int shmid;
  register int iproc = 0;;

  /* Alloue de la mémoire partagée */
  shmid = shmget(IPC_PRIVATE,
                 sizeof(struct shared),
                 (IPC_CREAT | 0600));
  partage = ((volatile struct shared *) shmat(shmid, 0, 0));
  shmctl(shmid, IPC_RMID, 0);

  /* Fais les inits ... */
  partage-&gt;pi = 0.0;
  partage-&gt;lock = 0;

  /* Crée un fils */
  if (!fork()) ++iproc;

  /* Récupère le nombre d'intervalles */
  intervalles = atoi(argv[1]);
  largeur = 1.0 / intervalles;

  /* Fais les calculs locaux */
  sommelocale = 0;
  for (i=iproc; i&lt;intervalles; i+=2) {
    register double x = (i + 0.5) * largeur;
    sommelocale += 4.0 / (1.0 + x * x);
  }
  sommelocale *= largeur;

  /* Verrou d'attente atomique, ajout, et déverrouillage ... */
  while (xchg((iproc + 1), &amp;(shared-&gt;lock))) ;
  shared-&gt;pi += sommelocale;
  shared-&gt;lock = 0;

  /* Fin du processus fils (barrière de synchro) */
  if (iproc == 0) {
    wait(NULL);
    printf("Estimation de pi: %f\n", partage-&gt;pi);
  }

  /* Sortie en bonne et due forme */
  return(0);
}
</pre><p>
Dans cet exemple, j'ai utilisé l'instruction atomique d'échange
pour mettre le verrouillage en œuvre. Pour de meilleures performances,
préférez-lui une technique de synchronisation évitant les intructions
verrouillant le bus.
</p><p>
Pendant les phases de débogage, il est utile de se souvenir que la
commande <code class="literal">ipcs</code> renvoie la liste des
facilités des IPC System V en cours d'utilisation.
</p></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e1629"/>2.6. Projection mémoire (<span class="foreignphrase"><em class="foreignphrase">Memory Map Call</em></span>)</h3></div></div></div><p>

L'utilisation des appels système pour accéder aux fichiers (les 
entrées/sorties) peut revenir cher. En fait, c'est la raison pour 
laquelle il existe une bibliothèque de gestion des entrées/sorties 
gérant un tampon dans l'espace utilisateur 
(<code class="literal">getchar()</code>, <code class="literal">fwrite()</code>, et cætera). 
Mais les tampons utilisateur ne remplissent pas leur fonction si 
plusieurs processus accèdent au même fichier ouvert en écriture. La 
solution Unix BSD à ce problème fut l'ajout d'un appel système 
permettant à une portion d'un fichier d'être projetée en mémoire 
utilisateur, en utilisant principalement les mécanismes de la mémoire 
virtuelle pour provoquer les mises à jour. Le même mécanisme a été 
utilisé pendant plusieurs années dans les systèmes de Sequent comme base 
de leur gestion du traitement parallèle en mémoire partagée. En dépit de 
commentaires très négatifs dans la page de manuel (assez ancienne), 
Linux semble correctement effectuer au moins quelques unes des fonctions 
de base, et sait prendre en charge l'usage dérivé de cet appel pour 
projeter un segment anonyme de mémoire pouvant être partagé par 
plusieurs processus.

</p><p>

L'implémentation Linux de l'appel <code class="literal">mmap()</code> est en 
elle-même une solution intégrée de remplacement des étapes 2, 3 et 4 du 
schéma classique de mémoire partagée System V, mis en évidence dans la 
section 2.5. Pour créer un segment de mémoire partagée anonyme :

</p><pre class="programlisting">
shmptr =
    mmap(0,                        /* Le système choisit l'adresse */
         b,                        /* Taille du segment de mémoire partagée */
         (PROT_READ | PROT_WRITE), /* droits d'accès, peuvent être rwx */
         (MAP_ANON | MAP_SHARED),  /* anonyme, partagé */
         0,                        /* descripteur de fichier (inutilisé) */
         0);                       /* offset fichier (inutilisé) */
</pre><p>

L'équivalent de l'appel de mémoire partagée System V 
<code class="literal">shmdt()</code> est <code class="literal">munmap()</code> :

</p><pre class="programlisting">
munmap(shmptr, b);
</pre><p>

À mon avis, on ne gagne pas grand chose à utiliser 
<code class="literal">mmap()</code> plutôt que les mécanismes de gestion de la 
mémoire partagée de System V.

</p></div></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title"><a id="d0e1665"/>3. <span class="foreignphrase"><em class="foreignphrase">Clusters</em></span> de systèmes Linux</h2></div></div></div><p>

Cette section tente de donner un aperçu de ce qu'est le traitement 
parallèle en <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> sous Linux. Les 
<span class="foreignphrase"><em class="foreignphrase">clusters</em></span> sont, actuellement, à la fois 
l'approche la plus populaire et la plus variée, en s'étendant du simple 
réseau de stations de travail (<span class="foreignphrase"><em class="foreignphrase">Network Of 
Workstations</em></span> : <span class="emphasis"><em>NOW</em></span>) aux 
machines en parallèle essentiellement construites sur mesure, et dans 
lesquelles il arrive que l'on trouve comme éléments des PC sous Linux. Il 
existe également un grand nombre de logiciels pouvant prendre en charge 
le calcul en parallèle dans des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> 
de machines Linux.

</p><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e1687"/>3.1. Pourquoi un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> ?</h3></div></div></div><p>

Le traitement en parallèle au travers d'un 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> offre plusieurs avantages 
majeurs :

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Chacune des machines d'un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> peut 
être un système complet, utilisable avec une large gamme d'applications 
de calcul. Cela conduit beaucoup de gens à suggérer l'idée que ce type 
de <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> pourrait faire usage de tous 
les <span class="quote">« <span class="quote">cycles machine perdus</span> »</span> sur les ordinateurs tournant à 
ne rien faire dans les bureaux. Il n'est pas si facile de récupérer ces 
cycles, et cela risque de ralentir l'écran de veille de votre collègue, 
mais cela peut être fait.

</p></li><li class="listitem"><p>

L'explosion actuelle des systèmes en réseau signifie que la plupart du 
matériel nécessaire à la construction d'un 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> se vend déjà en grande quantité 
et aux prix réduits inhérents à la <span class="quote">« <span class="quote">grande distribution</span> »</span>. 
On peut économiser encore un peu plus en partant du principe qu'une 
seule carte vidéo, un seul moniteur et un seul clavier soient 
nécessaires pour chaque <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> (bien 
qu'il vous faille tout de même les passer d'une machine à une autre pour 
faire l'installation initiale de Linux, une fois lancé, un PC sous Linux 
typique n'a pas besoin de <span class="quote">« <span class="quote">console</span> »</span>). En comparaison, les 
systèmes SMP et processeurs auxiliaires représentent des marchés plus 
réduits, tendant à proposer des prix plus élevés par performances à 
l'unité.

</p></li><li class="listitem"><p>

Les calculateurs en <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> peuvent 
<span class="emphasis"><em>évoluer en de très grands systèmes</em></span>. Alors qu'il est 
actuellement difficile de trouver un ordinateur SMP à plus de quatre 
processeurs qui soit compatible avec Linux, la plupart du matériel 
réseau disponible permet de bâtir facilement un 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> incluant jusqu'à 16 machines. 
Avec un peu d'huile de coude, on peut mettre en réseau des centaines 
voire des milliers de machines. En fait, Internet tout entier pourrait 
être assimilé à un seul immense <span class="foreignphrase"><em class="foreignphrase">cluster</em></span>.

</p></li><li class="listitem"><p>

Le fait que remplacer une <span class="quote">« <span class="quote">mauvaise machine</span> »</span> au sein d'un 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> soit une opération triviale 
comparé à la réparation d'un ordinateur SMP partiellement défaillant 
garantit une disponibilité bien plus élevée aux configurations de 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> soignées. Cela devient important 
non seulement pour les applications qui ne peuvent tolérer des 
interruptions de service trop importantes, mais aussi dans l'utilisation 
en général de systèmes qui contiennent un nombre suffisant de 
processeurs pour que la panne d'une machine en particulier soit assez 
courante (par exemple, même si la durée moyenne avant la première panne 
d'un PC est environ deux ans, dans un 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> de 32 machines, la probabilité 
qu'au moins une machine tombe en panne dans les six premiers mois est 
assez élevée).

</p></li></ul></div><p>

Très bien. Si les <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> sont gratuits 
ou très peu onéreux, peuvent devenir très grands et offrir une haute 
disponibilité… pourquoi tout le monde n'utilise pas un 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> ? Eh bien, parce qu'il y a 
aussi des problèmes :

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

À quelques exceptions près, le matériel réseau n'est pas conçu pour le 
traitement en parallèle. Typiquement, les temps de latence sont élevés 
et la bande passante réduite comparés aux systèmes SMP et processeurs 
auxiliaires. Par exemple, si les temps de latence d'un SMP n'excèdent 
généralement pas plus de quelques microsecondes, ils atteignent 
couramment des centaines, voire des milliers de microsecondes dans un 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span>. La bande passante des 
communications dans un système SMP dépasse souvent 100 mégaoctets par 
seconde. Bien que le matériel réseau le plus rapide (c'est-à-dire le 
<span class="quote">« <span class="quote">Gigabit Ethernet</span> »</span>) présente une vitesse comparable, la 
plupart des réseaux sont de 10 à 1000 fois plus lents.

La performance d'un matériel réseau est déjà suffisamment médiocre dans 
un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> <span class="emphasis"><em>isolé</em></span>. Si 
le réseau n'est pas isolé du reste du trafic, ce qui est souvent le cas 
lorsque l'on utilise des <span class="quote">« <span class="quote">machines qui sont en réseau</span> »</span> 
plutôt qu'un système conçu pour être un 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span>, les performances peuvent être 
bien pires encore.

</p></li><li class="listitem"><p>

La gestion logicielle des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> en 
tant que système unique est très mince. Par exemple, la commande 
<code class="literal">ps</code> ne fait état que des processus s'exécutant sur un 
seul système Linux, pas des processus s'exécutant à travers le 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> Linux entier.

</p></li></ul></div><p>

Moralité, les <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> ont un très grand 
potentiel, mais ce potentiel risque d'être très difficile à concrétiser 
pour la plupart des applications. La bonne nouvelle, c'est qu'il existe 
un soutien logiciel très développé pour vous aider à obtenir de bonnes 
performances avec les programmes adaptés à cet environnement, et qu'il 
existe également des réseaux conçus spécialement pour élargir la palette 
de programmes pouvant avoir de bonnes performances.

</p></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e1803"/>3.2. Le matériel réseau</h3></div></div></div><p>

Les réseaux informatiques sont en pleine explosion… mais vous le 
savez déjà. Un nombre toujours grandissant de technologies et produits 
réseau a été développé, et la plupart d'entre eux sont disponibles sous 
une forme qui peut être utilisée pour faire d'un groupe de machines (des 
PC fonctionnant chacun sous Linux) un 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> de traitement en parallèle.

</p><p>

Malheureusement, aucune technologie réseau ne résout complètement tous 
les problèmes. À vrai dire, le nombre d'approches différentes, en coût 
et en performances, est à première vue assez difficile à croire. Par 
exemple, le coût par machine mise en réseau s'étend de moins de 5 
dollars jusqu'à plus de 4000. La bande passante et les temps de latence 
varient aussi selon quatre ordres de grandeur.

</p><p>

Avant d'en apprendre plus sur les spécificités de certains réseaux, il 
est important de remarquer que ces choses évoluent très fréquemment 
(voir <a class="ulink" href="http://www.linux.org.uk/NetNews.html" target="_top">http://www.linux.org.uk/NetNews.html</a> pour avoir des 
nouvelles fraîches concernant les réseaux sous Linux), et qu'il est très 
difficile d'obtenir des infos précises concernant certains réseaux.

</p><p>

J'ai placé un <span class="quote">« <span class="quote"><span class="emphasis"><em>?</em></span></span> »</span> aux endroits 
incertains. J'ai aussi passé beaucoup de temps à faire des recherches 
sur ce sujet, mais je reste sûr que ce résumé est plein d'erreurs et 
d'omissions importantes. Si vous avez des corrections ou des ajouts à y 
apporter, merci de m'envoyer un courrier électronique en anglais à 
l'adresse suivante : <code class="email">&lt;<a class="email" href="mailto:hankd CHEZ engr POINT uky POINT edu">hankd CHEZ engr POINT uky POINT edu</a>&gt;</code>.

</p><p>

Les résumés comme le <a class="ulink" href="http://www.mcgeoch.com/other/lan-technology.html" target="_top">LAN Technology 
Scorecard</a><a href="#ftn.d0e1830" class="footnote" id="d0e1830"><sup class="footnote">[10]</sup></a> donnent les caractéristiques de nombreux et 
différents types de réseaux et de standards de réseaux locaux (LAN). 
Cependant, l'essentiel de ce guide pratique est centré sur les propriétés les 
plus indiquées à la construction d'un 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> Linux. Chaque section décrivant 
un type de réseau débute par une courte liste de caractéristiques. Ci 
dessous, la définition de chaque entrée.

</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">Prise en charge sous Linux :</span></dt><dd><p>

Si la réponse est <span class="emphasis"><em>non</em></span>, la signification est claire. 
Les autres réponses tentent de décrire l'interface de base utilisée pour 
accéder au réseau. La plupart du matériel réseau est interfacé via un 
pilote de périphérique du noyau, sachant typiquement gérer les 
communications TCP/UDP. D'autres réseaux utilisent des interfaces plus 
directes (par exemple des bibliothèques) pour réduire les temps de 
latence en évitant d'avoir à passer par le noyau.

</p><p>

Il y a quelques années, il était considéré comme parfaitement acceptable 
d'accéder au coprocesseur mathématique (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">floating 
point unit</em></span></span> »</span>) par un appel système mais 
aujourd'hui, c'est clairement ridicule. À mon avis, nécessiter un appel 
système pour chaque communication entre les processeurs exécutant un 
programme en parallèle est peu commode. Le problème est que les 
ordinateurs n'ont pas encore intégré ces mécanismes de communication, et 
que les approches non <span class="quote">« <span class="quote">orientées noyau</span> »</span> tendent à présenter 
des problèmes de portabilité. Vous allez entendre beaucoup parler de ce 
sujet dans un avenir proche, principalement sous la forme de la nouvelle 
<span class="emphasis"><em> Virtual Interface (VI) Architecture</em></span> (<a class="ulink" href="http://www.intel.com/intelpress/sum_via.htm" target="_top">http://www.intel.com/intelpress/sum_via.htm</a>) méthode 
standardisée pour les opérations des interfaces réseau et servant à 
contourner les couches des systèmes d'exploitation usuels. Le standard 
VI est appuyé par Compaq, Intel et Microsoft, et aura assurément un 
impact important sur la conception des SAN (<span class="foreignphrase"><em class="foreignphrase">System Area 
Network</em></span>) dans les prochaines années.

</p></dd><dt><span class="term">Bande passante maximum :</span></dt><dd><p>

C'est le chiffre dont tout le monde se soucie. J'ai généralement repris 
les débits maximum théoriques. Votre moyenne, elle, 
<span class="emphasis"><em>va</em></span> varier.

</p></dd><dt><span class="term">Temps de latence minimum :</span></dt><dd><p>

À mon avis, c'est le chiffre dont tout le monde devrait se soucier, plus 
encore que de la bande passante. Là encore, j'ai utilisé les 
(irréalistes) valeurs théoriques idéales, mais au moins ces nombres 
prennent en compte <span class="emphasis"><em>toutes</em></span> les sources de latence, 
tant logicielles que matérielles. Dans la plupart des cas, les temps de 
latence réseau ne durent que quelques microsecondes. Des nombres 
beaucoup plus grands reflètent les couches des matériels et logiciels 
inefficaces.

</p></dd><dt><span class="term">Disponibilité :</span></dt><dd><p>

Reprise telle quelle, cette ligne décrit la forme sous laquelle vous 
pouvez acquérir ce type de matériel. Le matériel de la grande 
distribution est disponible largement et de plusieurs fabricants, le 
prix étant alors le premier critère de choix. Les choses proposées par 
<span class="quote">« <span class="quote">différents fabricants</span> »</span> sont disponibles chez plus d'un 
seul concurrent, mais il existe des différences significatives, et des 
problèmes potentiels d'interopérabilité. Les réseaux produits par un 
<span class="quote">« <span class="quote">fabricant exclusif</span> »</span> vous laissent à la merci de ce 
fournisseur, aussi bienveillant soit-il. <span class="quote">« <span class="quote">Domaine public</span> »</span> 
signifie que même si vous ne pouvez trouver quelqu'un pour vous vendre 
ce type de matériel, vous ou n'importe qui d'autre pouvez acheter les 
composants et en fabriquer un exemplaire. C'est typiquement le cas des 
prototypes de recherche. Ils ne sont en général ni prêts à être utilisés 
par le public, ni disponibles à celui-ci.

</p></dd><dt><span class="term">Port ou bus utilisé :</span></dt><dd><p>

La manière dont on relie l'interface réseau à l'ordinateur. Les 
meilleures performances (et désormais les plus courantes) s'obtiennent 
avec le bus PCI. Il existe aussi des cartes pour bus EISA, VESA local 
bus (VLB), et ISA. ISA fut le premier, et il est toujours utilisé par 
les cartes aux basses performances. On trouve toujours l'EISA comme bus 
secondaire dans les machines PCI. Ces derniers temps, on ne trouve plus 
beaucoup de matériel à base de VLB (même si la <a class="ulink" href="http://www.vesa.org" target="_top">Video Electronics Standards 
Association</a> voit les choses autrement).

</p><p>

Bien sûr, toute interface que vous pouvez utiliser sans avoir à ouvrir 
le boîtier de votre PC est plus qu'attrayante. les interfaces IrDA 
(N.D.T. : port infrarouge) et USB font leur apparition de plus en 
plus fréquemment. Le Port Parallèle Standard (SPP) est longtemps resté 
<span class="quote">« <span class="quote">ce sur quoi vous branchiez votre imprimante</span> »</span>, mais s'est 
avéré dernièrement être très utile comme extension du bus ISA. Cette 
nouvelle fonction est améliorée par le standard IEEE 1284, qui spécifie 
les optimisations EPP et ECP. Il y a aussi le bon vieux port série 
RS232, lent mais fiable. Je n'ai eu vent d'aucun témoignage concernant 
l'interconnexion de machines par le biais des connecteurs vidéo (VGA), 
clavier, souris ou joystick…

</p></dd><dt><span class="term">Structure du réseau :</span></dt><dd><p>

Un bus est un fil, un ensemble de fils, ou une fibre (optique). Un 
<span class="foreignphrase"><em class="foreignphrase">hub</em></span> (<span class="quote">« <span class="quote">concentrateur</span> »</span> ou 
<span class="quote">« <span class="quote">plaque tournante</span> »</span>) est une petite boite qui peut recevoir 
différents types de fils ou de fibres. Les commutateurs 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">switched hubs</em></span></span> »</span>) permettent 
à plusieurs connexions de transmettre activement et simultanément leurs 
données.

</p></dd><dt><span class="term">Coût par machine reliée :</span></dt><dd><p>

Voici comment lire ces nombres. Supposons que, en dehors des connexions 
réseau, acheter un PC comme unité de votre 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> vous coûte 2000 dollars. L'ajout 
de Fast Ethernet porte le prix à l'unité à environ 2400 dollars. L'ajout 
de Myrinet mène ce prix à 3800 dollars environ. Si vous avez 20 000 
dollars à dépenser, vous pouvez alors avoir soit 8 machines reliées par 
du Fast Ethernet, soit 5 machines reliées par du Myrinet. Il est 
également très raisonnable d'utiliser plusieurs types de réseaux. Par 
exemple, avec 20 000 dollars, vous pouvez vous offrir 8 machines 
reliées entre elles par Fast Ethernet et TTL_PAPERS. Choisissez un 
réseau — ou un ensemble de réseaux — qui permettra à votre 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> d'exécuter votre application le 
plus rapidement possible.

</p><p>

Au moment où vous lirez ces lignes, ces chiffres seront faux… En 
fait, ils le sont sûrement déjà. Il peut aussi y avoir un grand nombre 
de réductions, d'offres spéciales, et cætera. Mais en tout cas, les prix 
cités ici ne seront jamais suffisamment erronés pour vous conduire à 
faire un choix totalement inapproprié. Nul besoin d'avoir un doctorat 
(même si c'est mon cas ;-) pour constater que l'utilisation de réseaux 
onéreux n'a de sens que si votre application a réellement besoin de 
leurs propriétés ou si les PC utilisés dans votre 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> sont eux aussi relativement 
chers.

</p></dd></dl></div><p>
Maintenant que vous êtes avertis, place au spectacle…
</p><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e1949"/>3.2.1. ArcNet</h4></div></div></div><p>

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
Prise en charge par Linux : <span class="emphasis"><em>pilotes du noyau</em></span>
</p></li><li class="listitem"><p>
Bande passante maximum : <span class="emphasis"><em>2,5 Mbits/s</em></span>
</p></li><li class="listitem"><p>
Temps de latence minimum : <span class="emphasis"><em>1000 microsecondes ?</em></span>
</p></li><li class="listitem"><p>
Disponibilité : <span class="emphasis"><em>différents fabricants</em></span>
</p></li><li class="listitem"><p>
Port ou bus utilisé : <span class="emphasis"><em>ISA</em></span>
</p></li><li class="listitem"><p>
Structure du réseau : <span class="emphasis"><em><span class="foreignphrase"><em class="foreignphrase">Hub</em></span> ou bus non commutés (anneau logique)</em></span>
</p></li><li class="listitem"><p>
Coût par machine reliée : <span class="emphasis"><em>200 dollars</em></span>
</p></li></ul></div><p>

</p><p>
ARCNET est un réseau local principalement destiné à être utilisé
dans les systèmes de contrôle temps réel embarqués. Comme Ethernet,
le réseau est physiquement organisé en prises le long d'un bus d'un
ou plusieurs <span class="foreignphrase"><em class="foreignphrase">hubs</em></span>. En revanche, et contrairement
à Ethernet, il utilise un protocole à base de jetons qui structure de manière
logique le réseau comme un anneau. Les entêtes des paquets sont réduites (3 ou 4
octets) et les messages peuvent être très courts (jusqu'à un seul octet).
De fait, ARCNET est plus efficace qu'Ethernet. Malheureusement, il est
aussi plus lent, et moins populaire ce qui le rend plus cher. Vous trouvez
plus d'informations sur le site de l'<a class="ulink" href="http://www.arcnet.com/" target="_top">ARCNET Trade Association</a>.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e2008"/>3.2.2. ATM</h4></div></div></div><p>

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
Prise en charge par Linux : <span class="emphasis"><em>pilotes du noyau, bibliothèques AAL*</em></span>
</p></li><li class="listitem"><p>
Bande passante maximum : <span class="emphasis"><em>155 Mbits/s</em></span> (bientôt, <span class="emphasis"><em>1200 Mbits/s</em></span>)
</p></li><li class="listitem"><p>
Temps de latence minimum : <span class="emphasis"><em>120 microsecondes</em></span>
</p></li><li class="listitem"><p>
Disponibilité : <span class="emphasis"><em>différents fabricants</em></span>
</p></li><li class="listitem"><p>
Port ou bus utilisé : <span class="emphasis"><em>PCI</em></span>
</p></li><li class="listitem"><p>
Structure du réseau : <span class="emphasis"><em><span class="foreignphrase"><em class="foreignphrase">hubs</em></span> commutés</em></span>
</p></li><li class="listitem"><p>
Coût par machine reliée : <span class="emphasis"><em>3000 dollars</em></span>
</p></li></ul></div><p>

</p><p>
A moins d'avoir été dans le coma ces dernières années, vous avez
sûrement beaucoup entendu dire qu'ATM (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Asynchronous Transfer Mode</em></span></span> »</span>)
<span class="emphasis"><em>est</em></span> l'avenir… Eh bien, en quelque sorte.
ATM est meilleur marché que HiPPI et plus rapide que Fast Ethernet,
et il peut être utilisé sur de très longues distances, ce qui
intéresse beaucoup les opérateurs téléphoniques. Le protocole du
réseau ATM est également conçu pour fournir une interface logicielle
aux temps d'accès réduits et gérant plus efficacement les messages
courts et les communications en temps réel (c'est-à-dire les transmissions
audio et vidéo numériques). C'est aussi l'un des réseaux aux plus hauts
débits que Linux prenne actuellement en charge. La mauvaise nouvelle,
c'est qu'ATM n'est pas vraiment bon marché, et qu'il demeure encore des
problèmes de compatibilité entre fabricants. Un aperçu du développement
ATM sous Linux est disponible sur <a class="ulink" href="http://linux-atm.sourceforge.net/" target="_top">http://linux-atm.sourceforge.net/</a>.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e2074"/>3.2.3. CAPERS</h4></div></div></div><p>

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
Prise en charge par Linux : <span class="emphasis"><em>bibliothèque AFAPI</em></span>
</p></li><li class="listitem"><p>
Bande passante maximum : <span class="emphasis"><em>1,2 Mbit/s</em></span>
</p></li><li class="listitem"><p>
Temps de latence maximum : <span class="emphasis"><em>3 microsecondes</em></span>
</p></li><li class="listitem"><p>
Disponibilité : <span class="emphasis"><em>grande distribution</em></span>
</p></li><li class="listitem"><p>
Port ou bus utilisé : <span class="emphasis"><em>SPP (port parallèle)</em></span>
</p></li><li class="listitem"><p>
Structure du réseau : <span class="emphasis"><em>câble entre 2 machines</em></span>
</p></li><li class="listitem"><p>
Coût par machine reliée : <span class="emphasis"><em>2 dollars</em></span>
</p></li></ul></div><p>

</p><p>

CAPERS (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Cable Adapter for Parallel Execution and 
Rapid Synchronisation</em></span></span> »</span> : <span class="quote">« <span class="quote">Adaptateur 
par Câble pour l'Exécution en Parallèle et la Synchronisation 
Rapide</span> »</span>) est un produit dérivé du projet PAPERS, de 
l'<span class="foreignphrase"><em class="foreignphrase">University School of Electrical and Computer 
Engineering</em></span> de Purdue. En substance, ce projet définit 
un protocole logiciel permettant d'utiliser une simple liaison 
point-à-point par le port parallèle, type <span class="quote">« <span class="quote">LapLink</span> »</span>, pour 
implémenter la bibliothèque PAPERS sur deux PC sous Linux. L'idée n'est 
exploitable à grande échelle, mais le prix est imbattable. Tout comme avec 
TTL_PAPERS, pour améliorer la sécurité du système, il est recommandé, 
mais pas nécessaire, d'appliquer un correctif mineur au noyau.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e2138"/>3.2.4. Ethernet</h4></div></div></div><p>

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
Prise en charge par Linux : <span class="emphasis"><em>pilotes du noyau</em></span>
</p></li><li class="listitem"><p>
Bande passante maximum : <span class="emphasis"><em>10 Mbits/s</em></span>
</p></li><li class="listitem"><p>
Latence minimum : <span class="emphasis"><em>100 microsecondes</em></span>
</p></li><li class="listitem"><p>
Disponibilité : <span class="emphasis"><em>grande distribution</em></span>
</p></li><li class="listitem"><p>
Port ou bus utilisé : <span class="emphasis"><em>PCI</em></span>
</p></li><li class="listitem"><p>
Structure du réseau : <span class="emphasis"><em>commutateurs ou concentrateurs, ou même bus simple</em></span>
</p></li><li class="listitem"><p>
Coût par machine connectée : <span class="emphasis"><em>100 dollars</em></span> (sans concentrateur, <span class="emphasis"><em>50 dollars</em></span>)
</p></li></ul></div><p>

</p><p>

Depuis plusieurs années maintenant, l'Ethernet à 10Mbits/s est le 
standard des technologies réseau. Une bonne carte Ethernet s'achète pour 
moins de 50 dollars, et bon nombre de PC en sont aujourd'hui équipés de 
série, l'interface étant intégrée à la carte-mère. Les réseaux à base 
Ethernet dont la charge n'est pas très élevée peuvent être organisés 
comme un long bus à prises multiples sans concentrateur 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">hub</em></span></span> »</span>). Une telle 
configuration peut servir jusqu'à 200 machines pour un coût minimal, 
mais n'est pas appropriée au traitement en parallèle. Ajouter un 
concentrateur non commuté n'améliore pas beaucoup les performances. En 
revanche, les commutateurs 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">switches</em></span></span> »</span>), qui peuvent 
offrir une bande passante maximum à plusieurs connexions simultanément 
ne coûtent qu'aux alentours de 100 dollars par port. Linux prend en 
charge un nombre impressionnant d'interfaces Ethernet différentes, mais 
il est important de garder à l'esprit que les variations entre ces 
matériels peuvent engendrer de grandes différences de performance. 
Consultez le <a class="ulink" href="http://www.traduc.org/docs/howto/lecture/Hardware-HOWTO.html" target="_top">Guide pratique de 
la compatibilité matérielle avec Linux</a> (N.D.T. : version 
française du <a class="ulink" href="http://www.tldp.org/HOWTO/Hardware-HOWTO/" target="_top"> 
<span class="foreignphrase"><em class="foreignphrase">Hardware Compatibility HOWTO</em></span> 
</a>) pour plus d'informations concernant les différents équipements 
fonctionnant sous Linux, et pour avoir une idée de leur qualité.

</p><p>

Le <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> Linux à 16 machines réalisé 
dans le cadre du projet <span class="quote">« <span class="quote"><a class="ulink" href="http://www.beowulf.org" target="_top">Beowulf</a></span> »</span> (initialement 
développé au CESDIS de la NASA) est une manière intéressante d'augmenter 
ses performances. C'est à Donald Becker, auteur de plusieurs pilotes de 
cartes Ethernet, que l'on doit la prise en charge de la répartition du 
trafic au travers de plusieurs cartes réseau s'éclipsant mutuellement 
(autrement dit, partageant les mêmes adresses réseau). Cette fonction 
est intégrée en standard dans Linux, et s'effectue de manière invisible 
en dessous du niveau des opérations sur les 
<span class="foreignphrase"><em class="foreignphrase">sockets</em></span>. Le coût d'un hub n'étant pas 
négligeable, relier chaque machine à deux (ou plus) réseaux Ethernet, 
sans <span class="foreignphrase"><em class="foreignphrase">hubs</em></span> ni 
<span class="foreignphrase"><em class="foreignphrase">switches</em></span>, pour améliorer les performances 
peut s'avérer financièrement très rentable. D'une manière générale, dans 
les situations où une machine est le goulet d'étranglement d'un réseau, 
la répartition de charge à travers plusieurs réseaux 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">shadow networks</em></span></span> »</span>) se 
révèle bien plus efficace que l'usage d'un réseau équipé d'un 
commutateur seul.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e2231"/>3.2.5. Ethernet (Fast Ethernet)</h4></div></div></div><p>

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
Prise en charge par Linux : <span class="emphasis"><em>pilotes du noyau</em></span>
</p></li><li class="listitem"><p>

Bande passante maximum : <span class="emphasis"><em>100 Mbits/s</em></span>

</p></li><li class="listitem"><p>

Temps de latence minimum : <span class="emphasis"><em>80 microsecondes</em></span>

</p></li><li class="listitem"><p>

Disponibilité : <span class="emphasis"><em>grande distribution</em></span>

</p></li><li class="listitem"><p>

Port ou bus utilisé : <span class="emphasis"><em>PCI</em></span>

</p></li><li class="listitem"><p>

Structure du réseau : <span class="emphasis"><em>concentrateurs ou commutateurs 
(<span xml:lang="en" class="foreignphrase"><em xml:lang="en" class="foreignphrase">hubs</em></span> ou <span xml:lang="en" class="foreignphrase"><em xml:lang="en" class="foreignphrase">switches</em></span>)</em></span>

</p></li><li class="listitem"><p>

Coût par machine connectée : <span class="emphasis"><em>400 dollars (?)</em></span>

</p></li></ul></div><p>

</p><p>

Bien qu'il existe un certain nombre de technologies différentes nommées 
<span class="quote">« <span class="quote">Fast Ethernet</span> »</span>, elles se réfèrent souvent à un réseau 
Ethernet 100 Mbits/s en grande partie compatible avec les anciens câbles 
et périphériques 10 Mbits/s type <span class="quote">« <span class="quote">10 BaseT</span> »</span>. Comme on peut 
s'y attendre, tout ce qui s'appelle Ethernet bénéficie des prix de la 
vente de masse, et ces interfaces ne coûtent généralement qu'une 
fraction du prix des cartes ATM à 155 Mbits/s. Le problème est qu'une 
collection de machines partageant tous le même <span class="quote">« <span class="quote">bus</span> »</span> à 100 
Mbits/s (à l'aide d'un <span class="foreignphrase"><em class="foreignphrase">hub</em></span> non commuté) 
peut présenter des performances n'atteignant en moyenne même pas celles 
d'un réseau 10 Mbits/s utilisant un commutateur fournissant à chaque 
machine une connexion 10 Mbits/s complète.

</p><p>
Les commutateurs pouvant fournir une connexion 100 Mbits à chaque
machine simultanément sont chers, mais les prix chutent chaque jour,
et ces commutateurs offrent une bande passante autrement plus élevée
que de simples <span class="foreignphrase"><em class="foreignphrase">hubs</em></span> non commutés. Ce qui rend les commutateurs ATM
si onéreux est la nécessité de commuter chaque cellule ATM, cellule
relativement courte. Certains commutateurs Ethernet parient sur une
fréquence de commutation attendue relativement lente et en tirent
profit en utilisant des techniques aux temps de latence réduits à
l'intérieur du commutateur, mais nécessitant quelques millisecondes
pour changer de voie. Si l'itinéraire de votre trafic réseau change
fréquemment, évitez ce type d'équipement.
</p><p>
Notez aussi que, comme pour Ethernet, le projet Beowulf
(<a class="ulink" href="http://www.beowulf.org" target="_top">http://www.beowulf.org</a>) de la NASA développe des pilotes aux performances supérieures
car utilisant la répartition de charge entre plusieurs cartes
Fast Ethernet.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e2310"/>3.2.6. Ethernet (Gigabit Ethernet)</h4></div></div></div><p>

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
Prise en charge par Linux : <span class="emphasis"><em>pilotes du noyau</em></span>
</p></li><li class="listitem"><p>
Bande passante maximum : <span class="emphasis"><em>1000 Mb/s</em></span>
</p></li><li class="listitem"><p>
Temps de latence minimum : <span class="emphasis"><em>300 microsecondes (?)</em></span>
</p></li><li class="listitem"><p>
Disponibilité : <span class="emphasis"><em>différents fabricants</em></span>
</p></li><li class="listitem"><p>
Port ou bus utilisé : <span class="emphasis"><em>PCI</em></span>
</p></li><li class="listitem"><p>
Structure réseau : <span class="emphasis"><em>commutateurs ou FDR</em></span>
</p></li><li class="listitem"><p>
Coût par machine connectée : <span class="emphasis"><em>2500 dollars (?)</em></span>
</p></li></ul></div><p>

</p><p>
Je ne suis pas sûr que <a class="ulink" href="http://www.gigabit-ethernet.org/" target="_top">Gigabit Ethernet</a>
ait une raison technologique valable
de s'appeler Ethernet… mais son nom inspire le fait que
Gigabit Ethernet est conçu pour être une technologie réseau
bon marché et de grande distribution, avec une prise en charge
native de l'IP. En revanche, les prix actuels reflètent le
fait que cela reste un produit difficile à fabriquer.
</p><p>

Contrairement aux autres technologies Ethernet, Gigabit Ethernet apporte 
un contrôle du flux, ce qui devrait en faire un réseau plus fiable. Les 
FDR, ou <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Full-Duplex 
Repeaters</em></span></span> »</span> (<span class="quote">« <span class="quote">répéteurs bidirectionnels 
simultanés</span> »</span>), se contentent de multiplexer les lignes, en 
utilisant des mémoires tampons et des contrôles de flux localisés pour 
améliorer les performances. La plupart des commutateurs sont construits 
comme de nouveaux modules pour les différents modèles de commutateurs 
compatible Gigabit déjà existants. Les commutateurs ou FDR sont 
distribués ou annoncés par au moins Acacianet, <a class="ulink" href="http://www.baynetworks.com/" target="_top">Bay networks</a>, <a class="ulink" href="http://www.cabletron.com/" target="_top">Cabletron</a> (désormais Enterasys. 
Page française : <a class="ulink" href="http://www.enterasys.com/fr/" target="_top">http://www.enterasys.com/fr/</a>), 
Networks digital, <a class="ulink" href="http://www.extremenetworks.com/homepage_french.asp" target="_top">Extreme 
networks</a>, <a class="ulink" href="http://www.foundrynet.com/" target="_top">Foundry 
networks</a>, Gigalabs.com, Packet engines, <a class="ulink" href="http://www.plaintree.com/" target="_top">Plaintree systems</a>, <a class="ulink" href="http://www.prominet.com/" target="_top">Prominet</a>, <a class="ulink" href="http://fr.sun.com/" target="_top">Sun microsystems</a>, et Xlnt.

</p><p>

Il existe un pilote pour Linux pour les <span class="quote">« <span class="quote">Yellowfin</span> »</span> G-NIC 
de Packet Engines<a href="#ftn.d0e2401" class="footnote" id="d0e2401"><sup class="footnote">[11]</sup></a>. Les premiers essais sous Linux ont fait état d'un 
taux de transfert environ 2,5 fois supérieur à la plus rapide des cartes 
Fast Ethernet à 100 Mbits/s. Avec les réseaux Gigabit, une configuration 
soigneuse du bus PCI est un facteur critique. Il reste toujours un doute 
quant à la poursuite des améliorations de ce pilote, et du développement 
des pilotes Linux des autres cartes réseau.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e2405"/>3.2.7. FC (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Fibre Channel</em></span></span> »</span>)</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Prise en charge par Linux : 
<span class="emphasis"><em>non</em></span><a href="#ftn.d0e2418" class="footnote" id="d0e2418"><sup class="footnote">[12]</sup></a>

</p></li><li class="listitem"><p>

Bande passante maximum : <span class="emphasis"><em>1062 Mbits/s</em></span>

</p></li><li class="listitem"><p>

Temps de latence minimum : <span class="emphasis"><em>?</em></span>

</p></li><li class="listitem"><p>

Disponibilité : <span class="emphasis"><em>différents fabricants</em></span>

</p></li><li class="listitem"><p>

Interface ou bus utilisé : <span class="emphasis"><em>PCI (?)</em></span>

</p></li><li class="listitem"><p>

Structure du réseau : <span class="emphasis"><em>?</em></span>

</p></li><li class="listitem"><p>

Coût par machine connectée : <span class="emphasis"><em>?</em></span>

</p></li></ul></div><p>

L'objectif du FC (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Fibre 
Channel</em></span></span> »</span>) est de fournir un médium 
d'entrée/sortie de type bloc aux performances élevées (une trame FC 
transporte un bloc de données d'une longueur forfaitaire de 2048 
octets), particulièrement adapté aux partages de disques et autres 
périphériques de stockage, qui peuvent alors être reliés directement au 
réseau FC plutôt qu'à travers un ordinateur. Niveau bande passante, le 
FC est présenté comme étant relativement rapide, avec un taux s'étendant 
de 133 à 1062 Mbits/s. Si le FC tend à devenir populaire en tant que 
solution haut-de-gamme de remplacement du SCSI, il pourrait rapidement 
devenir une technologie très abordable. Pour le moment, ce n'est pas 
abordable, et ce n'est pas pris en charge par Linux. La Fibre Channel 
Association tient une importante collection de références au FC, sur 
<a class="ulink" href="http://www.fibrechannel.org" target="_top">http://www.fibrechannel.org</a><a href="#ftn.d0e2465" class="footnote" id="d0e2465"><sup class="footnote">[13]</sup></a>.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e2478"/>3.2.8. FireWire (IEEE 1394)</h4></div></div></div><p>

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
Prise en charge par Linux : <span class="emphasis"><em>non</em></span><a href="#ftn.d0e2489" class="footnote" id="d0e2489"><sup class="footnote">[14]</sup></a>
</p></li><li class="listitem"><p>
Bande passante maximum : <span class="emphasis"><em>196,608 Mbits/s</em></span> (bientôt, <span class="emphasis"><em>393,216 Mbits/s</em></span>)
</p></li><li class="listitem"><p>
Temps de latence minimum : <span class="emphasis"><em>?</em></span>
</p></li><li class="listitem"><p>
Disponibilité : <span class="emphasis"><em>différents fabricants</em></span>
</p></li><li class="listitem"><p>
Interface ou bus utilisé : <span class="emphasis"><em>PCI</em></span>
</p></li><li class="listitem"><p>
Structure du réseau : <span class="emphasis"><em>aléatoire, sans cycles (auto-configuré)</em></span>
</p></li><li class="listitem"><p>
Coût par machine connectée : <span class="emphasis"><em>600 dollars</em></span>
</p></li></ul></div><p>

</p><p>
FireWire, ou standard IEEE 1394-1995, est voué à être le réseau numérique
à grande vitesse et à prix réduit des appareils électroniques domestiques.
Son application-phare est la connexion des caméscopes numériques aux
ordinateurs, mais FireWire est destiné à être utilisé dans des domaines
s'étendant de l'alternative au SCSI jusqu'à l'interconnexion des différents
composants de votre <span class="quote">« <span class="quote">Home Cinéma</span> »</span>. Il vous permet de relier plus de
64000 périphériques dans une topologie utilisant des bus et des ponts
mais ne formant pas de boucle, et détecte automatiquement la configuration
des périphériques lorsqu'ils sont ajoutés ou retirés. Les messages courts
(les <span class="quote">« <span class="quote">quadlets</span> »</span>, longs de quatre octets) sont également pris en charge,
de même que les transmissions isochrones sur le modèle de l'ATM (utilisées
pour préserver le synchronisme des messages multimédia). Adaptec propose
des produits FireWire permettant de relier jusqu'à 63 périphériques
à une seule carte PCI, et tient aussi un bon site d'information générale
concernant le FireWire sur
<a class="ulink" href="http://www.adaptec.com/worldwide/product/prodtechindex.html?cat=%2fTechnology%2fFireWire-1394&amp;prodkey=1394_summary" target="_top">http://www.adaptec.com</a>.
</p><p>
Bien que le FireWire ne soit pas le réseau le plus rapide disponible
actuellement, le marché de la grande distribution (qui tire les prix
vers le bas) et les temps de latence réduits pourraient en faire d'ici
l'an prochain la meilleure interface réseau pour le <span class="emphasis"><em><span class="foreignphrase"><em class="foreignphrase">message passing</em></span></em></span> dans
un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> de PC sous Linux.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e2553"/>3.2.9. HiPPI et Serial HiPPI</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Prise en charge par Linux : 
<span class="emphasis"><em>non</em></span><a href="#ftn.d0e2562" class="footnote" id="d0e2562"><sup class="footnote">[15]</sup></a>

</p></li><li class="listitem"><p>

Bande passante maximum : <span class="emphasis"><em>1600 Mbits/s</em></span> 
(<span class="emphasis"><em>1200 Mb/s</em></span> pour Serial HiPPI)

</p></li><li class="listitem"><p>

Temps de latence minimum : <span class="emphasis"><em>?</em></span>

</p></li><li class="listitem"><p>

Disponibilité : <span class="emphasis"><em>différents fabricants</em></span>

</p></li><li class="listitem"><p>

Interface ou bus utilisé : <span class="emphasis"><em>EISA, PCI</em></span>

</p></li><li class="listitem"><p>

Structure du réseau : <span class="emphasis"><em>commutateurs</em></span>

</p></li><li class="listitem"><p>

Coût par machine connectée : <span class="emphasis"><em>3500 dollars</em></span> 
(<span class="emphasis"><em>4,500</em></span> dollars pour Serial HiPPI)

</p></li></ul></div><p>

HiPPI (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">High Performance Parallel 
Interface</em></span></span> »</span>, soit <span class="quote">« <span class="quote">Interface Parallèle aux 
Performances Élevées</span> »</span>) était initialement censée fournir un taux 
de transfert élevé pour l'échange d'immenses blocs de données entre un 
supercalculateur et une autre machine (un autre supercalculateur, un 
<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">frame buffer</em></span></span> »</span>, une batterie 
de disques, et cætera), et est devenu le standard dominant dans le monde 
des supercalculateurs. Bien que ce soit un oxymoron, <span class="emphasis"><em>Serial 
HiPPI</em></span> devient également très populaire en utilisant 
typiquement de la fibre optique à la place des câbles HiPPI standard de 
32 bits de large (donc parallèles). Ces dernières années, les 
commutateurs HiPPI en croix sont devenus courants et les prix ont 
sérieusement chuté. Malheureusement, les équipement HiPPI Série, eux, 
sont encore très onéreux, et sont en général les seuls pris en charge 
par le bus PCI. Pire, Linux ne gère pas encore HiPPI. Le CERN tient une 
bonne présentation d'HiPPI sur <a class="ulink" href="http://www.cern.ch/HSI/hippi/" target="_top">http://www.cern.ch/HSI/hippi/</a>. Ils tiennent aussi une liste 
assez longue de distributeurs proposant le HiPPI sur <a class="ulink" href="http://www.cern.ch/HSI/hippi/procintf/manufact.htm" target="_top">http://www.cern.ch/HSI/hippi/procintf/manufact.htm</a>.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e2628"/>3.2.10. IrDA (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Infrared Data Association</em></span></span> »</span>)</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Prise en charge par Linux : <span class="emphasis"><em>non 
(?)</em></span><a href="#ftn.d0e2641" class="footnote" id="d0e2641"><sup class="footnote">[16]</sup></a>

</p></li><li class="listitem"><p>

Bande passante maximum : <span class="emphasis"><em>1,15 Mbits/s</em></span> et 
<span class="emphasis"><em>4 Mbits/s</em></span>

</p></li><li class="listitem"><p>

Temps de latence minimum : <span class="emphasis"><em>?</em></span>

</p></li><li class="listitem"><p>

Disponibilité : <span class="emphasis"><em>Différents fabricants</em></span>

</p></li><li class="listitem"><p>

Interface ou bus utilisé : <span class="emphasis"><em>IrDA</em></span>

</p></li><li class="listitem"><p>

Structure réseau : <span class="emphasis"><em>Air libre</em></span> ;-)

</p></li><li class="listitem"><p>

Coût par machine connectée : <span class="emphasis"><em>0</em></span>

</p></li></ul></div><p>

L'IrDA (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Infrared Data 
Association</em></span></span> »</span> ou <span class="quote">« <span class="quote">Association de Données par 
Infrarouges</span> »</span>, sur <a class="ulink" href="http://www.irda.org" target="_top">http://www.irda.org</a>), c'est ce 
petit appareil à infrarouges sur le coté des ordinateurs portables. Il 
reste assez difficile, par conception, de relier plus de deux 
ordinateurs par ce biais, aussi l'IrDA ne se prête-t-il guère à la 
<span class="quote">« <span class="quote">clusterisation</span> »</span>, ou mise en parallèle massive de 
nombreuses machines. Don Becker est toutefois l'auteur de quelques 
travaux préliminaires sur l'IrDA.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e2698"/>3.2.11. Myrinet</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Prise en charge par Linux : <span class="emphasis"><em>bibliothèques</em></span>

</p></li><li class="listitem"><p>

Bande passante maximum : <span class="emphasis"><em>1280 Mbits/s</em></span>

</p></li><li class="listitem"><p>

Temps de latence minimum : <span class="emphasis"><em>9 microsecondes</em></span>

</p></li><li class="listitem"><p>

Disponibilité : <span class="emphasis"><em>matériel propriétaire.</em></span>

</p></li><li class="listitem"><p>

Interface ou bus utilisés : <span class="emphasis"><em>PCI</em></span>

</p></li><li class="listitem"><p>

Structure du réseau : <span class="emphasis"><em>commutateurs</em></span>

</p></li><li class="listitem"><p>

Coût par machine connectée : <span class="emphasis"><em>1800 dollars</em></span>

</p></li></ul></div><p>

<a class="ulink" href="http://www.myri.com" target="_top">Myrinet</a> est un réseau local 
(LAN : <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Local Area 
Network</em></span></span> »</span>) conçu pour servir également de réseau 
système <a href="#ftn.d0e2753" class="footnote" id="d0e2753"><sup class="footnote">[17]</sup></a>. Les versions LAN et SAN utilisent des médias 
physiques distincts et leur caractéristiques sont sensiblement 
différentes. La version SAN est généralement utilisée au sein d'un 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span>.

</p><p>

La structure de Myrinet est très conventionnelle, mais a la réputation
d'être très bien implémentée. Les pilotes pour Linux sont connus pour
donner de très bons résultats, bien qu'il eût été fait état de frappantes
différences de performances d'une implémentation du bus PCI à l'autre.

</p><p>

Actuellement, Myrinet est assurément le réseau favori des responsables 
de <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> n'étant pas trop sévèrement 
limité au niveau budgétaire. Si, pour vous, un PC Linux typique est un 
Pentium Pro dernier cri ou un Pentium II avec au moins 256 Mo de mémoire 
vive, et un disque RAID et SCSI, alors le coût de Myrinet apparaît 
raisonnable. En revanche, avec des machines plus conventionnelles, il 
vous faudra probablement choisir entre relier <span class="emphasis"><em>N</em></span> 
machines avec Myrinet, ou <span class="emphasis"><em>2N</em></span> machines avec 
plusieurs équipements de type <span class="quote">« <span class="quote">Fast Ethernet</span> »</span> ou 
<span class="quote">« <span class="quote">TTL_PAPERS</span> »</span>. Tout cela dépend réellement de votre budget 
et du type de calcul qui vous importe le plus.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e2789"/>3.2.12. Parastation</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Prise en charge par Linux : <span class="emphasis"><em>couches d'abstraction 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">HAL</em></span></span> »</span>) ou bibliothèques 
réseau</em></span>

</p></li><li class="listitem"><p>

Bande passante maximum : <span class="emphasis"><em>125 Mbits/s</em></span>

</p></li><li class="listitem"><p>

Temps de latence minimum : <span class="emphasis"><em>2 microsecondes</em></span>

</p></li><li class="listitem"><p>

Disponibilité : <span class="emphasis"><em>fabricant exclusif</em></span>

</p></li><li class="listitem"><p>

Interface ou bus utilisé : <span class="emphasis"><em>PCI</em></span>

</p></li><li class="listitem"><p>

Structure du réseau : <span class="emphasis"><em>maillage, sans concentrateur</em></span>

</p></li><li class="listitem"><p>

Coût par machine connectée : <span class="emphasis"><em>plus de 1000 dollars</em></span>

</p></li></ul></div><p>

Le projet ParaStation (<a class="ulink" href="http://wwwipd.ira.uka.de/parastation" target="_top">http://wwwipd.ira.uka.de/parastation</a>) de la section informatique 
de l'Université de Karlsruhe est en train de mettre sur pieds un réseau 
<span class="quote">« <span class="quote">maison</span> »</span> compatible PVM et aux temps de latence réduits. 
Ils ont d'abord construit un prototype de ParaPC biprocesseur en 
utilisant une carte EISA conçue sur mesure et des PC fonctionnant sous 
Unix BSD, puis ont bâti de plus grands 
<span class="foreignphrase"><em class="foreignphrase">clusters</em></span> composés de machines Alpha DEC. 
Depuis Janvier 1997, Parastation est disponible sous Linux. Les cartes 
PCI sont produites en coopération avec une société nommée <a class="ulink" href="http://www.hitex.com" target="_top">Hitex</a>. Le matériel de Parastation 
implémente à la fois un système de transmission de messages rapide et 
fiable, et des barrières de synchronisation simples.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e2852"/>3.2.13. PLIP</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
Prise en charge par Linux : <span class="emphasis"><em>pilotes du noyau</em></span>
</p></li><li class="listitem"><p>
Bande passante maximum : <span class="emphasis"><em>1,2 Mbits/s</em></span>
</p></li><li class="listitem"><p>
Temps de latence minimum : <span class="emphasis"><em>1000 microsecondes ?</em></span>
</p></li><li class="listitem"><p>
Disponibilité : <span class="emphasis"><em>grande distribution</em></span>
</p></li><li class="listitem"><p>
Interface ou bus utilisé : <span class="emphasis"><em>SPP</em></span>
</p></li><li class="listitem"><p>
Structure du réseau : <span class="emphasis"><em>câble entre 2 machines</em></span>
</p></li><li class="listitem"><p>
Coût par machine connectée : <span class="emphasis"><em>2 dollars</em></span>
</p></li></ul></div><p>

Pour le seul coût d'un câble <span class="quote">« <span class="quote">LapLink</span> »</span> (N.D.T. : câble 
parallèle croisé), PLIP (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Parallel Line Interface 
Protocol</em></span></span> »</span>, soit <span class="quote">« <span class="quote">Protocole d'Interface par 
Ligne Parallèle</span> »</span>) permet à deux machines Linux de communiquer par 
le port parallèle en utilisant les couches logicielles standard basées 
sur la communication par <span class="quote">« <span class="quote">sockets</span> »</span>. En termes de bande 
passante, de temps de latence et d'évolutivité, il ne s'agit pas d'une 
technologie réseau sérieuse. En revanche, le coût de revient quasi-nul 
et la compatibilité logicielle s'avèrent être très utiles. Le pilote est 
partie intégrante du noyau Linux standard.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e2913"/>3.2.14. SCI</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Prise en charge par Linux : <span class="emphasis"><em>non</em></span>

</p></li><li class="listitem"><p>

Bande passante maximum : <span class="emphasis"><em>4000 Mbit/s</em></span>

</p></li><li class="listitem"><p>

Temps de latence minimum : <span class="emphasis"><em>2,7 microsecondes</em></span>

</p></li><li class="listitem"><p>

Disponibilité : <span class="emphasis"><em>différents fabricants.</em></span>

</p></li><li class="listitem"><p>

Interface ou bus utilisé : <span class="emphasis"><em>PCI et propriétaire</em></span>

</p></li><li class="listitem"><p>

Structure réseau : <span class="emphasis"><em>?</em></span>

</p></li><li class="listitem"><p>

Coût par machine connectée : <span class="emphasis"><em>+ de 1000 dollars</em></span>

</p></li></ul></div><p>

L'objectif de SCI (Scalable Coherent Interconnect, ANSI/IEEE 1596-1992) 
consiste essentiellement à fournir un mécanisme de haute performance 
pouvant assurer des accès cohérents à la mémoire partagée au travers 
d'un grand nombre de machines. On peut dire sans se mouiller que la 
bande passante et les temps de latences de SCI sont <span class="quote">« <span class="quote">très 
impressionnants</span> »</span> comparés à la plupart des autres technologies 
réseau. Le problème est que SCI n'est pas très répandu et reste donc 
assez onéreux, et que ce matériel n'est pas pris en charge par Linux.

</p><p>

SCI est principalement utilisé dans diverses implémentations 
propriétaires pour des machines à mémoire partagée logiquement et 
distribuée physiquement, comme le HP/Convex Exemplar SPP et le Sequent 
NUMA-Q 2000 (voir <a class="ulink" href="http://www.sequent.com" target="_top">http://www.sequent.com</a><a href="#ftn.d0e2967" class="footnote" id="d0e2967"><sup class="footnote">[18]</sup></a>). Ceci dit, SCI est disponible sous forme de 
carte PCI et de commutateurs quatre ports de Dolphin (on peut relier 
ainsi jusqu'à 16 machines en montant ces commutateurs en cascade), 
<a class="ulink" href="http://www.dolphinics.com" target="_top">http://www.dolphinics.com</a>, sous la série "Clustar". Le 
CERN tient à jour une bonne collection de liens concernant SCI sur 
<a class="ulink" href="http://www.cern.ch/HSI/sci/sci.html" target="_top">http://www.cern.ch/HSI/sci/sci.html</a>.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e2975"/>3.2.15. SCSI</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Prise en charge par Linux : <span class="emphasis"><em>pilotes du noyau</em></span>

</p></li><li class="listitem"><p>

Bande passante maximum : de <span class="emphasis"><em>5 Mbits/s</em></span> à plus 
de <span class="emphasis"><em>20 Mbits/s</em></span>

</p></li><li class="listitem"><p>

Temps de latence minimum : <span class="emphasis"><em>?</em></span>

</p></li><li class="listitem"><p>

Disponibilité : <span class="emphasis"><em>différents fabricants</em></span>

</p></li><li class="listitem"><p>

Interface ou bus utilisé : <span class="emphasis"><em>cartes PCI, EISA ou 
ISA</em></span>

</p></li><li class="listitem"><p>

Structure du réseau : <span class="emphasis"><em>bus inter-machines partageant des 
périphériques SCSI</em></span>

</p></li><li class="listitem"><p>

Coût par machine connectée : <span class="emphasis"><em>?</em></span>

</p></li></ul></div><p>

Le SCSI (Small Computer Systems Interconnect) consiste essentiellement 
en un bus d'entrée/sortie utilisé par les disques durs, les lecteurs de 
CD-ROM, les numériseurs 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">scanners</em></span></span> »</span>), et cætera. Il 
existe trois standards distincts : SCSI-1, SCSI-2 et SCSI-3, en 
vitesses "Fast" et "Ultra" et en largeur de bus de 8, 16 ou 32 bits 
(avec compatibilité FireWire annoncée pour SCSI-3). Tout cela est plutôt 
confus, mais nous savons tous qu'un bon SCSI est bien plus rapide que 
l'EIDE, et peut gérer plus de périphériques, plus efficacement.

</p><p>

Ce que beaucoup de gens ne réalisent pas, c'est qu'il est très simple de 
partager le même bus SCSI entre deux ordinateurs. Ce type de 
configuration est très utile pour partager des disques entre deux 
machines et mettre en place un système de 
<span class="emphasis"><em><span class="foreignphrase"><em class="foreignphrase">fail-over</em></span></em></span>, de façon 
à ce qu'une machine prenne à sa charge les requêtes à une base de 
données lorsque l'autre machine tombe en panne. C'est actuellement le 
seul mécanisme reconnu par le <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> PC 
de Microsoft : WolfPack. En revanche, l'incapacité du SCSI à 
évoluer vers de plus grands systèmes le rend en général inintéressant 
pour le traitement en parallèle.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e3039"/>3.2.16. ServerNet</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Prise en charge par Linux : <span class="emphasis"><em>non</em></span>

</p></li><li class="listitem"><p>

Maximum bandwidth : <span class="emphasis"><em>400 Mbits/s</em></span>

</p></li><li class="listitem"><p>

Temps de latence minimum : <span class="emphasis"><em>3 microsecondes</em></span>

</p></li><li class="listitem"><p>

Disponibilité : <span class="emphasis"><em>fabricant exclusif</em></span>

</p></li><li class="listitem"><p>

Interface ou bus utilisé : <span class="emphasis"><em>PCI</em></span>

</p></li><li class="listitem"><p>

Structure du réseau : <span class="emphasis"><em>arbre hexagonal / concentrateurs en 
mailles tétraédriques</em></span>

</p></li><li class="listitem"><p>

Coût par machine connectée : <span class="emphasis"><em>?</em></span>

</p></li></ul></div><p>

ServerNet est la solution réseau de haute performance proposée par 
Tandem (<a class="ulink" href="http://www.tandem.com" target="_top">http://www.tandem.com</a>). Dans le monde du 
traitement des transactions en ligne (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">OnLine 
Transation Processing</em></span></span> »</span>, ou <span class="quote">« <span class="quote">OLTP</span> »</span>) 
en particulier, Tandem est réputé être l'un des premiers fabricants de 
systèmes de haute fiabilité, aussi n'est-il pas surprenant que leurs 
réseaux ne revendiquent pas simplement la haute performance, mais aussi 
la <span class="quote">« <span class="quote">haute fiabilité et intégrité des données</span> »</span>. Une autre 
facette intéressante de ServerNet : ce matériel serait capable de 
transférer des données directement de périphérique à périphérique, pas 
simplement entre processeurs, mais également entre disques durs, et 
cætera, dans un style unilatéral similaire à ce qui a été suggéré pour 
les mécanismes d'accès à distance à la mémoire du MPI, décrits dans la 
section 3.5. Un dernier mot à propos de Servernet : Bien qu'il n'y 
ait qu'un seul fabricant, celui-ci est suffisamment puissant pour faire 
établir potentiellement Servernet en tant que standard majeur : 
Tandem appartient à Compaq<a href="#ftn.d0e3099" class="footnote" id="d0e3099"><sup class="footnote">[19]</sup></a>.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e3103"/>3.2.17. SHRIMP</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Prise en charge par Linux : <span class="emphasis"><em>interface utilisateur à 
mémoire mappée</em></span>

</p></li><li class="listitem"><p>

Bande passante maximum : <span class="emphasis"><em>180 Mbits/s</em></span>

</p></li><li class="listitem"><p>

Temps de latence minimum : <span class="emphasis"><em>5 microsecondes</em></span>

</p></li><li class="listitem"><p>

Disponibilité : <span class="emphasis"><em>prototype expérimental</em></span>

</p></li><li class="listitem"><p>

Interface ou bus utilisé : <span class="emphasis"><em>EISA</em></span>

</p></li><li class="listitem"><p>

Structure du réseau : <span class="emphasis"><em>Fond de panier en maille (comme 
pour le Paragon d'Intel)</em></span>

</p></li><li class="listitem"><p>

Coût par machine connectée : <span class="emphasis"><em>?</em></span>

</p></li></ul></div><p>

Le projet <a class="ulink" href="http://www.cs.princeton.edu/shrimp/" target="_top">SHRIMP</a> de la section 
des sciences des ordinateurs de l'Université de Princeton, met sur pieds 
un ordinateur parallèle en utilisant dont les éléments de traitement 
sont des ordinateurs PC sous Linux. Le premier SHRIMP 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Scalable, High-Performance, Really Inexpensive 
Multi-Processor</em></span></span> »</span>, soit <span class="quote">« <span class="quote">multiprocesseur 
évolutif et de hautes performances vraiment bon marché</span> »</span>) était un 
simple prototype biprocesseur utilisant une mémoire partagée sur une 
carte EISA développée pour l'occasion. Il existe désormais un prototype 
pouvant évoluer vers de plus larges configurations en utilisant une 
interface <span class="quote">« <span class="quote">maison</span> »</span> pour se connecter à une sorte de 
concentrateur, essentiellement conçu comme le réseau de routage en 
mailles utilisé dans le Paragon d'Intel. Des efforts considérables ont 
été faits pour développer une électronique de <span class="quote">« <span class="quote">communication 
mappée en mémoire virtuelle</span> »</span> aux 
<span class="foreignphrase"><em class="foreignphrase">overheads</em></span> réduits, avec sa couche 
logicielle.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e3170"/>3.2.18. SLIP</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Prise en charge par Linux : <span class="emphasis"><em>pilotes du noyau</em></span>

</p></li><li class="listitem"><p>

Bande passante maximum : <span class="emphasis"><em>0,1 Mbits/s</em></span>

</p></li><li class="listitem"><p>

Temps de latence minimum : <span class="emphasis"><em>1000 microsecondes ?</em></span>

</p></li><li class="listitem"><p>

Disponibilité : <span class="emphasis"><em>grande distribution</em></span>

</p></li><li class="listitem"><p>

Interface ou bus utilisé : <span class="emphasis"><em>RS232C</em></span>

</p></li><li class="listitem"><p>

Structure du réseau : <span class="emphasis"><em>câble entre deux machines</em></span>

</p></li><li class="listitem"><p>

Coût par machine connectée : <span class="emphasis"><em>2 dollars</em></span>

</p></li></ul></div><p>

Même si SLIP (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Serial Line Interface 
Protocol</em></span></span> »</span>) se situe définitivement au pied de 
l'échelle des performances, ce protocole (tout comme CSLIP ou PPP) 
permet à deux machines de communiquer en utilisant les 
<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">sockets</em></span></span> »</span> et ce au travers 
d'un câble RS232 ordinaire. Les ports RS232 peuvent être reliés à l'aide 
d'un câble série type NULL-MODEM, ou même au travers d'une ligne 
téléphonique en utilisant des modems. Dans tous les cas, les temps de 
latence sont élevés, et la bande passante réduite. Aussi, SLIP ne 
devrait être utilisé qu'en dernier recours. En revanche, la plupart des 
PC sont dotés de deux ports RS232. Il doit donc être possible de relier 
un groupe de machines sous forme de réseau linéaire ou d'anneau. Il 
existe même un logiciel de répartition de la charge appelé EQL.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e3226"/>3.2.19. TTL_PAPERS</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Prise en charge par Linux : <span class="emphasis"><em>bibliothèque AFAPI</em></span>

</p></li><li class="listitem"><p>

Bande passante maximum : <span class="emphasis"><em>1,6 Mbits/s</em></span>

</p></li><li class="listitem"><p>

Temps de latence minimum : <span class="emphasis"><em>3 microsecondes</em></span>

</p></li><li class="listitem"><p>

Disponibilité : <span class="emphasis"><em>conception dans le domaine public, 
fabricant exclusif</em></span>

</p></li><li class="listitem"><p>

Interface ou bus utilisé : <span class="emphasis"><em>SPP (port parallèle)</em></span>

</p></li><li class="listitem"><p>

Structure du réseau : <span class="emphasis"><em>arbre de concentrateurs</em></span>

</p></li><li class="listitem"><p>

Coût par machine connectée : <span class="emphasis"><em>100 dollars</em></span>

</p></li></ul></div><p>

Le projet PAPERS (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Purdue's Adapter for Parallel 
Execution and Rapid Synchronization</em></span></span> »</span>, soit 
<span class="quote">« <span class="quote">Adaptateur pour l'Exécution en Parallèle et la Synchronisation 
Rapide de l'université de Purdue</span> »</span>), mené par la Purdue University 
School of Electrical and Computer Engineering (<span class="quote">« <span class="quote">École Supérieure 
d'Électricité et d'Ingénierie en Informatique</span> »</span>), développe un 
ensemble logiciel et matériel évolutif et aux temps de latence réduits 
pour les communications des fonctions d'agrégation, permettant de mettre 
sur pieds un supercalculateur en parallèle utilisant comme nœuds 
des PC d'origine, non modifiés.

</p><p>

Plus d'une douzaine de versions de cartes <span class="quote">« <span class="quote">PAPERS</span> »</span>, reliées 
au PC à la station de travail via le port parallèle standard (SPP : 
<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Standard Parallel Port</em></span></span> »</span>), 
ont été construites, en suivant globalement deux grands axes. Les 
versions estampillées <span class="quote">« <span class="quote">PAPERS</span> »</span> visent les hautes 
performances, quelle que soit la technologie la plus indiquée, la 
version actuelle utilisant des FPGA (N.D.T. : famille de réseaux 
logiques programmables), et des modèles d'interfaces PCI à haut débit 
sont actuellement à l'étude. Par opposition, les versions nommées 
<span class="quote">« <span class="quote">TTL_PAPERS</span> »</span> sont conçues pour être facilement reproduites 
hors de l'université de Purdue, et s'appuient sur des modèles du domaine 
public remarquablement simples et qui peuvent être mis en place en 
utilisant de la logique TTL ordinaire. L'une de ces versions est 
produite commercialement.

</p><p>

Contrairement au matériel sur mesure conçu par d'autres universités, des 
<span class="foreignphrase"><em class="foreignphrase">clusters</em></span> TTL_PAPERS ont été assemblés 
dans plusieurs écoles depuis les États-Unis jusqu'en Corée du Sud. La 
bande passante est sévèrement limitée par la connectivité du port 
parallèle, mais PAPERS met en œuvre des fonctions d'agrégation aux 
temps de latence très réduits. Même les systèmes orientés messages les 
plus rapides ne peuvent offrir de telles performances sur ces fonctions 
d'agrégation. Ainsi, PAPERS est particulièrement performant dans la 
synchronisation des différents écrans d'un mur vidéo (à débattre dans le 
<span class="foreignphrase"><em class="foreignphrase">Video-Wall-HOWTO</em></span> actuellement en 
préparation), pour planifier les accès à un réseau à haut débit, pour 
évaluer les probabilités en recherche génétique, et cætera. Même si des 
<span class="foreignphrase"><em class="foreignphrase">clusters</em></span> PAPERS ont été construits en 
utilisant AIX d'IBM sur PowerPC, des DEC Alpha OSF/1, ou HP-UX sur HP 
PA-RISC, le PC sous Linux reste la plate-forme la mieux prise en charge.

</p><p>

Les programmes utilisateur utilisant l'AFAPI de TTL_PAPERS attaquent 
directement les registres matériels du port parallèle sous Linux, sans 
effectuer d'appel système à chaque accès. Pour ce faire, l'AFAPI demande 
d'abord les droits d'accès au port parallèle en utilisant soit 
<code class="literal">iopl()</code>, soit <code class="literal">ioperm()</code>. Le problème 
est que, l'un comme l'autre, ces appels obligent le programme appelant à 
être privilégié, ce qui introduit une faille de sécurité potentielle. La 
solution réside en un correctif optionnel à appliquer au noyau Linux et 
permettant à un processus privilégié de contrôler les permissions 
d'accès aux ports d'entrée/sortie pour n'importe quel autre processus.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e3318"/>3.2.20. USB (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Universal Serial Bus</em></span></span> »</span>)</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Prise en charge par Linux : <span class="emphasis"><em>pilotes du noyau</em></span>

</p></li><li class="listitem"><p>

Bande passante maximum : <span class="emphasis"><em>12 Mbits/s</em></span>

</p></li><li class="listitem"><p>

Temps de latence minimum : <span class="emphasis"><em>?</em></span>

</p></li><li class="listitem"><p>

Disponibilité : <span class="emphasis"><em>dans le commerce</em></span>

</p></li><li class="listitem"><p>

Interface ou bus utilisé : <span class="emphasis"><em>USB</em></span>

</p></li><li class="listitem"><p>

Structure du réseau : <span class="emphasis"><em>bus</em></span>

</p></li><li class="listitem"><p>

Coût par machine connectée : <span class="emphasis"><em>5 dollars</em></span>

</p></li></ul></div><p>

USB (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Universal Serial Bus</em></span></span> »</span>, 
<a class="ulink" href="http://www.usb.org" target="_top">http://www.usb.org</a>) est un bus fonctionnant à la vitesse 
de l'Ethernet conventionnel, dont les périphériques qui s'y rattachent 
peuvent être connectés à chaud 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Hot-Plug</em></span></span> »</span> : sans 
imposer la mise hors tension préalable du bus) et pouvant accueillir simultanément 
jusqu'à 127 de ces périphériques pouvant s'étendre du clavier à la 
caméra de vidéo-conférence. La manière dont on relie plusieurs 
ordinateurs par le biais de l'USB n'est pas clairement définie. Quoi 
qu'il en soit, les ports USB sont en train de s'établir très rapidement 
en standard sur les cartes-mères, au même titre que le port série RS232 
ou le port parallèle, aussi ne soyez pas surpris si vous voyez 
apparaître un ou deux ports USB <a href="#ftn.d0e3380" class="footnote" id="d0e3380"><sup class="footnote">[20]</sup></a> sur votre prochain PC.

</p><p>
D'une certaine manière, l'USB est pratiquement la version basse performance
à prix nul du FireWire que l'on peut se procurer aujourd'hui.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e3386"/>3.2.21. WAPERS</h4></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Prise en charge par Linux : <span class="emphasis"><em>bibliothèque AFAPI</em></span>

</p></li><li class="listitem"><p>

Bande passante maximum : <span class="emphasis"><em>0,4 Mbits/s</em></span>

</p></li><li class="listitem"><p>

Temps de latence : <span class="emphasis"><em>3 microsecondes</em></span>

</p></li><li class="listitem"><p>

Disponibilité : <span class="emphasis"><em>modèle dans le domaine public</em></span>

</p></li><li class="listitem"><p>

Interface ou bus utilisé : <span class="emphasis"><em>SPP (Port Parallèle Standard)</em></span>

</p></li><li class="listitem"><p>

Structure du réseau : <span class="emphasis"><em>modèle de câblage entre 2 à 64 machines</em></span>

</p></li><li class="listitem"><p>

Coût par machine connectée : <span class="emphasis"><em>5 dollars</em></span>

</p></li></ul></div><p>

WAPERS (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Wired-AND Adapter for Parallel Execution 
and Rapid Synchronization</em></span></span> »</span>, soit 
<span class="quote">« <span class="quote">Adaptateur par ET Câblé pour l'Exécution en Parallèle et la 
Synchronisation Rapide</span> »</span>) est une des facettes du projet PAPERS, 
de la Purdue University School of Electrical and Computer Engineering 
(<span class="quote">« <span class="quote">École Supérieure d'Électricité et d'Ingénierie en 
Informatique</span> »</span>). S'il est construit proprement, le port parallèle 
possède quatre bits de sortie à collecteur ouvert qui peuvent être 
câblés entre eux pour former un ET câblé de 4 bits de large. Ce ET câblé 
est assez sensible électriquement, et le nombre maximum de machines qui 
peuvent y être reliées dépend de façon critique des propriétés 
analogiques des ports (les limites maximum des puits de courant et les 
valeurs des résistances de <span class="foreignphrase"><em class="foreignphrase">pull-up</em></span>). On 
peut typiquement relier 7 à 8 machines en réseau de cette façon, avec 
WAPERS. Bien que les coûts et les temps de latences soient très réduits, 
la bande passante l'est aussi. WAPERS est donc bien plus indiqué comme 
réseau secondaire dédié aux fonctions d'agrégations que comme unique 
réseau d'un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span>. Comme pour 
TTL_PAPERS, il existe un correctif noyau visant à améliorer la sécurité, 
recommandé mais non requis.

</p></div></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e3450"/>3.3. Interface Logicielle Réseau</h3></div></div></div><p>

Avant d'explorer les ressources logicielles existantes en matière de 
traitement en parallèle, il est utile de couvrir rapidement les bases de 
l'interface logicielle de bas niveau gérant l'électronique du réseau. Il 
n'existe en réalité que trois options de base : les 
<span class="foreignphrase"><em class="foreignphrase">sockets</em></span>, les pilotes de périphériques et 
les bibliothèques utilisateur.

</p><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e3458"/>3.3.1. Les <span class="foreignphrase"><em class="foreignphrase">sockets</em></span></h4></div></div></div><p>

Le <span class="foreignphrase"><em class="foreignphrase">socket</em></span> est de loin la plus courante 
des interfaces réseau de bas niveau. Les 
<span class="foreignphrase"><em class="foreignphrase">sockets</em></span> sont partie intégrante d'Unix 
depuis plus d'une décennie et la plupart des standards dans le domaine 
du matériel électronique de réseau est conçue pour prendre en charge au 
moins deux types de protocoles de 
<span class="foreignphrase"><em class="foreignphrase">socket</em></span> : TCP et UDP. Ces deux types 
de <span class="foreignphrase"><em class="foreignphrase">sockets</em></span> vous permettent d'envoyer des 
blocs de données d'une longueur arbitraire d'une machine à l'autre, mais 
il existe plusieurs différences importantes. Typiquement, ils engendrent 
tous deux un temps de latence minimum d'environ 1000 microsecondes, même 
si les performances peuvent bien pires encore en fonction du trafic.

</p><p>

Ces types de <span class="foreignphrase"><em class="foreignphrase">sockets</em></span> constituent 
l'interface logicielle réseau de base pour la majorité des logiciels de 
traitement en parallèle portables et de plus haut niveau. Par exemple, 
PVM utilise une combinaison de l'UDP et du TCP, aussi en connaître les 
différences vous aidera à affiner les performances de votre système. Ce 
qui suit n'est qu'un aperçu de TCP et UDP. Référez-vous aux pages du 
manuel et à un bon livre de programmation pour plus de détails.

</p><div class="sect4"><div class="titlepage"><div><div><h5 class="title"><a id="d0e3482"/>3.3.1.1. Le protocole UDP (SOCK_DGRAM)</h5></div></div></div><p>

<span class="emphasis"><em>UDP</em></span> signifie <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">User Datagram 
Protocol</em></span></span> »</span> ou <span class="quote">« <span class="quote">Protocole de Datagrammes 
Utilisateur</span> »</span> mais il est plus facile de se souvenir des 
propriétés d'UDP en tant que <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Unreliable Datagram 
Processing</em></span></span> »</span>, ou <span class="quote">« <span class="quote">Traitement des Datagrammes 
Peu fiable</span> »</span>. En d'autres termes, UDP permet à chaque bloc d'être 
émis comme un message individuel, mais un message peut être perdu 
pendant la transmission. De fait, selon l'état du trafic sur le réseau, 
certains messages UDP peuvent être perdus, arriver plusieurs fois, ou 
arriver dans un ordre différent de celui dans lequel ils ont été émis. 
L'expéditeur d'un message UDP ne reçoit pas systématiquement d'accusé de 
réception, et c'est donc au programme écrit par l'utilisateur qu'il 
appartient de détecter et compenser ces problèmes. Heureusement, le 
protocole UDP garantit que si un message arrive, son contenu sera intact 
(c'est-à-dire que vous ne recevrez jamais un message incomplet).

</p><p>

Le bon coté de l'UDP est qu'il tend à être le plus rapide des protocoles 
des <span class="foreignphrase"><em class="foreignphrase">socket</em></span>. En outre, UDP est 
<span class="quote">« <span class="quote">orienté hors connexion</span> »</span> 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">connectionless</em></span></span> »</span>), ce qui 
signifie que chaque message est essentiellement indépendant des autres. 
On peut comparer chaque message à une lettre à La Poste. Vous pouvez 
envoyer plusieurs lettres à la même adresse, mais chacune d'entre elles 
est indépendante des autres, et vous n'êtes pas limité quant aux nombre 
de personnes à qui vous pouvez en envoyer.

</p></div><div class="sect4"><div class="titlepage"><div><div><h5 class="title"><a id="d0e3516"/>3.3.1.2. Le protocole TCP (SOCK_STREAM)</h5></div></div></div><p>

Contrairement à l'UDP, le <span class="emphasis"><em>TCP</em></span> est un protocole 
fiable et orienté connexion. Chaque bloc est considéré non pas comme un 
message, mais comme un bloc de données appartenant à un flot d'octets 
voyageant au travers d'une connexion établie entre l'expéditeur et le 
destinataire. Ce principe est très différent du système de messages de 
l'UDP car chaque bloc n'est qu'une partie du flot d'octets, et il 
appartient au programme utilisateur de trouver le moyen de les isoler 
car il n'y a aucune marque de séparation pour les distinguer. De plus, 
les connexions sont plus vulnérables aux perturbations du réseau, et 
seul un nombre limité de connexions simultanées peut exister au sein 
d'un même processus. Parce qu'il est fiable, le TCP engendre souvent des 
<span class="foreignphrase"><em class="foreignphrase">overheads</em></span> plus importants que l'UDP.

</p><p>

Le TCP réserve en revanche quelques bonnes surprises. Par exemple, si 
plusieurs messages sont envoyés à travers une connexion, TCP est capable 
de les rassembler dans une mémoire tampon pour mieux correspondre aux 
tailles standard des paquets de l'électronique du réseau, ce qui peut 
donner de meilleurs résultats que l'UDP dans le cas de groupes de 
messages courts ou de taille inhabituelle. Un autre avantage : Les 
réseaux bâtis sur des connexions physiques directes entre deux machines 
peuvent facilement et efficacement être assimilés à des connexions TCP. 
Ce fut le cas pour la <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Socket 
Library</em></span></span> »</span> (<span class="quote">« <span class="quote">bibliothèque de gestion de 
<span class="foreignphrase"><em class="foreignphrase">Sockets</em></span></span> »</span>), présentant une gestion 
compatible TCP au niveau de l'utilisateur qui ne différait des appels 
systèmes TCP standard que par le préfixe <code class="literal">PSS</code>, que 
l'on rajoutait au début du nom des fonctions à invoquer.

</p></div></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e3541"/>3.3.2. Les pilotes de périphériques</h4></div></div></div><p>

Lorsque l'on en arrive au stade où il faut effectivement injecter des 
données sur le réseau ou les y en extraire, l'interface logicielle des 
Unix standard fait partie du noyau et s'appelle <span class="quote">« <span class="quote">pilote</span> »</span> 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">driver</em></span></span> »</span>). UDP et TCP ne se 
contentent pas de transporter des données, ils s'accompagnent également 
d'importants <span class="foreignphrase"><em class="foreignphrase">overheads</em></span> dus à la gestion 
des <span class="foreignphrase"><em class="foreignphrase">sockets</em></span>. Par exemple, il faut que 
quelque chose s'occupe du fait que plusieurs connexions TCP peuvent 
partager la même interface réseau physique. Par opposition, un pilote de 
périphérique dédié à une interface réseau n'a besoin de mettre en 
œuvre qu'un petit nombre de fonctions de transport élémentaires. 
Ces pilotes peuvent alors être invoqués à l'aide de l'appel 
<code class="literal">open()</code> pour identifier le périphérique adéquat, puis 
en utilisant par exemple <code class="literal">read()</code> et 
<code class="literal">write()</code> sur le <span class="quote">« <span class="quote">fichier</span> »</span> ouvert. Ainsi, 
chaque opération peut transporter un bloc de données en coûtant à peine 
plus cher qu'un appel système, ce qui permet d'atteindre des délais de 
l'ordre de quelques dizaines de microsecondes.

</p><p>

Écrire un pilote de périphérique pour Linux n'est pas difficile… 
pourvu que vous sachiez <span class="emphasis"><em>parfaitement</em></span> comme 
fonctionne votre périphérique. Si vous n'en êtes pas sûr, n'essayez pas 
de le deviner. Déboguer un pilote de périphérique n'est pas une chose 
amusante, et faire des erreurs peut coûter la vie à votre matériel. En 
revanche, si ces risques ne vous effraient pas, il est possible d'écrire 
un pilote pour, par exemple, utiliser des cartes Ethernet dédiées comme 
des connexions machine-vers-machine <span class="quote">« <span class="quote">bêtes</span> »</span> mais très 
rapides car exonérées du protocole Ethernet habituel. Pour être exact, 
c'est pratiquement la technique utilisée par les premiers 
supercalculateurs Intel. Référez-vous au 
<span class="foreignphrase"><em class="foreignphrase">Device-Driver-HOWTO</em></span> pour plus 
d'informations.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e3582"/>3.3.3. Bibliothèques utilisateurs</h4></div></div></div><p>

Si vous avez pris des cours de programmation système, on a dù vous y 
apprendre qu'accéder directement aux registres matériels des 
périphériques à partir d'un programme utilisateur était l'exemple 
typique de ce qu'il ne faut pas faire, parce que l'un des principes même 
d'un système d'exploitation est de contrôler l'accès aux périphériques. 
Cependant, le simple fait de passer un appel système coûte au minimum 
quelques dizaines de microsecondes. Dans le cas d'interfaces réseau 
bâties sur mesure comme TTL_PAPERS, qui peut effectuer des opérations de 
base sur un réseau en seulement 3 microsecondes, un tel surcoût pour un 
appel système est intolérable. Le seul moyen d'éviter ce temps d'attente 
est de faire en sorte que du code s'exécutant au niveau de 
l'utilisateur, donc une <span class="quote">« <span class="quote">bibliothèque au niveau de 
l'utilisateur</span> »</span> <a href="#ftn.d0e3590" class="footnote" id="d0e3590"><sup class="footnote">[21]</sup></a>, puisse accéder directement au matériel, mais sans 
remettre en cause la souveraineté du système d'exploitation sur la 
gestion des droits d'accès aux ressources matérielles.

</p><p>
Sur un système typique, les seuls moyens, pour une bibliothèque utilisateur,
d'accéder directement aux registres du matériel sont les suivants :
</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>

Au lancement du programme utilisateur, faire un appel système pour 
mapper l'espace d'adressage qui contient les registres du périphérique 
dans le plan mémoire du processus utilisateur. Sur certains systèmes, 
l'appel système <code class="literal">mmap()</code> (traité pour la première fois 
dans la section 2.6) peut être utilisé pour mapper un fichier spécial 
représentant les adresses de la page de mémoire physique du 
périphérique. Il est en même temps relativement simple d'écrire un 
pilote de périphérique effectuant cette opération. De plus, ce pilote 
peut obtenir l'accès en ne mappant que la ou les pages qui contiennent 
les registres nécessaires, en maintenant ainsi le contrôle des droits 
d'accès sous la coupe du système d'exploitation.

</p></li><li class="listitem"><p>

Accéder ensuite aux registres du périphérique sans passer par un appel 
système en se contentant de charger ou de ranger des valeurs sur la 
plage d'adressage mappée. Par exemple, un

<code class="literal">*((char *) 0x1234) = 5;</code>

déposera un octet de valeur 5 à l'adresse mémoire 1234 en hexadécimal.

</p></li></ol></div><p>
Par bonheur, il se trouve que Linux pour Intel 386 et compatibles
offre une solution meilleure encore :
</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>

En invoquant l'appel système <code class="literal">ioperm()</code>
depuis un processus privilégié, obtenir la permission d'accéder
aux ports d'entrée/sortie correspondant précisément aux registres
du périphérique. Parallèlement, ces permissions peuvent être gérées
par un processus utilisateur privilégié et indépendant (autrement
dit : un <span class="quote">« <span class="quote">méta-système d'exploitation</span> »</span>) en utilisant l'appel
 système <span class="emphasis"><em>giveioperm()</em></span>, disponible sous la
forme d'un correctif à appliquer au noyau
Linux.

</p></li><li class="listitem"><p>

Accéder aux registres du périphérique sans appel système en
utilisant les instructions assembleur d'accès aux ports
d'entrée/sortie du 386.

</p></li></ol></div><p>
Cette seconde solution est préférable car il arrive souvent que
les registres de plusieurs périphériques soient réunis sur une
même page, auquel cas la première méthode ne pourrait offrir
de protection contre l'accès aux autres registres résidant dans
la même page que ceux appartenant au périphérique concerné.
L'inconvénient est que ces instructions ne peuvent bien sûr pas
être écrites en langage C. Il vous faudra à la place utiliser
un peu d'assembleur. La fonction utilisant l'assembleur en ligne
intégré à GCC (donc utilisable dans les programmes C) permettant
de lire un octet depuis un port est la suivante :
</p><pre class="programlisting">
extern inline unsigned char
inb(unsigned short port)
{
    unsigned char _v;
__asm__ __volatile__ ("inb %w1,%b0"
                      :"=a" (_v)
                      :"d" (port), "0" (0));
    return _v;
}
</pre><p>
La fonction symétrique permettant l'émission d'un octet est :
</p><p>

</p><pre class="programlisting">
extern inline void
outb(unsigned char value,
unsigned short port)
{
__asm__ __volatile__ ("outb %b0,%w1"
                      :/* pas de valeur retournée */
                      :"a" (value), "d" (port));
}
</pre><p>

</p></div></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e3641"/>3.4. PVM (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Parallel Virtual Machine</em></span></span> »</span>)</h3></div></div></div><p>

PVM (pour <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Parallel Virtual 
Machine</em></span></span> »</span>, soit <span class="quote">« <span class="quote">Machine Virtuelle en 
Parallèle</span> »</span>) est une bibliothèque de 
<span class="foreignphrase"><em class="foreignphrase">message-passing</em></span> portable et disponible 
gratuitement, s'appuyant généralement directement sur les 
<span class="foreignphrase"><em class="foreignphrase">sockets</em></span>. Cette bibliothèque s'est 
incontestablement établie comme le standard <span class="foreignphrase"><em class="foreignphrase">de 
facto</em></span> dans le domaine du traitement en parallèle à 
l'aide de <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> à transmission de 
messages.

</p><p>

PVM prend en charge les machines Linux monoprocesseur et SMP, comme les 
<span class="foreignphrase"><em class="foreignphrase">clusters</em></span> de machines Linux reliées entre 
elles à l'aide par des réseaux reconnaissant les 
<span class="foreignphrase"><em class="foreignphrase">sockets</em></span> (donc SLIP, PLIP, Ethernet, ATM). 
En fait, PVM fonctionnera même à travers un groupe de machines utilisant 
différents types de processeurs, de configurations et de réseaux 
physiques — Un <span class="emphasis"><em>cluster hétérogène</em></span> — 
même si l'envergure de ce <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> est de 
l'ordre de la mise en parallèle de machines en utilisant Internet pour 
les relier entre elles. PVM offre même des facilités de contrôles de 
tâches (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">jobs</em></span></span> »</span>) en parallèle 
au travers d'un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span>. Cerise sur le 
gâteau, PVM est disponible gratuitement et depuis longtemps 
(actuellement sur <a class="ulink" href="http://www.epm.ornl.gov/pvm/pvm_home.html" target="_top">http://www.epm.ornl.gov/pvm/pvm_home.html</a>), ce qui a conduit bon 
nombre de langages de programmation, de compilateurs, et d'outils de 
débogage ou autres à l'adopter comme leur <span class="quote">« <span class="quote">bibliothèque cible 
portable de <span class="foreignphrase"><em class="foreignphrase">message-passing</em></span></span> »</span>. Il 
existe également un groupe de discussion : <a class="ulink" href="news:comp.parallel.pvm" target="_top">news:comp.parallel.pvm</a>.

</p><p>

Il est important de remarquer, en revanche, que les appels PVM ajoutent 
généralement aux opérations <span class="foreignphrase"><em class="foreignphrase">socket</em></span> un 
<span class="foreignphrase"><em class="foreignphrase">overhead</em></span> non négligeable alors que les 
temps de latence de celles-ci sont déjà importants. En outre, les appels 
eux-mêmes ne sont pas aisés à manipuler.

</p><p>
Appliquée au même exemple de calcul de Pi décrit en section 1.3,
la version PVM du programme en langage C est la suivante :
</p><pre class="programlisting">
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;pvm3.h&gt;

#define NPROC	4

main(int argc, char **argv)
{
  register double sommelocale, largeur;
  double somme;
  register int intervalles, i;
  int mytid, iproc, msgtag = 4;
  int tids[NPROC];  /* Tableau des numéros des tâches */

  /* Début du traitement avec PVM */
  mytid = pvm_mytid();

  /* « Je rejoins le groupe et, si je suis la première instance,
     iproc=0, je crée plusieurs copies de moi-même. »
  */
  iproc = pvm_joingroup("pi");

  if (iproc == 0) {
    tids[0] = pvm_mytid();
    pvm_spawn("pvm_pi", &amp;argv[1], 0, NULL, NPROC-1, &amp;tids[1]);
  }
  /* On s'assure que tous les processus sont prêts  */
  pvm_barrier("pi", NPROC);

  /* Récupère le nombre d'intervalles */
  intervalles = atoi(argv[1]);
  largeur = 1.0 / intervalles;

  sommelocale = 0.0;
  for (i = iproc; i&lt;intervalles; i+=NPROC) {
    register double x = (i + 0.5) * largeur;
    sommelocale += 4.0 / (1.0 + x * x);
  }

  /* On ajuste les résultats locaux en fonction de la largeur */
  somme = sommlocale * largeur;
  pvm_reduce(PvmSum, &amp;sum, 1, PVM_DOUBLE, msgtag, "pi", 0);

  /* Seul le processus rattaché à la console renvoie le résultat */
  if (iproc == 0) {
    printf("Estimation de la valeur de pi: %f\n", somme);
  }

  /* On attend que le programme soit terminé,
     on quitte le groupe et
	 on sort de PVM. */
  pvm_barrier("pi", NPROC);
  pvm_lvgroup("pi");
  pvm_exit();
  return(0);
}
</pre></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e3711"/>3.5. MPI (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Message Passing Interface</em></span></span> »</span>)</h3></div></div></div><p>

Bien que PVM soit le standard de fait en matière de bibliothèque de 
<span class="foreignphrase"><em class="foreignphrase">message-passing</em></span>, MPI 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Message Passing 
Interface</em></span></span> »</span>) tend à devenir le nouveau standard 
officiel. Le site du standard MPI se trouve sur <a class="ulink" href="http://www.mcs.anl.gov:80/mpi/" target="_top">http://www.mcs.anl.gov:80/mpi/</a> et le groupe de discussion 
correspondant sur <a class="ulink" href="news:comp.parallel.mpi" target="_top">news:comp.parallel.mpi</a>.

</p><p>
En revanche, avant d'explorer MPI, je me sens obligé de parler
rapidement de la guerre de religion qui oppose PVM à MPI et qui
dure depuis quelques années. Je ne penche ni pour l'un ni pour
l'autre. Voici un résumé aussi impartial que possible des
différences entre les deux interfaces :
</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">Environnement de contrôle de l'exécution</span></dt><dd><p>
Pour faire simple, PVM en a un, et MPI ne précise pas
s'il existe, ni comment il doit être implémenté. Cela
signifie que certaines choses comme lancer l'exécution
d'un programme PVM se fait de la même manière partout,
alors que pour MPI, cela dépend de l'implémentation
utilisée.
</p></dd><dt><span class="term">Prise en charge des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> hétérogènes.</span></dt><dd><p>
PVM a grandi dans le monde de la collecte des cycles machines
inutilisés sur les stations de travail, et sait donc gérer donc
directement les mélanges hétérogènes de machines et de systèmes
d'exploitation. A contrario, MPI part du principe général que
la cible est un MPP (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Massively Parallel Processor</em></span></span> »</span>, soit
<span class="quote">« <span class="quote">Processeur Massivement Parallèle</span> »</span>) ou un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> dédié
de stations de travail pratiquement toutes identiques.
</p></dd><dt><span class="term">Syndrome de l'évier.</span></dt><dd><p>
PVM se révèle être conçu pour une catégorie d'utilisation bien
définie, ce que MPI 2.0 ne fait pas. Le nouveau standard MPI 2.0
inclut une variété de fonctionnalités qui s'étendent bien au delà
du simple modèle de <span class="foreignphrase"><em class="foreignphrase">message-passing</em></span>, comme le RMA
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Remote Memory Access</em></span></span> »</span>, soit <span class="quote">« <span class="quote">Accès Mémoire à Distance</span> »</span>) ou les
opérations d'entrée/sortie en parallèle sur les fichiers. Toutes
ces choses sont-elles bien utiles ? Assurément… mais assimiler
MPI 2.0 est comparable à réapprendre depuis zéro un langage de
programmation totalement nouveau.
</p></dd><dt><span class="term">Conception de l'interface utilisateur.</span></dt><dd><p>
MPI a été conçu après PVM, et en a incontestablement tiré les leçons.
MPI offre une gestion des tampons plus simple et plus efficace et
une couche d'abstraction de haut-niveau permettant de transmettre
des données définies par l'utilisateur comme des messages.
</p></dd><dt><span class="term">Force de loi.</span></dt><dd><p>
Pour ce que j'ai pu en voir, il existe toujours plus d'applications
conçues autour de PVM qu'autour de MPI. Néanmoins, porter celles-ci
vers MPI est chose facile, et le fait que MPI soit soutenu par un
standard formel très répandu signifie que MPI est, pour un certain nombre
d'institutions, une question de vision des choses.
</p></dd></dl></div><p>
Conclusion ? Disons qu'il existe au moins trois versions de MPI
développées de façon indépendante et disponibles gratuitement pouvant
fonctionner sur des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> de machines Linux (et j'ai écrit l'un
d'eux) :
</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
LAM (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Local Area Multicomputer</em></span></span> »</span>, soit <span class="quote">« <span class="quote">MultiOrdinateur Local</span> »</span>)
est une mise en œuvre complète du standard 1.1. Il permet aux programmes
MPI de s'exécuter sur un système Linux individuel ou au travers d'un
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> de systèmes Linux communiquant par le biais de <span class="foreignphrase"><em class="foreignphrase">sockets</em></span> TCP/UDP.
Le système inclut des facilités de base de contrôle de l'exécution, ainsi que
toute une gamme d'outils de développement et de débogage de programmes.
</p></li><li class="listitem"><p>

MPICH (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">MPI CHameleon</em></span></span> »</span>) est 
conçu pour être une implémentation complète et hautement portable du 
standard MPI 1.1. Tout comme LAM, il permet aux programmes MPI d'être 
exécutés sur des systèmes Linux individuels ou en 
<span class="foreignphrase"><em class="foreignphrase">clusters</em></span> via une communication par 
<span class="foreignphrase"><em class="foreignphrase">socket</em></span> TCP/UDP. En revanche, l'accent est 
porté sur la promotion de MPI en fournissant une implémentation efficace 
et facilement repositionnable. Pour porter cette implémentation, il faut 
réimplémenter soit les cinq fonctions de la <span class="quote">« <span class="quote">channel 
interface</span> »</span>, soit, pour de meilleures performances, la totalité de 
l'ADI (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Abstract Device 
Interface</em></span></span> »</span>, soit <span class="quote">« <span class="quote">Interface Périphérique 
Abstraite</span> »</span>). MPICH, et beaucoup d'informations concernant ce 
sujet et la façon de le porter, sont disponibles sur <a class="ulink" href="http://www.mcs.anl.gov/mpi/mpich/" target="_top">http://www.mcs.anl.gov/mpi/mpich/</a>.

</p></li><li class="listitem"><p>

AFMPI (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Aggregate Function 
MPI</em></span></span> »</span>) est une sous-implémentation du standard MPI 
2.0. C'est celle que j'ai écrite. S'appuyant sur AFAPI, elle est conçue 
pour être la vitrine des RMA et des fonctions de communications 
collectives, et n'offre donc qu'un soutien minimal des types MPI, de ses 
systèmes de communication, et cætera. Elle permet à des programmes C 
utilisant MPI d'être exécutés sur un système Linux individuel ou au 
travers d'un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> mis en réseau par du 
matériel pouvant prendre en charge l'AFAPI.

</p></li></ul></div><p>
Quelque soit l'implémentation MPI utilisée, il est toujours très simple
d'effectuer la plupart des types de communication.
</p><p>
En revanche, MPI 2.0 incorpore plusieurs paradigmes de communication
suffisamment différents entre eux fondamentalement pour qu'un programmeur
utilisant l'un d'entre eux puisse ne même pas reconnaître les autres
comme étant des styles de programmation MPI. Aussi, plutôt que d'explorer
un seul exemple de programme, il est utile de passer en revue un exemple de chacun
des (différents) paradigmes de communication de MPI. Tous les programmes
qui suivent emploient le même algorithme (celui de la section 1.3)
utilisé pour calculer Pi.
</p><p>
Le premier programme MPI utilise les appels de <span class="foreignphrase"><em class="foreignphrase">message-passing</em></span> MPI sur
chaque processeur pour que celui-ci renvoie son résultat partiel au
processeur 0, qui fait la somme de tous ces résultats et la renvoie à
l'écran :
</p><p>

</p><pre class="programlisting">
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;mpi.h&gt;

main(int argc, char **argv)
{
  register double largeur;
  double somme, sommelocale;
  register int intervalles, i;
  int nproc, iproc;
  MPI_Status status;

  if (MPI_Init(&amp;argc, &amp;argv) != MPI_SUCCESS) exit(1);
  MPI_Comm_size(MPI_COMM_WORLD, &amp;nproc);
  MPI_Comm_rank(MPI_COMM_WORLD, &amp;iproc);
  intervalles = atoi(argv[1]);
  largeur = 1.0 / intervalles;
  sommelocale = 0;
  for (i=iproc; i&lt;intervalles; i+=nproc) {
    register double x = (i + 0.5) * largeur;
    sommelocale += 4.0 / (1.0 + x * x);
  }
  sommelocale *= largeur;
  if (iproc != 0) {
    MPI_Send(&amp;lbuf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
  } else {
    somme = sommelocale;
    for (i=1; i&lt;nproc; ++i) {
      MPI_Recv(&amp;lbuf, 1, MPI_DOUBLE, MPI_ANY_SOURCE,
               MPI_ANY_TAG, MPI_COMM_WORLD, &amp;status);
      somme += sommelocale;
    }
    printf("Estimation de la valeur de pi: %f\n", somme);
  }
  MPI_Finalize();
  return(0);
}
</pre><p>

</p><p>
Le second programme MPI utilise les communications collectives (qui,
pour ce cas précis, sont incontestablement les plus appropriées) :
</p><p>

</p><pre class="programlisting">
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;mpi.h&gt;

main(int argc, char **argv)
{
  register double largeur;
  double somme, sommelocale;
  register int intervalles, i;
  int nproc, iproc;

  if (MPI_Init(&amp;argc, &amp;argv) != MPI_SUCCESS) exit(1);
  MPI_Comm_size(MPI_COMM_WORLD, &amp;nproc);
  MPI_Comm_rank(MPI_COMM_WORLD, &amp;iproc);
  intervalles = atoi(argv[1]);
  largeur = 1.0 / intervalles;
  sommelocale = 0;
  for (i=iproc; i&lt;intervalles; i+=nproc) {
    register double x = (i + 0.5) * largeur;
    sommelocale += 4.0 / (1.0 + x * x);
  }
  sommelocale *= largeur;
  MPI_Reduce(&amp;sommelocale, &amp;somme, 1, MPI_DOUBLE,
             MPI_SUM, 0, MPI_COMM_WORLD);
  if (iproc == 0) {
    printf("Estimation de la valeur de pi: %f\n", somme);
  }
  MPI_Finalize();
  return(0);
}
</pre><p>

</p><p>
La troisième version MPI utilise le mécanisme RMA de MPI 2.0 sur chaque processeur
pour ajouter la valeur locale de la variable <code class="literal">sommelocale</code> de ce dernier
à la variable <code class="literal">somme</code> du processeur 0 :
</p><p>

</p><pre class="programlisting">
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;mpi.h&gt;

main(int argc, char **argv)
{
  register double largeur;
  double somme = 0, sommelocale;
  register int intervalles, i;
  int nproc, iproc;
  MPI_Win somme_fen;

  if (MPI_Init(&amp;argc, &amp;argv) != MPI_SUCCESS) exit(1);
  MPI_Comm_size(MPI_COMM_WORLD, &amp;nproc);
  MPI_Comm_rank(MPI_COMM_WORLD, &amp;iproc);
  MPI_Win_create(&amp;somme, sizeof(somme), sizeof(somme),
                 0, MPI_COMM_WORLD, &amp;somme_fen);
  MPI_Win_fence(0, somme_fen);
  intervalles = atoi(argv[1]);
  largeur = 1.0 / intervalles;
  sommelocale = 0;
  for (i=iproc; i&lt;intervalles; i+=nproc) {
    register double x = (i + 0.5) * largeur;
    sommelocale += 4.0 / (1.0 + x * x);
  }
  sommelocale *= largeur;
  MPI_Accumulate(&amp;sommelocale, 1, MPI_DOUBLE, 0, 0,
                 1, MPI_DOUBLE, MPI_SUM, somme_fen);
  MPI_Win_fence(0, somme_fen);
  if (iproc == 0) {
    printf("Estimation de la valeur de pi: %f\n", somme);
  }
  MPI_Finalize();
  return(0);
}
</pre><p>

</p><p>
Il est utile de préciser que le mécanisme RMA de MPI 2.0 prévient
de façon remarquable tout problème de structures de données se trouvant
à des adresses mémoires différentes selon les processeurs, en se référant
à une "fenêtre" incluant l'adresse de base, une protection contre les
accès mémoire hors de portée, et même le rééchelonnement d'adresse. À une
implémentation efficace, s'ajoute le fait qu'un traitement RMA peut-être
reporté jusqu'à la prochaine <code class="literal">MPI__Win_fence</code>.
Pour faire simple, le mécanisme RMA est un étrange croisement entre
mémoire partagée distribuée et <span class="foreignphrase"><em class="foreignphrase">message passing</em></span>,
mais reste une interface très propre pouvant générer des communications très efficaces.
</p></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e3886"/>3.6. AFAPI (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Aggregate Function API</em></span></span> »</span>)</h3></div></div></div><p>

Contrairement à PVM, MPI, et cætera, l'interface AFAPI 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Aggregate Function API</em></span></span> »</span>, 
ou <span class="quote">« <span class="quote">Interface à Fonctions d'Agrégation</span> »</span>) n'a pas débuté sa 
vie en tant que couche d'abstraction portable s'appuyant sur un réseau 
matériel ou logiciel existant. AFAPI était plutôt la bibliothèque de 
gestion bas niveau d'un matériel spécifique pour PAPERS 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Purdue's Adapter for Parallel Execution and Rapid 
Synchronization</em></span></span> »</span>, soit <span class="quote">« <span class="quote">Adaptateur pour 
l'Exécution en Parallèle et la Synchronisation Rapide de l'université de 
Purdue</span> »</span>).

</p><p>
PAPERS a été rapidement présenté dans la section 3.2. Il s'agit d'un
réseau à fonction d'agrégations conçu sur mesure dont le modèle est dans
domaine public et qui présente des temps de latence inférieurs à quelques
microsecondes. Mais surtout, il s'agit de la tentative de construction
d'un supercalculateur formant une meilleure cible pour la technologie des
compilateurs que les supercalculateurs déjà existants. Il se distingue
en qualité de la plupart des efforts en matière de <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> Linux et de
PVM/MPI, qui s'attachent généralement à essayer d'exploiter les réseaux
standard au profit des rares applications en parallèle présentant une
granularité suffisante. Le fait que les éléments de PAPERS soient des
machines PC sous Linux ne sert qu'à permettre l'implémentation de
prototypes à des coûts les plus avantageux possibles.
</p><p>
La nécessité d'avoir une interface logicielle de bas niveau commune à
plus d'une douzaine d'implémentations différentes d'un prototype a
conduit la bibliothèque PAPERS à être standardisée sous le nom d'AFAPI.
Mais le modèle utilisé par AFAPI est simple en lui-même et bien plus
adapté aux interactions à la granularité plus fine, typiquement du code
compilé par des compilateurs parallélisés, ou écrit pour des architectures
SIMD. Non seulement la simplicité du modèle rend les machines PAPERS
aisées à construire, mais elle apporte également une efficacité surprenante
aux ports d'AFAPI sur différents types de système, tels que les SMP.
</p><p>
AFAPI fonctionne actuellement sur des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> Linux utilisant TTL_PAPERS,
CAPERS ou WAPERS. Elle fonctionne également (sans appel système ni même
instruction de verrouillage de bus, voir la section 2.2) sur les machines
SMP utilisant une bibliothèque de gestion de mémoire partagée type System V
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">System V Shared Memory</em></span></span> »</span>) appelée SHMAPERS. Une version fonctionnant sur
des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> Linux utilisant la diffusion UDP sur des réseaux conventionnels
(Ex : Ethernet) est en cours de développement. Toutes les versions d'AFAPI sont écrites
pour être appelées à partir des langages C ou C++.
</p><p>
L'exemple suivant est la version AFAPI du programme de calcul de
Pi décrit dans la section 1.3.
</p><p>

</p><pre class="programlisting">
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include "afapi.h"

main(int argc, char **argv)
{
  register double largeur, somme;
  register int intervalles, i;

  if (p_init()) exit(1);

  intervalles = atoi(argv[1]);
  largeur = 1.0 / intervalles;

  sum = 0;
  for (i=IPROC; i&lt;intervalles; i+=NPROC) {
    register double x = (i + 0.5) * largeur;
    somme += 4.0 / (1.0 + x * x);
  }

  somme = p_reduceAdd64f(somme) * largeur;

  if (IPROC == CPROC) {
    printf("Estimation de la valeur de pi: %f\n", somme);
  }

  p_exit();
  return(0);
}
</pre><p>

</p></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e3935"/>3.7. Autres bibliothèques de gestion de <span class="foreignphrase"><em class="foreignphrase">clusters</em></span></h3></div></div></div><p>

Outre PVM, MPI et AFAPI, les bibliothèques suivantes proposent des 
services qui peuvent s'avérer utiles au travers de grappes de machines 
Linux. Ces systèmes sont traités ici de manière moins approfondie 
simplement parce que, contrairement à PVM, MPI et AFAPI, je n'ai que 
peu, voire aucune expérience pratique de l'utilisation de ceux-ci sur 
des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> Linux. Si l'une de ces 
bibliothèques (ou même d'autres) vous est particulièrement utile, merci 
de m'envoyer un courrier électronique en anglais à

<code class="email">&lt;<a class="email" href="mailto:hankd CHEZ engr POINT uky POINT edu">hankd CHEZ engr POINT uky POINT edu</a>&gt;</code>

en me détaillant vos découvertes. J'envisagerai alors d'ajouter une 
section plus complète à son sujet.

</p><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e3948"/>3.7.1. Condor (migration de processus)</h4></div></div></div><p>

Condor est un système de gestion de ressources distribuées qui peut 
diriger de vastes <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> de stations de 
travail hétérogènes. Sa conception a été motivée par les besoins des 
utilisateurs souhaitant utiliser la puissance inexploitée de tels 
<span class="foreignphrase"><em class="foreignphrase">clusters</em></span> au profit de leurs tâches aux 
temps d'exécution prolongés et aux calculs intensifs. Condor reproduit 
dans une large mesure l'environnement de la machine initiale sur celle 
qui exécute le processus, même si ces deux machines ne partagent pas un 
système de fichier ou un mécanisme de mot de passe communs. Les tâches 
sous Condor qui se résument à un processus unique sont automatiquement 
interceptées et déplacées entre les différentes stations en fonctions 
des besoins pour les mener à terme.

</p><p>

Condor est disponible sur <a class="ulink" href="http://www.cs.wisc.edu/condor/" target="_top">http://www.cs.wisc.edu/condor/</a>. 
Une version Linux existe également. Contactez l'administrateur du site,

<code class="email">&lt;<a class="email" href="mailto:condor TIRET admin CHEZ cs POINT wisc POINT edu">condor TIRET admin CHEZ cs POINT wisc POINT edu</a>&gt;</code>,

pour plus de détails.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e3966"/>3.7.2. DFN-RPC (Réseau Allemand de la Recherche — <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Remote Procedure Call</em></span></span> »</span>)</h4></div></div></div><p>

Le DFN-RPC (un outil du Réseau Allemand de la Recherche — 
<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Remote Procedure Call</em></span></span> »</span>) a 
été développé pour distribuer et paralléliser des applications d'intéret 
scientifique ou technique entre une station de travail et un serveur de 
calcul ou un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span>. L'interface est 
optimisée pour les applications écrites en Fortran, mais le DFN-RPC peut 
aussi être utilisé dans un environnement de langage C. Une version Linux 
a été écrite. Plus d'information sur <a class="ulink" href="ftp://ftp.uni-stuttgart.de/pub/rus/dfn_rpc/README_dfnrpc.html" target="_top">ftp://ftp.uni-stuttgart.de/pub/rus/dfn_rpc/README_dfnrpc.html</a>.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e3984"/>3.7.3. DQS (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Distributed Queueing System</em></span></span> »</span>)</h4></div></div></div><p>

Pas vraiment une bibliothèque, DQS 3.0 (<span class="quote">« <span class="quote">Distributed Queueing 
System</span> »</span>, soit <span class="quote">« <span class="quote">Système de Files d'attente 
Distribuées</span> »</span>) est un système de mise en file d'attente des tâches 
qui a été développé et testé sous Linux. Ce système a été conçu pour 
permettre à la fois l'utilisation et l'administration d'un 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> de machines hétérogènes comme une 
seule entité. Disponible sur <a class="ulink" href="http://www.scri.fsu.edu/~pasko/dqs.html" target="_top">http://www.scri.fsu.edu/~pasko/dqs.html</a>.

</p><p>
Il existe aussi une version commerciale nommée CODINE 4.1.1 (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">COmputing in
DIstributed Network Environments</em></span></span> »</span>, soit <span class="quote">« <span class="quote">CAlcul en Environnement Réseau Distribué</span> »</span>).
</p></div></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e4013"/>3.8. Références générales aux <span class="foreignphrase"><em class="foreignphrase">clusters</em></span></h3></div></div></div><p>
Les <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> peuvent être construits et utilisés de tellement
de manières différentes que certains groupes ont apporté des
contributions particulièrement intéressantes. Ce qui suit fait référence aux
différents projets liés à la mise en place de <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> pouvant
avoir un intérêt d'ordre général. Ceci inclut un mélange de
références à des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> spécifiques à Linux et à des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span>
génériques. Cette liste est présentée dans l'ordre alphabétique.
</p><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4032"/>3.8.1. Beowulf</h4></div></div></div><p>

Le projet <a class="ulink" href="http://www.beowulf.org/" target="_top">Beowulf</a>, se 
focalise sur la production de logiciels pour une utilisation de stations 
de travail immédiatement disponibles basée sur du matériel PC de grande 
distribution, un réseau à haut débit interne au 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span>, et le système d'exploitation 
Linux.

</p><p>
Thomas Sterling a été le principal acteur de Beowulf, et continue
d'être un promoteur franc et éloquent de l'utilisation de <span class="foreignphrase"><em class="foreignphrase">clusters</em></span>
Linux dans le domaine du calcul scientifique en général. À vrai dire,
plusieurs groupes parlent à présent de leur <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> comme de système
de <span class="quote">« <span class="quote">classe Beowulf</span> »</span>, et ce même si la conception de ce <span class="foreignphrase"><em class="foreignphrase">cluster</em></span>
s'éloigne du modèle Beowulf officiel.
</p><p>
Don Becker, apportant son appui au projet Beowulf, a produit nombre
des pilotes réseau utilisés par Linux en général. Plusieurs de ces
pilotes ont même été adaptés pour être utilisés sous BSD. C'est
également à Don que l'on doit la possibilité, pour certains pilotes,
de répartir le trafic réseau à travers plusieurs connexions parallèles
pour augmenter les taux de transfert sans utiliser d'onéreux commutateurs.
Ce type de répartition de la charge réseau était le principal atout des
<span class="foreignphrase"><em class="foreignphrase">clusters</em></span> Beowulf.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4062"/>3.8.2. Linux/AP+</h4></div></div></div><p>

Le projet <a class="ulink" href="http://cap.anu.edu.au/cap/projects/linux" target="_top">Linux/AP+</a> ne 
concerne pas exactement le <span class="emphasis"><em>clustering</em></span> sous Linux, 
mais s'attache à faire fonctionner Linux sur l'AP1000+ de Fujitsu, et à 
y apporter les améliorations appropriées en matière de traitement en 
parallèle. L'AP1000+ est une machine en parallèle à base de SPARC et 
disponible dans le commerce, utilisant un réseau spécifique avec une 
topologie en tore, un taux de transfert de 25Mo/s et un temps de latence 
de 10 microsecondes… Pour faire court, cela ressemble beaucoup à 
un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> Linux SPARC.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4076"/>3.8.3. Locust</h4></div></div></div><p>
Le projet Locust est en train de mettre au point un système de mémoire partagée
virtuelle qui utilise les informations obtenues à la compilation pour
masquer les temps de latence des messages et réduire le trafic réseau
lors de l'exécution. <span class="quote">« <span class="quote">Pupa</span> »</span> forme la base du système de communication de
Locust, et est implémenté à l'aide d'un réseau Ethernet reliant des
machines PC 486 sous FreeBSD. Et Linux ?
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4084"/>3.8.4. Midway DSM (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Distributed Shared Memory</em></span></span> »</span>)</h4></div></div></div><p>
<a class="ulink" href="http://www.cs.cmu.edu/afs/cs.cmu.edu/project/midway/WWW/HomePage.html" target="_top">Midway</a> est une DSM (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Distributed Shared Memory</em></span></span> »</span>,
soit <span class="quote">« <span class="quote">Mémoire Partagée Distribuée</span> »</span>) logicielle, similaire à TreadMarks.
Le bon coté réside en l'utilisation d'indications à la compilation plutôt que de relativement
lents mécanismes d'erreur de page, et en sa gratuité. Le mauvais coté est cela ne fonctionne
pas sur des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> Linux.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4106"/>3.8.5. Mosix</h4></div></div></div><p>

MOSIX apporte des modifications au système d'exploitation BSD 
<span class="quote">« <span class="quote">BSDI</span> »</span> pour proposer une répartition de charge réseau 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">load balancing</em></span></span> »</span>) dynamique 
et une migration de processus préemptive au travers d'un groupe de PC 
mis en réseau. C'est un système très utile non seulement pour le 
traitement en parallèle, mais d'une manière générale pour utiliser un 
<span class="foreignphrase"><em class="foreignphrase">cluster</em></span> comme une machine SMP évolutive. 
Y aura-t-il une version Linux ? Voyez <a class="ulink" href="http://www.mosix.org" target="_top">http://www.mosix.org</a> pour plus d'informations<a href="#ftn.d0e4123" class="footnote" id="d0e4123"><sup class="footnote">[22]</sup></a>.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4127"/>3.8.6. NOW (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Network Of Workstations</em></span></span> »</span>)</h4></div></div></div><p>
Le projet NOW (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Network Of Workstations</em></span></span> »</span>, ou <span class="quote">« <span class="quote">Réseau de Stations de Travail</span> »</span>) de l'université de Berkeley (<a class="ulink" href="http://now.cs.berkeley.edu/" target="_top">http://now.cs.berkeley.edu</a>) a conduit dans une large mesure l'effort pour le calcul en
parallèle en utilisant des réseaux de stations de travail. Bon
nombre de travaux sont menés là-bas, tous tournés vers la
<span class="quote">« <span class="quote">démonstration en pratique d'un système à 100 processeurs dans
les prochaines années</span> »</span>. Hélas, ils n'utilisent pas Linux.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4149"/>3.8.7. Traitement en parallèle avec Linux</h4></div></div></div><p>
Le site web du <span class="quote">« <span class="quote">Traitement en parallèle avec Linux</span> »</span>
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Parallel processing using Linux</em></span></span> »</span>), sur <a class="ulink" href="http://yara.ecn.purdue.edu/~pplinux" target="_top">http://yara.ecn.purdue.edu/~pplinux</a>&gt;, est le site officiel
de ce guide pratique et de plusieurs documents en rapport avec ce thème,
y compris des présentations en ligne.
Parallèlement aux travaux du projet PAPERS, l'École Supérieure
d'Électricité et d'Informatique de Purdue (<span class="quote">« <span class="quote">Purdue
University School of Electrical and Computer Engineering</span> »</span>) reste
un leader en matière de traitement en parallèle. Ce site a été
mis en place pour aider les autres à utiliser des PC sous Linux
pour faire du traitement en parallèle.
</p><p>
Depuis l'assemblage du premier <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> de PC Linux en février 1994,
bien d'autres furent également assemblés à Purdue, dont plusieurs
équipés de murs vidéos. Bien que ces <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> s'appuyaient sur des
machines à base de microprocesseurs 386, 486 ou Pentium (mais pas de
Pentium Pro), Intel a récemment accordé à Purdue une donation qui lui
permettra de construire plusieurs grands <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> de systèmes à
Pentium II (avec pas moins de 165 machines par <span class="foreignphrase"><em class="foreignphrase">cluster</em></span>). Même si
tous ces <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> sont ou seront équipés de réseaux PAPERS, la plupart
sont également dotés de réseaux conventionnels.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4184"/>3.8.8. Pentium Pro Cluster Workshop</h4></div></div></div><p>
Les 10 et 11 avril 1997, le laboratoire AMES a tenu à Des Moines,
dans l'état de l'Iowa aux États-Unis, le <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Pentium Pro Cluster
Workshop</em></span></span> »</span> (<span class="quote">« <span class="quote">Atelier de <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> Pentium Pro</span> »</span>). Le site web
de cet atelier, <a class="ulink" href="http://www.scl.ameslab.gov" target="_top">http://www.scl.ameslab.gov</a>, renferme une mine d'informations concernant les <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> PC,
glanées auprès de tous les participants.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4205"/>3.8.9. TreadMarks DSM (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Distributed Shared Memory</em></span></span> »</span>)</h4></div></div></div><p>

La DSM (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Distributed Shared 
Memory</em></span></span> »</span>, ou <span class="quote">« <span class="quote">Mémoire Partagée 
Distribuée</span> »</span>) est une technique avec laquelle un système de 
<span class="foreignphrase"><em class="foreignphrase">message-passing</em></span> peut se présenter et agir 
comme un SMP. Il existe quelques systèmes de ce genre, la plupart 
utilisant les mécanismes d'erreur de page du système d'exploitation pour 
déclencher la transmission des messages. <a class="ulink" href="http://www.cs.rice.edu/~willy/TreadMarks/overview.html" target="_top">TreadMarks</a> 
est l'un des plus efficaces, et fonctionne sur les 
<span class="foreignphrase"><em class="foreignphrase">clusters</em></span> Linux. La mauvaise nouvelle est 
que <span class="quote">« <span class="quote">TreadMarks est distribué à un coût réduit aux universités et 
organisations à but non lucratif</span> »</span>. Pour plus d'informations 
concernant le logiciel, prenez contact (en anglais) avec

<code class="email">&lt;<a class="email" href="mailto:tmk CHEZ cs POINT rice POINT edu">tmk CHEZ cs POINT rice POINT edu</a>&gt;</code>.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4236"/>3.8.10. U-Net (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">User-level NETwork interface architecture</em></span></span> »</span>)</h4></div></div></div><p>

Le projet U-Net (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">User-level NETwork interface 
architecture</em></span></span> »</span>, ou <span class="quote">« <span class="quote">Architecture d'interface 
Réseau au Niveau Utilisateur</span> »</span>), accessible sur <a class="ulink" href="http://www.eecs.harvard.edu/~mdw/proj/old/unet" target="_top">http://www.eecs.harvard.edu/~mdw/proj/old/unet</a>, tente d'apporter 
temps de latence réduits et taux de transfert élevés sur du matériel 
réseau du commerce en virtualisant les interfaces réseau de manière à ce 
que les applications puissent envoyer et recevoir des messages sans 
passer par un appel système. U-Net fonctionne sur des PC Linux en 
utilisant du matériel Fast Ethernet basé sur une puce DEC DC21140, ou 
une carte ATM Fore Systems PCA-200 (mais pas PCA-200E).

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4254"/>3.8.11. WWT (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Wisconsin Wind Tunnel</em></span></span> »</span>)</h4></div></div></div><p>

On trouve bon nombre de projets relatifs à l'utilisation de 
<span class="foreignphrase"><em class="foreignphrase">clusters</em></span> dans le Wisconsin. Le projet WWT 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Wisconsin Wind Tunnel</em></span></span> »</span>, ou 
<span class="quote">« <span class="quote">Soufflerie du Wisconsin</span> »</span>), sur <a class="ulink" href="http://www.cs.wisc.edu/~wwt/" target="_top">http://www.cs.wisc.edu/~wwt/</a>, mène toutes sortes de travaux 
orientés vers le développement d'une interface <span class="quote">« <span class="quote">standard</span> »</span> 
entre les compilateurs et le matériel réseau sur lequel ils s'appuient. 
Il existe le <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Wisconsin COW</em></span></span> »</span> 
(pour <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Cluster Of 
Workstation</em></span></span> »</span>), <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Cooperative 
Shared Memory</em></span></span> »</span> et 
<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Tempest</em></span></span> »</span>, le 
<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Paradyn Parallel Performance 
Tools</em></span></span> »</span>, et cætera. Malheureusement, il n'y a pas 
grand chose concernant Linux.

</p></div></div></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title"><a id="d0e4298"/>4. SIMD <span class="foreignphrase"><em class="foreignphrase">Within A Register</em></span> : SWAR (Ex : utilisation de MMX)</h2></div></div></div><p>

Le SIMD (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Single Instruction stream, Multiple Data 
stream</em></span></span> »</span> ou <span class="quote">« <span class="quote">Un seul flux d'instruction, 
plusieurs flux de données</span> »</span>) à l'Intérieur d'Un Registre (ou 
<span class="quote">« <span class="quote">SIMD <span class="foreignphrase"><em class="foreignphrase">Within A 
Register</em></span></span> »</span> : SWAR) n'est pas un concept 
récent. En considérant une machine dotée de registres, bus de données et 
unités de fonctions de <span class="emphasis"><em>k</em></span> bits, il est connu depuis 
longtemps que les opérations sur les registres ordinaires peuvent se 
comporter comme des opérations parallèles SIMD sur 
<span class="emphasis"><em>n</em></span> champs de 
<span class="emphasis"><em>k</em></span>/<span class="emphasis"><em>n</em></span> bits chacun. Ce n'est en 
revanche qu'avec les efforts récents en matière de multimédia que 
l'accélération d'un facteur deux à huit apportée par les techniques SWAR 
a commencé à concerner l'informatique générale. Les versions de 1997 de 
la plupart des microprocesseurs incorporent une prise en charge 
matérielle du SWAR<a href="#ftn.d0e4330" class="footnote" id="d0e4330"><sup class="footnote">[23]</sup></a> :

</p><p>

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
<a class="ulink" href="http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/20726.pdf" target="_top">AMD K6 MMX (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">MultiMedia eXtensions</em></span></span> »</span>)</a>

</p></li><li class="listitem"><p>
<a class="ulink" href="http://www.sun.com/sparc/vis/index.html" target="_top">Sun SPARC V9 VIS (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Visual Instruction Set</em></span></span> »</span>)</a>
</p></li></ul></div><p>

</p><p>
Il existe quelques lacunes dans la prise en charge matérielle
apportée par les nouveaux microprocesseurs, des caprices comme
par exemple la prise en charge d'un nombre limité d'instructions
pour certaines tailles de champ. Il est toutefois important de
garder à l'esprit que bon nombre d'opérations SWAR peuvent se
passer d'accélération matérielle. Par exemple, les opérations
au niveau du bit sont insensibles au partitionnement logique d'un
registre.
</p><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e4360"/>4.1. Quels usages pour le SWAR ?</h3></div></div></div><p>
Bien que <span class="emphasis"><em>tout</em></span> processeur moderne soit capable
d'exécuter un programme en effectuant un minimum de parallélisme
SWAR, il est de fait que même le plus optimisé des jeux d'instructions
SWAR ne peut gérer un parallélisme d'intérêt vraiment général. A dire
vrai, de nombreuses personnes ont remarqué que les différences de
performance entre un Pentium ordinaire et un Pentium <span class="quote">« <span class="quote">avec technologie MMX</span> »</span>
étaient surtout dûes à certains détails, comme le fait que l'augmentation
de la taille du cache L1 coïncide avec l'apparition du MMX. Alors,
concrètement, à quoi le SWAR (ou le MMX) est-il utile ?
</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Dans le traitement des entiers, les plus courts étant les meilleurs. 
Deux valeurs 32 bits tiennent dans un registre MMX 64 bits, mais forment 
aussi une chaîne de huit caractères, ou encore permettent de représenter un
échiquier complet, à raison d'un bit par case. Note : il 
<span class="emphasis"><em>existera une version <span class="quote">« <span class="quote">virgule flottante</span> »</span> du 
MMX</em></span>, bien que très peu de choses aient été dites à ce sujet. 
Cyrix a déposé une présentation, <a class="ulink" href="ftp://ftp.cyrix.com/developr/mpf97rm.pdf" target="_top">ftp://ftp.cyrix.com/developr/mpf97rm.pdf</a>, qui contient quelques 
commentaires concernant <span class="emphasis"><em>MMFP</em></span>. Apparemment, MMFP 
pourra prendre en charge le chargement de nombres 32 bits en virgule 
flottante dans des registres MMX 64 bits. Ceci combiné à deux pipelines 
MMFP fournirait quatre FLOP <a href="#ftn.d0e4386" class="footnote" id="d0e4386"><sup class="footnote">[24]</sup></a> en simple précision par cycle d'horloge.

</p></li><li class="listitem"><p>

Pour le SIMD, ou parallélisme vectorisé. La même opération s'applique à 
tous les champs, simultanément. Il existe des moyens d'annihiler ses 
effets sur des champs sélectionnés (l'équivalent du 
<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">SIMD enable masking</em></span></span> »</span>, ou 
<span class="quote">« <span class="quote">activation du masquage</span> »</span>), mais ils sont compliqués à 
mettre en œuvre et grèvent les performances.

</p></li><li class="listitem"><p>

Pour les cas où la référence à la mémoire se fait de manière localisée 
et régulière (et de préférence regroupée). Le SWAR en général, et le MMX 
en particulier se révèlent désastreux sur les accès aléatoires. 
Rassembler le contenu d'un vecteur <code class="literal">x[y]</code> (où 
<code class="literal">y</code> est l'index d'un tableau) est extrêmement coûteux.

</p></li></ul></div><p>
Il existe donc d'importantes limitations, mais ce type de parallélisme
intervient dans un certain nombre d'algorithmes, et pas seulement dans les
applications multimédia. Lorsque l'algorithme est adapté, le SWAR est plus
efficace que le SMP ou le parallélisme en <span class="foreignphrase"><em class="foreignphrase">clusters</em></span>… et son utilisation
ne coûte rien !
</p></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e4421"/>4.2. Introduction à la programmation SWAR</h3></div></div></div><p>
Le concept de base du SWAR (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">SIMD Within A Register</em></span></span> »</span>,
ou <span class="quote">« <span class="quote">SIMD à l'intérieur d'un registre</span> »</span>) réside dans le fait que l'on peut utiliser des opérations sur
des registres de la taille d'un mot pour accélérer les calculs en effectuant des
opérations parallèles SIMD sur <span class="emphasis"><em>n</em></span> champs
de <span class="emphasis"><em>k</em></span>/<span class="emphasis"><em>n</em></span> bits. En revanche,
employer les techniques du SWAR peut parfois s'avérer maladroit, et certaines de leurs
opérations peuvent au final être plus coûteuses que leurs homologues en série
car elles nécessitent des instructions supplémentaires pour forcer le partitionnement
des champs.
</p><p>
Pour illustrer ce point, prenons l'exemple d'un mécanisme SWAR
grandement simplifié gérant quatre champs de 8 bits dans chaque
registre de 32 bits. Les valeurs de ces deux registres pourraient
être représentées comme suit :
</p><p>

</p><pre class="programlisting">
         PE3     PE2     PE1     PE0
      +-------+-------+-------+-------+
Reg0  | D 7:0 | C 7:0 | B 7:0 | A 7:0 |
      +-------+-------+-------+-------+
Reg1  | H 7:0 | G 7:0 | F 7:0 | E 7:0 |
      +-------+-------+-------+-------+
</pre><p>

</p><p>

Ceci indique simplement que chaque registre est vu essentiellement comme 
un vecteur de quatre valeurs entières 8 bits indépendantes. 
Alternativement, les valeurs <code class="literal">A</code> et 
<code class="literal">E</code> peuvent être vues comme les valeurs, dans Reg0 et 
Reg1, de l'élément de traitement 0 (ou <span class="quote">« <span class="quote">PE0</span> »</span> pour 
<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Processing Element 0</em></span></span> »</span>), 
<code class="literal">B</code> et <code class="literal">F</code> comme celles de l'élément 
1, et ainsi de suite.

</p><p>
Le reste de ce document passe rapidement en revue les classes de
base des opérations parallèles SIMD sur ces vecteurs d'entiers et
la façon dont ces fonctions peuvent être implémentées.
</p><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4472"/>4.2.1. Opérations polymorphiques</h4></div></div></div><p>
Certaines opérations SWAR peuvent être effectuées de façon triviale
en utilisant des opérations ordinaires sur des entiers 32 bits, sans
avoir à se demander si l'opération est réellement faite pour agir en
parallèle et indépendemment sur ces champs de 8 bits. On qualifie ce
genre d'opération SWAR de <span class="emphasis"><em>polymorphique</em></span>, parce que
la fonction est insensible aux types des champs (et à leur taille).
</p><p>
Tester si un champ quelconque est non-nul est une opération polymorphique,
tout comme les opérations logiques au niveau du bit. Par exemple, un <span class="quote">« <span class="quote">ET</span> »</span>
logique bit-à-bit ordinaire (l'opérateur <span class="quote">« <span class="quote"><code class="literal">&amp;</code></span> »</span>
du registre C) effectue son calcul bit-à-bit, quelque soit la taille des champs.
Un <span class="quote">« <span class="quote">ET</span> »</span> logique simple des registres ci-dessus donnerait :
</p><p>

</p><pre class="programlisting">
          PE3       PE2       PE1       PE0
      +---------+---------+---------+---------+
Reg2  | D&amp;H 7:0 | C&amp;G 7:0 | B&amp;F 7:0 | A&amp;E 7:0 |
      +---------+---------+---------+---------+
</pre><p>

</p><p>
Puisque le bit de résultat <span class="emphasis"><em>k</em></span> de l'opération <span class="quote">« <span class="quote">ET</span> »</span> logique
n'est affecté que par les valeurs des bits d'opérande <span class="emphasis"><em>k</em></span>,
toutes les tailles de champs peuvent être prises en charge par une même instruction.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4508"/>4.2.2. Opérations partitionnées</h4></div></div></div><p>
Malheureusement, de nombreuses et importantes opérations SWAR ne sont
pas polymorphiques. Les opérations arithmétiques comme l'addition, la
soustraction, la multiplication et la division sont sujettes aux
interactions de la <span class="quote">« <span class="quote">retenue</span> »</span> entre les champs. Ces opérations sont
dites <span class="emphasis"><em>partitionnées</em></span> car chacune d'elles doit
cloisonner effectivement les opérandes et le résultat pour éviter les
interactions entre champs. Il existe toutefois trois méthodes différentes
pouvant être employées pour parvenir à ces fins :
</p><div class="sect4"><div class="titlepage"><div><div><h5 class="title"><a id="d0e4519"/>4.2.2.1. Instructions partitionnées</h5></div></div></div><p>
L'approche la plus évidente pour implémenter les opérations partitionnées
consiste peut-être à proposer une prise en charge matérielle des
<span class="quote">« <span class="quote">instructions parallèles partitionnées</span> »</span> coupant le système de retenue
entre les champs. Cette approche peut offrir les performances les plus
élevées, mais elle nécessite la modification du jeu d'instruction du
processeur et implique en général des limitations sur la taille des
champs (Ex : ces instructions pourraient prendre en charge des champs larges
de 8 bits, mais pas de 12).
</p><p>
Le MMX des processeurs AMD, Cyrix et Intel, Le MAX de Digital, celui d'HP,
et le VIS de Sun implémentent tous des versions restreintes des instructions
partitionnées. Malheureusement, ces différents jeux d'instructions posent
des restrictions assez différentes entre elles, ce qui rend les algorithmes
difficilement portables. Étudions à titre d'exemple l'échantillon d'opérations
partitionnées suivant :
</p><p>

</p><pre class="programlisting">
  Instruction           AMD/Cyrix/Intel MMX   DEC MAX   HP MAX   Sun VIS
+---------------------+---------------------+---------+--------+---------+
| Différence Absolue  |                     |       8 |        |       8 |
+---------------------+---------------------+---------+--------+---------+
| Maximum             |                     |   8, 16 |        |         |
+---------------------+---------------------+---------+--------+---------+
| Comparaison         |           8, 16, 32 |         |        |  16, 32 |
+---------------------+---------------------+---------+--------+---------+
| Multiplication      |                  16 |         |        |    8x16 |
+---------------------+---------------------+---------+--------+---------+
| Addition            |           8, 16, 32 |         |     16 |  16, 32 |
+---------------------+---------------------+---------+--------+---------+
</pre><p>

</p><p>
Dans cette table, les chiffres indiquent les tailles de champ reconnues
par chaque opération. Même si la table exclut un certain nombre d'instructions
dont les plus exotiques, il est clair qu'il y a des différences. Cela a pour effet
direct de rendre inefficaces les modèles de programmation en langages de haut niveau,
et de sévèrement restreindre la portabilité.

</p></div><div class="sect4"><div class="titlepage"><div><div><h5 class="title"><a id="d0e4536"/>4.2.2.2. Opérations non partitionnées avec code de correction</h5></div></div></div><p>
Implémenter des opérations partitionnées en utilisant des instructions
partitionnées est certainement très efficace, mais comment faire lorsque
l'opération dont vous avez besoin n'est pas prise en charge par le matériel ?
Réponse : utiliser une série d'instructions ordinaires pour effectuer l'opération
malgré les effets de la retenue entre les champs, puis effectuer la correction
de ces effets indésirés.
</p><p>
C'est une approche purement logicielle, et les corrections apportent
bien entendu un surcoût en temps, mais elle fonctionne pleinement avec
le partitionnement en général. Cette approche est également <span class="quote">« <span class="quote">générale</span> »</span>
dans le sens où elle peut être utilisée soit pour combler les lacunes du
matériel dans le domaine des instructions partitionnées, soit pour apporter
un soutien logiciel complet aux machines qui ne sont pas du tout dotées
d'une prise en charge matérielle. À dire vrai, en exprimant ces séquences
de code dans un langage comme le C, on permet au SWAR d'être totalement
portable.
</p><p>
Ceci soulève immédiatement une question : quelle est précisément l'inefficacité
des opérations SWAR partitionnées simulées à l'aide d'opérations non partitionnées ?
Eh bien c'est très certainement la question à 65536 dollars, mais certaines opérations
ne sont pas aussi difficiles à mettre en œuvre que l'on pourrait le croire.
</p><p>
Prenons en exemple le cas de l'implémentation de l'addition d'un vecteur de quatre
éléments 8 bits contenant des valeurs entières, soit <code class="literal">x</code>+<code class="literal">y</code>,
en utilisant des opérations 32 bits ordinaires.
</p><p>
Une addition 32 bits ordinaire pourrait en fait rendre un résultat correct,
mais pas si la retenue d'un champ de 8 bits se reporte sur le champ suivant.
Aussi, notre but consiste simplement à faire en sorte qu'un tel report ne se produise
pas. Comme l'on est sûr qu'additionner deux champs de <span class="emphasis"><em>k</em></span> bits
ne peut générer qu'un résultat large d'au plus <span class="emphasis"><em>k</em></span>+1 bits,
on peut garantir qu'aucun report ne va se produire en <span class="quote">« <span class="quote">masquant</span> »</span> simplement le
bit de poids fort de chaque champs. On fait cela en appliquant un <span class="quote">« <span class="quote">ET</span> »</span> logique
à chaque opérande avec la valeur <code class="literal">0x7f7f7f7f</code>, puis
en effectuant un addition 32 bits habituelle.
</p><p>

</p><pre class="programlisting">
t = ((x &amp; 0x7f7f7f7f) + (y &amp; 0x7f7f7f7f));
</pre><p>

</p><p>
Ce résultat est correct… sauf pour le bit de poids fort de chacun
des champs. Il n'est question, pour calculer la valeur correcte, que
d'effectuer deux additions 1-bit partitionnées, depuis <code class="literal">x</code>
et <code class="literal">y</code> vers le résultat à 7 bits calculé
pour <code class="literal">t</code>. Heureusement, une addition
partitionnée sur 1 bit peut être implémentée à l'aide d'une
opération <span class="quote">« <span class="quote">OU Exclusif</span> »</span> logique ordinaire. Ainsi, le résultat est
tout simplement :
</p><p>

</p><pre class="programlisting">
(t ^ ((x ^ y) &amp; 0x80808080))
</pre><p>

</p><p>
D'accord. Peut-être n'est-ce pas si simple, en fin de compte. Après tout, cela fait six
opérations pour seulement quatre additions. En revanche, on remarquera
que ce nombre d'opérations n'est pas fonction du nombre de champs. Donc,
avec plus de champs, on gagne en rapidité. À dire vrai, il se peut que
l'on gagne quand même en vitesse simplement parce que les champs sont
chargés et redéposés en une seule opération (vectorisée sur des entiers),
que la disponibilité des registres est optimisée, et parce qu'il y a
moins de code dynamique engendrant des dépendances (parce que l'on évite
les références à des mots incomplets).
</p></div><div class="sect4"><div class="titlepage"><div><div><h5 class="title"><a id="d0e4599"/>4.2.2.3. Contrôler les valeurs des champs</h5></div></div></div><p>
Alors que les deux autres approches de l'implémentation des opérations
partitionnées se centrent sur l'exploitation du maximum d'espace possible
dans les registres, il peut être, au niveau du calcul, plus efficace de
contrôler les valeurs des champs de façon à ce que l'interaction
de la retenue entre ceux-ci ne se produise jamais. Par exemple, si l'on sait que
toutes les valeurs de champs additionnées sont telles qu'aucun dépassement
ne peut avoir lieu, une addition partitionnée peut être implémentée à
l'aide d'une instruction ordinaire. Cette contrainte posée, une addition
ordinaire pourrait en fin de compte apparaître polymorphique,
et être utilisable avec n'importe quelle taille de champ sans programme de
correction. Ce qui nous amène ainsi à la question suivante : Comment s'assurer
que les valeurs des champs ne vont pas provoquer d'événements dus à la
retenue ?
</p><p>
Une manière de faire cela consiste à implémenter des instructions partitionnées
capables de restreindre la portée des valeurs des champs. Les instructions
vectorisées de maximum et de minimum du MAX de Digital peuvent être
assimilées à une prise en charge matérielle de l'écrêtage des valeurs des
champs pour éviter les interactions de la retenue entre les champs.
</p><p>
En revanche, si l'on ne dispose pas d'instructions partitionnées à même
de restreindre efficacement la portée des valeurs des champs, existe-t-il
une condition qui puisse être imposée à un coût raisonnable et qui soit
suffisante pour garantir le fait que les effets de la retenue n'iront pas
perturber les champs adjacents ? La réponse se trouve dans l'analyse des
propriétés arithmétiques. Additionner deux nombres de <span class="emphasis"><em>k</em></span>
bits renvoie un résultat large d'au plus <span class="emphasis"><em>k</em></span>+1 bits.
Ainsi, un champ de <span class="emphasis"><em>k</em></span>+1 bits peut recevoir en toute
sécurité le résultat d'une telle opération, même s'il est produit par
une instruction ordinaire.
</p><p>
Supposons donc que les champs de 8 bits de nos précédents exemples
soient désormais des champs de 7 bits avec <span class="quote">« <span class="quote">espaces de séparation
pour retenue</span> »</span> d'un bit chacun :
</p><p>

</p><pre class="programlisting">
              PE3          PE2          PE1          PE0
      +----+-------+----+-------+----+-------+----+-------+
Reg0  | D' | D 6:0 | C' | C 6:0 | B' | B 6:0 | A' | A 6:0 |
      +----+-------+----+-------+----+-------+----+-------+
</pre><p>

</p><p>
Mettre en place un vecteur d'additions 7 bits se fait de la manière
suivante : On part du principe qu'avant l'exécution de toute instruction
partitionnée, les bits des séparateurs de retenue
(<code class="literal">A'</code>, <code class="literal">B'</code>,
<code class="literal">C'</code>, et <code class="literal">D'</code>)
sont nuls. En effectuant simplement une addition ordinaire, tous les
champs reçoivent une valeur correcte sur 7 bits. En revanche, certains
bits de séparation peuvent passer à 1. On peut remédier à cela en
appliquant une seule opération supplémentaire conventionnelle et masquant
les bits de séparation. Notre vecteur d'additions entières sur 7 bits,
<code class="literal">x</code>+<code class="literal">y</code>, devient
ainsi :
</p><p>

</p><pre class="programlisting">
((x + y) &amp; 0x7f7f7f7f)
</pre><p>

</p><p>
Ceci nécessite seulement deux opérations pour effectuer quatre additions.
Le gain en vitesse est évident.
</p><p>
Les lecteurs avertis auront remarqué que forcer les bits de séparation
à zéro ne convient pas pour les soustractions. La solution est toutefois
remarquablement simple : Pour calculer <code class="literal">x</code>-<code class="literal">y</code>,
on garantira simplement la condition initiale, qui veut que tous les bits
de séparation de <code class="literal">x</code> valent 1 et que tous ceux
de <code class="literal">y</code> soient nuls. Dans le pire des cas, nous
obtiendrons :
</p><p>

</p><pre class="programlisting">
(((x | 0x80808080) - y) &amp; 0x7f7f7f7f)
</pre><p>

</p><p>
On peut toutefois souvent se passer du <span class="quote">« <span class="quote">OU</span> »</span> logique en s'assurant
que l'opération qui génère la valeur de <code class="literal">x</code>
utilise <code class="literal">| 0x80808080</code> plutôt que
<code class="literal">&amp; 0x7f7f7f7f</code> en dernière étape.
</p><p>
Laquelle de ces méthodes doit-on appliquer aux opérations partitionnées du
SWAR ? La réponse est simple : <span class="quote">« <span class="quote">celle qui offre le gain en rapidité le
plus important</span> »</span>. Ce qui est intéressant, c'est que la méthode idéale peut
être différente selon chaque taille de champ, et ce à l'intérieur d'un
même programme, s'exécutant sur une même machine.
</p></div></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4692"/>4.2.3. Opérations de communication et de conversion de type</h4></div></div></div><p>
Bien que certains calculs en parallèle, incluant les opérations sur les
pixels d'une image, ont pour propriété le fait que la <span class="emphasis"><em>n</em></span>ième
valeur d'un vecteur soit une fonction des valeurs se trouvant à la <span class="emphasis"><em>n</em></span>ième
position des vecteurs des opérandes, ce n'est généralement pas le cas. Par exemple,
même les opérations sur les pixels telles que l'adoucissement ou le flou réclament
en opérande les valeurs des pixels adjacents, et les transformations comme la transformée
de Fourrier (FFT) nécessitent des schémas de communications plus complexes (et moins
localisés).
</p><p>
Il est relativement facile de mettre efficacement en place un système de communication
à une dimension entre les valeurs du voisinage immédiat pour effectuer du SWAR, en utilisant
des opérations de décalage non partitionnées. Par exemple, pour déplacer une valeur depuis
<code class="literal">PE</code> vers <code class="literal">PE</code>(<span class="emphasis"><em>n</em></span>+1),
un simple décalage logique suffit. Si les champs sont larges de 8 bits, on utilisera :
</p><p>

</p><pre class="programlisting">
(x &lt;&lt; 8)
</pre><p>

</p><p>
Pourtant, ce n'est pas toujours aussi simple. Par exemple, pour déplacer une valeur
depuis <code class="literal">PE</code><span class="emphasis"><em>n</em></span> vers
<code class="literal">PE</code>(<span class="emphasis"><em>n</em></span>-1), un simple décalage vers la
droite devrait suffire… mais le langage C ne précise pas si le décalage vers la
droite conserve le bit de signe, et certaines machines ne proposent, vers la droite,
qu'un décalage signé. Aussi, d'une manière générale, devons-nous mettre explicitement à
zéro les bits de signe pouvant être répliqués.
</p><p>

</p><pre class="programlisting">
((x &gt;&gt; 8) &amp; 0x00ffffff)
</pre><p>

</p><p>

L'ajout de connexions <span class="quote">« <span class="quote">à enroulement</span> »</span> 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">wrap-around</em></span></span> »</span>) à l'aide de 
décalages non partitionnés <a href="#ftn.d0e4746" class="footnote" id="d0e4746"><sup class="footnote">[25]</sup></a> est aussi raisonnablement efficace. Par exemple, pour 
déplacer une valeur depuis <code class="literal">PE</code><span class="emphasis"><em>i</em></span> 
vers <code class="literal">PE</code>(<span class="emphasis"><em>i</em></span>+1) avec 
enroulement :

</p><pre class="programlisting">
((x &lt;&lt; 8) | ((x &gt;&gt; 24) &amp; 0x000000ff))
</pre><p>

Les problèmes sérieux apparaissent lorsque des schémas de communications 
plus généraux doivent être mis en œuvre. Seul le jeu 
d'instructions du MAX de HP permet le réarrangement arbitraire des 
champs en une seule instruction, nommée <code class="literal">Permute</code>. 
Cette instruction <code class="literal">Permute</code> porte vraiment mal son 
nom : Non seulement elle effectue une permutation arbitraire des 
champs, mais elle autorise également les répétitions. En bref, elle met 
en place une opération arbitraire de <code class="literal">x[y]</code>.

</p><p>

Il reste malheureusement très difficile d'implémenter 
<code class="literal">x[y]</code> sans le concours d'une telle instruction. La 
séquence de code est généralement à la fois longue et inefficace, parce 
qu'en fait, il s'agit d'un programme séquentiel. Ceci est très décevant. 
La vitesse relativement élevée des opérations de type 
<code class="literal">x[y]</code> sur les les supercalculateurs SIMD MasPar 
MP1/MP2 et Thinking Machines CM1/CM2/CM200 était une des clés majeures 
de leur succès. Toutefois, un <code class="literal">x[y]</code> reste plus lent 
qu'une communication de proximité, même sur ces supercalculateurs. 
Beaucoup d'algorithmes ont donc été conçus pour réduire ces besoins en 
opérations de type <code class="literal">x[y]</code>. Pour simplifier, disons que 
sans soutien matériel, le meilleur est encore très certainement de 
développer des algorithmes SWAR en considérant <code class="literal">x[y]</code> 
comme étant interdit, ou au moins très coûteux.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e4791"/>4.2.4. Opérations récurrentes (réductions, balayages, et cætera)</h4></div></div></div><p>
Une récurrence est un calcul dans lequel il existe une relation
séquentielle apparente entre les valeurs à traiter. Si toutefois des
opérations associatives sont impliquées dans ces récurrences, il peut
être possible de recoder ces calculs en utilisant un algorithme
parallèle à structure organisée en arbre.
</p><p>
Le type de récurrence parallélisable le plus courant est probablement
la classe connue sous le nom de réduction associative. Par exemple,
pour calculer la somme des valeurs d'un vecteur, on écrit du code C
purement séquentiel, comme :
</p><p>

</p><pre class="programlisting">
t = 0;
for (i=0; i&lt;MAX; ++i) t += x[i];
</pre><p>

</p><p>

Cependant, l'ordre des additions est rarement important. Les opérations
en virgule flottante et les saturations peuvent rendre différents résultats
si l'ordre des additions est modifié, mais les additions ordinaires sur les
entiers (et qui reviennent au début après avoir atteint la valeur maximum)
renverront exactement les mêmes résultats, indépendemment de l'ordre dans
lequel elles sont effectuées. Nous pouvons ainsi réécrire cette séquence
sous la forme d'une somme parallèle structurée en arbre, dans laquelle nous
additionnons d'abord des paires de valeurs, puis des paires de ces sous-totaux,
et ainsi de suite jusqu'à l'unique somme finale. Pour un vecteur de quatre
valeurs 8 bits, seulement deux additions sont nécessaires. La première effectue
deux additions de 8 bits et retourne en résultat deux champs de 16 bits,
contenant chacun un résultat sur 9 bits :

</p><p>

</p><pre class="programlisting">
t = ((x &amp; 0x00ff00ff) + ((x &gt;&gt; 8) &amp; 0x00ff00ff));
</pre><p>

</p><p>
La deuxième fait la somme de ces deux valeurs de 9 bits dans
un champs de 16 bits, et renvoie un résultat sur 10 bits :
</p><p>

</p><pre class="programlisting">
((t + (t &gt;&gt; 16)) &amp; 0x000003ff)
</pre><p>

</p><p>

En réalité, la seconde opération effectue l'addition de deux champs de 
16 bits… mais les 16 bits de poids fort n'ont pas de 
signification. C'est pourquoi le résultat est masqué en une valeur de 10 
bits.

</p><p>

Les balayages (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">scans</em></span></span> »</span>), 
aussi connus sous le nom d'opérations <span class="quote">« <span class="quote">à préfixe parallèle</span> »</span> 
sont un peu plus difficile à mettre en œuvre efficacement. Ceci 
est dû au fait que contrairement aux réductions, les balayages peuvent 
produire des résultats partitionnées.

</p></div></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e4828"/>4.3. SWAR MMX sous Linux</h3></div></div></div><p>

Pour Linux, nous nous soucierons principalement des processeurs IA32. La 
bonne nouvelle, c'est qu'AMD, Cyrix et Intel implémentent tous le même 
jeu d'instructions MMX. En revanche, les performances de ces différents 
MMX sont variables. Le K6, par exemple, n'est doté que d'un seul 
<span class="foreignphrase"><em class="foreignphrase">pipeline</em></span> là où le Pentium MMX en a deux. 
La seule nouvelle vraiment mauvaise, c'est qu'Intel diffuse toujours ces 
stupides films publicitaires sur le MMX… ;-)

</p><p>

Il existe trois approches sérieuses du SWAR par le MMX :

</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>

L'utilisation des fonctions d'une bibliothèque dédiée au MMX. Intel, en 
particulier, a développé plusieurs <span class="quote">« <span class="quote">bibliothèques de 
performances</span> »</span>, offrant toute une gamme de fonctions optimisées à 
la main et destinées aux tâches multimédia courantes. Avec un petit 
effort, bon nombre d'algorithmes non-multimédia peuvent être 
retravaillés pour permettre à quelques unes des zones de calcul intensif 
de s'appuyer sur une ou plusieurs de ces bibliothèques. Ces 
bibliothèques ne sont pas disponibles sous Linux, mais pourraient être 
adaptées pour le devenir.

</p></li><li class="listitem"><p>

L'utilisation directe des instructions MMX. C'est assez compliqué, pour
deux raisons : D'abord, le MMX peut ne pas être disponible sur le processeur
concerné, ce qui oblige à fournir une alternative. Ensuite, l'assembleur IA32
utilisé en général sous Linux ne reconnaît actuellement pas les instructions
MMX.

</p></li><li class="listitem"><p>

L'utilisation d'un langage de haut niveau ou d'un module du 
compilateur qui puisse directement générer des instructions MMX 
appropriées. Quelques outils de ce type sont actuellement en cours de 
développement, mais aucun n'est encore pleinement fonctionnel sous 
Linux. Par exemple, à l'Université de Purdue (<a class="ulink" href="http://dynamo.ecn.purdue.edu/~hankd/SWAR/" target="_top">http://dynamo.ecn.purdue.edu/~hankd/SWAR/</a>), nous développons 
actuellement un compilateur qui admettra des fonctions écrites dans un 
<span class="quote">« <span class="quote">dialecte</span> »</span> explicite parallèle au langage C et qui générera 
des modules SWAR accessibles comme des fonctions C ordinaires, et qui 
feront usage de tous les supports SWAR disponibles, y compris le MMX. 
Les premiers prototypes de compilateurs à modules ont été générés à 
Fall, en 1996. Amener cette technologie vers un état réellement 
utilisable prend cependant beaucoup plus de temps que prévu 
initialement.

</p></li></ol></div><p>
En résumé, le SWAR par MMX est toujours d'un usage malaisé. Toutefois, avec
quelques efforts supplémentaires, la seconde approche décrite ci-dessus peut
être utilisée dès à présent. En voici les bases :
</p><p>

</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
Vous ne pourrez pas utiliser le MMX si votre processeur ne le prend pas
en charge. Le code GCC suivant vous permettra de savoir si votre processeur
est équipé de l'extension MMX. Si c'est le cas, la valeur renvoyée sera
différente de zéro, sinon nulle.

</p><pre class="programlisting">
inline extern
int mmx_init(void)
{
	int mmx_disponible;

	__asm__ __volatile__ (
		/* Récupère la version du CPU */
		"movl $1, %%eax\n\t"
		"cpuid\n\t"
		"andl $0x800000, %%edx\n\t"
		"movl %%edx, %0"
		: "=q" (mmx_disponible)
		: /* pas d'entrée */
	);
	return mmx_disponible;
}
</pre><p>

</p></li><li class="listitem"><p>
Un registre MMX contient essentiellement ce que GCC appellerait un
<code class="literal">unsigned long long</code>. Ainsi, ce sont des variables
de ce type et résidant en mémoire qui vont former le mécanisme de communication
entre les modules MMX et le programme C qui les appelle. Vous pouvez aussi déclarer
vos données MMX comme étant des structures de données alignées sur des adresses
multiples de 64 bits (il convient de garantir l'alignement sur 64 bits en déclarant
votre type de données comme étant membre d'une <code class="literal">union</code>
comportant un champ <code class="literal">unsigned long long</code>).
</p></li><li class="listitem"><p>
Si le MMX est disponible, vous pouvez écrire votre code MMX en utilisant
la directive assemble <code class="literal">.byte</code> pour coder chaque
instruction. C'est un travail pénible s'il est abattu à la main, mais pour un
compilateur, les générer n'est pas très difficile. Par exemple, l'instruction MMX
<code class="literal">PADDB MM0,MM1</code> pourrait être encodée par la ligne
d'assembleur in-line GCC suivante :


</p><pre class="programlisting">
__asm__ __volatile__ (".byte 0x0f, 0xfc, 0xc1\n\t");
</pre><p>


Souvenez-vous que le MMX utilise une partie du matériel destiné aux opérations
en virgule flottante, et donc que le code ordinaire mélangé au MMX ne doit pas
invoquer ces dernières. La pile en virgule flottante doit également être vide
avant l'exécution de tout code MMX. Cette pile est normalement vide à l'entrée
d'une fonction C ne faisant pas usage de la virgule flottante.


</p></li><li class="listitem"><p>
Clôturez votre code MMX par l'exécution de l'instruction <code class="literal">EMMS</code>,
qui peut être encodée par :


</p><pre class="programlisting">
__asm__ __volatile__ (".byte 0x0f, 0x77\n\t");
</pre><p>

</p></li></ol></div><p>

</p><p>
Tout ce qui précède paraît rébarbatif, et l'est. Ceci dit, le MMX
est encore assez jeune… de futures versions de ce document proposeront
de meilleures techniques pour programmer le SWAR MMX.
</p></div></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title"><a id="d0e4903"/>5. Processeurs auxiliaires des machines Linux</h2></div></div></div><p>
Même si cette approche n'est plus à la mode depuis quelques temps,
il reste virtuellement impossible aux autres méthodes de maintenir à
la fois prix bas et performances élevées, chose habituellement rendue
possible par l'utilisation d'un système Linux, lorsqu'il s'agit
d'héberger dans la machine une unité de calcul dédiée. Le problème est
que la prise en charge logicielle de ces outils est très limitée.
Nous serons plus ou moins livrés à nous mêmes.
</p><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e4908"/>5.1. Un PC Linux est une bonne station d'accueil</h3></div></div></div><p>
En général, les processeurs secondaires tendent à se spécialiser dans
l'exécution de fonctions bien spécifiques.
</p><p>
Avant de se sentir découragés parce que livrés à nous-mêmes, il est
utile de comprendre que, bien qu'il puisse être difficile de le préparer
à recevoir un système particulier, un PC sous Linux reste l'une des rares
plate-formes qui se prêtent convenablement à cet usage.
</p><p>
Un PC forme un bon système d'accueil pour deux raisons : La première est sa capacité
à évoluer aisément et de façon peu onéreuse. Les ressources telles que
la mémoire, les disques, le réseau et autres peuvent être ajoutées
vraiment très facilement à un PC. La seconde est sa facilité d'interfaçage.
Non seulement les prototypes de cartes ISA et PCI sont largement répandus
et disponibles, mais le port parallèle fournit également des performances
raisonnables dans une interface discrète. L'adressage séparé des entrées / sorties
de l'architecture IA32 facilite également l'interfaçage en offrant
une protection de ces adresses au niveau du port individuel.
</p><p>
Linux est également un bon système d'exploitation pour l'hébergement de
systèmes dédiés. La libre et complète disponibilité du code source, et les
nombreux manuels de programmation avancée constituent évidement une aide
très précieuse. Mais Linux apporte également une gestion des tâches pratiquement
temps-réel. Il existe même une version fonctionnant en vrai temps-réel.
Mais une chose peut-être plus importante encore est le fait que, même
dans un environnement Unix complet, Linux sait prendre en charge des outils
de développement écrits pour fonctionner sous MS-DOS ou Windows. Les programmes
DOS peuvent être exécutés dans un processus Unix en utilisant
<code class="literal">dosemu</code>, qui dresse une machine virtuelle protégée
qui peut littéralement exécuter du code MS-DOS. La prise en charge des programmes
Windows 3.xx sous Linux est encore plus directe : certains 
logiciels libres comme
<a class="ulink" href="http://www.winehq.org" target="_top"><code class="literal">wine</code></a>
simulent Windows 3.11<a href="#ftn.d0e4926" class="footnote" id="d0e4926"><sup class="footnote">[26]</sup></a>

suffisamment bien pour permettre à la plupart des programmes
Windows d'être exécutés correctement sur une machine Unix équipée de 
X-Window.

</p><p>
Les deux sections suivantes donnent des exemples de systèmes parallèles
auxiliaires que j'aimerais voir être exploités sous Linux :
</p></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e4932"/>5.2. Avez-vous essayé le DSP ?</h3></div></div></div><p>
Un marché prospère s'est développé autour des puces DSP (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Digital
Signal Processing</em></span></span> »</span>, ou <span class="quote">« <span class="quote">Traitement Numérique du Signal</span> »</span>) à hautes performances. Bien
qu'elles soient en général conçues pour être embarquées dans des systèmes dédiés à
des usages bien spécifiques, elles peuvent aussi être utilisées comme de très bons
ordinateurs parallèles annexes. Voici pourquoi :
</p><p>

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
Plusieurs d'entre elles, comme le TMS320 de
<a class="ulink" href="http://www.ti.com" target="_top">Texas Instruments</a> et la famille
SHARC d'<a class="ulink" href="http://www.analog.com" target="_top">Analog Devices</a> sont
conçues pour permettre l'assemblage de machines parallèles
en n'utilisant que très peu, voire aucun circuit logique intermédiaire.
</p></li><li class="listitem"><p>
Ces puces sont bon marché, spécialement au niveau du coût par MIP ou par
MFLOP. Prix des circuits de gestion logique de base compris, on peut trouver
un processeur DSP pour le dixième du prix du processeur d'un PC, à performances
comparables.

</p></li><li class="listitem"><p>
Elle ne nécessitent que peu de puissance et ne dissipent pas beaucoup de
chaleur. Cela signifie qu'il est possible d'alimenter toute une poignée de processeurs
de ce type avec une simple alimentation PC conventionnelle, et de les enfermer
dans le boîtier d'un PC sans transformer celui-ci en haut-fourneau.

</p></li><li class="listitem"><p>
La plupart des jeux d'instructions des DSP contiennent des choses assez
exotiques et que les langages de haut niveau (c'est-à-dire : comme le
C) ne sont pas à même d'utiliser correctement. Par exemple, l'<span class="quote">« <span class="quote">adressage de
bit inversé</span> »</span>. En utilisant des systèmes parallèles inclus dans une machine,
il est possible de compiler et d'exécuter directement la plupart du code sur
cette machine, tout en confiant l'exécution des quelques algorithmes consommant
la plupart du temps système aux DSP, par l'entremise d'un code particulièrement soigné
et optimisé à la main.

</p></li><li class="listitem"><p>
Ces DSP ne sont pas vraiment conçus pour faire fonctionner un système d'exploitation
UNIX ou assimilé, et ne sont généralement pas non plus adaptés à une utilisation
autonome comme processeur général d'un ordinateur. Le système de gestion de la mémoire,
par exemple, est insuffisant pour beaucoup d'entre eux. En d'autres mots, ils sont bien
plus efficaces lorsqu'ils sont intégrés au sein d'une machine hôte plus polyvalente
… telle qu'un PC sous Linux.
</p></li></ul></div><p>

</p><p>
Bien que de nombreux modems et cartes son contiennent des processeurs DSP
accessibles par des pilotes Linux, les grands profits arrivent avec l'utilisation de
systèmes parallèles intégrés comprenant au moins quatre processeurs DSP.
</p><p>
Même si la série TMS320 de Texas Instruments, sur <a class="ulink" href="http://dspvillage.ti.com" target="_top">http://dspvillage.ti.com</a>, est populaire depuis un bon moment, les systèmes de ce type étant
disponibles sont encore peu nombreux. Il existe à la fois une version
uniquement entière et une version virgule flottante du TMS320. Les
anciens modèles utilisaient un format de virgule flottante en simple précision assez
inhabituel, mais les nouveaux gèrent à présent les formats IEEE. Les anciens TMS320C4x
(ou simplement <span class="quote">« <span class="quote">C4x</span> »</span>), accomplissaient jusqu'à 80 MFLOP en utilisant le format de
nombre en virgule flottante simple précision spécifique à TI. En comparaison, un seul
<span class="quote">« <span class="quote">C67x</span> »</span> apportera jusqu'à 1 GFLOP en simple précision et 420 MFLOP en double précision
au format IEEE, en utilisant une architecture à base de VLIW nommée VelociTI. Non seulement
il est aisé de configurer un groupe de circuits de ce type pour en faire un multiprocesseur,
mais un de ces circuits, le multiprocesseur <span class="quote">« <span class="quote">'C8x</span> »</span>, formera à lui seul un processeur
principal à technologie RISC accusant 100 MFLOP au format IEEE, et doté soit de deux, soit
de quatre DSP esclaves intégrés.
</p><p>
L'autre famille de processeurs DSP qui ne soit pas simplement utilisée
ces temps-ci par quelques rares systèmes en parallèle est SHARC (ou
<span class="quote">« <span class="quote">ADSP-2106x</span> »</span>), d'<a class="ulink" href="http://www.analog.com/" target="_top">Analog Devices</a>.
Ces circuits peuvent être configurés en un multiprocesseur à mémoire partagée
formé par 6 processeurs sans nécessiter de logique externe pour les associer, et
peuvent aussi former de plus grands systèmes grâce à des circuits de liaison de
4 bits. Les systèmes au-delà de celui-ci sont essentiellement destinés aux applications
militaires, et reviennent assez cher. Toutefois, 
<a class="ulink" href="http://www.iced.com/" target="_top">Integrated Computing Engines, Inc.</a> produit un petit jeu de deux cartes PCI assez intéressant, nommé GreenICE. Cette
unité contient un réseau de 16 processeurs SHARC, et affiche une vitesse de pointe
d'1.9 GFLOP au format IEEE simple précision. GreenICE coûte moins de 5000 dollars.
</p><p>
À mon avis, les circuits DSP parallèles intégrés mériteraient une plus grande attention
de la part du petit monde du calcul en parallèle sous Linux…
</p></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e5001"/>5.3. Calcul à l'aide des FPGA et circuits logiques reconfigurables</h3></div></div></div><p>

Si l'objectif final du traitement en parallèle reste l'atteinte des plus 
hautes vitesses possibles, et bien pourquoi ne pas fabriquer du matériel 
sur mesure ? Nous connaissons tous la réponse : Trop cher, 
trop long à développer, le matériel ainsi conçu devient inutile lorsque 
l'algorithme change même de façon minime, et cætera. Cependant, les 
récentes avancées faites dans le domaine des FPGA 
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Field Programmable Gate 
Array</em></span></span> »</span>, ou <span class="quote">« <span class="quote">Réseaux Logiques Programmables 
à effet de Champ</span> »</span>) ont réduit à néant la plupart de ces 
objections. Aujourd'hui, la densité des portes logiques est suffisamment 
élevée pour qu'un processeur entier puisse être intégré dans un seul 
FPGA, et le temps de reconfiguration (ou de reprogrammation) d'un de ces 
FPGA a également chuté à un niveau où l'on peut raisonnablement 
reconfigurer le circuit même entre deux phases d'un même algorithme.

</p><p>
Il ne faut pas avoir froid aux yeux pour utiliser ces techniques : Il
faudra travailler avec des langages de description matérielle tels que
le VHDL pour configurer les FPGA, tout comme écrire du code de bas niveau
pour programmer les interfaces avec le système d'accueil Linux. En revanche,
le coût des FPGA est assez bas, spécialement pour les algorithmes opérant
sur des données entières et de précision normale (ce qui ne représente en fait
qu'un surensemble restreint de tout ce à quoi le SWAR s'applique bien), ces FPGA
peuvent effectuer des opérations complexes à peu près aussi vite qu'on peut les
leur transmettre. Par exemple, de simples systèmes à base de FPGA ont accusé des
performances supérieures à celles des supercalculateurs lors de recherches sur
des bases de données génétiques.
</p><p>
Il existe plusieurs compagnies produisant du matériel approprié à base de FPGA,
mais les deux suivantes en sont un bon exemple :
</p><p>

Virtual Computer Company propose toute une gamme de produits utilisant 
des FPGA Xilinx à base de SRAM et reconfigurables dynamiquement. Leur 
<span class="quote">« <span class="quote">Virtual ISA Proto Board</span> »</span> 8/16 bits coûte moins de 2000 
dollars.

</p><p>
L'ARC-PCI d'Altera (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Altera Reconfigurable Computer</em></span></span> »</span>, sur bus PCI), sur <a class="ulink" href="http://www.altera.com/html/new/pressrel/pr_arc-pci.html" target="_top">http://www.altera.com/html/new/pressrel/pr_arc-pci.html</a>, est un type de carte similaire, mais utilisant les FPGA d'Altera et un
bus PCI comme interface plutôt qu'un bus ISA.
</p><p>

Bon nombre de ces outils de conception, langages de description 
matérielle, compilateurs, routeurs, et cætera, sont livrés sous forme 
d'un code objet qui ne fonctionne que sous DOS ou Windows. Nous 
pourrions simplement conserver une partition DOS/Windows sur notre PC 
d'accueil et redémarrer lorsque nous en avons besoin. Toutefois, la 
plupart de ces outils peuvent probablement fonctionner sous Linux en 
utilisant <code class="literal">dosemu</code> ou des émulateurs Windows tels que 
<code class="literal">wine</code>.

</p></div></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title"><a id="d0e5039"/>6. D'intérêt général</h2></div></div></div><p>
Les sujets couverts dans cette section s'appliquent aux quatre
modèles de traitement en parallèle sous Linux.
</p><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e5044"/>6.1. Compilateurs et langages de programmation</h3></div></div></div><p>
Je suis principalement un <span class="quote">« <span class="quote">chercheur en compilateurs</span> »</span>. Je devrais
donc être capable de dire s'il y a beaucoup de compilateurs vraiment
performants, générant du code parallèle efficace pour les systèmes Linux.
Malheureusement, et pour dire la vérité, il est difficile de battre les performances
obtenues en exprimant votre programme en parallèle avec des communications
et autres opérations parallèles, le tout dans un code en langage C, compilé
par GCC.
</p><p>
Les projets de compilateurs ou de langages suivants représentent une
partie des meilleurs efforts produits pour la génération d'un code
raisonnablement efficace depuis les langages de haut niveau. Généralement,
chacun d'eux est raisonnablement efficace pour les tâches qu'il vise,
mais aucun ne correspond aux langages et aux compilateurs puissants et
tout-terrain qui vous feront abandonner définitivement l'écriture de programmes
C compilés par GCC… ce qui est très bien comme çà. Utilisez ces langages
et compilateurs à ce pour quoi ils ont été conçus, et vous serez récompensés
par des durées de développement plus courtes, des opérations de maintenance et de
débogages réduites, et cætera.
</p><p>
Il existe un grand nombre de langages et de compilateurs en dehors de ceux listés
ici (dans l'ordre alphabétique). Une liste de compilateurs librement
disponibles (la plupart n'ayant rien à voir avec le traitement en parallèle
sous Linux) est accessible ici : <a class="ulink" href="http://www.idiom.com/free-compilers" target="_top">http://www.idiom.com/free-compilers</a>.
</p><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e5059"/>6.1.1. Fortran 66/77/PCF/90/HPF/95</h4></div></div></div><p>
Au moins dans la communauté de l'informatique scientifique, le Fortran
sera toujours présent. Bien sûr, le Fortran d'aujourd'hui n'a plus la
même signification que celle définie par le standard ANSI de 1966. En
quelques mots, le Fortran 66 était très limité. Le Fortran 77 a ajouté
des nuances dans ses fonctions, la plus intéressante étant la prise en
charge améliorée des données de type caractère et la modification de la
sémantique des boucles <code class="literal">DO</code>. Le Fortran PCF
(<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Parallel Computing Forum</em></span></span> »</span>) a tenté d'ajouter diverses fonctions de
gestion de traitement en parallèle au Fortran 77. Le Fortran 90 est un langage moderne
et pleinement fonctionnel, qui apporte essentiellement des facilités de programmation
orientée objet ressemblant au C++ et une syntaxe de tableaux en parallèle au langage
du Fortran 77. HPF (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">High-Performance Fortran</em></span></span> »</span>, lui-même
proposé en deux versions (HPF-1 et HPF-2), est essentiellement
la version standardisée et améliorée de ce que beaucoup d'entre nous ont connu
sous les noms de CM Fortran, MasPar Fortran, ou Fortran D. Il étend le Fortran 90
avec diverses améliorations dédiées au traitement en parallèle, très centrées
sur la spécification d'agencements de données. Citons enfin le Fortran 95,
version quelque peu améliorée et raffinée du Fortran 90.
</p><p>
Ce qui fonctionne avec le C peut en général fonctionner aussi avec  <code class="literal">f2c</code>,
<code class="literal">g77</code>, ou les produits Fortran 90/95 commerciaux de NAG.
Ceci est dû au fait que tous ces compilateurs peuvent au final produire le
même code que celui utilisé en arrière-boutique par GCC.
</p><p>
Les paralléliseurs Fortran commerciaux pouvant générer du code pour SMP
sont disponibles sur <a class="ulink" href="http://www.kai.com" target="_top">http://www.kai.com</a> et <a class="ulink" href="http://www.crescentbaysoftware.com" target="_top">http://www.crescentbaysoftware.com</a>.
Il n'est pas clairement indiqué si ces compilateurs sont utilisables pour
des machines SMP Linux, mais ils devraient l'être étant donné que les <span class="foreignphrase"><em class="foreignphrase">threads</em></span>
POSIX standards (soit les LinuxThreads) fonctionnent sur des systèmes SMP sous Linux.
</p><p>
Le <a class="ulink" href="http://www.pgroup.com/" target="_top">Portlan Group</a> propose des compilateurs Fortran HPF (et C/C++) parallèles commerciaux
générant du code Linux SMP. Il existe aussi une version ciblant les <span class="foreignphrase"><em class="foreignphrase">clusters</em></span>
s'appuyant sur MPI ou PVM. Les produits de <a class="ulink" href="http://www.apri.com" target="_top">http://www.apri.com</a> pourraient aussi être utiles sur des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> ou des machines SMP.
</p><p>
Parmi les Fortran parallélisés disponibles librement et qui pourraient
fonctionner sur des systèmes Linux en parallèle, citons :
</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
ADAPTOR (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Automatic DAta Parallelism TranslaTOR</em></span></span> »</span>, <a class="ulink" href="http://www.gmd.de/SCAI/lab/adaptor/adaptor_home.html" target="_top">http://www.gmd.de/SCAI/lab/adaptor/adaptor_home.html</a>,
qui peut traduire du Fortran HPF en Fortran 77/90 avec appels MPI
ou PVM, mais qui ne mentionne pas Linux.
</p></li><li class="listitem"><p>
Fx, de l'Université Carnegie Mellon (N.D.T. : Pittsburgh), vise 
certains
<span class="foreignphrase"><em class="foreignphrase">clusters</em></span> de stations de travail, mais Linux ?
</p></li><li class="listitem"><p>
HPFC (un prototype de Compilateur HPF) génère du code Fortran 77
avec appels PVM. Est-il utilisable sur un <span class="foreignphrase"><em class="foreignphrase">cluster</em></span> Linux ?
</p></li><li class="listitem"><p>
PARADIGM (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">PARAllelizing compiler for DIstributed-memory
General-purpose Multicomputers</em></span></span> »</span>, <a class="ulink" href="http://www.crhc.uiuc.edu/Paradigm" target="_top">http://www.crhc.uiuc.edu/Paradigm</a>) peut-il
lui aussi être utilisé avec Linux ?
</p></li><li class="listitem"><p>
Le compilateur Polaris génère du code Fortran pour multiprocesseurs à mémoire partagée,
et pourrait bientôt être reciblé vers les <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> Linux PAPERS.

</p></li><li class="listitem"><p>
PREPARE, <a class="ulink" href="http://www.irisa.fr/EXTERNE/projet/pampa/PREPARE/prepare.html" target="_top">http://www.irisa.fr/EXTERNE/projet/pampa/PREPARE/prepare.html</a>,
vise les <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> MPI… On ne sait pas
vraiment s'il sait générer du code pour processeurs IA32.

</p></li><li class="listitem"><p>
Combinant ADAPT et ADLIB, <span class="quote">« <span class="quote">shpf</span> »</span> (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Subset High Performance Fortran
compilation system</em></span></span> »</span>)
est dans le domaine public et génère du code Fortran 90 avec appels MPI.
Donc, si vous avez un compilateur Fortran 90 sous Linux…

</p></li><li class="listitem"><p>
SUIF (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Stanford University Intermediate Form</em></span></span> »</span>, voir <a class="ulink" href="http://suif.stanford.edu" target="_top">
http://suif.stanford.edu</a>) propose des compilateurs parallélisés pour le C et le Fortran.
C'est aussi l'objectif du <span class="foreignphrase"><em class="foreignphrase">National Compiler Infrastructure Project</em></span><span class="quote">« <span class="quote">Quelqu'un s'occupe-t-il des systèmes parallèles sous Linux ?</span> »</span>
</p></li></ul></div><p>

Je suis sûr d'avoir omis plusieurs compilateurs potentiellement utiles 
dans les différents dialectes du Fortran, mais ils sont si nombreux 
qu'il est difficile d'en garder la trace. A l'avenir, je préférerais ne 
lister que ceux qui sont réputés fonctionner sous Linux. Merci de 
m'envoyer commentaires et corrections en anglais par courrier 
électronique à

<code class="email">&lt;<a class="email" href="mailto:hankd CHEZ engr POINT uky POINT edu">hankd CHEZ engr POINT uky POINT edu</a>&gt;</code>.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e5189"/>6.1.2. GLU (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Granular Lucid</em></span></span> »</span>)</h4></div></div></div><p>
GLU (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Granular Lucid</em></span></span> »</span>) est un système de programmation de très haut niveau
basé sur un modèle hybride combinant les modèles intentionnel (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Lucid</em></span></span> »</span>) et
impératif. Il reconnaît à la fois les <span class="foreignphrase"><em class="foreignphrase">sockets</em></span> PVM et TCP. Fonctionne-t-il sous
Linux ? (Le site du <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Computer Science Laboratory</em></span></span> »</span> se trouve sur
<a class="ulink" href="http://www.csl.sri.com" target="_top">http://www.csl.sri.com</a>.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e5216"/>6.1.3. Jade et SAM</h4></div></div></div><p>
Jade est un langage de programmation en parallèle sous forme d'extension au
langage C et exploitant les concurrences de la granularité des programmes séquentiels et
impératifs. Il s'appuie sur un modèle de mémoire partagée distribuée, modèle implémenté
par SAM dans les <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> de stations de travail utilisant PVM. Plus d'informations
sur
<a class="ulink" href="http://suif.stanford.edu/~scales/sam.html" target="_top">http://suif.stanford.edu/~scales/sam.html</a>.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e5227"/>6.1.4. Mentat et Legion</h4></div></div></div><p>
Mentat est un système de traitement en parallèle orienté objet qui fonctionne
avec des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> de stations de travail et qui a été porté vers Linux. Le
<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Mentat Programming Language</em></span></span> »</span> (MPL) est un langage de programmation orienté
objet basé sur le C++. Le système temps-réel de Mentat utilise quelque chose
qui ressemble vaguement à des appels de procédures à distance (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">remote
procédure calls</em></span></span> »</span> : RPC) non bloquantes. Plus d'informations sur <a class="ulink" href="http://www.cs.virginia.edu/~mentat" target="_top">http://www.cs.virginia.edu/~mentat</a>.
</p><p>
Legion <a class="ulink" href="http://www.cs.virginia.edu/~legion/" target="_top">http://www.cs.virginia.edu/~legion</a> est construit au dessus de Mentat, et simule une machine virtuelle unique
au travers des machines d'un réseau large zone.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e5251"/>6.1.5. MPL (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">MasPar Programming Language</em></span></span> »</span>)</h4></div></div></div><p>

À ne pas confondre avec le MPL de Mentat, ce langage était initialement 
développé pour être le dialecte C parallèle natif des supercalculateurs 
SIMD MasPar. MasPar ne se situe plus vraiment sur ce segment (ils 
s'appellent maintenant <a class="ulink" href="http://www.neovista.com" target="_top">NeoVista 
Solutions</a> et se spécialisent dans le <span class="foreignphrase"><em class="foreignphrase">data 
mining</em></span><a href="#ftn.d0e5265" class="footnote" id="d0e5265"><sup class="footnote">[27]</sup></a>, mais leur compilateur MPL a été construit en 
utilisant GCC. Il est donc librement disponible. Dans un effort concerté 
entre les université de l'Alabama, à Huntsville, et celle de Purdue, le 
MPL MasPar a été reciblé pour générer du code C avec appels AFAPI (voir 
la section 3.6), et fonctionne ainsi à la fois sur des machines Linux de 
type SMP et sur des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span>. Le 
compilateur est, néanmoins, quelque peu bogué… voir <a class="ulink" href="http://www.math.luc.edu/~laufer/mspls/papers/cohen.ps" target="_top">http://www.math.luc.edu/~laufer/mspls/papers/cohen.ps</a>.

</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e5277"/>6.1.6. PAMS (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Parallel Application Management System</em></span></span> »</span>)</h4></div></div></div><p>
Myrias est une compagnie qui vend un logiciel nommé PAMS (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Parallel
Application Management System</em></span></span> »</span>). PAMS fournit des directives très
simples destinées au traitement en parallèle utilisant de la mémoire
partagée virtuelle. Les réseaux de machines Linux ne sont pas encore
pris en charge.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e5290"/>6.1.7. Parallaxis-III</h4></div></div></div><p>
Parallaxis-III est un langage de programmation structurée qui reprend
Modula-2, en ajoutant des <span class="quote">« <span class="quote">processeurs et connexions virtuels</span> »</span> pour
le parallélisme des données (un modèle SIMD). La suite Parallaxis
comprend des compilateurs pour ordinateurs séquentiels et parallèles,
un débogueur (extension des débogueurs <code class="literal">gdb</code>
et <code class="literal">xgdb</code>), et une vaste gamme d'algorithmes
d'exemple de différents domaines, en particulier dans le traitement des
images. Il fonctionne sur les systèmes Linux séquentiels. Une ancienne
version prenait déjà en charge diverses plate-formes parallèles, et une
prochaine version le fera à nouveau (comprendre : ciblera les <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> PVM).
Plus d'informations sur <a class="ulink" href="http://www.informatik.uni-stuttgart.de/ipvr/bv/p3/p3.html" target="_top">http://www.informatik.uni-stuttgart.de/ipvr/bv/p3/p3.html</a>.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e5310"/>6.1.8. pC++/Sage++</h4></div></div></div><p>
pC++/Sage++ est une extension au langage C autorisant les opérations de
type <span class="quote">« <span class="quote">données en parallèle</span> »</span>, en utilisant des <span class="quote">« <span class="quote">collections d'objets</span> »</span>
formées à partir de classes <span class="quote">« <span class="quote">éléments</span> »</span> de base. Il s'agit d'un préprocesseur
générant du code C++ pouvant fonctionner en environnement PVM. Est-ce que
cela fonctionne sous Linux ? Plus d'informations ici : <a class="ulink" href="http://www.extreme.indiana.edu/sage/" target="_top">http://www.extreme.indiana.edu/sage</a>.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e5327"/>6.1.9. SR (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Synchronizing Resources</em></span></span> »</span>)</h4></div></div></div><p>
SR (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Synchronizing Resources</em></span></span> »</span>, ou <span class="quote">« <span class="quote">ressources synchronisées</span> »</span>)
est un langage de programmation de situations concurrentes et dans lequel les ressources
encapsulent les processus et les variables qu'ils partagent. Les <span class="quote">« <span class="quote">opérations</span> »</span>
forment le principal mécanisme d'interactions entre processus. SR propose une
intégration novatrice des mécanismes utilisées pour invoquer et traiter les
opérations. En conséquence, les appels de procédures locaux ou à distance,
les rendez-vous, le <span class="foreignphrase"><em class="foreignphrase">message passing</em></span>, la création dynamique de processus, la
multi-diffusion et les sémaphores sont tous pris en charge. SR gère également
les variables et opérations globales partagées.
</p><p>
Il existe une adaptation Linux, mais le type de parallélisme que SR peut y
faire fonctionner n'est pas clairement défini. Plus d'informations sur <a class="ulink" href="http://www.cs.arizona.edu/sr/www/index.html" target="_top">http://www.cs.arizona.edu/sr/www/index.html</a>.
</p></div><div class="sect3"><div class="titlepage"><div><div><h4 class="title"><a id="d0e5354"/>6.1.10. ZPL et IronMan</h4></div></div></div><p>
ZPL est un langage de programmation par matrices conçu pour gérer les
applications scientifiques et d'ingénierie. Il génère des appels à une
interface de <span class="foreignphrase"><em class="foreignphrase">message-passing</em></span> assez simple nommée IronMan, et les quelques
fonctions qui constituent cette interface peuvent facilement être
implémentées à l'aide de pratiquement n'importe quel système de <span class="foreignphrase"><em class="foreignphrase">message-passing</em></span>.
Il est toutefois principalement tourné vers PVM et MPI sur des <span class="foreignphrase"><em class="foreignphrase">clusters</em></span>
de stations de travail, et peut fonctionner sous Linux. Plus d'informations sur
<a class="ulink" href="http://www.cs.washington.edu/research/zpl/home/index.html" target="_top">http://www.cs.washington.edu/research/zpl/home/index.html</a>.
</p></div></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e5371"/>6.2. Question de performance</h3></div></div></div><p>
Beaucoup de gens passent beaucoup de temps à faire des mesures de
performances <span class="quote">« <span class="quote">au banc d'essai</span> »</span> de cartes-mères particulières, de
carte réseau, et cætera, pour déterminer laquelle d'entre elles est la
meilleure. Le problème de cette approche est que, le temps d'arriver à des
résultats probants, le matériel testé peut ne plus être le meilleur.
Il peut même être retiré du marché et remplacé par un modèle révisé et
aux propriétés radicalement différentes.
</p><p>
Acheter du matériel pour PC, c'est un peu comme acheter du jus d'orange.
Il est généralement fabriqué à partir de produits de bonne qualité, et ce
quelque soit le nom de la compagnie qui le distribue. Peu de gens connaissent
ou se soucient de la provenance de ces composant (ou du concentré de jus
d'orange). Ceci dit, il existe quelques différences auxquelles on devrait
être attentif. Mon conseil est simple : Soyez simplement conscients de ce
que vous pouvez attendre de votre matériel lorsqu'il fonctionne sous Linux,
puis portez votre attention sur la rapidité de livraison, un prix raisonnable
et une garantie convenable.
</p><p>
Il existe un excellent aperçu des différents processeurs pour PC sur <a class="ulink" href="http://www.pcguide.com/ref/cpu/fam/" target="_top">http://www.pcguide.com/ref/cpu/fam/</a>; En fait, le site <a class="ulink" href="http://www.pcguide.com/" target="_top">PC Guide</a> entier est rempli de bonnes présentations techniques
de l'électronique d'un PC. Il est également utile d'en savoir un peu sur les
performances et la configuration d'un matériel spécifique, et le <a class="ulink" href="http://www.traduc.org/docs/howto/lecture/Benchmarking-HOWTO.html" target="_top">Linux Benchmarking HOWTO</a> est un bon document pour commencer.
</p><p>

Les processeurs Intel IA32 sont dotés de plusieurs registres spéciaux 
qui peuvent être utilisés pour mesurer les performances d'un système en 
fonction dans ses moindres détails. Le VTune d'Intel, sur <a class="ulink" href="http://developer.intel.com/design/perftool/vtune" target="_top">http://developer.intel.com/design/perftool/vtune</a>, fait un usage 
poussé de ces registres de performances, dans un système d'optimisation 
du code vraiment très complet… qui malheureusement ne fonctionne 
pas sous Linux. Un pilote sous forme de module chargeable et une 
bibliothèque de fonctions servant à accéder aux registres de 
performances du Pentium sont disponibles et ont été écrits par Cuneyt 
Akinlar. Souvenez-vous que ces registres de performance sont différents 
selon les processeurs IA32. Ce code ne fonctionnera donc que sur un 
Pentium, pas sur un 486, ni sur un Pentium Pro, un Pentium II, un K6, et 
cætera.

</p><p>

Il y a encore un commentaire à faire à propos des performances, destiné 
spécialement à ceux qui veulent monter de grands 
<span class="foreignphrase"><em class="foreignphrase">clusters</em></span> dans de petits espaces. Les 
processeurs modernes incorporent pour certains des capteurs de 
température, et utilisent des circuits ralentissant la cadence du 
processeur lorsque cette température dépasse un certain seuil (tentative 
de réduction des émissions de chaleur et d'amélioration de la 
fiabilité). Je ne suis pas en train de dire que tout le monde devrait 
sortir s'acheter un module à effet Peltier (ou <span class="quote">« <span class="quote">pompe à 
chaleur</span> »</span>) pour refroidir chaque CPU, mais que nous devrions être 
conscients du fait qu'une température trop élevé ne se contente pas de 
raccourcir la durée de vie des composants, mais agit aussi directement 
sur les performances d'un système. Ne placez vos ordinateurs dans des 
configurations pouvant bloquer le flux d'air, piégeant la chaleur dans 
des zones confinées, et cætera.

</p><p>

Enfin, les performances ne sont pas seulement une question de vitesse, 
mais également de fiabilité et de disponibilité. Une haute fiabilité 
signifie que votre système ne plantera pratiquement jamais, même si un 
composant vient à tomber en panne… ce qui nécessite généralement 
un matériel spécial comme une alimentation redondante et une carte-mère 
autorisant le remplacement <span class="quote">« <span class="quote">à chaud</span> »</span> des équipements qui y 
sont connectés. Tout cela est en général assez cher. Une haute 
disponibilité signifie que votre système sera prêt à être utilisé 
pratiquement tout le temps. Le système peut planter si l'un des 
composants tombe en panne, mais il pourra être réparé et redémarré très 
rapidement. Le High-Availability HOWTO traite plusieurs des cas de base 
de la haute disponibilité. En revanche, dans le cas des 
<span class="foreignphrase"><em class="foreignphrase">clusters</em></span>, une haute disponibilité peut 
être assurée en prévoyant simplement quelques pièces de rechange. 
Éliminer le matériel défectueux et le remplacer par une de ces pièces de 
rechange peut apporter une plus grande disponibilité pour un coût 
d'entretien moins élevé que celui d'un contrat de maintenance.

</p></div><div class="sect2"><div class="titlepage"><div><div><h3 class="title"><a id="d0e5412"/>6.3. Conclusion — C'est fini !</h3></div></div></div><p>
Alors, y a-t-il quelqu'un dans l'assemblée qui fasse du traitement en
parallèle sous Linux ? Oui !
</p><p>

Il y a encore peu de temps, beaucoup de gens se demandaient si la mort 
de plusieurs compagnies fabricant des supercalculateurs parallèles 
n'annonçait pas la fin du traitement en parallèle. Ce n'était alors pas 
mon opinion (voir <a class="ulink" href="http://dynamo.ecn.purdue.edu/~hankd/Opinions/pardead.html" target="_top">http://dynamo.ecn.purdue.edu/~hankd/Opinions/pardead.html</a> pour 
un aperçu assez amusant de ce qui, à mon avis, s'est vraiment passé), et 
il semble assez clair qu'aujourd'hui le traitement en parallèle est à 
nouveau sur une pente ascendante. Même Intel, qui n'a cessé que 
récemment de produire des supercalculateurs parallèles, est fier du 
soutien apporté au traitement en parallèle par des choses comme le MMX, 
et l'EPIC (<span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Explicitly Parallel Instruction 
Computer</em></span></span> »</span>, ou <span class="quote">« <span class="quote">Ordinateur à jeu 
d'Instructions Parallèles Explicites</span> »</span>) de l'IA64.

</p><p>

Si vous faites une recherche sur les mots <span class="quote">« <span class="quote">Linux</span> »</span> et 
<span class="quote">« <span class="quote">Parallèle</span> »</span> dans votre moteur de recherche favori, vous 
trouverez un certain nombre d'endroits impliqués dans le traitement en 
parallèle sous Linux. Les <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> de PC 
sous Linux, en particulier, font leur apparition un peu partout. Le fait 
que Linux se prête particulièrement bien à ce genre de tâche combiné aux 
coûts réduits et aux hautes performances du matériel pour PC ont fait du 
traitement en parallèle sous Linux une approche populaire, tant pour les 
groupes au budget restreint que pour les vastes laboratoires de 
recherche nationaux confortablement subventionnés.

</p><p>

Certains projets énumérés dans ce document tiennent une liste de sites 
de recherche <span class="quote">« <span class="quote">apparentés</span> »</span> utilisant des configurations 
Linux parallèles similaires. Vous trouvez cependant sur <a class="ulink" href="http://yara.ecn.purdue.edu/~pplinux/Sites" target="_top">http://yara.ecn.purdue.edu/~pplinux/Sites</a> un document hypertexte 
dont le but est d'apporter photographies, descriptions et contacts vers 
les sites de tous les projets utilisant Linux pour effectuer des 
traitement en parallèle. Si vous voulez voir votre propre site y 
figurer :

</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>

Vous devez avoir un site <span class="quote">« <span class="quote">permanent</span> »</span> présentant le 
fonctionnement d'un système Linux en parallèle : Une machine SMP, 
un système SWAR, ou un PC équipé de processeurs dédiés, configuré pour 
permettre aux utilisateurs d'<span class="emphasis"><em>exécuter des programmes 
parallèles sous Linux</em></span>. Un environnement logiciel basé sur 
Linux et prenant directement en charge la gestion du traitement en 
parallèle (tel que PVM, MPI ou AFAPI) doit être installé sur le système. 
En revanche, le matériel ne doit pas nécessairement être dédié au 
traitement en parallèle sous Linux et peut être employé à des tâches 
complètement différentes lorsque les programmes parallèles ne sont pas 
en cours d'exécution.

</p></li><li class="listitem"><p>

Vous devez formuler une demande pour que votre site apparaisse sur cette 
liste. Envoyez vos informations en anglais à

<code class="email">&lt;<a class="email" href="mailto:hankd CHEZ engr POINT uky POINT edu">hankd CHEZ engr POINT uky POINT edu</a>&gt;</code>.

Merci de respecter le format utilisé par les autres entrées pour les 
informations concernant votre site. <span class="emphasis"><em>Aucun site ne sera 
répertorié sans demande explicite de la part du responsable de ce 
site</em></span>.

</p></li></ul></div><p>

Quatorze <span class="foreignphrase"><em class="foreignphrase">clusters</em></span> sont actuellement 
répertoriés dans cette liste, mais nous avons été informés de 
l'existence de plusieurs douzaines de 
<span class="foreignphrase"><em class="foreignphrase">clusters</em></span> Linux à travers le monde. Bien 
sûr, cette inscription n'implique aucun engagement. Notre objectif est 
simplement de favoriser le développement des connaissances, de la 
recherche et de la collaboration impliquant le traitement en parallèle 
sous Linux.

</p></div></div><div class="footnotes"><br/><hr width="100" align="left"/><div id="ftn.d0e493" class="footnote"><p><a href="#d0e493" class="para"><sup class="para">[1] </sup></a>

N.D.T. : <span class="quote"><span class="quote"><span class="foreignphrase"><em class="foreignphrase">flat memory 
model</em></span></span></span>, dans lequel toute la mémoire se trouve 
dans le même plan mémoire, par opposition aux segments, mémoire paginée, 
et tout autre modèle composé.

</p></div><div id="ftn.d0e709" class="footnote"><p><a href="#d0e709" class="para"><sup class="para">[2] </sup></a>

N.D.T. : décomposition d'un programme en plusieurs processus 
distincts, mais travaillant simultanément et de concert.

</p></div><div id="ftn.d0e732" class="footnote"><p><a href="#d0e732" class="para"><sup class="para">[3] </sup></a>

N.D.T. : qui a démarré la machine avant de passer en mode SMP.

</p></div><div id="ftn.d0e759" class="footnote"><p><a href="#d0e759" class="para"><sup class="para">[4] </sup></a>
N.D.T. : le lien vers l'ancienne version 1.1, lui, n'existe plus. La 
documentation la plus récente se trouve à ce jour sur <a class="ulink" href="http://www.intel.com/design/Pentium4/documentation.htm" target="_top">http://www.intel.com/design/Pentium4/documentation.htm</a>.
</p></div><div id="ftn.d0e1148" class="footnote"><p><a href="#d0e1148" class="para"><sup class="para">[5] </sup></a>

N.D.T. : inséré au sein du code source, ici en C.

</p></div><div id="ftn.d0e1247" class="footnote"><p><a href="#d0e1247" class="para"><sup class="para">[6] </sup></a>
 
N.D.T. : soit, sous Unix, être sous le compte <code class="literal">root</code>.

</p></div><div id="ftn.d0e1280" class="footnote"><p><a href="#d0e1280" class="para"><sup class="para">[7] </sup></a>

N.D.T. : temporisations introduites au sein d'un programme en 
utilisant par exemple des boucles et en consommant ainsi tout le temps 
machine alloué au processus plutôt qu'en rendant la main au système.

</p></div><div id="ftn.d0e1399" class="footnote"><p><a href="#d0e1399" class="para"><sup class="para">[8] </sup></a>

N.D.T. : <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">spin 
locks</em></span></span> »</span> : mise en état d'attente jusqu'à ce 
qu'une condition soit remplie.

</p></div><div id="ftn.d0e1606" class="footnote"><p><a href="#d0e1606" class="para"><sup class="para">[9] </sup></a>

N.D.T. : Il s'agit en fait d'un appel Unix standard.

</p></div><div id="ftn.d0e1830" class="footnote"><p><a href="#d0e1830" class="para"><sup class="para">[10] </sup></a>

N.D.T. : il semble que ce panel ne soit plus mis à jour depuis un 
certain temps. Le site suggéré proposait à la date de rédaction de la 
version française le bulletin le plus récent, mais n'est pas officiel.

</p></div><div id="ftn.d0e2401" class="footnote"><p><a href="#d0e2401" class="para"><sup class="para">[11] </sup></a>

N.D.T. : désormais intégré aux sources du noyau.

</p></div><div id="ftn.d0e2418" class="footnote"><p><a href="#d0e2418" class="para"><sup class="para">[12] </sup></a>

N.D.T. : les pilotes FC pour le noyau Linux ont en fait été écrits 
en 1999.

</p></div><div id="ftn.d0e2465" class="footnote"><p><a href="#d0e2465" class="para"><sup class="para">[13] </sup></a>

N.D.T. : La <span class="foreignphrase"><em class="foreignphrase">Fibre Channel 
Association</em></span> (FCA) et la <span class="foreignphrase"><em class="foreignphrase">Fibre Channel 
Loop Community</em></span> (FCLC) ont fusionné en 2000 pour former 
la <span class="foreignphrase"><em class="foreignphrase">Fibre Channel Industry Association</em></span>.

</p></div><div id="ftn.d0e2489" class="footnote"><p><a href="#d0e2489" class="para"><sup class="para">[14] </sup></a>

N.D.T. : les premiers pilotes FireWire pour Linux ont été écrits en 
1999 mais, bien que disponibles en standard, sont toujours considérés 
comme expérimentaux.

</p></div><div id="ftn.d0e2562" class="footnote"><p><a href="#d0e2562" class="para"><sup class="para">[15] </sup></a>

N.D.T. : HiPPI est aujourd'hui pris en charge par Linux, mais de 
façon restreinte et expérimentale.

</p></div><div id="ftn.d0e2641" class="footnote"><p><a href="#d0e2641" class="para"><sup class="para">[16] </sup></a>

N.D.T. : l'IrDA est pris en charge par le noyau depuis 2000.

</p></div><div id="ftn.d0e2753" class="footnote"><p><a href="#d0e2753" class="para"><sup class="para">[17] </sup></a>

SAN : <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">System Area 
Network</em></span></span> »</span>.

</p><p>

N.D.T. : à ne pas confondre avec <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">Storage Area 
Network</em></span></span> »</span>, qui partage le même acronyme.

</p></div><div id="ftn.d0e2967" class="footnote"><p><a href="#d0e2967" class="para"><sup class="para">[18] </sup></a>

N.D.T. : Sequent a été absorbé par IBM en septembre 1999.

</p></div><div id="ftn.d0e3099" class="footnote"><p><a href="#d0e3099" class="para"><sup class="para">[19] </sup></a>

N.D.T. : et donc désormais à Hewlett-Packard.

</p></div><div id="ftn.d0e3380" class="footnote"><p><a href="#d0e3380" class="para"><sup class="para">[20] </sup></a>

N.D.T. : les ports et le standard USB sont aujourd'hui parfaitement 
reconnus par Linux.

</p></div><div id="ftn.d0e3590" class="footnote"><p><a href="#d0e3590" class="para"><sup class="para">[21] </sup></a>

N.D.T. : par opposition à un <span class="quote">« <span class="quote">appel système</span> »</span>, donc sans franchir
la barrière du passage en mode noyau.

</p></div><div id="ftn.d0e4123" class="footnote"><p><a href="#d0e4123" class="para"><sup class="para">[22] </sup></a>

N.D.T. : MOSIX fonctionne aujourd'hui sous Linux.

</p></div><div id="ftn.d0e4330" class="footnote"><p><a href="#d0e4330" class="para"><sup class="para">[23] </sup></a>

N.D.T. : initialement, huit liens étaient proposés à cet endroit, 
devenus pour la plupart obsolètes.

</p></div><div id="ftn.d0e4386" class="footnote"><p><a href="#d0e4386" class="para"><sup class="para">[24] </sup></a>

N.D.T. : FLOP = <span class="quote">« <span class="quote"><span class="foreignphrase"><em class="foreignphrase">FLoating point 
OPeration</em></span></span> »</span>, ou <span class="quote">« <span class="quote">OPération en Virgule 
Flottante</span> »</span>.

</p></div><div id="ftn.d0e4746" class="footnote"><p><a href="#d0e4746" class="para"><sup class="para">[25] </sup></a>

N.D.T. : il s'agit en fait de simuler la ré-entrée par le coté 
opposé des données éjectées par le décalage. L'exemple qui suit permet 
d'implémenter ce cas en langage C, mais la plupart des microprocesseurs 
sont équipés d'instructions de rotation effectuant cela en une seule 
opération.

</p></div><div id="ftn.d0e4926" class="footnote"><p><a href="#d0e4926" class="para"><sup class="para">[26] </sup></a>

N.D.T. : WINE a évolué avec le temps et reconnaît naturellement
les versions plus récentes de ce système d'exploitation.

</p></div><div id="ftn.d0e5265" class="footnote"><p><a href="#d0e5265" class="para"><sup class="para">[27] </sup></a>

N.D.T. : le <span class="foreignphrase"><em class="foreignphrase">data mining</em></span> consiste à 
étudier et mettre au point des techniques efficaces de recherche d'une 
information au travers d'une immense quantité de données.

</p></div></div></div></body></html>