23 #ifndef __UT_RELACY_INCLUDED__
24 #define __UT_RELACY_INCLUDED__
26 #if !defined(UT_DEBUG_RELACY)
35 #define UT_LOG_EVENT(X)
77 #define RL_MSVC_OUTPUT // output debug message to MSVC
78 #define RL_DEBUGBREAK_ON_FAILURE // cause breakpoint on failures
80 #include <relacy/relacy_std.hpp>
87 using rl::debug_info_param;
89 using rl::recursive_timed_mutex;
95 #define SYS_MEMORY_ORDER_RELAXED (rl::mo_relaxed)
100 #define SYS_MEMORY_ORDER_LOAD (rl::mo_acquire)
101 #define SYS_MEMORY_ORDER_STORE (rl::mo_release)
102 #define SYS_MEMORY_ORDER_SEQ_CST (rl::mo_seq_cst)
108 class SYS_AtomicProxyConst
111 SYS_AtomicProxyConst(SYS_Atomic<T>
const & var, debug_info_param info)
112 : var_(
const_cast<SYS_Atomic<T>&
>(var))
117 T load(rl::memory_order mo = rl::mo_seq_cst)
const
119 return var_.load(mo, info_);
131 SYS_AtomicProxyConst&
operator = (SYS_AtomicProxyConst
const&);
135 class SYS_AtomicProxy :
public SYS_AtomicProxyConst<T>
138 SYS_AtomicProxy(SYS_Atomic<T> & var, debug_info_param info)
139 : SYS_AtomicProxyConst<T>(var, info)
143 void store(
T value, rl::memory_order mo = rl::mo_seq_cst)
145 this->var_.store(value, mo, this->info_);
149 return this->var_.add(value, this->info_);
153 return this->var_.exchange(xchg, this->info_);
157 template <
typename T>
158 class SYS_Atomic :
private rl::generic_atomic<T, true>
160 typedef rl::generic_atomic<T, true> SUPER;
169 SUPER::store(value, rl::mo_relaxed, $);
172 void store(
T val, rl::memory_order mo, rl::debug_info_param info)
174 SUPER::store(val, mo, info);
176 T load(rl::memory_order mo, rl::debug_info_param info)
const
178 return SUPER::load(mo, info);
180 T add(
T val, rl::debug_info_param info)
182 return SUPER::fetch_add(val, rl::mo_seq_cst, info) +
val;
189 SYS_AtomicProxyConst<T> operator () (debug_info_param info)
const
191 return SYS_AtomicProxyConst<T>(*
this, info);
194 SYS_AtomicProxy<T> operator () (debug_info_param info)
196 return SYS_AtomicProxy<T>(*
this, info);
199 friend class SYS_AtomicProxy<T>;
200 friend class SYS_AtomicProxyConst<T>;
202 RL_NOCOPY(SYS_Atomic);
207 template <
typename T>
222 return rl::ctx().current_thread()
223 + UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX;
226 class UT_RelacyObject
229 virtual ~UT_RelacyObject() { }
230 virtual void construct(
int num_threads) = 0;
231 virtual void destruct() = 0;
234 class UT_RelacyManager
242 void subscribe(UT_RelacyObject &obj)
244 mySubscribers.append(&obj);
245 if (myNumThreads > 0)
246 obj.construct(myNumThreads);
248 void unsubscribe(UT_RelacyObject &obj)
250 if (myNumThreads > 0)
252 mySubscribers.findAndRemove(&obj);
255 void construct(
int num_threads)
257 myNumThreads = num_threads;
258 for (
int i = 0; i < mySubscribers.entries(); i++)
259 mySubscribers(i)->construct(num_threads);
264 for (
int i = 0; i < mySubscribers.entries(); i++)
265 mySubscribers(i)->destruct();
273 static UT_RelacyManager theRelacyManager;
275 template <
typename T>
283 theRelacyManager.subscribe(*
this);
287 theRelacyManager.unsubscribe(*
this);
290 virtual void construct(
int num_threads)
292 myValues =
new T[num_threads];
293 myNumThreads = num_threads;
297 if (std::numeric_limits<T>::is_specialized
300 memset(static_cast<void *>(myValues), 0, myNumThreads*
sizeof(
T));
303 virtual void destruct()
310 T &getValueForThread(
int thread_index)
312 thread_index -= UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX;
313 UT_ASSERT(thread_index >= 0 && thread_index < myNumThreads);
314 return myValues[thread_index];
317 const T &getValueForThread(
int thread_index)
const
319 thread_index -= UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX;
320 UT_ASSERT(thread_index >= 0 && thread_index < myNumThreads);
321 return myValues[thread_index];
324 int maxThreadsSeen()
const
338 const_iterator(
const const_iterator &
copy)
344 const_iterator &
operator=(
const const_iterator ©)
357 return myVal->getValueForThread(myI);
365 const_iterator &operator++()
374 return (myVal == right.myVal
376 && myEnd == right.myEnd);
380 return !(*
this ==
right);
387 , myEnd(UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX
403 class iterator :
public const_iterator
410 iterator(
const iterator &
copy)
411 : const_iterator(copy)
414 iterator &
operator=(
const iterator ©)
423 return const_iterator::myVal->getValueForThread(
424 const_iterator::myI);
427 iterator &operator++()
429 if (const_iterator::myI < const_iterator::myEnd)
430 ++const_iterator::myI;
436 return (const_iterator::myVal == right.myVal
437 && const_iterator::myI == right.myI
438 && const_iterator::myEnd == right.myEnd);
442 return !(*
this ==
right);
447 : const_iterator(value, start)
456 UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX); }
460 UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX +
maxThreadsSeen()); }
464 {
return iterator(
this, UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX); }
467 {
return iterator(
this,
468 UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX +
maxThreadsSeen()); }
475 class UT_RecursiveTimedLockProxy
478 UT_RecursiveTimedLockProxy(
479 recursive_timed_mutex &mutex,
480 debug_info_param info
487 bool timedLock(
int ms) {
return mutex_.timed_lock(ms, info_); }
488 bool tryLock() {
return mutex_.try_lock(info_); }
489 void lock() { mutex_.lock(info_); }
490 void unlock() { mutex_.unlock(info_); }
493 recursive_timed_mutex & mutex_;
504 UT_RecursiveTimedLockProxy operator()(debug_info_param info)
506 return UT_RecursiveTimedLockProxy(mutex_, info);
510 recursive_timed_mutex mutex_;
520 #define SYSgetSTID UT_Relacy::SYSgetSTID
521 #define UT_RecursiveTimedLock UT_Relacy::UT_RecursiveTimedLock
522 #define UT_ThreadSpecificValue UT_Relacy::UT_ThreadSpecificValue
523 #define SYS_AtomicInt32 UT_Relacy::SYS_AtomicInt32
524 #define SYS_AtomicPtr UT_Relacy::SYS_AtomicPtr
530 #define UT_ASSERT RL_ASSERT
533 #define UT_LOG_EVENT(X) if (rl::ctx().collecting_history()) { RL_LOG(X); }
534 #define UT_VAR(X) VAR((X))
535 #define UT_VAR_T(X) VAR_T(X)
537 #endif // UT_DEBUG_RELACY
545 #ifdef UT_DEBUG_RELACY
547 template <
typename DERIVED_T,
int THREAD_COUNT>
548 class UT_RelacyTest :
public rl::test_suite<DERIVED_T, THREAD_COUNT>
551 static bool simulate(
int ITER_COUNT_RELACTY)
555 params.iteration_count = ITER_COUNT_RELACY;
556 params.search_type = rl::random_scheduler_type;
557 params.execution_depth_limit = 4000;
565 return rl::simulate<DERIVED_T>(
params);
571 UT_Relacy::theRelacyManager.construct(THREAD_COUNT);
575 UT_Relacy::theRelacyManager.destruct();
585 void setSeed(
unsigned int )
594 return num_threads - 1;
624 for (
int i = 0; i < myThreads.
entries(); i++)
633 for (
int i = myThreads.
entries(); i < count; i++)
650 for (
int i = 0; i < mySize; i++)
683 template <
typename T>
702 template <
typename DERIVED_T,
int THREAD_COUNT>
718 ts = UTmakeUnique<UT_Timer>(
typeid(DERIVED_T).
name());
720 for (
int iter = 0; iter < ITER_COUNT; iter++)
725 for (
int i = 0; i < THREAD_COUNT; i++)
734 for (
int i = 0; i < THREAD_COUNT; i++)
753 num.
itoa(ITER_COUNT);
755 ts->timeStamp(
"iterations", num);
762 mySeed = (
int32)(((
size_t)
this) & 0xFFFFFFFF);
776 UTnap((
unsigned)(SYSrandom(mySeed)*max_millisec));
782 int max_value = mySeqThreadIndex[max_id];
784 for (
int i = 1; i < num_threads; i++)
786 if (mySeqThreadIndex[i] > max_value)
788 max_value = mySeqThreadIndex[i];
798 int mySeqThreadIndex[THREAD_COUNT];
804 #endif // UT_DEBUG_RELACY
807 #endif // __UT_RELACY_INCLUDED__
constexpr auto max_value() -> T
cvex test(vector P=0;int unbound=3;export float s=0;export vector Cf=0;)
OIIO_UTIL_API bool copy(string_view from, string_view to, std::string &err)
UT_Thread * getThread(int i)
void sleepRandom(unsigned int max_millisec)
SYS_AtomicInt< int32 > SYS_AtomicInt32
GLenum const GLfloat * params
std::unique_ptr< T, Deleter > UT_UniquePtr
A smart pointer for unique ownership of dynamically allocated objects.
bool operator==(const BaseDimensions< T > &a, const BaseDimensions< Y > &b)
Lock adapter for std mutexes.
static ThreadPool * get(int count)
int getMaxThreadId(int num_threads) const
static bool simulate(int ITER_COUNT, bool verbose)
virtual bool startThread(UTthreadFunc func, void *data, int stacksize)=0
UT_RelacyTest< DERIVED_T, THREAD_COUNT > TestThread
friend class const_iterator
static int itoa(char *str, int64 i)
exint entries() const
Alias of size(). size() is preferred.
**Note that the tasks the is the thread number *for the or if it s being executed by a non pool thread(this *can happen in cases where the whole pool is occupied and the calling *thread contributes to running the work load).**Thread pool.Have fun
LeafData & operator=(const LeafData &)=delete
VULKAN_HPP_CONSTEXPR_14 VULKAN_HPP_INLINE T exchange(T &obj, U &&newValue)
ImageBuf OIIO_API add(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
bool operator!=(const BaseDimensions< T > &a, const BaseDimensions< Y > &b)
static UT_Thread * allocThread(SpinMode spin_mode, bool uses_tbb=true)
int maxThreadsSeen() const
static void * func(void *data)
UT_StdLockable< std::recursive_timed_mutex > UT_RecursiveTimedLock
**Note that the tasks the is the thread number *for the pool
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.