    /* 
     * vzcl_maxalloc.c 
     *  
     * Copyright 2012 Vanja Zecevic 
     *  
     * This program is free software: you can redistribute it and/or modify 
     * it under the terms of the GNU General Public License as published by 
     * the Free Software Foundation, either version 3 of the License, or 
     * (at your option) any later version. 
     * 
     * This program is distributed in the hope that it will be useful, 
     * but WITHOUT ANY WARRANTY; without even the implied warranty of 
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     * GNU General Public License for more details. 
     * 
     * You should have received a copy of the GNU General Public License 
     * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
     * 
     */  
      
    #include <stdio.h>  
    #include <CL/cl.h>  
	//#include <stdint.h>
	#include <string.h>

    int main (int argc, char * argv[])  
    {  
    int chunk = 10;  
    int maxmem = 2000;  
    int iChunk;  
    int nChunk;  
    int iX;  
    int iArg;  
    int nX;  
    int nAccessed;  
      
    cl_platform_id platform;  
    cl_device_id device;  
    cl_context Context;  
    cl_command_queue CmdQueue;  
    cl_int err_tr = CL_SUCCESS;  
    cl_ulong global_size;  
      
    cl_mem * buffers_dev;  
    int ** buffers_host;  
      
    /*----------------------------------------------------------------------------*/  
    /* Get flags.  */  
    if (argc <=6 ) {  
        for (iArg=1; iArg<argc; iArg++) {  
            if (!strcmp(argv[iArg],"--help")) {  
                printf(  
      "\nUSAGE:\n"  
      "vzcl_maxalloc <flags>\n"  
      "prints the ammount of available memory on an OpenCL device\n"  
      "reported by clGetDeviceInfo and also the actual ammount able to be\n"  
      "accessed.\n"  
      "\n"  
      "EXAMPLE:\n"  
      "vzcl_maxalloc --chunk 10 --maxmem 2000\n"  
      "\n"  
      "FLAGS:\n"  
      "--help   Prints this message\n"  
      "--chunk  The size of each chunk to be allocated in MB (default 10 MB)\n"  
      "--maxmem The maximum memory to allocate in MB (default 2000 MB)\n"  
                  );  
                exit(1);  
            }  
            else if (!strcmp(argv[iArg],"--chunk"))  chunk  = atoi(argv[iArg+1]);   
            else if (!strcmp(argv[iArg],"--maxmem")) maxmem = atoi(argv[iArg+1]);  
        }  
    }  
    nChunk = maxmem/chunk;  
    nX = (chunk*(int)1e6)/sizeof(int);  
      
    /*----------------------------------------------------------------------------*/  
    /* Initialize OpenCL devices.  */  
    err_tr = clGetPlatformIDs(1, &platform, NULL);  
    clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, NULL);  
    Context = clCreateContext(NULL, 1, &device, NULL, NULL, NULL);  
    CmdQueue = clCreateCommandQueue(Context, device, 0, NULL);  
      
    clGetDeviceInfo(device, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(cl_ulong),  
      &global_size, NULL);  
    printf("Created OpenCL context.\n"  
           "Global memory size: %li MB\n",  
           global_size/(int)1e6);  
      
    /*----------------------------------------------------------------------------*/  
    /* First allocate buffers.  */  
    buffers_dev = (cl_mem*)malloc(nChunk*sizeof(cl_mem));  
    for (iChunk=0; iChunk<nChunk; iChunk++) {  
        *(buffers_dev+iChunk) = clCreateBuffer(Context, CL_MEM_READ_WRITE,  
          nX*sizeof(int), NULL, &err_tr);  
        if (err_tr != CL_SUCCESS) {  
            /*printf("error %i\n", err_tr);*/  
            break;  
        }  
    }  
    printf("Allocated %lu MB\n", iChunk*nX*sizeof(int)/(int)1e6);  
    nChunk = iChunk;  
      
    /*----------------------------------------------------------------------------*/  
    /* Now try to access buffers.  */  
    buffers_host = (int**)malloc(nChunk*sizeof(int*));  
    for (iChunk=0; iChunk<nChunk; iChunk++) {  
        *(buffers_host+iChunk) = (int*)malloc(nX*sizeof(int));  
        for (iX=0; iX<nX; iX++) *(*(buffers_host+iChunk)+iX) = 0;  
        err_tr = clEnqueueWriteBuffer(CmdQueue, *(buffers_dev+iChunk), CL_TRUE, 0,  
          nX*sizeof(int), *(buffers_host+iChunk), 0, NULL, NULL);  
        if (err_tr != CL_SUCCESS) {  
            /*printf("error %i\n", err_tr);*/  
            break;  
        }  
    }  
    printf("Accessed %lu MB\n", iChunk*nX*sizeof(int)/(int)1e6);  
    nAccessed = iChunk;  
      
    for (iChunk=0; iChunk<nAccessed; iChunk++)  
      free(*(buffers_host+iChunk));  
    for (iChunk=0; iChunk<nChunk; iChunk++)  
      clReleaseMemObject(*(buffers_dev+iChunk));  
    free(buffers_host);  
    free(buffers_dev);  
    clReleaseCommandQueue(CmdQueue);  
    clReleaseContext(Context);  
      
    return 0;  
    }  


