GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/debug/real-time-logger.cpp Lines: 53 56 94.6 %
Date: 2023-03-15 12:04:10 Branches: 46 66 69.7 %

Line Branch Exec Source
1
/*
2
 * Copyright 2018,
3
 * Joseph Mirabel
4
 *
5
 * LAAS-CNRS
6
 *
7
 */
8
9
#include <dynamic-graph/real-time-logger.h>
10
11
#include <boost/date_time/posix_time/posix_time.hpp>
12
#include <boost/thread/thread.hpp>
13
14
namespace dynamicgraph {
15
5
RealTimeLogger::RealTimeLogger(const std::size_t &bufferSize)
16
    : buffer_(bufferSize, NULL),
17
      frontIdx_(0),
18
      backIdx_(0),
19
      oss_(NULL),
20

5
      nbDiscarded_(0) {
21

4015
  for (std::size_t i = 0; i < buffer_.size(); ++i) buffer_[i] = new Data;
22
5
}
23
24
5
RealTimeLogger::~RealTimeLogger() {
25
  // Check that we are not spinning...
26

4015
  for (std::size_t i = 0; i < buffer_.size(); ++i) delete buffer_[i];
27
5
}
28
29
122037
bool RealTimeLogger::spinOnce() {
30
122037
  if (empty()) return false;
31
122032
  Data *data = buffer_[frontIdx_];
32
122032
  frontIdx_ = (frontIdx_ + 1) % buffer_.size();
33
122032
  std::string str = data->buf.str();
34
  // It is important to pass str.c_str() and not str
35
  // because the str object may contains a '\0' so
36
  // str.size() may be different from strlen(str.c_str())
37
244064
  for (std::size_t i = 0; i < outputs_.size(); ++i)
38
122032
    outputs_[i]->write(str.c_str());
39
122032
  return true;
40
}
41
42
135834
RTLoggerStream RealTimeLogger::front() {
43
  // If no output or if buffer is full, discard message.
44

135834
  if (outputs_.empty() || full()) {
45
13802
    nbDiscarded_++;
46
13802
    return RTLoggerStream(NULL, oss_);
47
  }
48
122032
  bool alone = wmutex.try_lock();
49
  // If someone is writting, discard message.
50
122032
  if (!alone) {
51
    nbDiscarded_++;
52
    return RTLoggerStream(NULL, oss_);
53
  }
54
122032
  Data *data = buffer_[backIdx_];
55
  // backIdx_ = (backIdx_+1) % buffer_.size();
56
  // Reset position of cursor
57
122032
  data->buf.pubseekpos(0);
58
122032
  oss_.rdbuf(&data->buf);
59
122032
  return RTLoggerStream(this, oss_);
60
}
61
62
struct RealTimeLogger::thread {
63
  bool requestShutdown_;
64
  int threadPolicy_;
65
  int threadPriority_;
66
  bool changedThreadParams;
67
  boost::thread t_;
68
69
4
  explicit thread(RealTimeLogger *logger)
70
4
      : requestShutdown_(false),
71
        threadPolicy_(SCHED_OTHER),
72
        threadPriority_(0),
73
        changedThreadParams(true),
74
4
        t_(&thread::spin, this, logger) {}
75
76
  //  void setThreadPolicy(int policy) {
77
  //  threadPolicy_ = policy;
78
  //  changedThreadParams = true;
79
  // }
80
81
  // void setPriority(int priority) {
82
  //    threadPriority_ = priority;
83
  //    changedThreadParams = true;
84
  //  }
85
86
  //  int getThreadPolicy() { return threadPolicy_; }
87
  // int getThreadPriority() { return threadPriority_; }
88
89
4
  void changeThreadParams() {
90
    int threadPolicy;
91
    struct sched_param threadParam;
92
4
    if (pthread_getschedparam(pthread_self(), &threadPolicy, &threadParam) ==
93
        0) {
94
4
      threadPolicy = threadPolicy_;
95
4
      threadParam.sched_priority = threadPriority_;
96
4
      if (threadParam.sched_priority < sched_get_priority_min(threadPolicy))
97
        threadParam.sched_priority = sched_get_priority_min(threadPolicy);
98
99
4
      pthread_setschedparam(pthread_self(), threadPolicy, &threadParam);
100
4
      changedThreadParams = false;
101
    }
102
4
  }
103
104
2029
  void spin(RealTimeLogger *logger) {
105
    // Change the thread's scheduler from real-time to normal
106
    // and reduce its priority
107
108

2029
    while (!requestShutdown_ || !logger->empty()) {
109
      // If the logger did not write anything, it means the buffer is empty.
110
      // Do a pause
111
2025
      if (!logger->spinOnce())
112

4
        boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
113
2025
      if (changedThreadParams) changeThreadParams();
114
    }
115
4
  }
116
};
117
118
RealTimeLogger *RealTimeLogger::instance_ = NULL;
119
RealTimeLogger::thread *RealTimeLogger::thread_ = NULL;
120
121
281038
RealTimeLogger &RealTimeLogger::instance() {
122
281038
  if (instance_ == NULL) {
123

4
    instance_ = new RealTimeLogger(1000);
124
4
    thread_ = new thread(instance_);
125
  }
126
281038
  return *instance_;
127
}
128
129
4
void RealTimeLogger::destroy() {
130
4
  if (instance_ == NULL) return;
131
4
  thread_->requestShutdown_ = true;
132
4
  thread_->t_.join();
133
4
  delete instance_;
134
4
  delete thread_;
135
}
136
}  // namespace dynamicgraph