Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
tracinghandler.cc
Go to the documentation of this file.
1 
18 #if !ION_PRODUCTION
19 
21 
22 #include <vector>
23 
24 #include "ion/base/invalid.h"
25 #include "ion/base/logging.h"
26 #include "ion/base/serialize.h"
27 #include "ion/base/stringutils.h"
30 
31 ION_REGISTER_ASSETS(IonRemoteTracingRoot);
32 
33 namespace ion {
34 namespace remote {
35 
36 namespace {
37 
39 
45 
46 
47 class TracingHtmlHelper {
48  public:
49  TracingHtmlHelper();
50  ~TracingHtmlHelper();
51 
55  void AddHtml(uint64 frame_counter, const std::string& trace_string,
56  std::string* html_string);
57 
58  private:
60  struct ParsedLine {
62  enum Type {
63  kLabel, // A label for some Ion object.
64  kCall, // A call to an OpenGL function.
65  kError, // An OpenGL error message.
66  };
67 
68  ParsedLine() : type(kCall), level(0) {}
69 
70  Type type; // Type of line.
71  int level; // Indentation level of line.
72  std::string text; // Tracing text with indentation stripped out.
73  };
74 
76  void AddHeader(uint64 frame_counter, bool add_horizontal_rule,
77  std::ostringstream& s); // NOLINT
78 
80  const std::vector<ParsedLine> ParseLines(const std::string& trace_string);
81 
83  const ParsedLine ParseLine(const std::string& line);
84 
86  void AddHtmlForLines(const std::vector<ParsedLine>& parsed_lines,
87  std::ostringstream& s); // NOLINT
88 
90  void AddHtmlForCall(const std::string& line,
91  std::ostringstream& s); // NOLINT
92 };
93 
94 TracingHtmlHelper::TracingHtmlHelper() {}
95 TracingHtmlHelper::~TracingHtmlHelper() {}
96 
97 void TracingHtmlHelper::AddHtml(uint64 frame_counter,
98  const std::string& trace_string,
99  std::string* html_string) {
101  std::ostringstream s;
102 
103  AddHeader(frame_counter, !html_string->empty(), s);
104  const std::vector<ParsedLine> parsed_lines = ParseLines(trace_string);
105 
106  AddHtmlForLines(parsed_lines, s);
107 
108  html_string->append(s.str());
109 }
110 
111 void TracingHtmlHelper::AddHeader(uint64 frame_counter,
112  bool add_horizontal_rule,
113  std::ostringstream& s) { // NOLINT
114  if (add_horizontal_rule)
115  s << "<hr>\n";
116 
117  s << "<span class=\"trace_header\">OpenGL trace at frame "
118  << frame_counter << "</span><br><br>\n";
119 }
120 
121 const std::vector<TracingHtmlHelper::ParsedLine> TracingHtmlHelper::ParseLines(
122  const std::string& trace_string) {
123  const std::vector<std::string> lines = base::SplitString(trace_string, "\n");
124  const size_t num_lines = lines.size();
125 
126  std::vector<ParsedLine> parsed_lines;
127  parsed_lines.reserve(num_lines);
128  for (size_t i = 0; i < num_lines; ++i)
129  parsed_lines.push_back(ParseLine(lines[i]));
130 
131  return parsed_lines;
132 }
133 
134 const TracingHtmlHelper::ParsedLine TracingHtmlHelper::ParseLine(
135  const std::string& line) {
136  DCHECK(!line.empty());
137  const size_t length = line.size();
138  ParsedLine parsed_line;
139 
141  if (line.find("GL error") != std::string::npos) {
142  static const char kErrorHeader[] = "*** GL error after call to";
143  parsed_line.type = ParsedLine::kError;
144  parsed_line.level = 0;
146  parsed_line.text = line.substr(sizeof(kErrorHeader));
147  } else if (line[0] == '>' || line[0] == '-') {
149  const size_t num_dashes = line.find_first_not_of('-');
151  DCHECK_EQ(num_dashes % 1, 0U);
152  DCHECK_LT(num_dashes + 1, length);
153  DCHECK_EQ(line[num_dashes], '>');
154 
155  parsed_line.type = ParsedLine::kLabel;
156  parsed_line.level = static_cast<int>(num_dashes / 2);
157  parsed_line.text = line.substr(num_dashes + 1);
158 
160  if (base::EndsWith(parsed_line.text, ":"))
161  parsed_line.text.resize(parsed_line.text.size() - 1);
162  } else {
164  const size_t num_spaces = line.find_first_not_of(' ');
166  DCHECK_EQ(num_spaces % 1, 0U);
167 
168  parsed_line.type = ParsedLine::kCall;
169  parsed_line.level = static_cast<int>(num_spaces / 2);
170  parsed_line.text = line.substr(num_spaces);
171  }
172  return parsed_line;
173 }
174 
175 void TracingHtmlHelper::AddHtmlForLines(
176  const std::vector<ParsedLine>& parsed_lines,
177  std::ostringstream& s) { // NOLINT
178  s << "<div class=\"tree\">\n<ul>\n";
179 
180  const size_t num_lines = parsed_lines.size();
181  int cur_list = 0;
182  int list_level = -1;
183 
184  for (size_t i = 0; i < num_lines; ++i) {
185  const ParsedLine& line = parsed_lines[i];
186 
188  if (line.type == ParsedLine::kError) {
189  s << "<br><span class=\"trace_error\">" << "***OpenGL Error: "
190  << line.text << "</span><br><br>\n";
191  continue;
192  }
193 
195  while (list_level >= line.level) {
196  s << "</ul>\n</li>\n";
197  --list_level;
198  }
199 
200  if (line.type == ParsedLine::kLabel) {
202  const size_t list_id = cur_list++;
203  s << "<li><input type =\"checkbox\" checked=\"checked\" id=\"list-"
204  << list_id << "\"/><label for=\"list-" << list_id << "\">" << line.text
205  << "</label>\n<ul>\n";
206  list_level = line.level;
207  } else {
209  s << "<li>";
210  AddHtmlForCall(line.text, s);
211  s << "</li>\n";
212  }
213  }
214 
216  while (list_level >= 0) {
217  s << "</ul>\n</li>\n";
218  --list_level;
219  }
220 
221  s << "</ul>\n</div>\n";
222 }
223 
224 void
225 TracingHtmlHelper::AddHtmlForCall(const std::string& line,
226  std::ostringstream& s) { // NOLINT
227  std::vector<std::string> args = base::SplitString(line, "(),");
228  const size_t arg_count = args.size();
229 
231  for (size_t i = 0; i < arg_count; ++i)
232  args[i] = base::TrimStartAndEndWhitespace(args[i]);
233 
235  s << "<span class=\"trace_function\">" << args[0] << "</span>(";
236 
237  for (size_t i = 1; i < arg_count; ++i) {
238  std::string arg = args[i];
239 
241  const size_t pos = arg.find(" = ");
242  if (pos != std::string::npos) {
243  if (i > 1)
244  s << "</span>, ";
245  s << "<span class=\"trace_arg_name\">"
246  << arg.substr(0, pos) << "</span> = <span class=\"trace_arg_value\">"
247  << arg.substr(pos + 3, std::string::npos);
248  } else {
250  s << ", " << arg;
251  }
252  }
253  if (arg_count > 1)
254  s << "</span>";
255  s << ")";
256 }
257 
259 
264 
265 
267 static gfx::Renderer::ResourceType GetResourceTypeFromName(
268  const std::string& name) {
269  static const char* kResourceNames[gfx::Renderer::kNumResourceTypes] = {
270  "Attribute Arrays", // Renderer::kAttributeArray,
271  "Buffer Objects", // Renderer::kBufferObject,
272  "Framebuffer Objects", // Renderer::kFramebufferObject,
273  "Samplers", // Renderer::kSampler,
274  "Shader Input Registries", // Renderer::kShaderInputRegistry,
275  "Shader Programs", // Renderer::kShaderProgram,
276  "Shaders", // Renderer::kShader,
277  "Textures", // Renderer::kTexture,
278  };
279  int index;
280  for (index = 0; index < gfx::Renderer::kNumResourceTypes; ++index) {
281  if (name == kResourceNames[index])
282  break;
283  }
284  DCHECK_LT(index, gfx::Renderer::kNumResourceTypes);
285  return static_cast<gfx::Renderer::ResourceType>(index);
286 }
287 
288 } // anonymous namespace
289 
291 
296 
297 
299  const gfx::RendererPtr& renderer)
300  : HttpServer::RequestHandler("/ion/tracing"),
301  frame_(frame),
302  renderer_(renderer),
303  prev_stream_(renderer_->GetGraphicsManager()->GetTracingStream()),
304  state_(kInactive),
305  frame_counter_(0) {
306  using std::bind;
307  using std::placeholders::_1;
308 
309  IonRemoteTracingRoot::RegisterAssetsOnce();
310 
312  if (frame_.Get()) {
313  frame_->AddPreFrameCallback("TracingHandler",
314  bind(&TracingHandler::BeginFrame, this, _1));
315  frame_->AddPostFrameCallback("TracingHandler",
316  bind(&TracingHandler::EndFrame, this, _1));
317  }
318 }
319 
322  if (frame_.Get()) {
323  frame_->RemovePreFrameCallback("TracingHandler");
324  frame_->RemovePostFrameCallback("TracingHandler");
325  }
326 
328  renderer_->GetGraphicsManager()->SetTracingStream(prev_stream_);
329 }
330 
332  const std::string& path_in, const HttpServer::QueryMap& args,
333  std::string* content_type) {
334  const std::string path = path_in.empty() ? "index.html" : path_in;
335 
336  if (path == "trace_next_frame") {
338  const HttpServer::QueryMap::const_iterator it =
339  args.find("resources_to_delete");
340  resources_to_delete_ = it != args.end() ? it->second : "";
343  TraceNextFrame(args.find("nonblocking") == args.end());
344  return html_string_;
345  } else if (path == "clear") {
346  html_string_.clear();
347  return "clear";
348  } else {
349  const std::string& data =
350  base::ZipAssetManager::GetFileData("ion/tracing/" + path);
351  if (!base::IsInvalidReference(data)) {
353  if (base::EndsWith(path, "html"))
354  *content_type = "text/html";
355  return data;
356  }
357  }
358  return std::string();
359 }
360 
361 void TracingHandler::TraceNextFrame(bool block_until_frame_rendered) {
362  if (frame_.Get()) {
364  state_ = kWaitingForBeginFrame;
366  if (!block_until_frame_rendered) {
367  frame_->Begin();
368  frame_->End();
369  }
370  semaphore_.Wait();
371  DCHECK_EQ(state_, kInactive);
373  TracingHtmlHelper helper;
374  helper.AddHtml(frame_counter_, tracing_stream_.str(), &html_string_);
375  tracing_stream_.str("");
376  }
377 }
378 
379 void TracingHandler::BeginFrame(const gfxutils::Frame& frame) {
380  if (state_ == kWaitingForBeginFrame) {
382  if (!resources_to_delete_.empty()) {
384  const std::vector<std::string> resources =
385  base::SplitString(resources_to_delete_, ",");
386  const size_t num_resources = resources.size();
387  for (size_t i = 0; i < num_resources; ++i)
388  renderer_->ClearTypedResources(GetResourceTypeFromName(resources[i]));
389  resources_to_delete_.clear();
390  }
391  frame_counter_ = frame.GetCounter();
392  renderer_->GetGraphicsManager()->SetTracingStream(&tracing_stream_);
393  state_ = kWaitingForEndFrame;
394  }
395 }
396 
397 void TracingHandler::EndFrame(const gfxutils::Frame& frame) {
398  if (state_ == kWaitingForEndFrame) {
399  renderer_->GetGraphicsManager()->SetTracingStream(prev_stream_);
400  state_ = kInactive;
402  semaphore_.Post();
403  }
404 }
405 
406 } // namespace remote
407 } // namespace ion
408 
409 #endif
bool Post()
Wakes a single thread that is Wait()ing, or the next thread to call Wait().
Definition: semaphore.cc:85
bool IsInvalidReference(const T &value)
IsInvalidReference() returns true if a passed const reference of type T has an address of InvalidRefe...
Definition: invalid.h:41
bool Wait()
Blocks the calling thread until another thread calls Post().
Definition: semaphore.cc:205
int level
const std::string HandleRequest(const std::string &path, const HttpServer::QueryMap &args, std::string *content_type) override
The HandleRequest() function is passed the path (relative to its base path) of the file or directory ...
std::string text
ResourceType
The types of resources created by the renderer.
Definition: renderer.h:101
ION_REGISTER_ASSETS(IonRemoteTracingRoot)
Copyright 2016 Google Inc.
#define DCHECK(expr)
Definition: logging.h:331
std::string TrimStartAndEndWhitespace(const std::string &target)
Removes any whitespace characters at the beginning and end of the string.
Definition: stringutils.h:155
std::vector< std::string > ION_API SplitString(const std::string &str, const std::string &delimiters)
Splits a string into a vector of substrings, given a set of delimiter characters (expressed as a stri...
Definition: stringutils.cc:187
uint32 length
static const std::string & GetFileData(const std::string &filename)
Returns the data of the passed filename if the manager contains it.
T * Get() const
Returns a raw pointer to the instance, which may be NULL.
Definition: sharedptr.h:89
TracingHandler(const gfxutils::FramePtr &frame, const gfx::RendererPtr &renderer)
The constructor is passed a Frame instance that allows the handler to know when frames begin and end ...
std::string name
Definition: printer.cc:324
Copyright 2016 Google Inc.
#define DCHECK_EQ(val1, val2)
Definition: logging.h:332
bool EndsWith(const std::string &target, const std::string &end)
Returns whether target ends with end.
Definition: stringutils.h:81
const RendererPtr & renderer_
Renderer used to render images.
std::map< std::string, std::string > QueryMap
Definition: httpserver.h:35
A SharedPtr is a smart shared pointer to an instance of some class that implements reference counting...
Definition: sharedptr.h:60
#define DCHECK_LT(val1, val2)
Definition: logging.h:335
static const int kNumResourceTypes
Definition: renderer.h:111
Type type