GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/traces/tracer.cpp Lines: 96 118 81.4 %
Date: 2023-03-15 12:04:10 Branches: 104 226 46.0 %

Line Branch Exec Source
1
/*
2
 * Copyright 2010,
3
 * François Bleibel,
4
 * Olivier Stasse,
5
 *
6
 * CNRS/AIST
7
 *
8
 */
9
10
/* --------------------------------------------------------------------- */
11
/* --- INCLUDE --------------------------------------------------------- */
12
/* --------------------------------------------------------------------- */
13
14
/* DG */
15
#include <dynamic-graph/all-commands.h>
16
#include <dynamic-graph/debug.h>
17
#include <dynamic-graph/factory.h>
18
#include <dynamic-graph/pool.h>
19
#include <dynamic-graph/tracer.h>
20
#include <dynamic-graph/value.h>
21
22
#include <boost/bind.hpp>
23
24
using namespace std;
25
using namespace dynamicgraph;
26
using namespace dynamicgraph::command;
27
28

1
DYNAMICGRAPH_FACTORY_ENTITY_PLUGIN(Tracer, "Tracer");
29
30
/* --------------------------------------------------------------------- */
31
/* --- CLASS ----------------------------------------------------------- */
32
/* --------------------------------------------------------------------- */
33
34
2
Tracer::Tracer(const std::string n)
35
    : Entity(n),
36
      toTraceSignals(),
37
      traceStyle(TRACE_STYLE_DEFAULT),
38
      frequency(1),
39
      basename(),
40
      suffix(".dat"),
41
      rootdir(),
42
      namesSet(false),
43
      files(),
44
      names(),
45
      play(false),
46
      timeStart(0),
47
      triger(boost::bind(&Tracer::recordTrigger, this, _1, _2), sotNOSIGNAL,
48



2
             "Tracer(" + n + ")::triger") {
49

2
  signalRegistration(triger);
50
51
  /* --- Commands --- */
52
  {
53
    using namespace dynamicgraph::command;
54
2
    std::string doc;
55
56


4
    doc = docCommandVoid2("Add a new signal to trace.", "string (signal name)",
57
2
                          "string (filename, empty for default");
58

2
    addCommand("add",
59
2
               makeCommandVoid2(*this, &Tracer::addSignalToTraceByName, doc));
60
61
    doc =
62

2
        docCommandVoid0("Remove all signals. If necessary, close open files.");
63

2
    addCommand("clear",
64
2
               makeCommandVoid0(*this, &Tracer::clearSignalToTrace, doc));
65
66


4
    doc = docCommandVoid3(
67
        "Gives the args for file opening, and "
68
        "if signals have been set, open the corresponding files.",
69
2
        "string (dirname)", "string (prefix)", "string (suffix)");
70

2
    addCommand("open", makeCommandVoid3(*this, &Tracer::openFiles, doc));
71
72

2
    doc = docCommandVoid0("Close all the open files.");
73

2
    addCommand("close", makeCommandVoid0(*this, &Tracer::closeFiles, doc));
74
75

4
    doc = docCommandVoid0(
76
        "If necessary, dump "
77
2
        "(can be done automatically for some traces type).");
78

2
    addCommand("dump", makeCommandVoid0(*this, &Tracer::trace, doc));
79
80

2
    doc = docCommandVoid0("Start the tracing process.");
81

2
    addCommand("start", makeCommandVoid0(*this, &Tracer::start, doc));
82
83

2
    doc = docCommandVoid0("Stop temporarily the tracing process.");
84

2
    addCommand("stop", makeCommandVoid0(*this, &Tracer::stop, doc));
85
86

2
    addCommand("getTimeStart",
87
2
               makeDirectGetter(*this, &timeStart,
88

4
                                docDirectGetter("timeStart", "int")));
89

2
    addCommand("setTimeStart",
90
2
               makeDirectSetter(*this, &timeStart,
91

4
                                docDirectSetter("timeStart", "int")));
92
  }  // using namespace command
93
2
}
94
95
/* --------------------------------------------------------------------- */
96
/* --------------------------------------------------------------------- */
97
/* --------------------------------------------------------------------- */
98
99
5
void Tracer::addSignalToTrace(const SignalBase<int> &sig,
100
                              const string &filename) {
101
  dgDEBUGIN(15);
102
  // openFile may throw so it should be called first.
103
5
  if (namesSet) openFile(sig, filename);
104
4
  toTraceSignals.push_back(&sig);
105
4
  dgDEBUGF(15, "%p", &sig);
106
4
  names.push_back(filename);
107
4
  triger.addDependency(sig);
108
  dgDEBUGOUT(15);
109
4
}
110
111
4
void Tracer::addSignalToTraceByName(const string &signame,
112
                                    const string &filename) {
113
  dgDEBUGIN(15);
114
8
  istringstream iss(signame);
115

4
  SignalBase<int> &sig = PoolStorage::getInstance()->getSignal(iss);
116
4
  addSignalToTrace(sig, filename);
117
  dgDEBUGOUT(15);
118
3
}
119
120
/*! Empty the list of signals to trace. This function
121
 * does not modify the file list (it does not close
122
 * the files in particular.
123
 */
