Медленные начальные результаты синхронизации с использованием gettimeofday - хуже на сервере RHEL6.

Я использую gettimeofday() для измерения времени простого примера умножения матрицы, но я получаю результаты, которые изначально почти в два раза длиннее. На компьютере с сервером RHEL6 я получаю «плохие» результаты синхронизации в течение почти 1 секунды (~ 65 отдельных таймингов в этом примере). Все другие наши машины представляют собой рабочие станции RHEL5, и этот код работает на них намного лучше; Сначала я получаю только пару «плохих» результатов (в течение первых ~ 20 миллисекунд).

Судя по сообщениям на этом сайте, я думаю, что это, вероятно, как-то связано с планировщиком процессов ОС. Если я раскомментирую первый оператор «for» ниже (тем самым вставив начальный цикл занятости путем многократной инициализации матриц a, b и c), я не получу «плохих» результатов как на рабочей станции RHEL5, так и на сервере RHEL6. В качестве альтернативы, если я раскомментирую оператор сна, я получу ВСЕ «плохие» результаты синхронизации как для RHEL5, так и для RHEL6.

По какой-то причине мой процесс изначально запускается только с половиной доступа к ЦП, затем он получает «полный» доступ к ЦП, пока процесс остается занятым. Если он «спит», а затем возобновляет синхронизацию, он снова временно получает только половину полного доступа к ЦП.

На машине больше ничего не происходит (X не запущен). Я пробовал "chrt" для управления приоритетом процесса, но это ничего не изменило. Я убедился, что это происходит как с GCC 4.4.6, так и с ICC 12.1.0. Я тоже пробовал "красиво".

Вот код:

#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#define N 225
#define DELAY_LOOPS 8000
main() {
  struct timeval _t0, _t1, _t2;
  double a[N][N], b[N][N], c[N][N];
  double millisec, cum_ms;
  int i, j, k, l, m=0;
  gettimeofday( &_t0, NULL );
  // for( l=0; l<DELAY_LOOPS; l++ )
    for( i=0; i<N; i++ )
      for( j=0; j<N; j++ ) {
        a[i][j]=0;
        b[i][j]=i;
        c[i][j]=j;
      }
  for( l=0; l<75; l++ ) {
    gettimeofday( &_t1, NULL );
    for( i=0; i<N; i++ )
      for( j=0; j<N; j++ )
        for( k=0; k<N; k++ )
          a[i][j]+=b[i][k]*c[k][j];
    gettimeofday( &_t2, NULL );
    millisec  = 1000*(_t2.tv_sec-_t1.tv_sec);
    millisec += 1e-3*(_t2.tv_usec-_t1.tv_usec);
    cum_ms  = 1000*(_t2.tv_sec-_t0.tv_sec);
    cum_ms += 1e-3*(_t2.tv_usec-_t0.tv_usec);
    printf( "%d: duration %fms, cumulative %fms\n",
            m++, millisec, cum_ms );
    // sleep( 2 );
  }
  printf( "a[%d][%d]=%f\n", N/2, N/2, a[N/2][N/2] );
}

и вот результаты:

% icc -O2 -o test main.c; ./test
0: duration 13.049000ms, cumulative 13.677000ms
1: duration 13.026000ms, cumulative 26.753000ms
2: duration 12.911000ms, cumulative 39.668000ms
3: duration 12.913000ms, cumulative 52.584000ms
4: duration 12.914000ms, cumulative 65.501000ms
5: duration 12.911000ms, cumulative 78.415000ms
6: duration 12.912000ms, cumulative 91.331000ms
/* snip */
64: duration 12.912000ms, cumulative 840.633000ms
65: duration 10.455000ms, cumulative 851.092000ms
66: duration 5.910000ms, cumulative 857.004000ms
67: duration 5.908000ms, cumulative 862.914000ms
68: duration 5.907000ms, cumulative 868.823000ms
69: duration 5.908000ms, cumulative 874.732000ms
70: duration 5.912000ms, cumulative 880.646000ms
71: duration 5.907000ms, cumulative 886.554000ms
72: duration 5.907000ms, cumulative 892.462000ms
73: duration 5.908000ms, cumulative 898.372000ms
74: duration 5.908000ms, cumulative 904.281000ms
a[112][112]=211680000.000000

