-
Notifications
You must be signed in to change notification settings - Fork 14.3k
WIP: [Offload] Add testing for Offload program and kernel related entry points #127803
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
7cbe788
73ed36a
be5c36b
f6430fe
fb8a1cc
df9eb3e
71326ae
81bd646
8539184
20acc17
3423f70
44122e1
2aea022
5c121fa
3fbdf61
0ca7527
df52c01
edc79cb
7443873
9e56ad3
d3effbd
7afee0f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
//===-- Enqueue.td - Enqueue definitions for Offload -------*- tablegen -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file contains Offload API definitions related to enqueable operations | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
def : Function { | ||
let name = "olEnqueueMemcpy"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to be specific about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Off the top of my head I can't think of an reason why we couldn't make the queue handles optional. In UR we have optional handles, and don't hide the fact that they're pointers so they can be set to null. But if we want to avoid that then I can make the change to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer |
||
let desc = "Enqueue a memcpy operation."; | ||
let details = [ | ||
"For host pointers, use the device returned by olGetHostDevice", | ||
"At least one device must be a non-host device" | ||
]; | ||
let params = [ | ||
Param<"ol_queue_handle_t", "Queue", "handle of the queue", PARAM_IN>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't decide if I like the stream at the beginning or the end, but whatever we do it should be a consistent convention. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The queue is the first param in every function except |
||
Param<"void*", "DstPtr", "pointer to copy to", PARAM_IN>, | ||
Param<"ol_device_handle_t", "DstDevice", "device that DstPtr belongs to", PARAM_IN>, | ||
Param<"void*", "SrcPtr", "pointer to copy from", PARAM_IN>, | ||
Param<"ol_device_handle_t", "SrcDevice", "device that SrcPtr belongs to", PARAM_IN>, | ||
Param<"size_t", "Size", "size in bytes of data to copy", PARAM_IN>, | ||
Param<"ol_event_handle_t*", "EventOut", "optional recorded event for the enqueued operation", PARAM_OUT_OPTIONAL> | ||
]; | ||
let returns = [ | ||
Return<"OL_ERRC_INVALID_SIZE", ["`Size == 0`"]> | ||
]; | ||
} | ||
|
||
def : Struct { | ||
let name = "ol_kernel_launch_size_args_t"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing dynamic memory and other stuff, but since this is a struct we can always widen it. |
||
let desc = "Size-related arguments for a kernel launch."; | ||
let members = [ | ||
StructMember<"size_t", "Dimensions", "Number of work dimensions">, | ||
StructMember<"size_t", "NumGroupsX", "Number of work groups on the X dimension">, | ||
StructMember<"size_t", "NumGroupsY", "Number of work groups on the Y dimension">, | ||
StructMember<"size_t", "NumGroupsZ", "Number of work groups on the Z dimension">, | ||
StructMember<"size_t", "GroupSizeX", "Size of a work group on the X dimension.">, | ||
StructMember<"size_t", "GroupSizeY", "Size of a work group on the Y dimension.">, | ||
StructMember<"size_t", "GroupSizeZ", "Size of a work group on the Z dimension."> | ||
]; | ||
} | ||
|
||
def : Function { | ||
let name = "olEnqueueKernelLaunch"; | ||
let desc = "Enqueue a kernel launch with the specified size and parameters"; | ||
let details = []; | ||
let params = [ | ||
Param<"ol_queue_handle_t", "Queue", "handle of the queue", PARAM_IN>, | ||
Param<"ol_kernel_handle_t", "Kernel", "handle of the kernel", PARAM_IN>, | ||
Param<"const void*", "ArgumentsData", "pointer to the kernel argument struct", PARAM_IN>, | ||
Param<"size_t", "ArgumentsSize", "size of the kernel argument struct", PARAM_IN>, | ||
Param<"const ol_kernel_launch_size_args_t*", "LaunchSizeArgs", "pointer to the struct containing launch size parameters", PARAM_IN>, | ||
Param<"ol_event_handle_t*", "EventOut", "optional recorded event for the enqueued operation", PARAM_OUT_OPTIONAL> | ||
]; | ||
let returns = []; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
//===-- Event.td - Event definitions for Offload -----------*- tablegen -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file contains Offload API definitions related to the event handle | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
def : Function { | ||
let name = "olRetainEvent"; | ||
let desc = "Increment the event's reference count"; | ||
let details = []; | ||
let params = [ | ||
Param<"ol_event_handle_t", "Event", "handle of the event", PARAM_IN> | ||
]; | ||
let returns = []; | ||
} | ||
|
||
def : Function { | ||
let name = "olReleaseEvent"; | ||
let desc = "Decrement the event's reference count, and free it if the reference count reaches 0"; | ||
let details = []; | ||
let params = [ | ||
Param<"ol_event_handle_t", "Event", "handle of the event", PARAM_IN> | ||
]; | ||
let returns = []; | ||
} | ||
|
||
def : Function { | ||
let name = "olWaitEvent"; | ||
let desc = "Wait for the event to be complete"; | ||
let details = []; | ||
let params = [ | ||
Param<"ol_event_handle_t", "Event", "handle of the event", PARAM_IN> | ||
]; | ||
let returns = []; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
//===-- Kernel.td - Kernel definitions for Offload ---------*- tablegen -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file contains Offload API definitions related to the kernel handle | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
def : Function { | ||
let name = "olCreateKernel"; | ||
let desc = "Create a kernel from the function identified by `KernelName` in the given program"; | ||
let details = [ | ||
"The created kernel has an initial reference count of 1." | ||
]; | ||
let params = [ | ||
Param<"ol_program_handle_t", "Program", "handle of the program", PARAM_IN>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We likely need to make a distinction between an ELF image in host memory and a loaded image with an address on the GPU, HSA does that with some sort of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have that distinction in UR too, loading it on creation was just slightly easier with how the plugins work now. I can see if I can pull some stuff out into a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be nice to expose a read / write on the image before it's loaded, since that's what the image access lets us do. It's a very fast way to initialize globals. I'll need to fix up some of the image handling in the plugins, right now it's really, really bad about managing lifetimes, just copying a pointer and assuming that the data lives forever (Even after global destructors have run). |
||
Param<"const char*", "KernelName", "name of the kernel entry point in the program", PARAM_IN>, | ||
Param<"ol_kernel_handle_t*", "Kernel", "output pointer for the created kernel", PARAM_OUT> | ||
]; | ||
let returns = []; | ||
} | ||
|
||
def : Function { | ||
let name = "olRetainKernel"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need a reference count on the kernel? It's just a pointer to some global in the image the user gave. I'd just prefer an API that lets users get the address of a global and then get returned some information about the global like its size, whether it's a kernel, etc. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a consequence of the ability to set individual (or all) kernel arguments on a kernel object. With that, the kernel becomes the global address + whatever argument state the user has set, which necessitates tracking this state. If we go the direction of passing arguments at the time of a kernel launch then we can drop all this. |
||
let desc = "Increment the kernel's reference count"; | ||
let details = []; | ||
let params = [ | ||
Param<"ol_kernel_handle_t", "Kernel", "handle of the kernel", PARAM_IN> | ||
]; | ||
let returns = []; | ||
} | ||
|
||
def : Function { | ||
let name = "olReleaseKernel"; | ||
let desc = "Decrement the kernel's reference count, and free it if the reference count reaches 0"; | ||
let details = []; | ||
let params = [ | ||
Param<"ol_kernel_handle_t", "Kernel", "handle of the kernel", PARAM_IN> | ||
]; | ||
let returns = []; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
//===-- Memory.td - Memory definitions for Offload ---------*- tablegen -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file contains Offload API definitions related to memory allocations | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
def : Enum { | ||
let name = "ol_alloc_type_t"; | ||
let desc = "Represents the type of allocation made with olMemAlloc"; | ||
let etors = [ | ||
Etor<"HOST", "Host allocation">, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These names honestly suck (I know they came from the plugin), we should think up some better ones but that's an issue for another day. |
||
Etor<"DEVICE", "Device allocation">, | ||
Etor<"SHARED", "Shared allocation"> | ||
]; | ||
} | ||
|
||
def : Function { | ||
let name = "olMemAlloc"; | ||
let desc = "Creates a memory allocation on the specified device"; | ||
let params = [ | ||
Param<"ol_device_handle_t", "Device", "handle of the device to allocate on", PARAM_IN>, | ||
Param<"ol_alloc_type_t", "Type", "type of the allocation", PARAM_IN>, | ||
Param<"size_t", "Size", "size of the allocation in bytes", PARAM_IN>, | ||
Param<"void**", "AllocationOut", "output for the allocated pointer", PARAM_OUT> | ||
]; | ||
let returns = [ | ||
Return<"OL_ERRC_INVALID_SIZE", [ | ||
"`Size == 0`" | ||
]> | ||
]; | ||
} | ||
|
||
def : Function { | ||
let name = "olMemFree"; | ||
let desc = "Frees a memory allocation previously made by olMemAlloc"; | ||
let params = [ | ||
Param<"ol_device_handle_t", "Device", "handle of the device to allocate on", PARAM_IN>, | ||
Param<"ol_alloc_type_t", "Type", "type of the allocation", PARAM_IN>, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Undecided on forcing the user to track the allocation kind. I know CUDA does it with host/mem stuff. But I wonder if it's restrictively expensive to just put that in a hashmap somewhere in the API. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fully agree with this, and actually I don't know if a hashmap is really necessary. On CUDA we can use |
||
Param<"void*", "Address", "address of the allocation to free", PARAM_IN>, | ||
]; | ||
let returns = []; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
//===-- Program.td - Program definitions for Offload -------*- tablegen -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file contains Offload API definitions related to the program handle | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
def : Function { | ||
let name = "olCreateProgram"; | ||
let desc = "Create a program for the device from the binary image pointed to by `ProgData`"; | ||
let details = [ | ||
"The created program has an initial reference count of 1." | ||
]; | ||
let params = [ | ||
Param<"ol_device_handle_t", "Device", "handle of the device", PARAM_IN>, | ||
Param<"void*", "ProgData", "pointer to the program binary data", PARAM_IN>, | ||
Param<"size_t", "ProgDataSize", "size of the program binary in bytes", PARAM_IN>, | ||
Param<"ol_program_handle_t*", "Program", "output pointer for the created program", PARAM_OUT> | ||
]; | ||
let returns = []; | ||
} | ||
|
||
def : Function { | ||
let name = "olRetainProgram"; | ||
let desc = "Increment the program's reference count"; | ||
let details = []; | ||
let params = [ | ||
Param<"ol_program_handle_t", "Program", "handle of the program", PARAM_IN> | ||
]; | ||
let returns = []; | ||
} | ||
|
||
def : Function { | ||
let name = "olReleaseProgram"; | ||
let desc = "Decrement the program's reference count, and free it if the reference count reaches 0"; | ||
let details = []; | ||
let params = [ | ||
Param<"ol_program_handle_t", "Program", "handle of the program", PARAM_IN> | ||
]; | ||
let returns = []; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
//===-- Queue.td - Queue definitions for Offload -----------*- tablegen -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file contains Offload API definitions related to the queue handle | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
def : Function { | ||
let name = "olCreateQueue"; | ||
let desc = "Create a queue for the given device"; | ||
let details = [ | ||
"The created queue has an initial reference count of 1." | ||
]; | ||
let params = [ | ||
Param<"ol_device_handle_t", "Device", "handle of the device", PARAM_IN>, | ||
Param<"ol_queue_handle_t*", "Queue", "output pointer for the created queue", PARAM_OUT> | ||
]; | ||
let returns = []; | ||
} | ||
|
||
def : Function { | ||
let name = "olRetainQueue"; | ||
let desc = "Increment the queue's reference count."; | ||
let details = []; | ||
let params = [ | ||
Param<"ol_queue_handle_t", "Queue", "handle of the queue", PARAM_IN> | ||
]; | ||
let returns = []; | ||
} | ||
|
||
def : Function { | ||
let name = "olReleaseQueue"; | ||
let desc = "Decrement the queues's reference count, and free it if the reference count reaches 0"; | ||
let details = []; | ||
let params = [ | ||
Param<"ol_queue_handle_t", "Queue", "handle of the queue", PARAM_IN> | ||
]; | ||
let returns = []; | ||
} | ||
|
||
def : Function { | ||
let name = "olWaitQueue"; | ||
let desc = "Wait for the enqueued work on a queue to complete"; | ||
let details = []; | ||
let params = [ | ||
Param<"ol_queue_handle_t", "Queue", "handle of the queue", PARAM_IN> | ||
]; | ||
let returns = []; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way it works in HSA is that you iterate through all of the devices, and one of them has the special 'type' of host. So this should use the same interface as the GPU devices but have a different 'platform' as you call it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little wary of having a device discovered the regular way that a user can't actually enqueue work on (hopefully it will be usable that way, but as you've suggested in other comments the host plugin needs a bit of work).
But having the user check the device type to find the host device isn't too onerous so I can make this change.