Chênh lệch hiệu suất rất lớn (nhanh hơn 26 lần) khi biên dịch cho 32 và 64 bit


80

Tôi đang cố gắng đo lường sự khác biệt của việc sử dụng a forvà a foreachkhi truy cập danh sách các kiểu giá trị và kiểu tham chiếu.

Tôi đã sử dụng lớp sau để làm hồ sơ.

public static class Benchmarker
{
    public static void Profile(string description, int iterations, Action func)
    {
        Console.Write(description);

        // Warm up
        func();

        Stopwatch watch = new Stopwatch();

        // Clean up
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();

        watch.Start();
        for (int i = 0; i < iterations; i++)
        {
            func();
        }
        watch.Stop();

        Console.WriteLine(" average time: {0} ms", watch.Elapsed.TotalMilliseconds / iterations);
    }
}

Tôi đã sử dụng doublecho loại giá trị của mình. Và tôi đã tạo 'lớp giả' này để kiểm tra các loại tham chiếu:

class DoubleWrapper
{
    public double Value { get; set; }

    public DoubleWrapper(double value)
    {
        Value = value;
    }
}

Cuối cùng tôi chạy mã này và so sánh sự khác biệt về thời gian.

static void Main(string[] args)
{
    int size = 1000000;
    int iterationCount = 100;

    var valueList = new List<double>(size);
    for (int i = 0; i < size; i++) 
        valueList.Add(i);

    var refList = new List<DoubleWrapper>(size);
    for (int i = 0; i < size; i++) 
        refList.Add(new DoubleWrapper(i));

    double dummy;

    Benchmarker.Profile("valueList for: ", iterationCount, () =>
    {
        double result = 0;
        for (int i = 0; i < valueList.Count; i++)
        {
             unchecked
             {
                 var temp = valueList[i];
                 result *= temp;
                 result += temp;
                 result /= temp;
                 result -= temp;
             }
        }
        dummy = result;
    });

    Benchmarker.Profile("valueList foreach: ", iterationCount, () =>
    {
        double result = 0;
        foreach (var v in valueList)
        {
            var temp = v;
            result *= temp;
            result += temp;
            result /= temp;
            result -= temp;
        }
        dummy = result;
    });

    Benchmarker.Profile("refList for: ", iterationCount, () =>
    {
        double result = 0;
        for (int i = 0; i < refList.Count; i++)
        {
            unchecked
            {
                var temp = refList[i].Value;
                result *= temp;
                result += temp;
                result /= temp;
                result -= temp;
            }
        }
        dummy = result;
    });

    Benchmarker.Profile("refList foreach: ", iterationCount, () =>
    {
        double result = 0;
        foreach (var v in refList)
        {
            unchecked
            {
                var temp = v.Value;
                result *= temp;
                result += temp;
                result /= temp;
                result -= temp;
            }
        }

        dummy = result;
    });

    SafeExit();
}

Tôi đã chọn ReleaseAny CPUcác tùy chọn, chạy chương trình và nhận được thời gian như sau:

valueList for:  average time: 483,967938 ms
valueList foreach:  average time: 477,873079 ms
refList for:  average time: 490,524197 ms
refList foreach:  average time: 485,659557 ms
Done!

Sau đó, tôi chọn tùy chọn Phát hành và x64, chạy chương trình và nhận được thời gian như sau:

valueList for:  average time: 16,720209 ms
valueList foreach:  average time: 15,953483 ms
refList for:  average time: 19,381077 ms
refList foreach:  average time: 18,636781 ms
Done!

Tại sao phiên bản x64 bit nhanh hơn rất nhiều? Tôi mong đợi một số khác biệt, nhưng không phải là một cái gì đó lớn như thế này.

Tôi không có quyền truy cập vào các máy tính khác. Bạn có thể vui lòng chạy nó trên máy của bạn và cho tôi biết kết quả được không? Tôi đang sử dụng Visual Studio 2015 và tôi có Intel Core i7 930.

Đây là SafeExit()phương pháp để bạn có thể tự biên dịch / chạy:

