diff --git a/src/context.hpp b/src/context.hpp index cbfaaa8a..de3314e6 100644 --- a/src/context.hpp +++ b/src/context.hpp @@ -35,7 +35,7 @@ struct cvk_context : public _cl_context, cvk_context(cvk_device* device, const cl_context_properties* props, void* user_data) - : m_device(device) { + : m_device(device), m_user_data(user_data) { if (props) { while (*props) { @@ -49,23 +49,21 @@ struct cvk_context : public _cl_context, } // Get printf buffer size from extension. auto buff_size_prop_index = - get_property_index(CL_PRINTF_BUFFERSIZE_ARM); + get_property_value_index(CL_PRINTF_BUFFERSIZE_ARM); if (buff_size_prop_index != -1 && !config.printf_buffer_size.set) { m_printf_buffersize = m_properties[buff_size_prop_index]; } else { - m_printf_buffersize = config.printf_buffer_size; + m_printf_buffersize = 0; } // Get printf callback from extension auto printf_callback_prop_index = - get_property_index(CL_PRINTF_CALLBACK_ARM); + get_property_value_index(CL_PRINTF_CALLBACK_ARM); if (printf_callback_prop_index != -1) { m_printf_callback = (cvk_printf_callback_t)m_properties[printf_callback_prop_index]; - m_user_data = user_data; } else { m_printf_callback = nullptr; - m_user_data = nullptr; } } @@ -99,7 +97,7 @@ struct cvk_context : public _cl_context, return size <= m_device->max_mem_alloc_size(); } - int get_property_index(const int prop) { + int get_property_value_index(const int prop) { for (unsigned i = 0; i < m_properties.size(); i += 2) { if (m_properties[i] == prop) { return i + 1; @@ -108,7 +106,13 @@ struct cvk_context : public _cl_context, return -1; } - size_t get_printf_buffersize() { return m_printf_buffersize; } + size_t get_printf_buffersize() { + if (m_printf_buffersize) { + return m_printf_buffersize; + } else { + return config.printf_buffer_size; + } + } cvk_printf_callback_t get_printf_callback() { return m_printf_callback; } void* get_printf_userdata() { return m_user_data; } diff --git a/tests/api/printf.cpp b/tests/api/printf.cpp index cbade14c..570336fd 100644 --- a/tests/api/printf.cpp +++ b/tests/api/printf.cpp @@ -18,105 +18,7 @@ #include "unit.hpp" #include "utils.hpp" -#include - -#ifdef __APPLE__ -#include -#endif - -#ifdef WIN32 -#include -#include -#endif - -void printf_callback(const char* buffer, size_t len, size_t complete, - void* user_data) { - std::string* user_buffer = (std::string*)user_data; - *user_buffer += std::string(buffer); -} - -static std::string stdoutFileName; - -#define BUFFER_SIZE 1024 -static char stdoutBuffer[BUFFER_SIZE]; - -static void releaseStdout(int fd) { - fflush(stdout); - dup2(fd, fileno(stdout)); - close(fd); -} - -static bool getStdout(int& fd) { - fd = dup(fileno(stdout)); - if (!freopen(stdoutFileName.c_str(), "w", stdout)) { - fprintf(stderr, "ERROR!\n"); - releaseStdout(fd); - return false; - } - return true; -} - -static char* getStdoutContent() { - FILE* f; - memset(stdoutBuffer, 0, BUFFER_SIZE); - fflush(stdout); - f = fopen(stdoutFileName.c_str(), "r"); - if (f == nullptr) - return nullptr; - - char* ptr = stdoutBuffer; - do { - ptr += strlen(ptr); - ptr = fgets(ptr, BUFFER_SIZE, f); - } while (ptr != nullptr); - fclose(f); - - return stdoutBuffer; -} - -struct temp_folder_deletion { - ~temp_folder_deletion() { - if (!m_path.empty()) - std::filesystem::remove_all(m_path.c_str()); - } - void set_path(std::string path) { m_path = path; } - -private: - std::string m_path; -}; - -static char* mkdtemp(char* tmpl, size_t size) { -#ifdef WIN32 - if (_mktemp_s(tmpl, size + 1) != 0) { - return nullptr; - } - - if (!CreateDirectory(tmpl, nullptr)) { - return nullptr; - } - - return tmpl; -#else - return mkdtemp(tmpl); -#endif -} - -static std::string getStdoutFileName(temp_folder_deletion& temp) { - char template_tmp_dir[] = "clvk-XXXXXX"; - std::filesystem::path prefix( - mkdtemp(template_tmp_dir, sizeof(template_tmp_dir))); - std::filesystem::path suffix("stdout_buffer"); - temp.set_path(prefix.string()); - return (prefix / suffix).string(); -} - -TEST_F(WithCommandQueue, SimplePrintf) { - temp_folder_deletion temp; - stdoutFileName = getStdoutFileName(temp); - - int fd; - ASSERT_TRUE(getStdout(fd)); - +TEST_F(WithCommandQueueAndPrintf, SimplePrintf) { const char message[] = "Hello World!"; char source[512]; sprintf(source, "kernel void test_printf() { printf(\"%s\");}", message); @@ -127,22 +29,14 @@ TEST_F(WithCommandQueue, SimplePrintf) { EnqueueNDRangeKernel(kernel, 1, nullptr, &gws, &lws, 0, nullptr, nullptr); Finish(); - releaseStdout(fd); - auto printf_buffer = getStdoutContent(); - ASSERT_NE(printf_buffer, nullptr); - - ASSERT_STREQ(printf_buffer, message); + ASSERT_STREQ(m_printf_output.c_str(), message); } -TEST_F(WithCommandQueueNoSetUp, TooLongPrintf) { - std::string buffer = ""; +TEST_F(WithCommandQueueAndPrintf, TooLongPrintf) { // each print takes 12 bytes (4 for the printf_id, and 2*4 for the 2 integer // to print) + 4 for the byte written counter - cl_context_properties properties[4] = { - CL_PRINTF_CALLBACK_ARM, (cl_context_properties)printf_callback, - CL_PRINTF_BUFFERSIZE_ARM, (cl_context_properties)28}; - WithCommandQueue::SetUpWithContextProperties( - properties, reinterpret_cast(&buffer)); + auto cfg1 = + CLVK_CONFIG_SCOPED_OVERRIDE(printf_buffer_size, uint32_t, 28, true); // We only get the first 2 prints because the buffer is too small to get // the last one. @@ -162,19 +56,15 @@ TEST_F(WithCommandQueueNoSetUp, TooLongPrintf) { EnqueueNDRangeKernel(kernel, 1, nullptr, &gws, &lws, 0, nullptr, nullptr); Finish(); - ASSERT_STREQ(buffer.c_str(), message); + ASSERT_STREQ(m_printf_output.c_str(), message); } -TEST_F(WithCommandQueueNoSetUp, TooLongPrintf2) { - std::string buffer = ""; +TEST_F(WithCommandQueueAndPrintf, TooLongPrintf2) { // each print takes 12 bytes (4 for the printf_id, and 2*4 for the 2 integer // to print) + 4 for the byte written counter + 8 which are not enough for // the third print, but should not cause any issue in clvk - cl_context_properties properties[4] = { - CL_PRINTF_CALLBACK_ARM, (cl_context_properties)printf_callback, - CL_PRINTF_BUFFERSIZE_ARM, (cl_context_properties)36}; - WithCommandQueue::SetUpWithContextProperties( - properties, reinterpret_cast(&buffer)); + auto cfg1 = + CLVK_CONFIG_SCOPED_OVERRIDE(printf_buffer_size, uint32_t, 36, true); // We only get the first 2 prints because the buffer is too small to get // the last one. @@ -194,16 +84,10 @@ TEST_F(WithCommandQueueNoSetUp, TooLongPrintf2) { EnqueueNDRangeKernel(kernel, 1, nullptr, &gws, &lws, 0, nullptr, nullptr); Finish(); - ASSERT_STREQ(buffer.c_str(), message); + ASSERT_STREQ(m_printf_output.c_str(), message); } -TEST_F(WithCommandQueue, PrintfMissingLengthModifier) { - temp_folder_deletion temp; - stdoutFileName = getStdoutFileName(temp); - - int fd; - ASSERT_TRUE(getStdout(fd)); - +TEST_F(WithCommandQueueAndPrintf, PrintfMissingLengthModifier) { const char message[] = "1,2,3,4"; char source[512]; sprintf(source, @@ -216,11 +100,7 @@ TEST_F(WithCommandQueue, PrintfMissingLengthModifier) { EnqueueNDRangeKernel(kernel, 1, nullptr, &gws, &lws, 0, nullptr, nullptr); Finish(); - releaseStdout(fd); - auto printf_buffer = getStdoutContent(); - ASSERT_NE(printf_buffer, nullptr); - - ASSERT_STREQ(printf_buffer, message); + ASSERT_STREQ(m_printf_output.c_str(), message); } #endif diff --git a/tests/api/testcl.hpp b/tests/api/testcl.hpp index b012d849..878f6ab3 100644 --- a/tests/api/testcl.hpp +++ b/tests/api/testcl.hpp @@ -34,6 +34,7 @@ #define CL_USE_DEPRECATED_OPENCL_2_1_APIS #define CL_USE_DEPRECATED_OPENCL_2_2_APIS #include "CL/cl.h" +#include "CL/cl_ext.h" #ifdef CLVK_UNIT_TESTING_ENABLED #include "unit.hpp" @@ -211,11 +212,12 @@ class WithContext : public ::testing::Test { void SetUpWithContextProperties(const cl_context_properties* properties, void* user_data) { cl_int err; - m_context = clCreateContext( - properties, 1, &gDevice, - [](const char* errinfo, const void* private_info, size_t cb, - void* user_data) {}, - user_data, &err); + // TODO instrument calls to the context callback and validate that it's + // called in some tests + auto ctx_cb = [](const char* errinfo, const void* private_info, + size_t cb, void* user_data) {}; + m_context = + clCreateContext(properties, 1, &gDevice, ctx_cb, user_data, &err); ASSERT_CL_SUCCESS(err); } @@ -782,7 +784,20 @@ class WithProfiledCommandQueue : public WithCommandQueue { } }; -class WithCommandQueueNoSetUp : public WithCommandQueue { +static void printf_callback(const char* buffer, size_t len, size_t complete, + void* user_data) { + std::string* user_buffer = (std::string*)user_data; + *user_buffer += std::string(buffer); +} + +class WithCommandQueueAndPrintf : public WithCommandQueue { protected: - void SetUp() override{}; + void SetUp() override { + + cl_context_properties properties[2] = { + CL_PRINTF_CALLBACK_ARM, (cl_context_properties)printf_callback}; + WithCommandQueue::SetUpWithContextProperties( + properties, reinterpret_cast(&m_printf_output)); + }; + std::string m_printf_output{}; };