pw_trace: tokenizer basic example

Run the trace sample app and dump all trace data to a file.
- Use std::chrono::system_clock as the time source for host builds.
- Add trace_to_file.h which registers callbacks and saves all trace data
to a provided binary file.

Change-Id: I57fac75ed91fc98646e7aae920897687a39549ab
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/13802
Commit-Queue: Rob Oliver <rgoliver@google.com>
Reviewed-by: (☞゚∀゚)☞ Tennessee Carmel-Veilleux  <tennessee@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index c8f937b..e89bf65 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -109,7 +109,10 @@
     # Trace examples currently only support running on non-windows host
     if (defined(pw_toolchain_SCOPE.is_host_toolchain) &&
         pw_toolchain_SCOPE.is_host_toolchain && host_os != "win") {
-      deps += [ "$dir_pw_trace:trace_example_basic" ]
+      deps += [
+        "$dir_pw_trace:trace_example_basic",
+        "$dir_pw_trace_tokenized:trace_tokenized_example_basic",
+      ]
     }
   }
 }
diff --git a/pw_trace_tokenized/BUILD b/pw_trace_tokenized/BUILD
index 535e29d..c5dfe52 100644
--- a/pw_trace_tokenized/BUILD
+++ b/pw_trace_tokenized/BUILD
@@ -14,6 +14,7 @@
 
 load(
     "//pw_build:pigweed.bzl",
+    "pw_cc_binary",
     "pw_cc_library",
     "pw_cc_test",
 )
@@ -127,3 +128,27 @@
     ],
 )
 
+pw_cc_library(
+    name = "pw_trace_host_trace_time",
+    includes = [ "example/public" ],
+    deps = [ "//pw_trace" ],
+    srcs = [ "host_trace_time.cc" ]
+)
+
+pw_cc_library(
+    name = "pw_trace_example_to_file",
+    includes = [ "example/public" ],
+    deps = [ "//pw_trace" ],
+    hdrs = [ "example/public/pw_trace_tokenized/example/trace_to_file.h" ]
+)
+
+pw_cc_binary(
+    name = "trace_tokenized_example_basic",
+    deps = [
+        ":pw_trace_example_to_file",
+        "//pw_log",
+        "//dir_pw_trace",
+        "//dir_pw_trace:pw_trace_sample_app",
+    ],
+    srcs = [ "example/basic.cc" ]
+)
diff --git a/pw_trace_tokenized/BUILD.gn b/pw_trace_tokenized/BUILD.gn
index 7a083d1..97892fb 100644
--- a/pw_trace_tokenized/BUILD.gn
+++ b/pw_trace_tokenized/BUILD.gn
@@ -90,6 +90,11 @@
   sources = [ "fake_trace_time.cc" ]
 }
 
