Hai giao diện lập trình hiện tại được hỗ trợ để viết các chương trình CUDA là: CUDA C và CUDA driver API. Một ứng dụng thông thường sử dụng một trong hai, nhưng cũng có thể sử dụng cả hai dưới các giới hạn được trình bày ở phần sau.
CUDA C thể hiện mô hình lập trình CUDA như là một tập nhỏ các mở rộng của ngôn ngữ C. Mọi tệp nguồn chứa một số mở rộng này phải được biên dịch bằng. Các giới hạn này cho phép người lập trình định nghĩa một kernel như một hàm của C và sử dụng một số cú pháp mới để chỉ ra chiều của grid và block mỗi lần hàm kernel được gọi.
CUDA driver API là một API C ở mức thấp hơn cung cấp các hàm để tải các kernel như là các module của mã CUDA dạng nhị phân hoặc các mã assembly, để kiểm tra các tham số của chúng, và để thực hiện chúng. Các mã nhị phân và mã assembly thường có được sau khi biên dịch các kernel được viết bằng C.
CUDA C đi cùng với một API runtime và cả API runtime và API driver đều cung cấp các hàm để cấp phát, giải phóng bộ nhớ thiết bị, truyền dữ liệu dữ bộ nhớ host và bộ nhớ thiết bị, quản lý hệ thống có nhiều thiết bị,…
API runtime được xây dựng trên đỉnh của CUDA driver API. Việc quản lý khởi tạo, quản lý ngữ cảnh (context), quản lý module hoàn toàn được ẩn đi và do đó các đoạn mã rất ngắn gọn. CUDA C cũng hỗ trợ chế độ mô phỏng thiết bị, thường có ích trong việc gỡ rối Ngược lại, CUDA driver API yêu cầu nhiều code hơn, khó lập trình và gỡ rối hơn, nhưng nó đưa ra một sự điều khiển ở mức tốt hơn và độc lập với ngôn ngữ do đó có thể quản lý mã nhị phân hoặc assembly.
2.4.1. Biên dịch với NVCC
Các kernel có thể được viết sử dụng kiến trúc tập lệnh CUDA, được gọi là PTX (được mô tả trong tài liệu PTX reference manual). Tuy nhiên, thường sử dụng một ngôn ngữ lập trình cấp cao như là C sẽ hiệu quả hơn. Trong cả hai trường hợp, các
kernel phải được biên dịch thành mã nhị phân bởi nvcc để có thể thực hiện được trên thiết bị (device).
nvcc là một trình biên dịch đơn giản hóa việc biên dịch mã nguồn C hoặc mã PTX: Nó cung cấp các tùy chọn dòng lệnh đơn giản và quen thuộc và thực thi chúng bằng cách gọi tập các công cụ để thực hiện các pha biên dịch khác nhau. Phần này trình bày tổng quan về luồng công việc và các tùy chọn dòng lệnh của nvcc. Một mô tả đầy đủ có thể tìm trong tìm trong tài liệu nvcc user manual.
2.4.2. CUDA C
CUDA C cung cấp một cách thức đơn giản cho các người sử dụng quen thuộc với ngôn ngữ lập trình C để dễ dàng viết các chương trình để thực thi trên thiết bị.
Nó bao gồm một tập nhỏ các mở rộng của ngôn ngữ C và một thư viện thời gian chạy (runtime). Phần này tiếp tục giới thiệu tới thư viện runtime và một mô tả hoàn chỉnh cho runtime ở trong tài liệu CUDA reference manual [10]. Runtime được thực hiện trong thư viện động cudart và tất cả các mục của nó đều có tiền tố cuda.
Không có hàm khởi tạo rõ ràng cho runtime; nó khởi tạo khi một hàm runtime được gọi lần đầu tiên (chính xác hơn là mọi hàm trừ các hàm từ các phần quản lý phiên bản và thiết bị trong tài liệu reference manual). Cần chú ý đến điều này khi lựa chọn đúng lúc (timing) các lời gọi hàm runtime và khi thông dịch mã lỗi từ lời gọi đầu tiên trong runtime.
Một khi runtime đã được khởi tạo trong một tiến trình của host, mọi tài nguyên (bộ nhớ, luồng, sự kiện,…) được cấp phát qua một vài lời gọi hàm runtime trong tiến trình host chỉ hợp lệ bên trong ngữ cảnh của tiến trình đó. Do đó, chỉ các lời gọi các hàm runtime từ tiến trình của host (các lệnh copy bộ nhớ, chạy kernel,…) có thể sử dụng các tài nguyên này. Bởi vì đã có một CUDA context được tạo ra như là một phần của sự khởi tạo và được tương ứng với tiến trình của host và nó không thể được sử dụng cho bất kỳ tiến trình host nào khác.
Trên hệ thống có nhiều device, các kernel được thực hiện trên device 0 theo mặc định.