//*************************************************************************************** // Functions for handling Atomic Increment Registers (AIR). //*************************************************************************************** // // Copyright 2012, Chair for Operating Systems, RWTH Aachen University // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "iRCCE_lib.h" #ifdef AIR //-------------------------------------------------------------------------------------- // FUNCTION: iRCCE_atomic_alloc //-------------------------------------------------------------------------------------- // Allocates a new AIR register; returns iRCCE_ERRO if all AIRs are already allocated //-------------------------------------------------------------------------------------- int iRCCE_atomic_alloc(iRCCE_AIR** reg) { if(iRCCE_atomic_alloc_counter < 2 * RCCE_NP) { int next_reg = RC_COREID[iRCCE_atomic_alloc_counter]; if(iRCCE_atomic_alloc_counter > RCCE_NP) next_reg += RCCE_MAXNP; (*reg) = &iRCCE_atomic_inc_regs[next_reg]; #ifdef _OPENMP #pragma omp master { iRCCE_atomic_alloc_counter++; } #pragma omp barrier #else iRCCE_atomic_alloc_counter++; #endif iRCCE_atomic_write((*reg), 0); return iRCCE_SUCCESS; } else { return iRCCE_ERROR; } } //-------------------------------------------------------------------------------------- // FUNCTION: iRCCE_atomic_inc //-------------------------------------------------------------------------------------- // Increments an AIR register and returns its privious content //-------------------------------------------------------------------------------------- int iRCCE_atomic_inc(iRCCE_AIR* reg, int* value) { int _value; if(value == NULL) value = &value; #ifndef _OPENMP (*value) = (*reg->counter); #else #pragma omp critical { (*value) = reg->counter; reg->counter++; reg->init = reg->counter; } #endif return iRCCE_SUCCESS; } //-------------------------------------------------------------------------------------- // FUNCTION: iRCCE_atomic_read //-------------------------------------------------------------------------------------- // Returns the current value of an AIR register //-------------------------------------------------------------------------------------- int iRCCE_atomic_read(iRCCE_AIR* reg, int* value) { #ifndef _OPENMP (*value) = (*reg->init); #else #pragma omp critical { (*value) =reg->init; } #endif return iRCCE_SUCCESS; } //-------------------------------------------------------------------------------------- // FUNCTION: iRCCE_atomic_write //-------------------------------------------------------------------------------------- // Initializes an AIR register by writing a start value //-------------------------------------------------------------------------------------- int iRCCE_atomic_write(iRCCE_AIR* reg, int value) { #ifndef _OPENMP (*reg->init) = value; #else #pragma omp critical { reg->init = value; reg->counter = value; } #endif return iRCCE_SUCCESS; } //-------------------------------------------------------------------------------------- // FUNCTION: iRCCE_barrier //-------------------------------------------------------------------------------------- // A barrier version based on the Atomic Increment Registers (AIR); if AIRs are not // supported, the function makes a fall-back to the common RCCE_barrier(). //-------------------------------------------------------------------------------------- static void RC_wait(int wait) { #ifndef _OPENMP asm volatile( "movl %%eax,%%ecx\n\t" "test:nop\n\t" "loop test" : /* no output registers */ : "a" (wait) : "%ecx" ); #endif return; } static int idx = 0; static unsigned int rnd = 0; #ifdef _OPENMP #pragma omp threadprivate (idx, rnd) #endif int iRCCE_barrier(RCCE_COMM *comm) { int backoff = BACKOFF_MIN, wait, i = 0; int counter; if(comm == NULL) comm = &RCCE_COMM_WORLD; if (comm == &RCCE_COMM_WORLD) { iRCCE_atomic_inc(iRCCE_atomic_barrier[idx], &counter); if (counter < (comm->size-1)) { iRCCE_atomic_read(iRCCE_atomic_barrier[idx], &counter); while (counter > 0) { rnd = rnd * 1103515245u + 12345u; wait = BACKOFF_MIN + (rnd % (backoff << i)); RC_wait(wait); if (wait < BACKOFF_MAX) i++; iRCCE_atomic_read(iRCCE_atomic_barrier[idx], &counter); } } else { iRCCE_atomic_write(iRCCE_atomic_barrier[idx], 0); } idx = !idx; return(RCCE_SUCCESS); } else { return RCCE_barrier(comm); } } #else // !AIR int iRCCE_barrier(RCCE_COMM *comm) { if(comm == NULL) return RCCE_barrier(&RCCE_COMM_WORLD); else return RCCE_barrier(comm); } #endif // !AIR