<commit_before>/*
This file is part of cphVB and copyright (c) 2012 the cphVB team:
http://cphvb.bitbucket.org

cphVB is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as 
published by the Free Software Foundation, either version 3 
of the License, or (at your option) any later version.

cphVB 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 Lesser General Public License along with cphVB. 

If not, see <http://www.gnu.org/licenses/>.
*/

#include <cphvb.h>
#include "cphvb_ve_score.h"
#include <iostream>
#include <cphvb_mcache.h>

static cphvb_component *myself = NULL;
static cphvb_userfunc_impl reduce_impl = NULL;
static cphvb_intp reduce_impl_id = 0;
static cphvb_userfunc_impl random_impl = NULL;
static cphvb_intp random_impl_id = 0;
static cphvb_userfunc_impl matmul_impl = NULL;
static cphvb_intp matmul_impl_id = 0;
static cphvb_userfunc_impl lu_impl = NULL;
static cphvb_intp lu_impl_id = 0;
static cphvb_userfunc_impl fft_impl = NULL;
static cphvb_intp fft_impl_id = 0;
static cphvb_userfunc_impl fft2_impl = NULL;
static cphvb_intp fft2_impl_id = 0;

static cphvb_intp cphvb_ve_score_buffersizes = 0;
static computeloop* cphvb_ve_score_compute_loops = NULL;
static cphvb_tstate* cphvb_ve_score_tstates = NULL;

static cphvb_intp block_size = 1000;
static cphvb_intp bin_max = 25;

cphvb_error cphvb_ve_score_init(cphvb_component *self)
{
    myself = self;                              // Assign config container.

    char *env = getenv("CPHVB_VE_SCORE_BLOCKSIZE");   // Override block_size from environment-variable.
    if(env != NULL)
    {
        block_size = atoi(env);
    }
    if(block_size <= 0)                         // Verify it
    {
        fprintf(stderr, "CPHVB_VE_SCORE_BLOCKSIZE (%ld) should be greater than zero!\n", (long int)block_size);
        return CPHVB_ERROR;
    }
    //printf("[CPHVB_VE_SCORE_BLOCKSIZE=%ld]\n", block_size);
    //printf("[CPHVB_VE_SCORE_BINMAX=%ld]\n", bin_max);
    cphvb_mcache_init( 10 );
    return CPHVB_SUCCESS;
}

inline cphvb_error block_execute( cphvb_instruction* instr, cphvb_intp start, cphvb_intp end) {

    cphvb_intp i, k;

    //Make sure we have enough space
    if ((end - start + 1) > cphvb_ve_score_buffersizes) 
    {
    	cphvb_intp mcount = (end - start + 1);

    	// We only work in multiples of 1000
    	if (mcount % 1000 != 0)
    		mcount = (mcount + 1000) - (mcount % 1000);

    	// Make sure we re-allocate on error
    	cphvb_ve_score_buffersizes = 0;
    	
    	if (cphvb_ve_score_compute_loops != NULL) {
    		free(cphvb_ve_score_compute_loops);
    		free(cphvb_ve_score_tstates);
    		cphvb_ve_score_compute_loops = NULL;
    		cphvb_ve_score_tstates = NULL;
    	}
    	
    	cphvb_ve_score_compute_loops = (computeloop*)malloc(sizeof(computeloop) * mcount);
        cphvb_ve_score_tstates = (cphvb_tstate*)malloc(sizeof(cphvb_tstate)*mcount);
    	
    	if (cphvb_ve_score_compute_loops == NULL)
    		return CPHVB_OUT_OF_MEMORY;
    	if (cphvb_ve_score_tstates == NULL)
    		return CPHVB_OUT_OF_MEMORY;
    	
    	cphvb_ve_score_buffersizes = mcount;
    }
    
    computeloop* compute_loops = cphvb_ve_score_compute_loops;
    cphvb_tstate* states = cphvb_ve_score_tstates;
    cphvb_intp  nelements, trav_end=0;
    cphvb_error ret_errcode = CPHVB_SUCCESS;
    
    for(i=0; i<= (end-start);i++)                   // Reset traversal coordinates
        cphvb_tstate_reset( &states[i] );

    for(i=start, k=0; i <= end; i++,k++)            // Get the compute-loops
    {
        switch(instr[i].opcode) {                   // Ignore sys-ops
            case CPHVB_DISCARD:
            case CPHVB_FREE:
            case CPHVB_SYNC:
            case CPHVB_NONE:
            case CPHVB_USERFUNC:
                break;

            default:
                compute_loops[k] = cphvb_compute_get( &instr[i] );
                if(compute_loops[k] == NULL)
                {
                    end             = start + k - 1;
                    instr[i].status = CPHVB_TYPE_NOT_SUPPORTED;
                    ret_errcode     = CPHVB_PARTIAL_SUCCESS;
                    break;
                }
                else
                    instr[i].status = CPHVB_SUCCESS;
        }

    }
                                                    // Block-size split
    nelements = cphvb_nelements( instr[start].operand[0]->ndim, instr[start].operand[0]->shape );
    while(nelements>trav_end)
    {
        trav_end    += block_size;
        if (trav_end > nelements) {
            trav_end = nelements;
        }
        
        for(i=start, k=0; i <= end; i++, k++)
        {
            switch(instr[i].opcode) {                   // Ignore sys-ops
                case CPHVB_DISCARD:
                case CPHVB_FREE:
                case CPHVB_SYNC:
                case CPHVB_NONE:
                case CPHVB_USERFUNC:
                    break;

                default:
                    compute_loops[k]( &instr[i], &states[k], trav_end );
                    //compute_loops[k]( &instr[i], &states[k], 0 );
            }
        }
    }
    
    return ret_errcode;
}

