Move ftrace_reader code into src/traced/probes/ftrace

Reduces the API surface hiding the ftrace reader into src/.

Change-Id: Ie89b90013c6bd22ceed8aaf9595a23a4185b7b92
diff --git a/src/traced/probes/ftrace/ftrace_controller.h b/src/traced/probes/ftrace/ftrace_controller.h
new file mode 100644
index 0000000..381ec83
--- /dev/null
+++ b/src/traced/probes/ftrace/ftrace_controller.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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
+ *
+ *      http://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.
+ */
+
+#ifndef SRC_TRACED_PROBES_FTRACE_FTRACE_CONTROLLER_H_
+#define SRC_TRACED_PROBES_FTRACE_FTRACE_CONTROLLER_H_
+
+#include <unistd.h>
+
+#include <sys/stat.h>
+#include <bitset>
+#include <condition_variable>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "gtest/gtest_prod.h"
+#include "perfetto/base/scoped_file.h"
+#include "perfetto/base/task_runner.h"
+#include "perfetto/base/weak_ptr.h"
+#include "perfetto/protozero/message_handle.h"
+#include "perfetto/traced/data_source_types.h"
+#include "src/traced/probes/ftrace/ftrace_config.h"
+
+namespace perfetto {
+
+namespace protos {
+namespace pbzero {
+class FtraceEventBundle;
+class FtraceStats;
+class FtraceCpuStats;
+}  // namespace pbzero
+}  // namespace protos
+
+using BlockDeviceID = decltype(stat::st_dev);
+using Inode = decltype(stat::st_ino);
+
+struct FtraceCpuStats {
+  uint64_t cpu;
+  uint64_t entries;
+  uint64_t overrun;
+  uint64_t commit_overrun;
+  uint64_t bytes_read;
+  double oldest_event_ts;
+  double now_ts;
+  uint64_t dropped_events;
+  uint64_t read_events;
+
+  void Write(protos::pbzero::FtraceCpuStats*) const;
+};
+
+struct FtraceStats {
+  std::vector<FtraceCpuStats> cpu_stats;
+
+  void Write(protos::pbzero::FtraceStats*) const;
+};
+
+struct FtraceMetadata {
+  FtraceMetadata();
+
+  uint32_t overwrite_count;
+  BlockDeviceID last_seen_device_id = 0;
+#if PERFETTO_DCHECK_IS_ON()
+  bool seen_device_id = false;
+#endif
+  int32_t last_seen_common_pid = 0;
+
+  // A vector not a set to keep the writer_fast.
+  std::vector<std::pair<Inode, BlockDeviceID>> inode_and_device;
+  std::vector<int32_t> pids;
+
+  void AddDevice(BlockDeviceID);
+  void AddInode(Inode);
+  void AddPid(int32_t);
+  void AddCommonPid(int32_t);
+  void Clear();
+  void FinishEvent();
+};
+
+constexpr size_t kMaxSinks = 32;
+constexpr size_t kMaxCpus = 64;
+
+// Method of last resort to reset ftrace state.
+void HardResetFtraceState();
+
+class CpuReader;
+class EventFilter;
+class FtraceController;
+class FtraceConfigMuxer;
+class FtraceProcfs;
+class ProtoTranslationTable;
+
+// To consume ftrace data clients implement a |FtraceSink::Delegate| and use it
+// to create a |FtraceSink|. While the FtraceSink lives FtraceController will
+// call |GetBundleForCpu|, write data into the bundle then call
+// |OnBundleComplete| allowing the client to perform finalization.
+class FtraceSink {
+ public:
+  using FtraceEventBundle = protos::pbzero::FtraceEventBundle;
+  class Delegate {
+   public:
+    virtual void OnCreate(FtraceSink*) {}
+    virtual protozero::MessageHandle<FtraceEventBundle> GetBundleForCpu(
+        size_t) = 0;
+    virtual void OnBundleComplete(size_t,
+                                  protozero::MessageHandle<FtraceEventBundle>,
+                                  const FtraceMetadata&) = 0;
+    virtual ~Delegate();
+  };
+
+  FtraceSink(base::WeakPtr<FtraceController>,
+             FtraceConfigId id,
+             FtraceConfig config,
+             std::unique_ptr<EventFilter>,
+             Delegate*);
+  ~FtraceSink();
+
+  void DumpFtraceStats(FtraceStats*);
+
+  const FtraceConfig& config() const { return config_; }
+
+ private:
+  friend FtraceController;
+
+  FtraceSink(const FtraceSink&) = delete;
+  FtraceSink& operator=(const FtraceSink&) = delete;
+
+  EventFilter* event_filter() { return filter_.get(); }
+  FtraceMetadata* metadata_mutable() { return &metadata_; }
+
+  protozero::MessageHandle<FtraceEventBundle> GetBundleForCpu(size_t cpu) {
+    return delegate_->GetBundleForCpu(cpu);
+  }
+  void OnBundleComplete(size_t cpu,
+                        protozero::MessageHandle<FtraceEventBundle> bundle) {
+    delegate_->OnBundleComplete(cpu, std::move(bundle), metadata_);
+    metadata_.Clear();
+  }
+
+  const std::set<std::string>& enabled_events();
+
+  base::WeakPtr<FtraceController> controller_weak_;
+  const FtraceConfigId id_;
+  const FtraceConfig config_;
+  std::unique_ptr<EventFilter> filter_;
+  FtraceMetadata metadata_;
+  FtraceSink::Delegate* delegate_;
+};
+
+// Utility class for controlling ftrace.
+class FtraceController {
+ public:
+  static std::unique_ptr<FtraceController> Create(base::TaskRunner*);
+  virtual ~FtraceController();
+
+  std::unique_ptr<FtraceSink> CreateSink(FtraceConfig, FtraceSink::Delegate*);
+
+  void DisableAllEvents();
+  void WriteTraceMarker(const std::string& s);
+  void ClearTrace();
+
+ protected:
+  // Protected for testing.
+  FtraceController(std::unique_ptr<FtraceProcfs>,
+                   std::unique_ptr<ProtoTranslationTable>,
+                   std::unique_ptr<FtraceConfigMuxer>,
+                   base::TaskRunner*);
+
+  // Write
+  void DumpFtraceStats(FtraceStats*);
+
+  // Called to read data from the staging pipe for the given |cpu| and parse it
+  // into the sinks. Protected and virtual for testing.
+  virtual void OnRawFtraceDataAvailable(size_t cpu);
+
+  // Protected and virtual for testing.
+  virtual uint64_t NowMs() const;
+
+ private:
+  friend FtraceSink;
+  friend class TestFtraceController;
+  FRIEND_TEST(FtraceControllerIntegrationTest, EnableDisableEvent);
+
+  FtraceController(const FtraceController&) = delete;
+  FtraceController& operator=(const FtraceController&) = delete;
+
+  // Called on a worker thread when |cpu| has at least one page of data
+  // available for reading.
+  void OnDataAvailable(base::WeakPtr<FtraceController>,
+                       size_t generation,
+                       size_t cpu,
+                       uint32_t drain_period_ms);
+
+  static void DrainCPUs(base::WeakPtr<FtraceController>, size_t generation);
+  static void UnblockReaders(const base::WeakPtr<FtraceController>&);
+
+  uint32_t GetDrainPeriodMs();
+
+  void Register(FtraceSink*);
+  void Unregister(FtraceSink*);
+
+  void StartIfNeeded();
+  void StopIfNeeded();
+
+  // Begin lock-protected members.
+  std::mutex lock_;
+  std::condition_variable data_drained_;
+  std::bitset<kMaxCpus> cpus_to_drain_;
+  bool listening_for_raw_trace_data_ = false;
+  // End lock-protected members.
+
+  std::unique_ptr<FtraceProcfs> ftrace_procfs_;
+  std::unique_ptr<ProtoTranslationTable> table_;
+  std::unique_ptr<FtraceConfigMuxer> ftrace_config_muxer_;
+  size_t generation_ = 0;
+  bool atrace_running_ = false;
+  base::TaskRunner* task_runner_ = nullptr;
+  std::map<size_t, std::unique_ptr<CpuReader>> readers_;
+  std::set<FtraceSink*> sinks_;
+  base::WeakPtrFactory<FtraceController> weak_factory_;
+  PERFETTO_THREAD_CHECKER(thread_checker_)
+};
+
+}  // namespace perfetto
+
+#endif  // SRC_TRACED_PROBES_FTRACE_FTRACE_CONTROLLER_H_