17ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe/*
27ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe *
37ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe * Copyright 2017, The Android Open Source Project
47ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe *
57ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe * Licensed under the Apache License, Version 2.0 (the "License");
67ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe * you may not use this file except in compliance with the License.
77ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe * You may obtain a copy of the License at
87ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe *
97ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe *     http://www.apache.org/licenses/LICENSE-2.0
107ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe *
117ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe * Unless required by applicable law or agreed to in writing, software
127ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe * distributed under the License is distributed on an "AS IS" BASIS,
137ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
147ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe * See the License for the specific language governing permissions and
157ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe * limitations under the License.
167ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe */
177ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
187ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#ifndef SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_THREADED_HANDLER_H_
197ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#define SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_THREADED_HANDLER_H_
207ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
217ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include <chrono>
227ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include <condition_variable>
237ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include <cstdio>
247ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include <cstdlib>
257ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include <memory>
267ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include <mutex>
277ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include <string>
287ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include <thread>
297ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include <functional>
307ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
317ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include <inttypes.h>
327ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include <unistd.h>
337ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
347ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include <android-base/logging.h>
357ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include <android-base/stringprintf.h>
367ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
377ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include "perfprofd_record.pb.h"
387ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
397ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include "config.h"
407ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include "dropbox.h"
417ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include "perfprofdcore.h"
427ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#include "perfprofd_io.h"
437ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
447ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampenamespace android {
457ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampenamespace perfprofd {
467ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
477ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampeclass ThreadedConfig : public Config {
487ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe public:
497ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  void Sleep(size_t seconds) override {
507ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    if (seconds == 0) {
517ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      return;
527ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    }
537ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    std::unique_lock<std::mutex> guard(mutex_);
547ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    using namespace std::chrono_literals;
557ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    cv_.wait_for(guard, seconds * 1s, [&]() { return interrupted_; });
567ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  }
577ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  bool ShouldStopProfiling() override {
587ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    std::unique_lock<std::mutex> guard(mutex_);
597ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    return interrupted_;
607ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  }
617ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
627ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  void ResetStopProfiling() {
637ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    std::unique_lock<std::mutex> guard(mutex_);
647ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    interrupted_ = false;
657ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  }
667ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  void StopProfiling() {
677ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    std::unique_lock<std::mutex> guard(mutex_);
687ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    interrupted_ = true;
697ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    cv_.notify_all();
707ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  }
717ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
727ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  bool IsProfilingEnabled() const override {
737ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    return true;
747ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  }
757ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
767ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  // Operator= to simplify setting the config values. This will retain the
777ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  // original mutex, condition-variable etc.
787ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  ThreadedConfig& operator=(const ThreadedConfig& rhs) {
797ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    // Copy base fields.
807ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    *static_cast<Config*>(this) = static_cast<const Config&>(rhs);
817ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
827ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    return *this;
837ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  }
847ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
857ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe private:
867ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  bool is_profiling = false;
877ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  std::mutex mutex_;
887ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  std::condition_variable cv_;
897ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  bool interrupted_ = false;
907ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
917ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  friend class ThreadedHandler;
927ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe};
937ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
947ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampeclass ThreadedHandler  {
957ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe public:
967ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  ThreadedHandler() : cur_config_(new ThreadedConfig()) {}
977ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  explicit ThreadedHandler(ThreadedConfig* in) : cur_config_(in) {
987ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    CHECK(cur_config_ != nullptr);
997ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  }
1007ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1017ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  virtual ~ThreadedHandler() {}
1027ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1037ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  template <typename ConfigFn> bool StartProfiling(ConfigFn fn, std::string* error_msg) {
1047ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    std::lock_guard<std::mutex> guard(lock_);
1057ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1067ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    if (cur_config_->is_profiling) {
1077ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      *error_msg = "Already profiling";
1087ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      return false;
1097ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    }
1107ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    cur_config_->is_profiling = true;
1117ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    cur_config_->ResetStopProfiling();
1127ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1137ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    fn(*cur_config_);
1147ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1157ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    HandlerFn handler = GetResultHandler();
1167ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    auto profile_runner = [handler](ThreadedHandler* service) {
1177ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      ProfilingLoop(*service->cur_config_, handler);
1187ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1197ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      // This thread is done.
1207ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      std::lock_guard<std::mutex> unset_guard(service->lock_);
1217ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      service->cur_config_->is_profiling = false;
1227ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    };
1237ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    std::thread profiling_thread(profile_runner, this);
1247ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    profiling_thread.detach();  // Let it go.
1257ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1267ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    return true;
1277ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  }
1287ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1297ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  bool StopProfiling(std::string* error_msg) {
1307ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    std::lock_guard<std::mutex> guard(lock_);
1317ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    if (!cur_config_->is_profiling) {
1327ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      *error_msg = "Not profiling";
1337ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      return false;
1347ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    }
1357ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1367ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    cur_config_->StopProfiling();
1377ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1387ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    return true;
1397ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  }
1407ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1417ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe protected:
1427ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  // Handler for ProfilingLoop.
1437ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  virtual bool ResultHandler(android::perfprofd::PerfprofdRecord* encodedProfile,
1447ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe                             Config* config) {
1457ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    CHECK(config != nullptr);
1467ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    if (encodedProfile == nullptr) {
1477ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      return false;
1487ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    }
1497ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1507ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    if (static_cast<ThreadedConfig*>(config)->send_to_dropbox) {
1517ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      std::string error_msg;
1527ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      if (!dropbox::SendToDropbox(encodedProfile, config->destination_directory, &error_msg)) {
1537ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe        LOG(WARNING) << "Failed dropbox submission: " << error_msg;
1547ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe        return false;
1557ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      }
1567ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      return true;
1577ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    }
1587ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1597ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    if (encodedProfile == nullptr) {
1607ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      return false;
1617ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    }
1627ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    std::string data_file_path(config->destination_directory);
1637ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    data_file_path += "/perf.data";
1647ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    std::string path = android::base::StringPrintf("%s.encoded.%d", data_file_path.c_str(), seq_);
1657ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    if (!SerializeProtobuf(encodedProfile, path.c_str(), config->compress)) {
1667ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe      return false;
1677ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    }
1687ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1697ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    seq_++;
1707ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    return true;
1717ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  }
1727ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1737ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe private:
1747ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  // Helper for the handler.
1757ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  HandlerFn GetResultHandler() {
1767ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe    return HandlerFn(std::bind(&ThreadedHandler::ResultHandler,
1777ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe                               this,
1787ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe                               std::placeholders::_1,
1797ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe                               std::placeholders::_2));
1807ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  }
1817ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1827ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  std::mutex lock_;
1837ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1847ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  std::unique_ptr<ThreadedConfig> cur_config_;
1857ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1867ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe  int seq_ = 0;
1877ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe};
1887ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1897ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe}  // namespace perfprofd
1907ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe}  // namespace android
1917ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe
1927ecfbe85850996b10463bedbfa2745cf3761182cAndreas Gampe#endif  // SYSTEM_EXTRAS_PERFPROFD_PERFPROFD_THREADED_HANDLER_H_
193