Merge CUPY_CUB_BLOCK_REDUCTION_DISABLED and CUB_DISABLED#3461
Merge CUPY_CUB_BLOCK_REDUCTION_DISABLED and CUB_DISABLED#3461kmaehashi merged 25 commits intocupy:masterfrom
CUPY_CUB_BLOCK_REDUCTION_DISABLED and CUB_DISABLED#3461Conversation
|
PTAL. |
leofang
left a comment
There was a problem hiding this comment.
Thanks again, @asi1024, for working on this! I've done a quick pass and left some comments. The major change needed here is to handle scan properly. I think we can use CUB for both faster indexing (which I intended to do but overlooked for some reason!) and cumsum/cumprod, but the current implementation introduces a regression for the latter.
cupy/cuda/__init__.py
Outdated
| cub_enabled = False | ||
| if int(os.getenv('CUB_DISABLED', 0)) == 0: | ||
| if int(os.getenv('CUPY_CUB_ENABLED', 0)) == 1: | ||
| try: | ||
| from cupy.cuda import cub # NOQA | ||
| cub_enabled = True |
There was a problem hiding this comment.
I think this entire block (including the two lines below) should be changed to support CUPY_BACKENDS? At least cupy.cuda.cub_enabled should be removed as per #3445 (comment), but you'll need to fix every place that it appears in, such as the tests added in #2598 and #3428.
cupy/core/_routines_math.pyx
Outdated
| for backend in _backend._routine_backends: | ||
| if backend == _backend.BACKEND_CUB: | ||
| # result will be None if the scan is not compatible with CUB | ||
| if op == scan_op.SCAN_SUM: | ||
| cub_op = cub.CUPY_CUB_CUMSUM | ||
| else: | ||
| cub_op = cub.CUPY_CUB_CUMPROD | ||
| res = cub.cub_scan(out, cub_op) | ||
| if res is not None: | ||
| return out |
There was a problem hiding this comment.
We probably need this here (for fast indexing) as well as in scan_core() (where this came from), because cupy/math/sumprod.py calls the latter directly. Moreover, this early appearance does not take care:
- copy input: scan is an in-place operation (whether using CUB or not), so the input
amust be copied toout. - ravel input: CUB scan needs a 1D contiguous input.
- axis: CUB only handles non-batched scans (
axis is None).
So at least for cupy.cumsum() and cupy.cumprod() this won't work.
cupy/core/_routines_math.pyx
Outdated
| if cupy.cuda.cub_enabled: | ||
| # result will be None if the scan is not compatible with CUB | ||
| if op == scan_op.SCAN_SUM: | ||
| cub_op = cub.CUPY_CUB_CUMSUM | ||
| else: | ||
| cub_op = cub.CUPY_CUB_CUMPROD | ||
| res = cub.cub_scan(result, cub_op) | ||
| if not cupy.cuda.cub_enabled or res is None: | ||
| scan(result, op, dtype, result) | ||
| scan(result, op, dtype, result) |
There was a problem hiding this comment.
See my comment above for CUB scan.
Co-authored-by: Leo Fang <leofang@bnl.gov>
Co-authored-by: Leo Fang <leofang@bnl.gov>
|
PTAL. |
leofang
left a comment
There was a problem hiding this comment.
LGTM except for a few small nitpicks. I think you can apply all suggestions at once by switching to the "Files changed" tab and adding them to the batch. This way we won't generate excessive commits.
| @unittest.skipUnless( | ||
| cupy.core._backend.get_routine_backends() == ['cub'], | ||
| 'The CUB routine is not enabled') | ||
| class TestFcontiguousReduction(unittest.TestCase): |
There was a problem hiding this comment.
Not sure why the class name was changed? Note both C- & F- contiguity get tested.
| class TestFcontiguousReduction(unittest.TestCase): | |
| class TestCUBreduction(unittest.TestCase): |
There was a problem hiding this comment.
Sorry, I thought the skip condition is not needed and renamed before, and I forgot to undo after this tests don't pass without skip condition.
| @unittest.skipIf(cupy.cuda.cub_enabled is False, 'The CUB module is not built') | ||
| class TestCUBreduction(unittest.TestCase): | ||
| @unittest.skipUnless( | ||
| cupy.core._backend.get_routine_backends() == ['cub'], |
There was a problem hiding this comment.
I think as long as CUB is set enabled (or cupy.cuda.cub is built), it should be fine that other backends exist?
| cupy.core._backend.get_routine_backends() == ['cub'], | |
| 'cub' in cupy.core._backend.get_routine_backends(), |
There was a problem hiding this comment.
No, another backend may be chosen. However, cupy.core._backend.get_routine_backends()[:1] == ['cub'] may be better because the get_routine_backends indicates the priority of backends.
There was a problem hiding this comment.
Ah I see. That sounds good. Either [0] or [:1] is fine.
There was a problem hiding this comment.
Hi @asi1024 I thought about this again, and I think the rationale here was that if cupy.cuda.cub is built it should get tested (regardless how backends were set). If one of the CIs would be set up with CUPY_BACKENDS="cub," then this is OK; otherwise, once #2584 is up, we'll need to ensure these tests are run (by removing skipUnless() and using setUp() and tearDown() to temporarily overwrite the backends).
Let me know if you'd configure the CI or I should address the skips in #2584, thanks!
There was a problem hiding this comment.
I agree to set backends in setUp and tearDown. Fixed in 43b2da6.
| @testing.gpu | ||
| @unittest.skipIf(cupy.cuda.cub_enabled is False, 'The CUB module is not built') | ||
| @unittest.skipUnless( | ||
| cupy.core._backend.get_routine_backends() == ['cub'], |
There was a problem hiding this comment.
| cupy.core._backend.get_routine_backends() == ['cub'], | |
| 'cub' in cupy.core._backend.get_routine_backends(), |
| @testing.gpu | ||
| @unittest.skipIf(cupy.cuda.cub_enabled is False, 'The CUB module is not built') | ||
| @unittest.skipUnless( | ||
| cupy.core._backend.get_routine_backends() == ['cub'], |
There was a problem hiding this comment.
| cupy.core._backend.get_routine_backends() == ['cub'], | |
| 'cub' in cupy.core._backend.get_routine_backends(), |
| @testing.gpu | ||
| @unittest.skipIf(cupy.cuda.cub_enabled is False, 'The CUB module is not built') | ||
| @unittest.skipUnless( | ||
| cupy.core._backend.get_routine_backends() == ['cub'], |
There was a problem hiding this comment.
| cupy.core._backend.get_routine_backends() == ['cub'], | |
| 'cub' in cupy.core._backend.get_routine_backends(), |
cupy/cuda/__init__.py
Outdated
| cub_enabled = False | ||
| if int(os.getenv('CUB_DISABLED', 0)) == 0: | ||
| try: | ||
| from cupy.cuda import cub # NOQA | ||
| cub_enabled = True | ||
| except ImportError: | ||
| pass |
There was a problem hiding this comment.
👍 I thought this change would disable from cupy.cuda import cub but it seems still working. Interesting...
| res = cub.cub_scan(out, cub_op) | ||
| if res is not None: | ||
| break | ||
| else: |
cupyx/scipy/sparse/csr.py
Outdated
| if cupy.cuda.cub_enabled: | ||
|
|
||
| try: | ||
| from cupy.cuda.cub import device_csrmv |
There was a problem hiding this comment.
Actually this violates the dev guideline...Let's fix it properly:
| from cupy.cuda.cub import device_csrmv | |
| from cupy.cuda import cub |
cupyx/scipy/sparse/csr.py
Outdated
| try: | ||
| from cupy.cuda.cub import device_csrmv | ||
| except ImportError: | ||
| pass |
There was a problem hiding this comment.
| pass | |
| cub = None |
cupyx/scipy/sparse/csr.py
Outdated
| for backend in _backend.get_routine_backends(): | ||
| if (backend == _backend.BACKEND_CUB | ||
| and other.flags.c_contiguous): | ||
| return device_csrmv( |
There was a problem hiding this comment.
| return device_csrmv( | |
| return cub.device_csrmv( |
|
Jenkins, test this please. |
|
Successfully created a job for commit a4ab70e: |
|
Jenkins, test this please. |
|
Successfully created a job for commit a4ab70e: |
|
Jenkins CI test (for commit a4ab70e, target branch master) failed with status FAILURE. |
|
I should trigger after chainer/chainer-test#586 is merged. I canceled the Jenkins CI. |
|
Jenkins, test this please. |
|
Successfully created a job for commit a4ab70e: |
|
Jenkins CI test (for commit a4ab70e, target branch master) failed with status FAILURE. |
leofang
left a comment
There was a problem hiding this comment.
Oops! This line in test_csr.py:
func = 'cupyx.scipy.sparse.csr.device_csrmv'needs to be changed to
func = 'cupyx.scipy.sparse.csr.cub.device_csrmv'|
Jenkins, test this please. |
|
Successfully created a job for commit 41f4e45: |
|
Jenkins CI test (for commit 41f4e45, target branch master) succeeded! |
|
@asi1024 Do you know why some CUB tests (I think) were skipped in |
|
@leofang |
|
Jenkins, test this please. |
|
Successfully created a job for commit 8a8feea: |
|
Jenkins CI test (for commit 8a8feea, target branch master) succeeded! |
|
LGTM! |
Part of #3445.
CUPY_CUB_BLOCK_REDUCTION_DISABLEDandCUB_DISABLEDintoCUPY_CUB_ENABLED.CUPY_BACKENDS.cupy.core.set_reduction_backendsandcupy.core.routine_backends(These functions are for debug use. We will leave them undocumented.)