Ошибка сегментации (дамп ядра) при использовании avx в массиве, выделенном с помощью new [] - PullRequest
2 голосов
/ 08 апреля 2019

Когда я запускаю этот код в Visual Studio 2015, код работает правильно. Но код генерирует следующую ошибку в кодовых блоках: Ошибка сегментации (ядро сброшено).Я также запустил код в Ubuntu с той же ошибкой.

#include <iostream>
#include <immintrin.h>

struct INFO
{
    unsigned int id = 0;
    __m256i temp[8];
};

int main()
{
    std::cout<<"Start AVX..."<<std::endl;
    int _size = 100;
    INFO  *info = new INFO[_size];
    for (int i = 0; i<_size; i++)
    {
        for (int k = 0; k < 8; k++)
        {
            info[i].temp[k] = _mm256_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
                20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31);

        }
    }
    std::cout<<"End AVX."<<std::endl;
    return 0;
}

Ответы [ 2 ]

5 голосов
/ 08 апреля 2019

Проблема в том, что до C ++ 17 new и delete не учитывали выравнивание типа, который будет выделен.Если вы посмотрите на сгенерированную сборку из этой простой функции:

INFO* new_test() {
    int _size = 100;
    INFO  *info = new INFO[_size];
    return info;
}

Вы увидите, что при компиляции с чем-либо до C ++ 17 operator new[](unsigned long) вызывается, тогда как для C ++ 17 вызываетсяустанавливается в operator new[](unsigned long, std::align_val_t)32 передается для второго параметра). Поиграйте с ним в Godbolt .

Если вы не можете использовать C ++ 17, вы можете перезаписать operator new[]operator delete[] - и вам следует перезаписать operator newи operator delete также ...):

struct INFO {
    unsigned int id = 0;
    __m256i temp[8];
    void* operator new[](size_t size) {
        // part of C11:
        return aligned_alloc(alignof(INFO), size);
    }
    void operator delete[](void* addr) {
        free(addr); // aligned_alloc is compatible with free
    }
};

Это часть предыдущего примера Godbolt, если вы компилируете с -DOVERWRITE_OPERATOR_NEW.

Обратите внимание, что это не решаетпроблема выравнивания при использовании std::vector (или любого другого std -контейнера), для этого вам нужно передать выравнивающий распределитель в контейнер (не является частью предыдущего примера).

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

Я нашел два способа решения этой проблемы

Первое решение Как решить проблему 32-байтового выравнивания для операций загрузки / сохранения AVX?

struct INFO
{
    __m256i temp[8];
    unsigned int id = 0;
};
INFO  *info = static_cast<INFO*>(_mm_malloc(sizeof(INFO)*_size, 32));
_mm_free(info);

Второе решение

INFO  *info = new INFO[_size];
for (int i = 0; i < _size; i++)
{
    INFO new_info;
    for (int k = 0; k < 8; k++)
    {
        new_info.temp[k] = _mm256_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
            20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31);

    }
    info[i] = new_info;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...