Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
- run: uv sync --extra dev
- run: uv run pytest --cov-report term --cov-report html --cov-report xml --cov=src/libkernelbot unit-tests -v
- run: uv run pytest --cov-report term --cov-report html --cov-report xml --cov=src/libkernelbot -m "not integration" tests -v
- uses: actions/upload-artifact@v4
with:
name: coverage
Expand All @@ -25,13 +25,22 @@ jobs:
uses: py-cov-action/python-coverage-comment-action@v3
with:
GITHUB_TOKEN: ${{ github.token }}

- name: Store Pull Request comment to be posted
uses: actions/upload-artifact@v4
if: steps.coverage_comment.outputs.COMMENT_FILE_WRITTEN == 'true'
with:
# If you use a different name, update COMMENT_ARTIFACT_NAME accordingly
name: python-coverage-comment-action
# If you use a different name, update COMMENT_FILENAME accordingly
path: python-coverage-comment-action.txt

integration-tests:
runs-on: ubuntu-latest
timeout-minutes: 30
env:
MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }}
MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }}
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
- run: uv sync --extra dev
- run: uv run modal token set --token-id ${MODAL_TOKEN_ID} --token-secret ${MODAL_TOKEN_SECRET}
- run: uv run pytest -m integration tests -v
57 changes: 3 additions & 54 deletions examples/vectoradd_py/submission_cuda_inline.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
"""



add_module = load_inline(
name='add_cuda',
cpp_sources=add_cpp_source,
Expand All @@ -63,62 +62,12 @@
verbose=True,
)


def add(A, B):
if not A.is_cuda or not B.is_cuda:
raise RuntimeError("Both tensors must be on GPU")
return add_module.add_cuda(A, B)

def custom_kernel(data: input_t) -> output_t:
"""
Custom implementation of vector addition using CUDA inline function.
Args:
inputs: List of pairs of tensors [A, B] to be added.
Returns:
List of tensors containing element-wise sums.
"""
A, B = data

assert A.is_cuda and B.is_cuda, "Input tensors must be on GPU"
assert A.shape == B.shape, "Input tensors must have the same shape"
assert A.dtype == torch.float16 and B.dtype == torch.float16, "Input tensors must be float16"

M, N = A.shape
C = torch.empty_like(A)

n_threads = 256
n_blocks = (M * N + n_threads - 1) // n_threads

cuda_source = """
extern "C" __global__ void add_kernel(
const half* __restrict__ A,
const half* __restrict__ B,
half* __restrict__ C,
const int n_elements
) {
const int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < n_elements) {
C[idx] = __hadd(A[idx], B[idx]);
}
}
"""

module = torch.utils.cpp_extension.load_inline(
name=f"add_kernel_{M}_{N}",
cpp_sources="",
cuda_sources=cuda_source,
functions=["add_kernel"],
with_cuda=True,
extra_cuda_cflags=["-arch=sm_70"], # Adjust based on your GPU architecture
)

module.add_kernel(
cuda_stream=torch.cuda.current_stream(),
args=[
A.reshape(-1), B.reshape(-1), C.reshape(-1),
M * N,
],
blocks=n_blocks,
threads=n_threads,
)

return C
def custom_kernel(data: input_t) -> output_t:
return add(*data)
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ exclude_lines = [
[tool.pytest.ini_options]
testpaths = ["scripts", "tests"]
python_files = ["test_*.py", "*_test.py", "ci_test_*.py"]
markers = [
"integration: integration tests that need to interact externally, e.g., with modal/github actions/etc"
]

[tool.ruff]
line-length = 120
Expand Down
2 changes: 1 addition & 1 deletion src/libkernelbot/launchers/modal.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ async def run_submission(

result = await loop.run_in_executor(
None,
lambda: modal.Function.lookup("discord-bot-runner", func_name).remote(config=config),
lambda: modal.Function.from_name("discord-bot-runner", func_name).remote(config=config),
)

await status.update("✅ Waiting for modal run to finish... Done")
Expand Down
6 changes: 3 additions & 3 deletions src/runners/modal_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
"PyYAML",
)
.pip_install(
"torch~=2.7",
"torch>=2.7.0,<2.8.0",
"torchvision~=0.22",
"torchaudio~=2.7",
index_url="https://download.pytorch.org/whl/cu128"
"torchaudio>=2.7.0,<2.8.0",
index_url="https://download.pytorch.org/whl/cu128",
)
# other frameworks
.pip_install(
Expand Down
19 changes: 10 additions & 9 deletions unit-tests/conftest.py → tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,10 @@


@pytest.fixture(scope="module")
def docker_compose():
tgt_path = Path.cwd()
if tgt_path.name == "unit-tests":
tgt_path = tgt_path.parent

def docker_compose(project_root: Path):
"""Start a test database and run migrations"""
subprocess.check_call(
["docker", "compose", "-f", "docker-compose.test.yml", "up", "-d"], cwd=tgt_path
["docker", "compose", "-f", "docker-compose.test.yml", "up", "-d"], cwd=project_root
)

try:
Expand All @@ -25,7 +21,7 @@ def docker_compose():
["docker", "compose", "-f", "docker-compose.test.yml", "ps", "-q", "migrate-test"],
capture_output=True,
text=True,
cwd=tgt_path,
cwd=project_root,
)

if not result.stdout.strip(): # Container no longer exists
Expand All @@ -37,7 +33,7 @@ def docker_compose():
["docker", "compose", "-f", "docker-compose.test.yml", "logs", "migrate-test"],
capture_output=True,
text=True,
cwd=tgt_path,
cwd=project_root,
)

if "error" in logs.stdout.lower():
Expand All @@ -46,7 +42,7 @@ def docker_compose():
yield
finally:
subprocess.run(
["docker", "compose", "-f", "docker-compose.test.yml", "down", "-v"], cwd=tgt_path
["docker", "compose", "-f", "docker-compose.test.yml", "down", "-v"], cwd=project_root
)


Expand Down Expand Up @@ -122,3 +118,8 @@ def task_directory(tmp_path):
# Create task.yml
Path.write_text(tmp_path / "task.yml", TASK_YAML)
return tmp_path


@pytest.fixture(scope="session")
def project_root():
return Path(__file__).parent.parent
File renamed without changes.
File renamed without changes.
Loading
Loading