32 비트 및 64 비트 용으로 컴파일 할 때 큰 성능 차이 (26 배 더 빠름)


80

값 유형 및 참조 유형 목록에 액세스 할 때 a for와 a 를 사용하는 차이를 측정하려고했습니다 foreach.

다음 클래스를 사용하여 프로파일 링을 수행했습니다.

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);
    }
}

double내 가치 유형에 사용 했습니다. 그리고 참조 유형을 테스트하기 위해이 '가짜 클래스'를 만들었습니다.

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

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

마지막으로이 코드를 실행하고 시간 차이를 비교했습니다.

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();
}

나는 선택 Release하고 Any CPU옵션을 선택 하고 프로그램을 실행하고 다음과 같은 시간을 얻었습니다.

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!

그런 다음 릴리스 및 x64 옵션을 선택하고 프로그램을 실행하고 다음과 같은 시간을 얻었습니다.

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!

x64 비트 버전이 훨씬 빠른 이유는 무엇입니까? 나는 약간의 차이를 예상했지만 그렇게 큰 것은 아닙니다.

다른 컴퓨터에 액세스 할 수 없습니다. 당신의 컴퓨터에서 이것을 실행하고 결과를 알려주시겠습니까? Visual Studio 2015를 사용하고 있으며 Intel Core i7 930이 있습니다.

SafeExit()방법 은 다음과 같습니다 . 혼자서 컴파일 / 실행할 수 있습니다.

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

요청한대로 double?내 대신 사용 DoubleWrapper:

모든 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!

마지막으로 중요한 점 : x86프로필을 만들면Any CPU .


14
"모든 CPU"! = "32Bits"! "모든 CPU"로 컴파일 된 경우 응용 프로그램은 64 비트 시스템에서 64 비트 프로세스로 실행되어야합니다. 또한 GC를 엉망으로 만드는 코드를 제거 할 것입니다. 실제로 도움이되지 않습니다.
Thorsten Dittmar 2015-08-07

9
@ThorstenDittmar GC 호출은 측정 된 코드가 아닌 측정 전에 이루어집니다. 이는 GC 타이밍의 운이 그러한 측정에 영향을 미칠 수있는 정도를 줄이기 위해 충분히 합리적입니다. 또한 빌드 간의 요인으로 "좋아하는 32 비트"와 "좋아하는 64 비트"가 있습니다.
Jon Hanna

1
@ThorstenDittmar하지만 릴리스 버전 (Visual Studio 외부)을 실행하고 작업 관리자는 32 비트 응용 프로그램 (모든 CPU로 컴파일 할 때)이라고 말합니다. 또한. Jon Hanna가 말했듯이 GC 호출이 유용합니다.
Trauer 2015-08-07

2
어떤 런타임 버전을 사용하고 있습니까? 4.6의 새로운 RyuJIT는 훨씬 빠르지 만 이전 버전에서도 x64 컴파일러와 JITer는 x32 버전보다 더 새롭고 발전했습니다. x86 버전보다 훨씬 더 공격적인 최적화를 수행 할 수 있습니다.
Panagiotis Kanavos

2
관련된 유형이 효과가없는 것 같습니다. 변경 doublefloat, long또는 int당신은 유사한 결과를 얻을 수 있습니다.
Jon Hanna

답변:


87

나는 이것을 4.5.2에서 재현 할 수있다. 여기에 RyuJIT가 없습니다. x86 및 x64 디스 어셈블리 모두 합리적으로 보입니다. 범위 검사 등은 동일합니다. 동일한 기본 구조. 루프 풀림이 없습니다.

x86은 다른 float 명령어 세트를 사용합니다. 이 명령어의 성능은 분할을 제외하고 x64 명령어와 비슷해 보입니다 .

  1. 32 비트 x87 float 명령어는 내부적으로 10 바이트 정밀도를 사용합니다.
  2. 확장 된 정밀도 분할은 매우 느립니다.

