Vector2.Normalize ()의 결과가 동일한 입력으로 34 번 호출 된 후 왜 변경됩니까?


10

다음은 간단한 C # .NET Core 3.1 프로그램 System.Numerics.Vector2.Normalize()으로, 모든 호출에서 동일한 입력으로 루프 를 호출 하고 결과 정규화 된 벡터를 인쇄합니다.

using System;
using System.Numerics;
using System.Threading;

namespace NormalizeTest
{
    class Program
    {
        static void Main()
        {
            Vector2 v = new Vector2(9.856331f, -2.2437377f);
            for(int i = 0; ; i++)
            {
                Test(v, i);
                Thread.Sleep(100);
            }
        }

        static void Test(Vector2 v, int i)
        {
            v = Vector2.Normalize(v);
            Console.WriteLine($"{i:0000}: {v}");
        }
    }
}

그리고 내 컴퓨터에서 해당 프로그램을 실행 한 결과는 다음과 같습니다 (간단하게 잘립니다).

0000: <0.9750545, -0.22196561>
0001: <0.9750545, -0.22196561>
0002: <0.9750545, -0.22196561>
...
0031: <0.9750545, -0.22196561>
0032: <0.9750545, -0.22196561>
0033: <0.9750545, -0.22196561>
0034: <0.97505456, -0.22196563>
0035: <0.97505456, -0.22196563>
0036: <0.97505456, -0.22196563>
...

내 질문은 그래서, 왜 호출 한 결과 수행 Vector2.Normalize(v)에서의 변화 <0.9750545, -0.22196561>에를 <0.97505456, -0.22196563>그 34 배를 호출 한 후를? 이것이 예상됩니까, 아니면 언어 / 런타임의 버그입니까?


수레가 이상하다
Milney

2
@Milney 아마도, 그러나 그들은 또한 결정적 입니다. 이 동작은 수레가 이상하다고 설명하는 것이 아닙니다.
Konrad Rudolph

답변:


14

그래서 내 질문은 Vector2.Normalize (v) 호출 결과가 34 번 호출 된 후 <0.9750545, -0.22196561>에서 <0.97505456, -0.22196563>으로 변경되는 이유는 무엇입니까?

먼저 변경이 발생하는 이유. 해당 값을 계산하는 코드도 변경되기 때문에 변경 사항이 관찰됩니다.

코드의 첫 번째 실행에서 WinDbg를 일찍 시작하고 Normalizeed 벡터 를 계산하는 코드로 조금 내려 가면 다음 어셈블리를 볼 수 있습니다.

movss   xmm0,dword ptr [rax]
movss   xmm1,dword ptr [rax+4]
lea     rax,[rsp+40h]
movss   xmm2,dword ptr [rax]
movss   xmm3,dword ptr [rax+4]
mulss   xmm0,xmm2
mulss   xmm1,xmm3
addss   xmm0,xmm1
sqrtss  xmm0,xmm0
lea     rax,[rsp+40h]
movss   xmm1,dword ptr [rax]
movss   xmm2,dword ptr [rax+4]
xorps   xmm3,xmm3
movss   dword ptr [rsp+28h],xmm3
movss   dword ptr [rsp+2Ch],xmm3
divss   xmm1,xmm0
movss   dword ptr [rsp+28h],xmm1
divss   xmm2,xmm0
movss   dword ptr [rsp+2Ch],xmm2
mov     rax,qword ptr [rsp+28h]

~ 30 회 실행 후 (이 번호에 대해서는 나중에 더) 코드는 다음과 같습니다.

vmovsd  xmm0,qword ptr [rsp+70h]
vmovsd  qword ptr [rsp+48h],xmm0
vmovsd  xmm0,qword ptr [rsp+48h]
vmovsd  xmm1,qword ptr [rsp+48h]
vdpps   xmm0,xmm0,xmm1,0F1h
vsqrtss xmm0,xmm0,xmm0
vinsertps xmm0,xmm0,xmm0,0Eh
vshufps xmm0,xmm0,xmm0,50h
vmovsd  qword ptr [rsp+40h],xmm0
vmovsd  xmm0,qword ptr [rsp+48h]
vmovsd  xmm1,qword ptr [rsp+40h]
vdivps  xmm0,xmm0,xmm1
vpslldq xmm0,xmm0,8
vpsrldq xmm0,xmm0,8
vmovq   rcx,xmm0

