Repository: cupy/cupy

Issue:
Support new random API in ROCm
### Description

Seems that the blocker for implementing this feature was already addressed in 
https://github.com/ROCm-Developer-Tools/HIP/issues/2186


Discussion:
Let's add this limitation (only applies to ROCm 4.2 or earlier) to here:
https://docs.cupy.dev/en/latest/install.html#limitations

Resolving patch:
diff --git a/cupy/random/__init__.py b/cupy/random/__init__.py
--- a/cupy/random/__init__.py
+++ b/cupy/random/__init__.py
@@ -32,9 +32,9 @@ def default_rng(seed=None):  # NOQA  avoid redefinition of seed
     Returns:
         Generator: The initialized generator object.
     """  # NOQA, list of types need to be in one line for sphinx
-    if runtime.is_hip:
-        raise RuntimeError('Generator API not supported in HIP,'
-                           ' please use the legacy one.')
+    if runtime.is_hip and int(str(runtime.runtimeGetVersion())[:3]) < 403:
+        raise RuntimeError('Generator API not supported in ROCm<4.3,'
+                           ' please use the legacy one or update ROCm.')
     if isinstance(seed, BitGenerator):
         return Generator(seed)
     elif isinstance(seed, Generator):
@@ -94,12 +94,8 @@ def default_rng(seed=None):  # NOQA  avoid redefinition of seed
 from cupy.random._sample import random_sample as random  # NOQA
 from cupy.random._sample import random_sample as ranf  # NOQA
 from cupy.random._sample import random_sample as sample  # NOQA
-if not runtime.is_hip:
-    # This is disabled for HIP due to a problem when using
-    # dynamic dispatching of kernels
-    # see https://github.com/ROCm-Developer-Tools/HIP/issues/2186
-    from cupy.random._bit_generator import BitGenerator  # NOQA
-    from cupy.random._bit_generator import XORWOW  # NOQA
-    from cupy.random._bit_generator import MRG32k3a  # NOQA
-    from cupy.random._bit_generator import Philox4x3210  # NOQA
-    from cupy.random._generator_api import Generator  # NOQA
+from cupy.random._bit_generator import BitGenerator  # NOQA
+from cupy.random._bit_generator import XORWOW  # NOQA
+from cupy.random._bit_generator import MRG32k3a  # NOQA
+from cupy.random._bit_generator import Philox4x3210  # NOQA
+from cupy.random._generator_api import Generator  # NOQA
diff --git a/install/cupy_builder/_modules.py b/install/cupy_builder/_modules.py
--- a/install/cupy_builder/_modules.py
+++ b/install/cupy_builder/_modules.py
@@ -258,6 +258,25 @@ def get_modules(context: Context) -> List[Dict[str, Any]]:
             'curand',
         ],
     }
+    HIP_random = {
+        'name': 'random',
+        'required': True,
+        'file': [
+            'cupy.random._bit_generator',
+            ('cupy.random._generator_api',
+             ['cupy/random/cupy_distributions.cu']),
+        ],
+        'include': [
+            'hiprand/hiprand.h',
+        ],
+        'libraries': [
+            # Dependency from cuRAND header files
+            'amdhip64',  # was hiprtc and hip_hcc before ROCm 3.8.0
+            'hiprand',
+        ],
+        'check_method': build.check_hip_version,
+        'version_method': build.get_hip_version,
+    }
     CUDA_cusparselt = {
         'name': 'cusparselt',
         'file': [
@@ -363,6 +382,7 @@ def get_modules(context: Context) -> List[Dict[str, Any]]:
             HIP_cuda_nvtx_cusolver,
             HIP_cub,
             HIP_nccl,
+            HIP_random,
             COMMON_dlpack,
         ] + [HIP_thrust] if context.enable_thrust else []
 


Test patch:
diff --git a/tests/cupy_tests/random_tests/test_distributions.py b/tests/cupy_tests/random_tests/test_distributions.py
--- a/tests/cupy_tests/random_tests/test_distributions.py
+++ b/tests/cupy_tests/random_tests/test_distributions.py
@@ -2,7 +2,6 @@
 import pytest
 
 import cupy
-from cupy.cuda import runtime
 from cupy.random import _distributions
 from cupy import testing
 
@@ -194,8 +193,11 @@ def test_gamma_legacy(self, shape_dtype, scale_dtype):
 
     @cupy.testing.for_dtypes_combination(
         _float_dtypes, names=['shape_dtype', 'scale_dtype'])
-    @pytest.mark.xfail(
-        runtime.is_hip, reason='Generator API not supported in HIP')
+    @pytest.mark.skipif(
+        cupy.cuda.runtime.is_hip
+        and (int(str(cupy.cuda.runtime.runtimeGetVersion())[:3]) < 403),
+        reason="HIP<4.3 not supported ",
+    )
     def test_gamma_generator(self, shape_dtype, scale_dtype):
         self.check_distribution(cupy.random.default_rng().gamma,
                                 shape_dtype, scale_dtype)
@@ -549,8 +551,11 @@ def test_poisson_legacy(self, lam_dtype, dtype):
         self.check_distribution(_distributions.poisson, lam_dtype, dtype)
 
     @cupy.testing.for_float_dtypes('lam_dtype')
-    @pytest.mark.xfail(
-        runtime.is_hip, reason='Generator API not supported in HIP')
+    @pytest.mark.skipif(
+        cupy.cuda.runtime.is_hip
+        and (int(str(cupy.cuda.runtime.runtimeGetVersion())[:3]) < 403),
+        reason="HIP<4.3 not supported ",
+    )
     def test_poisson_generator(self, lam_dtype):
         self.check_distribution(cupy.random.default_rng(0).poisson,
                                 lam_dtype)
@@ -559,8 +564,11 @@ def test_poisson_generator(self, lam_dtype):
 @testing.gpu
 class TestDistributionsPoissonInvalid:
 
-    @pytest.mark.xfail(
-        runtime.is_hip, reason='Generator API not supported in HIP')
+    @pytest.mark.skipif(
+        cupy.cuda.runtime.is_hip
+        and (int(str(cupy.cuda.runtime.runtimeGetVersion())[:3]) < 403),
+        reason="HIP<4.3 not supported ",
+    )
     def test_none_lam_generator(self):
         with pytest.raises(TypeError):
             cupy.random.default_rng(0).poisson(None)
@@ -666,8 +674,11 @@ def test_standard_gamma_legacy(self, shape_dtype, dtype):
 
     @cupy.testing.for_float_dtypes('dtype', no_float16=True)
     @cupy.testing.for_float_dtypes('shape_dtype')
-    @pytest.mark.xfail(
-        runtime.is_hip, reason='Generator API not supported in HIP')
+    @pytest.mark.skipif(
+        cupy.cuda.runtime.is_hip
+        and (int(str(cupy.cuda.runtime.runtimeGetVersion())[:3]) < 403),
+        reason="HIP<4.3 not supported ",
+    )
     def test_standard_gamma_generator(self, shape_dtype, dtype):
         shape = numpy.ones(self.shape_shape, dtype=shape_dtype)
         self.check_generator_distribution('standard_gamma',
@@ -678,8 +689,11 @@ def test_standard_gamma_generator(self, shape_dtype, dtype):
 @testing.gpu
 class TestDistributionsStandardGammaInvalid(RandomDistributionsTestCase):
 
-    @pytest.mark.xfail(
-        runtime.is_hip, reason='Generator API not supported in HIP')
+    @pytest.mark.skipif(
+        cupy.cuda.runtime.is_hip
+        and (int(str(cupy.cuda.runtime.runtimeGetVersion())[:3]) < 403),
+        reason="HIP<4.3 not supported ",
+    )
     def test_none_shape_generator(self):
         with pytest.raises(TypeError):
             cupy.random.default_rng(0).standard_gamma(None)
diff --git a/tests/cupy_tests/random_tests/test_generator_api.py b/tests/cupy_tests/random_tests/test_generator_api.py
--- a/tests/cupy_tests/random_tests/test_generator_api.py
+++ b/tests/cupy_tests/random_tests/test_generator_api.py
@@ -12,8 +12,10 @@
 from cupy_tests.random_tests import common_distributions
 
 
-@pytest.mark.skipif(cupy.cuda.runtime.is_hip,
-                    reason='HIP does not support this')
+@pytest.mark.skipif(cupy.cuda.runtime.is_hip
+                    and (int(
+                        str(cupy.cuda.runtime.runtimeGetVersion())[:3]) < 403),
+                    reason='HIP<4.3 not supported ')
 class GeneratorTestCase(common_distributions.BaseGeneratorTestCase):
 
     target_method = None
@@ -301,8 +303,10 @@ class TestPower(
 
 @testing.with_requires('numpy>=1.17.0')
 @testing.gpu
-@pytest.mark.skipif(cupy.cuda.runtime.is_hip,
-                    reason='HIP does not support this')
+@pytest.mark.skipif(cupy.cuda.runtime.is_hip
+                    and (int(
+                        str(cupy.cuda.runtime.runtimeGetVersion())[:3]) < 403),
+                    reason='HIP<4.3 not supported ')
 class TestRandomStateThreadSafe(unittest.TestCase):
 
     def test_default_rng_thread_safe(self):