Skip to content

[SYCL][UR][OpenCL] Fix profiling tag ordering on OpenCL GPU - #22641

Open
crystarm wants to merge 3 commits into
intel:syclfrom
crystarm:profiling-tag-opencl-timestamp-recording
Open

crystarm wants to merge 3 commits into
intel:syclfrom
crystarm:profiling-tag-opencl-timestamp-recording

Conversation

@crystarm

Copy link
Copy Markdown
Contributor

Related to #22229.

submit_profiling_tag returned timestamps in the wrong order on opencl:gpu: the end tag's command_end could be earlier than the completion of work submitted before it, so E2End <= EndTagEnd failed and the e2e tests were masked with UNSUPPORTED: opencl && gpu.

Why

OpenCL devices don't advertise ext_oneapi_queue_profiling_tag (the adapter hard-codes UR_DEVICE_INFO_TIMESTAMP_RECORDING_SUPPORT_EXP to false), so the tag fell back to ext_oneapi_submit_barrier() and read its profiling info straight off the barrier event.

The NEO driver timestamps clEnqueueBarrierWithWaitList / clEnqueueMarkerWithWaitList when the command enters the pipeline, not when the preceding work completes. So the barrier's CL_PROFILING_COMMAND_END can be earlier than the end of a kernel enqueued before it.

I confirmed this with a small pure-OpenCL reproducer on Intel Iris Xe (NEO 26.05.037020): any synchronization-only tag (barrier/marker, empty or explicit wait list) fails 100% of the time, while any real device command (kernel or buffer fill) gives correct timestamps - including a fill into a
dedicated buffer, which is what this PR does.

