Skip to content
Closed
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
317 changes: 317 additions & 0 deletions .claude/skills/ck-docker
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
#!/bin/bash
# CK Docker Skill - Build and test composable_kernel in Docker with ROCm support

set -e
set -o pipefail

# Find project root (where .git directory is)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"

# Detect git branch and sanitize for docker naming (replace / and special chars with _)
GIT_BRANCH=$(cd "${PROJECT_ROOT}" && git rev-parse --abbrev-ref HEAD 2>/dev/null | tr '/' '_' | tr -cd 'a-zA-Z0-9_-' || echo "")
# Handle edge cases: detached HEAD, empty branch name
GIT_BRANCH=${GIT_BRANCH:-unknown}
# If branch is just "HEAD" (detached state), make it more descriptive
if [ "${GIT_BRANCH}" = "HEAD" ]; then
GIT_BRANCH="detached"
fi

# Ensure USER is set
USER_NAME=${USER:-$(whoami 2>/dev/null || echo "user")}

# Default container name: ck_<username>_<branch>
DEFAULT_NAME="ck_${USER_NAME}_${GIT_BRANCH}"
CONTAINER_NAME="${CK_CONTAINER_NAME:-${DEFAULT_NAME}}"

# Help message
show_help() {
cat << EOF
CK Docker Skill - Build and test composable_kernel in Docker

Usage: ck-docker <command> [options]

Commands:
start [name] Start Docker container
build [target] [--reconfigure] Build target (optionally reconfigure CMake)
test <test> [options] Run test
shell [name] Open shell in container
status [name] Check container status
stop [name] Stop and remove container

Examples:
ck-docker start
ck-docker build test_amdgcn_mma
ck-docker build --reconfigure test_amdgcn_mma
ck-docker test test_amdgcn_mma --gtest_filter=*Fp16*
ck-docker shell

Environment:
CK_CONTAINER_NAME - Override default container name (default: ck_<username>_<branch>)
CK_DOCKER_IMAGE - Override Docker image (default: rocm/composable_kernel:ck_ub24.04_rocm7.0.1)
GPU_TARGET - Override GPU target detection (e.g., gfx950, gfx942)
EOF
}

# Detect GPU target
detect_gpu() {
local container=$1
# Allow override via GPU_TARGET environment variable
if [ -n "${GPU_TARGET:-}" ]; then
echo "${GPU_TARGET}"
return 0
fi
docker exec "${container}" bash -c "
rocminfo 2>/dev/null | grep -oP 'gfx[0-9a-z]+' | head -1 || echo 'gfx950'
" | tr -d '\r\n'
}

# Start container
cmd_start() {
local name="${1:-${CONTAINER_NAME}}"
local docker_image="${CK_DOCKER_IMAGE:-rocm/composable_kernel:ck_ub24.04_rocm7.0.1}"

# Check if container exists (exact match to avoid substring collisions)
if docker ps -a --filter "name=^${name}$" --format '{{.Names}}' | grep -q "^${name}$"; then
# Check if container is running
if docker ps --filter "name=^${name}$" --format '{{.Names}}' | grep -q "^${name}$"; then
echo "Container '${name}' is already running"
return 0
else
echo "Starting existing container '${name}'..."
docker start "${name}"
echo "Container started"
return 0
fi
fi

echo "Creating new Docker container '${name}'..."
docker run -d \
--name "${name}" \
--device=/dev/kfd --device=/dev/dri \
--security-opt seccomp=unconfined \
--group-add video \
-v "${PROJECT_ROOT}":/workspace \
-w /workspace \
"${docker_image}" \
tail -f /dev/null

echo "Container '${name}' started successfully"
docker exec "${name}" bash -c "echo 'Working directory:' && pwd"
}

# Build target
cmd_build() {
local target=""
local name="${CONTAINER_NAME}"
local reconfigure=false

while [[ $# -gt 0 ]]; do
case $1 in
--name)
name="$2"
shift 2
;;
--reconfigure)
reconfigure=true
shift
;;
*)
target="$1"
shift
;;
esac
done