private static void SafeExit()
{
    Console.WriteLine("Done!");
    Console.ReadLine();
    System.Environment.Exit(1);
}

Theo yêu cầu, sử dụng double?thay vì của tôi DoubleWrapper:

Mọi CPU

valueList for:  average time: 482,98116 ms
valueList foreach:  average time: 478,837701 ms
refList for:  average time: 491,075915 ms
refList foreach:  average time: 483,206072 ms
Done!

x64

valueList for:  average time: 16,393947 ms
valueList foreach:  average time: 15,87007 ms
refList for:  average time: 18,267736 ms
refList foreach:  average time: 16,496038 ms
Done!

Cuối cùng nhưng không kém phần quan trọng: tạo x86hồ sơ mang lại cho tôi kết quả sử dụng gần như giống nhauAny CPU .


14
"Bất kỳ CPU nào"! = "32Bits"! Nếu được biên dịch "Bất kỳ CPU nào", ứng dụng của bạn sẽ chạy dưới dạng quy trình 64bit trên hệ thống 64bit của bạn. Ngoài ra, tôi muốn xóa mã gây rối với GC. Nó không thực sự giúp ích.
Thorsten Dittmar

9
@ThorstenDittmar các cuộc gọi GC là trước khi đo lường, chứ không phải trong mã được đo. Đó là một điều đủ hợp lý để làm để giảm mức độ may rủi của thời gian GC có thể ảnh hưởng đến phép đo như vậy. Ngoài ra, có "ưu đãi 32-bit" và "ưu tiên 64-bit" như một yếu tố giữa các bản dựng.
Jon Hanna

1
@ThorstenDittmar Nhưng tôi chạy phiên bản phát hành (bên ngoài Visual Studio) và Trình quản lý tác vụ cho biết đó là một ứng dụng 32 bit (khi được biên dịch sang Bất kỳ CPU nào). Cũng thế. Như Jon Hanna đã nói, cuộc gọi GC rất hữu ích.
Trauer

2
Bạn đang sử dụng phiên bản thời gian chạy nào? RyuJIT mới trong 4.6 nhanh hơn rất nhiều , nhưng ngay cả đối với các phiên bản trước đó, trình biên dịch x64 và JITer mới hơn và tiên tiến hơn so với các phiên bản x32. Chúng có thể thực hiện tối ưu hóa tích cực hơn nhiều so với các phiên bản x86.
Panagiotis Kanavos,

2
Tôi lưu ý rằng loại liên quan dường như không có tác dụng; thay đổi doublethành float, longhoặc intvà bạn nhận được kết quả tương tự.
Jon Hanna

Câu trả lời:


87

Tôi có thể tái tạo điều này trên 4.5.2. Không có RyuJIT ở đây. Cả hai cách tháo gỡ x86 và x64 trông hợp lý. Kiểm tra phạm vi và như vậy là giống nhau. Cấu trúc cơ bản giống nhau. Không có vòng lặp nào đang mở.

x86 sử dụng một tập hợp các lệnh float khác. Hiệu suất của các lệnh này dường như có thể so sánh được với các lệnh x64 ngoại trừ phép chia :

  1. Các lệnh float 32 bit x87 sử dụng độ chính xác 10 byte bên trong.
  2. Độ phân chia chính xác mở rộng siêu chậm.

Hoạt động phân chia làm cho phiên bản 32 bit cực kỳ chậm. Không lưu ý sự phân chia sẽ cân bằng hiệu suất ở một mức độ lớn (32 bit giảm từ 430ms xuống 3,25ms).

Peter Cordes chỉ ra rằng độ trễ lệnh của hai đơn vị dấu phẩy động không khác nhau. Có thể một số kết quả trung gian là số không chuẩn hóa hoặc NaN. Những điều này có thể kích hoạt một đường dẫn chậm ở một trong các đơn vị. Hoặc, có thể các giá trị khác nhau giữa hai triển khai do độ chính xác float 10 byte so với 8 byte.

