Skip to content

Commit c8e150c

Browse files
Merge branch 'main' into maxime/imm-cmd-list-support
2 parents 8370f2e + d06ba9d commit c8e150c

17 files changed

+517
-290
lines changed

cmake/match.py

Lines changed: 111 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -5,77 +5,132 @@
55
# See LICENSE.TXT
66
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
77

8-
# check if all lines match in a file
9-
# lines in a match file can contain regex inside of double curly braces {{}}
8+
# Check if all input file content matches match file content.
9+
# Lines in a match file can contain regex inside of double curly braces {{}}.
10+
# Regex patterns are limited to single line.
11+
#
12+
# List of available special tags:
13+
# {{OPT}} - makes content in the same line as the tag optional
14+
# {{IGNORE}} - ignores all content until the next successfully matched line or the end of the input
15+
# Special tags are mutually exclusive and are expected to be located at the start of a line.
16+
#
1017

18+
import os
1119
import sys
1220
import re
21+
from enum import Enum
1322

1423

1524
## @brief print the whole content of input and match files
16-
def print_content(input_lines, match_lines):
25+
def print_content(input_lines, match_lines, ignored_lines):
1726
print("--- Input Lines " + "-" * 64)
1827
print("".join(input_lines).strip())
1928
print("--- Match Lines " + "-" * 64)
2029
print("".join(match_lines).strip())
30+
print("--- Ignored Lines " + "-" * 62)
31+
print("".join(ignored_lines).strip())
2132
print("-" * 80)
2233

2334

24-
if len(sys.argv) != 3:
25-
print("Usage: python match.py <input_file> <match_file>")
26-
sys.exit(1)
27-
28-
input_file = sys.argv[1]
29-
match_file = sys.argv[2]
30-
31-
with open(input_file, 'r') as input, open(match_file, 'r') as match:
32-
input_lines = input.readlines()
33-
match_lines = match.readlines()
34-
35-
if len(match_lines) < len(input_lines):
36-
print(f"Match length < input length (input: {len(input_lines)}, match: {len(match_lines)})")
37-
print_content(input_lines, match_lines)
38-
sys.exit(1)
39-
40-
input_idx = 0
41-
opt = "{{OPT}}"
42-
for i, match_line in enumerate(match_lines):
43-
if match_line.startswith(opt):
44-
optional_line = True
45-
match_line = match_line[len(opt):]
46-
else:
47-
optional_line = False
48-
49-
# split into parts at {{ }}
50-
match_parts = re.split(r'\{{(.*?)\}}', match_line.strip())
51-
pattern = ""
52-
for j, part in enumerate(match_parts):
53-
if j % 2 == 0:
54-
pattern += re.escape(part)
55-
else:
56-
pattern += part
35+
## @brief print the incorrect match line
36+
def print_incorrect_match(match_line, present, expected):
37+
print("Line " + str(match_line) + " does not match")
38+
print("is: " + present)
39+
print("expected: " + expected)
5740