Я сталкиваюсь с проблемой независимо от уровня оптимизации (-O0, -O1, -O2 и т. д.).

Кто-нибудь знает что-нибудь о том, как выполняется планирование на сервере RHEL6? Так ли сильно она отличается от рабочей станции RHEL5? Я предполагаю, что разница, которую я вижу, больше связана с тем, что одна коробка является серверной версией RHEL, а другая — версией для рабочих станций (а не различием между выпуском 5 и 6). Есть ли простой способ уменьшить этот эффект на сервере RHEL6 и сделать его более похожим на рабочие станции RHEL5?

Есть идеи? Спасибо.


person chrisG    schedule 30.12.2011    source источник
comment
может быть из-за чрезмерных переключений контекста, которые может выполнять сервер. таким образом, что приводит к ситуации, когда расчет выполняется, но gettimeofday() называется послесловием. Просто мои 0,02 доллара   -  person Lelouch Lamperouge    schedule 31.12.2011
comment
Надеюсь, вы используете выделенный сервер.   -  person Shiplu Mokaddim    schedule 31.12.2011
comment
Это одна и та же JVM на обоих серверах?   -  person fge    schedule 31.12.2011


Ответы (2)


Может ли процессор перейти в состояние пониженного энергопотребления? Что-то вроде powertop может сказать вам это. (во вкладке Частотная статистика)

person Greg    schedule 30.12.2011
comment
Очень интересное предложение. Я не слышал о powertop. Под P-состояниями (частотами) вверху ничего нет. Я должен посмотреть на это еще немного, чтобы понять, на что я смотрю. Спасибо за предложение. Я все еще хотел бы знать, как я могу заставить свой сервер RHEL6 работать так же, как все рабочие станции RHEL5 в этом отношении. Спасибо. - person chrisG; 31.12.2011
comment
Я думаю, что это лучший лид на данный момент. Powertop 2.0 ссылка выглядит очень впечатляюще. К сожалению, для него требуется относительно новое ядро ​​(›2.6.36), поэтому в данный момент для меня это не вариант ни с RHEL5, ни с RHEL6. Однако я попытаюсь использовать его на своем ноутбуке (Ubuntu 11.10), чтобы посмотреть, что я могу узнать. - person chrisG; 04.01.2012
comment
Похоже, это то, что происходит. Мне удалось установить Powertop 1.97. К сожалению, это дало мне очень вводящую в заблуждение информацию на вкладке «Tunables». Он сказал мне, что работает регулятор cpufreq по требованию. На самом деле cpufreq вообще не работает. НО cpuidle на самом деле активен (в частности, intel_idle работает вместо acpi_idle, но я переключаюсь между ними). Отличная информация о cpuidle здесь: ссылка. Итог: все мои двенадцать ядер тратят все свое время в состоянии наименьшего энергопотребления (высокая задержка), когда я сплю между вызовами синхронизации. - person chrisG; 04.01.2012
comment
НАЙДЕНО РЕШЕНИЕ: Полностью отключите ACPI! Это решение с большим молотком, но это единственное, что я нашел, что работает. Целью компьютера является полномасштабный запуск моделей для сравнения решений OpenCL, CUDA и OpenMP. Экономия энергии не является приоритетом. Я отказываюсь от попыток настроить ACPI. Из того, что я нашел с помощью Google, похоже, что в ACPI есть ошибка. При включенном ACPI в RHEL6 синхронизация очень затруднена, потому что сначала требуется цикл занятости, чтобы разогнать ЦП. Если приложение использует OpenMP, также должен использоваться цикл занятости. Не влияет на сервер RHEL5 (минимально на рабочую станцию ​​RHEL5). - person chrisG; 04.01.2012
comment
Только что увидел ваши комментарии. Рад, что ты понял это. - person Greg; 20.02.2012

Не используйте gettimeofday(2) для измерения производительности. Это слишком медленно и просто не предназначено для этой работы.

Вместо этого используйте clock_gettime(2). Это позволяет вам выбрать один из нескольких системных таймеров. CLOCK_REALTIME — самый простой выбор, но CLOCK_PROCESS_CPUTIME_ID может быть лучше, если он у вас есть.

person alex tingle    schedule 30.12.2011