Fortran встроенные процедуры синхронизации, что лучше? cpu_time или system_clock
При синхронизации программы FORTRAN я обычно использую команду call cpu_time(t)
.
Затем я наткнулся на call system_clock([count,count_rate,count_max])
, который, похоже, делает то же самое. Однако в более сложной усадьбе.
Мое знание об этом происходит из: старой документации Intel.
Я не смог найти его на главной странице Intel. См. Мою разметку ниже.
- Какой из них более точный, или они похожи?
- Убирает ли один из них промахи в кеше (или другие), а другой нет или делает их?
- Или это единственная разница в том, что отмеченная вещь в моей разметке ниже?
Это мои вопросы, ниже я предоставил код для просмотра некоторых таймингов и обычаев. Они показали мне, что они очень похожи на результат и, похоже, похожи на реализацию.
Я должен отметить, что я, вероятно, всегда буду придерживаться cpu_time
, и мне не нужны более точные тайминги.
В приведенном ниже коде я попытался их сравнить. (я также пробовал более сложные вещи, но не буду поставлять, чтобы сохранить краткость)
Поэтому в основном мой результат таков:
-
cpu_time
- Прост в использовании, вам не нужны вызовы инициализации
- Прямое время в разнице
- Также должен быть специфичным для компилятора, но нет возможности увидеть точность. (норма - миллисекунды).
- Это сумма времени потока. То есть не рекомендуется для параллельных прогонов.
-
system_clock
- Требуется предварительная инициализация.
- Послепроцесс, в виде деления. (маленькая вещь, но тем не менее разница)
- Является компилятором конкретным. На моем ПК было найдено следующее:
- Intel 12.0.4 использует скорость счета 10000 из-за точности
INTEGER
.
- gcc-4.4.5 использует 1000, не знаю, как это отличает
- Является склонным к встрече с wraparounds, т.е. если
c1 > c2
, из-за count_max
- Время от одного стандартного времени. Таким образом, это даст фактическое время одного потока, а не суммы.
Код:
PROGRAM timer
IMPLICIT NONE
REAL :: t1,t2,rate
INTEGER :: c1,c2,cr,cm,i,j,n,s
INTEGER , PARAMETER :: x=20000,y=15000,runs=1000
REAL :: array(x,y),a_diff,diff
! First initialize the system_clock
CALL system_clock(count_rate=cr)
CALL system_clock(count_max=cm)
rate = REAL(cr)
WRITE(*,*) "system_clock rate ",rate
diff = 0.0
a_diff = 0.0
s = 0
DO n = 1 , runs
CALL CPU_TIME(t1)
CALL SYSTEM_CLOCK(c1)
FORALL(i = 1:x,j = 1:y)
array(i,j) = REAL(i)*REAL(j) + 2
END FORALL
CALL CPU_TIME(t2)
CALL SYSTEM_CLOCK(c2)
array(1,1) = array(1,2)
IF ( (c2 - c1)/rate < (t2-t1) ) s = s + 1
diff = (c2 - c1)/rate - (t2-t1) + diff
a_diff = ABS((c2 - c1)/rate - (t2-t1)) + a_diff
END DO
WRITE(*,*) "system_clock : ",(c2 - c1)/rate
WRITE(*,*) "cpu_time : ",(t2-t1)
WRITE(*,*) "sc < ct : ",s,"of",runs
WRITE(*,*) "mean diff : ",diff/runs
WRITE(*,*) "abs mean diff: ",a_diff/runs
END PROGRAM timer
Чтобы завершить здесь, я приведу результаты моего компилятора Intel 12.0.4 и gcc-4.4.5.
-
Intel 12.0.4
с -O0
system_clock rate 10000.00
system_clock : 2.389600
cpu_time : 2.384033
sc < ct : 1 of 1000
mean diff : 4.2409324E-03
abs mean diff: 4.2409897E-03
real 42m5.340s
user 41m48.869s
sys 0m12.233s
-
gcc-4.4.5
с -O0
system_clock rate 1000.0000
system_clock : 1.1849999
cpu_time : 1.1840820
sc < ct : 275 of 1000
mean diff : 2.05709646E-03
abs mean diff: 2.71424348E-03
real 19m45.351s
user 19m42.954s
sys 0m0.348s
Спасибо за чтение...
Ответы
Ответ 1
Эти два внутренних отчета сообщают о разных типах времени. system_clock сообщает "время на стене" или прошедшее время. cpu_time сообщает время, используемое процессором. На многозадачной машине они могут быть очень разными, например, если ваш процесс поделился процессором одинаково с тремя другими процессами и, следовательно, получил 25% от CPU и использовал 10 cpu секунд, потребуется около 40 секунд фактического истекшего или настенного время в часах.
Ответ 2
cpu_time() обычно имеет разрешение около 0,01 секунды на процессорах, совместимых с Intel. Это означает, что меньший интервал времени может считаться нулевым временем.
Большинство современных компиляторов для linux делают разрешение system_clock() зависящим от типов данных аргументов, поэтому integer (int64) даст более 1 микросекундного разрешения, а также разрешает подсчет за значительный промежуток времени.
gfortran для Windows был изменен в последнее время (в течение 2015 года), чтобы сделать system_clock() эквивалентным вызовам query_performance. ifort Windows, тем не менее, по-прежнему показывает примерно 0,01 разрешения для system_clock, даже после того, как omp_get_wtime был изменен для использования query_performance.
Я бы отменил предыдущие комментарии об измерении разрешения cpu_time или system_clock в тактовых импульсах, особенно если это можно считать относящимся к тикам процессора или данных, например, инструкция rdtsc может сообщить.
Ответ 3
Я нахожу itime
(см. gfortran manual), чтобы быть хорошей альтернативой system_clock
для выбора времени для трансляционных программ. Он очень прост в использовании:
integer, dimension(3) :: time
call itime(time)
print *, 'Hour: ', time(1)
print *, 'Minute:', time(2)
print *, 'Second:', time(3)
Ответ 4
Я нахожу secnds() как самый простой способ получить время на стене. Его использование почти идентично cpu_time().
real(8)::t1,delta
t1=secnds(0.0)
!Do stuff
delta=seconds(t1)