Точность timeIntervalSinceDate

Я работаю над игрой с движком, который обновляется 20 раз в секунду. Теперь я должен указать, где я хочу начать получать некоторые показатели производительности и настроить обновления рендеринга и логики. Для этого я начал добавлять некоторый код синхронизации в свой игровой цикл, реализованный следующим образом...

NSDate* startTime = [NSDate date];
// Game update logic here....
// Also timing of smaller internal events
NSDate* endTime = [NSDate date];
[endTime timeIntervalSinceDate:startTime];

Однако я заметил, что когда я синхронизировал блоки во внешней логике синхронизации, время, которое они потребовали для выполнения, не соответствовало общему затраченному времени.

Поэтому я написал небольшой модульный тест, чтобы продемонстрировать проблему, в которой я измеряю общее время, необходимое для завершения теста, а затем 10 меньших событий, вот оно...

- (void)testThatSumOfTimingsMatchesOverallTiming {

NSDate* startOfOverallTime = [NSDate date];

// Variable to hold summation of smaller timing events in the upcoming loop...
float sumOfIndividualTimes = 0.0;
NSTimeInterval times[10] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
for (int i = 0; i < 10; i++) {
    NSDate* startOfIndividualTime = [NSDate date];
    // Kill some time...
    sleep(1);
    NSDate* endOfIndividualTime = [NSDate date];
    times[i] = [endOfIndividualTime timeIntervalSinceDate:startOfIndividualTime];
    sumOfIndividualTimes += times[i];
}

NSDate* endOfOverallTime = [NSDate date];
NSTimeInterval overallTimeTaken = [endOfOverallTime timeIntervalSinceDate:startOfOverallTime];

NSLog(@"Sum of individual times: %fms", sumOfIndividualTimes);
NSLog(@"Overall time: %fms", overallTimeTaken);

STAssertFalse(TRUE, @"");
}

А вот и выход...

Sum of individual times: 10.001377ms
Overall time: 10.016834ms

Что довольно ясно иллюстрирует мою проблему. Общее время составило 0,000012 мс, но меньшие события заняли всего 0,000001 мс. Так что же случилось с остальными 0,000011 мс?

Есть ли что-то особенно неправильное в моем коде? Или есть альтернативный механизм синхронизации, который я должен использовать?


person mmccomb    schedule 25.12.2010    source источник
comment
Поэтому, как любезно рекомендовал Эд Марти в первом ответе, я переключил реализацию на использование CACurrentMediaTime() вместо объектов NSDate. К сожалению, по-прежнему существует несоответствие между суммой отдельных времен и общим временем, расхождение теперь составляет около 0,01 мс, что все еще очень похоже на реализацию NSDate.   -  person mmccomb    schedule 26.12.2010


Ответы (1)


Что ж, для запуска [NSDate date] и [endTime timeIntervalSinceDate:startDate] требуется некоторое время, что, вероятно, объясняет разницу.

Однако я бы использовал CACurrentMediaTime(), который возвращает CFTimeInterval (что является просто двойным), или mach_absolute_time(), который возвращает беззнаковое длинное целое число. Оба они избегают создания объектов и, вероятно, занимают меньше времени.

Конечно, вы все равно будете вычитать два числа в каждом кадре, что требует времени. Мое предложение обойти это было бы просто использовать lastFrameEnd:

CFTimeInterval lastFrameEnd = CACurrentMediaTime();
while (true) {
  // Game update logic here....
  // Also timing of smaller internal events
  CFTimeInterval frameEnd = CACurrentMediaTime();
  CFTimeInterval duration = frameEnd - lastFrameEnd;  //Use this
  lastFrameEnd = frameEnd;
}

При этом учитывается время от конца одного кадра до конца следующего, включая время, затрачиваемое на вычитание и вызовы методов.

person Ed Marty    schedule 25.12.2010
comment
Я учёл тот факт, что метод NSDate timeIntervalSinceDate сам по себе потребует некоторого времени, поэтому я также рассчитал время. Я обнаружил, что это также заняло относительно небольшое количество времени - может быть, всего 10-15% расхождения. Так что похоже, что время еще что-то пережевывает... Спасибо за предложение CACurrentMediaTime(), однако я переключу код, чтобы использовать его, и опубликую обратно с моими результатами. - person mmccomb; 25.12.2010
comment
Добавил обновление в исходный пост. После переключения на реализацию времени CACurrentMedia я все еще вижу то же поведение. К моему общему времени добавляется неучтенная 0,01 мс, которая на самом деле не коррелирует с кодом, который выполняется за пределами отдельных таймингов... - person mmccomb; 26.12.2010
comment
Вы также учитывали время, затраченное на создание объекта [NSDate date]? Вы внесли изменение, которое я предложил, чтобы не использовать время начала и окончания цикла? Поскольку на приращение и проверку счетчика циклов также тратится некоторое время, поэтому я предложил просто использовать начало одного кадра для начала следующего. - person Ed Marty; 26.12.2010
comment
Я учел создание NSDate в своих таймингах. Я слышал, что вы говорите о счетчике циклов, но ведь это не может быть такой дорогой операцией? Это на порядок больше, чем индивидуальное время, которое может показаться довольно высоким? Спасибо! - person mmccomb; 26.12.2010
comment
Вы будете удивлены, сколько времени можно потратить на счетчик циклов. Там можно провести довольно много времени. Вы можете превратить цикл for в цикл while(true) и выполнить счетчик цикла вручную, внутри тайминга, чтобы увидеть, сколько он на самом деле занимает. - person Ed Marty; 27.12.2010