2017-06-07 24 views
0

我試圖在需要實時運行的應用程序中實現日誌記錄功能(意思是在執行主文件期間花費幾毫秒寫入文件循環會顯着影響性能,因爲我們正在與幾個需要低延遲的系統接口)。我目前的執行記錄一條線成字符串流對象每毫秒,然後只在關機時得到的字符串寫入文件:使用具有實時性能要求的C++ stl stringstream記錄

class ControlDemo { 
    public: 
    ControlDemo(); 
    ~ControlDemo(); 
    void spin(); 
    // Other public methods 
    private: 
    void logLine(std::vector<double> data); 
    void writeLogFile(); 
    std::stringstream m_logged_data; 
    std::string m_log_filename; 
    bool m_continue_spinning; 
    // Other private methods 
}; 

ControlDemo::~ControlDemo() { 
    writeLogFile(); // write log data in RAM to a file 
} 

void ControlDemo::spin() { 
    while(m_continue_spinning){ 
    // do stuff 
    logLine(data_to_log); 
    sleepRemainingTime(); // maintaining ~1ms loop rate 
    } 
} 

void ControlDemo::logLine(std::vector<double> data) { 
    m_logged_data << getCurrentTime(); 
    for (std::vector<double>::iterator it = data.begin(); it != data.end(); ++it) 
    m_logged_data << ', ' << *it; 
    m_logged_data << std::endl; 
} 

void ControlDemo::writeLogFile() { 
    std::ofstream file; 
    file.open(m_log_file_path.c_str()); 

    file << m_logged_data.str(); 
    file.close(); 
    std::cerr << "Wrote log to " << m_log_file_path << std::endl; 
} 

我的願望是實現某種類型的緩衝功能,因此我可以指定最大數量我的日誌中的行,之後,最初的行將被丟棄(基本上是一個循環緩衝區)。通過這種方式,我不會浪費一堆內存,並且通過繼續累積記錄的數據來減慢我的應用程序的運行速度,當時可能只有最後20秒的數據很重要。我通過修改logLine()方法如下嘗試這樣的:

void ControlDemo::logLine(std::vector<double> data) { 
    static int line_num = 0; 
    if(line_num < m_max_num_lines) 
    line_num++; 
    else // discard first line before inserting next line 
    m_logged_data.ignore(1000,'\n'); // move get ptr to next line 

    m_logged_data << getCurrentTime(); 
    for (std::vector<double>::iterator it = data.begin(); it != data.end(); ++it) 
    m_logged_data << ', ' << *it; 
    m_logged_data << std::endl; 
} 

然而,被稱作writeLogFile()m_logged_data.str()仍返回所有記錄的數據,而不是僅在過去的m_max_num_lines,這表明移動stringstream的取指針與ignore()不影響stringstream對象使用的緩衝區的大小,或者以我想要的任何方式優化代碼。

我覺得要麼我缺少明顯的東西對stringstream類(爲什麼是不是有一個setBufferSize() ??看this),或者我應該用別的東西來管理日誌記錄功能。如果是後者,對我應該使用什麼課程有任何建議?關於stringstream的好處之一就是我使用的所有內置格式化功能(儘管我沒有在上面的代碼片段中顯示它)。因此,如果可能的話,保留這些格式化功能會很好。

+0

歡迎來到Stack Overflow。請花些時間閱讀[The Tour](http://stackoverflow.com/tour),並參閱[幫助中心](http://stackoverflow.com/help/asking)中的資料,瞭解您可以在這裏問。 –

+0

你有什麼格式要求? – EvilTeach

+0

您有多少內存可用於保存日誌記錄信息? – EvilTeach

回答

1

如果你真的想使用std :: stringstream,你可以創建一個std :: stringstream的數組,並將它用作你自己的環形緩衝區。這裏是一個非常小的例子:

#include <iostream> 
#include <fstream> 
#include <sstream> 

class CyclicStreamer { 
public: 
    CyclicStreamer(int _n, std::string _filename) : n(_n), cur(0), filename(_filename){ 
     s = new std::stringstream [n]; 
    }; 
    ~CyclicStreamer() { 
     delete s; 
    }; 
    void LogLine(int data) { 
     s[cur].str(std::string()); // clear the stringstream 
     s[cur] << data << std::endl; 
     cur = (cur+1) % n; 
    } 
    void LogToFile(){ 
     std::ofstream file; 
     file.open(filename.c_str()); 
     for(int i=cur;i<n;i++){ 
      file << s[i].str(); 
     } 
     for(int i=0;i<cur;i++){ 
      file << s[i].str(); 
     } 
     file.close(); 
    } 
private: 
    int n; 
    int cur; 
    std::string filename; 
    std::stringstream *s; 
}; 

int main() { 
    CyclicStreamer cs = CyclicStreamer(10, "log.txt"); 
    for(int i=0; i<=20; i++){ 
     cs.LogLine(i); 
    } 
    cs.LogToFile(); 
    return 0; 
} 

請注意,如果你在你自己的項目在這裏使用的例子有一個相當大的m_max_num_lines,你會惹上麻煩,因爲高於預期,你可能最終使用了很多的回憶因爲對於每個std :: stringstream它本身需要一點內存。更好的做法是讓每個人都存儲m_max_num_lines的一部分。假如,如果m_max_num_lines是1000,那麼你只能有10個std :: stringstream,每個最多存儲100行日誌。當一個std :: stringstram已經存儲了100行日誌時,cur = (cur+1) % n

請注意,如果您只能使用char數組並自行管理它會好得多。你可以節省內存和時間,但正如你所說,你失去了內置的格式化功能,儘管格式化原始字符數組也有很好的功能,例如, sprintf()

+0

如果你正在做實時,hhys的最後一段已經死了。一個用於存儲日誌消息的固定大小緩衝區數組的分配/釋放可能要快得多,並且有一個指向下一個緩衝區的指針。 – EvilTeach

相關問題