内置数组触发段错误:double矩阵转置为__m256d数组问题排查
段错误产生原因
- 核心原因是
__m256d类型的内存对齐要求未满足:__m256d是AVX指令集对应的256位双精度向量类型,硬件要求访问该类型的内存地址必须32字节对齐。你使用普通malloc分配的内存仅保证对齐到系统最大基础类型(64位系统通常为8或16字节),无法满足32字节对齐要求。 - 代码中使用
_mm256_loadu_pd仅解决了源矩阵数据的不对齐加载问题,但对result指针指向的地址做__m256d类型赋值时,编译器会默认生成对齐存储指令,未对齐的目标地址会触发处理器对齐异常,最终表现为段错误。
修复方案
优先选择对齐内存分配方案,不会损失向量运算性能:
方案1:替换普通malloc为对齐内存分配接口
根据运行环境选择对应接口:
Linux/macOS环境
可以使用aligned_alloc或者posix_memalign:
int block_count = (mat->cols + 3) / 4; size_t alloc_size = block_count * mat->rows * sizeof(__m256d); // 方式1:aligned_alloc,要求分配大小是对齐粒度的整数倍,此处已满足 __m256d *alt = (__m256d *) aligned_alloc(32, alloc_size); // 方式2:posix_memalign,兼容性更强 __m256d *alt = NULL; int ret = posix_memalign((void**)&alt, 32, alloc_size); if (ret != 0) { // 处理内存分配失败逻辑 }
Windows环境
使用_aligned_malloc分配,对应释放时需要用_aligned_free:
__m256d *alt = (__m256d *) _aligned_malloc(alloc_size, 32); // 释放逻辑:_aligned_free(alt);
方案2:使用不对齐存储指令(临时兼容方案,不推荐)
如果无法修改内存分配逻辑,可以将直接赋值替换为不对齐存储指令_mm256_storeu_pd,跳过对齐检查:
修改transpose_alter函数中的两处赋值逻辑即可:
// 原循环内赋值 // result[c_block * mat->rows + r] = _mm256_loadu_pd(mat_data_offset + c_block * 4); // 替换为 _mm256_storeu_pd((double*)&result[c_block * mat->rows + r], _mm256_loadu_pd(mat_data_offset + c_block * 4)); // 原剩余块赋值 // result[c_block * mat->rows + r] = _mm256_loadu_pd(buffer); // 替换为 _mm256_storeu_pd((double*)&result[c_block * mat->rows + r], _mm256_loadu_pd(buffer));
注意:该方案会增加存储指令的开销,降低运行效率,仅作为临时兼容方案使用
内容的提问来源于stack exchange,提问作者Wentinn Liao
相关产品推荐
相关产品推荐

