/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"><<a class="email" href="mailto:hankd CHEZ engr POINT uky POINT edu">hankd CHEZ engr POINT uky POINT edu</a>></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 <stdlib.h>
#include <stdio.h>
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<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"><<a class="email" href="mailto:dvandenbroeck CHEZ free POINT fr">dvandenbroeck CHEZ free POINT fr</a>></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"><<a class="email" href="mailto:majordomo CHEZ vger POINT rutgers POINT edu">majordomo CHEZ vger POINT rutgers POINT edu</a>></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&R (N.D.T. : Kernigan & 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 *) &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) & ˜(c-1)</code> est égal à
<code class="literal">((int) b) & ˜(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, &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> où <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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#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<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(&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(&thread,NULL,f,&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(&lock)</code> et
<code class="literal">pthread_mutex_unlock(&lock)</code>
comme il se doit.
</p></li><li class="listitem"><p>
Utilisation de <code class="literal">pthread_join(thread,&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 <stdio.h>
#include <stdlib.h>
#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<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(&pi_lock);
pi += sommelocale;
pthread_mutex_unlock(&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(&pi_lock, NULL);
/* Crée les deux threads */
if (pthread_create(&thread0, NULL, process, "0") ||
pthread_create(&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, &retval) ||
pthread_join(thread1, &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">-></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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/shm.h>
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->pi = 0.0;
partage->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<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), &(shared->lock))) ;
shared->pi += sommelocale;
shared->lock = 0;
/* Fin du processus fils (barrière de synchro) */
if (iproc == 0) {
wait(NULL);
printf("Estimation de pi: %f\n", partage->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"><<a class="email" href="mailto:hankd CHEZ engr POINT uky POINT edu">hankd CHEZ engr POINT uky POINT edu</a>></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&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 <stdlib.h>
#include <stdio.h>
#include <pvm3.h>
#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", &argv[1], 0, NULL, NPROC-1, &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<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, &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 <stdlib.h>
#include <stdio.h>
#include <mpi.h>
main(int argc, char **argv)
{
register double largeur;
double somme, sommelocale;
register int intervalles, i;
int nproc, iproc;
MPI_Status status;
if (MPI_Init(&argc, &argv) != MPI_SUCCESS) exit(1);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
MPI_Comm_rank(MPI_COMM_WORLD, &iproc);
intervalles = atoi(argv[1]);
largeur = 1.0 / intervalles;
sommelocale = 0;
for (i=iproc; i<intervalles; i+=nproc) {
register double x = (i + 0.5) * largeur;
sommelocale += 4.0 / (1.0 + x * x);
}
sommelocale *= largeur;
if (iproc != 0) {
MPI_Send(&lbuf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
} else {
somme = sommelocale;
for (i=1; i<nproc; ++i) {
MPI_Recv(&lbuf, 1, MPI_DOUBLE, MPI_ANY_SOURCE,
MPI_ANY_TAG, MPI_COMM_WORLD, &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 <stdlib.h>
#include <stdio.h>
#include <mpi.h>
main(int argc, char **argv)
{
register double largeur;
double somme, sommelocale;
register int intervalles, i;
int nproc, iproc;
if (MPI_Init(&argc, &argv) != MPI_SUCCESS) exit(1);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
MPI_Comm_rank(MPI_COMM_WORLD, &iproc);
intervalles = atoi(argv[1]);
largeur = 1.0 / intervalles;
sommelocale = 0;
for (i=iproc; i<intervalles; i+=nproc) {
register double x = (i + 0.5) * largeur;
sommelocale += 4.0 / (1.0 + x * x);
}
sommelocale *= largeur;
MPI_Reduce(&sommelocale, &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 <stdlib.h>
#include <stdio.h>
#include <mpi.h>
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(&argc, &argv) != MPI_SUCCESS) exit(1);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
MPI_Comm_rank(MPI_COMM_WORLD, &iproc);
MPI_Win_create(&somme, sizeof(somme), sizeof(somme),
0, MPI_COMM_WORLD, &somme_fen);
MPI_Win_fence(0, somme_fen);
intervalles = atoi(argv[1]);
largeur = 1.0 / intervalles;
sommelocale = 0;
for (i=iproc; i<intervalles; i+=nproc) {
register double x = (i + 0.5) * largeur;
sommelocale += 4.0 / (1.0 + x * x);
}
sommelocale *= largeur;
MPI_Accumulate(&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 <stdlib.h>
#include <stdio.h>
#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<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"><<a class="email" href="mailto:hankd CHEZ engr POINT uky POINT edu">hankd CHEZ engr POINT uky POINT edu</a>></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"><<a class="email" href="mailto:condor TIRET admin CHEZ cs POINT wisc POINT edu">condor TIRET admin CHEZ cs POINT wisc POINT edu</a>></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>>, 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"><<a class="email" href="mailto:tmk CHEZ cs POINT rice POINT edu">tmk CHEZ cs POINT rice POINT edu</a>></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">&</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&H 7:0 | C&G 7:0 | B&F 7:0 | A&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 & 0x7f7f7f7f) + (y & 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) & 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) & 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) & 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">& 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 << 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 >> 8) & 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 << 8) | ((x >> 24) & 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<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 & 0x00ff00ff) + ((x >> 8) & 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 >> 16)) & 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"><<a class="email" href="mailto:hankd CHEZ engr POINT uky POINT edu">hankd CHEZ engr POINT uky POINT edu</a>></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"><<a class="email" href="mailto:hankd CHEZ engr POINT uky POINT edu">hankd CHEZ engr POINT uky POINT edu</a>></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>
|