분할 작업은 32 비트 버전을 매우 느리게 만듭니다. 분할의 주석 처리를 제거하면 성능 이 크게 향상 됩니다 (430ms에서 3.25ms로 32 비트 감소).

Peter Cordes는 두 개의 부동 소수점 단위의 명령 대기 시간이 그렇게 다르지 않다고 지적합니다. 중간 결과 중 일부는 비정규 화 된 숫자 또는 NaN 일 수 있습니다. 이것은 유닛 중 하나에서 느린 경로를 유발할 수 있습니다. 또는 10 바이트 대 8 바이트 부동 소수점 정밀도 때문에 두 구현간에 값이 다를 수 있습니다.

Peter Cordes 는 또한 모든 중간 결과가 NaN 이라고 지적합니다. 이 문제를 제거하면 ( valueList.Add(i + 1)제수가 0이되지 않도록) 대부분 결과가 동일 해집니다. 분명히 32 비트 코드는 NaN 피연산자를 전혀 좋아하지 않습니다. 중간 값을 인쇄 해 봅시다 : if (i % 1000 == 0) Console.WriteLine(result);. 이것은 데이터가 이제 정상임을 확인합니다.

벤치마킹 할 때 현실적인 워크로드를 벤치마킹해야합니다. 하지만 무고한 부서가 당신의 벤치 마크를 망칠 수 있다고 누가 생각했을까요?!

더 나은 벤치 마크를 얻으려면 단순히 숫자를 합산하십시오.

나누기와 모듈로는 항상 매우 느립니다. Dictionary모듈로 연산자를 사용하지 않도록 BCL 코드를 수정하면 버킷 인덱스 성능이 향상됩니다. 이것이 얼마나 느린 분할인지입니다.

다음은 32 비트 코드입니다.

여기에 이미지 설명 입력

64 비트 코드 (동일한 구조, 빠른 분할) :

여기에 이미지 설명 입력

이것은되어 있지 SSE 명령어를 사용에도 불구하고 벡터화.


11
"무고한 부서가 벤치 마크를 망칠 수 있다고 누가 생각했을까요?" 나는 내부 루프에서 분할을 보자 마자 즉시했습니다. 종속성 체인의 일부로. 나누기는 2의 거듭 제곱으로 정수 나누기 일 때만 무죄합니다. agner.org/optimize insn 테이블에서 : Nehalem fdiv은 7-27 사이클 지연 (및 동일한 상호 처리량)입니다. divsd7-22 사이클입니다. addsd3c 대기 시간, 1 / c 처리량. Division은 Intel / AMD CPU에서 유일한 파이프 라인되지 않은 실행 단위입니다. C # JIT는 x86-64에 대한 루프를 벡터화하지 않습니다 (사용 divPd).
Peter Cordes

1
또한 32b C #에서 SSE 수학을 사용하지 않는 것이 정상입니까? JIT 포인트의 현재 기계 부분의 기능을 사용할 수 없습니까? 따라서 Haswell 이상에서는 SSE 대신 256b AVX2로 정수 루프를 자동 벡터화 할 수 있습니다. FP 루프의 벡터화를 얻으려면 FP 수학이 연관성이 아니기 때문에 4 개의 누산기와 같은 것을 병렬로 작성해야한다고 생각합니다. 그러나 어쨌든 32 비트 모드에서 SSE를 사용하는 것이 더 빠릅니다. x87 FP 스택을 다룰 필요가 없을 때 동일한 스칼라 작업을 수행하는 명령이 적기 때문입니다.
Peter Cordes

4
어쨌든 div는 매우 느리지 만 10B x87 fdiv는 8B SSE2보다 훨씬 느리지 않으므로 x86과 x86-64의 차이를 설명하지 않습니다. 그것을 설명 할 수있는 것은 FPU 예외 또는 비정규 / 무한으로 인한 감속입니다. x87 FPU 제어 단어는 SSE 반올림 / 예외 제어 레지스터 ( MXCSR) 와 별개입니다 . 비정규 또는 NaNs의 다른 처리는 26 perf diff의 요인을 설명한다고 생각할 수 있습니다. C #은 MXCSR에서 비정규를 0으로 설정할 수 있습니다.
Peter Cordes

