/* * memmgr_test.c * * Memory Allocator Interface tests. * * Copyright (C) 2009-2011 Texas Instruments, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Texas Instruments Incorporated nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* retrieve type definitions */ #define __DEBUG__ #undef __DEBUG_ENTRY__ #define __DEBUG_ASSERT__ #define __MAP_OK__ #undef __WRITE_IN_STRIDE__ #undef STAR_TRACE_MEM #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include /* for star_tiler_test */ #include /* open() */ #include /* close() */ #include /* ioctl() */ #define FALSE 0 #define TESTERR_NOTIMPLEMENTED -65378 #define MAX_ALLOCS 512 #define TESTS\ T(alloc_1D_test(4096, 0))\ T(alloc_2D_test(64, 64, PIXEL_FMT_8BIT))\ T(alloc_2D_test(64, 64, PIXEL_FMT_16BIT))\ T(alloc_2D_test(64, 64, PIXEL_FMT_32BIT))\ T(alloc_NV12_test(64, 64))\ T(map_1D_test(4096, 0))\ T(alloc_1D_test(176 * 144 * 2, 0))\ T(alloc_2D_test(176, 144, PIXEL_FMT_8BIT))\ T(alloc_2D_test(176, 144, PIXEL_FMT_16BIT))\ T(alloc_2D_test(176, 144, PIXEL_FMT_32BIT))\ T(alloc_NV12_test(176, 144))\ T(map_1D_test(176 * 144 * 2, 0))\ T(alloc_1D_test(640 * 480 * 2, 0))\ T(alloc_2D_test(640, 480, PIXEL_FMT_8BIT))\ T(alloc_2D_test(640, 480, PIXEL_FMT_16BIT))\ T(alloc_2D_test(640, 480, PIXEL_FMT_32BIT))\ T(alloc_NV12_test(640, 480))\ T(map_1D_test(640 * 480 * 2, 0))\ T(alloc_1D_test(848 * 480 * 2, 0))\ T(alloc_2D_test(848, 480, PIXEL_FMT_8BIT))\ T(alloc_2D_test(848, 480, PIXEL_FMT_16BIT))\ T(alloc_2D_test(848, 480, PIXEL_FMT_32BIT))\ T(alloc_NV12_test(848, 480))\ T(map_1D_test(848 * 480 * 2, 0))\ T(alloc_1D_test(1280 * 720 * 2, 0))\ T(alloc_2D_test(1280, 720, PIXEL_FMT_8BIT))\ T(alloc_2D_test(1280, 720, PIXEL_FMT_16BIT))\ T(alloc_2D_test(1280, 720, PIXEL_FMT_32BIT))\ T(alloc_NV12_test(1280, 720))\ T(map_1D_test(1280 * 720 * 2, 0))\ T(alloc_1D_test(1920 * 1080 * 2, 0))\ T(alloc_2D_test(1920, 1080, PIXEL_FMT_8BIT))\ T(alloc_2D_test(1920, 1080, PIXEL_FMT_16BIT))\ T(alloc_2D_test(1920, 1080, PIXEL_FMT_32BIT))\ T(alloc_NV12_test(1920, 1080))\ T(map_1D_test(1920 * 1080 * 2, 0))\ T(map_1D_test(4096, 0))\ T(map_1D_test(8192, 0))\ T(map_1D_test(16384, 0))\ T(map_1D_test(32768, 0))\ T(map_1D_test(65536, 0))\ T(neg_alloc_tests())\ T(neg_free_tests())\ T(neg_map_tests())\ T(neg_unmap_tests())\ T(neg_check_tests())\ T(page_size_test())\ T(maxalloc_2D_test(2500, 32, PIXEL_FMT_8BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(2500, 16, PIXEL_FMT_16BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(1250, 16, PIXEL_FMT_32BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(5000, 32, PIXEL_FMT_8BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(5000, 16, PIXEL_FMT_16BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(2500, 16, PIXEL_FMT_32BIT, MAX_ALLOCS))\ T(alloc_2D_test(8193, 16, PIXEL_FMT_8BIT))\ T(alloc_2D_test(8193, 16, PIXEL_FMT_16BIT))\ T(alloc_2D_test(4097, 16, PIXEL_FMT_32BIT))\ T(alloc_2D_test(16384, 16, PIXEL_FMT_8BIT))\ T(alloc_2D_test(16384, 16, PIXEL_FMT_16BIT))\ T(alloc_2D_test(8192, 16, PIXEL_FMT_32BIT))\ T(!alloc_2D_test(16385, 16, PIXEL_FMT_8BIT))\ T(!alloc_2D_test(16385, 16, PIXEL_FMT_16BIT))\ T(!alloc_2D_test(8193, 16, PIXEL_FMT_32BIT))\ T(maxalloc_1D_test(4096, MAX_ALLOCS))\ T(maxalloc_2D_test(64, 64, PIXEL_FMT_8BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(64, 64, PIXEL_FMT_16BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(64, 64, PIXEL_FMT_32BIT, MAX_ALLOCS))\ T(maxalloc_NV12_test(64, 64, MAX_ALLOCS))\ T(maxmap_1D_test(4096, MAX_ALLOCS))\ T(maxalloc_1D_test(176 * 144 * 2, MAX_ALLOCS))\ T(maxalloc_2D_test(176, 144, PIXEL_FMT_8BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(176, 144, PIXEL_FMT_16BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(176, 144, PIXEL_FMT_32BIT, MAX_ALLOCS))\ T(maxalloc_NV12_test(176, 144, MAX_ALLOCS))\ T(maxmap_1D_test(176 * 144 * 2, MAX_ALLOCS))\ T(maxalloc_1D_test(640 * 480 * 2, MAX_ALLOCS))\ T(maxalloc_2D_test(640, 480, PIXEL_FMT_8BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(640, 480, PIXEL_FMT_16BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(640, 480, PIXEL_FMT_32BIT, MAX_ALLOCS))\ T(maxalloc_NV12_test(640, 480, MAX_ALLOCS))\ T(maxmap_1D_test(640 * 480 * 2, MAX_ALLOCS))\ T(maxalloc_1D_test(848 * 480 * 2, MAX_ALLOCS))\ T(maxalloc_2D_test(848, 480, PIXEL_FMT_8BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(848, 480, PIXEL_FMT_16BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(848, 480, PIXEL_FMT_32BIT, MAX_ALLOCS))\ T(maxalloc_NV12_test(848, 480, MAX_ALLOCS))\ T(maxmap_1D_test(848 * 480 * 2, MAX_ALLOCS))\ T(maxalloc_1D_test(1280 * 720 * 2, MAX_ALLOCS))\ T(maxalloc_2D_test(1280, 720, PIXEL_FMT_8BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(1280, 720, PIXEL_FMT_16BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(1280, 720, PIXEL_FMT_32BIT, MAX_ALLOCS))\ T(maxalloc_NV12_test(1280, 720, MAX_ALLOCS))\ T(maxmap_1D_test(1280 * 720 * 2, MAX_ALLOCS))\ T(maxalloc_1D_test(1920 * 1080 * 2, MAX_ALLOCS))\ T(maxalloc_2D_test(1920, 1080, PIXEL_FMT_8BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(1920, 1080, PIXEL_FMT_16BIT, MAX_ALLOCS))\ T(maxalloc_2D_test(1920, 1080, PIXEL_FMT_32BIT, MAX_ALLOCS))\ T(maxalloc_NV12_test(1920, 1080, 2))\ T(maxalloc_NV12_test(1920, 1080, MAX_ALLOCS))\ T(maxmap_1D_test(1920 * 1080 * 2, MAX_ALLOCS))\ T(star_tiler_test(1000, 10))\ T(star_tiler_test(1000, 30))\ T(star_test(100, 10))\ T(star_test(1000, 10))\ /* this is defined in memmgr.c, but not exported as it is for internal use only */ extern int __test__MemMgr(); /** * Returns the default page stride for this block * * @author a0194118 (9/4/2009) * * @param width Width of 2D container * * @return Stride */ static bytes_t def_stride(bytes_t width) { return ROUND_UP_TO2POW(width, PAGE_SIZE); } /** * Returns the bytes per pixel for the pixel format. * * @author a0194118 (9/4/2009) * * @param pixelFormat Pixelformat * * @return Bytes per pixel */ static bytes_t def_bpp(pixel_fmt_t pixelFormat) { return (pixelFormat == PIXEL_FMT_32BIT ? 4 : pixelFormat == PIXEL_FMT_16BIT ? 2 : 1); } /** * This method fills up a range of memory using a start address * and start value. The method of filling ensures that * accidentally overlapping regions have minimal chances of * matching, even if the same starting value is used. This is * because the difference between successive values varies as * such. This series only repeats after 704189 values, so the * probability of a match for a range of at least 2 values is * less than 2*10^-11. * * V(i + 1) - V(i) = { 1, 2, 3, ..., 65535, 2, 4, 6, 8 ..., * 65534, 3, 6, 9, 12, ..., 4, 8, 12, 16, ... } * * @author a0194118 (9/6/2009) * * @param start start value * @param block pointer to block info strucure */ void fill_mem(uint16_t start, MemAllocBlock *block) { IN; uint16_t *ptr = (uint16_t *)block->ptr, delta = 1, step = 1; bytes_t height, width, stride, i; if (block->pixelFormat == PIXEL_FMT_PAGE) { height = 1; stride = width = block->dim.len; } else { height = block->dim.area.height; width = block->dim.area.width; stride = block->stride; } width *= def_bpp(block->pixelFormat); bytes_t size = height * stride; P("(%p,0x%x*0x%x,s=0x%x)=0x%x", block->ptr, width, height, stride, start); CHK_I(width,<=,stride); uint32_t *ptr32 = (uint32_t *)ptr; while (height--) { if (block->pixelFormat == PIXEL_FMT_32BIT) { for (i = 0; i < width; i += sizeof(uint32_t)) { uint32_t val = (start & 0xFFFF) | (((uint32_t)(start + delta) & 0xFFFF) << 16); *ptr32++ = val; start += delta; delta += step; /* increase step if overflown */ if (delta < step) delta = ++step; start += delta; delta += step; /* increase step if overflown */ if (delta < step) delta = ++step; } #ifdef __WRITE_IN_STRIDE__ while (i < stride && (height || ((PAGE_SIZE - 1) & (uint32_t)ptr32))) { *ptr32++ = 0; i += sizeof(uint32_t); } #else ptr32 += (stride - i) / sizeof(uint32_t); #endif } else { for (i = 0; i < width; i += sizeof(uint16_t)) { *ptr++ = start; start += delta; delta += step; /* increase step if overflown */ if (delta < step) delta = ++step; } #ifdef __WRITE_IN_STRIDE__ while (i < stride && (height || ((PAGE_SIZE - 1) & (uint32_t)ptr))) { *ptr++ = 0; i += sizeof(uint16_t); } #else ptr += (stride - i) / sizeof(uint16_t); #endif } } CHK_P((block->pixelFormat == PIXEL_FMT_32BIT ? (void *)ptr32 : (void *)ptr),==, (block->ptr + size)); OUT; } /** * This verifies if a range of memory at a given address was * filled up using the start value. * * @author a0194118 (9/6/2009) * * @param start start value * @param block pointer to block info strucure * * @return 0 on success, non-0 error value on failure */ int check_mem(uint16_t start, MemAllocBlock *block) { IN; uint16_t *ptr = (uint16_t *)block->ptr, delta = 1, step = 1; bytes_t height, width, stride, r, i; if (block->pixelFormat == PIXEL_FMT_PAGE) { height = 1; stride = width = block->dim.len; } else { height = block->dim.area.height; width = block->dim.area.width; stride = block->stride; } width *= def_bpp(block->pixelFormat); CHK_I(width,<=,stride); uint32_t *ptr32 = (uint32_t *)ptr; for (r = 0; r < height; r++) { if (block->pixelFormat == PIXEL_FMT_32BIT) { for (i = 0; i < width; i += sizeof(uint32_t)) { uint32_t val = (start & 0xFFFF) | (((uint32_t)(start + delta) & 0xFFFF) << 16); if (*ptr32++ != val) { DP("assert: val[%u,%u] (=0x%x) != 0x%x", r, i, *--ptr32, val); return R_I(MEMMGR_ERR_GENERIC); } start += delta; delta += step; /* increase step if overflown */ if (delta < step) delta = ++step; start += delta; delta += step; /* increase step if overflown */ if (delta < step) delta = ++step; } #ifdef __WRITE_IN_STRIDE__ while (i < stride && ((r < height - 1) || ((PAGE_SIZE - 1) & (uint32_t)ptr32))) { if (*ptr32++) { DP("assert: val[%u,%u] (=0x%x) != 0", r, i, *--ptr32); return R_I(MEMMGR_ERR_GENERIC); } i += sizeof(uint32_t); } #else ptr32 += (stride - i) / sizeof(uint32_t); #endif } else { for (i = 0; i < width; i += sizeof(uint16_t)) { if (*ptr++ != start) { DP("assert: val[%u,%u] (=0x%x) != 0x%x", r, i, *--ptr, start); return R_I(MEMMGR_ERR_GENERIC); } start += delta; delta += step; /* increase step if overflown */ if (delta < step) delta = ++step; } #ifdef __WRITE_IN_STRIDE__ while (i < stride && ((r < height - 1) || ((PAGE_SIZE - 1) & (uint32_t)ptr))) { if (*ptr++) { DP("assert: val[%u,%u] (=0x%x) != 0", r, i, *--ptr); return R_I(MEMMGR_ERR_GENERIC); } i += sizeof(uint16_t); } #else ptr += (stride - i) / sizeof(uint16_t); #endif } } return R_I(MEMMGR_ERR_NONE); } /** * This method allocates a 1D tiled buffer of the given length * and stride using MemMgr_Alloc. If successful, it checks * that the block information was updated with the pointer to * the block. Additionally, it verifies the correct return * values for MemMgr_IsMapped, MemMgr_Is1DBlock, * MemMgr_Is2DBlock, MemMgr_GetStride, TilerMem_GetStride. It * also verifies TilerMem_VirtToPhys using an internally stored * value of the ssptr. If any of these verifications fail, the * buffer is freed. Otherwise, it is filled using the given * start value. * * @author a0194118 (9/7/2009) * * @param length Buffer length * @param stride Buffer stride * @param val Fill start value * * @return pointer to the allocated buffer, or NULL on failure */ void *alloc_1D(bytes_t length, bytes_t stride, uint16_t val) { MemAllocBlock block; memset(&block, 0, sizeof(block)); block.pixelFormat = PIXEL_FMT_PAGE; block.dim.len = length; block.stride = stride; void *bufPtr = MemMgr_Alloc(&block, 1); CHK_P(bufPtr,==,block.ptr); if (bufPtr) { if (NOT_I(MemMgr_IsMapped(bufPtr),!=,0) || NOT_I(MemMgr_Is1DBlock(bufPtr),!=,0) || NOT_I(MemMgr_Is2DBlock(bufPtr),==,0) || NOT_I(MemMgr_GetStride(bufPtr),==,block.stride) || NOT_P(TilerMem_VirtToPhys(bufPtr),==,block.reserved) || NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(bufPtr)),==,PAGE_SIZE) || NOT_L((PAGE_SIZE - 1) & (long)bufPtr,==,(PAGE_SIZE - 1) & block.reserved)) { MemMgr_Free(bufPtr); return NULL; } fill_mem(val, &block); } return bufPtr; } /** * This method frees a 1D tiled buffer. The given length, * stride and start values are used to verify that the buffer is * still correctly filled. In the event of any errors, the * error value is returned. * * @author a0194118 (9/7/2009) * * @param length Buffer length * @param stride Buffer stride * @param val Fill start value * @param bufPtr Pointer to the allocated buffer * * @return 0 on success, non-0 error value on failure */ int free_1D(bytes_t length, bytes_t stride, uint16_t val, void *bufPtr) { MemAllocBlock block; memset(&block, 0, sizeof(block)); block.pixelFormat = PIXEL_FMT_PAGE; block.dim.len = length; block.stride = stride; block.ptr = bufPtr; int ret = A_I(check_mem(val, &block),==,0); ERR_ADD(ret, MemMgr_Free(bufPtr)); return ret; } /** * This method allocates a 2D tiled buffer of the given width, * height, stride and pixel format using * MemMgr_Alloc. If successful, it checks that the block * information was updated with the pointer to the block. * Additionally, it verifies the correct return values for * MemMgr_IsMapped, MemMgr_Is1DBlock, MemMgr_Is2DBlock, * MemMgr_GetStride, TilerMem_GetStride. It also verifies * TilerMem_VirtToPhys using an internally stored value of the * ssptr. If any of these verifications fail, the buffer is * freed. Otherwise, it is filled using the given start value. * * @author a0194118 (9/7/2009) * * @param width Buffer width * @param height Buffer height * @param fmt Pixel format * @param stride Buffer stride * @param val Fill start value * * @return pointer to the allocated buffer, or NULL on failure */ void *alloc_2D(pixels_t width, pixels_t height, pixel_fmt_t fmt, bytes_t stride, uint16_t val) { MemAllocBlock block; memset(&block, 0, sizeof(block)); block.pixelFormat = fmt; block.dim.area.width = width; block.dim.area.height = height; block.stride = stride; void *bufPtr = MemMgr_Alloc(&block, 1); CHK_P(bufPtr,==,block.ptr); if (bufPtr) { bytes_t cstride = (fmt == PIXEL_FMT_8BIT ? TILER_STRIDE_8BIT : fmt == PIXEL_FMT_16BIT ? TILER_STRIDE_16BIT : TILER_STRIDE_32BIT); if (NOT_I(MemMgr_IsMapped(bufPtr),!=,0) || NOT_I(MemMgr_Is1DBlock(bufPtr),==,0) || NOT_I(MemMgr_Is2DBlock(bufPtr),!=,0) || NOT_I(block.stride,!=,0) || NOT_I(MemMgr_GetStride(bufPtr),==,block.stride) || NOT_P(TilerMem_VirtToPhys(bufPtr),==,block.reserved) || NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(bufPtr)),==,cstride) || NOT_L((PAGE_SIZE - 1) & (long)bufPtr,==,(PAGE_SIZE - 1) & block.reserved)) { MemMgr_Free(bufPtr); return NULL; } fill_mem(val, &block); } return bufPtr; } /** * This method frees a 2D tiled buffer. The given width, * height, pixel format, stride and start values are used to * verify that the buffer is still correctly filled. In the * event of any errors, the error value is returned. * * @author a0194118 (9/7/2009) * * @param width Buffer width * @param height Buffer height * @param fmt Pixel format * @param stride Buffer stride * @param val Fill start value * @param bufPtr Pointer to the allocated buffer * * @return 0 on success, non-0 error value on failure */ int free_2D(pixels_t width, pixels_t height, pixel_fmt_t fmt, bytes_t stride, uint16_t val, void *bufPtr) { MemAllocBlock block; memset(&block, 0, sizeof(block)); block.pixelFormat = fmt; block.dim.area.width = width; block.dim.area.height = height; block.stride = def_stride(width * def_bpp(fmt)); block.ptr = bufPtr; int ret = A_I(check_mem(val, &block),==,0); ERR_ADD(ret, MemMgr_Free(bufPtr)); return ret; } /** * This method allocates an NV12 tiled buffer of the given width * and height using MemMgr_Alloc. If successful, it checks that * the block informations were updated with the pointers to the * individual blocks. Additionally, it verifies the correct * return values for MemMgr_IsMapped, MemMgr_Is1DBlock, * MemMgr_Is2DBlock, MemMgr_GetStride, TilerMem_GetStride for * both blocks. It also verifies TilerMem_VirtToPhys using an * internally stored values of the ssptr. If any of these * verifications fail, the buffer is freed. Otherwise, it is * filled using the given start value. * * @author a0194118 (9/7/2009) * * @param width Buffer width * @param height Buffer height * @param val Fill start value * * @return pointer to the allocated buffer, or NULL on failure */ void *alloc_NV12(pixels_t width, pixels_t height, uint16_t val) { MemAllocBlock blocks[2]; ZERO(blocks); blocks[0].pixelFormat = PIXEL_FMT_8BIT; blocks[0].dim.area.width = width; blocks[0].dim.area.height = height; blocks[1].pixelFormat = PIXEL_FMT_16BIT; blocks[1].dim.area.width = width >> 1; blocks[1].dim.area.height = height >> 1; void *bufPtr = MemMgr_Alloc(blocks, 2); CHK_P(blocks[0].ptr,==,bufPtr); if (bufPtr) { void *buf2 = bufPtr + blocks[0].stride * height; if (NOT_P(blocks[1].ptr,==,buf2) || NOT_I(MemMgr_IsMapped(bufPtr),!=,0) || NOT_I(MemMgr_IsMapped(buf2),!=,0) || NOT_I(MemMgr_Is1DBlock(bufPtr),==,0) || NOT_I(MemMgr_Is1DBlock(buf2),==,0) || NOT_I(MemMgr_Is2DBlock(bufPtr),!=,0) || NOT_I(MemMgr_Is2DBlock(buf2),!=,0) || NOT_I(blocks[0].stride,!=,0) || NOT_I(blocks[1].stride,!=,0) || NOT_I(MemMgr_GetStride(bufPtr),==,blocks[0].stride) || NOT_I(MemMgr_GetStride(buf2),==,blocks[1].stride) || NOT_P(TilerMem_VirtToPhys(bufPtr),==,blocks[0].reserved) || NOT_P(TilerMem_VirtToPhys(buf2),==,blocks[1].reserved) || NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(bufPtr)),==,TILER_STRIDE_8BIT) || NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(buf2)),==,TILER_STRIDE_16BIT) || NOT_L((PAGE_SIZE - 1) & (long)blocks[0].ptr,==,(PAGE_SIZE - 1) & blocks[0].reserved) || NOT_L((PAGE_SIZE - 1) & (long)blocks[1].ptr,==,(PAGE_SIZE - 1) & blocks[1].reserved)) { MemMgr_Free(bufPtr); return NULL; } fill_mem(val, blocks); fill_mem(val, blocks + 1); } else { CHK_P(blocks[1].ptr,==,NULL); } return bufPtr; } /** * This method frees an NV12 tiled buffer. The given width, * height and start values are used to verify that the buffer is * still correctly filled. In the event of any errors, the * error value is returned. * * @author a0194118 (9/7/2009) * * @param width Buffer width * @param height Buffer height * @param val Fill start value * @param bufPtr Pointer to the allocated buffer * * @return 0 on success, non-0 error value on failure */ int free_NV12(pixels_t width, pixels_t height, uint16_t val, void *bufPtr) { MemAllocBlock blocks[2]; memset(blocks, 0, sizeof(blocks)); blocks[0].pixelFormat = PIXEL_FMT_8BIT; blocks[0].dim.area.width = width; blocks[0].dim.area.height = height; blocks[0].stride = def_stride(width); blocks[0].ptr = bufPtr; blocks[1].pixelFormat = PIXEL_FMT_16BIT; blocks[1].dim.area.width = width >> 1; blocks[1].dim.area.height = height >> 1; blocks[1].stride = def_stride(width); blocks[1].ptr = bufPtr + blocks[0].stride * height; int ret = A_I(check_mem(val, blocks),==,0); ERR_ADD(ret, check_mem(val, blocks + 1)); ERR_ADD(ret, MemMgr_Free(bufPtr)); return ret; } /** * This method maps a preallocated 1D buffer of the given length * and stride into tiler space using MemMgr_Map. The mapped * address must differ from the supplied address is successful. * Moreover, it checks that the block information was * updated with the pointer to the block. Additionally, it * verifies the correct return values for MemMgr_IsMapped, * MemMgr_Is1DBlock, MemMgr_Is2DBlock, MemMgr_GetStride, * TilerMem_GetStride. It also verifies TilerMem_VirtToPhys * using an internally stored value of the ssptr. If any of * these verifications fail, the buffer is unmapped. Otherwise, * the original buffer is filled using the given start value. * * :TODO: how do we verify the mapping? * * @author a0194118 (9/7/2009) * * @param dataPtr Pointer to the allocated buffer * @param length Buffer length * @param stride Buffer stride * @param val Fill start value * * @return pointer to the mapped buffer, or NULL on failure */ void *map_1D(void *dataPtr, bytes_t length, bytes_t stride, uint16_t val) { MemAllocBlock block; memset(&block, 0, sizeof(block)); block.pixelFormat = PIXEL_FMT_PAGE; block.dim.len = length; block.stride = stride; block.ptr = dataPtr; void *bufPtr = MemMgr_Map(&block, 1); CHK_P(bufPtr,==,block.ptr); if (bufPtr) { if (NOT_P(bufPtr,!=,dataPtr) || NOT_I(MemMgr_IsMapped(bufPtr),!=,0) || NOT_I(MemMgr_Is1DBlock(bufPtr),!=,0) || NOT_I(MemMgr_Is2DBlock(bufPtr),==,0) || NOT_I(MemMgr_GetStride(bufPtr),==,block.stride) || NOT_P(TilerMem_VirtToPhys(bufPtr),==,block.reserved) || NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(bufPtr)),==,PAGE_SIZE) || NOT_L((PAGE_SIZE - 1) & (long)bufPtr,==,0) || NOT_L((PAGE_SIZE - 1) & block.reserved,==,0)) { MemMgr_UnMap(bufPtr); return NULL; } block.ptr = dataPtr; fill_mem(val, &block); } return bufPtr; } /** * This method unmaps a 1D tiled buffer. The given data * pointer, length, stride and start values are used to verify * that the buffer is still correctly filled. In the event of * any errors, the error value is returned. * * :TODO: how do we verify the mapping? * * @author a0194118 (9/7/2009) * * @param dataPtr Pointer to the preallocated buffer * @param length Buffer length * @param stride Buffer stride * @param val Fill start value * @param bufPtr Pointer to the mapped buffer * * @return 0 on success, non-0 error value on failure */ int unmap_1D(void *dataPtr, bytes_t length, bytes_t stride, uint16_t val, void *bufPtr) { MemAllocBlock block; memset(&block, 0, sizeof(block)); block.pixelFormat = PIXEL_FMT_PAGE; block.dim.len = length; block.stride = stride; block.ptr = dataPtr; int ret = A_I(check_mem(val, &block),==,0); ERR_ADD(ret, MemMgr_UnMap(bufPtr)); return ret; } /** * Tests the MemMgr_PageSize method. * * @author a0194118 (9/15/2009) * * @return 0 on success, non-0 error value on failure. */ int page_size_test() { return NOT_I(MemMgr_PageSize(),==,PAGE_SIZE); } /** * This method tests the allocation and freeing of a 1D tiled * buffer. * * @author a0194118 (9/7/2009) * * @param length Buffer length * @param stride Buffer stride * * @return 0 on success, non-0 error value on failure */ int alloc_1D_test(bytes_t length, bytes_t stride) { printf("Allocate & Free %ub 1D buffer\n", length); uint16_t val = (uint16_t) rand(); void *ptr = alloc_1D(length, stride, val); if (!ptr) return 1; int res = free_1D(length, stride, val, ptr); return res; } /** * This method tests the allocation and freeing of a 2D tiled * buffer. * * @author a0194118 (9/7/2009) * * @param width Buffer width * @param height Buffer height * @param fmt Pixel format * * @return 0 on success, non-0 error value on failure */ int alloc_2D_test(pixels_t width, pixels_t height, pixel_fmt_t fmt) { printf("Allocate & Free %ux%ux%ub 1D buffer\n", width, height, def_bpp(fmt)); uint16_t val = (uint16_t) rand(); void *ptr = alloc_2D(width, height, fmt, 0, val); if (!ptr) return 1; int res = free_2D(width, height, fmt, 0, val, ptr); return res; } /** * This method tests the allocation and freeing of an NV12 tiled * buffer. * * @author a0194118 (9/7/2009) * * @param width Buffer width * @param height Buffer height * * @return 0 on success, non-0 error value on failure */ int alloc_NV12_test(pixels_t width, pixels_t height) { printf("Allocate & Free %ux%u NV12 buffer\n", width, height); uint16_t val = (uint16_t) rand(); void *ptr = alloc_NV12(width, height, val); if (!ptr) return 1; int res = free_NV12(width, height, val, ptr); return res; } /** * This method tests the mapping and unmapping of a 1D buffer. * * @author a0194118 (9/7/2009) * * @param length Buffer length * @param stride Buffer stride * * @return 0 on success, non-0 error value on failure */ int map_1D_test(bytes_t length, bytes_t stride) { length = (length + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1); printf("Mapping and UnMapping 0x%xb 1D buffer\n", length); #ifdef __MAP_OK__ /* allocate aligned buffer */ void *buffer = malloc(length + PAGE_SIZE - 1); void *dataPtr = (void *)(((uint32_t)buffer + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); uint16_t val = (uint16_t) rand(); void *ptr = map_1D(dataPtr, length, stride, val); if (!ptr) return 1; int res = unmap_1D(dataPtr, length, stride, val, ptr); FREE(buffer); #else int res = TESTERR_NOTIMPLEMENTED; #endif return res; } /** * This method tests the allocation and freeing of a number of * 1D tiled buffers (up to MAX_ALLOCS) * * @author a0194118 (9/7/2009) * * @param length Buffer length * * @return 0 on success, non-0 error value on failure */ int maxalloc_1D_test(bytes_t length, int max_allocs) { printf("Allocate & Free max # of %ub 1D buffers\n", length); struct data { uint16_t val; void *bufPtr; } *mem; /* allocate as many buffers as we can */ mem = NEWN(struct data, max_allocs); void *ptr = (void *)mem; int ix, res = 0; for (ix = 0; ptr && ix < max_allocs;) { uint16_t val = (uint16_t) rand(); ptr = alloc_1D(length, 0, val); if (ptr) { mem[ix].val = val; mem[ix].bufPtr = ptr; ix++; } } P(":: Allocated %d buffers", ix); while (ix--) { ERR_ADD(res, free_1D(length, 0, mem[ix].val, mem[ix].bufPtr)); } FREE(mem); return res; } /** * This method tests the allocation and freeing of a number of * 2D tiled buffers (up to MAX_ALLOCS) * * @author a0194118 (9/7/2009) * * @param width Buffer width * @param height Buffer height * @param fmt Pixel format * * @return 0 on success, non-0 error value on failure */ int maxalloc_2D_test(pixels_t width, pixels_t height, pixel_fmt_t fmt, int max_allocs) { printf("Allocate & Free max # of %ux%ux%ub 1D buffers\n", width, height, def_bpp(fmt)); struct data { uint16_t val; void *bufPtr; } *mem; /* allocate as many buffers as we can */ mem = NEWN(struct data, max_allocs); void *ptr = (void *)mem; int ix, res = 0; for (ix = 0; ptr && ix < max_allocs;) { uint16_t val = (uint16_t) rand(); ptr = alloc_2D(width, height, fmt, 0, val); if (ptr) { mem[ix].val = val; mem[ix].bufPtr = ptr; ix++; } } P(":: Allocated %d buffers", ix); while (ix--) { ERR_ADD(res, free_2D(width, height, fmt, 0, mem[ix].val, mem[ix].bufPtr)); } FREE(mem); return res; } /** * This method tests the allocation and freeing of a number of * NV12 tiled buffers (up to MAX_ALLOCS) * * @author a0194118 (9/7/2009) * * @param width Buffer width * @param height Buffer height * * @return 0 on success, non-0 error value on failure */ int maxalloc_NV12_test(pixels_t width, pixels_t height, int max_allocs) { printf("Allocate & Free max # of %ux%u NV12 buffers\n", width, height); struct data { uint16_t val; void *bufPtr; } *mem; /* allocate as many buffers as we can */ mem = NEWN(struct data, max_allocs); void *ptr = (void *)mem; int ix, res = 0; for (ix = 0; ptr && ix < max_allocs;) { uint16_t val = (uint16_t) rand(); ptr = alloc_NV12(width, height, val); if (ptr) { mem[ix].val = val; mem[ix].bufPtr = ptr; ix++; } } P(":: Allocated %d buffers", ix); while (ix--) { ERR_ADD(res, free_NV12(width, height, mem[ix].val, mem[ix].bufPtr)); } FREE(mem); return res; } /** * This method tests the mapping and unnapping of a number of * 1D buffers (up to MAX_ALLOCS) * * @author a0194118 (9/7/2009) * * @param length Buffer length * * @return 0 on success, non-0 error value on failure */ int maxmap_1D_test(bytes_t length, int max_maps) { length = (length + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1); printf("Map & UnMap max # of %xb 1D buffers\n", length); #ifdef __MAP_OK__ struct data { uint16_t val; void *bufPtr, *buffer, *dataPtr; } *mem; /* map as many buffers as we can */ mem = NEWN(struct data, max_maps); void *ptr = (void *)mem; int ix, res = 0; for (ix = 0; ptr && ix < max_maps;) { /* allocate aligned buffer */ ptr = malloc(length + PAGE_SIZE - 1); if (ptr) { void *buffer = ptr; void *dataPtr = (void *)(((uint32_t)buffer + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); uint16_t val = (uint16_t) rand(); ptr = map_1D(dataPtr, length, 0, val); if (ptr) { mem[ix].val = val; mem[ix].bufPtr = ptr; mem[ix].buffer = buffer; mem[ix].dataPtr = dataPtr; ix++; } else { FREE(buffer); break; } } } P(":: Mapped %d buffers", ix); while (ix--) { ERR_ADD(res, unmap_1D(mem[ix].dataPtr, length, 0, mem[ix].val, mem[ix].bufPtr)); FREE(mem[ix].buffer); } #else int res = TESTERR_NOTIMPLEMENTED; #endif return res; } /** * This stress tests allocates/maps/frees/unmaps buffers at * least num_ops times. The test maintains a set of slots that * are initially NULL. For each operation, a slot is randomly * selected. If the slot is not used, it is filled randomly * with a 1D, 2D, NV12 or mapped buffer. If it is used, the * slot is cleared by freeing/unmapping the buffer already * there. The buffers are filled on alloc/map and this is * checked on free/unmap to verify that there was no memory * corruption. Failed allocation and maps are ignored as we may * run out of memory. The return value is the first error code * encountered, or 0 on success. * * This test sets the seed so that it produces reproducible * results. * * @author a0194118 (9/7/2009) * * @param num_ops Number of operations to perform * @param num_slots Number of slots to maintain * * @return 0 on success, non-0 error value on failure */ int star_test(uint32_t num_ops, uint16_t num_slots) { printf("Random set of %d Allocs/Maps and Frees/UnMaps for %d slots\n", num_ops, num_slots); srand(0x4B72316A); struct data { int op; uint16_t val; pixels_t width, height; bytes_t length; void *bufPtr; void *buffer; void *dataPtr; } *mem; /* allocate memory state */ mem = NEWN(struct data, num_slots); if (!mem) return NOT_P(mem,!=,NULL); /* perform alloc/free/unmaps */ int res = 0, ix; while (!res && num_ops--) { ix = rand() % num_slots; /* see if we need to free/unmap data */ if (mem[ix].bufPtr) { /* check memory fill */ switch (mem[ix].op) { case 0: res = unmap_1D(mem[ix].dataPtr, mem[ix].length, 0, mem[ix].val, mem[ix].bufPtr); FREE(mem[ix].buffer); break; case 1: res = free_1D(mem[ix].length, 0, mem[ix].val, mem[ix].bufPtr); break; case 2: res = free_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_8BIT, 0, mem[ix].val, mem[ix].bufPtr); break; case 3: res = free_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_16BIT, 0, mem[ix].val, mem[ix].bufPtr); break; case 4: res = free_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_32BIT, 0, mem[ix].val, mem[ix].bufPtr); break; case 5: res = free_NV12(mem[ix].width, mem[ix].height, mem[ix].val, mem[ix].bufPtr); break; } P("%s[%p]", mem[ix].op ? "free" : "unmap", mem[ix].bufPtr); ZERO(mem[ix]); } /* we need to allocate/map data */ else { int op = rand(); /* set width */ pixels_t width, height; switch ("AAAABBBBCCCDDEEF"[op & 15]) { case 'F': width = 1920; height = 1080; break; case 'E': width = 1280; height = 720; break; case 'D': width = 640; height = 480; break; case 'C': width = 848; height = 480; break; case 'B': width = 176; height = 144; break; case 'A': width = height = 64; break; } mem[ix].length = (bytes_t)width * height; mem[ix].width = width; mem[ix].height = height; mem[ix].val = ((uint16_t)rand()); /* perform operation */ mem[ix].op = "AAABBBBCCCCDDDDE"[(op >> 4) & 15] - 'A'; switch (mem[ix].op) { case 0: /* map 1D buffer */ #ifdef __MAP_OK__ /* allocate aligned buffer */ mem[ix].length = (mem[ix].length + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1); mem[ix].buffer = malloc(mem[ix].length + PAGE_SIZE - 1); if (mem[ix].buffer) { mem[ix].dataPtr = (void *)(((uint32_t)mem[ix].buffer + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); mem[ix].bufPtr = map_1D(mem[ix].dataPtr, mem[ix].length, 0, mem[ix].val); if (!mem[ix].bufPtr) FREE(mem[ix].buffer); } P("map[l=0x%x] = %p", mem[ix].length, mem[ix].bufPtr); break; #else mem[ix].op = 1; #endif case 1: mem[ix].bufPtr = alloc_1D(mem[ix].length, 0, mem[ix].val); P("alloc[l=0x%x] = %p", mem[ix].length, mem[ix].bufPtr); break; case 2: mem[ix].bufPtr = alloc_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_8BIT, 0, mem[ix].val); P("alloc[%d*%d*8] = %p", mem[ix].width, mem[ix].height, mem[ix].bufPtr); break; case 3: mem[ix].bufPtr = alloc_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_16BIT, 0, mem[ix].val); P("alloc[%d*%d*16] = %p", mem[ix].width, mem[ix].height, mem[ix].bufPtr); break; case 4: mem[ix].bufPtr = alloc_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_32BIT, 0, mem[ix].val); P("alloc[%d*%d*32] = %p", mem[ix].width, mem[ix].height, mem[ix].bufPtr); break; case 5: mem[ix].bufPtr = alloc_NV12(mem[ix].width, mem[ix].height, mem[ix].val); P("alloc[%d*%d*NV12] = %p", mem[ix].width, mem[ix].height, mem[ix].bufPtr); break; } /* check all previous buffers */ #ifdef STAR_TRACE_MEM for (ix = 0; ix < num_slots; ix++) { MemAllocBlock blk; if (mem[ix].bufPtr) { if(0) P("ptr=%p, op=%d, w=%d, h=%d, l=%x, val=%x", mem[ix].bufPtr, mem[ix].op, mem[ix].width, mem[ix].height, mem[ix].length, mem[ix].val); switch (mem[ix].op) { case 0: case 1: blk.pixelFormat = PIXEL_FMT_PAGE; blk.dim.len = mem[ix].length; break; case 5: blk.pixelFormat = PIXEL_FMT_16BIT; blk.dim.area.width = mem[ix].width >> 1; blk.dim.area.height = mem[ix].height >> 1; blk.stride = def_stride(mem[ix].width); /* same for Y and UV */ blk.ptr = mem[ix].bufPtr + mem[ix].height * blk.stride; check_mem(mem[ix].val, &blk); case 2: blk.pixelFormat = PIXEL_FMT_8BIT; blk.dim.area.width = mem[ix].width; blk.dim.area.height = mem[ix].height; blk.stride = def_stride(mem[ix].width); break; case 3: blk.pixelFormat = PIXEL_FMT_16BIT; blk.dim.area.width = mem[ix].width; blk.dim.area.height = mem[ix].height; blk.stride = def_stride(mem[ix].width * 2); break; case 4: blk.pixelFormat = PIXEL_FMT_32BIT; blk.dim.area.width = mem[ix].width; blk.dim.area.height = mem[ix].height; blk.stride = def_stride(mem[ix].width * 4); break; } blk.ptr = mem[ix].bufPtr; check_mem(mem[ix].val, &blk); } } #endif } } /* unmap and free everything */ for (ix = 0; ix < num_slots; ix++) { if (mem[ix].bufPtr) { /* check memory fill */ switch (mem[ix].op) { case 0: ERR_ADD(res, unmap_1D(mem[ix].dataPtr, mem[ix].length, 0, mem[ix].val, mem[ix].bufPtr)); FREE(mem[ix].buffer); break; case 1: ERR_ADD(res, free_1D(mem[ix].length, 0, mem[ix].val, mem[ix].bufPtr)); break; case 2: ERR_ADD(res, free_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_8BIT, 0, mem[ix].val, mem[ix].bufPtr)); break; case 3: ERR_ADD(res, free_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_16BIT, 0, mem[ix].val, mem[ix].bufPtr)); break; case 4: ERR_ADD(res, free_2D(mem[ix].width, mem[ix].height, PIXEL_FMT_32BIT, 0, mem[ix].val, mem[ix].bufPtr)); break; case 5: ERR_ADD(res, free_NV12(mem[ix].width, mem[ix].height, mem[ix].val, mem[ix].bufPtr)); break; } } } FREE(mem); return res; } /** * This stress tests allocates/maps/frees/unmaps buffers at * least num_ops times. The test maintains a set of slots that * are initially NULL. For each operation, a slot is randomly * selected. If the slot is not used, it is filled randomly * with a 1D, 2D, NV12 or mapped buffer. If it is used, the * slot is cleared by freeing/unmapping the buffer already * there. The buffers are filled on alloc/map and this is * checked on free/unmap to verify that there was no memory * corruption. Failed allocation and maps are ignored as we may * run out of memory. The return value is the first error code * encountered, or 0 on success. * * This test sets the seed so that it produces reproducible * results. * * @author a0194118 (9/7/2009) * * @param num_ops Number of operations to perform * @param num_slots Number of slots to maintain * * @return 0 on success, non-0 error value on failure */ int star_tiler_test(uint32_t num_ops, uint16_t num_slots) { printf("Random set of %d tiler Allocs/Maps and Frees/UnMaps for %d slots\n", num_ops, num_slots); srand(0x4B72316A); struct data { int op; struct tiler_block_info blk; void *buffer; } *mem; /* allocate memory state */ mem = NEWN(struct data, num_slots); if (!mem) return NOT_P(mem,!=,NULL); /* perform alloc/free/unmaps */ int ix, td = A_S(open("/dev/tiler", O_RDWR),>=,0), res = td < 0 ? td : 0; while (!res && num_ops--) { ix = rand() % num_slots; /* see if we need to free/unmap data */ if (mem[ix].blk.id) { P("free [0x%x(0x%x)]", mem[ix].blk.id, mem[ix].blk.ssptr); res = A_S(ioctl(td, TILIOC_FBLK, &mem[ix].blk),==,0); FREE(mem[ix].buffer); ZERO(mem[ix]); } /* we need to allocate/map data */ else { int op = rand(); /* set width */ pixels_t width, height; switch ("AAAABBBBCCCDDEEF"[op & 15]) { case 'F': width = 1920; height = 1080; break; case 'E': width = 1280; height = 720; break; case 'D': width = 640; height = 480; break; case 'C': width = 848; height = 480; break; case 'B': width = 176; height = 144; break; case 'A': width = height = 64; break; } bytes_t length = (bytes_t)width * height; /* perform operation */ mem[ix].op = "AAABBBBCCCCDDDDE"[(op >> 4) & 15] - 'A'; switch (mem[ix].op) { case 0: /* map 1D buffer */ /* allocate aligned buffer */ length = (length + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1); mem[ix].buffer = malloc(length + PAGE_SIZE - 1); if (mem[ix].buffer) { mem[ix].blk.dim.len = length; mem[ix].blk.fmt = TILFMT_PAGE; mem[ix].blk.ptr = (void *)(((uint32_t)mem[ix].buffer + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); res = A_S(ioctl(td, TILIOC_MBLK, &mem[ix].blk),==,0); if (res) FREE(mem[ix].buffer); } P("map[l=0x%x] = 0x%x(0x%x)", length, mem[ix].blk.id, mem[ix].blk.ssptr); break; case 1: mem[ix].blk.dim.len = length; mem[ix].blk.fmt = TILFMT_PAGE; res = A_S(ioctl(td, TILIOC_GBLK, &mem[ix].blk),==,0); P("alloc[l=0x%x] = 0x%x(0x%x)", length, mem[ix].blk.id, mem[ix].blk.ssptr); break; case 2: case 3: case 4: mem[ix].blk.dim.area.width = width; mem[ix].blk.dim.area.height = height; mem[ix].blk.fmt = TILFMT_8BIT + mem[ix].op - 2; res = A_S(ioctl(td, TILIOC_GBLK, &mem[ix].blk),==,0); P("alloc[%d*%d*%d] = 0x%x(0x%x)", width, height, 8 << (mem[ix].op -2), mem[ix].blk.id, mem[ix].blk.ssptr); break; } } } /* unmap and free everything */ for (ix = 0; ix < num_slots; ix++) { if (mem[ix].blk.id) { res = A_S(ioctl(td, TILIOC_FBLK, &mem[ix].blk),==,0); FREE(mem[ix].buffer); } } ERR_ADD_S(res, close(td)); FREE(mem); return res; } #define NEGA(exp) ({ void *__ptr__ = A_P(exp,==,NULL); if (__ptr__) MemMgr_Free(__ptr__); __ptr__ != NULL; }) /** * Performs negative tests for MemMgr_Alloc. * * @author a0194118 (9/7/2009) * * @return 0 on success, non-0 error value on failure */ int neg_alloc_tests() { printf("Negative Alloc tests\n"); MemAllocBlock block[2], *blk; memset(&block, 0, sizeof(block)); int ret = 0, num_blocks; for (num_blocks = 1; num_blocks < 3; num_blocks++) { blk = block + num_blocks - 1; P("/* bad pixel format */"); blk->pixelFormat = PIXEL_FMT_MIN - 1; blk->dim.len = PAGE_SIZE; ret |= NEGA(MemMgr_Alloc(block, num_blocks)); blk->pixelFormat = PIXEL_FMT_MAX + 1; ret |= NEGA(MemMgr_Alloc(block, num_blocks)); P("/* bad 1D stride */"); blk->pixelFormat = PIXEL_FMT_PAGE; blk->stride = PAGE_SIZE - 1; ret |= NEGA(MemMgr_Alloc(block, num_blocks)); P("/* 0 1D length */"); blk->dim.len = blk->stride = 0; ret |= NEGA(MemMgr_Alloc(block, num_blocks)); P("/* bad 2D stride */"); blk->pixelFormat = PIXEL_FMT_8BIT; blk->dim.area.width = PAGE_SIZE - 1; blk->stride = PAGE_SIZE - 1; blk->dim.area.height = 16; ret |= NEGA(MemMgr_Alloc(block, num_blocks)); P("/* bad 2D width */"); blk->stride = blk->dim.area.width = 0; ret |= NEGA(MemMgr_Alloc(block, num_blocks)); P("/* bad 2D height */"); blk->dim.area.height = 0; blk->dim.area.width = 16; ret |= NEGA(MemMgr_Alloc(block, num_blocks)); /* good 2D block */ blk->dim.area.height = 16; } block[0].pixelFormat = block[1].pixelFormat = PIXEL_FMT_8BIT; block[0].dim.area.width = 16384; block[0].dim.area.height = block[1].dim.area.width = 16; block[1].dim.area.height = 8192; ret |= NEGA(MemMgr_Alloc(block, 2)); return ret; } /** * Performs negative tests for MemMgr_Free. * * @author a0194118 (9/7/2009) * * @return 0 on success, non-0 error value on failure */ int neg_free_tests() { printf("Negative Free tests\n"); void *ptr = alloc_2D(2500, 10, PIXEL_FMT_16BIT, 2 * PAGE_SIZE, 0); int ret = 0; MemMgr_Free(ptr); P("/* free something twice */"); ret |= NOT_I(MemMgr_Free(ptr),!=,0); P("/* free NULL */"); ret |= NOT_I(MemMgr_Free(NULL),!=,0); P("/* free arbitrary value */"); ret |= NOT_I(MemMgr_Free((void *)0x12345678),!=,0); P("/* free mapped buffer */"); void *buffer = malloc(PAGE_SIZE * 2); void *dataPtr = (void *)(((uint32_t)buffer + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); ptr = map_1D(dataPtr, PAGE_SIZE, 0, 0); ret |= NOT_I(MemMgr_Free(ptr),!=,0); MemMgr_UnMap(ptr); return ret; } #define NEGM(exp) ({ void *__ptr__ = A_P(exp,==,NULL); if (__ptr__) MemMgr_UnMap(__ptr__); __ptr__ != NULL; }) /** * Performs negative tests for MemMgr_Map. * * @author a0194118 (9/7/2009) * * @return 0 on success, non-0 error value on failure */ int neg_map_tests() { printf("Negative Map tests\n"); MemAllocBlock block[2], *blk; memset(&block, 0, sizeof(block)); int ret = 0, num_blocks; for (num_blocks = 1; num_blocks < 3; num_blocks++) { blk = block + num_blocks - 1; P("/* bad pixel format */"); blk->pixelFormat = PIXEL_FMT_MIN - 1; blk->dim.len = PAGE_SIZE; ret |= NEGM(MemMgr_Map(block, num_blocks)); blk->pixelFormat = PIXEL_FMT_MAX + 1; ret |= NEGM(MemMgr_Map(block, num_blocks)); P("/* bad 1D stride */"); blk->pixelFormat = PIXEL_FMT_PAGE; blk->stride = PAGE_SIZE - 1; ret |= NEGM(MemMgr_Map(block, num_blocks)); P("/* 0 1D length */"); blk->dim.len = blk->stride = 0; ret |= NEGM(MemMgr_Map(block, num_blocks)); P("/* bad 2D stride */"); blk->pixelFormat = PIXEL_FMT_8BIT; blk->dim.area.width = PAGE_SIZE - 1; blk->stride = PAGE_SIZE - 1; blk->dim.area.height = 16; ret |= NEGM(MemMgr_Map(block, num_blocks)); P("/* bad 2D width */"); blk->stride = blk->dim.area.width = 0; ret |= NEGM(MemMgr_Map(block, num_blocks)); P("/* bad 2D height */"); blk->dim.area.height = 0; blk->dim.area.width = 16; ret |= NEGM(MemMgr_Map(block, num_blocks)); /* good 2D block */ blk->dim.area.height = 16; } P("/* 2 buffers */"); ret |= NEGM(MemMgr_Map(block, 2)); P("/* 1 2D buffer */"); ret |= NEGM(MemMgr_Map(block, 1)); P("/* 1 1D buffer with no address */"); block[0].pixelFormat = PIXEL_FMT_PAGE; block[0].dim.len = 2 * PAGE_SIZE; block[0].ptr = NULL; ret |= NEGM(MemMgr_Map(block, 1)); P("/* 1 1D buffer with not aligned start address */"); void *buffer = malloc(3 * PAGE_SIZE); void *dataPtr = (void *)(((uint32_t)buffer + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); block[0].ptr = dataPtr + 3; ret |= NEGM(MemMgr_Map(block, 1)); P("/* 1 1D buffer with not aligned length */"); block[0].ptr = dataPtr; block[0].dim.len -= 5; ret |= NEGM(MemMgr_Map(block, 1)); #if 0 /* TODO: it's possible that our va falls within the TILER addr range */ P("/* Mapping a tiled 1D buffer */"); void *ptr = alloc_1D(PAGE_SIZE * 2, 0, 0); dataPtr = (void *)(((uint32_t)ptr + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); block[0].ptr = dataPtr; block[0].dim.len = PAGE_SIZE; ret |= NEGM(MemMgr_Map(block, 1)); MemMgr_Free(ptr); #endif return ret; } /** * Performs negative tests for MemMgr_UnMap. * * @author a0194118 (9/7/2009) * * @return 0 on success, non-0 error value on failure */ int neg_unmap_tests() { printf("Negative Unmap tests\n"); void *ptr = alloc_1D(PAGE_SIZE, 0, 0); int ret = 0; P("/* unmap alloced buffer */"); ret |= NOT_I(MemMgr_UnMap(ptr),!=,0); MemMgr_Free(ptr); void *buffer = malloc(PAGE_SIZE * 2); void *dataPtr = (void *)(((uint32_t)buffer + PAGE_SIZE - 1) &~ (PAGE_SIZE - 1)); ptr = map_1D(dataPtr, PAGE_SIZE, 0, 0); MemMgr_UnMap(ptr); P("/* unmap something twice */"); ret |= NOT_I(MemMgr_UnMap(ptr),!=,0); P("/* unmap NULL */"); ret |= NOT_I(MemMgr_UnMap(NULL),!=,0); P("/* unmap arbitrary value */"); ret |= NOT_I(MemMgr_UnMap((void *)0x12345678),!=,0); return ret; } /** * Performs negative tests for MemMgr_Is.. functions. * * @author a0194118 (9/7/2009) * * @return 0 on success, non-0 error value on failure */ int neg_check_tests() { printf("Negative Is... tests\n"); void *ptr = malloc(32); int ret = 0; ret |= NOT_I(MemMgr_Is1DBlock(NULL),==,FALSE); ret |= NOT_I(MemMgr_Is1DBlock((void *)0x12345678),==,FALSE); ret |= NOT_I(MemMgr_Is1DBlock(ptr),==,FALSE); ret |= NOT_I(MemMgr_Is2DBlock(NULL),==,FALSE); ret |= NOT_I(MemMgr_Is2DBlock((void *)0x12345678),==,FALSE); ret |= NOT_I(MemMgr_Is2DBlock(ptr),==,FALSE); ret |= NOT_I(MemMgr_IsMapped(NULL),==,FALSE); ret |= NOT_I(MemMgr_IsMapped((void *)0x12345678),==,FALSE); ret |= NOT_I(MemMgr_IsMapped(ptr),==,FALSE); ret |= NOT_I(MemMgr_GetStride(NULL),==,0); ret |= NOT_I(MemMgr_GetStride((void *)0x12345678),==,0); ret |= NOT_I(MemMgr_GetStride(ptr),==,PAGE_SIZE); ret |= NOT_P(TilerMem_VirtToPhys(NULL),==,0); ret |= NOT_P(TilerMem_VirtToPhys((void *)0x12345678),==,0); ret |= NOT_P(TilerMem_VirtToPhys(ptr),!=,0); ret |= NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(NULL)),==,0); ret |= NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys((void *)0x12345678)),==,0); ret |= NOT_I(TilerMem_GetStride(TilerMem_VirtToPhys(ptr)),==,0); FREE(ptr); return ret; } DEFINE_TESTS(TESTS) /** * We run the same identity check before and after running the * tests. * * @author a0194118 (9/12/2009) */ void memmgr_identity_test(void *ptr) { /* also execute internal unit tests - this also verifies that we did not keep any references */ __test__MemMgr(); } /** * Main test function. Checks arguments for test case ranges, * runs tests and prints usage or test list if required. * * @author a0194118 (9/7/2009) * * @param argc Number of arguments * @param argv Arguments * * @return -1 on usage or test list, otherwise # of failed * tests. */ int main(int argc, char **argv) { return TestLib_Run(argc, argv, memmgr_identity_test, memmgr_identity_test, NULL); }