cphvb_error cphvb_ve_score_execute( cphvb_intp instruction_count, cphvb_instruction* instruction_list )
{
    cphvb_intp cur_index,  j;
    cphvb_instruction *inst, *binst;

    cphvb_intp bin_start, bin_end, bin_size;
    cphvb_intp bundle_start, bundle_end, bundle_size;
    cphvb_error res;

    for(cur_index=0; cur_index < instruction_count; cur_index++)
    {
        inst = &instruction_list[cur_index];
    }

    for(cur_index=0; cur_index < instruction_count; cur_index++)
    {
        inst = &instruction_list[cur_index];

        if(inst->status == CPHVB_SUCCESS)       // SKIP instruction
        {
            continue;
        }

        res = cphvb_mcache_malloc( inst );      // Allocate memory for operands
        if ( res != CPHVB_SUCCESS ) {
            return res;
        }
        
        switch(inst->opcode)                    // Dispatch instruction
        {
            case CPHVB_NONE:                    // NOOP.
            case CPHVB_DISCARD:
            case CPHVB_SYNC:
                inst->status = CPHVB_SUCCESS;
                break;

            case CPHVB_FREE:                        // Store data-pointer in malloc-cache
                inst->status = cphvb_mcache_free( inst );
                break;

            case CPHVB_USERFUNC:                // External libraries

                if(inst->userfunc->id == reduce_impl_id)
                {
                    inst->status = reduce_impl(inst->userfunc, NULL);
                }
                else if(inst->userfunc->id == random_impl_id)
                {
                    inst->status = random_impl(inst->userfunc, NULL);
                }
                else if(inst->userfunc->id == matmul_impl_id)
                {
                    inst->status = matmul_impl(inst->userfunc, NULL);
                }
                else if(inst->userfunc->id == lu_impl_id)
                {
                    inst->status = lu_impl(inst->userfunc, NULL);
                }
                else if(inst->userfunc->id == fft_impl_id)
                {
                    inst->status = fft_impl(inst->userfunc, NULL);
                }
                else if(inst->userfunc->id == fft2_impl_id)
                {
                    inst->status = fft2_impl(inst->userfunc, NULL);
                }
                else                            // Unsupported userfunc
                {
                    inst->status = CPHVB_USERFUNC_NOT_SUPPORTED;
                }

                break;

            default:                                            // Built-in operations
                                                                // -={[ BINNING ]}=-
                bin_start   = cur_index;                        // Count built-ins and their start/end indexes and allocate memory for them.
                bin_end     = cur_index;
                bool has_sys = false;
                //for(j=bin_start+1; j<instruction_count; j++)    
                for(j=bin_start+1; (j<instruction_count) && (j<bin_start+1+bin_max); j++)
                {
                    binst = &instruction_list[j];               
                    
                    if (binst->opcode == CPHVB_USERFUNC) {      // Stop bundle, userfunc encountered.
                        break;
                    }
                                                                // Delay sys-op
                    if ((binst->opcode == CPHVB_NONE) || \
                        (binst->opcode == CPHVB_DISCARD) || \
                        (binst->opcode == CPHVB_SYNC) || \
                        (binst->opcode == CPHVB_FREE) ) {
                        has_sys = true;
                    }

                    bin_end++;                                  // The "end" index
                    res = cphvb_mcache_malloc( binst );         // Allocate memory for operands
                    if ( res != CPHVB_SUCCESS ) {
                        return res;
                    }

                }
                bin_size = bin_end - bin_start +1;              // The counting part

                                                                // -={[ BUNDLING ]}=-
                bundle_size     = (bin_size > 1) ? cphvb_inst_bundle( instruction_list, bin_start, bin_end ) : 1;
                bundle_start    = bin_start;
                bundle_end      = bundle_start + bundle_size-1;

                //printf("Bundle: %ld %ld -> %ld\n", bundle_size, bundle_start, bundle_end);
                if (bundle_size > 1) { 
                    //printf("Bundle: %ld %ld -> %ld\n", bundle_size, bundle_start, bundle_end);
                    //cphvb_pprint_bundle( &(instruction_list[bundle_start]), bundle_size);
                    block_execute( instruction_list, bundle_start, bundle_end );
                    if (has_sys) {
                        for(j=bundle_start; j <= bundle_end; j++) {
                            inst = &instruction_list[j];
                            switch(inst->opcode)                    // Dispatch instruction
                            {
                                case CPHVB_NONE:                    // NOOP.
                                case CPHVB_DISCARD:
                                case CPHVB_SYNC:
                                    inst->status = CPHVB_SUCCESS;
                                    break;

                                case CPHVB_FREE:                        // Store data-pointer in malloc-cache
                                    inst->status = cphvb_mcache_free( inst );
                                    break;

                                       
                            }
                        }
                    }

                } else {
                    inst = &instruction_list[bundle_start];
                    inst->status = cphvb_compute_apply( inst );
                }
                cur_index += bundle_size-1;

        }

        if (inst->status != CPHVB_SUCCESS)    // Instruction failed
        {
            break;
        }

    }

    if (cur_index == instruction_count) {
        return CPHVB_SUCCESS;
    } else {
        return CPHVB_PARTIAL_SUCCESS;
    }

}