124
2
void Tracer::clearSignalToTrace() {
125
2
  closeFiles();
126
2
  toTraceSignals.clear();
127
2
  triger.clearDependencies();
128
2
}
129
130
// void Tracer::
131
// parasite( SignalBase<int>& sig )
132
// {
133
//   triger.parasite(sig);
134
// }
135
136
3
void Tracer::openFiles(const std::string &rootdir_,
137
                       const std::string &basename_,
138
                       const std::string &suffix_) {
139
  dgDEBUGIN(15);
140
3
  std::basic_string<char>::size_type n = rootdir_.length();
141
3
  rootdir = rootdir_;
142

3
  if ((0 < n) & ('/' != rootdir[n - 1])) rootdir += '/';
143
144
3
  basename = basename_;
145
3
  suffix = suffix_;
146
147

3
  if (files.size()) closeFiles();
148
149
3
  SignalList::const_iterator iter = toTraceSignals.begin();
150
3
  NameList::const_iterator iterName = names.begin();
151
3
  while (toTraceSignals.end() != iter) {
152
    dgDEBUG(15) << "Open <" << (*iter)->getName() << "> in <" << *iterName
153
                << ">." << std::endl;
154
    openFile(**iter, *iterName);
155
    ++iter;
156
    ++iterName;
157
  }
158
159
3
  namesSet = true;
160
  dgDEBUGOUT(15);
161
3
}
162
163
3
void Tracer::openFile(const SignalBase<int> &sig, const string &givenname) {
164
  dgDEBUGIN(15);
165
6
  string signame;
166
3
  if (givenname.length()) {
167
3
    signame = givenname;
168
  } else {
169
    signame = sig.shortName();
170
  }
171
172

9
  string filename = rootdir + basename + signame + suffix;
173
174
  dgDEBUG(5) << "Sig <" << sig.getName() << ">: new file " << filename << endl;
175

3
  std::ofstream *newfile = new std::ofstream(filename.c_str());
176
3
  files.push_back(newfile);
177
  dgDEBUGOUT(15);
178
3
}
179
180
2
void Tracer::closeFiles() {
181
  dgDEBUGIN(15);
182
4
  std::lock_guard<std::mutex> files_lock(files_mtx);
183
184
5
  for (FileList::iterator iter = files.begin(); files.end() != iter; ++iter) {
185
3
    std::ostream *filePtr = *iter;
186
3
    delete filePtr;
187
  }
188
2
  files.clear();
189
190
  dgDEBUGOUT(15);
191
2
}
192
193
/* --------------------------------------------------------------------- */
194
/* --------------------------------------------------------------------- */
195
/* --------------------------------------------------------------------- */
196
197
2002
void Tracer::record() {
198
2002
  if (!play) {
199
    dgDEBUGINOUT(15);
200
2
    return;
201
  }
202
203
  dgDEBUGIN(15);
204
205
  // Ensure record() never hangs. If the attempt to acquire the lock fails,
206
  // then closeFiles() is active and we shouldn't write to files anyways.
207
2000
  std::unique_lock<std::mutex> files_lock(files_mtx, std::try_to_lock);
208
2000
  if (!files_lock.owns_lock()) {
209
    dgDEBUGOUT(15);
210
    return;
211
  }
212
213
2000
  if (files.size() != toTraceSignals.size()) {
214
    DG_THROW
215
    ExceptionTraces(ExceptionTraces::NOT_OPEN, "No files open for tracing",
216
                    " (file=%d != %d=sig).", files.size(),
217
                    toTraceSignals.size());
218
  }
219
220
2000
  FileList::iterator iterFile = files.begin();
221
2000
  SignalList::iterator iterSig = toTraceSignals.begin();
222
223
6000
  while (toTraceSignals.end() != iterSig) {
224
    dgDEBUG(45) << "Try..." << endl;
225
4000
    recordSignal(**iterFile, **iterSig);
226
4000
    ++iterSig;
227
4000
    ++iterFile;
228
  }
229
  dgDEBUGOUT(15);
230
}
231
232
4000
void Tracer::recordSignal(std::ostream &os, const SignalBase<int> &sig) {
233
  dgDEBUGIN(15);
234
235
  try {
236

4000
    if (sig.getTime() > timeStart) {
237

2997
      os << sig.getTime() << "\t";
238
2997
      sig.trace(os);
239
2997
      os << endl;
240
    }
241
  } catch (ExceptionAbstract &exc) {
242
    os << exc << std::endl;
243
  } catch (...) {
244
    os << "Unknown error occurred while reading signal." << std::endl;
245
  }
246
247
  dgDEBUGOUT(15);
248
4000
}
249
250
2000
int &Tracer::recordTrigger(int &dummy, const int &time) {
251
  dgDEBUGIN(15) << "    time=" << time << endl;
252
2000
  record();
253
  dgDEBUGOUT(15);
254
2000
  return dummy;
255
}
256
257
void Tracer::trace() {}
258
259
/* --------------------------------------------------------------------- */
260
/* --------------------------------------------------------------------- */
261
/* --------------------------------------------------------------------- */
262
263
void Tracer::display(std::ostream &os) const {
264
  os << CLASS_NAME << " " << name << " [mode=" << (play ? "play" : "pause")
265
     << "] : " << endl
266
     << "  - Dep list: " << endl;
267
  for (SignalList::const_iterator iter = toTraceSignals.begin();
268
       toTraceSignals.end() != iter; ++iter) {
269
    os << "     -> " << (*iter)->getName() << endl;
270
  }
271
}
272
273
std::ostream &operator<<(std::ostream &os, const Tracer &t) {
274
  t.display(os);
275
  return os;
276
}