2
@Trauer 및 usr : valueList[i] = i에서 시작 i=0하여 첫 번째 루프 반복에서 0.0 / 0.0. 따라서 전체 벤치 마크의 모든 작업은 NaNs 로 수행됩니다 . 그 부서는 점점 더 결백 해 보입니다! 나는 NaNs의 성능 이나 x87과 SSE의 차이 에 대한 전문가는 아니지만 이것이 26x 성능 차이를 설명한다고 생각합니다. 초기화하면 결과가 32 비트와 64 비트 사이 에서 훨씬 더 가까워 질 것 valueList[i] = i+1입니다.
Peter Cordes 2015 년

1
0으로 플러시하는 경우 64 비트 더블에 너무 관심이 없지만 80 비트 확장과 64 비트 더블을 함께 사용하면 80 비트 값이 언더 플로되어 충분히 확장 될 수있는 상황 64 비트로 표현할 수있는 값을 산출하는 double것은 매우 드뭅니다. 80 비트 유형의 주요 사용 패턴 중 하나는 끝까지 결과를 단단히 반올림하지 않고도 여러 숫자를 합산 할 수 있도록하는 것이 었습니다. 이 패턴에서 오버플로는 문제가되지 않습니다.
supercat 2015-08-08

31

valueList[i] = i,에서 시작 i=0하므로 첫 번째 루프 반복이 수행 0.0 / 0.0됩니다. 따라서 전체 벤치 마크의 모든 작업은 NaNs 로 수행됩니다 .

으로 @usr이 분해 출력을 보여 64 비트는 SSE 부동 소수점을 사용하면서, 32 비트 버전은 x87 부동 소수점을 사용했다.

나는 NaNs의 성능 이나 x87과 SSE의 차이 에 대한 전문가는 아니지만 이것이 26x 성능 차이를 설명한다고 생각합니다. 초기화하면 결과가 32 비트와 64 비트 사이 에서 훨씬 더 가까워 질 것 valueList[i] = i+1입니다. (업데이트 : usr은 이것이 32 비트 및 64 비트 성능을 상당히 가깝게 만들었다는 것을 확인했습니다.)

분할은 다른 작업에 비해 매우 느립니다. @usr의 답변에 대한 내 의견을 참조하십시오. 또한 http://agner.org/optimize/ 에서 하드웨어와 asm 및 C / C ++ 최적화에 대한 수많은 유용한 정보 를 확인하십시오 . 일부는 C #과 관련이 있습니다. 그는 모든 최신 x86 CPU에 대한 대부분의 명령에 대한 대기 시간 및 처리량에 대한 명령 테이블을 가지고 있습니다.

그러나 10B x87 fdivdivsd일반 값 의 경우 SSE2의 8B 배정 밀도보다 훨씬 느리지 않습니다 . NaN, 무한대 또는 비정규와의 성능 차이에 대한 IDK.

그러나 NaN 및 기타 FPU 예외에서 발생하는 작업에 대해 다른 제어 기능이 있습니다. x87의 FPU 제어 단어 SSE를 라운딩 / 예외 제어 레지스터 (MXCSR)로부터 분리된다. x87이 모든 부서에 대해 CPU 예외를 수신하지만 SSE가 그렇지 않은 경우 26의 요소를 쉽게 설명합니다. 또는 NaN을 처리 할 때 큰 성능 차이가있을 수도 있습니다. 하드웨어는되어 있지 통해 튐에 최적화 NaNNaN.

비정상적인 속도 저하를 피하기위한 SSE 컨트롤이 여기에서 작동한다면 IDK result는 항상 그럴 것이라고 믿기 NaN때문입니다. C #이 MXCSR에서 비정규가 0 인 플래그를 설정하거나 0으로 플러시 플래그를 설정하는 경우 IDK (다시 읽을 때 비정규를 0으로 처리하는 대신 처음에 0을 씁니다).