cphvb_error cphvb_ve_score_shutdown( void )
{
    cphvb_mcache_clear();
    cphvb_mcache_delete();

    return CPHVB_SUCCESS;
}

cphvb_error cphvb_ve_score_reg_func(char *fun, cphvb_intp *id) {

    if(strcmp("cphvb_reduce", fun) == 0)
    {
    	if (reduce_impl == NULL)
    	{
			cphvb_component_get_func(myself, fun, &reduce_impl);
			if (reduce_impl == NULL)
				return CPHVB_USERFUNC_NOT_SUPPORTED;

			reduce_impl_id = *id;
			return CPHVB_SUCCESS;			
        }
        else
        {
        	*id = reduce_impl_id;
        	return CPHVB_SUCCESS;
        }
    }
    else if(strcmp("cphvb_random", fun) == 0)
    {
    	if (random_impl == NULL)
    	{
			cphvb_component_get_func(myself, fun, &random_impl);
			if (random_impl == NULL)
				return CPHVB_USERFUNC_NOT_SUPPORTED;

			random_impl_id = *id;
			return CPHVB_SUCCESS;			
        }
        else
        {
        	*id = random_impl_id;
        	return CPHVB_SUCCESS;
        }
    }
    else if(strcmp("cphvb_matmul", fun) == 0)
    {
    	if (matmul_impl == NULL)
    	{
			cphvb_component_get_func(myself, fun, &matmul_impl);
			if (matmul_impl == NULL)
				return CPHVB_USERFUNC_NOT_SUPPORTED;

			matmul_impl_id = *id;
			return CPHVB_SUCCESS;			
        }
        else
        {
        	*id = matmul_impl_id;
        	return CPHVB_SUCCESS;
        }
    }
    else if(strcmp("cphvb_lu", fun) == 0)
    {
    	if (lu_impl == NULL)
    	{
			cphvb_component_get_func(myself, fun, &lu_impl);
			if (lu_impl == NULL)
				return CPHVB_USERFUNC_NOT_SUPPORTED;

			lu_impl_id = *id;
			return CPHVB_SUCCESS;			
        }
        else
        {
        	*id = lu_impl_id;
        	return CPHVB_SUCCESS;
        }
    }
    else if(strcmp("cphvb_fft", fun) == 0)
    {
    	if (fft_impl == NULL)
    	{
			cphvb_component_get_func(myself, fun, &fft_impl);
			if (fft_impl == NULL)
				return CPHVB_USERFUNC_NOT_SUPPORTED;

			fft_impl_id = *id;
			return CPHVB_SUCCESS;			
        }
        else
        {
        	*id = fft_impl_id;
        	return CPHVB_SUCCESS;
        }
    }
    else if(strcmp("cphvb_fft2", fun) == 0)
    {
    	if (fft2_impl == NULL)
    	{
			cphvb_component_get_func(myself, fun, &fft2_impl);
			if (fft2_impl == NULL)
				return CPHVB_USERFUNC_NOT_SUPPORTED;

			fft2_impl_id = *id;
			return CPHVB_SUCCESS;			
        }
        else
        {
        	*id = fft2_impl_id;
        	return CPHVB_SUCCESS;
        }
    }
    
    return CPHVB_USERFUNC_NOT_SUPPORTED;
}

