// 如果定义了__ARM_NEON__,则包含头文件,用于支持ARM NEON指令集相关的操作 #ifdef __ARM_NEON__ #include #endif // 定义向量的大小为1024 const int VECTOR_SIZE = 1024; // 定义矩阵的大小为32(这里表示矩阵是32x32的) const int MATRIX_SIZE = 32; // 基础的向量加法函数 // 该函数实现了简单的向量加法操作,将输入向量a和b对应位置的元素相加,结果存储在result向量中 // 参数: // a:输入向量a的指针 // b:输入向量b的指针 // result:用于存储相加结果的向量指针 // size:向量的元素个数 void vectorAddBase(float* a, float* b, float* result, int size) { // 循环遍历向量的每个元素 for (int i = 0; i < size; ++i) { // 将a和b对应位置的元素相加,并存入result向量的对应位置 result[i] = a[i] + b[i]; } } // 如果定义了__ARM_NEON__,则执行以下NEON优化的向量加法函数 #ifdef __ARM_NEON__ // NEON优化的向量加法函数 // 该函数利用ARM NEON指令集对向量加法进行优化,以4个元素为一组进行处理(当向量大小是4的倍数时) // 参数: // a:输入向量a的指针 // b:输入向量b的指针 // result:用于存储相加结果的向量指针 // size:向量的元素个数 void vectorAddNeon(float* a, float* b, float* result, int size) { int i; // 以4个元素为一组进行处理,循环直到剩余元素不足4个 for (i = 0; i <= size - 4; i += 4) { // 使用vld1q_f32指令将向量a中从索引i开始的4个元素加载到NEON寄存器vecA中 float32x4_t vecA = vld1q_f32(&a[i]); // 使用vld1q_f32指令将向量b中从索引i开始的4个元素加载到NEON寄存器vecB中 float32x4_t vecB = vld1q_f32(&b[i]); // 使用vaddq_f32指令对vecA和vecB中的对应元素进行加法操作,结果存储在vecResult中 float32x4_t vecResult = vaddq_f32(vecA, vecB); // 使用vst1q_f32指令将vecResult中的4个元素存储回result向量中从索引i开始的位置 vst1q_f32(&result[i], vecResult); } // 处理向量大小不是4的倍数时剩余的元素 for (; i < size; ++i) { // 对于剩余元素,使用基础的加法方式将a和b对应位置的元素相加,并存入result向量的对应位置 result[i] = a[i] + b[i]; } } // 如果未定义__ARM_NEON__,则执行以下fallback操作,即调用基础的向量加法函数 #else void vectorAddNeon(float* a, float* b, float* result, int size) { vectorAddBase(a, b, result, size); // Fallback to base implementation } #endif // 基础的矩阵乘法函数 // 该函数实现了常规的矩阵乘法算法,按照矩阵乘法的规则计算两个矩阵A和B的乘积,结果存储在矩阵C中 // 参数: // A:输入矩阵A的指针 // B:输入矩阵B的指针 // C:用于存储乘法结果的矩阵指针 // N:矩阵的边长(这里假设矩阵是方阵,所以只需要一个边长参数) void matrixMultiplyBase(float* A, float* B, float* C, int N) { // 外层循环遍历矩阵A的行 for (int i = 0; i < N; ++i) { // 内层循环遍历矩阵B的列 for (int j = 0; j < N; ++j) { // 先将结果矩阵C中当前位置的元素初始化为0.0f C[i * N + j] = 0.0f; // 中间循环遍历矩阵A的列和矩阵B的行,用于计算乘积并累加 for (int k = 0; k < N; ++k) { C[i * N + j] += A[i * N + k] * B[k * N + j]; } } } } // 如果定义了__ARM_NEON__,则执行以下NEON优化的矩阵乘法函数 #ifdef __ARM_NEON__ // NEON优化的矩阵乘法函数 // 该函数利用ARM NEON指令集对矩阵乘法进行优化,以4个元素为一组处理矩阵B的列(当矩阵边长是4的倍数时) // 参数: // A:输入矩阵A的指针 // B:输入矩阵B的指针 // C:用于存储乘法结果的矩阵指针 // N:矩阵的边长(这里假设矩阵是方阵,所以只需要一个边长参数) void matrixMultiplyNeon(float* A, float* B, float* C, int N) { // 外层循环遍历矩阵A的行 for (int i = 0; i < N; ++i) { // 内层循环遍历矩阵B的列,每次处理4个元素一组 for (int j = 0; j < N; j += 4) { // 使用vmovq_n_f32指令将浮点数0.0f初始化为NEON寄存器sum,用于累加乘积结果 float32x4_t sum = vmovq_n_f32(0.0f); // 中间循环遍历矩阵A的列和矩阵B的行,用于计算乘积并累加 for (int k = 0; k < N; ++k) { // 使用vdupq_n_f32指令复制矩阵A中当前行、当前列k对应的元素到NEON寄存器vecA中 float32x4_t vecA = vdupq_n_f32(A[i * N + k]); // 使用vld1q_f32指令将矩阵B中当前列j从索引k开始的4个元素加载到NEON寄存器vecB中 float32x4_t vecB = vld1q_f32(&B[k * N + j]); // 使用vfmaq_f32指令将vecA和vecB中的对应元素相乘,并累加到sum寄存器中 sum = vfmaq_f32(sum, vecA, vecB); } // 使用vst1q_f32指令将sum寄存器中的4个元素存储回结果矩阵C中当前行、当前列j开始的位置 vst1q_f32(&C[i * N + j], sum); } } } // 如果未定义__ARM_NEON__,则执行以下fallback操作,即调用基础的矩阵乘法函数 #else void matrixMultiplyNeon(float* A, float* B, float* C, int N) { matrixMultiplyBase(A, B, C, N); // Fallback to base implementation } #endif // 计算两个timespec结构体表示的时间点之间的时间差的函数 // 参数: // start:起始时间点的timespec结构体 // end:结束时间点的timespec结构体 // 返回值:以秒为单位的时间差 double get_time_diff(struct timespec start, struct timespec end) { // 计算秒数差 double diff_sec = end.tv_sec - start.tv_sec; // 计算纳秒数差 double diff_nsec = end.tv_nsec - start.tv_nsec; // 将纳秒数差转换为秒并与秒数差相加,得到总时间差 return diff_sec + diff_nsec / 1e9; } // 如果定义了_WIN32,说明是在Windows平台下,包含头文件,并定义以下函数 #ifdef _WIN32 #include // 计算两个LARGE_INTEGER结构体表示的时间点之间的时间差的函数(用于Windows平台) // 参数: // start:起始时间点的LARGE_INTEGER结构体 // end:结束时间点的LARGE_INTEGER结构体 // frequency:时间频率的LARGE_INTEGER结构体 // 返回值:以秒为单位的时间差 double get_time_diff_windows(LARGE_INTEGER start, LARGE_INTEGER end, LARGE_INTEGER frequency) { // 计算经过的时间,通过两个时间点的QuadPart差值除以时间频率的QuadPart得到 double elapsed = (double)(end.QuadPart - start.QuadPart) / frequency.QuadPart; // 返回计算得到的时间差 return elapsed; } #endif