【发布时间】:2011-01-27 15:07:32
【问题描述】:
我们正在一个使用 OpenMP 的项目上运行一些代码,但我遇到了一些奇怪的事情。我已经包含了一些演示代码的部分内容。
测试比较在多线程循环中调用具有 const char* 参数的函数和 std::string 参数。这些函数基本上什么都不做,因此没有开销。
我所看到的是完成循环所需的时间存在重大差异。对于执行 100,000,000 次迭代的 const char* 版本,代码需要 0.075 秒才能完成,而 std::string 版本需要 5.08 秒。这些测试是在带有 gcc-4.4 的 Ubuntu-10.04-x64 上完成的。
我的问题基本上是这是否仅仅是由于 std::string 的动态分配以及为什么在这种情况下不能优化掉,因为它是 const 并且不能改变?
下面的代码,非常感谢您的回复。
编译:g++ -Wall -Wextra -O3 -fopenmp string_args.cpp -o string_args
#include <iostream>
#include <map>
#include <string>
#include <stdint.h>
// For wall time
#ifdef _WIN32
#include <time.h>
#else
#include <sys/time.h>
#endif
namespace
{
const int64_t g_max_iter = 100000000;
std::map<const char*, int> g_charIndex = std::map<const char*,int>();
std::map<std::string, int> g_strIndex = std::map<std::string,int>();
class Timer
{
public:
Timer()
{
#ifdef _WIN32
m_start = clock();
#else /* linux & mac */
gettimeofday(&m_start,0);
#endif
}
float elapsed()
{
#ifdef _WIN32
clock_t now = clock();
const float retval = float(now - m_start)/CLOCKS_PER_SEC;
m_start = now;
#else /* linux & mac */
timeval now;
gettimeofday(&now,0);
const float retval = float(now.tv_sec - m_start.tv_sec) + float((now.tv_usec - m_start.tv_usec)/1E6);
m_start = now;
#endif
return retval;
}
private:
// The type of this variable is different depending on the platform
#ifdef _WIN32
clock_t
#else
timeval
#endif
m_start; ///< The starting time (implementation dependent format)
};
}
bool contains_char(const char * id)
{
if( g_charIndex.empty() ) return false;
return (g_charIndex.find(id) != g_charIndex.end());
}
bool contains_str(const std::string & name)
{
if( g_strIndex.empty() ) return false;
return (g_strIndex.find(name) != g_strIndex.end());
}
void do_serial_char()
{
int found(0);
Timer clock;
for( int64_t i = 0; i < g_max_iter; ++i )
{
if( contains_char("pos") )
{
++found;
}
}
std::cout << "Loop time: " << clock.elapsed() << "\n";
++found;
}
void do_parallel_char()
{
int found(0);
Timer clock;
#pragma omp parallel for
for( int64_t i = 0; i < g_max_iter; ++i )
{
if( contains_char("pos") )
{
++found;
}
}
std::cout << "Loop time: " << clock.elapsed() << "\n";
++found;
}
void do_serial_str()
{
int found(0);
Timer clock;
for( int64_t i = 0; i < g_max_iter; ++i )
{
if( contains_str("pos") )
{
++found;
}
}
std::cout << "Loop time: " << clock.elapsed() << "\n";
++found;
}
void do_parallel_str()
{
int found(0);
Timer clock;
#pragma omp parallel for
for( int64_t i = 0; i < g_max_iter ; ++i )
{
if( contains_str("pos") )
{
++found;
}
}
std::cout << "Loop time: " << clock.elapsed() << "\n";
++found;
}
int main()
{
std::cout << "Starting single-threaded loop using std::string\n";
do_serial_str();
std::cout << "\nStarting multi-threaded loop using std::string\n";
do_parallel_str();
std::cout << "\nStarting single-threaded loop using char *\n";
do_serial_char();
std::cout << "\nStarting multi-threaded loop using const char*\n";
do_parallel_char();
}
【问题讨论】:
-
在没有 OpenMP 的情况下看到这个时间会很有趣。还有 contains_str 和 contains_char 的代码以及编译器标志,因此我们可以自己重复实验..
-
您是否尝试过调试和发布二进制文件?
-
不比较苹果和苹果。将字符串结构移出循环以获得等效比较。
-
如果没有 OpenMP,std::string 版本大约需要 5.5 秒,我猜这也是分配。我没有拉出字符串构造的原因是这是我想模仿我们真实代码的玩具代码。在实际版本中,对接受参数的函数的调用显然不在循环内,因此取出 std::string 构造并不是很明显的事情。无论如何,我实际上应该将其删除,因为“pos”已被写在很多地方。感谢 cmets。
-
对于那些有兴趣的人,是否可以附加一个文件来发布或者我应该把它复制进去(这是我的第一个问题:))?
标签: c++