Beispiel #1
0
void concurrent_vector_base::internal_grow( const size_type start, size_type finish, size_type element_size, internal_array_op1 init ) {
    __TBB_ASSERT( start<finish, "start must be less than finish" );
    size_t tmp = start;
    do {
        segment_index_t k_old = segment_index_of( tmp );
        size_type base = segment_base(k_old);
        size_t n = segment_size(k_old);
        helper::extend_segment_if_necessary(*this,k_old);
        segment_t& s = my_segment[k_old];
        void* array = s.array;
        if ( !array ) {
            if ( base==tmp ) {
                __TBB_ASSERT( !s.array, NULL );
                array = NFS_Allocate( n, element_size, NULL );
                ITT_NOTIFY( sync_releasing, &s.array );
                s.array = array;
            } else {
                ITT_NOTIFY(sync_prepare, &s.array);
                spin_wait_while_eq( s.array, (void*)0 );
                ITT_NOTIFY(sync_acquired, &s.array);
                array = s.array;
            }
        }
        size_type j_begin = tmp-base;
        size_type j_end = n > finish-base ? finish-base : n;
        (*init)( (void*)((char*)array+element_size*j_begin), j_end-j_begin );
        tmp = base+j_end;
    } while( tmp<finish );
}
Beispiel #2
0
market& market::global_market ( unsigned max_num_workers, size_t stack_size ) {
    global_market_mutex_type::scoped_lock lock( theMarketMutex );
    market *m = theMarket;
    if ( m ) {
        ++m->my_ref_count;
        if ( m->my_stack_size < stack_size )
            runtime_warning( "Newer master request for larger stack cannot be satisfied\n" );
    }
    else {
        max_num_workers = max( governor::default_num_threads() - 1, max_num_workers );
        // at least 1 worker is required to support starvation resistant tasks
        if( max_num_workers==0 ) max_num_workers = 1;
        // Create the global market instance
        size_t size = sizeof(market);
#if __TBB_TASK_GROUP_CONTEXT
        __TBB_ASSERT( __TBB_offsetof(market, my_workers) + sizeof(generic_scheduler*) == sizeof(market),
                      "my_workers must be the last data field of the market class");
        size += sizeof(generic_scheduler*) * (max_num_workers - 1);
#endif /* __TBB_TASK_GROUP_CONTEXT */
        __TBB_InitOnce::add_ref();
        void* storage = NFS_Allocate(size, 1, NULL);
        memset( storage, 0, size );
        // Initialize and publish global market
        m = new (storage) market( max_num_workers, stack_size );
        theMarket = m;
    }
    return *m;
}
Beispiel #3
0
arena::arena ( market& m, unsigned max_num_workers ) {
    __TBB_ASSERT( !my_guard, "improperly allocated arena?" );
    __TBB_ASSERT( sizeof(slot[0]) % NFS_GetLineSize()==0, "arena::slot size not multiple of cache line size" );
    __TBB_ASSERT( (uintptr_t)this % NFS_GetLineSize()==0, "arena misaligned" );
    my_market = &m;
    my_limit = 1;
    // Two slots are mandatory: for the master, and for 1 worker (required to support starvation resistant tasks).
    my_num_slots = max(2u, max_num_workers + 1);
    my_max_num_workers = max_num_workers;
    my_num_threads_active = 1; // accounts for the master
    __TBB_ASSERT ( my_max_num_workers < my_num_slots, NULL );
    // Construct mailboxes. Mark internal synchronization elements for the tools.
    for( unsigned i = 0; i < my_num_slots; ++i ) {
        __TBB_ASSERT( !slot[i].my_scheduler && !slot[i].task_pool, NULL );
        ITT_SYNC_CREATE(slot + i, SyncType_Scheduler, SyncObj_WorkerTaskPool);
        mailbox(i+1).construct();
        ITT_SYNC_CREATE(&mailbox(i+1), SyncType_Scheduler, SyncObj_Mailbox);
#if __TBB_STATISTICS
        slot[i].my_counters = new ( NFS_Allocate(sizeof(statistics_counters), 1, NULL) ) statistics_counters;
#endif /* __TBB_STATISTICS */
    }
    my_task_stream.initialize(my_num_slots);
    ITT_SYNC_CREATE(&my_task_stream, SyncType_Scheduler, SyncObj_TaskStream);
    my_mandatory_concurrency = false;
#if __TBB_TASK_GROUP_CONTEXT
    my_master_default_ctx = NULL;
#endif
}
Beispiel #4
0
void* concurrent_vector_base::internal_push_back( size_type element_size, size_type& index ) {
    __TBB_ASSERT( sizeof(my_early_size)==sizeof(reference_count), NULL );
    //size_t tmp = __TBB_FetchAndIncrementWacquire(*(tbb::internal::reference_count*)&my_early_size);
    size_t tmp = __TBB_FetchAndIncrementWacquire((tbb::internal::reference_count*)&my_early_size);
    index = tmp;
    segment_index_t k_old = segment_index_of( tmp );
    size_type base = segment_base(k_old);
    helper::extend_segment_if_necessary(*this,k_old);
    segment_t& s = my_segment[k_old];
    void* array = s.array;
    if ( !array ) {
        // FIXME - consider factoring this out and share with internal_grow_by
	if ( base==tmp ) {
	    __TBB_ASSERT( !s.array, NULL );
            size_t n = segment_size(k_old);
	    array = NFS_Allocate( n, element_size, NULL );
	    ITT_NOTIFY( sync_releasing, &s.array );
	    s.array = array;
	} else {
	    ITT_NOTIFY(sync_prepare, &s.array);
	    spin_wait_while_eq( s.array, (void*)0 );
	    ITT_NOTIFY(sync_acquired, &s.array);
	    array = s.array;
	}
    }
    size_type j_begin = tmp-base;
    return (void*)((char*)array+element_size*j_begin);
}
Beispiel #5
0
void concurrent_vector_base::internal_assign( const concurrent_vector_base& src, size_type element_size, internal_array_op1 destroy, internal_array_op2 assign, internal_array_op2 copy ) {
    size_type n = src.my_early_size;
    while( my_early_size>n ) { 
        segment_index_t k = segment_index_of( my_early_size-1 );
        size_type b=segment_base(k);
        size_type new_end = b>=n ? b : n;
        __TBB_ASSERT( my_early_size>new_end, NULL );
        destroy( (char*)my_segment[k].array+element_size*(new_end-b), my_early_size-new_end );
        my_early_size = new_end;
    }
    size_type dst_initialized_size = my_early_size;
    my_early_size = n;
    size_type b;
    for( segment_index_t k=0; (b=segment_base(k))<n; ++k ) {
        helper::extend_segment_if_necessary(*this,k);
        size_t m = segment_size(k);
        if ( !my_segment[k].array )
            my_segment[k].array = NFS_Allocate( m, element_size, NULL );
        if ( m>n-b ) m = n-b; 
        size_type a = 0;
        if ( dst_initialized_size>b ) {
            a = dst_initialized_size-b;
            if ( a>m ) a = m;
            assign( my_segment[k].array, src.my_segment[k].array, a );
            m -= a; 
            a *= element_size; 
        }
        if ( m>0 ) 
            copy( (char*)my_segment[k].array+a, (char*)src.my_segment[k].array+a, m );
    }
    __TBB_ASSERT( src.my_early_size==n, "detected use of ConcurrentVector::operator= with right side that was concurrently modified" );
}
Beispiel #6
0
arena& arena::allocate_arena( market& m, unsigned max_num_workers ) {
    __TBB_ASSERT( sizeof(base_type) + sizeof(arena_slot) == sizeof(arena), "All arena data fields must go to arena_base" );
    __TBB_ASSERT( sizeof(base_type) % NFS_GetLineSize() == 0, "arena slots area misaligned: wrong padding" );
    __TBB_ASSERT( sizeof(mail_outbox) == NFS_MaxLineSize, "Mailbox padding is wrong" );
    size_t n = allocation_size(max_num_workers);
    unsigned char* storage = (unsigned char*)NFS_Allocate( n, 1, NULL );
    // Zero all slots to indicate that they are empty
    memset( storage, 0, n );
    return *new( storage + num_slots_to_reserve(max_num_workers) * sizeof(mail_outbox) ) arena(m, max_num_workers);
}
Beispiel #7
0
void concurrent_vector_base::internal_reserve( size_type n, size_type element_size, size_type max_size ) {
    if ( n>max_size ) {
        throw std::length_error("argument to ConcurrentVector::reserve exceeds ConcurrentVector::max_size()");
    }
    for( segment_index_t k = helper::find_segment_end(*this); segment_base(k)<n; ++k ) {
        helper::extend_segment_if_necessary(*this,k);
        size_t m = segment_size(k);
        __TBB_ASSERT( !my_segment[k].array, "concurrent operation during reserve(...)?" );
        my_segment[k].array = NFS_Allocate( m, element_size, NULL );
    }
}
Beispiel #8
0
void concurrent_vector_base::helper::extend_segment( concurrent_vector_base& v ) {
    const size_t pointers_per_long_segment = sizeof(void*)==4 ? 32 : 64;
    segment_t* s = (segment_t*)NFS_Allocate( pointers_per_long_segment, sizeof(segment_t), NULL );
    std::memset( static_cast<void*>(s), 0, pointers_per_long_segment*sizeof(segment_t) );
    // If other threads are trying to set pointers in the short segment, wait for them to finish their
    // assignments before we copy the short segment to the long segment.
    atomic_backoff backoff;
    while( !v.my_storage[0].array || !v.my_storage[1].array ) backoff.pause();
    s[0] = v.my_storage[0];
    s[1] = v.my_storage[1];
    if( v.my_segment.compare_and_swap( s, v.my_storage )!=v.my_storage )
        NFS_Free(s);
}
Beispiel #9
0
void concurrent_vector_base::internal_copy( const concurrent_vector_base& src, size_type element_size, internal_array_op2 copy ) {
    size_type n = src.my_early_size;
    my_early_size = n;
    my_segment = my_storage;
    if ( n ) {
        size_type b;
        for( segment_index_t k=0; (b=segment_base(k))<n; ++k ) {
            helper::extend_segment_if_necessary(*this,k);
            size_t m = segment_size(k);
            __TBB_ASSERT( !my_segment[k].array, "concurrent operation during copy construction?" );
            my_segment[k].array = NFS_Allocate( m, element_size, NULL );
            if ( m>n-b ) m = n-b; 
            copy( my_segment[k].array, src.my_segment[k].array, m );
        }
    }
}
Beispiel #10
0
//------------------------------------------------------------------------
// Methods of affinity_partitioner_base_v3
//------------------------------------------------------------------------
void affinity_partitioner_base_v3::resize( unsigned factor ) {
    // Check factor to avoid asking for number of workers while there might be no arena.
    size_t new_size = factor ? factor*(governor::max_number_of_workers()+1) : 0;
    if( new_size!=my_size ) {
        if( my_array ) {
            NFS_Free( my_array );
            // Following two assignments must be done here for sake of exception safety.
            my_array = NULL;
            my_size = 0;
        }
        if( new_size ) {
            my_array = static_cast<affinity_id*>(NFS_Allocate(new_size,sizeof(affinity_id), NULL ));
            memset( my_array, 0, sizeof(affinity_id)*new_size );
            my_size = new_size;
        }
    } 
}
Beispiel #11
0
arena* arena::allocate_arena( unsigned number_of_slots, unsigned number_of_workers, stack_size_type stack_size ) {
    __TBB_ASSERT( sizeof(ArenaPrefix) % NFS_GetLineSize()==0, "ArenaPrefix not multiple of cache line size" );
    __TBB_ASSERT( sizeof(mail_outbox)==NFS_MaxLineSize, NULL );
    __TBB_ASSERT( stack_size>0, NULL );

    size_t n = sizeof(ArenaPrefix) + number_of_slots*(sizeof(mail_outbox)+sizeof(arena_slot));

    unsigned char* storage = (unsigned char*)NFS_Allocate( n, 1, NULL );
    // Zero all slots to indicate that they are empty
    memset( storage, 0, n );
    arena* a = (arena*)(storage + sizeof(ArenaPrefix)+ number_of_slots*(sizeof(mail_outbox)));
    __TBB_ASSERT( sizeof(a->slot[0]) % NFS_GetLineSize()==0, "arena::slot size not multiple of cache line size" );
    __TBB_ASSERT( (uintptr_t)a % NFS_GetLineSize()==0, NULL );
    new( &a->prefix() ) ArenaPrefix( number_of_slots, number_of_workers );

    // Allocate the worker_list
    WorkerDescriptor * w = new WorkerDescriptor[number_of_workers];
    memset( w, 0, sizeof(WorkerDescriptor)*(number_of_workers));
    a->prefix().worker_list = w;

    // Construct mailboxes.
    for( unsigned j=1; j<=number_of_slots; ++j ) 
        a->mailbox(j).construct();

    a->prefix().stack_size = stack_size;
    size_t k;
    // Mark each internal sync element for the tools
    for( k=0; k<number_of_workers; ++k ) {
        ITT_SYNC_CREATE(a->slot + k, SyncType_Scheduler, SyncObj_WorkerTaskPool);
        ITT_SYNC_CREATE(&w[k].scheduler, SyncType_Scheduler, SyncObj_WorkerLifeCycleMgmt);
        ITT_SYNC_CREATE(&a->mailbox(k+1), SyncType_Scheduler, SyncObj_Mailbox);
    }
    for( ; k<number_of_slots; ++k ) {
        ITT_SYNC_CREATE(a->slot + k, SyncType_Scheduler, SyncObj_MasterTaskPool);
        ITT_SYNC_CREATE(&a->mailbox(k+1), SyncType_Scheduler, SyncObj_Mailbox);
    }

    return a;
}