Peter Cordes cũng chỉ ra rằng tất cả các kết quả trung gian đều là NaN ... Loại bỏ vấn đề này ( valueList.Add(i + 1)để không có số chia nào là 0) hầu hết cân bằng kết quả. Rõ ràng, mã 32 bit không thích toán hạng NaN chút nào. Hãy in một số giá trị trung gian: if (i % 1000 == 0) Console.WriteLine(result);. Điều này xác nhận rằng dữ liệu hiện đã ổn định.

Khi đo điểm chuẩn, bạn cần xác định khối lượng công việc thực tế. Nhưng ai có thể nghĩ rằng một bộ phận vô tội có thể làm sai lệch điểm chuẩn của bạn ?!

Hãy thử tổng hợp các con số một cách đơn giản để có được điểm chuẩn tốt hơn.

Phân chia và mô đun luôn rất chậm. Nếu bạn sửa đổi Dictionarymã BCL để đơn giản là không sử dụng toán tử mô-đun để tính toán hiệu suất chỉ số nhóm có thể đo lường sẽ cải thiện. Đây là cách phân chia chậm.

Đây là mã 32 bit:

nhập mô tả hình ảnh ở đây

Mã 64 bit (cấu trúc giống nhau, phân chia nhanh):

nhập mô tả hình ảnh ở đây

Điều này không được vector hóa mặc dù đã sử dụng hướng dẫn SSE.


11
"Ai có thể nghĩ rằng một bộ phận vô tội có thể làm xáo trộn điểm chuẩn của bạn?" Tôi đã làm, ngay lập tức khi tôi nhìn thấy sự phân chia trong vòng lặp bên trong, đặc biệt. như một phần của chuỗi phụ thuộc. Phép chia chỉ vô tội khi nó là phép chia số nguyên cho lũy thừa 2. Từ bảng agner.org/optimize insn: Nehalem fdivcó độ trễ 7-27 chu kỳ (và thông lượng tương hỗ như nhau). divsdlà 7-22 chu kỳ. addsdở độ trễ 3c, thông lượng 1 / c. Division là đơn vị thực thi không pipelined duy nhất trong CPU Intel / AMD. C # JIT không vectơ hóa vòng lặp cho x86-64 (with divPd).
Peter Cordes

1
Ngoài ra, 32b C # không sử dụng toán học SSE có bình thường không? Không thể sử dụng các tính năng của phần máy hiện tại của JIT? Vì vậy, trên Haswell trở lên, nó có thể tự động vectơ hóa các vòng lặp số nguyên với 256b AVX2, thay vì chỉ SSE. Để vectơ hóa các vòng lặp FP, tôi đoán bạn phải viết chúng với những thứ như 4 bộ tích lũy song song, vì toán học FP không phải là liên kết. Nhưng dù sao, sử dụng SSE ở chế độ 32 bit sẽ nhanh hơn, vì bạn có ít hướng dẫn hơn để thực hiện cùng một công việc vô hướng khi bạn không phải xếp chồng x87 FP.
Peter Cordes

4
Dù sao, div rất chậm, nhưng 10B x87 fdiv không chậm hơn 8B SSE2, vì vậy điều này không giải thích sự khác biệt giữa x86 và x86-64. Những gì có thể giải thích nó là các ngoại lệ FPU hoặc làm chậm với đơn vị / vô hạn. Từ điều khiển FPU x87 tách biệt với thanh ghi điều khiển làm tròn / ngoại lệ SSE ( MXCSR). NaNTôi có thể nghĩ rằng cách xử lý khác nhau của các đơn vị hoặc s có thể giải thích được yếu tố của 26 điểm khác biệt. C # có thể đặt đơn vị đo lường-là-không trong MXCSR.
Peter Cordes

2
@Trauer và usr: Tôi chỉ nhận thấy rằng valueList[i] = i, bắt đầu từ i=0, vì vậy việc lặp lại vòng lặp đầu tiên thực hiện 0.0 / 0.0. Vì vậy, mọi hoạt động trong toàn bộ điểm chuẩn của bạn được thực hiện với NaNs. Bộ phận đó càng ngày càng kém vẻ ngây thơ! Tôi không phải là chuyên gia về hiệu suất với NaNs, hoặc sự khác biệt giữa x87 và SSE cho điều này, nhưng tôi nghĩ điều này giải thích sự khác biệt về hiệu suất 26x. Tôi cá rằng kết quả của bạn sẽ gần hơn rất nhiều giữa 32 và 64bit nếu bạn khởi tạo valueList[i] = i+1.
Peter Cordes

