-
Notifications
You must be signed in to change notification settings - Fork 115
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
Logger callback function sink #1748
base: main
Are you sure you want to change the base?
Conversation
source/loader/ur_lib.cpp
Outdated
return UR_RESULT_ERROR_INVALID_NULL_POINTER; | ||
} | ||
|
||
logger::get_logger().setCallbackSinkFunction(pfnLoggerCallback); |
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.
There is more than one logger. At the very least, each adapter will have its own logger instance, so this API needs to be in DDI and propagated to all adapters.
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 meant to highlight this as a question because I wasn't sure about how to get the callback function pointer into the logger as get_logger
takes a name parameter. I can't see any loader references in DDI tables, would I need to add one for the loader or should the entry point be part of another group maybe?
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.
This is not really a loader API, so I'd call this something like urSetLoggerCallback
and remove loader_only
from the spec. This will generate a DDI function where you can implement this for each adapter. And each adapter will then need to have the logger::get_logger().setSink()
call in their implementation. Because the instance returned by logger::get_logger()
is different for each adapter.
Additionally, if you want the application to be able to also get callbacks on loader-related messages, you'd need to make an if
in the template file to call logger::get_logger().setSink()
at the loader layer, before the function is forwarded to the adapter-specific implementation.
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've updated this as per your comments here and our conversation on Teams, each adapter implements this new entry point now. Thanks for your help!
If the idea is for the SYCL to hoist UR logs and print them using its own facility, wouldn't it make sense for |
e060f14
to
31d4486
Compare
@pbalcer thanks for your comments! I'm not sure about this one maybe you can clarify?
I think you mean so the user at the SYCL level doesn't need to interact with UR directly right? I'm not sure if that would be possible for this case as the callback would need to be passed through programmatically? |
The way you implemented it right now, for a SYCL end-user (I don't mean developer of SYCL runtime) to receive any sort of messages from the UR layer, they'd have to set But for that to be possible, the set callback function needs to always work, independent of the UR-level log setting. |
scripts/core/loader.yml
Outdated
desc: "[in] Function pointer to callback from the logger." | ||
- type: void* | ||
name: pUserData | ||
desc: "[in][out][optional] pointer to data to be passed to callback" |
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 this is implemented right now is not thread safe with respect to any other API call. This should be stated clearly in the docs.
(Ideally we'd figure out how to make it thread-safe though, but I don't see a simple way other than having a mutex around the logger, and that's just iffy).
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've updated the description here to say the creator of the callback function should be responsible for making it thread-safe.
b006f18
to
1151162
Compare
7678217
to
a8081b5
Compare
a8081b5
to
808e73a
Compare
3cfc04c
to
b4a2faf
Compare
7c297fc
to
8a04428
Compare
There is a workaround for warnings for now in this PR. and it is probably going to be merged first so could you delete it in this PR once merged as this should fix it properly @martygrant? Thanks! Edit: After a rethought that would cause e2e test failures as this will be merged after the deleting PI PR. So, we should attach the deletion of the workaround with changing the adapters to use this new logger mechanism and not in this PR. I added an issue for more context on this here. |
/// @brief Set a callback function for use by the logger to retrieve logging output. | ||
/// It is a requirement that the callback function is thread safe and the | ||
/// creator of the function will be responsible for this. | ||
/// |
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.
One more thing to document is that calling this, urAdapterSetLoggerCallback
, and urAdapterSetLoggerCallbackLevel
functions is not thread-safe with respect to any other function in the API. The reason is that they are modifying global state without using atomics or grabbing a lock. In other words, when something is writing a log, you may inadvertently change the logger callback pointer.
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.
Okay no problem, I reworded the description for urAdapterSetLoggerCallback
but will add it to urAdapterSetLoggerCallbackLevel
as well. It should specifically say not "thread safe with respect to any other function in the API"? Should the explanation be added here or is that enough?
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.
Most people understand thread-safe functions as safe to be invoked, with respect to themselves, concurrently by multiple threads. And that is how POSIX defines it. For example, you can't call strtok()
from multiple threads and expect it to work correctly, but you can call strtok()
in one thread, and e.g., write()
in another. In this case, the situation is a bit different, since urAdapterSetLoggerCallback
is not safe to call even with respect to other UR API functions (that are otherwise thread-safe). Small caveat is that implementations may choose to limit this unsafety to be per-adapter.
In my opinion this break the principle of least surprise, and should be thoroughly documented. Saying "not thread-safe" is not enough.
Ideally we'd fix this - one approach would be to only allow setting the callback as part of the loader config (and then somehow pass that callback to the adapter during initialization... won't be trivial), and then change the logger level variable to be an atomic.
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.
Thanks Piotr. @kbenzie do you have any thoughts on this? Would we want to modify the design now or just get this PR in as it is now and modify it later? If the latter then I'll move these comments to a new issue to track this.
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.
Lets revisit making this decision until after intel/llvm#14145 is merged.
8a04428
to
1cf3c31
Compare
1cf3c31
to
d8bf577
Compare
…back function. Configurable through two new entry points with adapter implementations: urAdapterSetLoggerCallback() and urAdapterSetLoggerCallbackLevel(). Moved logger::level enum to the spec, named ur_logger_level_t. Added new unit test suite for these entry points.
Co-authored-by: Kenneth Benzie (Benie) <[email protected]>
…Move entry points from global ddi table to adapter. Rename the callback function pointer to ur_logger_callback_t.
d8bf577
to
8936426
Compare
This PR implements #1330 through a new logger sink: a user configurable callback. It introduces some spec additions:
typedef void (*ur_logger_output_callback_t)(ur_logger_level_t level, const char *pLoggerMsg, void *pUserData)
urSetLoggerCallback(ur_adapter_handle_t hAdapter, ur_logger_output_callback_t pfnLoggerCallback, void *pUserData, ur_logger_level_t level
)`
urSetLoggerCallbackLevel(ur_adapter_handle_t hAdapter, ur_logger_level_t level)
typedef enum ur_logger_level_t
(moved the logger::level enum into the spec)This new logger sink will only be constructed once a user makes a call to
urSetLoggerCallback
, supplying their own callback function. They can set the minimum logging level throughurSetLoggerCallbackLevel
. Any subsequent logging calls will additionally make a call to the supplied callback where the log level, message and user data will be sent.A new test suite
LoggerWithCallbackSink
has been added to test this new functionality.intel/llvm PR: intel/llvm#14422