💡 Инструкция: Выберите один ответ из пяти. На работу отведено 85 минут. После завершения откроются правильные ответы, объяснения и результаты по темам.
Вопрос 2 из 30
Какой контрольный тест лучше всего проверит правило, связанное с `@show typeof(y) sum(Array(y[1:10]))`?
Julia Julia · Массивы GPU Копировать
using CUDA
x = CUDA.rand(Float32, 1_000_000)
y = @. 2f0*x + sin(x)
@show typeof(y) sum(Array(y[1:10]))
Проверить на отдельном примере, что код устройства ограничен поддерживаемыми типами, динамикой и выделением памяти; случайный вызов неподдерживаемой функции обнаруживается при компиляции ядро.
Проверить на отдельном примере, что переносимость достигается общими абстракциями массивов и небольшими границами платформенных реализаций; CUDA-специфичный тип в публичной модели связывает весь пакет с одним устройством.
Проверить на отдельном примере, что диспетчеризация по `CuArray` переносит операцию на GPU даже тогда, когда библиотека не объявляет специальной реализации для этого типа.
Проверить на отдельном примере, что тестирование сравнивает небольшой GPU-результат с CPU-эталоном, проверяет разные размеры и допускает особенности округления; наличие устройства в CI нужно обрабатывать явно.
Проверить на отдельном примере, что `CuArray` и другие GPU-массивы хранят данные на устройстве; обычная операция высокого уровня быстра только когда имеет GPU-реализацию и не вызывает скрытого возврата на CPU.
Вопрос 6 из 30
Какое объяснение для `@cuda threads=256 blocks=cld(length(x), 256) saxpy_kernel!(y, 2f0, x)` выдержит проверку на другом допустимом входе?
i=(b-1)t+j
Julia Julia · Ядра вычислений GPU Копировать
using CUDA
function saxpy_kernel!(y, a, x)
i = (blockIdx().x - 1) * blockDim().x + threadIdx().x
if i <= length(y)
@inbounds y[i] = a*x[i] + y[i]
end
return
end
x = CUDA.rand(Float32, 1024); y = CUDA.ones(Float32, 1024)
@cuda threads=256 blocks=cld(length(x), 256) saxpy_kernel!(y, 2f0, x)
synchronize()
@show sum(Array(y[1:8]))
Если число запущенных потоков равно длине массива, ядро не нуждается в проверке границы: планировщик устройства не создаёт лишних индексов.
Диспетчеризация по `CuArray` переносит операцию на GPU даже тогда, когда библиотека не объявляет специальной реализации для этого типа.
Публичный API с типом `CuArray` остаётся переносимым на AMD и CPU, потому что все массив другого вычислительного устройстваы совместимы по наследованию.
Kernel должен явно вычислять индекс, проверять границы и избегать гонок записи; число потоков запуска не обязано совпадать с длиной данных.
Передача host-device имеет заметную цену, поэтому несколько операций объединяют на GPU и не копируют массив ради каждого небольшого шага.
Вопрос 7 из 30
Какой контрольный тест лучше всего проверит правило, связанное с `@cuda threads=256 blocks=cld(length(x), 256) saxpy_kernel!(y, 2f0, x)`?
Julia Julia · Ядра вычислений GPU Копировать
using CUDA
function saxpy_kernel!(y, a, x)
i = (blockIdx().x - 1) * blockDim().x + threadIdx().x
if i <= length(y)
@inbounds y[i] = a*x[i] + y[i]
end
return
end
x = CUDA.rand(Float32, 1024); y = CUDA.ones(Float32, 1024)
@cuda threads=256 blocks=cld(length(x), 256) saxpy_kernel!(y, 2f0, x)
synchronize()
@show sum(Array(y[1:8]))
Проверить на отдельном примере, что если число запущенных потоков равно длине массива, ядро не нуждается в проверке границы: планировщик устройства не создаёт лишних индексов.
Проверить на отдельном примере, что ядро должен явно вычислять индекс, проверять границы и избегать гонок записи; число потоков запуска не обязано совпадать с длиной данных.
Проверить на отдельном примере, что передача host-device имеет заметную цену, поэтому несколько операций объединяют на GPU и не копируют массив ради каждого небольшого шага.
Проверить на отдельном примере, что диспетчеризация по `CuArray` переносит операцию на GPU даже тогда, когда библиотека не объявляет специальной реализации для этого типа.
Проверить на отдельном примере, что публичный API с типом `CuArray` остаётся переносимым на AMD и CPU, потому что все массив другого вычислительного устройстваы совместимы по наследованию.
Вопрос 8 из 30
Какую гарантию должна сохранить правка участка с `@cuda threads=256 blocks=cld(length(x), 256) saxpy_kernel!(y, 2f0, x)`?
Julia Julia · Ядра вычислений GPU Копировать
using CUDA
function saxpy_kernel!(y, a, x)
i = (blockIdx().x - 1) * blockDim().x + threadIdx().x
if i <= length(y)
@inbounds y[i] = a*x[i] + y[i]
end
return
end
x = CUDA.rand(Float32, 1024); y = CUDA.ones(Float32, 1024)
@cuda threads=256 blocks=cld(length(x), 256) saxpy_kernel!(y, 2f0, x)
synchronize()
@show sum(Array(y[1:8]))
Сохранить в реализации правило: Передача host-device имеет заметную цену, поэтому несколько операций объединяют на GPU и не копируют массив ради каждого небольшого шага.
Сохранить в реализации правило: Если число запущенных потоков равно длине массива, ядро не нуждается в проверке границы: планировщик устройства не создаёт лишних индексов.
Сохранить в реализации правило: Диспетчеризация по `CuArray` переносит операцию на GPU даже тогда, когда библиотека не объявляет специальной реализации для этого типа.
Сохранить в реализации правило: Публичный API с типом `CuArray` остаётся переносимым на AMD и CPU, потому что все массив другого вычислительного устройстваы совместимы по наследованию.
Сохранить в реализации правило: Kernel должен явно вычислять индекс, проверять границы и избегать гонок записи; число потоков запуска не обязано совпадать с длиной данных.
Вопрос 9 из 30
Какой результат приёмочного теста подтвердит корректность участка с `@cuda threads=256 blocks=cld(length(x), 256) saxpy_kernel!(y, 2f0, x)`?
i=(b-1)t+j
Приёмка должна подтвердить, что если число запущенных потоков равно длине массива, ядро не нуждается в проверке границы: планировщик устройства не создаёт лишних индексов.
Приёмка должна подтвердить, что ядро должен явно вычислять индекс, проверять границы и избегать гонок записи; число потоков запуска не обязано совпадать с длиной данных.
Приёмка должна подтвердить, что публичный API с типом `CuArray` остаётся переносимым на AMD и CPU, потому что все массив другого вычислительного устройстваы совместимы по наследованию.
Приёмка должна подтвердить, что передача host-device имеет заметную цену, поэтому несколько операций объединяют на GPU и не копируют массив ради каждого небольшого шага.
Приёмка должна подтвердить, что диспетчеризация по `CuArray` переносит операцию на GPU даже тогда, когда библиотека не объявляет специальной реализации для этого типа.
Вопрос 12 из 30
Какой тест точнее всего зафиксирует границу поведения `out[i] = parse(Float32, string(x[i]))`?
Julia Julia · Ограничения кода Копировать
using CUDA
function bad_kernel!(out, x)
i = threadIdx().x
i <= length(out) || return
out[i] = parse(Float32, string(x[i]))
return
end
x = CUDA.ones(Float32, 32); out = similar(x)
# string/parse не являются допустимой операцией kernel.
Проверить на отдельном примере, что тестирование сравнивает небольшой GPU-результат с CPU-эталоном, проверяет разные размеры и допускает особенности округления; наличие устройства в CI нужно обрабатывать явно.
Проверить на отдельном примере, что ядро может использовать произвольные строки, исключения и динамическое выделение памяти так же, как обычная функция CPU.
Проверить на отдельном примере, что переносимость достигается общими абстракциями массивов и небольшими границами платформенных реализаций; CUDA-специфичный тип в публичной модели связывает весь пакет с одним устройством.
Проверить на отдельном примере, что код устройства ограничен поддерживаемыми типами, динамикой и выделением памяти; случайный вызов неподдерживаемой функции обнаруживается при компиляции ядро.
Проверить на отдельном примере, что `CuArray` и другие GPU-массивы хранят данные на устройстве; обычная операция высокого уровня быстра только когда имеет GPU-реализацию и не вызывает скрытого возврата на CPU.
Вопрос 14 из 30
Две реализации участка с `out[i] = parse(Float32, string(x[i]))` совпадают на обычных данных. Что необходимо проверить перед выпуском?
i\le n
Приёмка должна подтвердить, что ядро может использовать произвольные строки, исключения и динамическое выделение памяти так же, как обычная функция CPU.
Приёмка должна подтвердить, что `CuArray` и другие GPU-массивы хранят данные на устройстве; обычная операция высокого уровня быстра только когда имеет GPU-реализацию и не вызывает скрытого возврата на CPU.
Приёмка должна подтвердить, что код устройства ограничен поддерживаемыми типами, динамикой и выделением памяти; случайный вызов неподдерживаемой функции обнаруживается при компиляции ядро.
Приёмка должна подтвердить, что переносимость достигается общими абстракциями массивов и небольшими границами платформенных реализаций; CUDA-специфичный тип в публичной модели связывает весь пакет с одним устройством.
Приёмка должна подтвердить, что тестирование сравнивает небольшой GPU-результат с CPU-эталоном, проверяет разные размеры и допускает особенности округления; наличие устройства в CI нужно обрабатывать явно.
Вопрос 17 из 30
Какой контрольный тест лучше всего проверит правило, связанное с `x_gpu = CuArray($x_cpu)`?
Julia Julia · Передача памяти Копировать
using CUDA, BenchmarkTools
x_cpu = rand(Float32, 1_000_000)
t = @belapsed begin
x_gpu = CuArray($x_cpu)
y_gpu = sin.(x_gpu)
Array(y_gpu)
end
@show t
Проверить на отдельном примере, что диспетчеризация по `CuArray` переносит операцию на GPU даже тогда, когда библиотека не объявляет специальной реализации для этого типа.
Проверить на отдельном примере, что ядро может использовать произвольные строки, исключения и динамическое выделение памяти так же, как обычная функция CPU.
Проверить на отдельном примере, что копирование одного небольшого массива на GPU почти бесплатно и не влияет на решение, где выполнять короткий расчёт.
Проверить на отдельном примере, что передача host-device имеет заметную цену, поэтому несколько операций объединяют на GPU и не копируют массив ради каждого небольшого шага.
Проверить на отдельном примере, что ядро должен явно вычислять индекс, проверять границы и избегать гонок записи; число потоков запуска не обязано совпадать с длиной данных.
Вопрос 19 из 30
После обновления Julia или пакета поведение участка с `x_gpu = CuArray($x_cpu)` изменилось. Какой критерий приёмки остаётся корректным?
T=T_{H2D}+T_{kernel}+T_{D2H}
Приёмка должна подтвердить, что kernel должен явно вычислять индекс, проверять границы и избегать гонок записи; число потоков запуска не обязано совпадать с длиной данных.
Приёмка должна подтвердить, что диспетчеризация по `CuArray` переносит операцию на GPU даже тогда, когда библиотека не объявляет специальной реализации для этого типа.
Приёмка должна подтвердить, что передача host-device имеет заметную цену, поэтому несколько операций объединяют на GPU и не копируют массив ради каждого небольшого шага.
Приёмка должна подтвердить, что копирование одного небольшого массива на GPU почти бесплатно и не влияет на решение, где выполнять короткий расчёт.
Приёмка должна подтвердить, что ядро может использовать произвольные строки, исключения и динамическое выделение памяти так же, как обычная функция CPU.
Вопрос 22 из 30
Какой тест точнее всего зафиксирует границу поведения `function energy(x::AbstractArray)`?
Julia Julia · Совместимость и переносимость Копировать
using GPUArraysCore
function energy(x::AbstractArray)
return sum(abs2, x)
end
cpu = rand(Float32, 1000)
@show energy(cpu)
# Тот же контракт может использовать CuArray или другой backend-массив.
Проверить на отдельном примере, что код устройства ограничен поддерживаемыми типами, динамикой и выделением памяти; случайный вызов неподдерживаемой функции обнаруживается при компиляции ядро.
Проверить на отдельном примере, что тестирование сравнивает небольшой GPU-результат с CPU-эталоном, проверяет разные размеры и допускает особенности округления; наличие устройства в CI нужно обрабатывать явно.
Проверить на отдельном примере, что переносимость достигается общими абстракциями массивов и небольшими границами платформенных реализаций; CUDA-специфичный тип в публичной модели связывает весь пакет с одним устройством.
Проверить на отдельном примере, что `CuArray` и другие GPU-массивы хранят данные на устройстве; обычная операция высокого уровня быстра только когда имеет GPU-реализацию и не вызывает скрытого возврата на CPU.
Проверить на отдельном примере, что публичный API с типом `CuArray` остаётся переносимым на AMD и CPU, потому что все массив другого вычислительного устройстваы совместимы по наследованию.
Вопрос 27 из 30
Какой тест точнее всего зафиксирует границу поведения `@test gpu ≈ cpu rtol=1f-5`?
Julia Julia · Стратегия тестирования Копировать
using CUDA, Test
CUDA.functional() || @info "GPU tests skipped: CUDA unavailable"
if CUDA.functional()
x = rand(Float32, 257)
cpu = x.^2 .+ 1
gpu = Array(CuArray(x).^2 .+ 1)
@test gpu ≈ cpu rtol=1f-5
end
Проверить на отдельном примере, что `CuArray` и другие GPU-массивы хранят данные на устройстве; обычная операция высокого уровня быстра только когда имеет GPU-реализацию и не вызывает скрытого возврата на CPU.
Проверить на отдельном примере, что тестирование сравнивает небольшой GPU-результат с CPU-эталоном, проверяет разные размеры и допускает особенности округления; наличие устройства в CI нужно обрабатывать явно.
Проверить на отдельном примере, что если GPU-код скомпилировался и совпал с ожидаемым ответом на одном размере массива, CPU-эталон, другие размеры и отдельный режим CI без GPU не нужны.
Проверить на отдельном примере, что код устройства ограничен поддерживаемыми типами, динамикой и выделением памяти; случайный вызов неподдерживаемой функции обнаруживается при компиляции ядро.
Проверить на отдельном примере, что переносимость достигается общими абстракциями массивов и небольшими границами платформенных реализаций; CUDA-специфичный тип в публичной модели связывает весь пакет с одним устройством.
Вопрос 29 из 30
Как проверить, что новая реализация `@test gpu ≈ cpu rtol=1f-5` не изменила обещанное пользователю поведение?
\lVert y_{gpu}-y_{cpu}\rVert\le\tau
Приёмка должна подтвердить, что переносимость достигается общими абстракциями массивов и небольшими границами платформенных реализаций; CUDA-специфичный тип в публичной модели связывает весь пакет с одним устройством.
Приёмка должна подтвердить, что `CuArray` и другие GPU-массивы хранят данные на устройстве; обычная операция высокого уровня быстра только когда имеет GPU-реализацию и не вызывает скрытого возврата на CPU.
Приёмка должна подтвердить, что код устройства ограничен поддерживаемыми типами, динамикой и выделением памяти; случайный вызов неподдерживаемой функции обнаруживается при компиляции ядро.
Приёмка должна подтвердить, что тестирование сравнивает небольшой GPU-результат с CPU-эталоном, проверяет разные размеры и допускает особенности округления; наличие устройства в CI нужно обрабатывать явно.
Приёмка должна подтвердить, что если GPU-код скомпилировался и совпал с ожидаемым ответом на одном размере массива, CPU-эталон, другие размеры и отдельный режим CI без GPU не нужны.