Changes

  • unified-runtime/.../opencl/event.cpp: implement urEnqueueTimestampRecordingExpusingclEnqueueFillBufferon a small internal buffer, whose timestamps do reflect completion of prior work. It needs command profiling, so if the queue isn't profiling-enabled we returnUR_RESULT_ERROR_UNSUPPORTED_FEATURE`.

  • unified-runtime/.../opencl/context.hpp: lazily-created, thread-safe 4-byte buffer per context, released with the context. It's never read - only the fill command's timestamps are used.

  • sycl/.../scheduler/commands.cpp (CGType::ProfilingTag): issue the recording with call_nocheck and fall back to a barrier on UR_RESULT_ERROR_UNSUPPORTED_FEATURE. Also addresses the existing TODO here.

  • sycl/.../experimental/profiling_tag.hpp: when the device lacks the aspect but the queue has profiling enabled, submit a profiling-tag command group (reusing the scheduler's in-order/out-of-order marker+barrier handling) instead of a bare barrier.

The device aspect stays false for OpenCL: the emulation needs queue profiling, but the aspect promises the tag works without it. Enabling the aspect (e.g. via an internal profiling queue) is a possible follow-up.

Level Zero / CUDA / HIP are unaffected - they advertise the aspect and already implement the recording, so they never take the fallback branch. The scheduler change only adds the fallback branch and turns a throwing call into a checked one; the success path is unchanged.

Testing

  • Unit tests (sycl/unittests/Extensions/ProfilingTag.cpp): split the old fallback test into two - native recording used on a profiling queue without the aspect, and the barrier fallback when the backend reports the recording unsupported.

  • E2E: dropped UNSUPPORTED: opencl && gpu from ProfilingTag/in_order_profiling_queue.cpp and ProfilingTag profiling_queue.cpp.

  • The reproducer's dedicated-buffer fill (matching this implementation) passes 200/200 iterations on Intel Iris Xe, vs. the old barrier fallback failing 200/200.

The NEO timestamping behavior is arguably a driver bug worth reporting separately; this is a runtime workaround that doesn't touch the public API or other backends.

P.S. I may have gone a little overboard with the code comments. If anyone else feels the same way, I will clean them up.

@crystarm
crystarm requested review from a team as code owners July 15, 2026 11:33
@crystarm
crystarm requested a review from againull July 15, 2026 11:33
@bratpiorka
bratpiorka requested a review from Copilot July 16, 2026 09:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes incorrect profiling-tag timestamp ordering on OpenCL GPUs by changing the Unified Runtime (UR) OpenCL adapter to record timestamps using a lightweight real device command (buffer fill) instead of synchronization-only commands whose profiling timestamps can be misordered on some drivers. This helps ensure profiling data ordering invariants hold and un-masks previously disabled SYCL ProfilingTag E2E coverage for opencl:gpu.

Changes:

  • Implement urEnqueueTimestampRecordingExp for OpenCL using clEnqueueFillBuffer on a lazily created per-context internal buffer (requires a profiling-enabled queue; otherwise reports unsupported).
  • Update SYCL scheduler ProfilingTag enqueue to attempt native timestamp recording via call_nocheck and fall back to a barrier on UR_RESULT_ERROR_UNSUPPORTED_FEATURE; update submit_profiling_tag() to route non-aspect + profiling-enabled queues through the internal profiling-tag CG path.
  • Split/adjust unit tests for both “timestamp recording works” and “timestamp recording unsupported → barrier fallback”, and re-enable OpenCL GPU E2E tests by removing the UNSUPPORTED lines.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
unified-runtime/source/adapters/opencl/event.cpp Implements OpenCL timestamp recording via a small buffer fill and requires queue profiling.
unified-runtime/source/adapters/opencl/context.hpp Adds lazy, thread-safe internal buffer storage to support the OpenCL timestamp emulation.
sycl/source/detail/scheduler/commands.cpp Uses non-throwing UR calls for timestamp recording with an explicit unsupported-feature fallback to a barrier.
sycl/include/sycl/ext/oneapi/experimental/profiling_tag.hpp Submits an internal profiling-tag CG when queue profiling is enabled even without the device aspect.
sycl/unittests/Extensions/ProfilingTag.cpp Expands unit tests to cover native timestamp path vs unsupported-feature barrier fallback.
sycl/test-e2e/ProfilingTag/profiling_queue.cpp Re-enables OpenCL GPU E2E coverage by removing the UNSUPPORTED directive.
sycl/test-e2e/ProfilingTag/in_order_profiling_queue.cpp Re-enables OpenCL GPU E2E coverage by removing the UNSUPPORTED directive.

Comment on lines +340 to +349
std::vector<cl_event> CLWaitEvents(numEventsInWaitList);
for (uint32_t I = 0; I < numEventsInWaitList; I++)
CLWaitEvents[I] = cast(phEventWaitList[I])->CLEvent;

const cl_uint Pattern = 0;
cl_event Event = nullptr;
CL_RETURN_ON_FAILURE(clEnqueueFillBuffer(
Queue->CLQueue, Buffer, &Pattern, sizeof(Pattern), /*offset=*/0,
/*size=*/sizeof(Pattern), numEventsInWaitList, CLWaitEvents.data(),
ifUrEvent(phEvent, Event)));
Comment on lines 75 to 83
for (uint32_t i = 0; i < DeviceCount; i++) {
ur::opencl::urDeviceRelease(cast(Devices[i]));
}
if (TimestampRecordingBuffer) {
clReleaseMemObject(TimestampRecordingBuffer);
}
if (IsNativeHandleOwned) {
clReleaseContext(CLContext);
}

@againull againull left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for delayed review, overall looks good, just few comments.

Comment on lines +3686 to +3697
if (!IsInOrderQueue)
Adapter.call<UrApiKind::urEventRelease>(PreTimestampMarkerEvent);
// A barrier with an empty wait list waits for all previously-submitted
// work and blocks subsequent work, providing the same ordering semantics
// as a native profiling tag.
if (auto Result =
Adapter.call_nocheck<UrApiKind::urEnqueueEventsWaitWithBarrier>(
MQueue->getHandleRef(),
/*num_events_in_wait_list=*/0,
/*event_wait_list=*/nullptr, Event);
Result != UR_RESULT_SUCCESS)
return Result;

@againull againull Jul 22, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's out-of-order queue, then we already have a barrier submitted before pre-timestamp, so we will submit barrier twice here.
Can we assign PreTimestampMarkerEvent to Event instead of releasing it and insert barrier under "else":

 if (!IsInOrderQueue) {
    // reuse PreTimestampMarkerEvent as output event
} else {
    // submit barrier
}

Comment on lines +3699 to +3700
if (TimestampResult != UR_RESULT_SUCCESS)
return TimestampResult;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to release PreTimestampMarkerEvent event under if (TimestampResult != UR_RESULT_SUCCESS) as well if it's out-of-order queue.
Ideally, we should use OwnedUrEvent from ur_utils.hpp so that release is handled automatically via raii.
But it probably requires a little extension of OwnedUrEvent like this:

  OwnedUrEvent &operator=(OwnedUrEvent &&Other) {
    if (this != &Other) {
      if (MEvent.has_value())
        MAdapter->call<UrApiKind::urEventRelease>(*MEvent);
      MEvent = Other.MEvent;
      MAdapter = Other.MAdapter;
      Other.MEvent = std::nullopt;
    }
    return *this;
  }
  OwnedUrEvent &operator=(const OwnedUrEvent &Other) = delete;

So I don't insist on doing it in this PR.

@bratpiorka

Copy link
Copy Markdown
Contributor

adapters/opencl LGTM but please apply copilot review feedback
Also, make sure to close #22229 after merge

@bratpiorka

Copy link
Copy Markdown
Contributor

@crystarm please rebase and resolve conflicts

@crystarm
crystarm force-pushed the profiling-tag-opencl-timestamp-recording branch from 85c9d4b to 2f969b5 Compare August 7, 2026 09:05
@crystarm

Copy link
Copy Markdown
Contributor Author

@bratpiorka
I've rebased the PR. When you have a chance, could you please take another look?

@crystarm
crystarm requested a review from againull August 23, 2026 12:20
@KornevNikita

Copy link
Copy Markdown
Contributor

@crystarm ProfilingTag/in_order_profiling_queue.cpp fails on native cpu

@crystarm

crystarm commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

@crystarm ProfilingTag/in_order_profiling_queue.cpp fails on native cpu

I'm sorry, I didn't notice that (ᵕ •_•)
I'll fix it asap

@crystarm

crystarm commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

@KornevNikita
The barrier fallback remained marked as a native profiling-tag event, so command_submit was queried from the Native CPU UR event, which does not support it. The fallback now uses the runtime-recorded submit timestamp, while successful timestamp-recording paths remain unchanged. Unit coverage was added as well.

I think it's gonna be all right now. Could you please approve the workflow?

@KornevNikita

Copy link
Copy Markdown
Contributor

@crystarm still fails

@crystarm
crystarm force-pushed the profiling-tag-opencl-timestamp-recording branch from 22ba5e9 to 020e26b Compare September 11, 2026 12:18
@crystarm

crystarm commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

@KornevNikita
Could you please approve the workflow again?

The previous fix switched command_submit to the runtime-recorded timestamp but incorrectly assumed it was already initialized, so CI returned zero. I now ensure the submission timestamp is recorded before submitting the fallback barrier and added regression coverage for this case.

I think it should FINALLY be cool now............. 😭😭😭🙏🙏🙏🙏

@crystarm

crystarm commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

I think it should FINALLY be cool now............. 😭😭😭🙏🙏🙏🙏

Well, it is not cool. I've no idea what else could be wrong, everything passed locally, including all Native CPU E2E test runs.

I'll keep looking into it.

@crystarm

crystarm commented Sep 13, 2026

Copy link
Copy Markdown
Contributor Author

#22810 changed profiling tag timestamp handling so that the runtime no longer initializes MSubmitTime for profiling tag events. Instead, native profiling tag implementations use a single device-recorded completion timestamp for all profiling queries.

The previous Native CPU fallback fix converted the fallback event into a regular profiling event and relied on MSubmitTime for command_submit. When CI tested it together with the current sycl branch, #22810 caused that field to remain zero.

When I created the original branch for this PR, #22810 was not yet part of sycl.

Merging the current sycl branch into it would introduce a merge commit and mix upstream history into the branch. Rebasing it would instead require rewriting the existing history and force-pushing the branch.

I wanted to keep the original branch intact, preserve the exact changes already reviewed and agreed upon with the maintainers, and avoid force-pushing anything.

So I created profiling-tag-opencl-timestamp-recording-v2 from the current sycl and reapplied the changes from the first two commits of this PR unchanged. I then added a separate fix for the Native CPU E2E failure, taking the profiling tag timestamp model introduced by #22810 into account.

The new fix keeps the fallback event marked as a profiling tag and uses its device-recorded completion timestamp for command_submit, command_start, and command_end.

The replacement branch is now available in #23153. If #23153 is accepted, this PR should be closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test-e2e/ProfilingTag/in_order_profiling_queue.cpp fails on opencl:gpu

5 participants