x87 FPU 제어 단어와 대조되는 SSE 부동 소수점 제어에 대한 인텔 기사를 찾았습니다 . NaN하지만 에 대해 할 말이 많지 않습니다 . 다음과 같이 끝납니다.

결론

비정규 및 언더 플로 번호로 인한 직렬화 및 성능 문제를 방지하려면 SSE 및 SSE2 명령어를 사용하여 하드웨어 내에서 Flush-to-Zero 및 Denormals-Are-Zero 모드를 설정하여 부동 소수점 응용 프로그램에 대한 최고의 성능을 활성화하십시오.

이것이 0으로 나누기에 도움이된다면 IDK.

for와 foreach

하나의 단일 루프 전달 종속성 체인이 아니라 처리량이 제한된 루프 본문을 테스트하는 것이 흥미로울 수 있습니다. 그대로 모든 작업은 이전 결과에 따라 달라집니다. CPU가 병렬로 수행 할 작업이 없습니다 (경계를 제외하고 mul / div 체인이 실행되는 동안 다음 배열로드를 확인).

"실제 작업"이 CPU 실행 리소스를 더 많이 차지하는 경우 메서드간에 더 많은 차이를 볼 수 있습니다. 또한 Sandybridge 이전 Intel에서는 28uop 루프 버퍼의 루프 피팅에 큰 차이가 있습니다. 그렇지 않은 경우 명령 디코딩 병목 현상이 발생합니다. 평균 명령어 길이가 더 긴 경우 (SSE에서 발생). 둘 이상의 uop로 디코딩하는 명령어는 디코더에 적합한 패턴 (예 : 2-1-1)이 아닌 한 디코더 처리량도 제한합니다. 따라서 루프 오버 헤드에 대한 더 많은 명령이있는 루프는 28 개 항목의 uop 캐시에있는 루프 피팅의 차이를 만들 수 있습니다. 이는 Nehalem에서 큰 문제이며 때로는 Sandybridge 이상에서 유용합니다.


NaN이 내 데이터 스트림에 있는지 여부에 따라 성능 차이를 관찰 한 적이 없지만 비정규 화 된 숫자가 있으면 성능에 차이를 만들 수 있습니다 . 이 예에서는 그렇지 않은 것 같지만 명심해야 할 사항입니다.
Jason R

@JasonR : NaN실제로 s가 정말 드물기 때문 인가요? 나는 비정규에 관한 모든 것, 그리고 인텔의 것에 대한 링크를 남겼습니다. 대부분 독자의 이익을 위해,이 특정한 경우에 정말로 많은 영향을 미칠 것이라고 생각했기 때문이 아닙니다.
Peter Cordes 2015 년

대부분의 응용 프로그램에서는 드뭅니다. 그러나 부동 소수점을 사용하는 새로운 소프트웨어를 개발할 때 구현 버그가 원하는 결과 대신 NaN 스트림을 생성하는 것은 드문 일이 아닙니다! 이것은 나에게 여러 번 발생했으며 NaN이 나타날 때 눈에 띄는 성능 저하를 기억하지 못합니다. 비정규 현상이 나타나게하는 일을한다면 그 반대를 관찰했습니다. 일반적으로 성능이 즉시 눈에 띄게 저하됩니다. 이것들은 나의 일화 적 경험에 근거한 것임을 주목하십시오. 방금 눈치 채지 못한 NaN의 성능 저하가있을 수 있습니다.
Jason R