cphvb_error cphvb_reduce( cphvb_userfunc *arg, void* ve_arg)
{
    return cphvb_compute_reduce( arg, ve_arg );
}

cphvb_error cphvb_random( cphvb_userfunc *arg, void* ve_arg)
{
    return cphvb_compute_random( arg, ve_arg );
}

cphvb_error cphvb_matmul( cphvb_userfunc *arg, void* ve_arg)
{
    return cphvb_compute_matmul( arg, ve_arg );
    
}
<commit_msg>Added max_bin and mcache as environment vars to score.<commit_after>/*
This file is part of cphVB and copyright (c) 2012 the cphVB team:
http://cphvb.bitbucket.org

cphVB is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as 
published by the Free Software Foundation, either version 3 
of the License, or (at your option) any later version.

cphVB 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 Lesser General Public License along with cphVB. 

If not, see <http://www.gnu.org/licenses/>.
*/

#include <cphvb.h>
#include "cphvb_ve_score.h"
#include <iostream>
#include <cphvb_mcache.h>

static cphvb_component *myself = NULL;
static cphvb_userfunc_impl reduce_impl = NULL;
static cphvb_intp reduce_impl_id = 0;
static cphvb_userfunc_impl random_impl = NULL;
static cphvb_intp random_impl_id = 0;
static cphvb_userfunc_impl matmul_impl = NULL;
static cphvb_intp matmul_impl_id = 0;
static cphvb_userfunc_impl lu_impl = NULL;
static cphvb_intp lu_impl_id = 0;
static cphvb_userfunc_impl fft_impl = NULL;
static cphvb_intp fft_impl_id = 0;
static cphvb_userfunc_impl fft2_impl = NULL;
static cphvb_intp fft2_impl_id = 0;

static cphvb_intp cphvb_ve_score_buffersizes = 0;
static computeloop* cphvb_ve_score_compute_loops = NULL;
static cphvb_tstate* cphvb_ve_score_tstates = NULL;

static cphvb_intp block_size = 1000;
static cphvb_intp bin_max = 25;
static cphvb_intp mcache_size = 10;

cphvb_error cphvb_ve_score_init(cphvb_component *self)
{
    myself = self;                              // Assign config container.

    char *env = getenv("CPHVB_VE_SCORE_BLOCKSIZE");   // Override block_size from environment-variable.
    if(env != NULL)
    {
        block_size = atoi(env);
    }
    if(block_size <= 0)                         // Verify it
    {
        fprintf(stderr, "CPHVB_VE_SCORE_BLOCKSIZE (%ld) should be greater than zero!\n", (long int)block_size);
        return CPHVB_ERROR;
    }

    env = getenv("CPHVB_VE_SCORE_BINMAX");   // Override block_size from environment-variable.
    if(env != NULL)
    {
        bin_max = atoi(env);
    }
    if(bin_max <= 0)                         // Verify it
    {
        fprintf(stderr, "CPHVB_VE_SCORE_BINMAX (%ld) should be greater than zero!\n", (long int)bin_max);
        return CPHVB_ERROR;
    }

    env = getenv("CPHVB_CORE_MCACHE_SIZE");   // Override block_size from environment-variable.
    if(env != NULL)
    {
        mcache_size = atoi(env);
    }
    if(mcache_size <= 0)                         // Verify it
    {
        fprintf(stderr, "CPHVB_CORE_MCACHE_SIZE (%ld) should be greater than zero!\n", (long int)mcache_size);
        return CPHVB_ERROR;
    }
    //printf("[CPHVB_VE_SCORE_BLOCKSIZE=%ld]\n", block_size);
    //printf("[CPHVB_VE_SCORE_BINMAX=%ld]\n", bin_max);
    //printf("[CPHVB_CORE_MCACHE_SIZE=%ld]\n", mcache_size);
    cphvb_mcache_init( mcache_size );
    return CPHVB_SUCCESS;
}

