ControlThreadOutputBuffer.h
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * ArmarX is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * ArmarX is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * @package RobotAPI::RobotUnit
17  * @author Raphael Grimm ( raphael dot grimm at kit dot edu )
18  * @date 2017
19  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20  * GNU General Public License
21  */
22 
23 #pragma once
24 
25 #include <vector>
26 
27 #include <ArmarXCore/core/logging/LoggingUtil.h> // THIS NEEDS TO BE INCLUDED BEFORE EXPRESSION EXCEPTION
32 
33 #include "../ControlTargets/ControlTargetBase.h"
34 #include "../Devices/ControlDevice.h"
35 #include "../Devices/SensorDevice.h"
36 #include "../SensorValues/SensorValueBase.h"
38 #include "RtTiming.h"
39 
40 namespace armarx
41 {
42  class RobotUnit;
43  struct ControlThreadOutputBuffer;
44 } // namespace armarx
45 
47 {
48  class Logging;
49 }
50 
51 namespace armarx::detail
52 {
54  {
56  {
57  }
58 
59  virtual ~RtMessageLogEntryBase() = default;
60 
63  RtMessageLogEntryBase& deactivateSpamTag(std::uint64_t tag);
64 
65  void print(Ice::Int controlThreadId) const;
66  virtual std::size_t line() const = 0;
67  virtual std::string file() const = 0;
68  virtual std::string func() const = 0;
69  virtual std::string format() const = 0;
70  IceUtil::Time getTime() const;
71 
73  protected:
74  friend struct RtMessageLogBuffer;
75 
76  private:
78  float deactivateSpamSec{0};
79  bool printMsg{false};
80  std::uint64_t deactivateSpamTag_;
81  IceUtil::Time time;
82  };
83 
85  {
87 
88  protected:
89  std::string format() const final override;
90  std::size_t line() const final override;
91  std::string file() const final override;
92  std::string func() const final override;
93 
95  };
96 
98  {
100 
101  protected:
102  std::string
103  format() const final override
104  {
105  return "";
106  }
107 
108  std::size_t
109  line() const final override
110  {
111  return 0;
112  }
113 
114  std::string
115  file() const final override
116  {
117  return "";
118  }
119 
120  std::string
121  func() const final override
122  {
123  return "";
124  }
125 
127  };
128 
130  {
131  RtMessageLogBuffer(const RtMessageLogBuffer& other, bool minimize = false);
132  RtMessageLogBuffer(std::size_t bufferSize,
133  std::size_t numEntries,
134  std::size_t bufferMaxSize,
135  std::size_t bufferMaxNumberEntries);
137 
138  RtMessageLogBuffer() = delete;
140  RtMessageLogBuffer& operator=(RtMessageLogBuffer&&) = delete;
141  RtMessageLogBuffer& operator=(const RtMessageLogBuffer&) = delete;
142 
143  void reset(std::size_t& bufferSize, std::size_t& numEntries, std::size_t iterationCount);
144 
145  const std::vector<const RtMessageLogEntryBase*>& getEntries() const;
146 
147  std::size_t getMaximalBufferSize() const;
148  std::size_t getMaximalNumberOfBufferEntries() const;
149 
150  private:
151  void deleteAll();
152 
154  friend struct ::armarx::ControlThreadOutputBuffer;
155  friend class ::armarx::RobotUnit;
156  friend class ::armarx::RobotUnitModule::Logging;
157 
158  const std::size_t initialBufferSize;
159  const std::size_t initialBufferEntryNumbers;
160  const std::size_t bufferMaxSize;
161  const std::size_t bufferMaxNumberEntries;
162 
163  std::vector<std::uint8_t> buffer;
164  std::size_t bufferSpace;
165  void* bufferPlace;
166 
167  std::vector<const RtMessageLogEntryBase*> entries;
168  std::size_t entriesWritten{0};
169 
170  std::size_t requiredAdditionalBufferSpace{0};
171  std::size_t requiredAdditionalEntries{0};
172  std::size_t messagesLost{0};
173 
174  std::size_t maxAlign{1};
175  };
176 
178  {
179  //default ctors / ops
180 
182  const KeyValueVector<std::string, ControlDevicePtr>& controlDevices,
184  std::size_t messageBufferSize,
185  std::size_t messageBufferNumberEntries,
186  std::size_t messageBufferMaxSize,
187  std::size_t messageBufferMaxNumberEntries);
189  bool minimize = false);
190 
195 
196  std::size_t getDataBufferSize() const;
197 
198  //data
199  /// @brief Timestamp in wall time (never use the virtual time for this)
203  std::vector<PropagateConst<SensorValueBase*>> sensors;
204  std::vector<std::vector<PropagateConst<ControlTargetBase*>>> control;
205  std::size_t iteration{0};
206 
208 
209  private:
210  std::vector<std::uint8_t> buffer;
211  };
212 } // namespace armarx::detail
213 
214 namespace armarx
215 {
217  {
220  using ConsumerFunctor = std::function<void(const Entry&, std::size_t, std::size_t)>;
221  std::size_t initialize(std::size_t numEntries,
222  const KeyValueVector<std::string, ControlDevicePtr>& controlDevices,
224  std::size_t messageBufferSize,
225  std::size_t messageBufferNumberEntries,
226  std::size_t messageBufferMaxSize,
227  std::size_t messageBufferMaxNumberEntries);
228 
230 
233  {
234  return RtLoggingInstance;
235  }
236 
237  //write
238  Entry& getWriteBuffer();
239  void commitWrite();
240 
241  //read
242  const Entry& getReadBuffer() const;
243  bool updateReadBuffer() const;
244 
245  //logging read
246  void resetLoggingPosition() const;
247  void forEachNewLoggingEntry(ConsumerFunctor consumer);
248  void forLatestLoggingEntry(ConsumerFunctor consumer, size_t numberOfEntriesToLog);
249 
250  std::size_t getNumberOfBytes() const;
251 
252  template <class LoggingEntryT, class... Ts>
253  RtMessageLogEntryBase* addMessageToLog(Ts&&... args);
254 
255  private:
256  friend class RobotUnitModule::Logging; ///TODO change code to make this unnecessary
257  /// @brief this pointer is used for rt message logging and is not null in the control thread
258  static thread_local ControlThreadOutputBuffer* RtLoggingInstance;
259 
260  std::size_t toBounds(std::size_t idx) const;
261 
262  //settings and initialization:
263  bool isInitialized{false};
264  std::size_t numEntries{0};
265 
266  std::atomic_size_t writePosition{0};
267  mutable std::atomic_size_t onePastLoggingReadPosition{0};
268  mutable std::atomic_size_t onePastReadPosition{0};
269 
270  std::vector<Entry> entries;
271  std::vector<std::uint8_t> data;
272 
273  std::size_t messageBufferSize{0};
274  std::size_t messageBufferEntries{0};
275  };
276 
278 } // namespace armarx
279 
280 #define ARMARX_RT_LOGF(...) \
281  (*(_detail_ARMARX_RT_LOGF(__FILE__, ARMARX_FUNCTION, __LINE__, __VA_ARGS__, true)))
282 
283 #define _detail_ARMARX_RT_LOGF(file_, func_, line_, FormatString, ...) \
284  ( \
285  [&] \
286  { \
287  using namespace ::armarx; \
288  using RtMessageLogEntryBase = ControlThreadOutputBuffer::RtMessageLogEntryBase; \
289  struct RtMessageLogEntry : RtMessageLogEntryBase \
290  { \
291  using TupleT = decltype(std::make_tuple(__VA_ARGS__)); \
292  const TupleT tuple; \
293  ARMARX_MINIMAL_PLACEMENT_CONSTRUCTION_HELPER \
294  std::size_t \
295  line() const final override \
296  { \
297  return line_; \
298  } \
299  std::string \
300  file() const final override \
301  { \
302  return file_; \
303  } \
304  std::string \
305  func() const final override \
306  { \
307  return func_; \
308  } \
309  std::string \
310  format() const final override \
311  { \
312  return TupleToStringF<0, std::tuple_size<TupleT>::value - 1>(FormatString, \
313  tuple); \
314  } \
315  RtMessageLogEntry(TupleT tuple) : tuple{std::move(tuple)} \
316  { \
317  } \
318  RtMessageLogEntry(const RtMessageLogEntry&) = default; \
319  }; \
320  if (::armarx::ControlThreadOutputBuffer::GetRtLoggingInstance()) \
321  { \
322  return ::armarx::ControlThreadOutputBuffer::GetRtLoggingInstance() \
323  ->addMessageToLog<RtMessageLogEntry>(__VA_ARGS__); \
324  } \
325  else \
326  { \
327  *(loghelper(file_, line_, func_)) \
328  << "Redirected RT Logging:\n" \
329  << RtMessageLogEntry(std::make_tuple(__VA_ARGS__)).format(); \
330  return dynamic_cast<RtMessageLogEntryBase*>( \
331  &::armarx::detail::RtMessageLogEntryNull::Instance); \
332  } \
333  }())
334 
335 #define ARMARX_RT_LOGF_DEBUG(...) \
336  ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::DEBUG)
337 #define ARMARX_RT_LOGF_VERBOSE(...) \
338  ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::VERBOSE)
339 #define ARMARX_RT_LOGF_INFO(...) \
340  ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::INFO)
341 #define ARMARX_RT_LOGF_IMPORTANT(...) \
342  ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::IMPORTANT)
343 #define ARMARX_RT_LOGF_WARNING(...) \
344  ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::WARN)
345 #define ARMARX_RT_LOGF_WARN(...) \
346  ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::WARN)
347 #define ARMARX_RT_LOGF_ERROR(...) \
348  ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::ERROR)
349 #define ARMARX_RT_LOGF_FATAL(...) \
350  ARMARX_RT_LOGF(__VA_ARGS__).setLoggingLevel(::armarx::MessageTypeT::FATAL)
351 
352 //impl
353 namespace armarx::detail
354 {
355  inline IceUtil::Time
357  {
358  return time;
359  }
360 
361  inline std::string
363  {
364  throw std::logic_error{"called 'format' of RtMessageLogEntryDummy"};
365  }
366 
367  inline std::size_t
369  {
370  throw std::logic_error{"called 'line' of RtMessageLogEntryDummy"};
371  }
372 
373  inline std::string
375  {
376  throw std::logic_error{"called 'file' of RtMessageLogEntryDummy"};
377  }
378 
379  inline std::string
381  {
382  throw std::logic_error{"called 'func' of RtMessageLogEntryDummy"};
383  }
384 
385  inline RtMessageLogBuffer::RtMessageLogBuffer(std::size_t bufferSize,
386  std::size_t numEntries,
387  std::size_t bufferMaxSize,
388  std::size_t bufferMaxNumberEntries) :
389  initialBufferSize{bufferSize},
390  initialBufferEntryNumbers{numEntries},
391  bufferMaxSize{bufferMaxSize},
392  bufferMaxNumberEntries{bufferMaxNumberEntries},
393  buffer(bufferSize, 0),
394  bufferSpace{buffer.size()},
395  bufferPlace{buffer.data()},
396  entries(numEntries, nullptr)
397  {
398  ARMARX_DEBUG << "RtMessageLogBuffer created with bufferSize=" << bufferSize
399  << " and numEntries=" << numEntries << " and bufferMaxSize=" << bufferMaxSize
400  << " and bufferMaxNumberEntries " << bufferMaxNumberEntries;
401  }
402 
404  {
405  deleteAll();
406  }
407 
408  inline const std::vector<const RtMessageLogEntryBase*>&
410  {
411  return entries;
412  }
413 
414  inline std::size_t
416  {
417  return bufferMaxSize;
418  }
419 
420  inline std::size_t
422  {
423  return bufferMaxNumberEntries;
424  }
425 
426  inline std::size_t
428  {
429  return buffer.size();
430  }
431 } // namespace armarx::detail
432 
433 namespace armarx
434 {
435  inline std::size_t
436  ControlThreadOutputBuffer::toBounds(std::size_t idx) const
437  {
438  return idx % numEntries;
439  }
440 
441  inline std::size_t
443  {
444  return data.size();
445  }
446 
447  template <class LoggingEntryT, class... Ts>
450  {
452  if (messages.entries.size() <= messages.entriesWritten)
453  {
454  ++messages.requiredAdditionalEntries;
455  ++messages.messagesLost;
457  }
458  messages.maxAlign = std::max(messages.maxAlign, alignof(LoggingEntryT));
459  void* place = std::align(alignof(LoggingEntryT),
460  sizeof(LoggingEntryT),
461  messages.bufferPlace,
462  messages.bufferSpace);
463  if (!place)
464  {
465  messages.requiredAdditionalBufferSpace +=
466  sizeof(LoggingEntryT) + alignof(LoggingEntryT) - 1;
467  ++messages.messagesLost;
469  }
470  RtMessageLogEntryBase* entry =
471  new (place) LoggingEntryT(std::make_tuple(std::forward<Ts>(args)...));
472  ARMARX_CHECK_NOT_NULL(entry);
473  messages.bufferPlace = static_cast<std::uint8_t*>(place) + sizeof(LoggingEntryT);
474 
475  messages.bufferSpace -= sizeof(LoggingEntryT);
476 
477  ARMARX_CHECK_IS_NULL(messages.entries.at(messages.entriesWritten));
478  messages.entries.at(messages.entriesWritten++) = entry;
479  return entry;
480  }
481 } // namespace armarx
armarx::detail::RtMessageLogBuffer::getMaximalBufferSize
std::size_t getMaximalBufferSize() const
Definition: ControlThreadOutputBuffer.h:415
armarx::detail::RtMessageLogEntryDummy::func
std::string func() const final override
Definition: ControlThreadOutputBuffer.h:380
armarx::MessageTypeT
MessageTypeT
Definition: LogSender.h:45
armarx::detail::RtMessageLogBuffer::~RtMessageLogBuffer
~RtMessageLogBuffer()
Definition: ControlThreadOutputBuffer.h:403
armarx::detail::RtMessageLogEntryBase::format
virtual std::string format() const =0
armarx::detail::RtMessageLogEntryBase::RtMessageLogBuffer
friend struct RtMessageLogBuffer
Definition: ControlThreadOutputBuffer.h:74
armarx::detail::RtMessageLogEntryDummy::line
std::size_t line() const final override
Definition: ControlThreadOutputBuffer.h:368
armarx::MessageTypeT::UNDEFINED
@ UNDEFINED
armarx::ControlThreadOutputBuffer::GetRtLoggingInstance
static ControlThreadOutputBuffer * GetRtLoggingInstance()
Definition: ControlThreadOutputBuffer.h:232
RtTiming.h
armarx::detail::RtMessageLogEntryNull::format
std::string format() const final override
Definition: ControlThreadOutputBuffer.h:103
armarx::detail::ControlThreadOutputBufferEntry::getDataBufferSize
std::size_t getDataBufferSize() const
Definition: ControlThreadOutputBuffer.h:427
armarx::detail::RtMessageLogEntryDummy::format
std::string format() const final override
Definition: ControlThreadOutputBuffer.h:362
armarx::detail::ControlThreadOutputBufferEntry::messages
RtMessageLogBuffer messages
Definition: ControlThreadOutputBuffer.h:207
ARMARX_CHECK_NOT_NULL
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
Definition: ExpressionException.h:206
ARMARX_MINIMAL_PLACEMENT_CONSTRUCTION_HELPER
#define ARMARX_MINIMAL_PLACEMENT_CONSTRUCTION_HELPER
Definition: HeterogenousContinuousContainerMacros.h:44
armarx::detail::ControlThreadOutputBufferEntry::sensors
std::vector< PropagateConst< SensorValueBase * > > sensors
Definition: ControlThreadOutputBuffer.h:203
armarx::detail::RtMessageLogEntryBase
Definition: ControlThreadOutputBuffer.h:53
HeterogenousContinuousContainer.h
ARMARX_MINIMAL_PLACEMENT_CONSTRUCTION_HELPER_BASE
#define ARMARX_MINIMAL_PLACEMENT_CONSTRUCTION_HELPER_BASE(CommonBaseType)
Definition: HeterogenousContinuousContainerMacros.h:28
armarx::detail::RtMessageLogEntryDummy
Definition: ControlThreadOutputBuffer.h:84
armarx::detail::RtMessageLogEntryDummy::Instance
static RtMessageLogEntryDummy Instance
Definition: ControlThreadOutputBuffer.h:86
armarx::detail::RtMessageLogEntryBase::deactivateSpam
RtMessageLogEntryBase & deactivateSpam(float sec)
Definition: ControlThreadOutputBuffer.cpp:247
armarx::detail::RtMessageLogEntryBase::deactivateSpamTag
RtMessageLogEntryBase & deactivateSpamTag(std::uint64_t tag)
Definition: ControlThreadOutputBuffer.cpp:255
armarx::detail::ControlThreadOutputBufferEntry::writeTimestamp
IceUtil::Time writeTimestamp
Timestamp in wall time (never use the virtual time for this)
Definition: ControlThreadOutputBuffer.h:200
armarx::SensorAndControl
detail::ControlThreadOutputBufferEntry SensorAndControl
Definition: NJointControllerBase.h:72
armarx::RobotUnitModule::Logging
This Module manages logging of data.
Definition: RobotUnitModuleLogging.h:120
armarx::detail::RtMessageLogBuffer
Definition: ControlThreadOutputBuffer.h:129
armarx::ControlThreadOutputBuffer
Definition: ControlThreadOutputBuffer.h:216
std::align
void * align(size_t alignment, size_t bytes, void *&bufferPlace, size_t &bufferSpace) noexcept
Definition: HeterogenousContinuousContainer.h:37
armarx::detail::RtMessageLogEntryNull
Definition: ControlThreadOutputBuffer.h:97
armarx::detail::ControlThreadOutputBufferEntry
Definition: ControlThreadOutputBuffer.h:177
ARMARX_CHECK_IS_NULL
#define ARMARX_CHECK_IS_NULL(ptr)
This macro evaluates whether ptr is null and if it turns out to be false it will throw an ExpressionE...
Definition: ExpressionException.h:194
armarx::detail::RtMessageLogBuffer::getEntries
const std::vector< const RtMessageLogEntryBase * > & getEntries() const
Definition: ControlThreadOutputBuffer.h:409
armarx::ControlThreadOutputBuffer::Entry
detail::ControlThreadOutputBufferEntry Entry
Definition: ControlThreadOutputBuffer.h:218
data
uint8_t data[1]
Definition: EtherCATFrame.h:68
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:177
armarx::detail::RtMessageLogBuffer::RtMessageLogBuffer
RtMessageLogBuffer()=delete
armarx::detail::RtMessageLogEntryNull::Instance
static RtMessageLogEntryNull Instance
Definition: ControlThreadOutputBuffer.h:99
armarx::ControlThreadOutputBuffer::ConsumerFunctor
std::function< void(const Entry &, std::size_t, std::size_t)> ConsumerFunctor
Definition: ControlThreadOutputBuffer.h:220
armarx::detail::RtMessageLogBuffer::getMaximalNumberOfBufferEntries
std::size_t getMaximalNumberOfBufferEntries() const
Definition: ControlThreadOutputBuffer.h:421
max
T max(T t1, T t2)
Definition: gdiam.h:48
armarx::detail
Definition: ApplicationNetworkStats.cpp:34
armarx::detail::RtMessageLogEntryBase::file
virtual std::string file() const =0
armarx::detail::RtMessageLogEntryDummy::file
std::string file() const final override
Definition: ControlThreadOutputBuffer.h:374
armarx::ControlThreadOutputBuffer::addMessageToLog
RtMessageLogEntryBase * addMessageToLog(Ts &&... args)
Definition: ControlThreadOutputBuffer.h:449
TripleBuffer.h
armarx::armem::Time
armarx::core::time::DateTime Time
Definition: forward_declarations.h:13
LoggingUtil.h
armarx::KeyValueVector< std::string, ControlDevicePtr >
ExpressionException.h
armarx::detail::RtMessageLogEntryBase::print
void print(Ice::Int controlThreadId) const
Definition: ControlThreadOutputBuffer.cpp:263
armarx::ControlThreadOutputBuffer::getWriteBuffer
Entry & getWriteBuffer()
Definition: ControlThreadOutputBuffer.cpp:34
armarx::detail::ControlThreadOutputBufferEntry::sensorValuesTimestamp
IceUtil::Time sensorValuesTimestamp
Definition: ControlThreadOutputBuffer.h:201
armarx::detail::RtMessageLogEntryNull::line
std::size_t line() const final override
Definition: ControlThreadOutputBuffer.h:109
armarx::detail::RtMessageLogEntryBase::~RtMessageLogEntryBase
virtual ~RtMessageLogEntryBase()=default
std
Definition: Application.h:66
armarx::detail::RtMessageLogEntryNull::file
std::string file() const final override
Definition: ControlThreadOutputBuffer.h:115
armarx::detail::RtMessageLogEntryBase::setLoggingLevel
RtMessageLogEntryBase & setLoggingLevel(MessageTypeT lvl)
Definition: ControlThreadOutputBuffer.cpp:239
armarx::detail::RtMessageLogEntryBase::func
virtual std::string func() const =0
armarx::detail::RtMessageLogEntryBase::getTime
IceUtil::Time getTime() const
Definition: ControlThreadOutputBuffer.h:356
armarx::VariantType::Int
const VariantTypeId Int
Definition: Variant.h:916
StringHelperTemplates.h
armarx::detail::RtMessageLogEntryBase::RtMessageLogEntryBase
RtMessageLogEntryBase()
Definition: ControlThreadOutputBuffer.h:55
armarx::detail::ControlThreadOutputBufferEntry::control
std::vector< std::vector< PropagateConst< ControlTargetBase * > > > control
Definition: ControlThreadOutputBuffer.h:204
armarx::RobotUnitModule
Definition: ControlDevice.h:34
armarx::detail::RtMessageLogEntryNull::func
std::string func() const final override
Definition: ControlThreadOutputBuffer.h:121
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
armarx::detail::ControlThreadOutputBufferEntry::timeSinceLastIteration
IceUtil::Time timeSinceLastIteration
Definition: ControlThreadOutputBuffer.h:202
armarx::ControlThreadOutputBuffer::getNumberOfBytes
std::size_t getNumberOfBytes() const
Definition: ControlThreadOutputBuffer.h:442
armarx::detail::RtMessageLogEntryBase::line
virtual std::size_t line() const =0
PropagateConst.h
armarx::rtNow
IceUtil::Time rtNow()
Definition: RtTiming.h:40