# Check if container is running (exact match)
if ! docker ps --filter "name=^${name}$" --format '{{.Names}}' | grep -q "^${name}$"; then
echo "Container '${name}' not running. Starting..."
cmd_start "${name}"
fi

# Reconfigure CMake if requested or if build.ninja doesn't exist
if [ "$reconfigure" = true ] || ! docker exec "${name}" test -f /workspace/build/build.ninja 2>/dev/null; then
echo "Detecting GPU target..."
local gpu_target=$(detect_gpu "${name}")

if [ "$reconfigure" = true ]; then
echo "Reconfiguring CMake from scratch for GPU target: ${gpu_target}"
else
echo "Configuring build with CMake for GPU target: ${gpu_target}"
fi

docker exec "${name}" bash -c "
cd /workspace || exit 1
rm -rf /workspace/build
mkdir /workspace/build
cd /workspace/build || exit 1
cmake .. -GNinja \
-DGPU_TARGETS=${gpu_target} \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_COMPILER=/opt/rocm/llvm/bin/clang++ \
-DBUILD_TESTING=ON 2>&1 | tail -30
"
fi

if [ -z "$target" ]; then
echo "Building all configured targets..."
else
echo "Building target: ${target}"
fi

docker exec "${name}" bash -c "
cd /workspace/build || exit 1
ninja ${target} 2>&1
"

echo "Build complete"
}

# Run test
cmd_test() {
local test_name=""
local name="${CONTAINER_NAME}"
local -a test_options=()

while [[ $# -gt 0 ]]; do
case $1 in
--name)
name="$2"
shift 2
;;
--gtest_*|--help)
test_options+=("$1")
shift
;;
*)
if [ -z "$test_name" ]; then
test_name="$1"
else
test_options+=("$1")
fi
shift
;;
esac
done

if [ -z "$test_name" ]; then
echo "Error: test_name required"
echo "Usage: ck-docker test <test_name> [--name container_name] [gtest_options]"
return 1
fi

# Check if container is running (exact match)
if ! docker ps --filter "name=^${name}$" --format '{{.Names}}' | grep -q "^${name}$"; then
echo "Error: Container '${name}' not running"
echo "Start it with: ck-docker start --name ${name}"
return 1
fi

if ! docker exec "${name}" test -f "/workspace/build/bin/${test_name}" 2>/dev/null; then
echo "Test executable not found. Building ${test_name}..."
cmd_build "${test_name}" --name "${name}"
fi

echo "Running: ${test_name} ${test_options[*]}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# Build the command with proper quoting
local cmd="cd /workspace/build && ./bin/${test_name}"
for opt in "${test_options[@]}"; do
cmd="${cmd} $(printf '%q' "$opt")"
done
docker exec "${name}" bash -c "${cmd}"
}

# Shell
cmd_shell() {
local name="${1:-${CONTAINER_NAME}}"

# Check if container is running (exact match)
if ! docker ps --filter "name=^${name}$" --format '{{.Names}}' | grep -q "^${name}$"; then
echo "Container '${name}' not running. Starting..."
cmd_start "${name}"
fi

echo "Opening shell in '${name}' (type 'exit' to leave)..."
docker exec -it "${name}" bash
}

