为啥这个 C 语言中的 SIMD 示例代码可以用 minGW 编译,但可执行文件不能在我的 Windows 机器上运行?

Posted

技术标签:

【中文标题】为啥这个 C 语言中的 SIMD 示例代码可以用 minGW 编译,但可执行文件不能在我的 Windows 机器上运行?【英文标题】:Why does this SIMD example code in C compile with minGW but the executable doesn't run on my windows machine?为什么这个 C 语言中的 SIMD 示例代码可以用 minGW 编译,但可执行文件不能在我的 Windows 机器上运行? 【发布时间】:2014-12-11 21:50:21 【问题描述】:

我正在学习 SIMD 的基础知识,因此我得到了一个简单的代码 sn-p 来了解 SSE 和 SSE2 的工作原理。

我最近安装了 minGW 来使用 gcc 在 windows 中编译 C 代码,而不是使用 Visual Studio 编译器。

这个例子的目的是把两个浮点数相加,然后乘以第三个。

包含的标头如下(我猜这些标头用于能够使用 SSE 内在函数):

#include <time.h>
#include <stdio.h>
#include <xmmintrin.h>
#include <pmmintrin.h>
#include <time.h>
#include <sys/time.h> // for timing

然后我有一个函数来检查现在是什么时候,比较计算之间的时间:

double now()
   struct timeval t; double f_t;
   gettimeofday(&t, NULL);
   f_t = t.tv_usec; f_t = f_t/1000000.0; f_t +=t.tv_sec;
   return f_t;

在“标量”意义上进行计算的函数如下:

void run_scalar()
  unsigned int i;
  for( i = 0; i < N; i++ )
     rs[i] = (a[i]+b[i])*c[i];
     

这里是 sse2 函数的代码:

void run_sse2()
  unsigned int i;
  __m128 *mm_a = (__m128 *)a; 
  __m128 *mm_b = (__m128 *)b;
  __m128 *mm_c = (__m128 *)c;
  __m128 *mm_r = (__m128 *)rv;
  for( i = 0; i <N/4; i++)
    mm_r[i] = _mm_mul_ps(_mm_add_ps(mm_a[i],mm_b[i]),mm_c[i]);
  

向量的定义方式如下(N 是向量的大小,它在别处定义)并调用函数 init() 来初始化它们:

float a[N] __attribute__((aligned(16)));
float b[N] __attribute__((aligned(16)));
float c[N] __attribute__((aligned(16)));
float rs[N] __attribute__((aligned(16)));
float rv[N] __attribute__((aligned(16)));

void init()
  unsigned int i;
  for( i = 0; i < N; i++ )
      a[i] = (float)rand () / RAND_MAX / N; 
      b[i] = (float)rand () / RAND_MAX / N;  
      c[i] = (float)rand () / RAND_MAX / N; 
  

最后是调用函数并打印结果和计算时间的main。

int main()
  double t;
  init();
  t = now();
  run_scalar();
  t = now()-t;
  printf("S = %10.9f Temps du code scalaire   : %f seconde(s)\n",1e5*sum(rs),t);
  t = now();
  run_sse2();
  t = now()-t;
  printf("S = %10.9f Temps du code vectoriel 2: %f seconde(s)\n",1e5*sum(rv),t);

总而言之,如果我使用“gcc -o vec vectorial.c -msse -msse2 -msse3”或“mingw32-gcc -o vec vectorial.c -msse -msse2 -msse3”的命令行编译此代码它编译没有任何问题,但由于某种原因,我无法在我的 Windows 机器上运行它,在命令提示符下我得到“拒绝访问”,屏幕上出现一条大消息,说“此应用程序无法在您的计算机上运行PC,要找到适合您 PC 的版本,请与软件发行商联系”。

我真的不明白发生了什么,我对 MinGW 或 C 也没有太多经验(只是在 Linux 机器上完成的 C++ 入门课程)。我尝试过使用不同的标头,因为我认为我的目标处理器可能与我 PC 上的处理器不同,但无法解决问题。我发现的大部分信息都很混乱。