1
Đối với flush-to-zero, tôi không quá quan tâm đến nó với đôi 64 bit, nhưng khi 80 bit mở rộng và 64 bit kép được sử dụng cùng nhau, các tình huống mà giá trị 80 bit có thể tràn xuống và sau đó được mở rộng đủ để mang lại một giá trị có thể biểu diễn được vì 64-bit doublesẽ khá hiếm. Một trong những kiểu sử dụng chính của loại 80-bit là cho phép nhiều số được cộng lại với nhau mà không cần phải làm tròn kết quả một cách chặt chẽ cho đến cuối cùng. Theo mô hình đó, tràn không phải là một vấn đề.
supercat

31

valueList[i] = i, bắt đầu từ i=0, vì vậy lặp lại vòng lặp đầu tiên thực hiện 0.0 / 0.0. Vì vậy, mọi hoạt động trong toàn bộ điểm chuẩn của bạn được thực hiện với NaNs.

Như @usr đã hiển thị trong đầu ra tháo gỡ , phiên bản 32bit sử dụng dấu phẩy động x87, trong khi bản 64bit sử dụng dấu phẩy động SSE.

Tôi không phải là chuyên gia về hiệu suất với NaNs, hoặc sự khác biệt giữa x87 và SSE cho điều này, nhưng tôi nghĩ điều này giải thích sự khác biệt về hiệu suất 26x. Tôi cá rằng kết quả của bạn sẽ gần hơn rất nhiều giữa 32 và 64bit nếu bạn khởi tạo valueList[i] = i+1. (cập nhật: usr xác nhận rằng điều này làm cho hiệu suất 32 và 64bit khá gần nhau.)

Việc phân chia diễn ra rất chậm so với các hoạt động khác. Xem nhận xét của tôi về câu trả lời của @ usr. Ngoài ra, hãy xem http://agner.org/optimize/ để biết rất nhiều thứ tuyệt vời về phần cứng và tối ưu hóa asm và C / C ++, một số liên quan đến C #. Anh ấy có các bảng hướng dẫn về độ trễ và thông lượng cho hầu hết các hướng dẫn cho tất cả các CPU x86 gần đây.

Tuy nhiên, 10B x87 fdivkhông chậm hơn nhiều so với độ chính xác kép 8B của SSE2 divsd, đối với các giá trị bình thường. IDK về sự khác biệt hoàn toàn với NaN, số vô hạn hoặc đơn vị.

Tuy nhiên, chúng có các biện pháp kiểm soát khác nhau đối với những gì xảy ra với NaN và các trường hợp ngoại lệ FPU khác. Từ điều khiển FPU x87 tách biệt với thanh ghi điều khiển làm tròn / ngoại lệ SSE (MXCSR). Nếu x87 nhận được một ngoại lệ CPU cho mọi bộ phận, nhưng SSE thì không, điều đó dễ dàng giải thích hệ số 26. Hoặc có thể chỉ có sự khác biệt về hiệu suất quá lớn khi xử lý NaN. Phần cứng không được tối ưu hóa để chạy NaNsau NaN.

IDK nếu SSE kiểm soát để tránh làm chậm bằng đồng tiền sẽ phát huy tác dụng ở đây, vì tôi tin rằng resultsẽ luôn luôn như vậy NaN. IDK nếu C # đặt cờ không có giá trị trong MXCSR hoặc cờ giảm giá trị bằng không (cờ này viết các số 0 ở vị trí đầu tiên, thay vì coi các đơn giá trị là 0 khi đọc lại).

Tôi đã tìm thấy một bài báo của Intel về điều khiển dấu chấm động SSE, đối chiếu nó với từ điều khiển FPU x87. Tuy nhiên, nó không có nhiều điều để nói NaN. Nó kết thúc với điều này:

Phần kết luận

