[Fawkes Git] branch/thofmann/syncpoint: syncpoint: move dot graph generation to webview plugin

Till Hofmann hofmann at kbsg.rwth-aachen.de
Wed May 25 11:36:16 CEST 2016


Changes have been pushed for the project "Fawkes Robotics Software Framework".

Gitweb: http://git.fawkesrobotics.org/fawkes.git
Trac:   http://trac.fawkesrobotics.org

The branch, thofmann/syncpoint has been updated
        to  b4872b73cbabc8e44879d4a01bff3ebdd96511d5 (commit)
      from  dd21195687d5e6f6d12cbd388b7ea04ce73b23b4 (commit)

http://git.fawkesrobotics.org/fawkes.git/thofmann/syncpoint

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- *Log* ---------------------------------------------------------------
commit b4872b73cbabc8e44879d4a01bff3ebdd96511d5
Author:     Till Hofmann <hofmann at kbsg.rwth-aachen.de>
AuthorDate: Wed May 25 11:32:22 2016 +0200
Commit:     Till Hofmann <hofmann at kbsg.rwth-aachen.de>
CommitDate: Wed May 25 11:32:22 2016 +0200

    syncpoint: move dot graph generation to webview plugin
    
    Until now, the SyncPoingManager generated the (textual) dot graph for
    the syncpoint visualization. However, this lead to the cyclic dependency
    syncpoint -> aspect -> syncpoint. This is because the blocked timing
    aspect uses syncpoints, and for visualization, we need to get all
    blocked timing hooks. Furthermore, the generation of the dot graph is
    not the SyncPointManager's task anyway. Thus, move the dot graph
    generation to the webview plugin where it is used.
    
    The disadvantage of this is that we cannot generate dotgraphs outside of
    the webview plugin anymore. If this is necessary, the functionality
    should be moved to a separate lib/plugin.

http://git.fawkesrobotics.org/fawkes.git/commit/b4872b7
http://trac.fawkesrobotics.org/changeset/b4872b7

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


- *Summary* -----------------------------------------------------------
 src/libs/syncpoint/Makefile                 |    2 +-
 src/libs/syncpoint/syncpoint.cpp            |   19 ++++
 src/libs/syncpoint/syncpoint.h              |    1 +
 src/libs/syncpoint/syncpoint_manager.cpp    |  146 -------------------------
 src/libs/syncpoint/syncpoint_manager.h      |    3 -
 src/plugins/webview/syncpoint_processor.cpp |  152 ++++++++++++++++++++++++++-
 src/plugins/webview/syncpoint_processor.h   |    7 ++
 7 files changed, 179 insertions(+), 151 deletions(-)


- *Diffs* -------------------------------------------------------------

- *commit* b4872b73cbabc8e44879d4a01bff3ebdd96511d5 - - - - - - - - - -
Author:  Till Hofmann <hofmann at kbsg.rwth-aachen.de>
Date:    Wed May 25 11:32:22 2016 +0200
Subject: syncpoint: move dot graph generation to webview plugin

 src/libs/syncpoint/Makefile                 |    2 +-
 src/libs/syncpoint/syncpoint.cpp            |   19 ++++
 src/libs/syncpoint/syncpoint.h              |    1 +
 src/libs/syncpoint/syncpoint_manager.cpp    |  146 -------------------------
 src/libs/syncpoint/syncpoint_manager.h      |    3 -
 src/plugins/webview/syncpoint_processor.cpp |  152 ++++++++++++++++++++++++++-
 src/plugins/webview/syncpoint_processor.h   |    7 ++
 7 files changed, 179 insertions(+), 151 deletions(-)

_Diff for modified files_:
diff --git a/src/libs/syncpoint/Makefile b/src/libs/syncpoint/Makefile
index 0a3e911..154a448 100644
--- a/src/libs/syncpoint/Makefile
+++ b/src/libs/syncpoint/Makefile
@@ -17,7 +17,7 @@ BASEDIR = ../../..
 include $(BASEDIR)/etc/buildsys/config.mk
 
 