有人可以帮助我了解发生了什么吗?在针对 Linux 平台进行编译的 minGW 配置中是否存在问题?代码中的某些东西在 Windows 中没有等效项吗?

我正在尝试在 64 位 Windows 8.1 电脑上运行它

编辑:尝试了下面链接的站点中建议的配置。输出保持不变。

如果我尝试通过 MSYS 运行,我会收到“错误文件编号” 如果我尝试通过命令提示符运行,我会得到 Access is Denied。

我猜有某种由权限引起的错误。尝试关闭防病毒和用户帐户控制,但仍然没有成功。

有什么想法吗?

【问题讨论】:

您的交叉编译器可能针对 x64,但您尝试在 32 位 Windows 上运行它? 你能运行一个用你的 GCC 编译的简单的“hello world”程序吗? 是的,我做到了,它运行良好:/ main() 不会编译干净。因为该函数具有预期的 int 返回,但代码缺少预期的 'return(0);'就在最后一个右大括号之前。我也没有看到子函数的原型,它应该列在主函数之前。 (子函数应该列在主函数之后)你需要在'gcc'之后添加-Wall参数,这样所有的警告都会显示出来。 我注意到 被列出了两次。这将是“好的”,因为头文件具有适当的包装器,因此它们的内容不能在单个编译单元中包含多次。 【参考方案1】:

您的代码没有任何问题,此外,您没有提供sum()N 的定义,但这不是问题。开关-msse -msse2 似乎不是必需的。

我能够在 Linux(Ubuntu x86_64,使用 gcc 4.8.2 和 4.6.3 编译,在 Atom D2700 和 AMD Athlon LE-1640 上)和 Windows7/64(使用 gcc 4.5.3 编译)上编译和运行您的代码(32 位)和 4.8.2(64 位),在 Core i3-4330 和 Core i7-4960X 上)。它运行没有问题。

您确定您的 CPU 支持所需的指令吗?你得到的错误代码到底是什么?您使用了哪种 MinGW 配置?出于好奇,我使用了http://win-builds.org/download.html 提供的那个,非常简单。

然而,使用优化标志-O3 创造了最好的结果——使用标量循环! -m64 -mtune=native -s 也很有用。

【讨论】:

关于最后一段:-O3 启用了自动矢量化,因此很可能“标量”版本被编译为根本不是标量的东西:) 我的 CPU 是 i7-4860HQ。我猜我的 minGW 没有配置为针对我的 CPU 或类似的东西,我对 MinGW 一点也不熟悉,所以我想这就是问题所在。我有 4.8.1 gcc 版本,我刚刚从他们的网站上下载了 MinGW,并按照说明进行了基本设置。我尝试按照网站上的安装说明使用您建议的那个,但没有运气。如果我通过 Msys 运行编译器并尝试运行我得到的 exe,编译会继续进行,没有错误或警告,但是当我尝试运行 exe 时,我得到“”错误文件号“ 您对在哪里学习如何使用 MinGW 和 gcc 有什么建议吗?我真的觉得我不知道自己在做什么,而且 MinGW 网站不是很清晰或对新手友好。顺便说一句:感谢您的回答

以上是关于为啥这个 C 语言中的 SIMD 示例代码可以用 minGW 编译,但可执行文件不能在我的 Windows 机器上运行?的主要内容,如果未能解决你的问题,请参考以下文章

为啥向量长度 SIMD 代码比普通 C 慢

为啥此 SIMD 代码运行速度比等效标量慢?

这个 Delphi 6 位图修改代码可以用 SIMD 或其他方法加速吗?

这个C语言小程序在每输入三个数后会不会自动换行,我感觉没问题,为啥运行时不自动换行

为啥 strchr 比我的 simd 代码快两倍

C语言中free掉一段空间后为啥还要使用NULL