2017-06-07 6 views
0

私は、リアルタイムで実行する必要があるアプリケーションでロギング機能を実装しようとしています(つまり、メインの実行中にファイルに数ミリ秒を費やします低レイテンシを必要とするいくつかのシステムに接続しているため、ループはパフォーマンスに大きな影響を与えます)。私の現在の実装では、ミリ秒ごとにstringstreamオブジェクトにラインをログに記録し、その後にのみ、シャットダウン時にファイルへの結果の文字列を書き込みます。リアルタイムのパフォーマンス要件を持つC++ stlストリングストリームを使用したロギング

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; 
} 

私の願いは、私は最大数を指定することができるバッファリング機能のいくつかの種類を実装することです私のログの行のうち、最初の行は破棄されます(本質的に循環バッファです)。このようにして、RAMの束を無駄にしたり、データの最後の20秒しか重要でないときに、ログに記録されたデータを蓄積し続けることでアプリケーションの速度を落とすことはありません。

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しかし、ignore()でポインタを取得にstringstreamを移動することはないことを示唆している:私は次のようにlogLine()方法を変更することでこれを試みましたstringstreamオブジェクトで使用されるバッファのサイズに影響を与えたり、意図した方法でコードを最適化したりします。

stringstreamクラス(なぜsetBufferSize()thisを参照)がないのですか)、または私はロギング機能を管理するために別のものを使用する必要があります。後者の場合は、どのようなクラスを使用すべきかに関する提案はありますか? stringstreamについての素晴らしい点の1つは、私が使用している組み込みの書式設定機能のすべてです(ただし、上のコードスニペットでは示していませんが)。したがって、可能であれば、これらの書式設定機能を維持することは素晴らしいことです。

+0

ようこそスタックオーバーフロー。 [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

リアルタイムで作業している場合、最後の段落は死んでいます。ログメッセージを格納する固定サイズのバッファ配列の割り当て/割り当て解除の1つで、次のバッファを使用するかどうかを指示するポインタを使用すると、はるかに高速になる可能性があります。 – EvilTeach

関連する問題