-LIBS_libfawkessyncpoint = fawkescore fawkesutils fawkesaspects
+LIBS_libfawkessyncpoint = fawkescore fawkesutils
 OBJS_libfawkessyncpoint = $(patsubst %.cpp,%.o,$(patsubst qa/%,,$(subst $(SRCDIR)/,,$(realpath $(wildcard $(SRCDIR)/*.cpp)))))
 HDRS_libfawkessyncpoint = $(subst $(SRCDIR)/,,$(wildcard $(SRCDIR)/*.h))
 
diff --git a/src/libs/syncpoint/syncpoint.cpp b/src/libs/syncpoint/syncpoint.cpp
index f3d5d76..0ccdbad 100644
--- a/src/libs/syncpoint/syncpoint.cpp
+++ b/src/libs/syncpoint/syncpoint.cpp
@@ -483,6 +483,25 @@ SyncPoint::get_emit_calls() const {
   return emit_calls_;
 }
 
+/**
+ * Check if the given waiter is currently waiting with the given type
+ * @param watcher the string identifier of the watcher to check
+ * @param type the type of call to check
+ */
+bool
+SyncPoint::watcher_is_waiting(std::string watcher, WakeupType type) const
+{
+  switch (type) {
+    case SyncPoint::WAIT_FOR_ONE:
+      return watchers_wait_for_one_.count(watcher);
+    case SyncPoint::WAIT_FOR_ALL:
+      return watchers_wait_for_all_.count(watcher);
+    default:
+      throw Exception("Unknown watch type %u for syncpoint %s",
+                      type, identifier_);
+  }
+}
+
 void
 SyncPoint::reset_emitters() {
   last_emitter_reset_ = Time();
diff --git a/src/libs/syncpoint/syncpoint.h b/src/libs/syncpoint/syncpoint.h
index 4a1e641..a1eba54 100644
--- a/src/libs/syncpoint/syncpoint.h
+++ b/src/libs/syncpoint/syncpoint.h
@@ -99,6 +99,7 @@ class SyncPoint
     std::multiset<std::string> get_emitters() const;
     CircularBuffer<SyncPointCall> get_wait_calls(WakeupType type = WAIT_FOR_ONE) const;
     CircularBuffer<SyncPointCall> get_emit_calls() const;
+    bool watcher_is_waiting(std::string watcher, WakeupType type) const;
 
 
     /**
diff --git a/src/libs/syncpoint/syncpoint_manager.cpp b/src/libs/syncpoint/syncpoint_manager.cpp
index faa6d61..10f7171 100644
--- a/src/libs/syncpoint/syncpoint_manager.cpp
+++ b/src/libs/syncpoint/syncpoint_manager.cpp
@@ -21,15 +21,12 @@
 
 #include <core/threading/mutex_locker.h>
 
-#include <aspect/blocked_timing.h>
-
 #include <syncpoint/syncpoint_manager.h>
 #include <syncpoint/exceptions.h>
 
 #include "syncpoint_call_stats.h"
 
 #include <string>
-#include <sstream>
 
 namespace fawkes {
 #if 0 /* just to make Emacs auto-indent happy */
@@ -122,149 +119,6 @@ SyncPointManager::get_syncpoints() {
   return syncpoints_;
 }
 
-/**
- * Get DOT graph for all SyncPoints
- * @param max_age Show only SyncPoint calls which are younger than max_age
- * @return string representation of DOT graph
- */
-std::string
-SyncPointManager::all_syncpoints_as_dot(float max_age)
-{
-  std::stringstream graph;
-  graph << std::fixed; //fixed point notation
-  graph.precision(3); //3 decimal places
-  graph << "digraph { graph [fontsize=14]; "
-      << "node [fontsize=12]; edge [fontsize=12]; ";
-  graph.setf(std::ios::fixed, std::ios::floatfield);
-
-  MutexLocker ml(mutex_);
-  for (std::set<RefPtr<SyncPoint>, SyncPointSetLessThan>::const_iterator sp_it = syncpoints_.begin();
-      sp_it != syncpoints_.end(); sp_it++) {
-    graph << "\"" << (*sp_it)->get_identifier() << "\""
-        << " [shape=box];";
-  }
-
-  for (std::set<RefPtr<SyncPoint>, SyncPointSetLessThan>::const_iterator sp_it = syncpoints_.begin();
-      sp_it != syncpoints_.end(); sp_it++) {
-    graph << "\"" << (*sp_it)->get_identifier() << "\";";
-
-    // EMIT CALLS
-    CircularBuffer<SyncPointCall> emit_calls = (*sp_it)->get_emit_calls();
-    // generate call stats
-    std::map<std::string, SyncPointCallStats> emit_call_stats;
-    for (CircularBuffer<SyncPointCall>::iterator emitcalls_it = emit_calls.begin();
-        emitcalls_it != emit_calls.end(); emitcalls_it++) {
-      // Remove the main thread from the graph, and also remove any emit calls
-      // to the SyncPoint "/" to improve the resulting graph.
-      // The main thread emits and waits for every hook, which adds a lot of
-      // uninteresting edges to the graph.
-      // Similarly, all emitters also emit "/", which is not interesting to see.
-      if (emitcalls_it->get_caller() == "FawkesMainThread" ||
-          (*sp_it)->get_identifier() == "/") {
-        continue;
-      }
-      emit_call_stats[emitcalls_it->get_caller()].update_calls(emitcalls_it->get_call_time());
-    }
-
-    for (std::map<std::string, SyncPointCallStats>::iterator emit_call_stats_it = emit_call_stats.begin();
-        emit_call_stats_it != emit_call_stats.end(); emit_call_stats_it++) {
-      float age = (Time() - emit_call_stats_it->second.get_last_call()).in_sec();
-      if (age < max_age) {
-      graph << "\"" << emit_call_stats_it->first << "\" -> \""
-          <<  (*sp_it)->get_identifier()
-          << "\"" << " [label=\""
-          << " freq=" << emit_call_stats_it->second.get_call_frequency() << "Hz"
-          << " age=" << age << "s"
-          << " #calls=" << emit_call_stats_it->second.get_num_calls()
-          << "\"" << "];";
-      }
-    }
-
-    // WAIT FOR ONE CALLS
-    CircularBuffer<SyncPointCall> wait_one_calls = (*sp_it)->get_wait_calls(SyncPoint::WAIT_FOR_ONE);
-    // generate call stats
-    std::map<std::string, SyncPointCallStats> wait_one_call_stats;
-    for (CircularBuffer<SyncPointCall>::iterator waitcalls_it = wait_one_calls.begin();
-        waitcalls_it != wait_one_calls.end(); waitcalls_it++) {
-      wait_one_call_stats[waitcalls_it->get_caller()].update_calls(*waitcalls_it);
-    }
-
-    for (std::map<std::string, SyncPointCallStats>::iterator wait_call_stats_it = wait_one_call_stats.begin();
-        wait_call_stats_it != wait_one_call_stats.end(); wait_call_stats_it++) {
-      if (wait_call_stats_it->first == "FawkesMainThread") {
-        continue;
-      }
-      float age = (Time() - wait_call_stats_it->second.get_last_call()).in_sec();
-      if (age < max_age) {
-        graph << "\"" << (*sp_it)->get_identifier() << "\"" << " -> "
-            << "\"" << wait_call_stats_it->first << "\"" << " [label=" << "\""
-            << " avg=" << wait_call_stats_it->second.get_waittime_average() <<  "s"
-            << " age=" << age << "s"
-            << " #calls=" << wait_call_stats_it->second.get_num_calls()
-            //          << " max=" << max_wait_time << "s"
-            << "\"";
-        if ((*sp_it)->watchers_wait_for_one_.count(wait_call_stats_it->first)) {
-          graph << ",color=\"red\"";
-        }
-        graph << ",style=dotted";
-        graph << "];";
-      }
-    }
-
-    // WAIT FOR ALL CALLS
-    CircularBuffer<SyncPointCall> wait_all_calls = (*sp_it)->get_wait_calls(SyncPoint::WAIT_FOR_ALL);
-    // generate call stats
-    std::map<std::string, SyncPointCallStats> wait_all_call_stats;
-    for (CircularBuffer<SyncPointCall>::iterator waitcalls_it = wait_all_calls.begin();
-        waitcalls_it != wait_all_calls.end(); waitcalls_it++) {
-      wait_all_call_stats[waitcalls_it->get_caller()].update_calls(*waitcalls_it);
-    }
-
-    for (std::map<std::string, SyncPointCallStats>::iterator wait_call_stats_it = wait_all_call_stats.begin();
-        wait_call_stats_it != wait_all_call_stats.end(); wait_call_stats_it++) {
-      if (wait_call_stats_it->first == "FawkesMainThread") {
-        continue;
-      }
-      float age = (Time() - wait_call_stats_it->second.get_last_call()).in_sec();
-      if (age < max_age) {
-        graph << "\"" << (*sp_it)->get_identifier() << "\"" << " -> "
-            << "\"" << wait_call_stats_it->first << "\"" << " [label=" << "\""
-            << " avg=" << wait_call_stats_it->second.get_waittime_average() <<  "s"
-            << " age=" << age << "s"
-            << " #calls=" << wait_call_stats_it->second.get_num_calls()
-            //<< " max=" << max_wait_time << "s"
-            << "\"";
-        if ((*sp_it)->watchers_wait_for_all_.count(wait_call_stats_it->first)) {
-          graph << ",color=\"red\"";
-        }
-        graph << ",style=dashed";
-        graph << "];";
-      }
-    }
-  }
-  // Visualize hook dependencies by directly adding edges from one hook to the
-  // next. This is necessary because we removed the main thread from the
-  // visualization, which makes sure that the hooks are started in the right
-  // order. To retain the dependencies between the hooks, add edges manually.
-  // Essentially, these edges represent the order that is guaranteed by the
-  // main thread.
-  // Note: this expects that
-  //   (1) pre loop is the first, post loop th last hook,
-  //   (2) no custom enum values (e.g. WAKEUP_HOOK_ACT = 5) are specified.
-  for (uint i = BlockedTimingAspect::WAKEUP_HOOK_PRE_LOOP;
-       i != BlockedTimingAspect::WAKEUP_HOOK_POST_LOOP;
-       i++) {
-    graph << "\""
-      << BlockedTimingAspect::blocked_timing_hook_to_end_syncpoint(
-        static_cast<BlockedTimingAspect::WakeupHook>(i)) << "\""
-      << " -> " << "\""
-      << BlockedTimingAspect::blocked_timing_hook_to_start_syncpoint(
-        static_cast<BlockedTimingAspect::WakeupHook>(i+1))
-      << "\";";
-  }
-  graph << "}";
-  return graph.str();
-}
 
 /** Find the prefix of the SyncPoint's identifier which is the identifier of
  *  the direct predecessor SyncPoint.
diff --git a/src/libs/syncpoint/syncpoint_manager.h b/src/libs/syncpoint/syncpoint_manager.h
index 82fc13f..6f06c1b 100644
--- a/src/libs/syncpoint/syncpoint_manager.h
+++ b/src/libs/syncpoint/syncpoint_manager.h
@@ -50,8 +50,6 @@ class SyncPointManager
 
     std::set<RefPtr<SyncPoint>, SyncPointSetLessThan > get_syncpoints();
 
-    std::string all_syncpoints_as_dot(float max_age);
-
   protected:
     /** Set of all existing SyncPoints */
     std::set<RefPtr<SyncPoint>, SyncPointSetLessThan > syncpoints_;
@@ -68,7 +66,6 @@ class SyncPointManager
       const std::string component) const;
     MultiLogger *logger_;
 
-
 };
 
 } // end namespace fawkes
diff --git a/src/plugins/webview/syncpoint_processor.cpp b/src/plugins/webview/syncpoint_processor.cpp
index 1f9893f..7209f63 100644
--- a/src/plugins/webview/syncpoint_processor.cpp
+++ b/src/plugins/webview/syncpoint_processor.cpp
@@ -25,7 +25,11 @@
 #include <webview/file_reply.h>
 #include <webview/error_reply.h>
 
+#include <syncpoint/syncpoint_call_stats.h>
+#include <aspect/blocked_timing.h>
+
 #include <string>
+#include <sstream>
 #include <cstring>
 #include <cstdlib>
 #include <cerrno>
@@ -71,7 +75,8 @@ WebviewSyncPointRequestProcessor::process_request(const fawkes::WebRequest *requ
     std::string subpath = request->url().substr(baseurl_len_);
 
     if (subpath == "/graph.png") {
-      std::string graph = syncpoint_manager_->all_syncpoints_as_dot(max_age_);
+      std::string graph = all_syncpoints_as_dot(
+        syncpoint_manager_->get_syncpoints(), max_age_);
 
       FILE *f = tmpfile();
       if (NULL == f) {
@@ -106,3 +111,148 @@ WebviewSyncPointRequestProcessor::process_request(const fawkes::WebRequest *requ
     return NULL;
   }
 }
+
+/**
+ * Get DOT graph for all SyncPoints
+ * @param max_age Show only SyncPoint calls which are younger than max_age
+ * @return string representation of DOT graph
+ */
+std::string
+WebviewSyncPointRequestProcessor::all_syncpoints_as_dot(
+  const std::set<RefPtr<SyncPoint>,SyncPointSetLessThan> syncpoints,
+  float max_age)
+{
+  std::stringstream graph;
+  graph << std::fixed; //fixed point notation
+  graph.precision(3); //3 decimal places
+  graph << "digraph { graph [fontsize=14]; "
+      << "node [fontsize=12]; edge [fontsize=12]; ";
+  graph.setf(std::ios::fixed, std::ios::floatfield);
+
+  for (std::set<RefPtr<SyncPoint>, SyncPointSetLessThan>::const_iterator sp_it = syncpoints.begin();
+      sp_it != syncpoints.end(); sp_it++) {
+    graph << "\"" << (*sp_it)->get_identifier() << "\""
+        << " [shape=box];";
+  }
+
+  for (std::set<RefPtr<SyncPoint>, SyncPointSetLessThan>::const_iterator sp_it = syncpoints.begin();
+      sp_it != syncpoints.end(); sp_it++) {
+    graph << "\"" << (*sp_it)->get_identifier() << "\";";
+
+    // EMIT CALLS
+    CircularBuffer<SyncPointCall> emit_calls = (*sp_it)->get_emit_calls();
+    // generate call stats
+    std::map<std::string, SyncPointCallStats> emit_call_stats;
+    for (CircularBuffer<SyncPointCall>::iterator emitcalls_it = emit_calls.begin();
+        emitcalls_it != emit_calls.end(); emitcalls_it++) {
+      // Remove the main thread from the graph, and also remove any emit calls
+      // to the SyncPoint "/" to improve the resulting graph.
+      // The main thread emits and waits for every hook, which adds a lot of
+      // uninteresting edges to the graph.
+      // Similarly, all emitters also emit "/", which is not interesting to see.
+      if (emitcalls_it->get_caller() == "FawkesMainThread" ||
+          (*sp_it)->get_identifier() == "/") {
+        continue;
+      }
+      emit_call_stats[emitcalls_it->get_caller()].update_calls(emitcalls_it->get_call_time());
+    }
+
+    for (std::map<std::string, SyncPointCallStats>::iterator emit_call_stats_it = emit_call_stats.begin();
+        emit_call_stats_it != emit_call_stats.end(); emit_call_stats_it++) {
+      float age = (Time() - emit_call_stats_it->second.get_last_call()).in_sec();
+      if (age < max_age) {
+      graph << "\"" << emit_call_stats_it->first << "\" -> \""
+          <<  (*sp_it)->get_identifier()
+          << "\"" << " [label=\""
+          << " freq=" << emit_call_stats_it->second.get_call_frequency() << "Hz"
+          << " age=" << age << "s"
+          << " #calls=" << emit_call_stats_it->second.get_num_calls()
+          << "\"" << "];";
+      }
+    }
+
+    // WAIT FOR ONE CALLS
+    CircularBuffer<SyncPointCall> wait_one_calls = (*sp_it)->get_wait_calls(SyncPoint::WAIT_FOR_ONE);
+    // generate call stats
+    std::map<std::string, SyncPointCallStats> wait_one_call_stats;
+    for (CircularBuffer<SyncPointCall>::iterator waitcalls_it = wait_one_calls.begin();
+        waitcalls_it != wait_one_calls.end(); waitcalls_it++) {
+      wait_one_call_stats[waitcalls_it->get_caller()].update_calls(*waitcalls_it);
+    }
+
+    for (std::map<std::string, SyncPointCallStats>::iterator wait_call_stats_it = wait_one_call_stats.begin();
+        wait_call_stats_it != wait_one_call_stats.end(); wait_call_stats_it++) {
+      if (wait_call_stats_it->first == "FawkesMainThread") {
+        continue;
+      }
+      float age = (Time() - wait_call_stats_it->second.get_last_call()).in_sec();
+      if (age < max_age) {
+        graph << "\"" << (*sp_it)->get_identifier() << "\"" << " -> "
+            << "\"" << wait_call_stats_it->first << "\"" << " [label=" << "\""
+            << " avg=" << wait_call_stats_it->second.get_waittime_average() <<  "s"
+            << " age=" << age << "s"
+            << " #calls=" << wait_call_stats_it->second.get_num_calls()
+            //          << " max=" << max_wait_time << "s"
+            << "\"";
+        if ((*sp_it)->watcher_is_waiting(wait_call_stats_it->first, SyncPoint::WAIT_FOR_ONE)) {
+          graph << ",color=\"red\"";
+        }
+        graph << ",style=dotted";
+        graph << "];";
+      }
+    }
+
+    // WAIT FOR ALL CALLS
+    CircularBuffer<SyncPointCall> wait_all_calls = (*sp_it)->get_wait_calls(SyncPoint::WAIT_FOR_ALL);
+    // generate call stats
+    std::map<std::string, SyncPointCallStats> wait_all_call_stats;
+    for (CircularBuffer<SyncPointCall>::iterator waitcalls_it = wait_all_calls.begin();
+        waitcalls_it != wait_all_calls.end(); waitcalls_it++) {
+      wait_all_call_stats[waitcalls_it->get_caller()].update_calls(*waitcalls_it);
+    }
+
+    for (std::map<std::string, SyncPointCallStats>::iterator wait_call_stats_it = wait_all_call_stats.begin();
+        wait_call_stats_it != wait_all_call_stats.end(); wait_call_stats_it++) {
+      if (wait_call_stats_it->first == "FawkesMainThread") {
+        continue;
+      }
+      float age = (Time() - wait_call_stats_it->second.get_last_call()).in_sec();
+      if (age < max_age) {
+        graph << "\"" << (*sp_it)->get_identifier() << "\"" << " -> "
+            << "\"" << wait_call_stats_it->first << "\"" << " [label=" << "\""
+            << " avg=" << wait_call_stats_it->second.get_waittime_average() <<  "s"
+            << " age=" << age << "s"
+            << " #calls=" << wait_call_stats_it->second.get_num_calls()
+            //<< " max=" << max_wait_time << "s"
+            << "\"";
+        if ((*sp_it)->watcher_is_waiting(wait_call_stats_it->first, SyncPoint::WAIT_FOR_ALL)) {
+          graph << ",color=\"red\"";
+        }
+        graph << ",style=dashed";
+        graph << "];";
+      }
+    }
+  }
+  // Visualize hook dependencies by directly adding edges from one hook to the
+  // next. This is necessary because we removed the main thread from the
+  // visualization, which makes sure that the hooks are started in the right
+  // order. To retain the dependencies between the hooks, add edges manually.
+  // Essentially, these edges represent the order that is guaranteed by the
+  // main thread.
+  // Note: this expects that
+  //   (1) pre loop is the first, post loop th last hook,
+  //   (2) no custom enum values (e.g. WAKEUP_HOOK_ACT = 5) are specified.
+  for (uint i = BlockedTimingAspect::WAKEUP_HOOK_PRE_LOOP;
+       i != BlockedTimingAspect::WAKEUP_HOOK_POST_LOOP;
+       i++) {
+    graph << "\""
+      << BlockedTimingAspect::blocked_timing_hook_to_end_syncpoint(
+        static_cast<BlockedTimingAspect::WakeupHook>(i)) << "\""
+      << " -> " << "\""
+      << BlockedTimingAspect::blocked_timing_hook_to_start_syncpoint(
+        static_cast<BlockedTimingAspect::WakeupHook>(i+1))
+      << "\";";
+  }
+  graph << "}";
+  return graph.str();
+}
diff --git a/src/plugins/webview/syncpoint_processor.h b/src/plugins/webview/syncpoint_processor.h
index 9e45670..00c4041 100644
--- a/src/plugins/webview/syncpoint_processor.h
+++ b/src/plugins/webview/syncpoint_processor.h
@@ -25,6 +25,7 @@
 
 #include <webview/request_processor.h>
 
+#include <core/utils/refptr.h>
 #include <syncpoint/syncpoint_manager.h>
 
 namespace fawkes {
@@ -41,6 +42,12 @@ class WebviewSyncPointRequestProcessor : public fawkes::WebRequestProcessor
 
   virtual fawkes::WebReply * process_request(const fawkes::WebRequest *request);
 
+ protected:
+  std::string all_syncpoints_as_dot(
+    const std::set< fawkes::RefPtr<fawkes::SyncPoint>,
+                    fawkes::SyncPointSetLessThan > syncpoints,
+    float max_age);
+
  private:
   char *baseurl_;
   size_t baseurl_len_;




-- 
Fawkes Robotics Framework                 http://www.fawkesrobotics.org


More information about the fawkes-commits mailing list