2013-01-23 40 views
6

我爲圖形文件格式寫了一個簡單的閱讀器和解析器。問題是它非常慢。這裏有相關的方法:爲什麼鎖定會減慢這個順序文件解析器?

Graph METISGraphReader::read(std::string path) { 
    METISParser parser(path); 
    std::pair<int64_t, int64_t> header = parser.getHeader(); 
    int64_t n = header.first; 
    int64_t m = header.second; 

    Graph G(n); 

    node u = 0; 
    while (parser.hasNext()) { 
     u += 1; 
     std::vector<node> adjacencies = parser.getNext(); 
     for (node v : adjacencies) { 
      if (! G.hasEdge(u, v)) { 
       G.insertEdge(u, v); 
      } 
     } 
    } 
    return G; 
} 

std::vector<node> METISParser::getNext() { 
    std::string line; 
    bool comment = false; 
    do { 
     comment = false; 
     std::getline(this->graphFile, line); 
     // check for comment line starting with '%' 
     if (line[0] == '%') { 
      comment = true; 
      TRACE("comment line found"); 
     } else { 
      return parseLine(line); 
     } 

    } while (comment); 
} 

static std::vector<node> parseLine(std::string line) { 
    std::stringstream stream(line); 
    std::string token; 
    char delim = ' '; 
    std::vector<node> adjacencies; 

    // split string and push adjacent nodes 
    while (std::getline(stream, token, delim)) { 
     node v = atoi(token.c_str()); 
     adjacencies.push_back(v); 
    } 
    return adjacencies; 
} 

爲了診斷爲什麼它如此之慢,我跑了它在一個探查器(蘋果儀器)。結果令人驚訝:由於鎖定開銷,速度很慢。該程序在pthread_mutex_lock_pthread_cond_wait中花費了90%以上的時間。

Instruments

我不知道在哪裏的鎖定開銷從何而來,但我需要擺脫它。你能建議下一步嗎?

編輯:看到擴展的呼叫棧爲_pthread_con_wait。我不能看着這找出鎖定開銷的來源:

enter image description here

+0

@KonradRudolph我從一個文件,'的std :: ifstream'讀取。你爲什麼認爲我從標準輸入讀取? – clstaudt

+0

因爲我是一個旋鈕。 –

+0

嗯,(爲什麼)您是否將您的代碼與OpenMP鏈接? log4cxx會帶來這種依賴性嗎? –

回答

2

展開對_pthread_cond_wait調用棧和調用的pthread_mutex_lock找出鎖定調用從調用。

作爲一個猜測,我會說它是在你所做的所有不必要的堆分配。堆是一個線程安全的資源,在這個平臺上,線程安全可以通過互斥體提供。

+1

查看上面展開的調用堆棧。我在哪裏做不必要的堆分配? – clstaudt

+0

鎖定在OpenMP框架中完成,該框架位於您在此處展示的代碼之外。就您創建的臨時字符串和向量而言,您所做的分配比您需要的要多,但與您在OpenMP中執行的任何操作相比,它們都是小土豆。 – karunski

+0

「您在創建的臨時字符串和向量方面所做的分配比您需要的要多」可能,但這些分配都在堆棧中,對嗎? – clstaudt

1

,其從istream讀取數據會鎖住mutex,所有功能從streambuf讀取數據和解鎖mutex。爲了消除這種開銷,請直接從streambuf而不是istream讀取文件,並且不要使用stringstream來解析數據。

這裏是一個版本的getline使用的streambuf代替istream

bool fastGetline(streambuf* sb, std::string& t) 
{ 
    t.clear(); 
    for(;;) { 
     int c = sb->sbumpc(); 
     switch (c) { 
     case '\n': 
      return true; 
     case '\r': 
      if(sb->sgetc() == '\n') 
       sb->sbumpc(); 
      return true; 
     case EOF: 
      return !t.empty(); 
     default: 
      t += (char)c; 
    } 
} 
+0

這是有道理的。我會在明天嘗試使用'fastGetline'來實現我的解析器,然後我們會看看它是否有效。 – clstaudt

+0

如果有一個''\ r'' ** not **後跟一個''\ n'',那麼'fastGetline'仍然會終止。我相信最好把這個''\ r'' push_back並繼續閱讀。儘管如何處理獨立的''\ r''s是一個判斷問題。總之,一個有趣的答案。 – Ali

+0

@Ali Standalone在大約十年前,Mac被用作Mac的行尾。 – user763305

相關問題