void operator()(int id) const { barrier->wait(); Harness::Sleep(2*id); void *o = pool_malloc(pool, id%2? 64 : 128*1024); barrier->wait(); pool_free(pool, o); }
void Run ( uint_t idx ) { #if TBBTEST_USE_TBB tbb::task_scheduler_init init; #endif AssertLive(); if ( idx == 0 ) { ASSERT ( !m_taskGroup && !m_tasksSpawned, "SharedGroupBody must be reset before reuse"); m_taskGroup = new Concurrency::task_group; Spawn( c_numTasks0 ); Wait(); if ( m_sharingMode & VagabondGroup ) m_barrier.wait(); else DeleteTaskGroup(); } else { while ( m_tasksSpawned == 0 ) __TBB_Yield(); ASSERT ( m_taskGroup, "Task group is not initialized"); Spawn (c_numTasks1); if ( m_sharingMode & ParallelWait ) Wait(); if ( m_sharingMode & VagabondGroup ) { ASSERT ( idx == 1, "In vagabond mode SharedGroupBody must be used with 2 threads only" ); m_barrier.wait(); DeleteTaskGroup(); } } AssertLive(); }
void operator()( int id ) const { const int ITERS = 1000; void *local[ITERS]; startB.wait(); for (int i=id*OBJ_CNT; i<(id+1)*OBJ_CNT; i++) { afterTerm[i] = pool_malloc(pool, i%2? 8*1024 : 9*1024); memset(afterTerm[i], i, i%2? 8*1024 : 9*1024); crossThread[i] = pool_malloc(pool, i%2? 9*1024 : 8*1024); memset(crossThread[i], i, i%2? 9*1024 : 8*1024); } for (int i=1; i<ITERS; i+=2) { local[i-1] = pool_malloc(pool, 6*1024); memset(local[i-1], i, 6*1024); local[i] = pool_malloc(pool, 16*1024); memset(local[i], i, 16*1024); } mallocDone.wait(); int myVictim = threadNum-id-1; for (int i=myVictim*OBJ_CNT; i<(myVictim+1)*OBJ_CNT; i++) pool_free(pool, crossThread[i]); for (int i=0; i<ITERS; i++) pool_free(pool, local[i]); }
void operator() ( int id ) const { ASSERT( id < 2, "Only two test driver threads are expected" ); // a barrier is required to ensure both threads started; otherwise the test may deadlock: // the first thread would execute FireAndForgetTask at shutdown and wait for FafCanFinish, // while the second thread wouldn't even start waiting for the loader lock hold by the first one. if ( id == 0 ) { driver_barrier.wait(); // Prepare global data g_Root1 = new( tbb::task::allocate_root() ) tbb::empty_task; g_Root2 = new( tbb::task::allocate_root() ) tbb::empty_task; g_Root3 = new( tbb::task::allocate_root() ) tbb::empty_task; g_Task = new( g_Root3->allocate_child() ) tbb::empty_task; g_Root3->set_ref_count(2); // Run tests NativeParallelFor( NumTestFuncs, TestThreadBody() ); ASSERT( g_NumTestsExecuted == NumTestFuncs, "Test driver: Wrong number of tests executed" ); // This test checks the validity of temporarily restoring the value of // the last TLS slot for a given key during the termination of an // auto-initialized master thread (in governor::auto_terminate). // If anything goes wrong, generic_scheduler::cleanup_master() will assert. // The context for this task must be valid till the task completion. tbb::task &r = *new( tbb::task::allocate_root(*g_Ctx) ) FireAndForgetTask; r.spawn(r); } else { tbb::task_group_context ctx; g_Ctx = &ctx; driver_barrier.wait(); spin_wait_until_eq( FafStarted, true ); UseAFewNewTlsKeys(); FafCanFinish = true; spin_wait_until_eq( FafCompleted, true ); } }
void operator()(int id) const { if (!id) { Harness::LIBRARY_HANDLE lib = Harness::OpenLibrary(TEST_LIBRARY_NAME("test_malloc_used_by_lib_dll")); ASSERT(lib, "Can't load " TEST_LIBRARY_NAME("test_malloc_used_by_lib_dll")); runPtr = Harness::GetAddress(lib, "callDll"); unloadCallback.lib = lib; } startBarr.wait(); (*runPtr)(); endBarr.wait(unloadCallback); }
void operator()(int id) const { void *p = pool_malloc(pool, id%2? 8 : 9000); ASSERT(p && liveRegions, NULL); barrier->wait(); if (!id) { bool ok = pool_destroy(pool); ASSERT(ok, NULL); ASSERT(!liveRegions, "Expected all regions were released."); } // other threads must wait till pool destruction, // to not call thread destruction cleanup before this barrier->wait(); }
void operator()( int id ) const { rml::MemPoolPolicy pol(CrossThreadGetMem, CrossThreadPutMem); const int objLen = 10*id; pool_create_v1(id, &pol, &pool[id]); obj[id] = (char*)pool_malloc(pool[id], objLen); ASSERT(obj[id], NULL); memset(obj[id], id, objLen); { const size_t lrgSz = 2*16*1024; void *ptrLarge = pool_malloc(pool[id], lrgSz); ASSERT(ptrLarge, NULL); memset(ptrLarge, 1, lrgSz); // consume all small objects while (pool_malloc(pool[id], 5*1024)) ; // releasing of large object can give a chance to allocate more pool_free(pool[id], ptrLarge); ASSERT(pool_malloc(pool[id], 5*1024), NULL); } barrier.wait(); int myPool = number_of_threads-id-1; for (int i=0; i<10*myPool; i++) ASSERT(myPool==obj[myPool][i], NULL); pool_free(pool[myPool], obj[myPool]); pool_destroy(pool[myPool]); }
void operator() (int) const { tbb::internal::spin_wait_while_eq(gPtr, (void*)NULL); scalable_free(gPtr); my_barr->wait(); my_ward.wait_to_finish(); ++FinishedTasks; }
void operator()( int /*id*/ ) const { startB->wait(); for (int i=0; i<iters; i++) { void *o = pool_malloc(pool, reqSize); ASSERT(o, NULL); pool_free(pool, o); } }
/*override*/ tbb::task* execute() { ASSERT( !(~theLocalState->m_flags & m_flag), NULL ); if( N < 2 ) return NULL; bool globalBarrierActive = false; if ( theLocalState->m_isMaster ) { if ( theGlobalBarrierActive ) { // This is the root task. Its N is equal to the number of threads. // Spawn a task for each worker. set_ref_count(N); for ( int i = 1; i < N; ++i ) spawn( *new( allocate_child() ) FibTask(20, m_flag, m_observer) ); if ( theTestMode & tmSynchronized ) { theGlobalBarrier.wait(); ASSERT( m_observer.m_entries >= N, "Wrong number of on_entry calls after the first barrier" ); // All the spawned tasks have been stolen by workers. // Now wait for workers to spawn some more tasks for this thread to steal back. theGlobalBarrier.wait(); ASSERT( !theGlobalBarrierActive, "Workers are expected to have reset this flag" ); } else theGlobalBarrierActive = false; wait_for_all(); return NULL; } } else { if ( theGlobalBarrierActive ) { if ( theTestMode & tmSynchronized ) { theGlobalBarrier.wait(); globalBarrierActive = true; } theGlobalBarrierActive = false; } } set_ref_count(3); spawn( *new( allocate_child() ) FibTask(N-1, m_flag, m_observer) ); spawn( *new( allocate_child() ) FibTask(N-2, m_flag, m_observer) ); if ( globalBarrierActive ) { // It's the first task executed by a worker. Release the master thread. theGlobalBarrier.wait(); } wait_for_all(); return NULL; }
void operator()( int /*id*/ ) const { const int ITERS = 10000; startB->wait(); for (int i=0; i<ITERS; i++) { void *o = pool_malloc(pool, reqSize); ASSERT(o, NULL); pool_free(pool, o); } }
void Wait () { while ( m_threadsReady != m_numThreads ) __TBB_Yield(); const uint_t numSpawned = c_numTasks0 + c_numTasks1 * (m_numThreads - 1); ASSERT ( m_tasksSpawned == numSpawned, "Wrong number of spawned tasks. The test is broken" ); REMARK("Max spawning parallelism is %u out of %u\n", Harness::ConcurrencyTracker::PeakParallelism(), g_MaxConcurrency); if ( m_sharingMode & ParallelWait ) { m_barrier.wait( &Harness::ConcurrencyTracker::Reset ); { Harness::ConcurrencyTracker ct; m_taskGroup->wait(); } if ( Harness::ConcurrencyTracker::PeakParallelism() == 1 ) REPORT ( "Warning: No parallel waiting detected in TestParallelWait\n" ); m_barrier.wait(); } else m_taskGroup->wait(); ASSERT ( m_tasksSpawned == numSpawned, "No tasks should be spawned after wait starts. The test is broken" ); ASSERT ( s_tasksExecuted == numSpawned, "Not all spawned tasks were executed" ); }
void operator()(int thread_id ) const { bool existed; sBarrier.wait(); for(int i = 0; i < nIters; ++i ) { existed = thread_id & 1; int oldval = locals->local(existed); ASSERT(existed == (i > 0), "Error on first reference"); ASSERT(!existed || (oldval == thread_id), "Error on fetched value"); existed = thread_id & 1; locals->local(existed) = thread_id; ASSERT(existed, "Error on assignment"); } }
void State::exercise( bool is_owner ) { barrier.wait(); if( is_owner ) { Cover(0); if( ja.try_acquire() ) { Cover(1); ++job_created; ja.set_and_release(job); Cover(2); if( ja.try_acquire() ) { Cover(3); ja.release(); Cover(4); if( ja.try_acquire() ) { Cover(5); ja.release(); } } Cover(6); } else { Cover(7); } if( DelayMask&1<<N ) { while( !job_received ) __TBB_Yield(); } } else { // Using extra bit of DelayMask for choosing whether to run wait_for_job or not. if( DelayMask&1<<N ) { rml::job* j= &ja.wait_for_job(); if( j!=&job ) REPORT("%p\n",j); ASSERT( j==&job, NULL ); job_received = true; } Cover(8); } rml::job* j; if( ja.try_plug(j) ) { ASSERT( j==&job || !j, NULL ); if( j ) { Cover(9+is_owner); ++job_destroyed; } else { __TBB_ASSERT( !is_owner, "owner failed to create job but plugged self" ); Cover(11); } } else { Cover(12+is_owner); } }
void operator()(const int tid) const { sBarrier.wait(); for(int i=0; i < nIters; ++i) { Harness::Sleep( tid * tickCounts ); tbb::tick_count t0 = tbb::tick_count::now(); mySem.P(); tbb::tick_count t1 = tbb::tick_count::now(); tottime[tid] += (t1-t0).seconds(); int curval = ++pCount; if(curval > ourCounts[tid]) ourCounts[tid] = curval; Harness::Sleep( innerWait ); --pCount; ASSERT((int)pCount >= 0, NULL); mySem.V(); } }
void operator()(const int /* threadID */ ) const { int nIters = MAX_WORK/nThread; sBarrier.wait(); tbb::tick_count t0 = tbb::tick_count::now(); for(int j = 0; j < nIters; j++) { for(int i = 0; i < MAX_WORK * (100 - WorkRatiox100); i++) { locals.local() += 1.0; } { tbb::critical_section::scoped_lock my_lock(cs); for(int i = 0; i < MAX_WORK * WorkRatiox100; i++) { locals.local() += 1.0; } unprotected_count++; } } locals.local() = (tbb::tick_count::now() - t0).seconds(); }
void FilterBase::Consume(const int /*tid*/) { unsigned myToken; sBarrier.wait(); do { while(!myTokens) mySem.P(); // we have a slot available. --myTokens; // moving this down reduces spurious wakeups myToken = myBuffer[curToken&(MAX_TOKENS-1)]; if(myToken) { ASSERT(myToken == curToken*3+1, "Error in received token"); ++curToken; Harness::Sleep(myWait); unsigned temp = ++otherTokens; if(temp == 1) nextSem.V(); } } while(myToken); // end of processing ASSERT(curToken + 1 == totTokens, "Didn't receive enough tokens"); }
// send a bunch of non-Null "tokens" to consumer, then a NULL. void FilterBase::Produce(const int /*tid*/) { nextBuffer[0] = 0; // just in case we provide no tokens sBarrier.wait(); while(totTokens) { while(!myTokens) mySem.P(); // we have a slot available. --myTokens; // moving this down reduces spurious wakeups --totTokens; if(totTokens) nextBuffer[curToken&(MAX_TOKENS-1)] = curToken*3+1; else nextBuffer[curToken&(MAX_TOKENS-1)] = (unsigned)NULL; ++curToken; Harness::Sleep(myWait); unsigned temp = ++otherTokens; if(temp == 1) nextSem.V(); } nextSem.V(); // final wakeup }
void operator()( int i ) const { theLocalState->m_isMaster = true; uintptr_t f = i <= MaxFlagIndex ? 1<<i : 0; MyObserver o(f); if ( theTestMode & tmSynchronized ) theMasterBarrier.wait(); // when mode is local observation but not synchronized and when num threads == default if ( theTestMode & tmAutoinitialization ) o.observe(true); // test autoinitialization can be done by observer // when mode is local synchronized observation and when num threads == default if ( theTestMode & tmLeavingControl ) o.test_leaving(); // Observer in enabled state must outlive the scheduler to ensure that // all exit notifications are called. tbb::task_scheduler_init init(m_numThreads); // when local & non-autoinitialized observation mode if ( theTestMode & tmLocalObservation ) o.observe(true); for ( int j = 0; j < 2; ++j ) { tbb::task &t = *new( tbb::task::allocate_root() ) FibTask(m_numThreads, f, o); tbb::task::spawn_root_and_wait(t); thePrevMode = theTestMode; } if( o.is_leaving_test() ) { REMARK( "Testing on_scheduler_leaving()\n"); ASSERT(o.m_workerEntries > 0, "Unbelievable"); // TODO: start from 0? for ( int j = o.m_workerExits; j < o.m_workerEntries; j++ ) { REMARK( "Round %d: entries %d, exits %d\n", j, (int)o.m_workerEntries, (int)o.m_workerExits ); ASSERT_WARNING(o.m_workerExits == j, "Workers unexpectedly leaved arena"); o.dismiss_one(); double n_seconds = 5; (Harness::TimedWaitWhileEq(n_seconds))(o.m_workerExits, j); ASSERT( n_seconds >= 0, "Time out while waiting for a worker to leave arena"); __TBB_Yield(); } } }
void operator()(const int /* threadID */ ) const { int nIters = MAX_WORK/nThread; sBarrier.wait(); tbb::tick_count t0 = tbb::tick_count::now(); for(int j = 0; j < nIters; j++) { for(int i = 0; i < MAX_WORK * (100 - WorkRatiox100); i++) { locals.local() += 1.0; } cs.lock(); ASSERT( !cs.try_lock(), "recursive try_lock must fail" ); #if TBB_USE_EXCEPTIONS && !__TBB_THROW_ACROSS_MODULE_BOUNDARY_BROKEN if(test_throw && j == (nIters / 2)) { bool was_caught = false, unknown_exception = false; try { cs.lock(); } catch(tbb::improper_lock& e) { ASSERT( e.what(), "Error message is absent" ); was_caught = true; } catch(...) { was_caught = unknown_exception = true; } ASSERT(was_caught, "Recursive lock attempt did not throw"); ASSERT(!unknown_exception, "tbb::improper_lock exception is expected"); } #endif /* TBB_USE_EXCEPTIONS && !__TBB_THROW_ACROSS_MODULE_BOUNDARY_BROKEN */ for(int i = 0; i < MAX_WORK * WorkRatiox100; i++) { locals.local() += 1.0; } unprotected_count++; cs.unlock(); } locals.local() = (tbb::tick_count::now() - t0).seconds(); }
void operator()(int id) const { startB->wait(); void *o = pool_malloc(pool, id%2? 64 : 128*1024); ASSERT(!o, "All memory must be consumed."); }
void operator() (bool do_malloc) const { my_barr->wait(); if (do_malloc) scalable_malloc(10); ++FinishedTasks; }
void operator() (int) const { gPtr = scalable_malloc(8); my_barr->wait(); ++FinishedTasks; }
void CMemTest::NULLReturn(UINT MinSize, UINT MaxSize, int total_threads) { const int MB_PER_THREAD = TOTAL_MB_ALLOC / total_threads; // find size to guarantee getting NULL for 1024 B allocations const int MAXNUM_1024 = (MB_PER_THREAD + (MB_PER_THREAD>>2)) * 1024; std::vector<MemStruct> PointerList; void *tmp; CountErrors=0; int CountNULL, num_1024; if (FullLog) REPORT("\nNULL return & check errno:\n"); UINT Size; Limit limit_total(TOTAL_MB_ALLOC), no_limit(0); void **buf_1024 = (void**)Tmalloc(MAXNUM_1024*sizeof(void*)); ASSERT(buf_1024, NULL); /* We must have space for pointers when memory limit is hit. Reserve enough for the worst case, taking into account race for limited space between threads. */ PointerList.reserve(TOTAL_MB_ALLOC*MByte/MinSize); /* There is a bug in the specific version of GLIBC (2.5-12) shipped with RHEL5 that leads to erroneous working of the test on Intel64 and IPF systems when setrlimit-related part is enabled. Switching to GLIBC 2.5-18 from RHEL5.1 resolved the issue. */ if (perProcessLimits) limitBarrier->wait(limit_total); else limitMem(MB_PER_THREAD); /* regression test against the bug in allocator when it dereference NULL while lack of memory */ for (num_1024=0; num_1024<MAXNUM_1024; num_1024++) { buf_1024[num_1024] = Tcalloc(1024, 1); if (! buf_1024[num_1024]) { ASSERT_ERRNO(errno == ENOMEM, NULL); break; } } for (int i=0; i<num_1024; i++) Tfree(buf_1024[i]); Tfree(buf_1024); do { Size=rand()%(MaxSize-MinSize)+MinSize; tmp=Tmalloc(Size); if (tmp != NULL) { myMemset(tmp, 0, Size); PointerList.push_back(MemStruct(tmp, Size)); } } while(tmp != NULL); ASSERT_ERRNO(errno == ENOMEM, NULL); if (FullLog) REPORT("\n"); // preparation complete, now running tests // malloc if (FullLog) REPORT("malloc...."); CountNULL = 0; while (CountNULL==0) for (int j=0; j<COUNT_TESTS; j++) { Size=rand()%(MaxSize-MinSize)+MinSize; errno = ENOMEM+j+1; tmp=Tmalloc(Size); if (tmp == NULL) { CountNULL++; if ( CHECK_ERRNO(errno != ENOMEM) ) { CountErrors++; if (ShouldReportError()) REPORT("NULL returned, error: errno (%d) != ENOMEM\n", errno); } } else { // Technically, if malloc returns a non-NULL pointer, it is allowed to set errno anyway. // However, on most systems it does not set errno. bool known_issue = false; #if __linux__ if( CHECK_ERRNO(errno==ENOMEM) ) known_issue = true; #endif /* __linux__ */ if ( CHECK_ERRNO(errno != ENOMEM+j+1) && !known_issue) { CountErrors++; if (ShouldReportError()) REPORT("error: errno changed to %d though valid pointer was returned\n", errno); } myMemset(tmp, 0, Size); PointerList.push_back(MemStruct(tmp, Size)); } } if (FullLog) REPORT("end malloc\n"); if (CountErrors) REPORT("%s\n",strError); else if (FullLog) REPORT("%s\n",strOk); error_occurred |= ( CountErrors>0 ) ; CountErrors=0; //calloc if (FullLog) REPORT("calloc...."); CountNULL = 0; while (CountNULL==0) for (int j=0; j<COUNT_TESTS; j++) { Size=rand()%(MaxSize-MinSize)+MinSize; errno = ENOMEM+j+1; tmp=Tcalloc(COUNT_ELEM_CALLOC,Size); if (tmp == NULL) { CountNULL++; if ( CHECK_ERRNO(errno != ENOMEM) ){ CountErrors++; if (ShouldReportError()) REPORT("NULL returned, error: errno(%d) != ENOMEM\n", errno); } } else { // Technically, if calloc returns a non-NULL pointer, it is allowed to set errno anyway. // However, on most systems it does not set errno. bool known_issue = false; #if __linux__ if( CHECK_ERRNO(errno==ENOMEM) ) known_issue = true; #endif /* __linux__ */ if ( CHECK_ERRNO(errno != ENOMEM+j+1) && !known_issue ) { CountErrors++; if (ShouldReportError()) REPORT("error: errno changed to %d though valid pointer was returned\n", errno); } PointerList.push_back(MemStruct(tmp, Size)); } } if (FullLog) REPORT("end calloc\n"); if (CountErrors) REPORT("%s\n",strError); else if (FullLog) REPORT("%s\n",strOk); error_occurred |= ( CountErrors>0 ) ; CountErrors=0; if (FullLog) REPORT("realloc...."); CountNULL = 0; if (PointerList.size() > 0) while (CountNULL==0) for (size_t i=0; i<(size_t)COUNT_TESTS && i<PointerList.size(); i++) { errno = 0; tmp=Trealloc(PointerList[i].Pointer,PointerList[i].Size*2); if (PointerList[i].Pointer == tmp) // the same place { bool known_issue = false; #if __linux__ if( errno==ENOMEM ) known_issue = true; #endif /* __linux__ */ if (errno != 0 && !known_issue) { CountErrors++; if (ShouldReportError()) REPORT("valid pointer returned, error: errno not kept\n"); } PointerList[i].Size *= 2; } else if (tmp != PointerList[i].Pointer && tmp != NULL) // another place { bool known_issue = false; #if __linux__ if( errno==ENOMEM ) known_issue = true; #endif /* __linux__ */ if (errno != 0 && !known_issue) { CountErrors++; if (ShouldReportError()) REPORT("valid pointer returned, error: errno not kept\n"); } // newly allocated area have to be zeroed myMemset((char*)tmp + PointerList[i].Size, 0, PointerList[i].Size); PointerList[i].Pointer = tmp; PointerList[i].Size *= 2; } else if (tmp == NULL) { CountNULL++; if ( CHECK_ERRNO(errno != ENOMEM) ) { CountErrors++; if (ShouldReportError()) REPORT("NULL returned, error: errno(%d) != ENOMEM\n", errno); } // check data integrity if (NonZero(PointerList[i].Pointer, PointerList[i].Size)) { CountErrors++; if (ShouldReportError()) REPORT("NULL returned, error: data changed\n"); } } } if (FullLog) REPORT("realloc end\n"); if (CountErrors) REPORT("%s\n",strError); else if (FullLog) REPORT("%s\n",strOk); error_occurred |= ( CountErrors>0 ) ; for (UINT i=0; i<PointerList.size(); i++) { Tfree(PointerList[i].Pointer); } if (perProcessLimits) limitBarrier->wait(no_limit); else limitMem(0); }
tbb::task* execute () { theLocalState->m_flags = 0; theWorkersBarrier.wait(); return NULL; }