LCOV - code coverage report
Current view: top level - source/extensions/watchdog/profile_action - profile_action.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 55 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 4 0.0 %

          Line data    Source code
       1             : #include "source/extensions/watchdog/profile_action/profile_action.h"
       2             : 
       3             : #include <chrono>
       4             : 
       5             : #include "envoy/thread/thread.h"
       6             : 
       7             : #include "source/common/profiler/profiler.h"
       8             : #include "source/common/protobuf/utility.h"
       9             : #include "source/common/stats/symbol_table.h"
      10             : 
      11             : #include "absl/strings/str_format.h"
      12             : 
      13             : namespace Envoy {
      14             : namespace Extensions {
      15             : namespace Watchdog {
      16             : namespace ProfileAction {
      17             : namespace {
      18             : static constexpr uint64_t DefaultMaxProfiles = 10;
      19             : 
      20           0 : std::string generateProfileFilePath(const std::string& directory, TimeSource& time_source) {
      21           0 :   const uint64_t timestamp = DateUtil::nowToSeconds(time_source);
      22           0 :   if (absl::EndsWith(directory, "/")) {
      23           0 :     return absl::StrFormat("%s%s.%d", directory, "ProfileAction", timestamp);
      24           0 :   }
      25           0 :   return absl::StrFormat("%s/%s.%d", directory, "ProfileAction", timestamp);
      26           0 : }
      27             : } // namespace
      28             : 
      29             : ProfileAction::ProfileAction(
      30             :     envoy::extensions::watchdog::profile_action::v3::ProfileActionConfig& config,
      31             :     Server::Configuration::GuardDogActionFactoryContext& context)
      32             :     : path_(config.profile_path()),
      33             :       duration_(
      34             :           std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(config, profile_duration, 5000))),
      35             :       max_profiles_(config.max_profiles() == 0 ? DefaultMaxProfiles : config.max_profiles()),
      36             :       profiles_attempted_(context.stats_.counterFromStatName(
      37             :           Stats::StatNameManagedStorage(
      38             :               absl::StrCat(context.guarddog_name_, ".profile_action.attempted"),
      39             :               context.stats_.symbolTable())
      40             :               .statName())),
      41             :       profiles_successfully_captured_(context.stats_.counterFromStatName(
      42             :           Stats::StatNameManagedStorage(
      43             :               absl::StrCat(context.guarddog_name_, ".profile_action.successfully_captured"),
      44             :               context.stats_.symbolTable())
      45             :               .statName())),
      46           0 :       context_(context), timer_cb_(context_.dispatcher_.createTimer([this] {
      47           0 :         if (Profiler::Cpu::profilerEnabled()) {
      48           0 :           Profiler::Cpu::stopProfiler();
      49           0 :           running_profile_ = false;
      50           0 :         } else {
      51           0 :           ENVOY_LOG_MISC(error,
      52           0 :                          "Profile Action's stop() was scheduled, but profiler isn't running!");
      53           0 :           return;
      54           0 :         }
      55             : 
      56           0 :         if (!context_.api_.fileSystem().fileExists(profile_filename_)) {
      57           0 :           ENVOY_LOG_MISC(error, "Profile file {} wasn't created!", profile_filename_);
      58           0 :         } else {
      59           0 :           profiles_successfully_captured_.inc();
      60           0 :         }
      61           0 :       })) {}
      62             : 
      63             : void ProfileAction::run(
      64             :     envoy::config::bootstrap::v3::Watchdog::WatchdogAction::WatchdogEvent /*event*/,
      65             :     const std::vector<std::pair<Thread::ThreadId, MonotonicTime>>& thread_last_checkin_pairs,
      66           0 :     MonotonicTime /*now*/) {
      67           0 :   if (running_profile_) {
      68           0 :     return;
      69           0 :   }
      70           0 :   profiles_attempted_.inc();
      71             : 
      72             :   // Check if there's a tid that justifies profiling
      73           0 :   if (thread_last_checkin_pairs.empty()) {
      74           0 :     ENVOY_LOG_MISC(warn, "Profile Action: No tids were provided.");
      75           0 :     return;
      76           0 :   }
      77             : 
      78           0 :   if (profiles_started_ >= max_profiles_) {
      79           0 :     ENVOY_LOG_MISC(warn,
      80           0 :                    "Profile Action: Unable to profile: enabled but already wrote {} profiles.",
      81           0 :                    profiles_started_);
      82           0 :     return;
      83           0 :   }
      84             : 
      85           0 :   auto& fs = context_.api_.fileSystem();
      86           0 :   if (!fs.directoryExists(path_)) {
      87           0 :     ENVOY_LOG_MISC(error, "Profile Action: Directory path {} doesn't exist.", path_);
      88           0 :     return;
      89           0 :   }
      90             : 
      91             :   // Generate file path for output and try to profile
      92           0 :   profile_filename_ = generateProfileFilePath(path_, context_.api_.timeSource());
      93             : 
      94           0 :   if (!Profiler::Cpu::profilerEnabled()) {
      95           0 :     if (Profiler::Cpu::startProfiler(profile_filename_)) {
      96             :       // Update state
      97           0 :       running_profile_ = true;
      98           0 :       ++profiles_started_;
      99             : 
     100             :       // Schedule callback to stop
     101           0 :       timer_cb_->enableTimer(duration_);
     102           0 :     } else {
     103           0 :       ENVOY_LOG_MISC(error, "Profile Action failed to start the profiler.");
     104           0 :     }
     105           0 :   } else {
     106           0 :     ENVOY_LOG_MISC(error, "Profile Action unable to start the profiler as it is in use elsewhere.");
     107           0 :   }
     108           0 : }
     109             : 
     110             : } // namespace ProfileAction
     111             : } // namespace Watchdog
     112             : } // namespace Extensions
     113             : } // namespace Envoy

Generated by: LCOV version 1.15