Разница в наносекундной точности между JVM и переполнением стека

При измерении времени на JVM с System.nanoTime() Вы получаете более высокую точность, чем с std::chrono::high_resolution_clock, Как это может быть и есть ли кроссплатформенный способ получить ту же точность в C ++, что и в JVM.

Примеры:

Котлин (JVM):

fun main(args: Array<String>) {
for (i in 0..10)
test() // warmup

println("Average resolution: ${test()}ns")
}

fun test(): Double {
val timeList = mutableListOf<Long>()

for (i in 0 until 10_000_000) {
val time = System.nanoTime()
if (timeList.isEmpty() || time != timeList.last())
timeList.add(time)
}

return timeList
.mapIndexed { i, l -> if (i > 0) l - timeList[i - 1] else null }
.filterNotNull()
.average()
}

Выход: Average resolution: 433.37ns

C ++:

#include <iostream>
#include <chrono>
#include <numeric>
#include <vector>

int main() {
using namespace std;
using namespace chrono;

vector<long long int> time_list;

for(int i = 0; i < 10'000'000; ++i) {
auto time = duration_cast<nanoseconds>(high_resolution_clock::now().time_since_epoch()).count();
if(time_list.empty() || time != time_list[time_list.size() - 1])
time_list.push_back(time);
}

adjacent_difference(time_list.begin(), time_list.end(), time_list.begin());
auto result = accumulate(time_list.begin() + 1, time_list.end(), 0.0) / (time_list.size() - 1);

printf("Average resolution: %.2fns", result);

return 0;
}

Выход: Average resolution: 15625657.89ns Изменить: (MinGW g ++)
Редактировать: Вывод: Average resolution: 444.88ns (MSVC)

Это было сделано в Windows, но в Linux я получаю похожие результаты.

Редактировать:

Хорошо, исходный C ++ был рассчитан с MinGW и g ++ после перехода на MSVC. Я получил те же результаты, что и JVM (444,88 нс).

0

Решение

Ваш пример Java (Kotlin) не измеряет гранулярность наносекунды; в основном он измеряет, сколько времени занимает сборка списка объектов Long. (или разверните кучу, или выделите объекты и заголовки объектов — если вы запускаете тест только один раз, он может попытаться собрать мусор, но он не будет успешным, пока работает цикл)

Java довольно быстро распределяет память, обычно быстрее, чем стандартные библиотеки для C / C ++.

Для C ++ возможно, по крайней мере, что значительный процент воспринимаемой точности наносекундных часов поступает от вызова push_back 10 миллионов раз на вектор, который включает в себя ряд перераспределений.

Лучшим тестом будет (Котлин, но то же самое можно сделать и для C ++) — нет необходимости запоминать временные метки в списке, чтобы вычислить среднюю разницу между ними.

fun main(args: Array<String>) {
for (i in 0 until 10) {
runTest();
}
}

fun runTest() {
var lastTime = System.nanoTime()
var count = 0;
var total = 0L;
for (i in 0 until 50_000_000) {
val time = System.nanoTime()
if (time > lastTime) {
count++;
total += time - lastTime;
lastTime = time;
}
}

val result = total / count;

println("Average resolution: ${result}ns")
}

Примечание: это дает мне довольно последовательную точность 32-35 нс в Java, намного лучше, чем 45-200 нс, которые дал мне ваш исходный код.

Что касается вашего кода C ++, ваш исходный код, работающий на моем MacBookPro, дает мне 68-78 нс (при запуске в цикле, который запускает его 10 раз)

Я также удалил ненужный вектор из вашего кода, а затем он дает результат 50-51 нс, что дает достойное указание на то, что реальная гранулярность составляет 50 нс.

JVM работает несколько лучше, чем 32-35 нс (на 38% лучше, чем 50 нс), но разница не настолько велика, как вы упомянули.

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

#include <iostream>
#include <chrono>
#include <numeric>
#include <vector>int main1() {
using namespace std;
using namespace chrono;

vector<long long int> time_list;

long long total = 0;
int count = 0;
auto lastTime = duration_cast<nanoseconds>(high_resolution_clock::now().time_since_epoch()).count();
for(int i = 0; i < 50000000; ++i) {
auto time = duration_cast<nanoseconds>(high_resolution_clock::now().time_since_epoch()).count();
if (time > lastTime) {
count++;
total += time - lastTime;
lastTime = time;
}
}

long long result = total / count;

printf("Average resolution: %.2lld ns\n", result);

return 0;
}

int main() {
for (int i = 0; i < 10; i++) {
main1();
}
}
1

Другие решения

Разрешение в c ++ зависит от платформы, но вы можете добиться большей точности, используя вызовы, зависящие от платформы (например, clock_gettime от time.h в Linux)

0

По вопросам рекламы [email protected]