# Status
cmd_status() {
local name="${1:-}"
local docker_image="${CK_DOCKER_IMAGE:-rocm/composable_kernel:ck_ub24.04_rocm7.0.1}"

if [ -z "$name" ]; then
echo "Composable Kernel Docker Containers:"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
docker ps -a --filter "ancestor=${docker_image}" \
--format "table {{.Names}}\t{{.Status}}\t{{.CreatedAt}}" || echo "No containers found"
else
# Check if container is running (exact match)
if docker ps --filter "name=^${name}$" --format '{{.Names}}' | grep -q "^${name}$"; then
echo "Container '${name}' is RUNNING"
docker ps --filter "name=^${name}$" --format "table {{.Names}}\t{{.Status}}\t{{.Image}}"
echo ""
echo "GPU Information:"
docker exec "${name}" bash -c "rocm-smi --showproductname 2>/dev/null | head -10 || echo 'No GPU detected'"
elif docker ps -a --filter "name=^${name}$" --format '{{.Names}}' | grep -q "^${name}$"; then
echo "Container '${name}' exists but is STOPPED"
echo "Start with: ck-docker start ${name}"
else
echo "Container '${name}' does NOT exist"
echo "Create with: ck-docker start ${name}"
fi
fi
}

# Stop
cmd_stop() {
local name="${1:-${CONTAINER_NAME}}"

# Check if container exists (exact match)
if docker ps -a --filter "name=^${name}$" --format '{{.Names}}' | grep -q "^${name}$"; then
echo "Stopping and removing container '${name}'..."
docker stop "${name}" 2>/dev/null || true
docker rm "${name}" 2>/dev/null || true
echo "Container stopped and removed"
else
echo "Container '${name}' does not exist"
fi
}

# Main command dispatcher
case "${1:-}" in
start)
shift
cmd_start "$@"
;;
build)
shift
cmd_build "$@"
;;
test)
shift
cmd_test "$@"
;;
shell)
shift
cmd_shell "$@"
;;
status)
shift
cmd_status "$@"
;;
stop)
shift
cmd_stop "$@"
;;
help|--help|-h)
show_help
;;
*)
echo "Unknown command: ${1:-}"
echo ""
show_help
exit 1
;;
esac
80 changes: 80 additions & 0 deletions .claude/skills/ck-docker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# ck-docker

Build and test composable_kernel in Docker with ROCm support.

## Terminal Usage

Direct command-line usage:

```bash
# From composable_kernel directory
.claude/skills/ck-docker start
.claude/skills/ck-docker build test_amdgcn_mma
.claude/skills/ck-docker test test_amdgcn_mma --gtest_filter=*Fp16*
.claude/skills/ck-docker status
.claude/skills/ck-docker shell

# Or add to PATH
export PATH="$PATH:$PWD/.claude/skills"
ck-docker start
```

## Ask Claude

Just ask in natural language:
- "Start the docker container"
- "Build test_amdgcn_mma"
- "Run test_amdgcn_mma with filter *Fp16*"
- "Check container status"
- "Open a shell in the container"

## Commands

```
ck-docker start [name] Start Docker container
ck-docker build [target] [--reconfigure] Build target (optionally reconfigure CMake)
ck-docker test <name> [options] Run test
ck-docker shell [name] Interactive shell
ck-docker status [name] Check status
ck-docker stop [name] Stop container
```

## Configuration

- **Image**: rocm/composable_kernel:ck_ub24.04_rocm7.0.1
- **GPU**: Auto-detected via rocminfo (fallback: gfx950)
- **Compiler**: /opt/rocm/llvm/bin/clang++
- **Build**: Ninja + CMake (Release)
- **Mount**: Current directory → /workspace
- **Container Name**: Auto-generated as `ck_<username>_<branch>` to avoid clashes

## Environment

```bash
export CK_CONTAINER_NAME=my_build # Override default container name
export CK_DOCKER_IMAGE=rocm/composable_kernel:ck_ub24.04_rocm7.0.1 # Override Docker image
export GPU_TARGET=gfx942 # Override GPU target detection
```

## Examples

```bash
# Start container
ck-docker start

# Build and run test
ck-docker build test_amdgcn_mma
ck-docker test test_amdgcn_mma

# Force clean CMake reconfiguration and build
ck-docker build --reconfigure test_amdgcn_mma

# Custom container
ck-docker start my_build
ck-docker build test_amdgcn_mma --name my_build
ck-docker test test_amdgcn_mma --name my_build

# Debug
ck-docker shell
ck-docker status
```