+pw_source_set("host_trace_time") {
+  deps = [ ":pw_trace_tokenized_core" ]
+  sources = [ "host_trace_time.cc" ]
+}
+
 pw_source_set("pw_trace_tokenized_core") {
   public_configs = [
     ":backend_config",
@@ -114,3 +119,24 @@
 pw_doc_group("docs") {
   sources = [ "docs.rst" ]
 }
+
+config("trace_example_config") {
+  include_dirs = [ "example/public" ]
+}
+
+pw_source_set("trace_example_to_file") {
+  deps = [ ":pw_trace_tokenized" ]
+  public_configs = [ ":trace_example_config" ]
+  public = [ "example/public/pw_trace_tokenized/example/trace_to_file.h" ]
+}
+
+# Builds trace examples
+pw_executable("trace_tokenized_example_basic") {
+  deps = [
+    ":trace_example_to_file",
+    "$dir_pw_log",
+    "$dir_pw_trace",
+    "$dir_pw_trace:trace_sample_app",
+  ]
+  sources = [ "example/basic.cc" ]
+}
diff --git a/pw_trace_tokenized/docs.rst b/pw_trace_tokenized/docs.rst
index f0af6a5..61715fc 100644
--- a/pw_trace_tokenized/docs.rst
+++ b/pw_trace_tokenized/docs.rst
@@ -180,3 +180,17 @@
 ------------------
 ``pw_ring_buffer``
 ``pw_varint``
+
+
+--------
+Examples
+--------
+The examples all use `pw_trace` sample app to provide the trace data. Details
+for how to build, run, and decode the traces are included at the top of each
+example. This is early work, and is provided as an example of how different
+tracing concepts can look.
+
+Basic
+-----
+The basic example turns on tracing and dumps all trace output to a file provided
+on the command line.
diff --git a/pw_trace_tokenized/example/basic.cc b/pw_trace_tokenized/example/basic.cc
new file mode 100644
index 0000000..4daa894
--- /dev/null
+++ b/pw_trace_tokenized/example/basic.cc
@@ -0,0 +1,49 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//==============================================================================
+// BUID
+// ninja -C out
+// host_clang_debug/obj/pw_trace_tokenized/bin/trace_tokenized_example_basic
+//
+// RUN
+// .out/host_clang_debug/obj/pw_trace_tokenized/bin/trace_tokenized_example_basic
+// trace.bin
+//
+// DECODE
+// python pw_trace_tokenized/py/trace_tokenized.py -i trace.bin -o trace.json
+// ./out/host_clang_debug/obj/pw_trace_tokenized/bin/trace_tokenized_example_basic
+//
+// VIEW
+// In chrome navigate to chrome://tracing, and load the trace.json file.
+
+#include "pw_log/log.h"
+#include "pw_trace/example/sample_app.h"
+#include "pw_trace_tokenized/example/trace_to_file.h"
+
+int main(int argc, char** argv) {  // Take filename as arg
+  if (argc != 2) {
+    PW_LOG_ERROR("Expected output file name as argument.\n");
+    return -1;
+  }
+
+  // Enable tracing.
+  PW_TRACE_SET_ENABLED(true);
+
+  // Dump trace data to the file passed in.
+  pw::trace::TraceToFile trace_to_file(argv[1]);
+
+  PW_LOG_INFO("Running basic trace example...\n");
+  RunTraceSampleApp();
+  return 0;
+}
\ No newline at end of file
diff --git a/pw_trace_tokenized/example/public/pw_trace_tokenized/example/trace_to_file.h b/pw_trace_tokenized/example/public/pw_trace_tokenized/example/trace_to_file.h
new file mode 100644
index 0000000..5c2d783
--- /dev/null
+++ b/pw_trace_tokenized/example/public/pw_trace_tokenized/example/trace_to_file.h
@@ -0,0 +1,69 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//==============================================================================
+//
+
+#pragma once
+
+#include <stdio.h>
+
+#include <fstream>
+
+#include "pw_trace/example/sample_app.h"
+#include "pw_trace_tokenized/trace_callback.h"
+
+namespace pw {
+namespace trace {
+
+class TraceToFile {
+ public:
+  TraceToFile(const char* file_name) {
+    Callbacks::Instance().RegisterSink(TraceSinkStartBlock,
+                                       TraceSinkAddBytes,
+                                       TraceSinkEndBlock,
+                                       &out_,
+                                       &sink_handle_);
+    out_.open(file_name, std::ios::out | std::ios::binary);
+  }
+
+  ~TraceToFile() {
+    Callbacks::Instance().UnregisterSink(sink_handle_);
+    out_.close();
+  }
+
+  static void TraceSinkStartBlock(void* user_data, size_t size) {
+    std::ofstream* out = reinterpret_cast<std::ofstream*>(user_data);
+    uint8_t b = static_cast<uint8_t>(size);
+    out->write(reinterpret_cast<const char*>(&b), sizeof(b));
+  }
+
+  static void TraceSinkAddBytes(void* user_data,
+                                const void* bytes,
+                                size_t size) {
+    std::ofstream* out = reinterpret_cast<std::ofstream*>(user_data);
+    out->write(reinterpret_cast<const char*>(bytes), size);
+  }
+
+  static void TraceSinkEndBlock(void* user_data) {
+    std::ofstream* out = reinterpret_cast<std::ofstream*>(user_data);
+    out->flush();
+  }
+
+ private:
+  std::ofstream out_;
+  CallbacksImpl::SinkHandle sink_handle_;
+};
+
+}  // namespace trace
+}  // namespace pw
diff --git a/pw_trace_tokenized/host_trace_time.cc b/pw_trace_tokenized/host_trace_time.cc
new file mode 100644
index 0000000..b9135b4
--- /dev/null
+++ b/pw_trace_tokenized/host_trace_time.cc
@@ -0,0 +1,36 @@
+// Copyright 2020 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//==============================================================================
+//
+
+#include <chrono>
+
+#include "pw_trace_tokenized/trace_tokenized.h"
+
+using namespace std::chrono;
+
+namespace {
+
+auto start = system_clock::now();
+
+}  // namespace
+
+// Define trace time as a counter for tests.
+PW_TRACE_TIME_TYPE pw_trace_GetTraceTime() {
+  auto delta = system_clock::now() - start;
+  return duration_cast<microseconds>(delta).count();
+}
+
+// Microsecond time source
+size_t pw_trace_GetTraceTimeTicksPerSecond() { return 1000000; }
diff --git a/targets/host/target_toolchains.gni b/targets/host/target_toolchains.gni
index 1a9512b..98b094f 100644
--- a/targets/host/target_toolchains.gni
+++ b/targets/host/target_toolchains.gni
@@ -35,8 +35,8 @@
   # Configure backend for trace facade.
   pw_trace_BACKEND = "$dir_pw_trace_tokenized"
 
-  # Tokenizer trace time, for now using a fake time.
-  pw_trace_tokenizer_time = "$dir_pw_trace_tokenized:fake_trace_time"
+  # Tokenizer trace time.
+  pw_trace_tokenizer_time = "$dir_pw_trace_tokenized:host_trace_time"
 
   # Allow nanopb to be toggled via a build arg on host for easy testing.
   _has_nanopb = pw_protobuf_GENERATORS + [ "nanopb" ] - [ "nanopb" ] !=