@JasonR : IDK, 아마도 NaN은 SSE에서 더 느리다면 그리 많지 않을 것입니다. 분명히 x87에게는 큰 문제입니다. SSE FP 의미 체계는 PII / PIII 시대에 인텔에서 설계했습니다. 이러한 CPU에는 현재 설계와 동일한 비 순차적 기계가 있으므로 SSE를 설계 할 때 P6에 대한 고성능을 염두에 두었을 것입니다. (예, Skylake는 P6 마이크로 아키텍처를 기반으로합니다. 일부는 변경되었지만 여전히 uop로 디코딩하고 재정렬 버퍼를 사용하여 실행 포트에 예약합니다.) x87 의미 체계는 다음을위한 선택적 외부 코 프로세서 칩을 위해 설계되었습니다. 순차 스칼라 CPU.
Peter Cordes

@PeterCordes Skylake를 P6 기반 칩이라고 부르는 것은 너무 무리입니다. 1) FPU는 Sandy Bridge 시대에 (거의) 완전히 재 설계되었으므로 이전 P6 FPU는 기본적으로 현재까지 사라졌습니다. 2) x86 to uop 디코딩은 Core2 시대에 중요한 수정이있었습니다. 이전 설계는 컴퓨팅 및 메모리 명령을 별도의 uop으로 디코딩하는 반면 Core2 + 칩에는 컴퓨팅 명령 메모리 연산자 로 구성된 uop이 있습니다. 이로 인해 더 복잡한 설계와 잠재적으로 더 낮은 피크 주파수의 비용으로 성능과 전력 효율성이 크게 향상되었습니다.
shodanshok

1

우리는 모든 부동 소수점 연산의 99.9 %가 NaN을 포함 할 것이라는 관찰을 가지고 있는데, 이는 최소한 매우 드문 것입니다 (Peter Cordes가 먼저 발견). usr에 의한 또 다른 실험이 있는데, 나누기 명령을 제거하면 시간차가 거의 완전히 사라진다는 것을 발견했습니다.

그러나 사실은 첫 번째 분할이 초기 NaN을 제공하는 0.0 / 0.0을 계산하기 때문에 NaN이 생성된다는 것입니다. 나누기가 수행되지 않으면 결과는 항상 0.0이되고 항상 0.0 * temp-> 0.0, 0.0 + temp-> temp, temp-temp = 0.0을 계산합니다. 따라서 분할을 제거하면 분할이 제거 될뿐만 아니라 NaN도 제거되었습니다. NaN이 실제로 문제이고 한 구현은 NaN을 매우 느리게 처리하고 다른 구현에는 문제가 없다고 예상합니다.

i = 1에서 루프를 시작하고 다시 측정하는 것이 좋습니다. 4 개의 연산 결과 * temp, + temp, / temp,-temp는 효과적으로 (1-temp)를 더하므로 대부분의 연산에 대해 비정상적인 숫자 (0, 무한대, NaN)가 없습니다.

유일한 문제는 나누기가 항상 정수 결과를 제공하고 일부 나누기 구현에는 올바른 결과가 많은 비트를 사용하지 않을 때 바로 가기가 있다는 것입니다. 예를 들어, 310.0 / 31.0을 나누면 10.0을 처음 4 비트로 제공하고 나머지는 0.0이고 일부 구현은 나머지 50 비트를 평가하는 것을 중지 할 수 있지만 다른 구현은 할 수 없습니다. 상당한 차이가있는 경우 결과 = 1.0 / 3.0으로 루프를 시작하면 차이가 발생합니다.


-2

컴퓨터에서 64 비트에서 더 빠르게 실행되는 데에는 몇 가지 이유가있을 수 있습니다. 어떤 CPU를 사용하고 있는지 물어 본 이유는 64 비트 CPU가 처음 등장했을 때 AMD와 Intel이 64 비트 코드를 처리하는 메커니즘이 다르기 때문입니다.

프로세서 아키텍처 :

인텔의 CPU 아키텍처는 순전히 64 비트였습니다. 32 비트 코드를 실행하기 위해서는 32 비트 명령어를 실행하기 전에 CPU 내부에서 64 비트 명령어로 변환해야했습니다.

