2013-01-18 62 views
3

我有以下片段。boost :: spirit :: qi性能

#include <iostream> 
#include <sstream> 
#include <chrono> 

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/classic.hpp> 

namespace qi = boost::spirit::qi; 
namespace classic = boost::spirit::classic; 

template<typename T> 
void output_time(const T& end, const T& begin) 
{ 
    std::cout << std::chrono::duration_cast<std::chrono::seconds>(
     end - begin).count() << std::endl; 
} 

template<typename Iter> 
struct qi_grammar : public qi::grammar<Iter> 
{ 
    qi_grammar():qi_grammar::base_type(rule_) 
    { 
     rule_ = *string_; 
     string_ = qi::char_('"') >> *(qi::char_ - '"') >> qi::char_('"'); 
    } 
    qi::rule<Iter> rule_; 
    qi::rule<Iter> string_; 
}; 

template<typename Iter> 
struct classic_grammar : public classic::grammar<classic_grammar<Iter>> 
{ 
    template<typename ScannerT> 
    struct definition 
    { 
     definition(const classic_grammar&) 
     { 
     rule = *string_; 
     string_ = classic::ch_p('"') >> *(classic::anychar_p - '"') >> classic::ch_p('"'); 
     } 
     classic::rule<ScannerT> rule, string_; 
     const classic::rule<ScannerT>& start() const { return rule; } 
    }; 
}; 

template<typename Iter> 
void parse(Iter first, Iter last, const qi_grammar<Iter>& prs) 
{ 
    auto start = std::chrono::system_clock::now(); 
    for (int i = 0; i < 100; ++i) 
    { 
     Iter next = first; 
     if (!qi::parse(next, last, prs) || next != last) 
     { 
     assert(false); 
     } 
    } 
    auto finish = std::chrono::system_clock::now(); 
    output_time(finish, start); 
} 

template<typename Iter> 
void parse_c(Iter first, Iter last, const classic_grammar<Iter>& prs) 
{ 
    auto start = std::chrono::system_clock::now(); 
    for (int i = 0; i < 100; ++i) 
    { 
     auto info = classic::parse(first, last, prs); 
     if (!info.hit) assert(false); 
    } 
    auto finish = std::chrono::system_clock::now(); 
    output_time(finish, start); 
} 

int main() 
{ 
    qi_grammar<std::string::const_iterator> qi_lexeme; 
    classic_grammar<std::string::const_iterator> classic_lexeme; 
    std::stringstream ss; 
    for (int i = 0; i < 1024 * 500; ++i) 
    { 
     ss << "\"name\""; 
    } 
    const std::string s = ss.str(); 
    std::cout << "Size: " << s.size() << std::endl; 
    std::cout << "Qi" << std::endl; 
    parse(s.begin(), s.end(), qi_lexeme); 
    std::cout << "Classic" << std::endl; 
    parse_c(s.begin(), s.end(), classic_lexeme); 
} 

结果

[email protected]:~/My_pro1/cpp_pro$ ./simple_j 
Size: 3072000 
Qi 
0 
Classic 
1 

所以,补气解析比传统快。但是,当我改变)string_规则性病属性::字符串((即qi::rule<Iter, std::string()> string_;)我有

[email protected]:~/My_pro1/cpp_pro$ ./simple_j 
Size: 3072000 
Qi 
19 
Classic 
1 

这是非常,非常缓慢。我做错了什么?谢谢。

编译器:gcc 4.6.3。提升 - 1.48.0。标志:-std = C++ 0x -O2。在LWS结果是相同的。语义动作为char_即

string_ = qi::char_('"') >> *(qi::char_[boost::bind(&some_f, _1)] - '"') 
>> qi::char_('"')[boost::bind(&some_clear_f, _1)]; 

使用率提高性能比较,但我正在寻找另一种解决方案也是如此,如果它的存在。

+0

什么编译器?什么编译器标志(优化等)? –

+0

@IgorR。 gcc 4.6.3。 -std = C++ 0x和-O2 – ForEveR

+3

看起来像你的问题是类似于这一个:http://stackoverflow.com/questions/13343874/boost-spirit-qi-slow –

回答

3

我想我在SO上回答了一个非常类似的问题。可悲的是,我找不到它。

简而言之,您可能更喜欢在源数据中使用迭代器,而不是在每次匹配时分配(并复制)字符串。

当使用

qi::rule<Iter, boost::iterator_range<Iter>()> string_; 
string_ = qi::raw [ qi::char_('"') >> *(qi::char_ - '"') >> qi::char_('"') ]; 

我得到了(有显着(16倍)更大的数据集):

Size: 49152000 
Qi 
12 
Classic 
11 

事实上,改变规则本身后

string_ = qi::raw [ qi::lit('"') >> *~qi::char_('"') >> '"' ]; 

我得到

Size: 49152000 
Qi 
7 
Classic 
11 

所以......这是相当不错的,我想。看到它在LWS:http://liveworkspace.org/code/opA5s$0

为了完整起见,很明显,你可以做这样的事情

const std::string dummy("hello world"); 
auto r = boost::make_iterator_range(begin(dummy), end(dummy)); 
std::string asstring(r.begin(), r.end()); 

诀窍得到的iterator_range的字符串是延迟实际字符串建设需要时。您可能想要自动产生这个技巧。这是Spirit Lex对令牌属性所做的。你可能想看看。

+0

**编辑过的**有一个澄清和优化,可以节省40%的运行时间,使'Qi'版本***大大优越(比'classic'快1/3)。 (注意我在一个带有8Mb RAM的Q9550上使用了gcc 4.7.2,64位,-O3 -march = native [-ltcmalloc](http://code.google.com/p/gperftools/?redir=1)) - 另请参阅[其他答案](http://stackoverflow.com/search?q=user%3A85371+tcmalloc)有关'libtcmalloc'的信息 – sehe

+0

哦...我不知道原始指令。非常感谢你。我想,这将是我的问题的答案。 – ForEveR

相关问题