diff --git a/common_thread.h b/common_thread.h index e9b76a8805..760717e8f1 100644 --- a/common_thread.h +++ b/common_thread.h @@ -106,7 +106,15 @@ typedef struct blas_queue { blas_arg_t *args; void *range_m; void *range_n; + + /* + * sa and sb are caller-owned inputs. worker_sb reports the sb workspace + * used by the threading backend for the most recent invocation. + * Keeping these roles separate prevents a reused queue from treating a + * released workspace as input to its next invocation. + */ void *sa, *sb; + void *worker_sb; struct blas_queue *next; @@ -183,6 +191,7 @@ static __inline void blas_queue_init(blas_queue_t *queue){ queue -> sa = NULL; queue -> sb = NULL; + queue -> worker_sb = NULL; queue-> next = NULL; } diff --git a/cpp_thread_test/CMakeLists.txt b/cpp_thread_test/CMakeLists.txt index 5271d4594c..13307611e0 100644 --- a/cpp_thread_test/CMakeLists.txt +++ b/cpp_thread_test/CMakeLists.txt @@ -29,6 +29,10 @@ if (CPP_THREAD_SAFETY_TEST) add_executable(dgemm_thread_safety_mixed dgemm_thread_safety_mixed.cpp) target_link_libraries(dgemm_thread_safety_mixed ${CPP_THREAD_SAFETY_LIBS}) add_test(NAME dgemm_thread_safety_mixed COMMAND ${CMAKE_CURRENT_BINARY_DIR}/dgemm_thread_safety_mixed ${CPP_THREAD_SAFETY_DGEMM_MIXED_ARGS}) + + if (USE_THREAD AND (USE_OPENMP OR (NOT WIN32 AND NOT CYGWIN))) + add_test(NAME dgemm_thread_safety_mixed_callback COMMAND ${CMAKE_CURRENT_BINARY_DIR}/dgemm_thread_safety_mixed ${CPP_THREAD_SAFETY_DGEMM_MIXED_ARGS} --callback) + endif() endif() diff --git a/cpp_thread_test/Makefile b/cpp_thread_test/Makefile index fe7a286251..8c2d347b00 100644 --- a/cpp_thread_test/Makefile +++ b/cpp_thread_test/Makefile @@ -3,6 +3,22 @@ include $(TOPDIR)/Makefile.system all :: dgemv_tester dgemm_tester dgemm_mixed_tester +CALLBACK_THREAD_TEST = +ifeq ($(SMP),1) +ifeq ($(USE_OPENMP),1) +CALLBACK_THREAD_TEST = 1 +else +ifneq ($(OSNAME),$(filter $(OSNAME),WINNT CYGWIN_NT)) +CALLBACK_THREAD_TEST = 1 +endif +endif +endif + +ifeq ($(CALLBACK_THREAD_TEST),1) +.PHONY : dgemm_mixed_callback_tester +all :: dgemm_mixed_callback_tester +endif + dgemv_tester : $(CXX) $(COMMON_OPT) -Wall -Wextra -Wshadow -std=c++11 dgemv_thread_safety.cpp ../$(LIBNAME) $(EXTRALIB) $(FEXTRALIB) -o dgemv_tester ./dgemv_tester @@ -15,5 +31,10 @@ dgemm_mixed_tester : dgemm_tester $(CXX) $(COMMON_OPT) -Wall -Wextra -Wshadow -std=c++11 dgemm_thread_safety_mixed.cpp ../$(LIBNAME) $(EXTRALIB) $(FEXTRALIB) -o dgemm_mixed_tester ./dgemm_mixed_tester +ifeq ($(CALLBACK_THREAD_TEST),1) +dgemm_mixed_callback_tester : dgemm_mixed_tester + ./dgemm_mixed_tester --callback +endif + clean :: rm -f dgemv_tester dgemm_tester dgemm_mixed_tester diff --git a/cpp_thread_test/dgemm_thread_safety_mixed.cpp b/cpp_thread_test/dgemm_thread_safety_mixed.cpp index 1ad021bb33..62d6b83832 100644 --- a/cpp_thread_test/dgemm_thread_safety_mixed.cpp +++ b/cpp_thread_test/dgemm_thread_safety_mixed.cpp @@ -14,6 +14,21 @@ #endif #include "cpp_thread_safety_common.h" +std::atomic callbackInvocations(0); + +void thread_callback(int sync, openblas_dojob_callback doJob, int numJobs, + size_t jobDataElementSize, void* jobData, int doJobData){ + (void)sync; + callbackInvocations.fetch_add(1, std::memory_order_relaxed); + std::vector workers; + workers.reserve(numJobs); + char* jobs = static_cast(jobData); + for(int i=0; i& transA, std::vector& noTransA, std::vector& B, double* firstOutput, double* secondOutput, const blasint randomMatSize, const bool sameVariant){ cblas_dgemm(CblasRowMajor, CblasTrans, CblasNoTrans, randomMatSize, 2, 2, 1.0, &transA[0], randomMatSize, &B[0], 2, 0.0, firstOutput, 2); if (sameVariant) @@ -48,26 +63,31 @@ int main(int argc, char* argv[]){ uint32_t numTestRounds = 200; uint32_t maxHwThreads = GetMaxHwThreads(); bool sameVariant = false; + bool useCallback = false; if (maxHwThreads < numConcurrentThreads) numConcurrentThreads = maxHwThreads; - if (argc != 1 && argc != 4 && argc != 5){ - std::cout<<"ERROR: expected zero arguments, or: [sameVariant]"< positionalArgs; + for (int i = 1; i < argc; i++){ + std::cout< [sameVariant]] [--callback]"< cliArgs; - for (int i = 1; i < argc; i++){ - cliArgs.push_back(argv[i]); - std::cout<(matrixElements) * 2 * 8 + static_cast(outputElements) * (2 + 2 * numConcurrentThreads) * 8)/static_cast(1024*1024)<<" MiB of RAM\n"< routine; + queue->worker_sb = queue->sb; if (queue -> mode & BLAS_LEGACY) { legacy_exec(routine, queue -> mode, queue -> args, queue -> sb); @@ -1140,9 +1141,10 @@ if (!(queue -> mode & BLAS_COMPLEX)){ /* Other types in future */ } } -queue->sb=sb; } + queue->worker_sb = sb; + #ifdef MONITOR main_status[cpu] = MAIN_RUNNING2; #endif diff --git a/driver/others/blas_server_omp.c b/driver/others/blas_server_omp.c index d77fbea659..6044a790c4 100644 --- a/driver/others/blas_server_omp.c +++ b/driver/others/blas_server_omp.c @@ -329,7 +329,6 @@ static void exec_threads(int thread_num, blas_queue_t *queue, int buf_index){ if (sa == NULL) { sa = (void *)((BLASLONG)buffer + GEMM_OFFSET_A); - queue->sa=sa; } if (sb == NULL) { @@ -378,10 +377,11 @@ fprintf(stderr,"UNHANDLED COMPLEX\n"); /* Other types in future */ } } - queue->sb=sb; } } + queue->worker_sb = sb; + if (queue -> mode & BLAS_LEGACY) { legacy_exec(queue -> routine, queue -> mode, queue -> args, sb); } else diff --git a/driver/others/blas_server_win32.c b/driver/others/blas_server_win32.c index c8aa4c50b0..e827ceea0b 100644 --- a/driver/others/blas_server_win32.c +++ b/driver/others/blas_server_win32.c @@ -311,9 +311,10 @@ static DWORD WINAPI blas_thread_server(void *arg){ /* Other types in future */ } } - queue->sb=sb; } + queue->worker_sb = sb; + #ifdef MONITOR main_status[cpu] = MAIN_RUNNING2; #endif @@ -483,6 +484,7 @@ int exec_blas(BLASLONG num, blas_queue_t *queue){ if ((num > 1) && queue -> next) exec_blas_async(1, queue -> next); routine = queue -> routine; + queue->worker_sb = queue->sb; if (queue -> mode & BLAS_LEGACY) { legacy_exec(routine, queue -> mode, queue -> args, queue -> sb);