Linux上的C ++代码要慢得多

时间:2017-06-11 15:46:56

标签: c++ linux windows

我正在编写简单的程序,我想知道它在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

主要目标是确定时间。

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

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

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

在下面的代码片段中,我使用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()

FYI - “class PPLSem_t”是运行Posix Process Semaphore的4-single-line-methods设置为本地模式(unamed,unshared)。

上述测试仅测量方法调用的成本,在此实验中未调用上下文切换(非常慢)。

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

那你怎么做这个有用的?

两个步骤。 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。

希望这有帮助。