inline cphvb_error block_execute( cphvb_instruction* instr, cphvb_intp start, cphvb_intp end) {

    cphvb_intp i, k;

    //Make sure we have enough space
    if ((end - start + 1) > cphvb_ve_score_buffersizes) 
    {
    	cphvb_intp mcount = (end - start + 1);

    	// We only work in multiples of 1000
    	if (mcount % 1000 != 0)
    		mcount = (mcount + 1000) - (mcount % 1000);

    	// Make sure we re-allocate on error
    	cphvb_ve_score_buffersizes = 0;
    	
    	if (cphvb_ve_score_compute_loops != NULL) {
    		free(cphvb_ve_score_compute_loops);
    		free(cphvb_ve_score_tstates);
    		cphvb_ve_score_compute_loops = NULL;
    		cphvb_ve_score_tstates = NULL;
    	}
    	
    	cphvb_ve_score_compute_loops = (computeloop*)malloc(sizeof(computeloop) * mcount);
        cphvb_ve_score_tstates = (cphvb_tstate*)malloc(sizeof(cphvb_tstate)*mcount);
    	
    	if (cphvb_ve_score_compute_loops == NULL)
    		return CPHVB_OUT_OF_MEMORY;
    	if (cphvb_ve_score_tstates == NULL)
    		return CPHVB_OUT_OF_MEMORY;
    	
    	cphvb_ve_score_buffersizes = mcount;
    }
    
    computeloop* compute_loops = cphvb_ve_score_compute_loops;
    cphvb_tstate* states = cphvb_ve_score_tstates;
    cphvb_intp  nelements, trav_end=0;
    cphvb_error ret_errcode = CPHVB_SUCCESS;
    
    for(i=0; i<= (end-start);i++)                   // Reset traversal coordinates
        cphvb_tstate_reset( &states[i] );

    for(i=start, k=0; i <= end; i++,k++)            // Get the compute-loops
    {
        switch(instr[i].opcode) {                   // Ignore sys-ops
            case CPHVB_DISCARD:
            case CPHVB_FREE:
            case CPHVB_SYNC:
            case CPHVB_NONE:
            case CPHVB_USERFUNC:
                break;

            default:
                compute_loops[k] = cphvb_compute_get( &instr[i] );
                if(compute_loops[k] == NULL)
                {
                    end             = start + k - 1;
                    instr[i].status = CPHVB_TYPE_NOT_SUPPORTED;
                    ret_errcode     = CPHVB_PARTIAL_SUCCESS;
                    break;
                }
                else
                    instr[i].status = CPHVB_SUCCESS;
        }

    }
                                                    // Block-size split
    nelements = cphvb_nelements( instr[start].operand[0]->ndim, instr[start].operand[0]->shape );
    while(nelements>trav_end)
    {
        trav_end    += block_size;
        if (trav_end > nelements) {
            trav_end = nelements;
        }
        
        for(i=start, k=0; i <= end; i++, k++)
        {
            switch(instr[i].opcode) {                   // Ignore sys-ops
                case CPHVB_DISCARD:
                case CPHVB_FREE:
                case CPHVB_SYNC:
                case CPHVB_NONE:
                case CPHVB_USERFUNC:
                    break;

                default:
                    compute_loops[k]( &instr[i], &states[k], trav_end );
                    //compute_loops[k]( &instr[i], &states[k], 0 );
            }
        }
    }
    
    return ret_errcode;
}

