diff --git a/examples/parallel/README.md b/examples/parallel/README.md new file mode 100644 index 0000000..8a56ef1 --- /dev/null +++ b/examples/parallel/README.md @@ -0,0 +1,14 @@ +# parfor Example +This example can only run if Parallel Computing Toolbox is installed. It shows how to instrument a parfor loop using spans. parfor is a function in Parallel Computing Toolbox that implements a parallel for-loop. It performs its iterations in parallel by sending them to workers in a parallel pool. The instrumented code loops through a series of random matrices and compute their maximum eigenvalue. +* At the beginning of the first run, initialization is necessary to create and store a global tracer provider. +* Initialization is also necessary in the parfor block, as this code is run in separate workers and each worker needs to run the initialization during the first run. +* A span is created both before and inside the parfor block. +* To have all the spans form a single trace, context has to be passed explicitly into the parfor block. + +## Running the Example +1. Start an instance of [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector). +2. Start MATLAB. +3. Make sure Parallel Computing Toolbox is installed by typing the command "ver parallel". +3. Ensure the installation directory of OpenTelemetry-matlab is on the MATLAB path. +4. Run parfor\_example. By default, MATLAB automatically opens a parallel pool of workers on your local machine. +5. Run parfor\_example again. The second run should be faster than the first run because the parallel pool takes some time to start up. diff --git a/examples/parallel/parfor_example.m b/examples/parallel/parfor_example.m new file mode 100644 index 0000000..acf0baf --- /dev/null +++ b/examples/parallel/parfor_example.m @@ -0,0 +1,65 @@ +function a = parfor_example +% This example creates a trace through a parfor loop, by creating a span in +% each iteration and propagating context. +% +% Copyright 2024 The MathWorks, Inc. + +% initialize tracing +runOnce(@initTracer); + +% start the top level span and make it current +tr = opentelemetry.trace.getTracer("parfor_example"); +sp = startSpan(tr, "main function"); +scope = makeCurrent(sp); %#ok<*NASGU> + +n = 80; +A = 500; +a = zeros(1,n); % initialize the output +nworkers = 4; % maximum number of workers + +% propagate the current context by extracting and passing it in headers +carrier = opentelemetry.context.propagation.injectContext(); +headers = carrier.Headers; + +parfor (i = 1:n, nworkers) + % parfor block needs its own initialization + runOnce(@initTracer); + + % extract context from headers and make it current + carrier = opentelemetry.context.propagation.TextMapCarrier(headers); + newcontext = opentelemetry.context.propagation.extractContext(carrier); + scope_i = setCurrentContext(newcontext); + + % start a span for this iteration + tr_i = opentelemetry.trace.getTracer("parfor_example"); + sp_i = startSpan(tr_i, "Iteration" + i); + + % compute the maximum eigenvalue of a random matrix + a(i) = max(abs(eig(rand(A)))); + + % end the scope and the span + scope_i = []; + endSpan(sp_i); +end +end + +function initTracer +% set up global TracerProvider +resource = dictionary("service.name", "OpenTelemetry-Matlab_examples"); +tp = opentelemetry.sdk.trace.TracerProvider(... + opentelemetry.sdk.trace.SimpleSpanProcessor, Resource=resource); +setTracerProvider(tp); + +% set up global propagator +prop = opentelemetry.trace.propagation.TraceContextPropagator(); +setTextMapPropagator(prop); +end + +% This helper ensures the input function is only run once +function runOnce(fh) +persistent hasrun +if isempty(hasrun) + feval(fh); + hasrun = 1; +end +end