Sin이나 Sqrt 등의 산술 연산과 곱셈의 처리 부하를 비교해 보았는지를 검증해 보았다

16211 단어 mathILSpyC#

전치



이 기사는 다음 기사에 대해 자체 검증을 한 것입니다.

「Sin이나 Sqrt등의 산술 연산과 곱셈의 처리 부하를 비교해 보았다」
htps : // 이 m / 케이 kd ms / ms / 1 66 7480f23c9fbcfc0

Masakari Welcome의 전 기사 저자에게 감사드립니다.

결론



원래 기사의 코드는 어쩌면 최적화로 여러 가지 지워집니다.

여기에서 측정한 결과:


Mult
Sin
Sqrt
아탄
Exp
Pow
Pow2


1배
24.39배
1.20배
35.23배
23.58배
41.82배
31.84배


Windows10에서 C# 콘솔 앱으로 측정, C#의 Math 함수를 이용, 코드는 기사 하단

동기



과연 Sqrt가 Mult보다 빠른 것은 이상하지 않습니까?

디 컴파일 해 보았습니다.



세상에는 C# 바이너리를 소스 코드로 되돌려주는 소프트웨어가 있다
그 중 하나인 ILSpy에 걸어 보기로 한다

결과





대책



C# 최적화 대책을 잘 모르기 때문에
우선 결과가 사용될지도 모른다고 컴파일러를 의심 어둠에 빠뜨려 보자



모든 계산이 f의 최종 값에 영향을 미쳤습니다.
f를 public 멤버에 대입했습니다.

에서 ILSpy



가자.

그 밖에도 ildasm에서 함수 호출 자체가 사라지지 않았는지 봤는데 성과 없었기 때문에 생략

추가



Q : sqrt는 곱셈 나눗셈없이 갈 수 있기 때문에 빠르더라도 보통은?
A: 과연 곱셈 1회보다는 느립니다

Q:Mult 이외는 이전의 계산 결과 사용하고 있지 않아! 최적화되어 있지 않나!
A : 사용하지 않아도 문제없는 코드를 토했기 때문에 그렇게

Sin의 디 컴파일 결과



드디어 기계어 레이어



제대로 fsin 명령으로 루프하고 있음을 알 수 있습니다.
(0x01580CC1에 fsin 명령이 있으며 루프의 jmp 대상은 그 이전의 0x01580CBF, 단계 실행에서도 확인됨)

최종 실행 결과





실행 횟수와 실행에 걸린 시간을 밀리 초 단위로 출력 한 것

구체적으로 몇 배 빠르거나 한 번 더 붙일 때


Mult
Sin
Sqrt
아탄
Exp
Pow
Pow2


1배
24.39배
1.20배
35.23배
23.58배
41.82배
31.84배


결론



unity는 어쩌면 측정 결과와 관련이 없을 것이라는 만심의 근본적이었습니다.

IL Fuck은 f에 대입도 배제한 엄밀 계측하고 싶었지만 C# 힘이 부족하다

기사도 더 보기 좋게 하고 싶었지만 qiita 힘이 부족하다

자신은 C#별로 쓰지 않기 때문에 실수가 있겠지만, 발견 한 사람은이 기사처럼 검증 기사를 가지고, 제발

마지막으로 검증에 사용한 코드를 넣을 때

MathTest.cs
using System;
using System.Linq;

public class MathTest {
   public double count;
   public double step = 1;

   public MathTest(double count = 1000.0) {
         this.count = count;
   }

   public double trash;
   private void Mult() {
      double f = 1.0;

      for (double i = 0; i < count; i += step) {
         f = f * i;
      }
      trash = f;
   }

   private void Sin() {
      double f = 1.0;

      for (double i = 0; i < count; i += step) {
         f = Math.Sin(i);
      }
      trash = f;
   }

   private void Sqrt() {
      double f = 1.0;

      for (double i = 0; i < count; i += step) {
         f = Math.Sqrt(i);
      }
      trash = f;
   }

   private void Pow() {
      double f = 1.0;

      for (double i = 0; i < count; i += step) {
         f = Math.Pow(i, i);
      }
      trash = f;
   }

   private void Pow2() {
      double f = 1.0;

      for (double i = 0; i < count; i += step) {
         f = Math.Pow(i, 2);
      }
      trash = f;
   }

   private void Atan() {
      double f = 1.0;

      for (double i = 0; i < count; i += step) {
         f = Math.Atan(i);
      }
      trash = f;
   }

   private void Exp() {
      double f = 1.0;

      for (double i = 0; i < count; i += step) {
         f = Math.Exp(i);
      }
      trash = f;
   }

   public long[] run() {
      return new Action[] { Mult, Sin, Sqrt, Atan, Exp, Pow, Pow2 }.Select(act => {
         var sw = new System.Diagnostics.Stopwatch();
         sw.Start();
         act();
         sw.Stop();
         return sw.ElapsedMilliseconds;
      }).ToArray();
   }
}

class Program {
   static void Main(string[] args) {
      new MathTest(100.0).run(); // メモリキャッシュとか対策にちょっと回す
      Console.WriteLine("計測開始(単位はms)");
      Console.WriteLine("Mult, Sin, Sqrt, Atan, Exp, Pow, Pow2");
      foreach (double count in new double[] { 100_000.0, 1_000_000.0, 10_000_000.0, 100_000_000.0 }) {
         Console.WriteLine((int)count);
         Console.WriteLine(String.Join(", ", new MathTest(count).run()));
      }
      Console.ReadLine();
   }
}

좋은 웹페이지 즐겨찾기