linux上的C++代码比windows上慢得多[关闭]

Posted

技术标签:

【中文标题】linux上的C++代码比windows上慢得多[关闭]【英文标题】:C++ code is much slower on linux than on windows [closed] 【发布时间】:2017-06-11 15:46:56 【问题描述】:

我正在编写简单的程序,我想测量它在 Windows 和 Linux(均为 64 位)上的执行时间。我有一个问题,因为在 Windows 上表中的 1 000 000 个元素大约需要 35 秒,而在 linux 上,10 个元素大约需要 30 秒。为什么差异如此之大? 我究竟做错了什么?我的代码中有什么东西在 Linux 上不合适吗?

这是我的代码:

void fillTable(int s, int t[])

    srand(time(0));
    for (int i = 0; i < s; i++)
    
        t[i] = rand();
    

void checkIfIsPrimeNotParalleled(int size, int table[])

    for (int i = 0; i < size; i++)
    
        int tmp = table[i];

        if (tmp < 2)
        
        


        for (int i = 2; i < tmp; i++)
        
            if (tmp % i == 0)
            
            
            else
            
            
        
    

void mesureTime(int size, int table[], int numberOfRepetitions)

    long long sum = 0;
    clock_t start_time, end_time;
    fillTable(size, table);

    for (int i = 0; i < numberOfRepetitions; i++)
    
        start_time = clock();

        checkIfIsPrimeNotParalleled(size, table); 

        end_time = clock();
        double duration = (end_time - start_time) / CLOCKS_PER_SEC;
        sum += duration;
    
    cout << "Avg: " << round(sum / numberOfRepetitions) << " s"<<endl;


int main()


    static constexpr int size = 1000000; 
    int *table = new int[size];
    int numberOfRepetitions = 1;
    mesureTime(size, table, numberOfRepetitions);
    delete[] table;
    return 0;


和 Linux 的 makefile。在 Windows 上,我使用的是 Visual Studio 2015

.PHONY: Project1

CXX = g++
EXEC = tablut
LDFLAGS = -fopenmp
CXXFLAGS = -std=c++11 -Wall -Wextra -fopenmp -m64
SRC= Project1.cpp
OBJ= $(SRC:.cpp=.o)

all: $(EXEC)

tablut: $(OBJ)
    $(CXX) -o tablut $(OBJ) $(LDFLAGS)

%.o: %.cpp
    $(CXX) -o $@ -c $< $(CXXFLAGS) 

clean:
    rm -rf *.o

mrproper: clean
    rm -rf tablut

主要目标是测量时间。

【问题讨论】:

有什么理由不让 GCC 优化这段代码? (喜欢 -03 选项?) 你是在Windows下以Release模式运行代码吗? 当我用 O3、O2 甚至 O1 运行这个项目时,99999999 个元素的时间是 0 秒 你的被测函数没有效果,对函数的调用可以优化掉。 微基准测试比仅仅围绕某个函数循环要难一些。例如,请参阅 Chandler Carruth 在 youtube 上的演讲。 【参考方案1】:

您的代码将 for 循环设置为 1,000,000 次迭代。正如其他人所指出的,编译器可以优化这个循环,这样你什么都学不到。

我用来解决好编译器问题的一种技术是用低成本时间检查替换固定循环。

在下面的代码 sn-p 中,我使用 chrono 进行持续时间测量,并使用 time(0) 来检查测试结束。 Chrono 不是我发现的成本最低的时间检查,但我认为对于我如何使用它来说已经足够了。 std::time(0) 测量为大约 5 ns(在我的系统上),大约是我测量的最快的。

// Note 7 - semaphore function performance
// measure duration when no thread 'collision' and no context switch
 void measure_LockUnlock()
    
       PPLSem_t*    sem1 = new PPLSem_t;
       assert(nullptr != sem1);
       size_t     count1 = 0;
       size_t     count2 = 0;
       std::cout << dashLine << "  3 second measure of lock()/unlock()"
                 << " (no collision) " << std::endl;
       time_t t0 = time(0) + 3;

       Time_t start_us = HRClk_t::now();
       do 
          assert(0 == sem1->lock());   count1 += 1;
          assert(0 == sem1->unlock()); count2 += 1;
          if(time(0) > t0)  break;
       while(1);
       auto  duration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);

       assert(count1 == count2);
       std::cout << report (" 'sem lock()+unlock()' ", count1, duration_us.count());

       delete sem1;
       std::cout << "\n";
     // void mainMeasures_LockUnlock()

仅供参考-“类 PPLSem_t”是 4 单行方法,运行设置为本地模式的 Posix 进程信号量(未命名,未共享)。

上面的测试只测量方法调用的成本,在这个实验中没有调用上下文切换(众所周知的慢)。


但是等等,你说... lock() 和 unlock() 中的一个没有副作用吗?同意。但是编译器知道吗?它必须假设他们这样做。

那么你如何使它有用呢?

两步。 1) 测量您的锁定/解锁性能。 2) 将 for 循环内部的代码(而不是 for 循环本身)添加到此锁定/解锁循环中,然后再次测量性能。

这两个度量的区别在于你寻找的信息,我认为编译器无法优化它。

在我的旧戴尔上使用 Ubuntu 15.10 和 g++v5.2.1.23 和 -O3 进行持续时间测量的结果是

  --------------------------------------------------------------
  3 second measure of lock()/unlock() (no collision) 
  133.5317660 M 'sem lock()+unlock()'  events in 3,341,520 us
  39.96138464 M 'sem lock()+unlock()'  events per second
  25.02415792 n sec per  'sem lock()+unlock()'  event 

因此,每种方法中的一种大约需要 12.5 纳秒,并且在大约 3 秒内实现了 133 次 10^6 次迭代。

您可以尝试调整时间以达到 1,000,000 次迭代,或者简单地使用迭代计数跳出循环。 (即如果 count1 == 1,000,000)中断;一种想法)


如果您选择接受它,您的任务是找到一个合适的简单快速的方法(或两个)具有副作用(您知道不会发生),然后将您的代码添加到该循环中,然后运行直到循环计数为 1,000,000。


希望这会有所帮助。

【讨论】:

嗯,也许这帮助太大了,但我的 PPLSem_t 代码存在于我的其他 SE 答案之一中。 您可以尝试定时循环而不使用具有副作用的方法...它可以工作,因为编译器无法猜测您的系统性能。 oops ... 注意到我的 chrono typedef 丢失了。在此处查看我的答案:***.com/a/44467595/2785528 以获取副本【参考方案2】:

您没有在 Linux 上启用优化来构建。将 -O2-O3 添加到您的编译器标志 (CXXFLAGS) 中,您将看到显着的性能提升。

【讨论】:

当我用 O3、O2 甚至 O1 运行这个项目时,99999999 个元素的时间是 0 秒 @karo96 你去。编译器完成了它的工作并优化了你的代码,因为它没有副作用。 我会说 0 秒比 35 秒快得多

以上是关于linux上的C++代码比windows上慢得多[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

在 AIX/bash 上的 bash 循环中读取文件比在 Linux/ksh 中慢得多 - BLOCKSIZE?

为什么犰狳矩阵计算比Fortran慢得多

为啥 lstat 在 APFS (OSX) 上的性能比 Ext4 (Linux) 差

Intel 上的多线程比 AMD 慢得多

C++ 似乎比 Project Euler 的 Python Ruby 慢得多

为啥在 C++ 中从标准输入读取行比 Python 慢得多?