mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
276 lines
9.8 KiB
Swift
276 lines
9.8 KiB
Swift
// RUN: %target-run-simple-swift
|
|
// REQUIRES: executable_test
|
|
// REQUIRES: OS=macosx
|
|
|
|
// Translated from standard OpenCL hello.c program
|
|
|
|
// Abstract: A simple "Hello World" compute example showing basic usage of OpenCL which
|
|
// calculates the mathematical square (X[i] = pow(X[i],2)) for a buffer of
|
|
// floating point values.
|
|
//
|
|
//
|
|
// Version: <1.0>
|
|
//
|
|
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc. ("Apple")
|
|
// in consideration of your agreement to the following terms, and your use,
|
|
// installation, modification or redistribution of this Apple software
|
|
// constitutes acceptance of these terms. If you do not agree with these
|
|
// terms, please do not use, install, modify or redistribute this Apple
|
|
// software.
|
|
//
|
|
// In consideration of your agreement to abide by the following terms, and
|
|
// subject to these terms, Apple grants you a personal, non - exclusive
|
|
// license, under Apple's copyrights in this original Apple software ( the
|
|
// "Apple Software" ), to use, reproduce, modify and redistribute the Apple
|
|
// Software, with or without modifications, in source and / or binary forms
|
|
// provided that if you redistribute the Apple Software in its entirety and
|
|
// without modifications, you must retain this notice and the following text
|
|
// and disclaimers in all such redistributions of the Apple Software. Neither
|
|
// the name, trademarks, service marks or logos of Apple Inc. may be used to
|
|
// endorse or promote products derived from the Apple Software without specific
|
|
// prior written permission from Apple. Except as expressly stated in this
|
|
// notice, no other rights or licenses, express or implied, are granted by
|
|
// Apple herein, including but not limited to any patent rights that may be
|
|
// infringed by your derivative works or by other works in which the Apple
|
|
// Software may be incorporated.
|
|
//
|
|
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
|
// WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
|
// WARRANTIES OF NON - INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
|
|
// PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION
|
|
// ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
|
|
//
|
|
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
|
// CONSEQUENTIAL DAMAGES ( INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION ) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
|
|
// AND / OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER
|
|
// UNDER THEORY OF CONTRACT, TORT ( INCLUDING NEGLIGENCE ), STRICT LIABILITY OR
|
|
// OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
// Copyright ( C ) 2008 Apple Inc. All Rights Reserved.
|
|
//
|
|
|
|
|
|
import OpenCL
|
|
import StdlibUnittest
|
|
|
|
// Also import modules which are used by StdlibUnittest internally. This
|
|
// workaround is needed to link all required libraries in case we compile
|
|
// StdlibUnittest with -sil-serialize-all.
|
|
import SwiftPrivate
|
|
#if _runtime(_ObjC)
|
|
import ObjectiveC
|
|
#endif
|
|
|
|
import Foundation
|
|
import Darwin
|
|
|
|
let KernelSource = "\n" +
|
|
"__kernel void square( \n" +
|
|
" __global float* input, \n" +
|
|
" __global float* output, \n" +
|
|
" const unsigned int count) \n" +
|
|
"{ \n" +
|
|
" int i = get_global_id(0); \n" +
|
|
" if(i < count) \n" +
|
|
" output[i] = input[i] * input[i]; \n" +
|
|
"} \n" +
|
|
"\n"
|
|
|
|
|
|
let DATA_SIZE = 1024
|
|
|
|
var tests = TestSuite("MiscSDKOverlay")
|
|
|
|
tests.test("clSetKernelArgsListAPPLE") {
|
|
var err: cl_int // error code returned from api calls
|
|
|
|
var data = [Float](repeating: 0, count: DATA_SIZE) // original data set given to device
|
|
var results = [Float](repeating: 0, count: DATA_SIZE) // results returned from device
|
|
var correct: Int // number of correct results returned
|
|
|
|
var global: size_t // global domain size for our calculation
|
|
var local: size_t = 0 // local domain size for our calculation
|
|
|
|
var device_id: cl_device_id = nil // compute device id
|
|
var context: cl_context // compute context
|
|
var commands: cl_command_queue // compute command queue
|
|
var program: cl_program // compute program
|
|
var kernel: cl_kernel // compute kernel
|
|
|
|
var input: cl_mem // device memory used for the input array
|
|
var output: cl_mem // device memory used for the output array
|
|
|
|
// Fill our data set with random float values
|
|
//
|
|
var count = DATA_SIZE
|
|
for i in 0..<count {
|
|
data[i] = Float(rand()) / Float(RAND_MAX)
|
|
}
|
|
|
|
// Connect to a compute device
|
|
//
|
|
var gpu = 1
|
|
err = clGetDeviceIDs(nil, cl_device_type(gpu != 0 ? CL_DEVICE_TYPE_GPU : CL_DEVICE_TYPE_CPU), 1, &device_id, nil)
|
|
if (err != CL_SUCCESS)
|
|
{
|
|
print("Error: Failed to create a device group!")
|
|
exit(EXIT_FAILURE)
|
|
}
|
|
|
|
// Create a compute context
|
|
//
|
|
context = clCreateContext(nil, 1, &device_id, nil, nil, &err)
|
|
if (context == nil)
|
|
{
|
|
print("Error: Failed to create a compute context!")
|
|
exit(EXIT_FAILURE)
|
|
}
|
|
|
|
// Create a command commands
|
|
//
|
|
commands = clCreateCommandQueue(context, device_id, 0, &err)
|
|
if (commands == nil)
|
|
{
|
|
print("Error: Failed to create a command commands!")
|
|
exit(EXIT_FAILURE)
|
|
}
|
|
|
|
// Create the compute program from the source buffer
|
|
//
|
|
program = KernelSource.withCString {
|
|
(s: UnsafePointer<CChar>)->cl_program in
|
|
var s = s
|
|
return withUnsafeMutablePointer(&s) {
|
|
return clCreateProgramWithSource(context, 1, $0, nil, &err)
|
|
}
|
|
}
|
|
if (program == nil)
|
|
{
|
|
print("Error: Failed to create compute program!")
|
|
exit(EXIT_FAILURE)
|
|
}
|
|
|
|
// Build the program executable
|
|
//
|
|
err = clBuildProgram(program, 0, nil, nil, nil, nil)
|
|
if (err != CL_SUCCESS)
|
|
{
|
|
var len: Int = 0
|
|
|
|
var buffer = [CChar](repeating: 0, count: 2048)
|
|
|
|
print("Error: Failed to build program executable!")
|
|
clGetProgramBuildInfo(
|
|
program, device_id, cl_program_build_info(CL_PROGRAM_BUILD_LOG), 2048, &buffer, &len)
|
|
print("\(String(cString: buffer))")
|
|
exit(1)
|
|
}
|
|
|
|
// Create the compute kernel in the program we wish to run
|
|
//
|
|
kernel = clCreateKernel(program, "square", &err)
|
|
if (kernel == nil || err != cl_int(CL_SUCCESS))
|
|
{
|
|
print("Error: Failed to create compute kernel!")
|
|
exit(1)
|
|
}
|
|
|
|
// Create the input and output arrays in device memory for our calculation
|
|
//
|
|
input = clCreateBuffer(context, cl_mem_flags(CL_MEM_READ_ONLY), sizeof(Float.self) * count, nil, nil)
|
|
output = clCreateBuffer(context, cl_mem_flags(CL_MEM_WRITE_ONLY), sizeof(Float.self) * count, nil, nil)
|
|
if (input == nil || output == nil)
|
|
{
|
|
print("Error: Failed to allocate device memory!")
|
|
exit(1)
|
|
}
|
|
|
|
// Write our data set into the input array in device memory
|
|
//
|
|
err = clEnqueueWriteBuffer(commands, input, cl_bool(CL_TRUE), 0, sizeof(Float.self) * count, data, 0, nil, nil)
|
|
if (err != CL_SUCCESS)
|
|
{
|
|
print("Error: Failed to write to source array!")
|
|
exit(1)
|
|
}
|
|
|
|
// Set the arguments to our compute kernel
|
|
//
|
|
err = 0
|
|
err = withUnsafePointers(&input, &output, &count) {
|
|
inputPtr, outputPtr, countPtr in
|
|
clSetKernelArgsListAPPLE(
|
|
kernel, 3,
|
|
0, sizeof(cl_mem.self), inputPtr,
|
|
1, sizeof(cl_mem.self), outputPtr,
|
|
2, sizeofValue(count), countPtr)
|
|
}
|
|
|
|
|
|
if (err != CL_SUCCESS)
|
|
{
|
|
print("Error: Failed to set kernel arguments! \(err)")
|
|
exit(1)
|
|
}
|
|
|
|
// Get the maximum work group size for executing the kernel on the device
|
|
//
|
|
err = clGetKernelWorkGroupInfo(kernel, device_id, cl_kernel_work_group_info(CL_KERNEL_WORK_GROUP_SIZE), sizeofValue(local), &local, nil)
|
|
if (err != CL_SUCCESS)
|
|
{
|
|
print("Error: Failed to retrieve kernel work group info! \(err)")
|
|
exit(1)
|
|
}
|
|
|
|
// Execute the kernel over the entire range of our 1d input data set
|
|
// using the maximum number of work group items for this device
|
|
//
|
|
global = count
|
|
err = clEnqueueNDRangeKernel(commands, kernel, 1, nil, &global, &local, 0, nil, nil)
|
|
if (err != 0)
|
|
{
|
|
print("Error: Failed to execute kernel!")
|
|
exit(EXIT_FAILURE)
|
|
}
|
|
|
|
// Wait for the command commands to get serviced before reading back results
|
|
//
|
|
clFinish(commands)
|
|
|
|
// Read back the results from the device to verify the output
|
|
//
|
|
err = clEnqueueReadBuffer( commands, output, cl_bool(CL_TRUE), 0, sizeof(Float.self) * count, &results, cl_uint(0), nil, nil )
|
|
if (err != CL_SUCCESS)
|
|
{
|
|
print("Error: Failed to read output array! \(err)")
|
|
exit(1)
|
|
}
|
|
|
|
// Validate our results
|
|
//
|
|
correct = 0
|
|
for i in 0..<count
|
|
{
|
|
if(results[i] == data[i] * data[i]){
|
|
correct += 1
|
|
}
|
|
}
|
|
|
|
// Print a brief summary detailing the results
|
|
//
|
|
print("Computed '\(correct)/\(count)' correct values!")
|
|
|
|
// Shutdown and cleanup
|
|
//
|
|
clReleaseMemObject(input)
|
|
clReleaseMemObject(output)
|
|
clReleaseProgram(program)
|
|
clReleaseKernel(kernel)
|
|
clReleaseCommandQueue(commands)
|
|
clReleaseContext(context)
|
|
}
|
|
|
|
runAllTests()
|