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)
97 #define SYS_MEMORY_ORDER_ACQ_REL (rl::mo_acq_rel)
98 #define SYS_MEMORY_ORDER_ACQUIRE (rl::mo_acquire)
99 #define SYS_MEMORY_ORDER_RELEASE (rl::mo_release)
100 #define SYS_MEMORY_ORDER_SEQ_CST (rl::mo_seq_cst)
106 class SYS_AtomicProxyConst
109 SYS_AtomicProxyConst(SYS_Atomic<T>
const & var, debug_info_param info)
110 : var_(
const_cast<SYS_Atomic<T>&
>(var))
115 T load(rl::memory_order mo = rl::mo_seq_cst)
const
117 return var_.load(mo, info_);
129 SYS_AtomicProxyConst&
operator = (SYS_AtomicProxyConst
const&);
133 class SYS_AtomicProxy :
public SYS_AtomicProxyConst<T>
136 SYS_AtomicProxy(SYS_Atomic<T> & var, debug_info_param info)
137 : SYS_AtomicProxyConst<T>(var, info)
141 void store(
T value, rl::memory_order mo = rl::mo_seq_cst)
143 this->var_.store(value, mo, this->info_);
147 return this->var_.add(value, this->info_);
151 return this->var_.exchange(xchg, this->info_);
155 template <
typename T>
156 class SYS_Atomic :
private rl::generic_atomic<T, true>
158 typedef rl::generic_atomic<T, true> SUPER;
167 SUPER::store(value, rl::mo_relaxed, $);
170 void store(
T val, rl::memory_order mo, rl::debug_info_param info)
172 SUPER::store(val, mo, info);
174 T load(rl::memory_order mo, rl::debug_info_param info)
const
176 return SUPER::load(mo, info);
178 T add(
T val, rl::debug_info_param info)
180 return SUPER::fetch_add(val, rl::mo_seq_cst, info) +
val;
187 SYS_AtomicProxyConst<T> operator () (debug_info_param info)
const
189 return SYS_AtomicProxyConst<T>(*
this, info);
192 SYS_AtomicProxy<T> operator () (debug_info_param info)
194 return SYS_AtomicProxy<T>(*
this, info);
197 friend class SYS_AtomicProxy<T>;
198 friend class SYS_AtomicProxyConst<T>;
200 RL_NOCOPY(SYS_Atomic);
205 template <
typename T>
220 return rl::ctx().current_thread()
221 + UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX;
224 class UT_RelacyObject
227 virtual ~UT_RelacyObject() { }
228 virtual void construct(
int num_threads) = 0;
229 virtual void destruct() = 0;
232 class UT_RelacyManager
240 void subscribe(UT_RelacyObject &obj)
242 mySubscribers.append(&obj);
243 if (myNumThreads > 0)
244 obj.construct(myNumThreads);
246 void unsubscribe(UT_RelacyObject &obj)
248 if (myNumThreads > 0)
250 mySubscribers.findAndRemove(&obj);
253 void construct(
int num_threads)
255 myNumThreads = num_threads;
256 for (
int i = 0; i < mySubscribers.entries(); i++)
257 mySubscribers(i)->construct(num_threads);
262 for (
int i = 0; i < mySubscribers.entries(); i++)
263 mySubscribers(i)->destruct();
271 static UT_RelacyManager theRelacyManager;
273 template <
typename T>
281 theRelacyManager.subscribe(*
this);
285 theRelacyManager.unsubscribe(*
this);
288 virtual void construct(
int num_threads)
290 myValues =
new T[num_threads];
291 myNumThreads = num_threads;
295 if (std::numeric_limits<T>::is_specialized
298 memset(static_cast<void *>(myValues), 0, myNumThreads*
sizeof(
T));
301 virtual void destruct()
308 T &getValueForThread(
int thread_index)
310 thread_index -= UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX;
311 UT_ASSERT(thread_index >= 0 && thread_index < myNumThreads);
312 return myValues[thread_index];
315 const T &getValueForThread(
int thread_index)
const
317 thread_index -= UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX;
318 UT_ASSERT(thread_index >= 0 && thread_index < myNumThreads);
319 return myValues[thread_index];
322 int maxThreadsSeen()
const
336 const_iterator(
const const_iterator &
copy)
342 const_iterator &
operator=(
const const_iterator ©)
355 return myVal->getValueForThread(myI);
363 const_iterator &operator++()
372 return (myVal == right.myVal
374 && myEnd == right.myEnd);
378 return !(*
this ==
right);
385 , myEnd(UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX
401 class iterator :
public const_iterator
408 iterator(
const iterator &
copy)
409 : const_iterator(copy)
412 iterator &
operator=(
const iterator ©)
421 return const_iterator::myVal->getValueForThread(
422 const_iterator::myI);
425 iterator &operator++()
427 if (const_iterator::myI < const_iterator::myEnd)
428 ++const_iterator::myI;
434 return (const_iterator::myVal == right.myVal
435 && const_iterator::myI == right.myI
436 && const_iterator::myEnd == right.myEnd);
440 return !(*
this ==
right);
445 : const_iterator(value, start)
454 UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX); }
458 UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX +
maxThreadsSeen()); }
462 {
return iterator(
this, UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX); }
465 {
return iterator(
this,
466 UT_Thread::UT_FIRST_SEQUENTIAL_THREAD_INDEX +
maxThreadsSeen()); }
473 class UT_RecursiveTimedLockProxy
476 UT_RecursiveTimedLockProxy(
477 recursive_timed_mutex &mutex,
478 debug_info_param info
485 bool timedLock(
int ms) {
return mutex_.timed_lock(ms, info_); }
486 bool tryLock() {
return mutex_.try_lock(info_); }
487 void lock() { mutex_.lock(info_); }
488 void unlock() { mutex_.unlock(info_); }
491 recursive_timed_mutex & mutex_;
502 UT_RecursiveTimedLockProxy operator()(debug_info_param info)
504 return UT_RecursiveTimedLockProxy(mutex_, info);
508 recursive_timed_mutex mutex_;
518 #define SYSgetSTID UT_Relacy::SYSgetSTID
519 #define UT_RecursiveTimedLock UT_Relacy::UT_RecursiveTimedLock
520 #define UT_ThreadSpecificValue UT_Relacy::UT_ThreadSpecificValue
521 #define SYS_AtomicInt32 UT_Relacy::SYS_AtomicInt32
522 #define SYS_AtomicPtr UT_Relacy::SYS_AtomicPtr
528 #define UT_ASSERT RL_ASSERT
531 #define UT_LOG_EVENT(X) if (rl::ctx().collecting_history()) { RL_LOG(X); }
532 #define UT_VAR(X) VAR((X))
533 #define UT_VAR_T(X) VAR_T(X)
535 #endif // UT_DEBUG_RELACY
543 #ifdef UT_DEBUG_RELACY
545 template <
typename DERIVED_T,
int THREAD_COUNT>
546 class UT_RelacyTest :
public rl::test_suite<DERIVED_T, THREAD_COUNT>
549 static bool simulate(
int ITER_COUNT_RELACTY)
553 params.iteration_count = ITER_COUNT_RELACY;
554 params.search_type = rl::random_scheduler_type;
555 params.execution_depth_limit = 4000;
563 return rl::simulate<DERIVED_T>(
params);
569 UT_Relacy::theRelacyManager.construct(THREAD_COUNT);
573 UT_Relacy::theRelacyManager.destruct();
583 void setSeed(
unsigned int )
592 return num_threads - 1;
622 for (
int i = 0; i < myThreads.
entries(); i++)
631 for (
int i = myThreads.
entries(); i < count; i++)
648 for (
int i = 0; i < mySize; i++)
681 template <
typename T>
700 template <
typename DERIVED_T,
int THREAD_COUNT>
716 ts = UTmakeUnique<UT_Timer>(
typeid(DERIVED_T).
name());
718 for (
int iter = 0; iter < ITER_COUNT; iter++)
723 for (
int i = 0; i < THREAD_COUNT; i++)
732 for (
int i = 0; i < THREAD_COUNT; i++)
751 num.
itoa(ITER_COUNT);
753 ts->timeStamp(
"iterations", num);
760 mySeed = (
int32)(((
size_t)
this) & 0xFFFFFFFF);
774 UTnap((
unsigned)(SYSrandom(mySeed)*max_millisec));
780 int max_value = mySeqThreadIndex[max_id];
782 for (
int i = 1; i < num_threads; i++)
784 if (mySeqThreadIndex[i] > max_value)
786 max_value = mySeqThreadIndex[i];
796 int mySeqThreadIndex[THREAD_COUNT];
802 #endif // UT_DEBUG_RELACY
805 #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)
GLsizei const GLfloat * value
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
GLuint const GLchar * name
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.
static UT_Thread * allocThread(SpinMode spin_mode)
**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)
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.