// TODO: Can we do additional checks? CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuArrayGetDescriptor)(CUDA_ARRAY_DESCRIPTOR *pArrayDescriptor, CUarray hArray) { OrigFn fn; CUresult result; CUcontext ctx = NULL; cgCtxListType *ctxNode; cgArrListType *node; VALGRIND_GET_ORIG_FN(fn); cgLock(); CALL_FN_W_WW(result, fn, pArrayDescriptor, hArray); // Determine context of current thread .. cgGetCtx(&ctx); // .. locate the respective ctx node .. ctxNode = cgFindCtx(ctx); // .. and finally locate the array in the context's list of arrays. node = cgFindArr(ctxNode, hArray); if (result == CUDA_SUCCESS && !node) { VALGRIND_PRINTF("cuArrayGetDescriptor returned successfully, but array not found\n"); VALGRIND_PRINTF_BACKTRACE(" in cudagrind's internal list. Reason: Unknown\n"); } else if (result != CUDA_SUCCESS && node) { VALGRIND_PRINTF("cuArrayGetDescriptor returned with error code: %d,\n", result); VALGRIND_PRINTF_BACKTRACE(" but array is found in cudagrind's internal list.\n"); } else if (result != CUDA_SUCCESS) { VALGRIND_PRINTF("cuArrayGetDescriptor returned with error code: %d,\n", result); VALGRIND_PRINTF_BACKTRACE(" possible reason: Wrong context or array not previously created.\n"); } cgUnlock(); return result; }
/* * Adds the array residing in context ctx and referenced by dptr to the allocated array list. * * Input: * CUcontext ctx - CUDA context of array * CUarray dptr - device pointer of array */ void cgAddArr(CUcontext ctx, CUarray dptr) { cgCtxListType *ctxNode; cgArrListType *arrNode; // Initialize desc with dummy values CUDA_ARRAY3D_DESCRIPTOR desc = {0, 0, CU_AD_FORMAT_FLOAT, 0, 0, 0}; CUresult error; // Locate or create entry for context ctxNode = cgFindCtx(ctx); // Nasty hack: // If we call cuArray3DGetDescriptor first, its wrapper will // produce a spurious (albeit, at this point, legit) error message, // because the array is not contained in our internal list. But if // we call cgCtxAddArr first, we are missing the array descriptor! // -> We add the array with a dummy descriptor which in turn allows // us to fetch the original descriptor through the driver without // triggering the checks in the cuArray3DGetDescriptor wrapper. // // 1. Add array to internal list, including dummy descriptor cgCtxAddArr(ctxNode, dptr, desc); // 2. Get real descriptor, the wrapper wont complain now error = cuArray3DGetDescriptor(&desc, dptr); if (error != CUDA_SUCCESS) { VALGRIND_PRINTF("Error: cuArray3DGetDescriptor returned with %d in cgAddArr.\n", error); } // 3. Fetch node of array and set the real descriptor arrNode = cgFindArr(ctxNode, dptr); arrNode->desc = desc; #ifdef CUDAGRIND_DEBUG VALGRIND_PRINTF("Context list after 'cgAddArr' operation:\n"); printCtxList(); #endif }
int main (int argc, char **argv) { int x = 0; x += VALGRIND_PRINTF("Yo "); x += VALGRIND_PRINTF("Yo "); x += VALGRIND_PRINTF("Ma\n"); fprintf(stderr, "%d\n", x); x = VALGRIND_PRINTF_BACKTRACE("Backtrace line one\nLine two:\n"); fprintf(stderr, "%d\n", x); return 0; }
CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemcpyDtoDAsync)(CUdeviceptr dstDevice, CUdeviceptr srcDevice, size_t ByteCount, CUstream hStream) { int error = 0; long vgErrorAddress; vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&hStream, sizeof(CUstream)); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Error: 'hStream' in call to cuMemcpyDtoDAsync not defined.\n"); } cgLock(); CUcontext ctx = NULL; cgCtxListType *nodeCtx; cgMemListType *nodeMemDst, *nodeMemSrc; // Get current context .. cgGetCtx(&ctx); nodeCtx = cgFindCtx(ctx); // .. and locate memory if we are handling device memory nodeMemDst = cgFindMem(nodeCtx, dstDevice); nodeMemSrc = cgFindMem(nodeCtx, srcDevice); if (nodeMemDst && nodeMemDst->locked & 2 && nodeMemDst->stream != hStream) { error++; VALGRIND_PRINTF("Error: Concurrent write and read access by different streams.\n"); } if (nodeMemSrc && nodeMemSrc->locked && nodeMemSrc->stream != hStream) { error++; VALGRIND_PRINTF("Error: Concurrent write and read access by different streams.\n"); } if (nodeMemDst) { nodeMemDst->locked = nodeMemDst->locked | 2; nodeMemDst->stream = hStream; } if (nodeMemSrc) { nodeMemSrc->locked = nodeMemSrc->locked | 1; nodeMemSrc->stream = hStream; } cgUnlock(); if (error) { VALGRIND_PRINTF_BACKTRACE(""); } return cuMemcpyDtoD(dstDevice, srcDevice, ByteCount); }
/* * Removes the entry of array referenced by dptr from ctxNode's array list. * * Input: * cgCtxListType *ctxNode - The node from which dptr is to be removed * CUarray dptr - The device pointer of the to be removed array entry */ void cgCtxDelArr(cgCtxListType *ctxNode, CUarray dptr) { cgArrListType *toFree, *node = ctxNode->array; int deleted = 0; // Run through list of memory segments and remove it if it's found if (node) { if (node->dptr == dptr) { ctxNode->array = node->next; toFree = node; deleted = 1; } else { while (node->next && node->next->dptr != dptr) { node = node->next; } // If node->next is not NULL it has to contain dptr now if (node->next) { toFree = node->next; node->next = node->next->next; deleted = 1; } } } // Print error if the to be deletec device pointer can not be found if (!deleted) { VALGRIND_PRINTF("Error: Tried to remove non-existant device array reference in cgCtxDelArr.\n"); VALGRIND_PRINTF_BACKTRACE("Possible reason: Wrong CUDA context or double free on device array pointer.\n"); } else { // Else free the memory used by the node .. free(toFree); // TODO: Also remove the context entry if it's empty? And where? } }
/* * Adds an entry for the array referenced by dptr with given descriptor desc to the given context node ctxNode. * * cgCtxLisType *ctxNode - Node containing memory information for context * CUarray dptr - Device array reference (1D,2D or 3D) * CUDA_ARRAY3D_DESCRIPTOR desc- Descripter array referenced by dptr */ void cgCtxAddArr(cgCtxListType *ctxNode, CUarray dptr, CUDA_ARRAY3D_DESCRIPTOR desc) { cgArrListType *node; // Create new entry if list is still empty if (!(ctxNode->array)) { ctxNode->array = (cgArrListType*)malloc(sizeof(cgArrListType)); node = ctxNode->array; node->dptr = dptr; node->desc = desc; node->locked = 0; // Do not have to set node->stream here node->next = NULL; } else { node = ctxNode->array; while (node->next && node->dptr != dptr) { node = node->next; } if (node->dptr != dptr) { node->next = (cgArrListType*)malloc(sizeof(cgArrListType)); node = node->next; node->dptr = dptr; node->desc = desc; node->locked = 0; // Do not have to set node->stream here node->next = NULL; } else { VALGRIND_PRINTF("Error: Tried to add already existing array reference in cgCtxAddArr.\n"); VALGRIND_PRINTF_BACKTRACE("Possible reason: Unknown. This should not have happened!"); } } }
/* * Adds an entry for the device memory referenced by dptr of given size to the given context node ctxNode. * * cgCtxLisType *ctxNode - Node containing memory information for context * CUdeviceptr dptr - Device pointer to memory * size_t size - Size of memory referenced by dptr */ void cgCtxAddMem(cgCtxListType *ctxNode, CUdeviceptr dptr, size_t size) { cgMemListType *node; // Create new entry if list is still empty if (!(ctxNode->memory)) { ctxNode->memory = (cgMemListType*)malloc(sizeof(cgMemListType)); node = ctxNode->memory; node->dptr = dptr; node->isSymbol = 0; node->size = size; node->locked = 0; // Do not have to set node->stream here node->next = NULL; } else { node = ctxNode->memory; while (node->next && node->dptr != dptr) { node = node->next; } if (node->dptr != dptr) { node->next = (cgMemListType*)malloc(sizeof(cgMemListType)); node = node->next; node->dptr = dptr; node->isSymbol = 0; node->size = size; node->locked = 0; // Do not have to set node->stream here node->next = NULL; } else { VALGRIND_PRINTF("Error: Tried to add already existing device pointer in cgCtxAddMem.\n"); VALGRIND_PRINTF_BACKTRACE("Possible reason: Unknown. This should not have happened!"); } } }
int main (int argc, char **argv) { int x = VALGRIND_PRINTF("Yo"); printf ("%d\n", x); return 0; }
// The gcc constructor facility is used to initialize the POSIX Mutex that makes // Cudagrind threadsafe and output a welcome Message when it's being run. void __attribute__ ((constructor)) cgConstructor() { #ifndef CUDAGRIND_NOPTHREAD // If CUDAGRIND_NOTHREADS is int error; // Set to PTHREAD_MUTEX_RECURSIVE to enable recursive calls inside Cudagrind wrappers error = pthread_mutexattr_settype(&cgMutexAttr, PTHREAD_MUTEX_RECURSIVE); if (error) { VALGRIND_PRINTF("Error: Constructor failed to set mutex attribute with error %d.\n", error); } error = pthread_mutex_init(&cgMutex, &cgMutexAttr); if (error) { VALGRIND_PRINTF("Error: Constructor failed to set mutex attribute with error %d.\n", error); } #endif VALGRIND_PRINTF("\nWelcome to Cudagrind version %d.%d.%d\n\n", CG_VERSION_MAJOR, CG_VERSION_MINOR, CG_VERSION_REVISION); }
// Helper function that prints the current ctx/gpu-mem list on the screen void printCtxList() { cgCtxListType *ctxList = cgCtxList; cgMemListType *memList; cgArrListType *arrList; if (cgCtxList) { while (ctxList) { VALGRIND_PRINTF("CTX %lu: ", ctxList->ctx); memList = ctxList->memory; while (memList) { VALGRIND_PRINTF("%lu (%lu) -> ", memList->dptr, memList->size); memList = memList->next; } VALGRIND_PRINTF("\n"); if (ctxList->array) { VALGRIND_PRINTF(" Arr: "); arrList = ctxList->array; // TODO: More debug output (size) for arrays? while (arrList) { VALGRIND_PRINTF("%lu -> ", arrList->dptr); arrList = arrList->next; } VALGRIND_PRINTF("\n"); } ctxList = ctxList->next; } } else { VALGRIND_PRINTF("CTX list is currently empty!\n"); } }
ucs_log_func_rc_t ucs_log_default_handler(const char *file, unsigned line, const char *function, ucs_log_level_t level, const char *prefix, const char *message, va_list ap) { size_t buffer_size = ucs_config_memunits_get(ucs_global_opts.log_buffer_size, 256, 2048); const char *short_file; struct timeval tv; size_t length; char *buf; char *valg_buf; if (!ucs_log_enabled(level) && (level != UCS_LOG_LEVEL_PRINT)) { return UCS_LOG_FUNC_RC_CONTINUE; } buf = ucs_alloca(buffer_size + 1); buf[buffer_size] = 0; strncpy(buf, prefix, buffer_size); length = strlen(buf); vsnprintf(buf + length, buffer_size - length, message, ap); short_file = strrchr(file, '/'); short_file = (short_file == NULL) ? file : short_file + 1; gettimeofday(&tv, NULL); if (level <= ucs_global_opts.log_level_trigger) { ucs_handle_error(ucs_log_level_names[level], "%13s:%-4u %s: %s", short_file, line, ucs_log_level_names[level], buf); } else if (RUNNING_ON_VALGRIND) { valg_buf = ucs_alloca(buffer_size + 1); snprintf(valg_buf, buffer_size, "[%lu.%06lu] %16s:%-4u %-4s %-5s %s\n", tv.tv_sec, tv.tv_usec, short_file, line, "UCX", ucs_log_level_names[level], buf); VALGRIND_PRINTF("%s", valg_buf); } else if (ucs_log_initialized) { fprintf(ucs_log_file, "[%lu.%06lu] [%s:%-5d:%d] %16s:%-4u %-4s %-5s %s\n", tv.tv_sec, tv.tv_usec, ucs_log_hostname, ucs_log_pid, ucs_log_get_thread_num(), short_file, line, "UCX", ucs_log_level_names[level], buf); } else { fprintf(stdout, "[%lu.%06lu] %16s:%-4u %-4s %-5s %s\n", tv.tv_sec, tv.tv_usec, short_file, line, "UCX", ucs_log_level_names[level], buf); } /* flush the log file if the log_level of this message is fatal or error */ if (level <= UCS_LOG_LEVEL_ERROR) { ucs_log_flush(); } return UCS_LOG_FUNC_RC_CONTINUE; }
// The gcc destructor facility is used to clear the POSIX Mutex void __attribute__ ((destructor)) cgDestructor() { #ifndef CUDAGRIND_NOPTHREAD int error; error = pthread_mutex_destroy(&cgMutex); if (error) { VALGRIND_PRINTF("Error: Deconstructor failed to free mutex with error %d.\n", error); } #endif // Search through whole context and memory/array lists for unfreed memory. // Memory allocated to handle symboles will be ignored. cgCtxListType *nodeCtx = cgCtxList; cgMemListType *nodeMem; cgArrListType *nodeArr; int countMem = 0, countArr = 0; size_t sizeMem = 0, sizeArr = 0; while (nodeCtx) { nodeMem = nodeCtx->memory; while (nodeMem) { if (!(nodeMem->isSymbol)) { countMem++; sizeMem += nodeMem->size; } nodeMem = nodeMem->next; } nodeArr = nodeCtx->array; while (nodeArr) { countArr++; // TODO: Calculate amount of lost memory for arrays nodeArr = nodeArr->next; } nodeCtx = nodeCtx->next; } if (countMem || countArr) { VALGRIND_PRINTF("Cudagrind leak report:\n"); if (countMem) { VALGRIND_PRINTF(" %d device memory region (%lu bytes) not freed.\n", countMem, (unsigned long)sizeMem); } if (countArr) { VALGRIND_PRINTF(" %d device arrays not freed.\n", countArr); } } }
/* * Adds the memory residing in context ctx and referenced by dptr to the allocated memory list. * * Input: * CUcontext ctx - CUDA context of memory * CUdeviceptr dptr - device pointer of memory * size_t bytesize - size of memory in bytes */ void cgAddMem(CUcontext ctx, CUdeviceptr dptr, size_t bytesize) { cgCtxListType *ctxNode; // Locate or create entry for context ctxNode = cgFindCtx(ctx); cgCtxAddMem(ctxNode, dptr, bytesize); #ifdef CUDAGRIND_DEBUG VALGRIND_PRINTF("Context list after 'cgAddMem' operation:\n"); printCtxList(); #endif }
bool valgrindCheckObjectInPool(MM_GCExtensionsBase *extensions, uintptr_t baseAddress) { #if defined(VALGRIND_REQUEST_LOGS) VALGRIND_PRINTF("Checking for an object at 0x%lx\n", baseAddress); #endif /* defined(VALGRIND_REQUEST_LOGS) */ MUTEX_ENTER(extensions->memcheckHashTableMutex); bool exists = hashTableFind(extensions->memcheckHashTable, &baseAddress) != NULL ? true : false; MUTEX_EXIT(extensions->memcheckHashTableMutex); return exists; }
/* * Removes the entry of the array residing in context ctx and referenced by dptr from allocated array list. * * Input: * CUcontext ctx - context * CUarray dptr - device pointer of to be removed 2D array */ void cgDelArr(CUcontext ctx, CUarray dptr) { cgCtxListType *ctxNode; // Locate the entry for the context .. // TODO: What happens if context does not exist anymore (we create it .. // but is that what we really want?!) ctxNode = cgFindCtx(ctx); cgCtxDelArr(ctxNode, dptr); #ifdef CUDAGRIND_DEBUG VALGRIND_PRINTF("Context list after 'cgDelArr' operation:\n"); printCtxList(); #endif }
void memory_status_calibrate (const char *marker) { int l, d, r, s; VALGRIND_PRINTF ("Calibrating: %s\n", marker); VALGRIND_DO_LEAK_CHECK; VALGRIND_COUNT_LEAKS(l, d, r, s); _memory_baseline_leaks = l; _memory_baseline_errors = VALGRIND_COUNT_ERRORS; }
int memory_status_verify (const char *marker) { int l, d, r, s, status; VALGRIND_PRINTF ("Verifying: %s\n", marker); status = MEMORY_OK; if (VALGRIND_COUNT_ERRORS > _memory_baseline_errors) status |= MEMORY_ERROR; VALGRIND_DO_LEAK_CHECK; VALGRIND_COUNT_LEAKS(l, d, r, s); if (l > _memory_baseline_leaks) status |= MEMORY_LEAK; return status; }
void* child_fn_1 ( void* arg ) { const char* threadname = "try1"; int r; # if !defined(VGO_darwin) pthread_setname_np(pthread_self(), threadname); # else pthread_setname_np(threadname); # endif bad_things(3); VALGRIND_PRINTF("%s", "I am in child_fn_1\n"); r = pthread_create(&children[2], NULL, child_fn_2, NULL); assert(!r); r = pthread_join(children[2], NULL); assert(!r); return NULL; }
/* * pmemobj_vg_check_no_undef -- (internal) check whether there are any undefined * regions */ static void pmemobj_vg_check_no_undef(struct pmemobjpool *pop) { LOG(4, "pop %p", pop); struct { void *start, *end; } undefs[MAX_UNDEFS]; int num_undefs = 0; VALGRIND_DO_DISABLE_ERROR_REPORTING; char *addr_start = pop->addr; char *addr_end = addr_start + pop->size; while (addr_start < addr_end) { char *noaccess = (char *)VALGRIND_CHECK_MEM_IS_ADDRESSABLE( addr_start, addr_end - addr_start); if (noaccess == NULL) noaccess = addr_end; while (addr_start < noaccess) { char *undefined = (char *)VALGRIND_CHECK_MEM_IS_DEFINED( addr_start, noaccess - addr_start); if (undefined) { addr_start = undefined; #ifdef VALGRIND_CHECK_MEM_IS_UNDEFINED addr_start = (char *) VALGRIND_CHECK_MEM_IS_UNDEFINED( addr_start, noaccess - addr_start); if (addr_start == NULL) addr_start = noaccess; #else while (addr_start < noaccess && VALGRIND_CHECK_MEM_IS_DEFINED( addr_start, 1)) addr_start++; #endif if (num_undefs < MAX_UNDEFS) { undefs[num_undefs].start = undefined; undefs[num_undefs].end = addr_start - 1; num_undefs++; } } else addr_start = noaccess; } #ifdef VALGRIND_CHECK_MEM_IS_UNADDRESSABLE addr_start = (char *)VALGRIND_CHECK_MEM_IS_UNADDRESSABLE( addr_start, addr_end - addr_start); if (addr_start == NULL) addr_start = addr_end; #else while (addr_start < addr_end && (char *)VALGRIND_CHECK_MEM_IS_ADDRESSABLE( addr_start, 1) == addr_start) addr_start++; #endif } VALGRIND_DO_ENABLE_ERROR_REPORTING; if (num_undefs) { /* * How to resolve this error: * If it's part of the free space Valgrind should be told about * it by VALGRIND_DO_MAKE_MEM_NOACCESS request. If it's * allocated - initialize it or use VALGRIND_DO_MAKE_MEM_DEFINED * request. */ VALGRIND_PRINTF("Part of the pool is left in undefined state on" " boot. This is pmemobj's bug.\nUndefined" " regions:\n"); for (int i = 0; i < num_undefs; ++i) VALGRIND_PRINTF(" [%p, %p]\n", undefs[i].start, undefs[i].end); if (num_undefs == MAX_UNDEFS) VALGRIND_PRINTF(" ...\n"); /* Trigger error. */ VALGRIND_CHECK_MEM_IS_DEFINED(undefs[0].start, 1); } }
CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemsetD2D32)(CUdeviceptr dstDevice, size_t dstPitch, unsigned int ui, size_t Width, size_t Height) { OrigFn fn; CUresult result; CUcontext ctx = NULL; cgMemListType *nodeMemDst; int error = 0; long vgErrorAddress; size_t dstSize; VALGRIND_GET_ORIG_FN(fn); cgLock(); CALL_FN_W_5W(result, fn, dstDevice, dstPitch, ui, Width, Height); // Check if function parameters are defined. // TODO: Warning or error in case of a partially undefined ui? vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&dstDevice, sizeof(CUdeviceptr)); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Error: 'dstDevice' in call to cuMemsetD2D32 not defined.\n"); } vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&dstPitch, sizeof(size_t)); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Error: 'dstPitch' in call to cuMemsetD2D32 not defined.\n"); } vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&ui, sizeof(ui)); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Warning: 'ui' in call to cuMemsetD2D32 is not fully defined.\n"); } vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&Width, sizeof(size_t)); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Error: 'Width' in call to cuMemsetD2D32 not defined.\n"); } vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&Height, sizeof(size_t)); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Error: 'Height' in call to cuMemsetD2D32 not defined.\n"); } // Fetch current context cgGetCtx(&ctx); nodeMemDst = cgFindMem(cgFindCtx(ctx), dstDevice); // Check if memory has been allocated if (!nodeMemDst) { error++; VALGRIND_PRINTF("Error: Destination device memory not allocated in call to cuMemsetD2D32.\n"); } else { // If memory is allocated, check size of available memory dstSize = nodeMemDst->size - (dstDevice - nodeMemDst->dptr); // The whole memory block of dstPitch*Height must fit into memory if (dstSize < sizeof(ui) * dstPitch * Height) { error++; VALGRIND_PRINTF("Error: Allocated device memory too small in call to cuMemsetD2D32.\n" " Expected %lu allocated bytes but only found %lu.\n", sizeof(ui) * dstPitch * Height, dstSize); } // Check if dstDevice and dstPitch are both properly aligned // TODO: Is this a valid check? (see also cuMemsetD32) if (dstDevice % 4) { error++; VALGRIND_PRINTF("Error: Pointer dstDevice in call to cuMemsetD2D32 not four byte aligned.\n"); } if (dstPitch % 4) { error++; VALGRIND_PRINTF("Error: Destination pitch in call to cuMemsetD2D32 not four byte aligned.\n"); } } // Make sure pitch is big enough to accommodate asked for Width if (dstPitch < Width) { error++; VALGRIND_PRINTF("Error: dstPitch smaller than Width in call to cuMemsetD2D32.\n"); } if (error) { VALGRIND_PRINTF_BACKTRACE(""); } cgUnlock(); return result; }
CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemcpy3D)(const CUDA_MEMCPY3D *pCopy) { OrigFn fn; CUresult result; CUcontext ctx = NULL; int error = 0, error_addressable, error_defined; long vgErrorAddress = 0, vgErrorAddressDefined = 0; VALGRIND_GET_ORIG_FN(fn); cgLock(); CALL_FN_W_W(result, fn, pCopy); // Check if pCopy is null, not allocated or undefined. // For obvious reasons we skip the following checks if either condition is true. if (!pCopy) { error++; VALGRIND_PRINTF_BACKTRACE("Error: pCopy in call to cuMemcpy3D is NULL.\n"); cgUnlock(); return result; } else if ( vgErrorAddress = VALGRIND_CHECK_MEM_IS_ADDRESSABLE(pCopy, sizeof(CUDA_MEMCPY3D)) ) { error++; VALGRIND_PRINTF_BACKTRACE("Error: pCopy in call to cuMemcpy3D points to unallocated memory.\n"); cgUnlock(); return result; } // It makes no sense to check _IS_DEFINED on the whole structure, since only part of it is used! // General checks of constaints imposed by reference manual if (pCopy->srcMemoryType != CU_MEMORYTYPE_ARRAY) { if (pCopy->srcPitch && pCopy->srcPitch < pCopy->WidthInBytes + pCopy->srcXInBytes) { error++; VALGRIND_PRINTF("Error: srcPitch < WidthInBytes+srcXInBytes in cuMemcpy3D.\n"); } if (pCopy->srcHeight && pCopy->srcHeight < pCopy->Height + pCopy->srcY) { error++; VALGRIND_PRINTF("Error: srcHeight < Height+srcY in cuMemcpy3D.\n"); } } if (pCopy->dstMemoryType != CU_MEMORYTYPE_ARRAY) { if (pCopy->dstPitch && pCopy->dstPitch < pCopy->WidthInBytes + pCopy->dstXInBytes) { error++; VALGRIND_PRINTF("Error: dstPitch < WidthInBytes+dstXInBytes in cuMemcpy3D.\n"); } if (pCopy->dstHeight && pCopy->dstHeight < pCopy->Height + pCopy->dstY) { error++; VALGRIND_PRINTF("Error: dstHeight < Height+dstY in cuMemcpy3D.\n"); } } switch (pCopy->srcMemoryType) { case CU_MEMORYTYPE_UNIFIED: // TODO: How do we handle unified memory? break; case CU_MEMORYTYPE_HOST: { void *line; error_addressable = 0; error_defined = 0; // TODO: Is Height, Depth > 1, even for 1D/2D copy operations? for (int i = 0 ; i < pCopy->Height ; i++) { for (int j = 0 ; j < pCopy->Depth ; j++) { line = (void*)( (char*)pCopy->srcHost + ((pCopy->srcZ + j) * pCopy->srcHeight + (pCopy->srcY + i))*pCopy->srcPitch + pCopy->srcXInBytes ); vgErrorAddress = VALGRIND_CHECK_MEM_IS_ADDRESSABLE(line, (size_t)pCopy->WidthInBytes); if (vgErrorAddress) { error_addressable++; } else { vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(line, (size_t)pCopy->WidthInBytes); if (vgErrorAddress) { error_defined++; } } } } // TODO: Can we give precise information about location of error? if (error_addressable) { error++; VALGRIND_PRINTF("Error: (Part of) source host memory not allocated\n" " in call to cuMemcpy3D.\n"); } if (error_defined) { error++; VALGRIND_PRINTF("Error: (Part of) source host memory not defined\n" " in call to cuMemcpy3D.\n"); } break; } case CU_MEMORYTYPE_DEVICE: { // ptrEnd points to the end of the memory area which pCopy->srcDevice points into CUdeviceptr line, ptrEnd; cgMemListType *nodeMem; // TODO: Check if pCopy->srcDevice is defined? cgGetCtx(&ctx); nodeMem = cgFindMem(cgFindCtx(ctx), pCopy->srcDevice); // We only track addressable status (whether memory is allocated) for device memory regions error_addressable = 0; if (nodeMem) { ptrEnd = nodeMem->dptr + nodeMem->size; /* for (int i = 0 ; i < pCopy->Height ; i++) { for (int j = 0 ; j < pCopy->Depth ; j++) { line = (CUdeviceptr)( pCopy->srcDevice + ((pCopy->srcZ + j) * pCopy->srcHeight + (pCopy->srcY + i)) * pCopy->srcPitch + pCopy->srcXInBytes ); // Is there enough allocated memory left to statisfy the current line? if (ptrEnd - line < pCopy->WidthInBytes) { error_addressable++; } } } */ // Device memory should not be fragmented, so we only check the very last slice of memory line = (CUdeviceptr)( pCopy->srcDevice + ( (pCopy->srcZ + pCopy->Depth - 1) * pCopy->srcHeight + (pCopy->srcY + pCopy->Height - 1) ) * pCopy->srcPitch + pCopy->srcXInBytes); if (ptrEnd - line < pCopy->WidthInBytes) { error_addressable++; } } else { error_addressable++; } if (error_addressable) { error++; VALGRIND_PRINTF("Error: (Part of) source device memory not allocated\n" " in call to cuMemcpy3D.\n"); } break; } case CU_MEMORYTYPE_ARRAY: { CUDA_ARRAY3D_DESCRIPTOR descriptor; int bytesPerElement; int widthInBytes; // Fetch array descriptor .. cuArray3DGetDescriptor(&descriptor, pCopy->srcArray); bytesPerElement = cgArrDescBytesPerElement(&descriptor); if (!bytesPerElement) { error++; VALGRIND_PRINTF("Error: Unknown Format value in src array descriptor in cuMemcpy3D.\n"); } widthInBytes = bytesPerElement * descriptor.Width; // .. and check if dimensions are conform to the ones requested in pCopy if (widthInBytes - pCopy->srcXInBytes < pCopy->WidthInBytes) { error++; VALGRIND_PRINTF("Error: Available width of %u bytes in source array is smaller than\n" " requested Width of %u bytes in pCopy of cuMemcpy3D.\n", widthInBytes - pCopy->srcXInBytes, pCopy->WidthInBytes); } if (pCopy->Height > 1 && descriptor.Height - pCopy->srcY < pCopy->Height) { error++; VALGRIND_PRINTF("Error: Available Height of %u in source array is smaller than\n" " requested Height of %u in pCopy of cuMemcpy3D.\n", descriptor.Height - pCopy->srcY, pCopy->Height); } if (pCopy->Depth > 1 && descriptor.Depth - pCopy->srcZ < pCopy->Depth) { error++; VALGRIND_PRINTF("Error: Available Depth of %u in source array is smaller than\n" " requested Depth of %u in pCopy of cuMemcpy3D.\n", descriptor.Depth - pCopy->srcY, pCopy->Height); } break; } default: error++; VALGRIND_PRINTF("Error: Unknown source memory type %d in cuMemcpy3D\n"); break; } switch (pCopy->dstMemoryType) { case CU_MEMORYTYPE_UNIFIED: // TODO: How do we handle unified memory? break; case CU_MEMORYTYPE_HOST: { void *line; error_addressable = 0; error_defined = 0; // TODO: Is Height, Depth > 1, even for 1D/2D copy operations? for (int i = 0 ; i < pCopy->Height ; i++) { for (int j = 0 ; j < pCopy->Depth ; j++) { line = (void*)( (char*)pCopy->dstHost + ((pCopy->dstZ + j) * pCopy->dstHeight + (pCopy->dstY + i))*pCopy->dstPitch + pCopy->dstXInBytes ); // Unlike for the source operand we only need to check allocation status here vgErrorAddress = VALGRIND_CHECK_MEM_IS_ADDRESSABLE(line, (size_t)pCopy->WidthInBytes); if (vgErrorAddress) { error_addressable++; } } } // TODO: Can we give precise information about location of error? if (error_addressable) { error++; VALGRIND_PRINTF("Error: (Part of) destination host memory not allocated\n" " in call to cuMemcpy3D.\n"); } break; } case CU_MEMORYTYPE_DEVICE: { // ptrEnd points to the end of the memory area which pCopy->dstDevice points into CUdeviceptr line, ptrEnd; cgMemListType *nodeMem; // TODO: Check if pCopy->dstDevice is defined? cgGetCtx(&ctx); nodeMem = cgFindMem(cgFindCtx(ctx), pCopy->dstDevice); // We only track addressable status (whether memory is allocated) for device memory regions error_addressable = 0; if (nodeMem) { ptrEnd = nodeMem->dptr + nodeMem->size; /* for (int i = 0 ; i < pCopy->Height ; i++) { for (int j = 0 ; j < pCopy->Depth ; j++) { line = (CUdeviceptr)( pCopy->dstDevice + ((pCopy->dstZ + j) * pCopy->dstHeight + (pCopy->dstY + i)) * pCopy->dstPitch + pCopy->dstXInBytes ); // Is there enough allocated memory left to statisfy the current line? if (ptrEnd - line < pCopy->WidthInBytes) { error_addressable++; } } } */ // Device memory should not be fragmented, so we only check the very last slice of memory line = (CUdeviceptr)( pCopy->dstDevice + ( (pCopy->dstZ + pCopy->Depth - 1) * pCopy->dstHeight + (pCopy->dstY + pCopy->Height - 1) ) * pCopy->dstPitch + pCopy->dstXInBytes); if (ptrEnd - line < pCopy->WidthInBytes) { error_addressable++; } } else { error_addressable++; } if (error_addressable) { error++; VALGRIND_PRINTF("Error: (Part of) destination device memory not allocated\n" " in call to cuMemcpy3D.\n"); } break; } case CU_MEMORYTYPE_ARRAY: { CUDA_ARRAY3D_DESCRIPTOR descriptor; int bytesPerElement; int widthInBytes; // Fetch array descriptor .. cuArray3DGetDescriptor(&descriptor, pCopy->dstArray); bytesPerElement = cgArrDescBytesPerElement(&descriptor); if (!bytesPerElement) { error++; VALGRIND_PRINTF("Error: Unknown Format value in dst array descriptor in cuMemcpy3D.\n"); } widthInBytes = bytesPerElement * descriptor.Width; // .. and check if dimensions are conform to the ones requested in pCopy if (widthInBytes - pCopy->dstXInBytes < pCopy->WidthInBytes) { error++; VALGRIND_PRINTF("Error: Available width of %u bytes in destination array is smaller than\n" " requested Width of %u bytes in pCopy of cuMemcpy3D.\n", widthInBytes - pCopy->dstXInBytes, pCopy->WidthInBytes); } if (pCopy->Height > 1 && descriptor.Height - pCopy->dstY < pCopy->Height) { error++; VALGRIND_PRINTF("Error: Available Height of %u in destination array is smaller than\n" " requested Height of %u in pCopy of cuMemcpy3D.\n", descriptor.Height - pCopy->dstY, pCopy->Height); } if (pCopy->Depth > 1 && descriptor.Depth - pCopy->dstZ < pCopy->Depth) { error++; VALGRIND_PRINTF("Error: Available Depth of %u in destination array is smaller than\n" " requested Depth of %u in pCopy of cuMemcpy3D.\n", descriptor.Depth - pCopy->dstZ, pCopy->Depth); } break; } default: error++; VALGRIND_PRINTF("Error: Unknown destination memory type %d in cuMemcpy3D\n"); break; } if (error) { VALGRIND_PRINTF_BACKTRACE(" %d errors detected in call to cuMemcpy3D.", error); } cgUnlock(); return result; }
CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemcpyHtoA)(CUarray dstArray, size_t dstOffset, const void *srcHost, size_t ByteCount) { OrigFn fn; CUresult result; CUcontext ctx = NULL; cgCtxListType *nodeCtx; cgArrListType *nodeArrDst; cgMemListType *nodeMemSrc; long vgErrorAddress; int error = 0; VALGRIND_GET_ORIG_FN(fn); cgLock(); CALL_FN_W_WWWW(result, fn, dstArray, dstOffset, srcHost, ByteCount); // Check if actual function parameters are defined if (VALGRIND_CHECK_MEM_IS_DEFINED(&dstArray, sizeof(CUarray))) { error++; VALGRIND_PRINTF("Error: dstArray in call to cuMemcpyAtoD is not defined.\n"); } else if (!dstArray) { error++; VALGRIND_PRINTF("Error: dstArray in call to cuMemcpyAtoD is NULL.\n"); } if (VALGRIND_CHECK_MEM_IS_DEFINED(&dstOffset, sizeof(size_t))) { error++; VALGRIND_PRINTF("Error: dstOffset in call to cuMemcpyAtoD is not defined.\n"); } if (VALGRIND_CHECK_MEM_IS_DEFINED(&srcHost, sizeof(CUdeviceptr))) { error++; VALGRIND_PRINTF("Error: srcHost in call to cuMemcpyAtoD is not defined.\n"); } else if (!srcHost) { error++; VALGRIND_PRINTF("Error: srcDevice in call to cuMemcpyAtoD is NULL"); } if (VALGRIND_CHECK_MEM_IS_DEFINED(&ByteCount, sizeof(size_t))) { error++; VALGRIND_PRINTF("Error: ByteCount in call to cuMemcpyAtoD is not defined.\n"); } cgGetCtx(&ctx); nodeCtx = cgFindCtx(ctx); nodeArrDst = cgFindArr(nodeCtx, dstArray); if (srcHost) { vgErrorAddress = VALGRIND_CHECK_MEM_IS_ADDRESSABLE(srcHost, ByteCount); // Check if memory referenced by srcHost has been allocated. if (vgErrorAddress) { error++; VALGRIND_PRINTF("Error: Source host memory in cuMemcpyHtoA is not not allocated.\n" " Expected %l bytes but only found %l.\n", ByteCount, vgErrorAddress - (long)srcHost); } else { // If allocated, now check if host memory is defined. vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(srcHost, ByteCount); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Error: Source host memory in cuMemcpyHtoA is not defined.\n" " Expected %l bytes but only found %l.\n", ByteCount, vgErrorAddress - (long)srcHost); } } } if (nodeArrDst) { // Check if array is 1-dimensional or big enough in first dimension if (nodeArrDst->desc.Height > 1 || nodeArrDst->desc.Depth > 1) { if (nodeArrDst->desc.Width - dstOffset < ByteCount) { error++; VALGRIND_PRINTF("Error: Destination array in cuMemcpyAtoD is 2-dimensional\n" " and ByteCount bigger than available width in first dimension.\n"); } else { VALGRIND_PRINTF("Warning: Destination array in cuMemcpyAtoD is 2-dimensional.\n"); } } else if (nodeArrDst->desc.Width - dstOffset < ByteCount) { // If array is 1D, check size. VALGRIND_PRINTF("Error: Destination array in cuMemcpyAtoD is too small.\n" " Expected %l bytes but only found %l.\n", ByteCount, nodeArrDst->desc.Width - dstOffset); error++; } } else { error++; VALGRIND_PRINTF("Error: Destination array not allocated in call to cuMemcpyAtoD.\n"); } cgUnlock(); return result; }
// Copy Host->Device CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemcpyHtoD)(CUdeviceptr dstDevice, const void *srcHost, size_t ByteCount) { OrigFn fn; CUresult result; CUcontext ctx = NULL; cgCtxListType *nodeCtx; cgMemListType *nodeMem; size_t dstSize; long vgErrorAddress, vgErrorAddressDstDevice, vgErrorAddressSrcHost; VALGRIND_GET_ORIG_FN(fn); cgLock(); vgErrorAddressDstDevice = VALGRIND_CHECK_MEM_IS_DEFINED(&dstDevice, sizeof(void*)); vgErrorAddressSrcHost = VALGRIND_CHECK_MEM_IS_DEFINED(&srcHost, sizeof(CUdeviceptr)); // TODO: Currently errors are exclusive .. i.e. with undefined src and NULL // dst pointer, only the undefined pointer is reported. if (vgErrorAddressDstDevice || vgErrorAddressSrcHost) { VALGRIND_PRINTF("Error:"); if (vgErrorAddressDstDevice) { VALGRIND_PRINTF(" destination device"); if (vgErrorAddressSrcHost) { VALGRIND_PRINTF(" and"); } } if (vgErrorAddressSrcHost) { VALGRIND_PRINTF(" source host"); } VALGRIND_PRINTF_BACKTRACE(" pointer in cuMemcpyHtoD not defined.\n"); } else if (dstDevice != 0 && srcHost != NULL) { cgGetCtx(&ctx); // Check allocation status and available size on device nodeCtx = cgFindCtx(ctx); nodeMem = cgFindMem(nodeCtx, dstDevice); if (!nodeMem) { VALGRIND_PRINTF("Error: Device memory during host->device memory copy is not allocated."); } else { dstSize = nodeMem->size - (dstDevice - nodeMem->dptr); if (dstSize < ByteCount) { VALGRIND_PRINTF("Error: Allocated device memory too small for host->device memory copy.\n"); VALGRIND_PRINTF(" Expected %lu allocated bytes but only found %lu.", ByteCount, dstSize); } } if (!nodeMem || dstSize < ByteCount) { VALGRIND_PRINTF_BACKTRACE("\n"); } // Check allocation and definedness for host memory vgErrorAddress = VALGRIND_CHECK_MEM_IS_ADDRESSABLE(srcHost, ByteCount); if (vgErrorAddress) { VALGRIND_PRINTF("Error: Host memory during host->device memory copy is not allocated.\n"); VALGRIND_PRINTF(" Expected %lu allocated bytes but only found %lu.", ByteCount, vgErrorAddress - (long)srcHost); } else { vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(srcHost, ByteCount); if (vgErrorAddress) { VALGRIND_PRINTF("Error: Host memory during host->device memory copy is not defined.\n"); VALGRIND_PRINTF(" Expected %lu defined bytes but only found %lu.", ByteCount, vgErrorAddress - (long)srcHost); } } if (vgErrorAddress) { VALGRIND_PRINTF_BACKTRACE("\n"); } } else { VALGRIND_PRINTF("Error: cuMemcpyHtoD called with NULL"); if (dstDevice == 0) { VALGRIND_PRINTF(" device"); if (srcHost == NULL) VALGRIND_PRINTF(" and"); } if (srcHost == NULL) { VALGRIND_PRINTF(" host"); } VALGRIND_PRINTF_BACKTRACE(" pointer.\n"); } CALL_FN_W_WWW(result, fn, dstDevice, srcHost, ByteCount); cgUnlock(); return result; }
static cairo_test_status_t cairo_test_for_target (cairo_test_context_t *ctx, const cairo_boilerplate_target_t *target, int dev_offset, cairo_bool_t similar) { cairo_test_status_t status; cairo_surface_t *surface = NULL; cairo_t *cr; const char *empty_str = ""; char *offset_str; char *base_name, *base_path; char *out_png_path; char *ref_path = NULL, *ref_png_path, *cmp_png_path = NULL; char *new_path = NULL, *new_png_path; char *xfail_path = NULL, *xfail_png_path; char *base_ref_png_path; char *base_new_png_path; char *base_xfail_png_path; char *diff_png_path; char *test_filename = NULL, *pass_filename = NULL, *fail_filename = NULL; cairo_test_status_t ret; cairo_content_t expected_content; cairo_font_options_t *font_options; const char *format; cairo_bool_t have_output = FALSE; cairo_bool_t have_result = FALSE; void *closure; double width, height; cairo_bool_t have_output_dir; #if HAVE_MEMFAULT int malloc_failure_iterations = ctx->malloc_failure; int last_fault_count = 0; #endif /* Get the strings ready that we'll need. */ format = cairo_boilerplate_content_name (target->content); if (dev_offset) xasprintf (&offset_str, ".%d", dev_offset); else offset_str = (char *) empty_str; xasprintf (&base_name, "%s.%s.%s%s%s", ctx->test_name, target->name, format, similar ? ".similar" : "", offset_str); if (offset_str != empty_str) free (offset_str); ref_png_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, target->name, target->basename, format, CAIRO_TEST_REF_SUFFIX, CAIRO_TEST_PNG_EXTENSION); new_png_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, target->name, target->basename, format, CAIRO_TEST_NEW_SUFFIX, CAIRO_TEST_PNG_EXTENSION); xfail_png_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, target->name, target->basename, format, CAIRO_TEST_XFAIL_SUFFIX, CAIRO_TEST_PNG_EXTENSION); base_ref_png_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, NULL, NULL, format, CAIRO_TEST_REF_SUFFIX, CAIRO_TEST_PNG_EXTENSION); base_new_png_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, NULL, NULL, format, CAIRO_TEST_NEW_SUFFIX, CAIRO_TEST_PNG_EXTENSION); base_xfail_png_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, NULL, NULL, format, CAIRO_TEST_XFAIL_SUFFIX, CAIRO_TEST_PNG_EXTENSION); if (target->file_extension != NULL) { ref_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, target->name, target->basename, format, CAIRO_TEST_REF_SUFFIX, target->file_extension); new_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, target->name, target->basename, format, CAIRO_TEST_NEW_SUFFIX, target->file_extension); xfail_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, target->name, target->basename, format, CAIRO_TEST_XFAIL_SUFFIX, target->file_extension); } have_output_dir = _cairo_test_mkdir (ctx->output); xasprintf (&base_path, "%s/%s", have_output_dir ? ctx->output : ".", base_name); xasprintf (&out_png_path, "%s" CAIRO_TEST_OUT_PNG, base_path); xasprintf (&diff_png_path, "%s" CAIRO_TEST_DIFF_PNG, base_path); if (ctx->test->requirements != NULL) { const char *required; required = target->is_vector ? "target=raster" : "target=vector"; if (strstr (ctx->test->requirements, required) != NULL) { cairo_test_log (ctx, "Error: Skipping for %s target %s\n", target->is_vector ? "vector" : "raster", target->name); ret = CAIRO_TEST_UNTESTED; goto UNWIND_STRINGS; } required = target->is_recording ? "target=!recording" : "target=recording"; if (strstr (ctx->test->requirements, required) != NULL) { cairo_test_log (ctx, "Error: Skipping for %s target %s\n", target->is_recording ? "recording" : "non-recording", target->name); ret = CAIRO_TEST_UNTESTED; goto UNWIND_STRINGS; } } width = ctx->test->width; height = ctx->test->height; if (width && height) { width += dev_offset; height += dev_offset; } #if HAVE_MEMFAULT REPEAT: MEMFAULT_CLEAR_FAULTS (); MEMFAULT_RESET_LEAKS (); ctx->last_fault_count = 0; last_fault_count = MEMFAULT_COUNT_FAULTS (); /* Pre-initialise fontconfig so that the configuration is loaded without * malloc failures (our primary goal is to test cairo fault tolerance). */ #if HAVE_FCINIT FcInit (); #endif MEMFAULT_ENABLE_FAULTS (); #endif have_output = FALSE; have_result = FALSE; /* Run the actual drawing code. */ ret = CAIRO_TEST_SUCCESS; surface = (target->create_surface) (base_path, target->content, width, height, ctx->test->width + 25 * NUM_DEVICE_OFFSETS, ctx->test->height + 25 * NUM_DEVICE_OFFSETS, CAIRO_BOILERPLATE_MODE_TEST, &closure); if (surface == NULL) { cairo_test_log (ctx, "Error: Failed to set %s target\n", target->name); ret = CAIRO_TEST_UNTESTED; goto UNWIND_STRINGS; } #if HAVE_MEMFAULT if (ctx->malloc_failure && MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 && cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY) { goto REPEAT; } #endif if (cairo_surface_status (surface)) { MF (MEMFAULT_PRINT_FAULTS ()); cairo_test_log (ctx, "Error: Created an error surface: %s\n", cairo_status_to_string (cairo_surface_status (surface))); ret = CAIRO_TEST_FAILURE; goto UNWIND_STRINGS; } /* Check that we created a surface of the expected type. */ if (cairo_surface_get_type (surface) != target->expected_type) { MF (MEMFAULT_PRINT_FAULTS ()); cairo_test_log (ctx, "Error: Created surface is of type %d (expected %d)\n", cairo_surface_get_type (surface), target->expected_type); ret = CAIRO_TEST_UNTESTED; goto UNWIND_SURFACE; } /* Check that we created a surface of the expected content, * (ignore the artificial CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED value). */ expected_content = cairo_boilerplate_content (target->content); if (cairo_surface_get_content (surface) != expected_content) { MF (MEMFAULT_PRINT_FAULTS ()); cairo_test_log (ctx, "Error: Created surface has content %d (expected %d)\n", cairo_surface_get_content (surface), expected_content); ret = CAIRO_TEST_FAILURE; goto UNWIND_SURFACE; } if (cairo_surface_set_user_data (surface, &cairo_boilerplate_output_basename_key, base_path, NULL)) { #if HAVE_MEMFAULT cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); goto REPEAT; #else ret = CAIRO_TEST_FAILURE; goto UNWIND_SURFACE; #endif } cairo_surface_set_device_offset (surface, dev_offset, dev_offset); cr = cairo_create (surface); if (cairo_set_user_data (cr, &_cairo_test_context_key, (void*) ctx, NULL)) { #if HAVE_MEMFAULT cairo_destroy (cr); cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); goto REPEAT; #else ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; #endif } if (similar) cairo_push_group_with_content (cr, expected_content); /* Clear to transparent (or black) depending on whether the target * surface supports alpha. */ cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); cairo_paint (cr); cairo_restore (cr); /* Set all components of font_options to avoid backend differences * and reduce number of needed reference images. */ font_options = cairo_font_options_create (); cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON); cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY); cairo_set_font_options (cr, font_options); cairo_font_options_destroy (font_options); cairo_save (cr); alarm (ctx->timeout); status = (ctx->test->draw) (cr, ctx->test->width, ctx->test->height); alarm (0); cairo_restore (cr); if (similar) { cairo_pop_group_to_source (cr); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_paint (cr); } #if HAVE_MEMFAULT MEMFAULT_DISABLE_FAULTS (); /* repeat test after malloc failure injection */ if (ctx->malloc_failure && MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 && (status == CAIRO_TEST_NO_MEMORY || cairo_status (cr) == CAIRO_STATUS_NO_MEMORY || cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY)) { cairo_destroy (cr); cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); cairo_debug_reset_static_data (); #if HAVE_FCFINI FcFini (); #endif if (MEMFAULT_COUNT_LEAKS () > 0) { MEMFAULT_PRINT_FAULTS (); MEMFAULT_PRINT_LEAKS (); } goto REPEAT; } #endif /* Then, check all the different ways it could fail. */ if (status) { cairo_test_log (ctx, "Error: Function under test failed\n"); ret = status; goto UNWIND_CAIRO; } #if HAVE_MEMFAULT if (MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 && MEMFAULT_HAS_FAULTS ()) { VALGRIND_PRINTF ("Unreported memfaults..."); MEMFAULT_PRINT_FAULTS (); } #endif if (target->finish_surface != NULL) { #if HAVE_MEMFAULT /* We need to re-enable faults as most recording-surface processing * is done during cairo_surface_finish(). */ MEMFAULT_CLEAR_FAULTS (); last_fault_count = MEMFAULT_COUNT_FAULTS (); MEMFAULT_ENABLE_FAULTS (); #endif /* also check for infinite loops whilst replaying */ alarm (ctx->timeout); status = target->finish_surface (surface); alarm (0); #if HAVE_MEMFAULT MEMFAULT_DISABLE_FAULTS (); if (ctx->malloc_failure && MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 && status == CAIRO_STATUS_NO_MEMORY) { cairo_destroy (cr); cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); cairo_debug_reset_static_data (); #if HAVE_FCFINI FcFini (); #endif if (MEMFAULT_COUNT_LEAKS () > 0) { MEMFAULT_PRINT_FAULTS (); MEMFAULT_PRINT_LEAKS (); } goto REPEAT; } #endif if (status) { cairo_test_log (ctx, "Error: Failed to finish surface: %s\n", cairo_status_to_string (status)); ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } } /* Skip image check for tests with no image (width,height == 0,0) */ if (ctx->test->width != 0 && ctx->test->height != 0) { cairo_surface_t *ref_image; cairo_surface_t *test_image; cairo_surface_t *diff_image; buffer_diff_result_t result; cairo_status_t diff_status; if (ref_png_path == NULL) { cairo_test_log (ctx, "Error: Cannot find reference image for %s\n", base_name); /* we may be running this test to generate reference images */ _xunlink (ctx, out_png_path); /* be more generous as we may need to use external renderers */ alarm (4 * ctx->timeout); test_image = target->get_image_surface (surface, 0, ctx->test->width, ctx->test->height); alarm (0); diff_status = cairo_surface_write_to_png (test_image, out_png_path); cairo_surface_destroy (test_image); if (diff_status) { if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS) ret = CAIRO_TEST_CRASHED; else ret = CAIRO_TEST_FAILURE; cairo_test_log (ctx, "Error: Failed to write output image: %s\n", cairo_status_to_string (diff_status)); } have_output = TRUE; ret = CAIRO_TEST_XFAILURE; goto UNWIND_CAIRO; } if (target->file_extension != NULL) { /* compare vector surfaces */ char *filenames[] = { ref_png_path, ref_path, new_png_path, new_path, xfail_png_path, xfail_path, base_ref_png_path, base_new_png_path, base_xfail_png_path, }; xasprintf (&test_filename, "%s.out%s", base_path, target->file_extension); xasprintf (&pass_filename, "%s.pass%s", base_path, target->file_extension); xasprintf (&fail_filename, "%s.fail%s", base_path, target->file_extension); if (cairo_test_file_is_older (pass_filename, filenames, ARRAY_SIZE (filenames))) { _xunlink (ctx, pass_filename); } if (cairo_test_file_is_older (fail_filename, filenames, ARRAY_SIZE (filenames))) { _xunlink (ctx, fail_filename); } if (cairo_test_files_equal (out_png_path, ref_path)) { cairo_test_log (ctx, "Vector surface matches reference.\n"); have_output = FALSE; ret = CAIRO_TEST_SUCCESS; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, new_path)) { cairo_test_log (ctx, "Vector surface matches current failure.\n"); have_output = FALSE; ret = CAIRO_TEST_NEW; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, xfail_path)) { cairo_test_log (ctx, "Vector surface matches known failure.\n"); have_output = FALSE; ret = CAIRO_TEST_XFAILURE; goto UNWIND_CAIRO; } if (cairo_test_files_equal (test_filename, pass_filename)) { /* identical output as last known PASS */ cairo_test_log (ctx, "Vector surface matches last pass.\n"); have_output = TRUE; ret = CAIRO_TEST_SUCCESS; goto UNWIND_CAIRO; } if (cairo_test_files_equal (test_filename, fail_filename)) { /* identical output as last known FAIL, fail */ cairo_test_log (ctx, "Vector surface matches last fail.\n"); have_result = TRUE; /* presume these were kept around as well */ have_output = TRUE; ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } } /* be more generous as we may need to use external renderers */ alarm (4 * ctx->timeout); test_image = target->get_image_surface (surface, 0, ctx->test->width, ctx->test->height); alarm (0); if (cairo_surface_status (test_image)) { cairo_test_log (ctx, "Error: Failed to extract image: %s\n", cairo_status_to_string (cairo_surface_status (test_image))); if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS) ret = CAIRO_TEST_CRASHED; else ret = CAIRO_TEST_FAILURE; cairo_surface_destroy (test_image); goto UNWIND_CAIRO; } _xunlink (ctx, out_png_path); diff_status = cairo_surface_write_to_png (test_image, out_png_path); if (diff_status) { cairo_test_log (ctx, "Error: Failed to write output image: %s\n", cairo_status_to_string (diff_status)); cairo_surface_destroy (test_image); ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } have_output = TRUE; /* binary compare png files (no decompression) */ if (target->file_extension == NULL) { char *filenames[] = { ref_png_path, new_png_path, xfail_png_path, base_ref_png_path, base_new_png_path, base_xfail_png_path, }; xasprintf (&test_filename, "%s", out_png_path); xasprintf (&pass_filename, "%s.pass.png", base_path); xasprintf (&fail_filename, "%s.fail.png", base_path); if (cairo_test_file_is_older (pass_filename, filenames, ARRAY_SIZE (filenames))) { _xunlink (ctx, pass_filename); } if (cairo_test_file_is_older (fail_filename, filenames, ARRAY_SIZE (filenames))) { _xunlink (ctx, fail_filename); } if (cairo_test_files_equal (test_filename, pass_filename)) { cairo_test_log (ctx, "PNG file exactly matches last pass.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_SUCCESS; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, ref_png_path)) { cairo_test_log (ctx, "PNG file exactly matches reference image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_SUCCESS; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, new_png_path)) { cairo_test_log (ctx, "PNG file exactly matches current failure image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_NEW; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, xfail_png_path)) { cairo_test_log (ctx, "PNG file exactly matches known failure image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_XFAILURE; goto UNWIND_CAIRO; } if (cairo_test_files_equal (test_filename, fail_filename)) { cairo_test_log (ctx, "PNG file exactly matches last fail.\n"); have_result = TRUE; /* presume these were kept around as well */ cairo_surface_destroy (test_image); ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } } else { if (cairo_test_files_equal (out_png_path, ref_png_path)) { cairo_test_log (ctx, "PNG file exactly matches reference image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_SUCCESS; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, new_png_path)) { cairo_test_log (ctx, "PNG file exactly matches current failure image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_NEW; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, xfail_png_path)) { cairo_test_log (ctx, "PNG file exactly matches known failure image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_XFAILURE; goto UNWIND_CAIRO; } } if (cairo_test_files_equal (out_png_path, base_ref_png_path)) { cairo_test_log (ctx, "PNG file exactly reference image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_SUCCESS; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, base_new_png_path)) { cairo_test_log (ctx, "PNG file exactly current failure image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_NEW; goto UNWIND_CAIRO; } if (cairo_test_files_equal (out_png_path, base_xfail_png_path)) { cairo_test_log (ctx, "PNG file exactly known failure image.\n"); have_result = TRUE; cairo_surface_destroy (test_image); ret = CAIRO_TEST_XFAILURE; goto UNWIND_CAIRO; } /* first compare against the ideal reference */ ref_image = cairo_test_get_reference_image (ctx, base_ref_png_path, target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED); if (cairo_surface_status (ref_image)) { cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n", base_ref_png_path, cairo_status_to_string (cairo_surface_status (ref_image))); cairo_surface_destroy (test_image); ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ctx->test->width, ctx->test->height); cmp_png_path = base_ref_png_path; diff_status = image_diff (ctx, test_image, ref_image, diff_image, &result); _xunlink (ctx, diff_png_path); if (diff_status || image_diff_is_failure (&result, target->error_tolerance)) { /* that failed, so check against the specific backend */ ref_image = cairo_test_get_reference_image (ctx, ref_png_path, target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED); if (cairo_surface_status (ref_image)) { cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n", ref_png_path, cairo_status_to_string (cairo_surface_status (ref_image))); cairo_surface_destroy (test_image); ret = CAIRO_TEST_FAILURE; goto UNWIND_CAIRO; } cmp_png_path = ref_png_path; diff_status = image_diff (ctx, test_image, ref_image, diff_image, &result); if (diff_status) { cairo_test_log (ctx, "Error: Failed to compare images: %s\n", cairo_status_to_string (diff_status)); ret = CAIRO_TEST_FAILURE; } else if (image_diff_is_failure (&result, target->error_tolerance)) { ret = CAIRO_TEST_FAILURE; diff_status = cairo_surface_write_to_png (diff_image, diff_png_path); if (diff_status) { cairo_test_log (ctx, "Error: Failed to write differences image: %s\n", cairo_status_to_string (diff_status)); } else { have_result = TRUE; } cairo_test_copy_file (test_filename, fail_filename); } else { /* success */ cairo_test_copy_file (test_filename, pass_filename); } } else { /* success */ cairo_test_copy_file (test_filename, pass_filename); } /* If failed, compare against the current image output, * and attempt to detect systematic failures. */ if (ret == CAIRO_TEST_FAILURE) { char *image_out_path; image_out_path = cairo_test_reference_filename (ctx, base_name, ctx->test_name, "image", "image", format, CAIRO_TEST_OUT_SUFFIX, CAIRO_TEST_PNG_EXTENSION); if (image_out_path != NULL) { if (cairo_test_files_equal (out_png_path, image_out_path)) { ret = CAIRO_TEST_XFAILURE; } else { ref_image = cairo_image_surface_create_from_png (image_out_path); if (cairo_surface_status (ref_image) == CAIRO_STATUS_SUCCESS) { diff_status = image_diff (ctx, test_image, ref_image, diff_image, &result); if (diff_status == CAIRO_STATUS_SUCCESS && !image_diff_is_failure (&result, target->error_tolerance)) { ret = CAIRO_TEST_XFAILURE; } cairo_surface_destroy (ref_image); } } free (image_out_path); } } cairo_surface_destroy (test_image); cairo_surface_destroy (diff_image); } if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) { cairo_test_log (ctx, "Error: Function under test left cairo status in an error state: %s\n", cairo_status_to_string (cairo_status (cr))); ret = CAIRO_TEST_ERROR; goto UNWIND_CAIRO; } UNWIND_CAIRO: free (test_filename); free (fail_filename); free (pass_filename); test_filename = fail_filename = pass_filename = NULL; #if HAVE_MEMFAULT if (ret == CAIRO_TEST_FAILURE) MEMFAULT_PRINT_FAULTS (); #endif cairo_destroy (cr); UNWIND_SURFACE: cairo_surface_destroy (surface); if (target->cleanup) target->cleanup (closure); #if HAVE_MEMFAULT cairo_debug_reset_static_data (); #if HAVE_FCFINI FcFini (); #endif if (MEMFAULT_COUNT_LEAKS () > 0) { if (ret != CAIRO_TEST_FAILURE) MEMFAULT_PRINT_FAULTS (); MEMFAULT_PRINT_LEAKS (); } if (ret == CAIRO_TEST_SUCCESS && --malloc_failure_iterations > 0) goto REPEAT; #endif if (have_output) cairo_test_log (ctx, "OUTPUT: %s\n", out_png_path); if (have_result) { if (cmp_png_path == NULL) { /* XXX presume we matched the normal ref last time */ cmp_png_path = ref_png_path; } cairo_test_log (ctx, "REFERENCE: %s\nDIFFERENCE: %s\n", cmp_png_path, diff_png_path); } UNWIND_STRINGS: free (out_png_path); free (ref_png_path); free (base_ref_png_path); free (ref_path); free (new_png_path); free (base_new_png_path); free (new_path); free (xfail_png_path); free (base_xfail_png_path); free (xfail_path); free (diff_png_path); free (base_path); free (base_name); return ret; }
CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemcpy2DAsync)(const CUDA_MEMCPY2D *pCopy, CUstream hStream) { int error = 0; long vgErrorAddress; vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&hStream, sizeof(CUstream)); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Error: 'hStream' in call to cuMemcpy2DAsync not defined.\n"); } cgLock(); CUcontext ctx = NULL; cgGetCtx(&ctx); // Check if destination (device) memory/array is already being written to. switch (pCopy->dstMemoryType) { case CU_MEMORYTYPE_DEVICE: { cgMemListType *nodeMem; nodeMem = cgFindMem(cgFindCtx(ctx), pCopy->dstDevice); if (nodeMem) { // Are we trying to read a memory region that's being written by diffrent stream? if (nodeMem->locked & 2 && nodeMem->stream != hStream) { error++; VALGRIND_PRINTF("Error: Concurrent write and read access by different streams.\n"); } nodeMem->locked = nodeMem->locked | 1; nodeMem->stream = hStream; } break; } case CU_MEMORYTYPE_ARRAY: { cgArrListType *nodeArr; nodeArr = cgFindArr(cgFindCtx(ctx), pCopy->dstArray); if (nodeArr) { // Are we trying to read an array that's being written by different stream? if (nodeArr->locked & 2 && nodeArr->stream != hStream) { error++; VALGRIND_PRINTF("Error: Concurrent write and read access to array by different streams.\n"); } nodeArr->locked = nodeArr->locked | 1; nodeArr->stream = hStream; } break; } } // Check if source (device) memory/array is already being written to/read from. switch (pCopy->srcMemoryType) { case CU_MEMORYTYPE_DEVICE: { cgMemListType *nodeMem; nodeMem = cgFindMem(cgFindCtx(ctx), pCopy->srcDevice); if (nodeMem) { // Are we trying to read a memory region that's being written by diffrent stream? if (nodeMem->locked && nodeMem->stream != hStream) { error++; VALGRIND_PRINTF("Error: Concurrent write and read access by different streams.\n"); } nodeMem->locked = nodeMem->locked | 2; nodeMem->stream = hStream; } break; } case CU_MEMORYTYPE_ARRAY: { cgArrListType *nodeArr; nodeArr = cgFindArr(cgFindCtx(ctx), pCopy->srcArray); if (nodeArr) { // Are we trying to read an array that's being written by different stream? if (nodeArr->locked && nodeArr->stream != hStream) { error++; VALGRIND_PRINTF("Error: Concurrent write and read access to array by different streams.\n"); } nodeArr->locked = nodeArr->locked | 2; nodeArr->stream = hStream; } break; } } cgUnlock(); if (error) { VALGRIND_PRINTF_BACKTRACE(""); } return cuMemcpy2D(pCopy); }
CUresult I_WRAP_SONAME_FNNAME_ZZ(libcudaZdsoZa, cuMemsetD16)(CUdeviceptr dstDevice, unsigned short us, size_t N) { OrigFn fn; CUresult result; CUcontext ctx = NULL; cgMemListType *nodeMemDst; int error = 0; long vgErrorAddress; size_t dstSize; VALGRIND_GET_ORIG_FN(fn); cgLock(); CALL_FN_W_WWW(result, fn, dstDevice, us, N); // Check if function parameters are defined. // TODO: Warning or error in case of a partially undefined us? vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&dstDevice, sizeof(CUdeviceptr)); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Error: 'dstDevice' in call to cuMemsetD16 not defined.\n"); } vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&us, sizeof(us)); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Warning: 'us' in call to cuMemsetD16 is not fully defined.\n"); } vgErrorAddress = VALGRIND_CHECK_MEM_IS_DEFINED(&N, sizeof(size_t)); if (vgErrorAddress) { error++; VALGRIND_PRINTF("Error: 'N' in call to cuMemsetD16 not defined.\n"); } // Fetch current context cgGetCtx(&ctx); nodeMemDst = cgFindMem(cgFindCtx(ctx), dstDevice); // Check if memory has been allocated if (!nodeMemDst) { error++; VALGRIND_PRINTF("Error: Destination device memory not allocated in call to cuMemsetD16.\n"); } else { // If memory is allocated, check size of available memory dstSize = nodeMemDst->size - (dstDevice - nodeMemDst->dptr); if (dstSize < sizeof(unsigned short) * N) { error++; VALGRIND_PRINTF("Error: Allocated device memory too small in call to cuMemsetD16.\n" " Expected %lu allocated bytes but only found %lu.\n", sizeof(unsigned short) * N, dstSize); } // Check if pointer is properly two byte aligned. // TODO: Is this a valid check? if (dstDevice % 2) { error++; VALGRIND_PRINTF("Error: Pointer dstDevice in call to cuMemsetD16 not two byte aligned.\n"); } } if (error) { VALGRIND_PRINTF_BACKTRACE(""); } cgUnlock(); return result; }