58-
# empty input file or end of input file, from now on match file must be optional
59-
if not input_lines:
60-
if optional_line is True:
61-
continue
62-
else:
63-
print("End of input file or empty file.")
64-
print("expected: " + match_line.strip())
41+
42+
## @brief pattern matching script status values
43+
class Status(Enum):
44+
INPUT_END = 1
45+
MATCH_END = 2
46+
INPUT_AND_MATCH_END = 3
47+
PROCESSING = 4
48+
49+
50+
## @brief check matching script status
51+
def check_status(input_lines, match_lines):
52+
if not input_lines and not match_lines:
53+
return Status.INPUT_AND_MATCH_END
54+
elif not input_lines:
55+
return Status.INPUT_END
56+
elif not match_lines:
57+
return Status.MATCH_END
58+
return Status.PROCESSING
59+
60+
61+
## @brief pattern matching tags.
62+
## Tags are expected to be at the start of the line.
63+
class Tag(Enum):
64+
OPT = "{{OPT}}" # makes the line optional
65+
IGNORE = "{{IGNORE}}" # ignores all input until next match or end of input file
66+
67+
68+
## @brief main function for the match file processing script
69+
def main():
70+
if len(sys.argv) != 3:
71+
print("Usage: python match.py <input_file> <match_file>")
72+
sys.exit(1)
73+
74+
input_file = sys.argv[1]
75+
match_file = sys.argv[2]
76+
77+
with open(input_file, 'r') as input, open(match_file, 'r') as match:
78+
input_lines = input.readlines()
79+
match_lines = match.readlines()
80+
81+
ignored_lines = []
82+
83+
input_idx = 0
84+
match_idx = 0
85+
tags_in_effect = []
86+
while True:
87+
# check file status
88+
status = check_status(input_lines[input_idx:], match_lines[match_idx:])
89+
if (status == Status.INPUT_AND_MATCH_END) or (status == Status.MATCH_END and Tag.IGNORE in tags_in_effect):
90+
# all lines matched or the last line in match file is an ignore tag
91+
sys.exit(0)
92+
elif status == Status.MATCH_END:
93+
print_incorrect_match(match_idx + 1, input_lines[input_idx].strip(), "");
94+
print_content(input_lines, match_lines, ignored_lines)
6595
sys.exit(1)
6696

67-
input_line = input_lines[input_idx].strip()
68-
if not re.fullmatch(pattern, input_line):
69-
if optional_line is True:
70-
continue
97+
input_line = input_lines[input_idx].strip() if input_idx < len(input_lines) else ""
98+
match_line = match_lines[match_idx]
99+
100+
# check for tags
101+
if match_line.startswith(Tag.OPT.value):
102+
tags_in_effect.append(Tag.OPT)
103+
match_line = match_line[len(Tag.OPT.value):]
104+
elif match_line.startswith(Tag.IGNORE.value):
105+
tags_in_effect.append(Tag.IGNORE)
106+
match_idx += 1
107+
continue # line with ignore tag should be skipped
108+
109+
# split into parts at {{ }}
110+
match_parts = re.split(r'\{{(.*?)\}}', match_line.strip())
111+
pattern = ""
112+
for j, part in enumerate(match_parts):
113+
if j % 2 == 0:
114+
pattern += re.escape(part)
115+
else:
116+
pattern += part
117+
118+
# match or process tags
119+
if re.fullmatch(pattern, input_line):
120+
input_idx += 1
121+
match_idx += 1
122+
tags_in_effect = []
123+
elif Tag.OPT in tags_in_effect:
124+
match_idx += 1
125+
tags_in_effect.remove(Tag.OPT)
126+
elif Tag.IGNORE in tags_in_effect:
127+
ignored_lines.append(input_line + os.linesep)
128+
input_idx += 1
71129
else:
72-
print("Line " + str(i+1) + " does not match")
73-
print("is: " + input_line)
74-
print("expected: " + match_line.strip())
75-
print_content(input_lines, match_lines)
130+
print_incorrect_match(match_idx + 1, input_line, match_line.strip())
131+
print_content(input_lines, match_lines, ignored_lines)
76132
sys.exit(1)
77-
else:
78-
if (input_idx == len(input_lines) - 1):
79-
input_lines = []
80-
else:
81-
input_idx += 1
133+
134+
135+
if __name__ == "__main__":
136+
main()

