From 69f2911e04ffb1b19eef1fafb8c040af271f656e Mon Sep 17 00:00:00 2001 From: Tor Aamodt Date: Thu, 15 Jul 2010 18:09:46 -0800 Subject: creating branch for adding support for CUDA 3.x and Fermi [git-p4: depot-paths = "//depot/gpgpu_sim_research/fermi/distribution/": change = 6829] --- benchmarks/CUDA/STO/storeCPU.c | 1114 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1114 insertions(+) create mode 100644 benchmarks/CUDA/STO/storeCPU.c (limited to 'benchmarks/CUDA/STO/storeCPU.c') diff --git a/benchmarks/CUDA/STO/storeCPU.c b/benchmarks/CUDA/STO/storeCPU.c new file mode 100644 index 0000000..09d1997 --- /dev/null +++ b/benchmarks/CUDA/STO/storeCPU.c @@ -0,0 +1,1114 @@ +/*========================================================================== + S T O R E C P U + +* Copyright (c) 2008, NetSysLab at the University of British Columbia +* All rights reserved. +* +* 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 the University 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 NetSysLab ``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 NetSysLab 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. + + +DESCRIPTION + CPU version of the storeGPU library. + + +==========================================================================*/ + +/*========================================================================== + + INCLUDES + +==========================================================================*/ +#include +#include +#include + + +#include "cust.h" +#include "md5_cpu.h" +#include "sha1_cpu.h" + + +#ifdef FEATURE_WIN32_THREADS +#include +#endif + +/*========================================================================== + + DATA DECLARATIONS + +==========================================================================*/ + +/*-------------------------------------------------------------------------- + TYPE DEFINITIONS +--------------------------------------------------------------------------*/ +// defines an execution context +typedef struct sc_exec_context { + int threads_per_block; + int blocks_per_grid; + int total_threads; + int total_size; + int chunk_size; + int pad_size; +} sc_exec_context_type; + +#ifdef FEATURE_WIN32_THREADS +typedef struct thread_data_struct { + + unsigned char *input; + unsigned char *output; + int ilen; + +} thread_data_type, *pt_thread_data_type; +#endif /* FEATURE_WIN32_THREADS */ + + +/*-------------------------------------------------------------------------- + FUNCTION PROTOTYPES +--------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + CONSTANTS +--------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + GLOBAL VARIABLES +--------------------------------------------------------------------------*/ + + +/*-------------------------------------------------------------------------- + MACROS +--------------------------------------------------------------------------*/ + +#define GET_REAL_CHUNK_SIZE(chunk_size) ((chunk_size) - 12) + +/*========================================================================== + + FUNCTIONS + +==========================================================================*/ + +/*-------------------------------------------------------------------------- + LOCAL FUNCTIONS +--------------------------------------------------------------------------*/ + +#ifdef FEATURE_DYNAMIC_EXEC_CONTEXT +#ifdef FEATURE_MAXIMIZE_NUM_OF_THREADS +/*=========================================================================== + +FUNCTION SC_GET_EXEC_CONTEXT + +DESCRIPTION + sets the execution context the algorithm will run within: chunk size, + thread per block, blocks, padding and total number of threads according + to client buffer size. + +DEPENDENCIES + None + +RETURN VALUE + execution context + +===========================================================================*/ +static void sc_get_exec_context(int size, sc_exec_context_type* ctx){ + + int threads_per_block; + int blocks_per_grid; + int total_threads; + int chunk_size; + int pad_size; + + int total_chunks = 0; + int found = 0; + int index = 1; + + + //**** Determine the execution context ****// + /* The algorithm will try to determine the context by minimizing chunk + * size and maximizing total number of threads + * TODO: May be we can do better here + */ + while ( !found ) { + // Set chunk size + chunk_size = GET_REAL_CHUNK_SIZE(BASIC_CHUNK_SIZE * index); + + if ( chunk_size > MAX_CHUNK_SIZE ) + break; + + // Calculate the required padding for this chunk size + pad_size = ((size % chunk_size) == 0) ? 0 : + chunk_size - (size % chunk_size); + + // total number of chunks required if we are going to use this chunk size + total_chunks = (pad_size == 0) ? size / chunk_size : + (size / chunk_size) + 1; + + if ( total_chunks <= MAX_NUM_OF_THREADS ) { + // Got it, this is the minimum chunk size we can use. Now determine the + // threads and blocks numbers. + total_threads = total_chunks; + + // Get block and grid sizes + if (total_chunks <= MAX_THREADS_PER_BLOCK ) { + threads_per_block = total_chunks; + blocks_per_grid = 1; + + } else { + threads_per_block = MAX_THREADS_PER_BLOCK; + blocks_per_grid = ((total_threads % threads_per_block) == 0) ? + (total_threads/threads_per_block) : + (total_threads/threads_per_block) + 1; + + } + + found = 1; + + } + index++; + + } + + + //**** Fill the struct with the solution ****// + ctx->threads_per_block = threads_per_block; + ctx->blocks_per_grid = blocks_per_grid; + ctx->total_threads = total_threads; + ctx->total_size = size + pad_size; + ctx->chunk_size = chunk_size; + ctx->pad_size = pad_size; + +} + +#else /* FEATURE_MAXIMIZE_NUM_OF_THREADS */ +/*=========================================================================== + +FUNCTION SC_GET_EXEC_CONTEXT + +DESCRIPTION + sets the required chunk size, thread per block and number of blocks + needed for kernel execution according to client buffer size. + +DEPENDENCIES + None + +RETURN VALUE + execution context + +===========================================================================*/ +static void sc_get_exec_context(int size, sc_exec_context_type* ctx){ + + int threads_per_block; + int blocks_per_grid; + int total_threads; + int chunk_size; + int pad_size; + + int total_chunks = 0; + int found = 0; + + int index = MAX_CHUNK_SIZE / BASIC_CHUNK_SIZE; + + + + //**** Determine the execution context ****// + /* The algorithm will try to determine the context by minimizing chunk + * size and maximizing total number of threads + * TODO: May be we can do better here + */ + while ( 1 ) { + // Set chunk size + chunk_size = GET_REAL_CHUNK_SIZE(BASIC_CHUNK_SIZE * index); + + // don't go less than minimum chunk size + if ( chunk_size < BASIC_CHUNK_SIZE ) + break; + + // Calculate the required padding for this chunk size + pad_size = ((size % chunk_size) == 0) ? 0 : + chunk_size - (size % chunk_size); + + // total number of chunks required if we are going to use this chunk size + total_chunks = (pad_size == 0) ? size / chunk_size : + (size / chunk_size) + 1; + + + // don't go beyond the maximum number of threads or maximum global memory + // TODO: it seems that the kernel breaks way before reaching the maximum + // global memory size (around 94MByte input plus the required + // scratch space) + if (total_chunks > MAX_NUM_OF_THREADS) + break; + + // each thread will take care of one chunk + total_threads = total_chunks; + + + // Get block and grid sizes + if (total_chunks <= MAX_THREADS_PER_BLOCK ) { + threads_per_block = total_chunks; + blocks_per_grid = 1; + + } else { + threads_per_block = MAX_THREADS_PER_BLOCK; + blocks_per_grid = ((total_threads % threads_per_block) == 0) ? + (total_threads/threads_per_block) : + (total_threads/threads_per_block) + 1; + + } + found = 1; + + if( total_threads > NUM_OF_MULTIPROCESSORS * 32) + break; + + index--; + + } + + + //**** Fill the struct with the solution ****// + ctx->threads_per_block = threads_per_block; + ctx->blocks_per_grid = blocks_per_grid; + ctx->total_threads = total_threads; + ctx->total_size = size + pad_size; + ctx->chunk_size = chunk_size; + ctx->pad_size = pad_size; + +} +#endif /* FEATURE_MAXIMIZE_NUM_OF_THREADS */ + + +/*=========================================================================== + +FUNCTION SC_GET_OVERLAP_EXEC_CONTEXT + +DESCRIPTION + sets the required chunk size, thread per block and number of blocks + needed for kernel execution according to client buffer size, offset + and block size. + +DEPENDENCIES + None + +RETURN VALUE + execution context + +===========================================================================*/ +static void sc_get_overlap_exec_context( int size, int offset, + int block_size, + sc_exec_context_type* ctx ) { + + int threads_per_block; + int blocks_per_grid; + int total_threads; + int total_size; + int pad_size; + + + //**** Get the total number of threads required ****// + total_threads = (size + offset - block_size) / offset; + total_threads = ((size + offset - block_size) % offset) != 0 ? + total_threads + 1 : total_threads; + + + //**** Get the required padding for the last block ****// + pad_size = ((total_threads - 1) * offset + block_size) - size; + + + //**** threads and blocks ****// + if( total_threads > MAX_THREADS_PER_BLOCK ) { + + threads_per_block = MAX_THREADS_PER_BLOCK; + blocks_per_grid = (total_threads % MAX_THREADS_PER_BLOCK) == 0 ? + (total_threads / MAX_THREADS_PER_BLOCK) : + (total_threads / MAX_THREADS_PER_BLOCK) + 1; + } else { + + threads_per_block = total_threads; + blocks_per_grid = 1; + } + + total_size = size + pad_size; + + + //**** Fill the struct with the solution ****// + ctx->threads_per_block = threads_per_block; + ctx->blocks_per_grid = blocks_per_grid; + ctx->total_threads = total_threads; + ctx->total_size = total_size; + ctx->chunk_size = block_size; + ctx->pad_size = pad_size; + +} +#endif /* FEATURE_DYNAMIC_EXEC_CONTEXT */ + +/*=========================================================================== + +FUNCTION SC_PRINT_EXEC_CONTEXT + +DESCRIPTION + Prints out the passed execution context structure + +DEPENDENCIES + None + +RETURN VALUE + None + +===========================================================================*/ +static void sc_print_exec_context( sc_exec_context_type* ctx ) { + printf("\n== CPU Execution Context ==\n"); + printf("Threads : %d\n", ctx->threads_per_block); + printf("Blocks : %d\n", ctx->blocks_per_grid); + printf("Total Threads : %d\n", ctx->total_threads); + printf("Total Size : %d\n", ctx->total_size); + printf("Chunk Size : %d\n", ctx->chunk_size); + printf("Padding : %d\n\n", ctx->pad_size); +} + +#ifdef FEATURE_WIN32_THREADS +/*=========================================================================== + +FUNCTION MD5_CPU_MT + +DESCRIPTION + The multithread CPU implementation of the MD5 algorithm + +DEPENDENCIES + None + +RETURN VALUE + Hash + +===========================================================================*/ +static DWORD WINAPI md5_cpu_mt( LPVOID data ){ + + pt_thread_data_type thread_data; + + //cast to the correct data type + thread_data = (pt_thread_data_type)data; + + md5_cpu_internal(thread_data->input, thread_data->ilen, thread_data->output); + + return 0; +} + + +/*=========================================================================== + +FUNCTION MD5_CPU_MT + +DESCRIPTION + The multithread CPU implementation of the MD5 algorithm + +DEPENDENCIES + None + +RETURN VALUE + Hash + +===========================================================================*/ +static DWORD WINAPI sha1_cpu_mt( LPVOID data ){ + + pt_thread_data_type thread_data; + + //cast to the correct data type + thread_data = (pt_thread_data_type)data; + + sha1_cpu_internal(thread_data->input, thread_data->ilen, thread_data->output); + + return 0; +} +#endif /* FEATURE_WIN32_THREADS */ + + +/*-------------------------------------------------------------------------- + GLOBAL FUNCTIONS +--------------------------------------------------------------------------*/ +/*=========================================================================== + +FUNCTION SC_MD5_STANDARD + +DESCRIPTION + The standard MD5 algorithm + +DEPENDENCIES + None + +RETURN VALUE + Hash + +===========================================================================*/ +void sc_md5_standard( unsigned char* buffer, int size, unsigned char** output) { + + unsigned char * result; + + result = (unsigned char*)malloc( MD5_HASH_SIZE ); + + md5_cpu_internal( buffer, size, result ); + + *output = result; +} + +/*=========================================================================== + +FUNCTION SC_SHA1_STANDARD + +DESCRIPTION + The standard SHA1 algorithm + +DEPENDENCIES + None + +RETURN VALUE + Hash + +===========================================================================*/ +void sc_sha1_standard(unsigned char* buffer, int size, unsigned char** output) { + + unsigned char * result; + + result = (unsigned char*)malloc( SHA1_HASH_SIZE ); + + sha1_cpu_internal( buffer, size, result ); + + *output = result; + +} + +/*=========================================================================== + +FUNCTION SC_MD5 + +DESCRIPTION + CPU version of the MD5 algorithm + +DEPENDENCIES + None + +RETURN VALUE + Hash + +===========================================================================*/ +void sc_md5( unsigned char* buffer, int size, + unsigned char** output, int* output_size) { + + + //**** Variable Declarations ****// + sc_exec_context_type exec_context; + unsigned char* scratch_data; + int chunk_index; + int hash_index; + int k; + +#ifdef FEATURE_WIN32_THREADS + + /* This structure contains the input for a particular thread */ + pt_thread_data_type thread_data; + + /* Thread identifiers */ + DWORD *thread_id; + + /* Thread handlers */ + HANDLE *thread_handle; + +#endif /* FEATURE_WIN32_THREADS */ + +#ifdef FEATURE_DYNAMIC_EXEC_CONTEXT + //**** Calculate pad size and needed block and grid sizes ****// + sc_get_exec_context(size, &exec_context); +#else + //**** Fill the execution context structure ****// + exec_context.threads_per_block = THREADS_PER_BLOCK; + exec_context.blocks_per_grid = BLOCKS_PER_GRID; + exec_context.chunk_size = CHUNK_SIZE; + exec_context.total_size = size; + exec_context.total_threads = TOTAL_NUM_OF_THREADS; + exec_context.pad_size = 0; + +#endif /* FEATURE_DYNAMIC_EXEC_CONTEXT */ + + sc_print_exec_context( &exec_context ); + + scratch_data = (unsigned char *)malloc(MD5_HASH_SIZE * exec_context.total_threads); + +#ifdef FEATURE_WIN32_THREADS + + //allocate memory for the thread ids + thread_id = (DWORD *)malloc(sizeof(DWORD)*exec_context.total_threads - 1); + + //allocate memory for the thread handle + thread_handle = (HANDLE *)malloc(sizeof(HANDLE)*exec_context.total_threads-1); + + //create structures for thread ids + for( k = 0; k < exec_context.total_threads-1; k++ ) { + + // set indices + chunk_index = k * exec_context.chunk_size; + hash_index = k * MD5_HASH_SIZE; + + // Allocate memory for thread data. + // thread_data_type is a type that contains the input and output buffers + // wrapped up into a structure + // this is used by the thread to compute and store the hashed values. + thread_data = (pt_thread_data_type) HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(thread_data_type)); + + // In case something wrong happen. That is: if memory cannot be + // allocated in the Heap of the current process. + if( thread_data == NULL ) { + fprintf(stderr,"\n[FATAL ERROR] Unable to allocate memory in the heap for Thread[%d]",k); + ExitProcess(2); + } + + // Generate unique data for each thread. + thread_data->input = buffer + chunk_index; + thread_data->ilen = exec_context.chunk_size; + thread_data->output = scratch_data + hash_index; + + // Create a thread + thread_handle[k] = CreateThread(NULL, 0, md5_cpu_mt, thread_data, + 0, &thread_id[k]); + + int i; + + // Check whether the thread was created correctly. If it was not, close the + // handlers and release memory + if (thread_handle[k] == NULL) { + + fprintf(stderr,"\n[FATAL ERROR] Unable to spawn thread[%d].\n\t Releasing resources and saying goodbye!\n",k); + + for( i=0; i < exec_context.total_threads-1; i++) { + + if ( thread_handle[i] != NULL ) { + CloseHandle(thread_handle[i]); + } + } + + HeapFree(GetProcessHeap(), 0, thread_data); + + ExitProcess(k); + } + } + + // wait for each thread to finish + WaitForMultipleObjects(exec_context.total_threads-1, thread_handle, + TRUE, INFINITE); + + // Close all thread handles and free memory allocation. + for(k=0; k < exec_context.total_threads-1; k++) { + CloseHandle(thread_handle[k]); + } + + HeapFree(GetProcessHeap(), 0, thread_data); + +#else + + for( k = 0; k < exec_context.total_threads - 1; k++) { + chunk_index = k * exec_context.chunk_size; + hash_index = k * MD5_HASH_SIZE; + md5_cpu_internal(buffer + chunk_index, exec_context.chunk_size, + scratch_data + hash_index ); + } +#endif /* FEATURE_WIN32_THREADS */ + + chunk_index = k * exec_context.chunk_size; + hash_index = k * MD5_HASH_SIZE; + + if(exec_context.pad_size != 0) { + + unsigned char *last_chunk = (unsigned char*)malloc(exec_context.chunk_size); + + memset(last_chunk, 0, exec_context.chunk_size); + memcpy(last_chunk, buffer + chunk_index, + exec_context.chunk_size - exec_context.pad_size); + md5_cpu_internal(last_chunk, exec_context.chunk_size, + scratch_data + hash_index ); + } else { + + md5_cpu_internal(buffer + chunk_index, exec_context.chunk_size, + scratch_data + hash_index ); + } + + //**** will do the last hshing stage ****// + sc_md5_standard( scratch_data, MD5_HASH_SIZE * exec_context.total_threads, + output ); + + *output_size = MD5_HASH_SIZE; + +} + +/*=========================================================================== + +FUNCTION SC_MD5_OVERLAP + +DESCRIPTION + Returns the MD5 hash of each block for the provided buffer + +DEPENDENCIES + None + +RETURN VALUE + Hash value + +===========================================================================*/ +void sc_md5_overlap(unsigned char* buffer, int size, int block_size, + int offset, unsigned char** output, int* output_size) { + + //**** Variable Declarations ****// + sc_exec_context_type exec_context; + unsigned char* result; + int chunk_index; + int hash_index; + int k; + +#ifdef FEATURE_WIN32_THREADS + + /* This structure contains the input for a particular thread */ + pt_thread_data_type thread_data; + + /* Thread identifiers */ + DWORD *thread_id; + + /* Thread handlers */ + HANDLE *thread_handle; + +#endif /* FEATURE_WIN32_THREADS */ + +#ifdef FEATURE_DYNAMIC_EXEC_CONTEXT + //**** Calculate pad size and needed block and grid sizes ****// + sc_get_overlap_exec_context(size, offset, block_size, &exec_context); +#else + //**** Fill the execution context structure ****// + exec_context.threads_per_block = THREADS_PER_BLOCK; + exec_context.blocks_per_grid = BLOCKS_PER_GRID; + exec_context.chunk_size = CHUNK_SIZE; + exec_context.total_size = size; + exec_context.total_threads = TOTAL_NUM_OF_THREADS; + exec_context.pad_size = 0; +#endif /* FEATURE_DYNAMIC_EXEC_CONTEXT */ + + sc_print_exec_context( &exec_context ); + + result = (unsigned char*)malloc(MD5_HASH_SIZE * exec_context.total_threads); + +#ifdef FEATURE_WIN32_THREADS + + int i; + + //allocate memory for the thread ids + thread_id = (DWORD *)malloc(sizeof(DWORD)*exec_context.total_threads-1); + + //allocate memory for the thread handle + thread_handle = (HANDLE *)malloc(sizeof(HANDLE)*exec_context.total_threads-1); + + //create structures for thread ids + for( k = 0; k < exec_context.total_threads-1; k++ ) { + + // set indices + chunk_index = k * offset; + hash_index = k * MD5_HASH_SIZE; + + // Allocate memory for thread data. + // thread_data_type is a type that contains the input and output buffers + // wrapped up into a structure + // this is used by the thread to compute and store the hashed values. + thread_data = (pt_thread_data_type) HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(thread_data_type)); + + // In case something wrong happen. That is: if memory cannot be + // allocated in the Heap of the current process. + if( thread_data == NULL ) { + fprintf(stderr,"\n[FATAL ERROR] Unable to allocate memory in the heap for Thread[%d]",k); + ExitProcess(2); + } + + // Generate unique data for each thread. + thread_data->input = buffer + chunk_index; + thread_data->ilen = block_size; + thread_data->output = result + hash_index; + + // Create a thread + thread_handle[k] = CreateThread(NULL, 0, md5_cpu_mt, thread_data, + 0, &thread_id[k]); + + // Check whether the thread was created correctly. If it was not, close the + // handlers and release memory + if (thread_handle[k] == NULL) { + + fprintf(stderr,"\n[FATAL ERROR] Unable to spawn thread[%d].\n\t Releasing resources and saying goodbye!\n",k); + + for( i=0; i < exec_context.total_threads-1; i++) { + + if ( thread_handle[i] != NULL ) { + CloseHandle(thread_handle[i]); + } + } + + HeapFree(GetProcessHeap(), 0, thread_data); + + ExitProcess(k); + } + } + + // wait for each thread to finish + WaitForMultipleObjects(exec_context.total_threads-1, thread_handle, + TRUE, INFINITE); + + // Close all thread handles and free memory allocation. + for(k=0; k < exec_context.total_threads-1; k++) { + CloseHandle(thread_handle[k]); + } + + HeapFree(GetProcessHeap(), 0, thread_data); + +#else + + for(k = 0 ; k < exec_context.total_threads - 1; k++) { + chunk_index = k * offset; + hash_index = k * MD5_HASH_SIZE; + md5_cpu_internal(buffer + chunk_index, block_size, result + hash_index ); + } + +#endif /* FEATURE_WIN32_THREADS */ + + chunk_index = k * offset; + hash_index = k * MD5_HASH_SIZE; + md5_cpu_internal(buffer + chunk_index, block_size - exec_context.pad_size, + result + hash_index ); + + + *output = result; + *output_size = MD5_HASH_SIZE * exec_context.total_threads; + +} + +/*=========================================================================== + +FUNCTION SC_SHA1 + +DESCRIPTION + CPU version of the SHA1 algorithm + +DEPENDENCIES + None + +RETURN VALUE + Hash + +===========================================================================*/ +void sc_sha1( unsigned char* buffer, int size, + unsigned char** output, int* output_size) { + + //**** Variable Declarations ****// + sc_exec_context_type exec_context; + unsigned char* scratch_data; + int chunk_index; + int hash_index; + int k; + +#ifdef FEATURE_WIN32_THREADS + + /* This structure contains the input for a particular thread */ + pt_thread_data_type thread_data; + + /* Thread identifiers */ + DWORD *thread_id; + + /* Thread handlers */ + HANDLE *thread_handle; + +#endif /* FEATURE_WIN32_THREADS */ + +#ifdef FEATURE_DYNAMIC_EXEC_CONTEXT + //**** Calculate pad size and needed block and grid sizes ****// + sc_get_exec_context(size, &exec_context); +#else + //**** Fill the execution context structure ****// + exec_context.threads_per_block = THREADS_PER_BLOCK; + exec_context.blocks_per_grid = BLOCKS_PER_GRID; + exec_context.chunk_size = CHUNK_SIZE; + exec_context.total_size = size; + exec_context.total_threads = TOTAL_NUM_OF_THREADS; + exec_context.pad_size = 0; +#endif /* FEATURE_DYNAMIC_EXEC_CONTEXT */ + + sc_print_exec_context( &exec_context ); + + scratch_data = (unsigned char*)malloc(SHA1_HASH_SIZE * exec_context.total_threads); + +#ifdef FEATURE_WIN32_THREADS + + int i; + + //allocate memory for the thread ids + thread_id = (DWORD *)malloc(sizeof(DWORD)*exec_context.total_threads-1); + + //allocate memory for the thread handle + thread_handle = (HANDLE *)malloc(sizeof(HANDLE)*exec_context.total_threads-1); + + //create structures for thread ids + for( k = 0; k < exec_context.total_threads-1; k++ ) { + + // set indices + chunk_index = k * exec_context.chunk_size; + hash_index = k * SHA1_HASH_SIZE; + + // Allocate memory for thread data. + // thread_data_type is a type that contains the input and output buffers + // wrapped up into a structure + // this is used by the thread to compute and store the hashed values. + thread_data = (pt_thread_data_type) HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(thread_data_type)); + + // In case something wrong happen. That is: if memory cannot be + // allocated in the Heap of the current process. + if( thread_data == NULL ) { + fprintf(stderr,"\n[FATAL ERROR] Unable to allocate memory in the heap for Thread[%d]",k); + ExitProcess(2); + } + + // Generate unique data for each thread. + thread_data->input = buffer + chunk_index; + thread_data->ilen = exec_context.chunk_size; + thread_data->output = scratch_data + hash_index; + + // Create a thread + thread_handle[k] = CreateThread(NULL, 0, sha1_cpu_mt, thread_data, + 0, &thread_id[k]); + + // Check whether the thread was created correctly. If it was not, close the + // handlers and release memory + if (thread_handle[k] == NULL) { + + fprintf(stderr,"\n[FATAL ERROR] Unable to spawn thread[%d].\n\t Releasing resources and saying goodbye!\n",k); + + for( i=0; i < exec_context.total_threads-1; i++) { + + if ( thread_handle[i] != NULL ) { + CloseHandle(thread_handle[i]); + } + } + + HeapFree(GetProcessHeap(), 0, thread_data); + + ExitProcess(k); + } + } + + // wait for each thread to finish + WaitForMultipleObjects(exec_context.total_threads-1, thread_handle, + TRUE, INFINITE); + + // Close all thread handles and free memory allocation. + for(k=0; k < exec_context.total_threads-1; k++) { + CloseHandle(thread_handle[k]); + } + + HeapFree(GetProcessHeap(), 0, thread_data); + +#else + + for( k = 0; k < exec_context.total_threads - 1; k++) { + chunk_index = k * exec_context.chunk_size; + hash_index = k * SHA1_HASH_SIZE; + sha1_cpu_internal(buffer + chunk_index, exec_context.chunk_size, + scratch_data + hash_index ); + } + +#endif /* FEATURE_WIN32_THREADS */ + + chunk_index = k * exec_context.chunk_size; + hash_index = k * SHA1_HASH_SIZE; + + if(exec_context.pad_size != 0) { + + unsigned char *last_chunk = (unsigned char*)malloc(exec_context.chunk_size); + + memset(last_chunk, 0, exec_context.chunk_size); + memcpy(last_chunk, buffer + chunk_index, + exec_context.chunk_size - exec_context.pad_size); + sha1_cpu_internal(last_chunk, exec_context.chunk_size, + scratch_data + hash_index ); + } else { + + sha1_cpu_internal(buffer + chunk_index, exec_context.chunk_size, + scratch_data + hash_index ); + } + + //**** will do the last hshing stage ****// + sc_sha1_standard( scratch_data, SHA1_HASH_SIZE * exec_context.total_threads, + output ); + + *output_size = SHA1_HASH_SIZE; + +} + +/*=========================================================================== + +FUNCTION SC_SHA1_OVERLAP + +DESCRIPTION + CPU version of the SHA1 overlap algorithm + +DEPENDENCIES + None + +RETURN VALUE + Hash + +===========================================================================*/ +void sc_sha1_overlap(unsigned char* buffer, int size, int block_size, + int offset, unsigned char** output, int* output_size) { + + //**** Variable Declarations ****// + sc_exec_context_type exec_context; + unsigned char* result; + int chunk_index; + int hash_index; + int k; + +#ifdef FEATURE_WIN32_THREADS + + /* This structure contains the input for a particular thread */ + pt_thread_data_type thread_data; + + /* Thread identifiers */ + DWORD *thread_id; + + /* Thread handlers */ + HANDLE *thread_handle; + +#endif /* FEATURE_WIN32_THREADS */ + +#ifdef FEATURE_DYNAMIC_EXEC_CONTEXT + + //**** Calculate pad size and needed block and grid sizes ****// + sc_get_overlap_exec_context(size, offset, block_size, &exec_context); + +#else + //**** Fill the execution context structure ****// + exec_context.threads_per_block = THREADS_PER_BLOCK; + exec_context.blocks_per_grid = BLOCKS_PER_GRID; + exec_context.chunk_size = CHUNK_SIZE; + exec_context.total_size = size; + exec_context.total_threads = TOTAL_NUM_OF_THREADS; + exec_context.pad_size = 0; +#endif /* FEATURE_DYNAMIC_EXEC_CONTEXT */ + + sc_print_exec_context( &exec_context ); + + result = (unsigned char*)malloc(SHA1_HASH_SIZE * exec_context.total_threads); + +#ifdef FEATURE_WIN32_THREADS + + int i; + + //allocate memory for the thread ids + thread_id = (DWORD *)malloc(sizeof(DWORD)*exec_context.total_threads-1); + + //allocate memory for the thread handle + thread_handle = (HANDLE *)malloc(sizeof(HANDLE)*exec_context.total_threads-1); + + //create structures for thread ids + for( k = 0; k < exec_context.total_threads-1; k++ ) { + + // set indices + chunk_index = k * offset; + hash_index = k * SHA1_HASH_SIZE; + + // Allocate memory for thread data. + // thread_data_type is a type that contains the input and output buffers + // wrapped up into a structure + // this is used by the thread to compute and store the hashed values. + thread_data = (pt_thread_data_type) HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + sizeof(thread_data_type)); + + // In case something wrong happen. That is: if memory cannot be + // allocated in the Heap of the current process. + if( thread_data == NULL ) { + fprintf(stderr,"\n[FATAL ERROR] Unable to allocate memory in the heap for Thread[%d]",k); + ExitProcess(2); + } + + // Generate unique data for each thread. + thread_data->input = buffer + chunk_index; + thread_data->ilen = block_size; + thread_data->output = result + hash_index; + + // Create a thread + thread_handle[k] = CreateThread(NULL, 0, sha1_cpu_mt, thread_data, + 0, &thread_id[k]); + + // Check whether the thread was created correctly. If it was not, close the + // handlers and release memory + if (thread_handle[k] == NULL) { + + fprintf(stderr,"\n[FATAL ERROR] Unable to spawn thread[%d].\n\t Releasing resources and saying goodbye!\n",k); + + for( i=0; i < exec_context.total_threads-1; i++) { + + if ( thread_handle[i] != NULL ) { + CloseHandle(thread_handle[i]); + } + } + + HeapFree(GetProcessHeap(), 0, thread_data); + + ExitProcess(k); + } + } + + // wait for each thread to finish + WaitForMultipleObjects(exec_context.total_threads-1, thread_handle, + TRUE, INFINITE); + + // Close all thread handles and free memory allocation. + for(k=0; k < exec_context.total_threads-1; k++) { + CloseHandle(thread_handle[k]); + } + + HeapFree(GetProcessHeap(), 0, thread_data); + +#else + + for(k = 0 ; k < exec_context.total_threads - 1; k++) { + chunk_index = k * offset; + hash_index = k * SHA1_HASH_SIZE; + sha1_cpu_internal(buffer + chunk_index, block_size, result + hash_index ); + } + +#endif /* FEATURE_WIN32_THREADS */ + + chunk_index = k * offset; + hash_index = k * SHA1_HASH_SIZE; + sha1_cpu_internal(buffer + chunk_index, block_size - exec_context.pad_size, + result + hash_index ); + + + *output = result; + *output_size = SHA1_HASH_SIZE * exec_context.total_threads; + +} -- cgit v1.3