Сравнение производительности различных конструкций pthread - PullRequest
0 голосов
/ 01 апреля 2019

Мне нужно сравнить производительность различных конструкций pthread, таких как мьютекс, семафоры, блокировки чтения-записи, а также соответствующих последовательных программ, при разработке некоторых экспериментов. Основная проблема заключается в решении , как измерить время выполнения кода для анализа?

Я читал о некоторых функциях C, таких как clock (), gettimeofday () и т. Д. Из того, что я мог понять, мы можем использовать clock (), чтобы получить фактическое количество циклов ЦП, используемых программой (вычитая значение, возвращаемое функция в начале и конце кода, время которого мы хотим измерить), gettimeofday () возвращает время настенных часов для выполнения программы.

Но проблема в том, что общее количество циклов ЦП не представляется мне хорошим критерием, поскольку оно суммирует время ЦП, затрачиваемое на все параллельные потоки (поэтому, по моему мнению, clock () не годится). Также время настенных часов не очень хорошее, так как в фоновом режиме могут выполняться другие процессы, поэтому время, наконец, зависит от того, как запланированы потоки (так что gettimeofday () также не подходит мне).

Некоторые другие функции, о которых я знаю, также выполняют те же функции, что и выше. Итак, я хотел знать, есть ли какая-то функция, которую я могу использовать для своего анализа, или я ошибаюсь где-то в своем заключении выше?

Ответы [ 2 ]

0 голосов
/ 01 апреля 2019

С linux clock_gettime :

   CLOCK_PROCESS_CPUTIME_ID (since Linux 2.6.12)
          Per-process CPU-time clock (measures CPU time consumed by all
          threads in the process).

   CLOCK_THREAD_CPUTIME_ID (since Linux 2.6.12)
          Thread-specific CPU-time clock.

Я считаю, что clock() где-то был реализован как clock_gettime(CLOCK_PROCESS_CPUTIME_ID, но я вижу, что он реализован с использованием times() в glibc.

Так что, если вы хотите измерить удельное время процессора для конкретного потока, вы можете использовать clock_gettimer(CLOCK_THREAD_CPUTIME_ID, ... в системах GNU / Linux.

Никогда не используйте gettimeofday или clock_gettime(CLOCK_REALTIME для измерения выполнения программы.Даже не думай об этом.gettimeofday - это «настенные часы» - вы можете отобразить их на стене в своей комнате.Если вы хотите измерить течение времени, забудьте о gettimeofday.

. Если вы хотите, вы также можете оставаться полностью совместимым с поссиксилией, используя pthread_getcpuclockid в вашей ветке и используявозвращается clock_id значение с clock_gettime.

0 голосов
/ 01 апреля 2019

Я не уверен, что суммирование массива - хороший тест, вам не нужен мьютекс и т. Д. Для суммирования массива в многопоточности, каждый поток просто должен суммировать выделенную часть массива, и есть много доступ к памяти для нескольких вычислений процессора. Пример (значения SZ и NTHREADS указаны при компиляции), измеренное время является реальным (монотонным):

#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

static int Arr[SZ];

void * thSum(void * a)
{
  int s = 0, i;
  int sup = *((int *) a) + SZ/NTHREADS;

  for (i = *((int *) a); i != sup; ++i)
    s += Arr[i];

  *((int *) a) = s;
}

int main()
{
  int i;

  for (i = 0; i != SZ; ++i)
    Arr[i] = rand();

  struct timespec t0, t1;

  clock_gettime(CLOCK_MONOTONIC, &t0);

  int s = 0;

  for (i = 0; i != SZ; ++i)
    s += Arr[i];

  clock_gettime(CLOCK_MONOTONIC, &t1);
  printf("mono thread : %d %lf\n", s,
         (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec)/1000000000.0);

  clock_gettime(CLOCK_MONOTONIC, &t0);

  int n[NTHREADS];
  pthread_t ths[NTHREADS];

  for (i = 0; i != NTHREADS; ++i) {
    n[i] = SZ / NTHREADS * i;
    if (pthread_create(&ths[i], NULL, thSum, &n[i])) {
      printf("cannot create thread %d\n", i);
      return -1;
    }
  }

  int s2 = 0;

  for (i = 0; i != NTHREADS; ++i) {
    pthread_join(ths[i], NULL);
    s2 += n[i];
  }

  clock_gettime(CLOCK_MONOTONIC, &t1);
  printf("%d threads : %d %lf\n", NTHREADS, s2,
         (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec)/1000000000.0);
}

Компиляции и исполнения:

(массив из 100.000.000 элементов)

/tmp % gcc -DSZ=100000000 -DNTHREADS=2 -O3 s.c -lpthread -lrt
/tmp % ./a.out
mono thread : 563608529 0.035217
2 threads : 563608529 0.020407
/tmp % ./a.out
mono thread : 563608529 0.034991
2 threads : 563608529 0.022659
/tmp % gcc -DSZ=100000000 -DNTHREADS=4 -O3 s.c -lpthread -lrt
/tmp % ./a.out
mono thread : 563608529 0.035212
4 threads : 563608529 0.014234
/tmp % ./a.out
mono thread : 563608529 0.035184
4 threads : 563608529 0.014163
/tmp % gcc -DSZ=100000000 -DNTHREADS=8 -O3 s.c -lpthread -lrt
/tmp % ./a.out
mono thread : 563608529 0.035229
8 threads : 563608529 0.014971
/tmp % ./a.out
mono thread : 563608529 0.035142
8 threads : 563608529 0.016248

(массив из 1000 000 000 элементов)

/tmp % gcc -DSZ=1000000000 -DNTHREADS=2 -O3 s.c -lpthread -lrt
/tmp % ./a.out
mono thread : -1471389927 0.343761
2 threads : -1471389927 0.197303
/tmp % ./a.out
mono thread : -1471389927 0.346682
2 threads : -1471389927 0.197669
/tmp % gcc -DSZ=1000000000 -DNTHREADS=4 -O3 s.c -lpthread -lrt
/tmp % ./a.out
mono thread : -1471389927 0.346859
4 threads : -1471389927 0.130639
/tmp % ./a.out
mono thread : -1471389927 0.346506
4 threads : -1471389927 0.130751
/tmp % gcc -DSZ=1000000000 -DNTHREADS=8 -O3 s.c -lpthread -lrt
/tmp % ./a.out
mono thread : -1471389927 0.346954
8 threads : -1471389927 0.123572
/tmp % ./a.out
mono thread : -1471389927 0.349652
8 threads : -1471389927 0.127059

Как вы можете видеть, даже если время выполнения не делится на количество потоков, узким местом, вероятно, является доступ к памяти

...