source/adapters/level_zero/command_buffer.cpp

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,13 @@
4545
│ Prefix │ Commands added to UR command-buffer by UR user │ Suffix │
4646
└──────────┴────────────────────────────────────────────────┴─────────┘
4747
48-
┌───────────────────┬──────────────────────────────┐
49-
Prefix │Reset signal event │ Barrier waiting on wait event│
50-
└───────────────────┴──────────────────────────────┘
48+
┌───────────────────┬──────────────┐──────────────────────────────┐
49+
Prefix │Reset signal event │ Reset events │ Barrier waiting on wait event│
50+
└───────────────────┴──────────────┘──────────────────────────────┘
5151
5252
┌─────────────────────────────────────────────┐──────────────┐
53-
Suffix │Barrier waiting on sync-point event, │ Reset events
54-
│signalling the UR command-buffer signal event│
53+
Suffix │Barrier waiting on sync-point event, │ Query CMD
54+
│signalling the UR command-buffer signal event│ Timestamps
5555
└─────────────────────────────────────────────┘──────────────┘
5656
5757
For a call to `urCommandBufferEnqueueExp` with an event_list `EL`,
@@ -431,6 +431,10 @@ urCommandBufferCreateExp(ur_context_handle_t Context, ur_device_handle_t Device,
431431

432432
ZeStruct<ze_command_list_desc_t> ZeCommandListDesc;
433433
ZeCommandListDesc.commandQueueGroupOrdinal = QueueGroupOrdinal;
434+
// Dependencies between commands are explicitly enforced by sync points when
435+
// enqueuing. Consequently, relax the command ordering in the command list
436+
// can enable the backend to further optimize the workload
437+
ZeCommandListDesc.flags = ZE_COMMAND_LIST_FLAG_RELAXED_ORDERING;
434438

435439
ze_command_list_handle_t ZeCommandList;
436440
// TODO We could optimize this by pooling both Level Zero command-lists and UR
@@ -491,18 +495,6 @@ urCommandBufferFinalizeExp(ur_exp_command_buffer_handle_t CommandBuffer) {
491495
(CommandBuffer->ZeCommandList, CommandBuffer->SignalEvent->ZeEvent,
492496
NumEvents, WaitEventList.data()));
493497

494-
// Reset the wait-event for the UR command-buffer that is signalled when its
495-
// submission dependencies have been satisfied.
496-
ZE2UR_CALL(zeCommandListAppendEventReset,
497-
(CommandBuffer->ZeCommandList, CommandBuffer->WaitEvent->ZeEvent));
498-
499-
// Reset the L0 events we use for command-buffer internal sync-points to the
500-
// non-signalled state
501-
for (auto Event : WaitEventList) {
502-
ZE2UR_CALL(zeCommandListAppendEventReset,
503-
(CommandBuffer->ZeCommandList, Event));
504-
}
505-
506498
// Close the command list and have it ready for dispatch.
507499
ZE2UR_CALL(zeCommandListClose, (CommandBuffer->ZeCommandList));
508500
return UR_RESULT_SUCCESS;
@@ -876,6 +868,24 @@ UR_APIEXPORT ur_result_t UR_APICALL urCommandBufferEnqueueExp(
876868

877869
// Create command-list to execute before `CommandListPtr` and will signal
878870
// when `EventWaitList` dependencies are complete.
871+
ur_command_list_ptr_t WaitCommandList{};
872+
UR_CALL(Queue->Context->getAvailableCommandList(Queue, WaitCommandList, false,
873+
false));
874+
875+
// Create a list of events of all the events that compose the command buffer
876+
// workload.
877+
// This loop also resets the L0 events we use for command-buffer internal
878+
// sync-points to the non-signalled state.
879+
// This is required for multiple submissions.
880+
const size_t NumEvents = CommandBuffer->SyncPoints.size();
881+
std::vector<ze_event_handle_t> WaitEventList{NumEvents};
882+
for (size_t i = 0; i < NumEvents; i++) {
883+
auto ZeEvent = CommandBuffer->SyncPoints[i]->ZeEvent;
884+
WaitEventList[i] = ZeEvent;
885+
ZE2UR_CALL(zeCommandListAppendEventReset,
886+
(WaitCommandList->first, ZeEvent));
887+
}
888+
879889
bool MustSignalWaitEvent = true;
880890
if (NumEventsInWaitList) {
881891
_ur_ze_event_list_t TmpWaitList;
@@ -890,10 +900,6 @@ UR_APIEXPORT ur_result_t UR_APICALL urCommandBufferEnqueueExp(
890900
CommandBuffer->WaitEvent->WaitList.insert(TmpWaitList);
891901

892902
if (!CommandBuffer->WaitEvent->WaitList.isEmpty()) {
893-
ur_command_list_ptr_t WaitCommandList{};
894-
UR_CALL(Queue->Context->getAvailableCommandList(Queue, WaitCommandList,
895-
false, false))
896-
897903
ZE2UR_CALL(zeCommandListAppendBarrier,
898904
(WaitCommandList->first, CommandBuffer->WaitEvent->ZeEvent,
899905
CommandBuffer->WaitEvent->WaitList.Length,
@@ -916,22 +922,50 @@ UR_APIEXPORT ur_result_t UR_APICALL urCommandBufferEnqueueExp(
916922

917923
// Execution event for this enqueue of the UR command-buffer
918924
ur_event_handle_t RetEvent{};
919-
if (Event) {
920-
// Create a command-list to signal RetEvent on completion
921-
ur_command_list_ptr_t SignalCommandList{};
922-
UR_CALL(Queue->Context->getAvailableCommandList(Queue, SignalCommandList,
923-
false, false));
924925

926+
// Create a command-list to signal RetEvent on completion
927+
ur_command_list_ptr_t SignalCommandList{};
928+
UR_CALL(Queue->Context->getAvailableCommandList(Queue, SignalCommandList,
929+
false, false));
930+
// Reset the wait-event for the UR command-buffer that is signalled when its
931+
// submission dependencies have been satisfied.
932+
ZE2UR_CALL(zeCommandListAppendEventReset,
933+
(SignalCommandList->first, CommandBuffer->WaitEvent->ZeEvent));
934+
935+
if (Event) {
925936
UR_CALL(createEventAndAssociateQueue(Queue, &RetEvent,
926937
UR_COMMAND_COMMAND_BUFFER_ENQUEUE_EXP,
927938
SignalCommandList, false, true));
928939

929-
ZE2UR_CALL(zeCommandListAppendBarrier,
930-
(SignalCommandList->first, RetEvent->ZeEvent, 1,
931-
&(CommandBuffer->SignalEvent->ZeEvent)));
932-
Queue->executeCommandList(SignalCommandList, false, false);
940+
if ((Queue->Properties & UR_QUEUE_FLAG_PROFILING_ENABLE)) {
941+
// Multiple submissions of a command buffer implies that we need to save
942+
// the event timestamps before resubmiting the command buffer. We
943+
// therefore copy the these timestamps in a dedicated USM memory section
944+
// before completing the command buffer execution, and then attach this
945+
// memory to the event returned to users to allow to allow the profiling
946+
// engine to recover these timestamps.
947+
command_buffer_profiling_t *Profiling = new command_buffer_profiling_t();
948+
949+
Profiling->NumEvents = WaitEventList.size();
950+
Profiling->Timestamps =
951+
new ze_kernel_timestamp_result_t[Profiling->NumEvents];
952+
953+
ZE2UR_CALL(zeCommandListAppendQueryKernelTimestamps,
954+
(SignalCommandList->first, WaitEventList.size(),
955+
WaitEventList.data(), (void *)Profiling->Timestamps, 0,
956+
RetEvent->ZeEvent, 1,
957+
&(CommandBuffer->SignalEvent->ZeEvent)));
958+
959+
RetEvent->CommandData = static_cast<void *>(Profiling);
960+
} else {
961+
ZE2UR_CALL(zeCommandListAppendBarrier,
962+
(SignalCommandList->first, RetEvent->ZeEvent, 1,
963+
&(CommandBuffer->SignalEvent->ZeEvent)));
964+
}
933965
}
934966

967+
Queue->executeCommandList(SignalCommandList, false, false);
968+
935969
if (Event) {
936970
*Event = RetEvent;
937971
}

source/adapters/level_zero/command_buffer.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
#include "context.hpp"
2020
#include "queue.hpp"
2121

22+
struct command_buffer_profiling_t {
23+
ur_exp_command_buffer_sync_point_t NumEvents;
24+
ze_kernel_timestamp_result_t *Timestamps;
25+
};
26+
2227
struct ur_exp_command_buffer_handle_t_ : public _ur_object {
2328
ur_exp_command_buffer_handle_t_(ur_context_handle_t Context,
2429
ur_device_handle_t Device,

0 commit comments

Comments
 (0)