blob: 2bb76b6f6eb5c23dc1a593a3152e183cf3c9b146 [file] [log] [blame]
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <utils.h>
#include <list_utils.h>
#include <debug_utils.h>
#include <memmgr.h>
#include <tilermem.h>
#include <tilermem_utils.h>
#include <testlib.h>
/* for star_tiler_test */
#include <fcntl.h> /* open() */
#include <unistd.h> /* close() */
#include <sys/ioctl.h> /* 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);
}