2013-01-18 2 views
3

다음 스 니펫이 있습니다.boost :: spirit :: qi perfomance

#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. flags : -std = C++ 0x -O2. LWS 결과는 동일합니다. char_ 즉

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

에 대한 의미 조치

사용은 perfomance을 향상하지만, 만약 존재한다면 내가 너무 다른 해결책을 찾고 있어요.

+0

어떤 컴파일러입니까? 어떤 컴파일러 플래그 (최적화 등)? –

+0

@IgorR. gcc 4.6.3. -std = C++ 0x and -O2 – ForEveR

+3

질문과 비슷한 것 같습니다 : http://stackoverflow.com/questions/13343874/boost-spirit-qi-slow –

답변

3

내가 전에 매우 비슷한 질문에 대답했다고 생각합니다. 슬프게도, 나는 그것을 발견 할 수 없다.

간단히 말하면, 매치마다 문자열을 할당 (복사)하는 대신 반복기를 소스 데이터에 사용하는 것이 좋습니다.

(상당히 (16X) 큰 데이터 세트)

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

I있어 사용 :

Size: 49152000 
Qi 
12 
Classic 
11 

실제로, 규칙 자체를 변경 한 후에 I

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' 버전 ***이 매우 우수합니다 (클래식보다 1/3 빠름). (참고 gcc 4.7.2, 64 비트, -O3 -march = 네이티브 [-ltcmalloc] (http://code.google.com/p/gperftools/?redir=1) - 8MB RAM을 갖춘 Q9550에서) - 'libtcmalloc'에 대한 정보는 [기타 답변들] (http://stackoverflow.com/search?q=user%3A85371+tcmalloc)도 참조하십시오. – sehe

+0

오 ... 원시 지시어에 대해 모르겠습니다. 고마워요. 내 질문에 대한 대답이 될거야. – ForEveR