cphvb_error cphvb_ve_score_execute( cphvb_intp instruction_count, cphvb_instruction* instruction_list )
{
    cphvb_intp cur_index,  j;
    cphvb_instruction *inst, *binst;

    cphvb_intp bin_start, bin_end, bin_size;
    cphvb_intp bundle_start, bundle_end, bundle_size;
    cphvb_error res;

    for(cur_index=0; cur_index < instruction_count; cur_index++)
    {
        inst = &instruction_list[cur_index];
    }

    for(cur_index=0; cur_index < instruction_count; cur_index++)
    {
        inst = &instruction_list[cur_index];

        if(inst->status == CPHVB_SUCCESS)       // SKIP instruction
        {
            continue;
        }

        res = cphvb_mcache_malloc( inst );      // Allocate memory for operands
        if ( res != CPHVB_SUCCESS ) {
            return res;
        }
        
        switch(inst->opcode)                    // Dispatch instruction
        {
            case CPHVB_NONE:                    // NOOP.
            case CPHVB_DISCARD:
            case CPHVB_SYNC:
                inst->status = CPHVB_SUCCESS;
                break;

            case CPHVB_FREE:                        // Store data-pointer in malloc-cache
                inst->status = cphvb_mcache_free( inst );
                break;

            case CPHVB_USERFUNC:                // External libraries

                if(inst->userfunc->id == reduce_impl_id)
                {
                    inst->status = reduce_impl(inst->userfunc, NULL);
                }
                else if(inst->userfunc->id == random_impl_id)
                {
                    inst->status = random_impl(inst->userfunc, NULL);
                }
                else if(inst->userfunc->id == matmul_impl_id)
                {
                    inst->status = matmul_impl(inst->userfunc, NULL);
                }
                else if(inst->userfunc->id == lu_impl_id)
                {
                    inst->status = lu_impl(inst->userfunc, NULL);
                }
                else if(inst->userfunc->id == fft_impl_id)
                {
                    inst->status = fft_impl(inst->userfunc, NULL);
                }
                else if(inst->userfunc->id == fft2_impl_id)
                {
                    inst->status = fft2_impl(inst->userfunc, NULL);
                }
                else                            // Unsupported userfunc
                {
                    inst->status = CPHVB_USERFUNC_NOT_SUPPORTED;
                }

                break;

            default:                                            // Built-in operations
                                                                // -={[ BINNING ]}=-
                bin_start   = cur_index;                        // Count built-ins and their start/end indexes and allocate memory for them.
                bin_end     = cur_index;
                bool has_sys = false;
                //for(j=bin_start+1; j<instruction_count; j++)    
                for(j=bin_start+1; (j<instruction_count) && (j<bin_start+1+bin_max); j++)
                {
                    binst = &instruction_list[j];               
                    
                    if (binst->opcode == CPHVB_USERFUNC) {      // Stop bundle, userfunc encountered.
                        break;
                    }
                                                                // Delay sys-op
                    if ((binst->opcode == CPHVB_NONE) || \
                        (binst->opcode == CPHVB_DISCARD) || \
                        (binst->opcode == CPHVB_SYNC) || \
                        (binst->opcode == CPHVB_FREE) ) {
                        has_sys = true;
                    }

                    bin_end++;                                  // The "end" index
                    res = cphvb_mcache_malloc( binst );         // Allocate memory for operands
                    if ( res != CPHVB_SUCCESS ) {
                        return res;
                    }

                }
                bin_size = bin_end - bin_start +1;              // The counting part

                                                                // -={[ BUNDLING ]}=-
                bundle_size     = (bin_size > 1) ? cphvb_inst_bundle( instruction_list, bin_start, bin_end ) : 1;
                bundle_start    = bin_start;
                bundle_end      = bundle_start + bundle_size-1;

                //printf("Bundle: %ld %ld -> %ld\n", bundle_size, bundle_start, bundle_end);
                if (bundle_size > 1) { 
                    //printf("Bundle: %ld %ld -> %ld\n", bundle_size, bundle_start, bundle_end);
                    //cphvb_pprint_bundle( &(instruction_list[bundle_start]), bundle_size);
                    block_execute( instruction_list, bundle_start, bundle_end );
                    if (has_sys) {
                        for(j=bundle_start; j <= bundle_end; j++) {
                            inst = &instruction_list[j];
                            switch(inst->opcode)                    // Dispatch instruction
                            {
                                case CPHVB_NONE:                    // NOOP.
                                case CPHVB_DISCARD:
                                case CPHVB_SYNC:
                                    inst->status = CPHVB_SUCCESS;
                                    break;

                                case CPHVB_FREE:                        // Store data-pointer in malloc-cache
                                    inst->status = cphvb_mcache_free( inst );
                                    break;

                                       
                            }
                        }
                    }

                } else {
                    inst = &instruction_list[bundle_start];
                    inst->status = cphvb_compute_apply( inst );
                }
                cur_index += bundle_size-1;

        }

        if (inst->status != CPHVB_SUCCESS)    // Instruction failed
        {
            break;
        }

    }

    if (cur_index == instruction_count) {
        return CPHVB_SUCCESS;
    } else {
        return CPHVB_PARTIAL_SUCCESS;
    }

}

