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