Неправильное указатель производительности - PullRequest
1 голос
/ 17 июня 2010

Не смещенные указатели (в ЛУЧШЕМ возможном случае) должны замедлять производительность и в худшем случае приводить к сбою вашей программы (при условии, что компилятор был достаточно хорош для компиляции вашей недопустимой программы c).

Хорошоследующий код не имеет различий в производительности между выровненными и выровненными версиями.Почему это так?

/* brutality.c */

#ifdef BRUTALITY
    xs = (unsigned long *) ((unsigned char *) xs + 1);
#endif

...

/* main.c */

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

#define size_t_max ((size_t)-1)
#define max_count(var) (size_t_max / (sizeof var))

int main(int argc, char *argv[]) {

    unsigned long sum, *xs, *itr, *xs_end;
    size_t element_count = max_count(*xs) >> 4;

    xs = malloc(element_count * (sizeof *xs));
    if(!xs) exit(1);

    xs_end = xs + element_count - 1; sum = 0;

    for(itr = xs; itr < xs_end; itr++)
        *itr = 0;

#include "brutality.c"

    itr = xs;
    while(itr < xs_end)
        sum += *itr++;

    printf("%lu\n", sum);

    /* we could free the malloc-ed memory here */
    /* but we are almost done                  */
    exit(0);
}

Скомпилировано и протестировано на двух отдельных машинах с использованием

gcc -pedantic -Wall -O0 -std=c99 main.c
for i in {0..9}; do time ./a.out; done

Ответы [ 7 ]

3 голосов
/ 17 июня 2010

Я проверял это некоторое время назад на машинах Win32 и не заметил большого количества штрафов на 32-битных машинах.На 64-битной, однако, это было значительно медленнее.Например, я запустил следующий бит кода.На 32-битном компьютере напечатанное время почти не изменилось.Но на 64-битной машине время несовпадения доступа было почти вдвое больше.Время следует за кодом.

#define UINT unsigned __int64
#define ENDPART QuadPart
#else
#define UINT unsigned int
#define ENDPART LowPart
#endif


int main(int argc, char *argv[])
{
   LARGE_INTEGER startCount, endCount, freq;
   int i;
   int offset;
   int iters = atoi(argv[1]);
   char *p = (char*)malloc(16);
   double *d;

   for ( offset = 0; offset < 9; offset++ )
      {
      d = (double*)( p + offset );
      printf( "Address alignment = %u\n", (unsigned int)d % 8 );
      *d = 0;
      QueryPerformanceFrequency(&freq);
      QueryPerformanceCounter(&startCount);
      for(i = 0; i < iters; ++i)
         *d = *d + 1.234;
      QueryPerformanceCounter(&endCount);

      printf( "Time:  %lf\n",
             (double)(endCount.ENDPART-startCount.ENDPART)/freq.ENDPART );
      }
}

Вот результаты на 64-битной машине.Я скомпилировал код как 32-битное приложение.

[P:\t]pointeralignment.exe 100000000
Address alignment = 0
Time:  0.484156
Address alignment = 1
Time:  0.861444
Address alignment = 2
Time:  0.859656
Address alignment = 3
Time:  0.861639
Address alignment = 4
Time:  0.860234
Address alignment = 5
Time:  0.861539
Address alignment = 6
Time:  0.860555
Address alignment = 7
Time:  0.859800
Address alignment = 0
Time:  0.484898
2 голосов
/ 17 июня 2010

Архитектура x86 всегда была способна обрабатывать неправильные обращения, поэтому вы никогда не получите сбой. Другие процессоры могут быть не такими удачливыми.

Вы, вероятно, не видите никакой разницы во времени, потому что цикл связан с памятью; он может работать только так быстро, как данные могут быть получены из оперативной памяти. Вы можете подумать, что смещение приведет к тому, что доступ к ОЗУ будет выполнен дважды, но первый доступ помещает его в кэш, а второй доступ может перекрываться при получении следующего значения из ОЗУ.

1 голос
/ 17 июня 2010

Вы предполагаете архитектуры x86 или x64.Например, на MIPS ваш код может привести к повышению сигнала SIGBUS (ошибка шины).На других архитектурах доступ без выравнивания обычно медленнее, чем доступ с выравниванием, хотя он очень сильно зависит от архитектуры.

0 голосов
/ 17 июня 2010

Может быть, для размещения такого огромного буфера, система выполняет разбиение памяти на диск и с диска.Это может затопить небольшие различия.Попробуйте намного меньший буфер и большое количество циклов в программе.

Я сделал моды, которые я предложил здесь и в комментариях, и протестировал на своей системе (усталый, 4-летний, 32-битныйноутбук).Код показан ниже.Я получаю ощутимую разницу, но только около 3%.Я утверждаю, что мои изменения увенчались успехом, потому что ваш вопрос говорит о том, что вы не понимаете разницы вообще правильно?

Извините, я использую Windows и использовал специфичный для Windows API GetTickCount (), с которым я знаком, потому что я часто делаю тесты синхронизации,и наслаждайтесь простотой этого неправильно названного API (он фактически возвращает миллисекунды с момента запуска системы).

/* main.cpp */

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#define BRUTALITY

int main(int argc, char *argv[]) {
    unsigned long i, begin, end;
    unsigned long sum, *xs, *itr, *xs_begin, *xs_end;
    size_t element_count = 100000;

    xs = (unsigned long *)malloc(element_count * (sizeof *xs));
    if(!xs) exit(1);
    xs_end = xs + element_count - 1;
    #ifdef BRUTALITY
    xs_begin = (unsigned long *) ((unsigned char *) xs + 1);
    #else
    xs_begin = xs;
    #endif

    begin = GetTickCount();
    for( i=0; i<50000; i++ )
    {
        for(itr = xs_begin; itr < xs_end; itr++)
            *itr = 0;

        sum = 0;
        itr = xs_begin;
        while(itr < xs_end)
            sum += *itr++;
    }
    end = GetTickCount();

    printf("sum=%lu elapsed time=%lumS\n", sum, end-begin );

    free(xs);
    exit(0);
}
0 голосов
/ 17 июня 2010

Вы никогда не определяли BRUTALITY в своем опубликованном коде.Вы уверены, что тестируете в «брутальном» режиме?

0 голосов
/ 17 июня 2010

Вероятно, потому, что malloc из такого количества байтов возвращает NULL. По крайней мере, это то, что он делает для меня.

0 голосов
/ 17 июня 2010

x86 или x64?

Неверно выровненные указатели были убийцей в x86, где 64-битные архитектуры были не так подвержены сбоям или даже низкой производительности вообще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...