cphvb_error cphvb_ve_score_shutdown( void )
{
    cphvb_mcache_clear();
    cphvb_mcache_delete();

    return CPHVB_SUCCESS;
}

cphvb_error cphvb_ve_score_reg_func(char *fun, cphvb_intp *id) {

    if(strcmp("cphvb_reduce", fun) == 0)
    {
    	if (reduce_impl == NULL)
    	{
			cphvb_component_get_func(myself, fun, &reduce_impl);
			if (reduce_impl == NULL)
				return CPHVB_USERFUNC_NOT_SUPPORTED;

			reduce_impl_id = *id;
			return CPHVB_SUCCESS;			
        }
        else
        {
        	*id = reduce_impl_id;
        	return CPHVB_SUCCESS;
        }
    }
    else if(strcmp("cphvb_random", fun) == 0)
    {
    	if (random_impl == NULL)
    	{
			cphvb_component_get_func(myself, fun, &random_impl);
			if (random_impl == NULL)
				return CPHVB_USERFUNC_NOT_SUPPORTED;

			random_impl_id = *id;
			return CPHVB_SUCCESS;			
        }
        else
        {
        	*id = random_impl_id;
        	return CPHVB_SUCCESS;
        }
    }
    else if(strcmp("cphvb_matmul", fun) == 0)
    {
    	if (matmul_impl == NULL)
    	{
			cphvb_component_get_func(myself, fun, &matmul_impl);
			if (matmul_impl == NULL)
				return CPHVB_USERFUNC_NOT_SUPPORTED;

			matmul_impl_id = *id;
			return CPHVB_SUCCESS;			
        }
        else
        {
        	*id = matmul_impl_id;
        	return CPHVB_SUCCESS;
        }
    }
    else if(strcmp("cphvb_lu", fun) == 0)
    {
    	if (lu_impl == NULL)
    	{
			cphvb_component_get_func(myself, fun, &lu_impl);
			if (lu_impl == NULL)
				return CPHVB_USERFUNC_NOT_SUPPORTED;

			lu_impl_id = *id;
			return CPHVB_SUCCESS;			
        }
        else
        {
        	*id = lu_impl_id;
        	return CPHVB_SUCCESS;
        }
    }
    else if(strcmp("cphvb_fft", fun) == 0)
    {
    	if (fft_impl == NULL)
    	{
			cphvb_component_get_func(myself, fun, &fft_impl);
			if (fft_impl == NULL)
				return CPHVB_USERFUNC_NOT_SUPPORTED;

			fft_impl_id = *id;
			return CPHVB_SUCCESS;			
        }
        else
        {
        	*id = fft_impl_id;
        	return CPHVB_SUCCESS;
        }
    }
    else if(strcmp("cphvb_fft2", fun) == 0)
    {
    	if (fft2_impl == NULL)
    	{
			cphvb_component_get_func(myself, fun, &fft2_impl);
			if (fft2_impl == NULL)
				return CPHVB_USERFUNC_NOT_SUPPORTED;

			fft2_impl_id = *id;
			return CPHVB_SUCCESS;			
        }
        else
        {
        	*id = fft2_impl_id;
        	return CPHVB_SUCCESS;
        }
    }
    
    return CPHVB_USERFUNC_NOT_SUPPORTED;
}

cphvb_error cphvb_reduce( cphvb_userfunc *arg, void* ve_arg)
{
    return cphvb_compute_reduce( arg, ve_arg );
}

cphvb_error cphvb_random( cphvb_userfunc *arg, void* ve_arg)
{
    return cphvb_compute_random( arg, ve_arg );
}

cphvb_error cphvb_matmul( cphvb_userfunc *arg, void* ve_arg)
{
    return cphvb_compute_matmul( arg, ve_arg );
    
}

{'fraction_non_alphanumeric': 0.09078330127231615, 'fraction_numerical': 0.005197259626742263, 'mean_word_length': 1.5478933791917455, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 107, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 38, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6511300', 'n_tokens_mistral': 9896, 'n_tokens_neox': 9315, 'n_words': 1848}