Существует ли стандартный макрос для обнаружения архитектур, требующих согласованного доступа к памяти? - PullRequest
7 голосов
/ 07 декабря 2011

Предполагая что-то вроде:

void mask_bytes(unsigned char* dest, unsigned char* src, unsigned char* mask, unsigned int len)
{
  unsigned int i;
  for(i=0; i<len; i++)
  {
     dest[i] = src[i] & mask[i];
  }
}

Я могу работать быстрее на машине без выравнивания (например, x86), написав что-то вроде:

void mask_bytes(unsigned char* dest, unsigned char* src, unsigned char* mask, unsigned int len)
{
  unsigned int i;
  unsigned int wordlen = len >> 2;
  for(i=0; i<wordlen; i++)
  {
    ((uint32_t*)dest)[i] = ((uint32_t*)src)[i] & ((uint32_t*)mask)[i]; // this raises SIGBUS on SPARC and other archs that require aligned access.
  }
  for(i=wordlen<<2; i<len; i++){
    dest[i] = src[i] & mask[i];
  }
}

Однако его нужно собратьна нескольких архитектурах, поэтому я хотел бы сделать что-то вроде:

void mask_bytes(unsigned char* dest, unsigned char* src, unsigned char* mask, unsigned int len)
{
  unsigned int i;
  unsigned int wordlen = len >> 2;

#if defined(__ALIGNED2__) || defined(__ALIGNED4__) || defined(__ALIGNED8__)
  // go slow
  for(i=0; i<len; i++)
  {
     dest[i] = src[i] & mask[i];
  }
#else
  // go fast
  for(i=0; i<wordlen; i++)
  {
    // the following line will raise SIGBUS on SPARC and other archs that require aligned access.
    ((uint32_t*)dest)[i] = ((uint32_t*)src)[i] & ((uint32_t*)mask)[i]; 
  }
  for(i=wordlen<<2; i<len; i++){
    dest[i] = src[i] & mask[i];
  }
#endif
}

Но я не могу найти никакой хорошей информации о макросах, определенных компилятором (например, мой гипотетический __ALIGNED4__ выше), которые определяют выравнивание или любые умные способы использованияпрепроцессор для определения целевой архитектуры выравнивания.Я мог бы просто протестировать defined (__SVR4) && defined (__sun), но я бы предпочел что-то, что будет просто работать TM на других архитектурах, требующих согласованного доступа к памяти.

Ответы [ 3 ]

5 голосов
/ 07 декабря 2011

Хотя x86 молча исправляет невыровненный доступ, это вряд ли является оптимальным для производительности.Обычно лучше принять определенное выравнивание и выполнить исправления самостоятельно:

unsigned int const alignment = 8;   /* or 16, or sizeof(long) */

void memcpy(char *dst, char const *src, unsigned int size) {
    if((((intptr_t)dst) % alignment) != (((intptr_t)src) % alignment)) {
        /* no common alignment, copy as bytes or shift around */
    } else {
        if(((intptr_t)dst) % alignment) {
            /* copy bytes at the beginning */
        }
        /* copy words in the middle */
        if(((intptr_t)dst + size) % alignment) {
            /* copy bytes at the end */
        }
    }
}

Кроме того, ознакомьтесь с инструкциями SIMD.

2 голосов
/ 07 декабря 2011

Стандартным подходом будет иметь скрипт configure, который запускает программу для проверки на проблемы с выравниванием.Если тестовая программа не дает сбоя, скрипт configure определяет макрос в сгенерированном заголовке config, который обеспечивает более быструю реализацию.Безопасная реализация по умолчанию.

void mask_bytes(unsigned char* dest, unsigned char* src, unsigned char* mask, unsigned int len)
{
  unsigned int i;
  unsigned int wordlen = len >> 2;

#if defined(UNALIGNED)
  // go fast
  for(i=0; i<wordlen; i++)
  {
    // the following line will raise SIGBUS on SPARC and other archs that require aligned access.
    ((uint32_t*)dest)[i] = ((uint32_t*)src)[i] & ((uint32_t*)mask)[i]; 
  }
  for(i=wordlen<<2; i<len; i++){
    dest[i] = src[i] & mask[i];
  }
#else
  // go slow
  for(i=0; i<len; i++)
  {
     dest[i] = src[i] & mask[i];
  }
#endif
}
1 голос
/ 07 декабря 2011

(я нахожу странным, что у вас есть src и mask, когда они действительно коммутируют. Я переименовал mask_bytes в memand. Но в любом случае ...)

Другой вариант - использовать различные функции, использующие преимущества типов в C. Например:

void memand_bytes(char *dest, char *src1, char *src2, size_t len)
{
    unsigned int i;
    for (i = 0; i < len; i++)
        dest[i] = src1[i] & src2[i];
}

void memand_ints(int *dest, int *src1, int *src2, size_t len)
{
    unsigned int i;
    for (i = 0; i < len; i++)
        dest[i] = src1[i] & src2[i];
}

Таким образом, вы позволяете программисту решать.

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