Để tránh các vấn đề về hiệu suất và tuần tự hóa do sai số và số dòng, hãy sử dụng hướng dẫn SSE và SSE2 để đặt chế độ Flush-to-Zero và Denormals-Are-Zero trong phần cứng để kích hoạt hiệu suất cao nhất cho các ứng dụng dấu phẩy động.

IDK nếu điều này giúp bất kỳ với số chia cho-không.

so với foreach

Có thể thú vị khi kiểm tra một phần thân vòng lặp bị giới hạn thông lượng, thay vì chỉ là một chuỗi phụ thuộc được thực hiện theo vòng lặp duy nhất. Vì nó là, tất cả công việc phụ thuộc vào kết quả trước đó; không có gì để CPU làm song song (ngoài việc kiểm tra giới hạn tải mảng tiếp theo trong khi chuỗi mul / div đang chạy).

Bạn có thể thấy sự khác biệt nhiều hơn giữa các phương pháp nếu "công việc thực sự" chiếm nhiều tài nguyên thực thi của CPU hơn. Ngoài ra, trên Intel trước Sandybridge, có một sự khác biệt lớn giữa việc lắp vòng lặp trong bộ đệm vòng lặp 28uop hay không. Bạn nhận được hướng dẫn giải mã tắc nghẽn nếu không, đặc biệt. khi độ dài lệnh trung bình dài hơn (xảy ra với SSE). Các hướng dẫn giải mã đến nhiều hơn một uop cũng sẽ hạn chế thông lượng của bộ giải mã, trừ khi chúng có dạng phù hợp với bộ giải mã (ví dụ: 2-1-1). Vì vậy, một vòng lặp với nhiều hướng dẫn hơn về chi phí vòng lặp có thể tạo ra sự khác biệt giữa vòng lặp có phù hợp trong bộ nhớ cache uop 28 mục nhập hay không, đây là một vấn đề lớn trên Nehalem và đôi khi hữu ích trên Sandybridge và sau đó.


Tôi chưa từng gặp trường hợp nào mà tôi quan sát thấy bất kỳ sự khác biệt nào về hiệu suất dựa trên việc liệu các NaN có trong luồng dữ liệu của tôi hay không, nhưng sự hiện diện của các số không chuẩn hóa có thể tạo ra sự khác biệt lớn về hiệu suất. Có vẻ như không phải như vậy trong ví dụ này, nhưng đó là điều cần lưu ý.
Jason R

@JasonR: Đó có phải chỉ vì NaNs thực sự hiếm trong thực tế? Tôi đã để lại tất cả những thứ về mệnh giá, và liên kết đến những thứ của Intel, chủ yếu là vì lợi ích của người đọc, không phải vì tôi nghĩ rằng nó thực sự sẽ có nhiều ảnh hưởng đến trường hợp cụ thể này.
Peter Cordes

Trong hầu hết các ứng dụng, chúng rất hiếm. Tuy nhiên, khi phát triển phần mềm mới sử dụng dấu phẩy động, không hiếm khi lỗi triển khai mang lại luồng NaN thay vì kết quả mong muốn! Điều này đã xảy ra với tôi nhiều lần và tôi không nhớ lại bất kỳ màn trình diễn đáng chú ý nào khi NaNs bật lên. Tôi đã quan sát thấy điều ngược lại nếu tôi làm điều gì đó khiến những điều bất thường xuất hiện; thường dẫn đến hiệu suất giảm đáng kể ngay lập tức. Lưu ý rằng những điều này chỉ dựa trên kinh nghiệm giai thoại của tôi; có thể có một số sụt giảm hiệu suất với NaN mà tôi không nhận thấy.
Jason R

@JasonR: IDK, có lẽ NaN không chậm hơn nhiều với SSE. Rõ ràng chúng là một vấn đề lớn đối với x87. Ngữ nghĩa của SSE FP được Intel thiết kế trong những ngày PII / PIII. Những CPU đó có cùng một bộ máy bên dưới giống như các thiết kế hiện tại, vì vậy có lẽ chúng có hiệu suất cao cho P6 khi thiết kế SSE. (Đúng, Skylake dựa trên vi kiến ​​trúc P6. Một số thứ đã thay đổi, nhưng nó vẫn giải mã thành uops và lên lịch cho các cổng thực thi với bộ đệm sắp xếp lại.) Ngữ nghĩa x87 được thiết kế cho một chip đồng xử lý bên ngoài tùy chọn cho một CPU vô hướng theo thứ tự.
Peter Cordes