다른 opcode, 다른 확장-SSE vs AVX 그리고 다른 opcode로 계산의 정밀도가 다릅니다.

이제 그 이유에 대해 더 자세히? .NET Core (버전에 대해서는 확실하지 않지만 3.0으로 가정하지만 2.1에서 테스트 됨)에는 "계층 JIT 컴파일"이라는 것이 있습니다. 처음에는 빠르게 생성되는 코드를 생성하지만 최적이 아닐 수도 있습니다. 나중에 런타임에서 코드가 많이 사용됨을 감지하면 새롭고 최적화 된 코드를 생성하는 데 시간이 더 걸립니다. 이것은 .NET Core의 새로운 기능이므로 이러한 동작은 이전에 관찰되지 않을 수 있습니다.

또한 왜 34 번의 전화를합니까? 계층화 된 컴파일이 시작되는 임계 값이므로 약 30 회의 실행이 발생할 것으로 예상되므로 약간 이상합니다. 상수는 coreclr 의 소스 코드에서 볼 수 있습니다 . 시작될 때 약간의 추가 변동이있을 수 있습니다.

이런 경우인지 set COMPlus_TieredCompilation=0확인하기 위해 실행을 다시 실행 하고 확인하여 환경 변수를 설정하여 계층화 된 컴파일을 비활성화 할 수 있습니다 . 이상한 효과가 사라졌습니다.

C:\Users\lukas\source\repos\FloatMultiple\FloatMultiple\bin\Release\netcoreapp3.1
λ FloatMultiple.exe

0000: <0,9750545  -0,22196561>
0001: <0,9750545  -0,22196561>
0002: <0,9750545  -0,22196561>
...
0032: <0,9750545  -0,22196561>
0033: <0,9750545  -0,22196561>
0034: <0,9750545  -0,22196561>
0035: <0,97505456  -0,22196563>
0036: <0,97505456  -0,22196563>
^C
C:\Users\lukas\source\repos\FloatMultiple\FloatMultiple\bin\Release\netcoreapp3.1
λ set COMPlus_TieredCompilation=0

C:\Users\lukas\source\repos\FloatMultiple\FloatMultiple\bin\Release\netcoreapp3.1
λ FloatMultiple.exe

0000: <0,97505456  -0,22196563>
0001: <0,97505456  -0,22196563>
0002: <0,97505456  -0,22196563>
...
0032: <0,97505456  -0,22196563>
0033: <0,97505456  -0,22196563>
0034: <0,97505456  -0,22196563>
0035: <0,97505456  -0,22196563>
0036: <0,97505456  -0,22196563>

이것이 예상됩니까, 아니면 언어 / 런타임의 버그입니까?

이미보고 된 버그가 있습니다- 문제 1119


그들은 그것을 일으키는 단서가 없습니다. OP가 후속 조치를 취하고 여기에 답변 링크를 게시 할 수 있기를 바랍니다.
Hans Passant

1
철저하고 유익한 답변에 감사드립니다! 해당 버그 보고서는 실제로이 질문을 게시 한 후에 제출 한 보고서이며 실제로 버그인지 알 수 없습니다. 그들은 변화하는 가치를 원치 않는 행동으로 생각하고 헤 이젠 버그와 고쳐야 할 무언가를 생각하는 것처럼 들립니다.
Walt D

예, 오전 2시에 분석을 수행하기 전에 레포를 확인해야합니다. :) 어쨌든 그것은 흥미로운 문제였습니다.
Paweł Łukasik

@HansPassant 죄송합니다. 제안하신 내용이 확실하지 않습니다. 당신은 명확히 할 수 있습니까?
Walt D

그 github 문제가 당신에 의해 게시되지 않았습니까? 그들이 틀렸다는 것을 그들에게 알려주십시오.
Hans Passant
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.