You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@PokhodenkoSA this requirement should be considered when we reevaluate the queue manager design. If we make the get_active_queues re-entrant that should be enough? Basically, we have to remove the use of the static global stack for the queues. Adding this for gold.
@oleksandr-pavlyk, the relevant test is one that uses await inside the with statement. Your test does not test anything related to await in a meaningful way.
As soon as I replace stack_context = stack.working_stack_context with stack_context = stack.broken_stack_context things fall apart:
(idp) [08:47:56 nuc04 async_stack]$ python async_run.py
Traceback (most recent call last):
File "async_run.py", line 31, in <module>
asyncio.run(main())
File "~/.conda/envs/idp/lib/python3.7/asyncio/runners.py", line 43, in run
return loop.run_until_complete(main)
File "~/.conda/envs/idp/lib/python3.7/asyncio/base_events.py", line 587, in run_until_complete
return future.result()
File "async_run.py", line 26, in main
await j1
File "async_run.py", line 12, in task1
assert c == v, "task1 check failed at i={}, (c, v) = ({}, {})".format(i, c, v)
AssertionError: task1 check failed at i=1, (c, v) = (7, 11)
I was never able to do make it work with contextvars.ContextVar. Can you perhaps refer me to an example?
broken_stack_context fails for obvious reasons, the two tasks both push to the same stack when they enter the with block, meaning after both have hit their first await, one sees the others value.
Your working_stack_context succeeds because it creates a fresh stack for each task - of course two unrelated objects won't interfere with each other.
However, it's not representative of the original problem any more - in the real API, you don't use s at all, but use _st in both pieces of code.
Cython here is a distraction I think, and not really relevant to what you're struggling with.
this example from the python docs seems reasonable.
I think the mistake here is using DPCTLQueueMgr_GetCurrentQueue at all
DPCTLQueueMgr is a nice API for use from C where thread-locals are the only thing to worry about - but it's completely superfluous in Python, where ContextVar is already the manager. I'd recommend a current_queue variable in Python / Cython that stores a ContextVar pointing to a cl::sycl::queue
I think the mistake here is using DPCTLQueueMgr_GetCurrentQueue at all
Yes, the whole issue arises because we are keeping the state in C rather than in Python. I initially did it this way to make it easy for us to get the current queue by just calling DPCTLQueueMgr_GetCurrentQueue from any native code. E.g., one could set the "current queue" in Python and then retrieve that queue inside an LLVM module numba-dppy generates by simply calling the C API function.
I support not storing the state globally in the C library. Also, we can use async-context-managers as syntactic sugar.
@shssf@PokhodenkoSA@reazulhoque I am adding you to the discussion here, as these changes will impact how numba-dppy and dpnp use dpctl.
Also, we can use async-context-managers as syntactic sugar.
I see no benefit to using async context manager here. Async context managers are for when your context manager requires access to the event loop to enter and leave the context. dpctl doesn't need access to the event loop, so there's no point doing this.
Activity
diptorupd commentedon Oct 8, 2020
@PokhodenkoSA this requirement should be considered when we reevaluate the queue manager design. If we make the get_active_queues re-entrant that should be enough? Basically, we have to remove the use of the static global stack for the queues. Adding this for gold.
diptorupd commentedon Nov 3, 2020
@oleksandr-pavlyk since we are talking about the specs, these questions should be addressed.
oleksandr-pavlyk commentedon Apr 6, 2021
Here is an example I used to verify that
dpctlworks correctly with coroutines:It executes normally, and outputs
"done"as expected without errors.eric-wieser commentedon Apr 6, 2021
@oleksandr-pavlyk, the relevant test is one that uses
awaitinside thewithstatement. Your test does not test anything related toawaitin a meaningful way.oleksandr-pavlyk commentedon Apr 6, 2021
Thank you @eric-wieser, having moved await inside the with context I still see no issues:
The code uses two queues with different backends, and checks that the current queue, which is being reset with the context, has the expected backend.
eric-wieser commentedon Apr 6, 2021
Yes, that code also is unlikely to detect any problems because it doesn't actually use the context after resuming from the await.
Swapping the
withwith theforshould ensure the problem surfaces.To be clear, #265 already outlines the solution here - the state must be stored in PEP 567's
ContextVars.oleksandr-pavlyk commentedon Apr 6, 2021
Ok, indeed
trips.
oleksandr-pavlyk commentedon Apr 12, 2021
@eric-wieser
Here is a Cython file I used:
Using the
asynciodriver like in the previous comment:The code executes just fine:
As soon as I replace
stack_context = stack.working_stack_contextwithstack_context = stack.broken_stack_contextthings fall apart:I was never able to do make it work with
contextvars.ContextVar. Can you perhaps refer me to an example?eric-wieser commentedon Apr 12, 2021
broken_stack_contextfails for obvious reasons, the two tasks both push to the same stack when they enter thewithblock, meaning after both have hit their first await, one sees the others value.Your
working_stack_contextsucceeds because it creates a fresh stack for each task - of course two unrelated objects won't interfere with each other.However, it's not representative of the original problem any more - in the real API, you don't use
sat all, but use_stin both pieces of code.Cython here is a distraction I think, and not really relevant to what you're struggling with.
this example from the python docs seems reasonable.
oleksandr-pavlyk commentedon Apr 12, 2021
You are right, use of Cython can be avoided.
This context manager works as expected with
async_run.py, where I doimport stack2 as stack, andstack_context = stack.stack_context.The think I was missing was the concept of
Token, and how it is needed to restore to the previous context state.So in
dpctlwe need two changes:contextvars.ContextVarto store the global instance of the queue managerQueueMgrclass needs to implement a.copymethod.eric-wieser commentedon Apr 12, 2021
I think the mistake here is using
DPCTLQueueMgr_GetCurrentQueueat allDPCTLQueueMgris a nice API for use from C where thread-locals are the only thing to worry about - but it's completely superfluous in Python, whereContextVaris already the manager. I'd recommend acurrent_queuevariable in Python / Cython that stores aContextVarpointing to acl::sycl::queuediptorupd commentedon Apr 12, 2021
Yes, the whole issue arises because we are keeping the state in C rather than in Python. I initially did it this way to make it easy for us to get the current queue by just calling
DPCTLQueueMgr_GetCurrentQueuefrom any native code. E.g., one could set the "current queue" in Python and then retrieve that queue inside an LLVM module numba-dppy generates by simply calling the C API function.I support not storing the state globally in the C library. Also, we can use async-context-managers as syntactic sugar.
@shssf @PokhodenkoSA @reazulhoque I am adding you to the discussion here, as these changes will impact how numba-dppy and dpnp use dpctl.
eric-wieser commentedon Apr 13, 2021
For reference, there is a C API for contextvars too;
PyContextVar_Getis probably all you need.eric-wieser commentedon Apr 13, 2021
I see no benefit to using async context manager here. Async context managers are for when your context manager requires access to the event loop to enter and leave the context. dpctl doesn't need access to the event loop, so there's no point doing this.
Added get_device_cached_queue utility function