@PeterCordes Gọi Skylake là chip dựa trên P6 là quá xa vời. 1) FPU đã được (gần như) thiết kế lại hoàn toàn trong thời kỳ Sandy Bridge, vì vậy FPU P6 cũ về cơ bản đã biến mất như ngày nay; 2) giải mã x86 to uop đã có một sửa đổi quan trọng trong thời đại Core2: trong khi các thiết kế trước đây giải mã lệnh tính toán và bộ nhớ dưới dạng các uops riêng biệt, chip Core2 + có các uop bao gồm một lệnh tính toán một toán tử bộ nhớ. Điều này dẫn đến hiệu suất và hiệu suất năng lượng tăng lên đáng kể, với chi phí thiết kế phức tạp hơn và tần số đỉnh có thể thấp hơn.
shodanshok

1

Chúng tôi nhận thấy rằng 99,9% tất cả các phép toán dấu phẩy động sẽ liên quan đến NaN, điều này ít nhất là rất bất thường (do Peter Cordes phát hiện trước). Chúng tôi có một thử nghiệm khác của usr, cho thấy rằng việc loại bỏ các hướng dẫn phân chia làm cho chênh lệch thời gian gần như biến mất hoàn toàn.

Tuy nhiên, thực tế là NaN chỉ được tạo ra bởi vì phép chia đầu tiên tính 0,0 / 0,0 cho ra NaN ban đầu. Nếu các phép chia không được thực hiện, kết quả sẽ luôn là 0,0 và chúng tôi sẽ luôn tính 0,0 * temp -> 0,0, 0,0 + temp -> temp, temp - temp = 0,0. Vì vậy, loại bỏ bộ phận không chỉ loại bỏ các bộ phận, mà còn loại bỏ các NaN. Tôi hy vọng rằng NaN thực sự là vấn đề và một triển khai xử lý NaN rất chậm, trong khi triển khai còn lại không gặp vấn đề.

Sẽ rất đáng giá khi bắt đầu vòng lặp ở i = 1 và đo lại. Bốn phép toán cho kết quả là * temp, + temp, / temp, - temp cộng (1 - temp) một cách hiệu quả nên chúng ta sẽ không có bất kỳ số bất thường nào (0, infinity, NaN) cho hầu hết các phép toán.

Vấn đề duy nhất có thể là phép chia luôn cho kết quả số nguyên và một số triển khai phép chia có các phím tắt khi kết quả đúng không sử dụng nhiều bit. Ví dụ: chia 310.0 / 31.0 cho 10.0 là bốn bit đầu tiên với phần còn lại là 0.0 và một số triển khai có thể ngừng đánh giá 50 bit còn lại hoặc lâu hơn trong khi những cách khác thì không. Nếu có sự khác biệt đáng kể, thì việc bắt đầu vòng lặp với kết quả = 1.0 / 3.0 sẽ tạo ra sự khác biệt.


-2

Có thể có một số lý do tại sao điều này thực thi nhanh hơn ở 64 bit trên máy của bạn. Lý do tôi hỏi bạn đang sử dụng CPU nào là vì khi CPU 64bit lần đầu tiên xuất hiện, AMD và Intel có các cơ chế khác nhau để xử lý mã 64bit.

Kiến trúc bộ xử lý:

Kiến trúc CPU của Intel hoàn toàn là 64bit. Để thực thi mã 32 bit, các lệnh 32 bit cần được chuyển đổi (bên trong CPU) sang các lệnh 64 bit trước khi thực thi.

Kiến trúc CPU của AMD là xây dựng 64bit ngay trên kiến ​​trúc 32bit của họ; nghĩa là, về cơ bản, nó là một kiến ​​trúc 32 bit với phạm vi 64 bit - không có quá trình chuyển đổi mã.

