성능 테스트를 위한 정확한 시간 측정
메소드 호출과 같은 무언가가 코드를 수신한 시간을 가장 정확하게 확인하는 방법은 무엇입니까?
가장 쉽고 빠르게 추측할 수 있는 것은 다음과 같습니다.
DateTime start = DateTime.Now;
{
// Do some work
}
TimeSpan timeItTook = DateTime.Now - start;
하지만 이게 얼마나 정확할까요?더 좋은 방법이 있습니까?
더 나은 방법은 Stopwatch 클래스를 사용하는 것입니다.
using System.Diagnostics;
// ...
Stopwatch sw = new Stopwatch();
sw.Start();
// ...
sw.Stop();
Console.WriteLine("Elapsed={0}",sw.Elapsed);
다른 사람들이 말했듯이,Stopwatch여기서 사용하기 좋은 수업입니다.유용한 방법으로 포장할 수 있습니다.
public static TimeSpan Time(Action action)
{
Stopwatch stopwatch = Stopwatch.StartNew();
action();
stopwatch.Stop();
return stopwatch.Elapsed;
}
(사용법 참고)Stopwatch.StartNew()스톱워치를 만든 다음 전화를 거는 것보다 이것이 더 좋습니다.Start()단순성의 관점에서.)분명히 이것은 대리인을 호출하는 것의 타격을 야기하지만, 대부분의 경우 그것은 관련이 없을 것입니다.그런 다음 다음과 같이 기록합니다.
TimeSpan time = StopwatchUtil.Time(() =>
{
// Do some work
});
당신은 심지어 만들 수도 있습니다.ITimer이를 위한 인터페이스, 구현StopwatchTimer, CpuTimer등(가능한 경우)
다른 사람들이 말했듯이,Stopwatch이를 위한 올바른 도구가 되어야 합니다.그러나 몇 가지 개선 사항이 있을 수 있습니다. 구체적으로 이 스레드를 참조하십시오. C#의 작은 코드 샘플을 벤치마킹하면 이 구현이 개선될 수 있습니까?
여기서 토마스 마이어호퍼의 유용한 조언을 보았습니다.
기본적으로 코드는 다음과 같습니다.
//prevent the JIT Compiler from optimizing Fkt calls away
long seed = Environment.TickCount;
//use the second Core/Processor for the test
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2);
//prevent "Normal" Processes from interrupting Threads
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
//prevent "Normal" Threads from interrupting this thread
Thread.CurrentThread.Priority = ThreadPriority.Highest;
//warm up
method();
var stopwatch = new Stopwatch()
for (int i = 0; i < repetitions; i++)
{
stopwatch.Reset();
stopwatch.Start();
for (int j = 0; j < iterations; j++)
method();
stopwatch.Stop();
print stopwatch.Elapsed.TotalMilliseconds;
}
또 다른 접근 방식은 다음과 같습니다.Process.TotalProcessTime여기에 표시된 것처럼 CPU가 코드/프로세스를 실행하는 데 사용된 시간을 측정합니다. 다른 프로세스가 측정에 영향을 주지 않기 때문에 더 실제적인 시나리오를 반영할 수 있습니다.다음과 같은 작업을 수행합니다.
var start = Process.GetCurrentProcess().TotalProcessorTime;
method();
var stop = Process.GetCurrentProcess().TotalProcessorTime;
print (end - begin).TotalMilliseconds;
동일한 것에 대한 자세한 구현은 여기에서 확인할 수 있습니다.
사용하기 쉬운 방법으로 두 가지를 모두 수행하기 위해 도우미 클래스를 작성했습니다.
public class Clock
{
interface IStopwatch
{
bool IsRunning { get; }
TimeSpan Elapsed { get; }
void Start();
void Stop();
void Reset();
}
class TimeWatch : IStopwatch
{
Stopwatch stopwatch = new Stopwatch();
public TimeSpan Elapsed
{
get { return stopwatch.Elapsed; }
}
public bool IsRunning
{
get { return stopwatch.IsRunning; }
}
public TimeWatch()
{
if (!Stopwatch.IsHighResolution)
throw new NotSupportedException("Your hardware doesn't support high resolution counter");
//prevent the JIT Compiler from optimizing Fkt calls away
long seed = Environment.TickCount;
//use the second Core/Processor for the test
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2);
//prevent "Normal" Processes from interrupting Threads
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
//prevent "Normal" Threads from interrupting this thread
Thread.CurrentThread.Priority = ThreadPriority.Highest;
}
public void Start()
{
stopwatch.Start();
}
public void Stop()
{
stopwatch.Stop();
}
public void Reset()
{
stopwatch.Reset();
}
}
class CpuWatch : IStopwatch
{
TimeSpan startTime;
TimeSpan endTime;
bool isRunning;
public TimeSpan Elapsed
{
get
{
if (IsRunning)
throw new NotImplementedException("Getting elapsed span while watch is running is not implemented");
return endTime - startTime;
}
}
public bool IsRunning
{
get { return isRunning; }
}
public void Start()
{
startTime = Process.GetCurrentProcess().TotalProcessorTime;
isRunning = true;
}
public void Stop()
{
endTime = Process.GetCurrentProcess().TotalProcessorTime;
isRunning = false;
}
public void Reset()
{
startTime = TimeSpan.Zero;
endTime = TimeSpan.Zero;
}
}
public static void BenchmarkTime(Action action, int iterations = 10000)
{
Benchmark<TimeWatch>(action, iterations);
}
static void Benchmark<T>(Action action, int iterations) where T : IStopwatch, new()
{
//clean Garbage
GC.Collect();
//wait for the finalizer queue to empty
GC.WaitForPendingFinalizers();
//clean Garbage
GC.Collect();
//warm up
action();
var stopwatch = new T();
var timings = new double[5];
for (int i = 0; i < timings.Length; i++)
{
stopwatch.Reset();
stopwatch.Start();
for (int j = 0; j < iterations; j++)
action();
stopwatch.Stop();
timings[i] = stopwatch.Elapsed.TotalMilliseconds;
print timings[i];
}
print "normalized mean: " + timings.NormalizedMean().ToString();
}
public static void BenchmarkCpu(Action action, int iterations = 10000)
{
Benchmark<CpuWatch>(action, iterations);
}
}
그냥 전화하세요.
Clock.BenchmarkTime(() =>
{
//code
}, 10000000);
또는
Clock.BenchmarkCpu(() =>
{
//code
}, 10000000);
의 마지막 부분.Clock까다로운 부분입니다.최종 타이밍을 표시하려면 원하는 타이밍을 선택하는 것이 좋습니다.나는 확장 방법을 썼습니다.NormalizedMean이 값은 노이즈를 제거하는 읽기 시간의 평균을 제공합니다.즉, 실제 평균에서 각 타이밍의 편차를 계산한 다음 편차의 평균(절대 편차라고 함. 자주 들리는 표준 편차가 아님)에서 벗어난 값(더 느린 값만)을 버리고 마지막으로 나머지 값의 평균을 반환합니다.예를 들어, 이는 시간 값이 다음과 같은 경우를 의미합니다.{ 1, 2, 3, 2, 100 }(ms 또는 무엇이든), 그것은 폐기됩니다.100 의평 을균반다니의 합니다.{ 1, 2, 3, 2 }은 어느것이것입니다.2 타이밍이 아면시간이인 경우.{ 240, 220, 200, 220, 220, 270 }그것은 사라집니다.270 의평 을균반다니의 합니다.{ 240, 220, 200, 220, 220 }은 어느것이것입니다.220.
public static double NormalizedMean(this ICollection<double> values)
{
if (values.Count == 0)
return double.NaN;
var deviations = values.Deviations().ToArray();
var meanDeviation = deviations.Sum(t => Math.Abs(t.Item2)) / values.Count;
return deviations.Where(t => t.Item2 > 0 || Math.Abs(t.Item2) <= meanDeviation).Average(t => t.Item1);
}
public static IEnumerable<Tuple<double, double>> Deviations(this ICollection<double> values)
{
if (values.Count == 0)
yield break;
var avg = values.Average();
foreach (var d in values)
yield return Tuple.Create(d, avg - d);
}
Stopwatch 클래스 사용
시스템. 진단.Stopwatch는 이 작업을 위해 설계되었습니다.
스톱워치는 괜찮지만 작업을 10^6회 반복한 다음 10^6으로 나눕니다.당신은 훨씬 더 정확해질 것입니다.
사용 중인 항목:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(myUrl);
System.Diagnostics.Stopwatch timer = new Stopwatch();
timer.Start();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
statusCode = response.StatusCode.ToString();
response.Close();
timer.Stop();
언급URL : https://stackoverflow.com/questions/969290/exact-time-measurement-for-performance-testing
'programing' 카테고리의 다른 글
| 디스크에서 파일을 삭제하지 않고 어떻게 파일을 전송합니까? (0) | 2023.05.24 |
|---|---|
| Excel 셀에서 형식이 지정된 텍스트에 태그가 있는 HTML 텍스트 (0) | 2023.05.24 |
| @*ngIf에서 자식 보기 (0) | 2023.05.24 |
| 스토리보드 및 ARC가 없는 Xcode (0) | 2023.05.24 |
| NPM 글로벌 설치 "모듈을 찾을 수 없음" (0) | 2023.05.24 |