AMD의 CPU 아키텍처는 32 비트 아키텍처 바로 위에 64 비트를 구축하는 것이 었습니다. 즉, 기본적으로 64 비트 확장이있는 32 비트 아키텍처였으며 코드 변환 프로세스가 없었습니다.

이것은 분명히 몇 년 전 이었기 때문에 기술이 어떻게 바뀌 었는지 모르겠지만, 기본적으로 64 비트 코드가 64 비트 시스템에서 더 나은 성능을 발휘할 것으로 기대할 수 있습니다. 명령어 당 비트.

.NET JIT

JIT 컴파일러가 프로세서 아키텍처에 따라 코드를 최적화 할 수있는 방식 때문에 .NET (및 Java와 같은 기타 관리 언어)이 C ++와 같은 언어보다 성능이 우수하다고 주장합니다. 이 점에서 JIT 컴파일러는 64 비트 아키텍처에서 사용할 수 없었거나 32 비트에서 실행될 때 해결 방법이 필요한 것을 활용하고 있음을 알 수 있습니다.

노트 :

DoubleWrapper를 사용하는 대신 Nullable<double>또는 약식 구문을 사용하는 것을 고려해 보셨습니까? double?-테스트에 영향을 미치는지 확인하고 싶습니다.

참고 2 : 일부 사람들은 64 비트 아키텍처에 대한 내 의견을 IA-64와 통합하는 것 같습니다. 명확히하기 위해 내 대답에서 64 비트는 x86-64를 나타내고 32 비트는 x86-32를 나타냅니다. 여기에는 IA-64가 언급 된 것이 없습니다!


4
좋아요, 왜 26 배 더 빠릅니까? 대답에서 이것을 찾을 수 없습니다.
usr

2
나는 그것이 지터 차이라고 추측하고 있지만 추측 이상은 아닙니다.
Jon Hanna

2
@seriesOne : MSalters가 IA-64와 x86-64를 섞고 있다고 말하는 것 같습니다. (인텔은 설명서에서 x86-64 용 IA-32e도 사용합니다.) 모든 사람의 데스크탑 CPU는 x86-64입니다. Itanic은 몇 년 전에 침몰했으며 워크 스테이션이 아닌 서버에서 주로 사용되었다고 생각합니다. Core2 (x86-64 롱 모드를 지원하는 최초의 P6 제품군 CPU)는 실제로 64 비트 모드에서 몇 가지 제한이 있습니다. 예를 들어 uop 매크로 융합은 32 비트 모드에서만 작동합니다. Intel과 AMD는 32 비트 디자인을 64 비트로 확장했습니다.
Peter Cordes

1
@PeterCordes 어디서 IA-64를 언급 했습니까? Itanium CPU는 완전히 다른 디자인과 명령어 세트라는 것을 알고 있습니다. EPIC 또는 명시 적 병렬 명령어 컴퓨팅으로 태그가 지정된 초기 모델. MSalters가 64 비트와 IA-64를 결합하고 있다고 생각합니다. 내 대답은 아이태니엄 CPU 제품군을 참조 거기에 아무것도 없었다 - 64 Architecture를 마찬가지입니다
마태 복음 레이튼

2
@ series0ne : 좋습니다. 인텔 CPU가 "순수 64 비트"라는 단락은 완전히 말도 안됩니다. 나는 당신이 IA-64를 생각하고 있다고 생각했습니다. 왜냐하면 당신이 완전히 틀리지 않았을 것이기 때문입니다. 32 비트 코드를 실행하기위한 추가 변환 단계는 없었습니다. x86-> uop 디코더에는 x86 및 x86-64의 두 가지 유사한 모드가 있습니다. Intel은 P4 위에 64 비트 P4를 구축했습니다. 64 비트 Core2는 Core 및 Pentium M에 비해 다른 많은 아키텍처 개선 사항과 함께 제공되었지만 32 비트 모드에서만 작동하는 매크로 퓨전과 같은 것은 64 비트가 고정되었음을 보여줍니다. (상당히 디자인 프로세스 초기이지만 여전히)
Peter Cordes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.