-
Notifications
You must be signed in to change notification settings - Fork 443
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into nonrecordable-span
- Loading branch information
Showing
9 changed files
with
346 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
project(etw_threadpool) | ||
|
||
add_executable(etw_threadpool main.cc) | ||
|
||
target_link_libraries(etw_threadpool ${CMAKE_THREAD_LIBS_INIT} | ||
opentelemetry_api opentelemetry_exporter_etw) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# ETW Exporter multithreaded context propagation example | ||
|
||
## Preface | ||
|
||
This example shows how to pass context from main dispatcher thread to worker threads. | ||
While this example is convenient to run in Visual Studio with ETW exporter, the same | ||
logic should apply to any other exporter. Only the initial portion that obtains ETW | ||
Tracer is unique to ETW, the rest can be reused. | ||
|
||
## How to debug events in Visual Studio 2019 or newer | ||
|
||
Specify your component instrumentation name, which should match the destination ETW | ||
Provider Name or GUID. Example uses "OpenTelemetry-ETW-TLD" for the instrument / | ||
instrumentation name. | ||
|
||
In Visual Studio IDE: | ||
|
||
- navigate to `View -> Other Windows -> Diagnostic Events...` | ||
- click `Configure...` gear on top. | ||
- specify `OpenTelemetry-ETW-TLD` in the list of providers to monitor. | ||
- run example. | ||
- `Diagnostic Events` view shows you the event flow in realtime. | ||
|
||
## Explanation of the code flow | ||
|
||
`main` function acts as a dispatcher to manage thread pool called `pool`. `beep_bop` | ||
span is started in the `main`. Then in a loop up to `kMaxThreads` get started | ||
concurrently. Each thread executing `beep` function with a parent scope of `main`. | ||
`beep` subsequently calls into `bop` function, with a parent scope of `beep` span. | ||
Entire execution of all threads is grouped under the main span called `beep_bop`. | ||
At the end of execution, the `main` function joins all pending threads and ends | ||
the main span. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
// Copyright The OpenTelemetry Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
// Include common Trace Provider API and processor | ||
#include "opentelemetry/sdk/trace/simple_processor.h" | ||
#include "opentelemetry/sdk/trace/tracer_provider.h" | ||
#include "opentelemetry/trace/provider.h" | ||
|
||
#include "opentelemetry/exporters/etw/etw_tracer_exporter.h" | ||
|
||
#include <iostream> | ||
#include <thread> | ||
|
||
#include <cstdio> | ||
#ifndef LOG_DEBUG | ||
# include <mutex> | ||
|
||
/** | ||
* @brief Thread-safe logger routine. | ||
* @param format | ||
* @param args | ||
* @return | ||
*/ | ||
static inline int log_vprintf(const char *format, va_list args) | ||
{ | ||
static std::mutex cout_mutex; | ||
std::lock_guard<std::mutex> lk(cout_mutex); | ||
return vprintf(format, args); | ||
}; | ||
|
||
/** | ||
* @brief Thread-safe logger routine. | ||
* @param format | ||
* @param | ||
* @return | ||
*/ | ||
static inline int log_printf(const char *format, ...) | ||
{ | ||
int result; | ||
va_list ap; | ||
va_start(ap, format); | ||
result = log_vprintf(format, ap); | ||
va_end(ap); | ||
return result; | ||
}; | ||
|
||
// Debug macros | ||
# define LOG_DEBUG(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) | ||
# define LOG_TRACE(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) | ||
# define LOG_INFO(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) | ||
# define LOG_WARN(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) | ||
# define LOG_ERROR(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) | ||
#endif | ||
|
||
using namespace OPENTELEMETRY_NAMESPACE; | ||
|
||
using namespace opentelemetry::exporter::etw; | ||
|
||
// Specify destination ETW Provider Name or GUID. | ||
// | ||
// In Visual Studio: | ||
// - View -> Other Windows -> Diagnostic Events... | ||
// - Click Configure (gear on top). | ||
// - Specify "OpenTelemetry-ETW-TLD" in the list of providers. | ||
// | ||
// Event view shows event flow in realtime. | ||
const char *kGlobalProviderName = "OpenTelemetry-ETW-TLD"; | ||
|
||
std::string providerName = kGlobalProviderName; | ||
|
||
// One provider can be used to associate with different destinations. | ||
exporter::etw::TracerProvider provider; | ||
|
||
// Code below is generic and may be reused with any other TracerProvider. | ||
// In ETW provider case - instrumentation name must match destination | ||
// ETW provider name. | ||
nostd::shared_ptr<trace::Tracer> tracer = provider.GetTracer(providerName, "1.0"); | ||
|
||
// Obtain numeric thread id | ||
static inline uint64_t gettid() | ||
{ | ||
std::stringstream ss; | ||
ss << std::this_thread::get_id(); | ||
uint64_t id = std::stoull(ss.str()); | ||
return id; | ||
} | ||
|
||
// bop gets called by beep. | ||
void bop() | ||
{ | ||
LOG_TRACE("bop worker tid=%u", gettid()); | ||
auto span = tracer->StartSpan("bop"); | ||
span->AddEvent("BopEvent", {{"tid", gettid()}}); | ||
span->SetAttribute("attrib", 2); | ||
span->End(); | ||
} | ||
|
||
// beep gets called in its own thread. | ||
// It is running in a thread pool, invoked via lambda by dispatcher. | ||
void beep() | ||
{ | ||
LOG_TRACE("beep worker tid=%u", gettid()); | ||
auto span = tracer->StartSpan("beep"); | ||
span->AddEvent("BeepEvent", {{"tid", gettid()}}); | ||
span->SetAttribute("attrib", 1); | ||
{ | ||
auto bopScope = tracer->WithActiveSpan(span); | ||
bop(); | ||
} | ||
span->End(); | ||
} | ||
|
||
// Max number of threads to spawn | ||
constexpr int kMaxThreads = 10; | ||
|
||
int main(int arc, char **argv) | ||
{ | ||
std::thread pool[kMaxThreads]; | ||
|
||
// Main dispatcher span: parent of all child thread spans. | ||
auto mainSpan = tracer->StartSpan("beep_bop"); | ||
mainSpan->SetAttribute("attrib", 0); | ||
|
||
// Start several threads to perform beep-bop actions. | ||
LOG_TRACE("beep-boop dispatcher tid=%u", gettid()); | ||
for (auto i = 0; i < kMaxThreads; i++) | ||
{ | ||
pool[i] = std::thread([&]() { | ||
// This code runs in its own worker thread. | ||
auto beepScope = tracer->WithActiveSpan(mainSpan); | ||
// call beep -> bop | ||
beep(); | ||
}); | ||
}; | ||
|
||
// Join all worker threads in the pool | ||
for (auto &th : pool) | ||
{ | ||
try | ||
{ | ||
if (th.joinable()) | ||
th.join(); | ||
} | ||
catch (...) | ||
{ | ||
// thread might have been gracefully terminated already | ||
} | ||
} | ||
|
||
// End span | ||
mainSpan->End(); | ||
|
||
return 0; | ||
} |
Oops, something went wrong.