Đây rõ ràng là cách đây vài năm, vì vậy tôi không biết liệu công nghệ đã thay đổi như thế nào, nhưng về cơ bản, bạn sẽ mong đợi mã 64bit hoạt động tốt hơn trên máy 64bit vì CPU có thể hoạt động với số lượng gấp đôi bit mỗi lệnh.

.NET JIT

Có ý kiến ​​cho rằng .NET (và các ngôn ngữ được quản lý khác như Java) có khả năng hoạt động tốt hơn các ngôn ngữ như C ++ vì cách trình biên dịch JIT có thể tối ưu hóa mã của bạn theo kiến ​​trúc bộ xử lý của bạn. Về mặt này, bạn có thể thấy rằng trình biên dịch JIT đang sử dụng thứ gì đó trong kiến ​​trúc 64bit mà có thể không có sẵn hoặc yêu cầu giải pháp thay thế khi thực thi ở 32bit.

Ghi chú:

Thay vì sử dụng DoubleWrapper, bạn đã cân nhắc việc sử dụng Nullable<double>hay viết tắt cú pháp: double?- Tôi muốn biết liệu điều đó có ảnh hưởng gì đến các bài kiểm tra của bạn không.

Lưu ý 2: Một số người dường như đang nhầm lẫn ý kiến ​​của tôi về kiến ​​trúc 64bit với IA-64. Chỉ cần làm rõ, trong câu trả lời của tôi, 64bit đề cập đến x86-64 và 32bit đề cập đến x86-32. Không có gì ở đây tham chiếu đến IA-64!


4
OK, vậy tại sao nó nhanh hơn 26 lần? Không thể tìm thấy điều này trong câu trả lời.
usr

2
Tôi đoán đó là sự khác biệt rung động, nhưng không nhiều hơn là đoán.
Jon Hanna

2
@seriesOne: Tôi nghĩ MSalters đang cố nói rằng bạn đang trộn IA-64 với x86-64. (Intel cũng sử dụng IA-32e cho x86-64, trong sách hướng dẫn của họ). CPU máy tính để bàn của mọi người là x86-64. Itanic bị chìm cách đây vài năm và tôi nghĩ chủ yếu được sử dụng trong các máy chủ chứ không phải máy trạm. Core2 (CPU dòng P6 đầu tiên hỗ trợ chế độ dài x86-64) thực sự có một số hạn chế ở chế độ 64bit. ví dụ: uop macro-fusion chỉ hoạt động ở chế độ 32bit. Intel và AMD đã làm điều tương tự: mở rộng thiết kế 32bit của họ lên 64bit.
Peter Cordes

1
@PeterCordes tôi đã đề cập đến IA-64 ở đâu? Tôi biết rằng CPU Itanium là một tập lệnh và thiết kế hoàn toàn khác; các mô hình đầu tiên được gắn thẻ là EPIC hoặc Máy tính hướng dẫn song song rõ ràng. Tôi nghĩ MSalters đang kết hợp 64bit và IA-64. Câu trả lời của tôi đúng với x86-64 architecture- chẳng có gì trong đó tham khảo các gia đình CPU Itanium
Matthew Layton

2
@ series0ne: Ok, vậy thì đoạn của bạn về CPU Intel là "hoàn toàn là 64bit" là hoàn toàn vô nghĩa. Tôi cho rằng bạn đang nghĩ đến IA-64 vì khi đó bạn sẽ không hoàn toàn sai. Không bao giờ có thêm một bước dịch để chạy mã 32bit. Bộ giải mã x86-> uop chỉ có hai chế độ tương tự: x86 và x86-64. Intel đã xây dựng P4 64bit trên P4. 64bit Core2 đi kèm với nhiều cải tiến kiến ​​trúc khác so với Core và Pentium M, nhưng những thứ như kết hợp macro chỉ hoạt động ở chế độ 32bit cho thấy rằng 64bit đã được bắt đầu. (khá sớm trong quá trình thiết kế, nhưng vẫn còn.)
Peter Cordes
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.