Vì vậy, câu hỏi của tôi là, tại sao kết quả của việc gọi Vector2. Chuẩn hóa (v) thay đổi từ <0.9750545, -0.22196561> thành <0.97505456, -0.22196563> sau khi gọi nó 34 lần?
Vì vậy, đầu tiên - tại sao sự thay đổi xảy ra. Sự thay đổi được quan sát bởi vì mã tính toán các giá trị đó cũng thay đổi.
Nếu chúng ta đột nhập vào WinDbg sớm trong các lần thực thi mã đầu tiên và đi sâu hơn một chút vào mã tính toán Normalize
vectơ ed, chúng ta có thể thấy tập hợp sau (ít nhiều - tôi đã cắt giảm một số phần):
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]
và sau ~ 30 lần thực thi (sẽ nói thêm về số này sau) đây sẽ là mã:
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
Các mã khác nhau, các phần mở rộng khác nhau - SSE so với AVX và, tôi đoán, với các mã khác nhau, chúng tôi có được độ chính xác khác nhau của các phép tính.
Vì vậy, bây giờ nhiều hơn về lý do tại sao? .NET Core (không chắc chắn về phiên bản - giả sử 3.0 - nhưng nó đã được thử nghiệm trong 2.1) có một thứ gọi là "Biên dịch JIT theo tầng". Những gì nó làm là lúc đầu nó tạo ra mã được tạo ra nhanh, nhưng có thể không phải là siêu tối ưu. Chỉ sau này khi bộ thực thi phát hiện ra rằng mã được sử dụng nhiều, nó sẽ dành thêm thời gian để tạo mã mới, tối ưu hơn. Đây là một điều mới trong .NET Core vì vậy hành vi như vậy có thể không được quan sát trước đó.
Ngoài ra tại sao 34 cuộc gọi? Điều này hơi lạ vì tôi dự đoán điều này sẽ xảy ra trong khoảng 30 lần thực thi vì đây là ngưỡng mà quá trình biên dịch theo tầng bắt đầu. Có thể thấy hằng số trong mã nguồn của coreclr . Có thể có một số thay đổi bổ sung khi nó khởi động.
Chỉ cần xác nhận rằng đây là trường hợp, bạn có thể vô hiệu hóa trình biên dịch theo tầng bằng cách đặt biến môi trường bằng cách phát hành set COMPlus_TieredCompilation=0
và kiểm tra lại việc thực hiện. Hiệu ứng lạ đã biến mất.
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>
Đây có phải là dự kiến, hoặc đây là một lỗi trong ngôn ngữ / thời gian chạy?
Đã có một lỗi được báo cáo cho vấn đề này - Số 1119