mirror of https://github.com/grpc/grpc.git
[debug] Fine grained event tracing (#31105)
* moved-from-stats * [debug] Fine grained event tracing * Automated change: Fix sanity tests * comment * Automated change: Fix sanity tests * iwyu * Automated change: Fix sanity tests Co-authored-by: ctiller <ctiller@users.noreply.github.com>pull/31058/head
parent
945fe012ed
commit
e8df8185e5
20 changed files with 306 additions and 0 deletions
@ -0,0 +1,89 @@ |
||||
// Copyright 2022 gRPC 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
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/debug/event_log.h" |
||||
|
||||
#include <algorithm> |
||||
#include <atomic> |
||||
#include <cstdint> |
||||
|
||||
#include "absl/strings/str_cat.h" |
||||
#include "absl/strings/str_join.h" |
||||
|
||||
#include <grpc/support/log.h> |
||||
|
||||
namespace grpc_core { |
||||
|
||||
std::atomic<EventLog*> EventLog::g_instance_{nullptr}; |
||||
|
||||
EventLog::~EventLog() { |
||||
GPR_ASSERT(g_instance_.load(std::memory_order_acquire) != this); |
||||
} |
||||
|
||||
void EventLog::BeginCollection() { |
||||
for (auto& fragment : fragments_) { |
||||
MutexLock lock(&fragment.mu); |
||||
fragment.entries.clear(); |
||||
} |
||||
collection_begin_ = gpr_get_cycle_counter(); |
||||
g_instance_.store(this, std::memory_order_release); |
||||
Append("logging", 1); |
||||
} |
||||
|
||||
std::vector<EventLog::Entry> EventLog::EndCollection( |
||||
absl::Span<const absl::string_view> wanted_events) { |
||||
Append("logging", -1); |
||||
g_instance_.store(nullptr, std::memory_order_release); |
||||
std::vector<Entry> result; |
||||
for (auto& fragment : fragments_) { |
||||
MutexLock lock(&fragment.mu); |
||||
for (const auto& entry : fragment.entries) { |
||||
if (std::find(wanted_events.begin(), wanted_events.end(), entry.event) != |
||||
wanted_events.end()) { |
||||
result.push_back(entry); |
||||
} |
||||
} |
||||
fragment.entries.clear(); |
||||
} |
||||
std::stable_sort( |
||||
result.begin(), result.end(), |
||||
[](const Entry& a, const Entry& b) { return a.when < b.when; }); |
||||
return result; |
||||
} |
||||
|
||||
void EventLog::AppendInternal(absl::string_view event, int64_t delta) { |
||||
auto& fragment = fragments_.this_cpu(); |
||||
MutexLock lock(&fragment.mu); |
||||
fragment.entries.push_back({gpr_get_cycle_counter(), event, delta}); |
||||
} |
||||
|
||||
std::string EventLog::EndCollectionAndReportCsv( |
||||
absl::Span<const absl::string_view> columns) { |
||||
auto events = EndCollection(columns); |
||||
std::vector<int64_t> values(columns.size(), 0); |
||||
std::string result = |
||||
absl::StrCat("timestamp,", absl::StrJoin(columns, ","), "\n"); |
||||
for (const auto& entry : events) { |
||||
auto idx = std::find(columns.begin(), columns.end(), entry.event) - |
||||
columns.begin(); |
||||
values[idx] += entry.delta; |
||||
absl::StrAppend(&result, entry.when - collection_begin_, ",", |
||||
absl::StrJoin(values, ","), "\n"); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
} // namespace grpc_core
|
@ -0,0 +1,81 @@ |
||||
// Copyright 2022 gRPC 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
|
||||
//
|
||||
// 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 GRPC_CORE_LIB_DEBUG_EVENT_LOG_H |
||||
#define GRPC_CORE_LIB_DEBUG_EVENT_LOG_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <stdint.h> |
||||
|
||||
#include <atomic> |
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include "absl/base/thread_annotations.h" |
||||
#include "absl/strings/string_view.h" |
||||
#include "absl/types/span.h" |
||||
|
||||
#include "src/core/lib/gpr/time_precise.h" |
||||
#include "src/core/lib/gprpp/per_cpu.h" |
||||
#include "src/core/lib/gprpp/sync.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
// Debug utility to collect a burst of events and then later log them as a
|
||||
// detailed sequence.
|
||||
// Collects (timestamp, counter-name, delta) and gives back a csv with
|
||||
// timestamps and accumulated values for each counter in separate columns.
|
||||
class EventLog { |
||||
public: |
||||
EventLog() = default; |
||||
~EventLog(); |
||||
|
||||
EventLog(const EventLog&) = delete; |
||||
EventLog& operator=(const EventLog&) = delete; |
||||
|
||||
void BeginCollection(); |
||||
std::string EndCollectionAndReportCsv( |
||||
absl::Span<const absl::string_view> columns); |
||||
|
||||
static void Append(absl::string_view event, int64_t delta) { |
||||
EventLog* log = g_instance_.load(std::memory_order_acquire); |
||||
if (log == nullptr) return; |
||||
log->AppendInternal(event, delta); |
||||
} |
||||
|
||||
private: |
||||
struct Entry { |
||||
gpr_cycle_counter when; |
||||
absl::string_view event; |
||||
int64_t delta; |
||||
}; |
||||
|
||||
struct Fragment { |
||||
Mutex mu; |
||||
std::vector<Entry> entries ABSL_GUARDED_BY(mu); |
||||
}; |
||||
|
||||
void AppendInternal(absl::string_view event, int64_t delta); |
||||
std::vector<Entry> EndCollection( |
||||
absl::Span<const absl::string_view> wanted_events); |
||||
|
||||
PerCpu<Fragment> fragments_; |
||||
gpr_cycle_counter collection_begin_; |
||||
static std::atomic<EventLog*> g_instance_; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif // GRPC_CORE_LIB_DEBUG_EVENT_LOG_H
|
@ -0,0 +1,46 @@ |
||||
// Copyright 2022 gRPC 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
|
||||
//
|
||||
// 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 GRPC_CORE_LIB_GPRPP_PER_CPU_H |
||||
#define GRPC_CORE_LIB_GPRPP_PER_CPU_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include <cstddef> |
||||
#include <memory> |
||||
|
||||
#include <grpc/support/cpu.h> |
||||
|
||||
#include "src/core/lib/iomgr/exec_ctx.h" |
||||
|
||||
namespace grpc_core { |
||||
|
||||
template <typename T> |
||||
class PerCpu { |
||||
public: |
||||
T& this_cpu() { return data_[ExecCtx::Get()->starting_cpu()]; } |
||||
|
||||
T* begin() { return data_.get(); } |
||||
T* end() { return data_.get() + cpus_; } |
||||
const T* begin() const { return data_.get(); } |
||||
const T* end() const { return data_.get() + cpus_; } |
||||
|
||||
private: |
||||
const size_t cpus_ = gpr_cpu_num_cores(); |
||||
std::unique_ptr<T[]> data_{new T[cpus_]}; |
||||
}; |
||||
|
||||
} // namespace grpc_core
|
||||
|
||||
#endif // GRPC_CORE_LIB_GPRPP_PER_CPU_H
|
Loading…
Reference in new issue