1

내 랩톱 성능을 비교하는 작은 프로그램을 작성했습니다. 프로그램 CPU를 집중적으로 사용하기 위해 Rabin-Karp 패턴 매칭 알고리즘을 (병렬 API를 통해 구현 된) 멀티 스레딩 코드와 함께 구현했습니다.컴파일러 최적화 플래그가 켜져있는 CPU 집중 응용 프로그램

컴파일러 최적화 플래그를 해제 한 상태에서 프로그램을 실행하면 최적화 플래그가 켜진 상태에서 실행하는 데 걸리는 시간보다 훨씬 더 많은 시간이 걸리는 것으로 나타났습니다.

예를 들어

: 촬영

  • 시간 (최적화 플래그가 꺼져 때) : (. 약) 40초
  • 이 시간 촬영 (최적화 플래그가 켜져) : (. 약) 18초

컴파일러가 어떤 종류의 최적화를 적용하고 있는지 알면 궁금합니다. 성능이 크게 향상됩니다. 이 플래그가 켜지거나 꺼져있는 상태에서 코드가 실행될 때 진행되는 상황을 이해하는 방법에 대한 포인터는 정말 유용 할 것입니다.

코드

void Main() 
{ 
    Dictionary<string,bool> collection = new Dictionary<string,bool>(); 
    IEnumerable<string> commonWords = File.ReadAllLines(@"G:\LINQPad4\words.txt") 
     .Where(x => !string.IsNullOrEmpty(x)).Select(t => t.Trim()); 

    string magna_carta = File.ReadAllText(@"G:\LINQPad4\magna-carta.txt"); 

    Parallel.ForEach(commonWords, 
    () => new Dictionary<string,bool>(), 
    (word, loopState, localState) => 
    { 
     RabinKarpAlgo rbAlgo = new RabinKarpAlgo(magna_carta,word); 
     localState.Add(word,rbAlgo.Match()); 
     return localState; 
    }, 
    (localState) => 
    { 
     lock(collection){ 
      foreach(var item in localState) 
      { 
       collection.Add(item.Key, item.Value); 
      } 
     } 
    }); 

    collection.Dump(); 
} 

public class RabinKarpAlgo 
{ 
    private readonly string inputString; 
    private readonly string pattern; 
    private ulong siga = 0; 
    private ulong sigb = 0; 
    private readonly ulong Q = 100007; 
    private readonly ulong D = 256; 

    public RabinKarpAlgo(string inputString, string pattern) 
    { 
     this.inputString = inputString; 
     this.pattern = pattern; 
    } 

    public bool Match() 
    { 
     for (int i = 0; i < pattern.Length; i++) 
     { 
      siga = (siga * D + (ulong)inputString[i]) % Q; 
      sigb = (sigb * D + (ulong)pattern[i]) % Q; 
     } 

     if(siga == sigb) 
      return true; 

     ulong pow = 1; 
     for (int k = 1; k <= pattern.Length - 1; k++) 
      pow = (pow * D) % Q; 

     for (int j = 1; j <= inputString.Length - pattern.Length; j++) 
     { 
      siga = (siga + Q - pow * (ulong)inputString[j - 1] %Q) % Q; 
      siga = (siga * D + (ulong)inputString[j + pattern.Length - 1]) % Q; 

      if (siga == sigb) 
      { 
       if (inputString.Substring(j, pattern.Length) == pattern) 
       { 
        return true; 
       } 
      } 
     } 

     return false; 
    } 
} 
다음과 같은 GitHub의 저장소에서 관련 파일을 다운로드 할 수 있습니다

: Rabin-Karp Test

: Performance Testing

+2

추측으로을의 차이를 볼 수있는 2 가지 방법을 여기

루프와 함께 할 수있는 몇 가지 예입니다 1) 2 가지 경우에 대해 생성 된 IL을 비교 한 다음 2 가지 경우 모두를 생성하고 생성 된 어셈블리를 비교합니다. 디버그가 켜지면 JIT는 많은 최적화를 건너 뜁니다. 생성 된 출력을 보지 않고서는 추측 만 남았을 것입니다. –

+0

IL 코드는 최적화 된 코드에서 "nop"및 다른 문과 같은 몇 가지 차이점을 제외하고 두 경우 모두 거의 비슷합니다. "ngen"접근 방식을 시도하고 생성 된 어셈블리를 비교합니다. –

+0

@ JamesManning 당신이 ngen을 필요로하지 않는다고 생각합니다. 코드를 컴파일하고 시작한 다음 디버거를 부착하고 어셈블리 코드를 살펴보십시오. – svick

답변

3

특별한 경우가 3 병렬 foreach 안에있는 루프, 나는 대부분의 최적화가 동적 인 루프 변환과 물론 수학 부분을 통해 이루어질 것이라고 강력히 믿는다. 이에 블로그 항목이 Loop transformation

에릭 Lippert의는 C# 컴파일러 팀 : what does the optimize switch do