2017-06-07 2 views
0

Je tente d'implémenter la fonctionnalité de journalisation dans une application devant s'exécuter en temps réel (ce qui signifie que l'écriture de quelques millisecondes dans un fichier pendant l'exécution du La boucle affectera significativement les performances car nous interagissons avec plusieurs systèmes nécessitant une faible latence. Mon implémentation actuelle enregistre une ligne dans un stringstream chaque objet milliseconde, et écrit ensuite la chaîne résultante à un fichier uniquement lors de l'arrêt:Journalisation à l'aide de stringstream C++ stl avec des exigences de performances en temps réel

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

Mon désir est de mettre en œuvre un certain type de fonctionnalité de mise en mémoire tampon dans lequel je peux spécifier le nombre maximum de lignes dans mon journal, après quoi, les lignes initiales seront rejetées (essentiellement un tampon circulaire). De cette façon, je ne gaspille pas beaucoup de RAM et ralentis mon application en continuant à accumuler des données enregistrées, alors que peut-être seulement les 20 dernières secondes de données sont importantes. Je tentai en modifiant la méthode logLine() comme suit:

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

Cependant, le m_logged_data.str() qui est appelé à writeLogFile() retourne encore toutes les données enregistrées plutôt que seulement le dernier m_max_num_lines, ce qui suggère que le déplacement du pointeur stringstream obtenir avec ignore() ne affecter la taille du tampon utilisé par l'objet stringstream ou optimiser le code de l'une des façons que je voulais.

je me sens comme soit je manque quelque chose évidente de la classe stringstream (pourquoi est-il pas un setBufferSize() ?? voir this), ou devrais-je être à utiliser une autre pour gérer la fonctionnalité de journalisation. Si ce dernier, des suggestions sur quelle classe je devrais utiliser? L'une des bonnes choses à propos de stringstream est l'ensemble des fonctionnalités de mise en forme intégrées, que j'utilise (même si je ne l'ai pas montré dans les extraits de code ci-dessus). Donc, conserver ces capacités de formatage serait bien si possible.

+0

Bienvenue dans Stack Overflow. Veuillez prendre le temps de lire [The Tour] (http://stackoverflow.com/tour) et de consulter le contenu du [Centre d'aide] (http://stackoverflow.com/help/asking) quoi et comment vous pouvez demandez ici. –

+0

Quelles sont les exigences de formatage? – EvilTeach

+0

combien de mémoire disposez-vous pour stocker les informations de journalisation? – EvilTeach

Répondre

1

Si vous aimez vraiment utiliser std :: stringstream, vous pouvez créer un tableau de std :: stringstream et l'utiliser comme votre propre tampon circulaire. Voici un petit exemple:

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

Prenez note que si vous utilisez l'exemple ici dans votre propre projet avec une assez grande m_max_num_lines, vous aurez des ennuis parce que vous pourriez finir par utiliser beaucoup plus de souvenirs que prévu car pour chaque chaîne strings :: std :: elle prend un peu de mémoire elle-même. Une meilleure façon de le faire est de permettre à chacun d'entre eux de stocker une partie de m_max_num_lines. Dites, si m_max_num_lines est 1000, alors vous ne pouvez avoir que 10 std :: stringstream, chacun stockant un maximum de 100 lignes de log. Quand une chaîne de caractères std :: a déjà enregistré 100 lignes de journal, cur = (cur+1) % n. Notez que ce serait beaucoup mieux si vous pouvez simplement utiliser une matrice de caractères et la gérer par vous-même. Vous économisez à la fois de la mémoire et de l'heure, mais comme vous l'avez dit, vous perdez ces fonctionnalités de mise en forme intégrées, bien qu'il existe également de très jolies fonctionnalités de mise en forme d'un tableau de caractères brut, par exemple. sprintf().

+0

Si vous faites en temps réel, hhys dernier paragraphe est mort. Une allocation/désallocation d'un tableau de tampons de taille fixe dans lequel vous stockez votre message de consignation, avec un pointeur indiquant quel tampon doit être utilisé est susceptible d'être beaucoup plus rapide. – EvilTeach