#include <sys/time.h>
#include <sys/types.h>
-#include <linux/aio_abi.h>
+#ifdef HAVE_LIBAIO_H
+#include <libaio.h>
+#endif
#include <queue>
#include <set>
// Global Datastruture shared by the Cache Coherency Worker Threads.
struct cc_cacheline_data {
- int *num;
+ char *num;
};
// Typical usage:
// ResumeWorkers() or StopWorkers() has been called. Number of distinct
// calling threads must match the worker count (see AddWorkers() and
// RemoveSelf()).
- bool ContinueRunning();
+ bool ContinueRunning(bool *paused);
- // TODO(matthewb): Is this functionality really necessary? Remove it if not.
- //
// This is a hack! It's like ContinueRunning(), except it won't pause. If
// any worker threads use this exclusively in place of ContinueRunning() then
// PauseWorkers() should never be used!
enum Status { RUN, PAUSE, STOP };
void WaitOnPauseBarrier() {
+#ifdef HAVE_PTHREAD_BARRIERS
int error = pthread_barrier_wait(&pause_barrier_);
if (error != PTHREAD_BARRIER_SERIAL_THREAD)
sat_assert(error == 0);
+#endif
}
void AcquireNumWorkersLock() {
pthread_rwlock_t status_rwlock_;
Status status_;
+#ifdef HAVE_PTHREAD_BARRIERS
// Guaranteed to not be in use when (status_ != PAUSE).
pthread_barrier_t pause_barrier_;
+#endif
DISALLOW_COPY_AND_ASSIGN(WorkerStatus);
};
virtual ~WorkerThread();
// Initialize values and thread ID number.
- void InitThread(int thread_num_init,
- class Sat *sat_init,
- class OsLayer *os_init,
- class PatternList *patternlist_init,
- WorkerStatus *worker_status);
+ virtual void InitThread(int thread_num_init,
+ class Sat *sat_init,
+ class OsLayer *os_init,
+ class PatternList *patternlist_init,
+ WorkerStatus *worker_status);
// This function is DEPRECATED, it does nothing.
void SetPriority(Priority priority) { priority_ = priority; }
bool InitPriority();
// Wait for the thread to complete its cleanup.
- virtual int JoinThread();
+ virtual bool JoinThread();
// Kill worker thread with SIGINT.
- virtual int KillThread();
+ virtual bool KillThread();
// This is the task function that the thread executes.
// This is implemented per subclass.
- virtual int Work();
+ virtual bool Work();
// Starts per-WorkerThread timer.
void StartThreadTimer() {gettimeofday(&start_time_, NULL);}
int64 ReadThreadTimer() {
struct timeval end_time_;
gettimeofday(&end_time_, NULL);
- return (end_time_.tv_sec - start_time_.tv_sec)*1000000 +
+ return (end_time_.tv_sec - start_time_.tv_sec)*1000000ULL +
(end_time_.tv_usec - start_time_.tv_usec);
}
// Stops per-WorkerThread timer and records thread run duration.
}
// Acccess member variables.
- int GetStatus() {return status_;}
+ bool GetStatus() {return status_;}
int64 GetErrorCount() {return errorcount_;}
int64 GetPageCount() {return pages_copied_;}
int64 GetRunDurationUSec() {return runduration_usec_;}
// Returns bandwidth defined as pages_copied / thread_run_durations.
- float GetCopiedData();
+ virtual float GetCopiedData();
// Calculate worker thread specific copied data.
virtual float GetMemoryCopiedData() {return 0;}
virtual float GetDeviceCopiedData() {return 0;}
// Calculate worker thread specific bandwidth.
virtual float GetMemoryBandwidth()
{return GetMemoryCopiedData() / (
- runduration_usec_ * 1.0 / 1000000);}
+ runduration_usec_ * 1.0 / 1000000.);}
virtual float GetDeviceBandwidth()
{return GetDeviceCopiedData() / (
- runduration_usec_ * 1.0 / 1000000);}
+ runduration_usec_ * 1.0 / 1000000.);}
+
+ void set_cpu_mask(cpu_set_t *mask) {
+ memcpy(&cpu_mask_, mask, sizeof(*mask));
+ }
+
+ void set_cpu_mask_to_cpu(int cpu_num) {
+ cpuset_set_ab(&cpu_mask_, cpu_num, cpu_num + 1);
+ }
- void set_cpu_mask(int32 mask) {cpu_mask_ = mask;}
void set_tag(int32 tag) {tag_ = tag;}
// Returns CPU mask, where each bit represents a logical cpu.
- uint32 AvailableCpus();
+ bool AvailableCpus(cpu_set_t *cpuset);
// Returns CPU mask of CPUs this thread is bound to,
- uint32 CurrentCpus();
+ bool CurrentCpus(cpu_set_t *cpuset);
+ // Returns Current Cpus mask as string.
+ string CurrentCpusFormat() {
+ cpu_set_t current_cpus;
+ CurrentCpus(¤t_cpus);
+ return cpuset_format(¤t_cpus);
+ }
int ThreadID() {return thread_num_;}
// Bind worker thread to specified CPU(s)
- bool BindToCpus(uint32 thread_mask);
+ bool BindToCpus(const cpu_set_t *cpuset);
protected:
// This function dictates whether the main work loop
// do {
// // work.
// } while (IsReadyToRun());
- virtual bool IsReadyToRun() { return worker_status_->ContinueRunning(); }
- // TODO(matthewb): Is this function really necessary? Remove it if not.
- //
+ virtual bool IsReadyToRun(bool *paused = NULL) {
+ return worker_status_->ContinueRunning(paused);
+ }
+
// Like IsReadyToRun(), except it won't pause.
virtual bool IsReadyToRunNoPause() {
return worker_status_->ContinueRunningNoPause();
unsigned int size_in_bytes,
AdlerChecksum *checksum,
struct page_entry *pe);
+ // SSE copy with address tagging.
+ virtual bool AdlerAddrMemcpyWarm(uint64 *dstmem64,
+ uint64 *srcmem64,
+ unsigned int size_in_bytes,
+ AdlerChecksum *checksum,
+ struct page_entry *pe);
// Crc data with address tagging.
virtual bool AdlerAddrCrcC(uint64 *srcmem64,
unsigned int size_in_bytes,
AdlerChecksum *checksum,
struct page_entry *pe);
+ // Setup tagging on an existing page.
+ virtual bool TagAddrC(uint64 *memwords,
+ unsigned int size_in_bytes);
// Report a mistagged cacheline.
- bool ReportTagError(uint64 *mem64,
+ virtual bool ReportTagError(uint64 *mem64,
uint64 actual,
uint64 tag);
// Print out the error record of the tag mismatch.
- void ProcessTagError(struct ErrorRecord *error,
+ virtual void ProcessTagError(struct ErrorRecord *error,
int priority,
const char *message);
protected:
// General state variables that all subclasses need.
int thread_num_; // Thread ID.
- volatile int status_; // Error status.
+ volatile bool status_; // Error status.
volatile int64 pages_copied_; // Recorded for memory bandwidth calc.
volatile int64 errorcount_; // Miscompares seen by this thread.
- volatile uint32 cpu_mask_; // Cores this thread is allowed to run on.
+ cpu_set_t cpu_mask_; // Cores this thread is allowed to run on.
volatile uint32 tag_; // Tag hint for memory this thread can use.
bool tag_mode_; // Tag cachelines with vaddr.
FileThread();
// Set filename to use for file IO.
virtual void SetFile(const char *filename_init);
- virtual int Work();
+ virtual bool Work();
// Calculate worker thread specific bandwidth.
virtual float GetDeviceCopiedData()
// Record of where these pages were sourced from, and what
// potentially broken components they passed through.
struct PageRec {
- struct Pattern *pattern; // This is the data it should contain.
+ class Pattern *pattern; // This is the data it should contain.
void *src; // This is the memory location the data was sourced from.
void *dst; // This is where it ended up.
};
NetworkThread();
// Set hostname to use for net IO.
virtual void SetIP(const char *ipaddr_init);
- virtual int Work();
+ virtual bool Work();
// Calculate worker thread specific bandwidth.
virtual float GetDeviceCopiedData()
NetworkSlaveThread();
// Set socket for IO.
virtual void SetSock(int sock);
- virtual int Work();
+ virtual bool Work();
protected:
virtual bool IsNetworkStopSet();
class NetworkListenThread : public NetworkThread {
public:
NetworkListenThread();
- virtual int Work();
+ virtual bool Work();
private:
virtual bool Listen();
class CopyThread : public WorkerThread {
public:
CopyThread() {}
- virtual int Work();
+ virtual bool Work();
// Calculate worker thread specific bandwidth.
virtual float GetMemoryCopiedData()
{return GetCopiedData()*2;}
class InvertThread : public WorkerThread {
public:
InvertThread() {}
- virtual int Work();
+ virtual bool Work();
// Calculate worker thread specific bandwidth.
virtual float GetMemoryCopiedData()
{return GetCopiedData()*4;}
FillThread();
// Set how many pages this thread should fill before exiting.
virtual void SetFillPages(int64 num_pages_to_fill_init);
- virtual int Work();
+ virtual bool Work();
private:
// Fill a page with the data pattern in pe->pattern.
class CheckThread : public WorkerThread {
public:
CheckThread() {}
- virtual int Work();
+ virtual bool Work();
// Calculate worker thread specific bandwidth.
virtual float GetMemoryCopiedData()
{return GetCopiedData();}
class ErrorPollThread : public WorkerThread {
public:
ErrorPollThread() {}
- virtual int Work();
+ virtual bool Work();
private:
DISALLOW_COPY_AND_ASSIGN(ErrorPollThread);
class CpuStressThread : public WorkerThread {
public:
CpuStressThread() {}
- virtual int Work();
+ virtual bool Work();
private:
DISALLOW_COPY_AND_ASSIGN(CpuStressThread);
CpuCacheCoherencyThread(cc_cacheline_data *cc_data,
int cc_cacheline_count_,
int cc_thread_num_,
+ int cc_thread_count_,
int cc_inc_count_);
- virtual int Work();
+ virtual bool Work();
protected:
+ // Used by the simple random number generator as a shift feedback;
+ // this polynomial (x^64 + x^63 + x^61 + x^60 + 1) will produce a
+ // psuedorandom cycle of period 2^64-1.
+ static const uint64 kRandomPolynomial = 0xD800000000000000ULL;
+ // A very simple psuedorandom generator that can be inlined and use
+ // registers, to keep the CC test loop tight and focused.
+ static uint64 SimpleRandom(uint64 seed);
+
cc_cacheline_data *cc_cacheline_data_; // Datstructure for each cacheline.
int cc_local_num_; // Local counter for each thread.
int cc_cacheline_count_; // Number of cache lines to operate on.
int cc_thread_num_; // The integer id of the thread which is
// used as an index into the integer array
// of the cacheline datastructure.
+ int cc_thread_count_; // Total number of threads being run, for
+ // calculations mixing up cache line access.
int cc_inc_count_; // Number of times to increment the counter.
private:
int64 write_threshold,
int non_destructive);
- virtual int Work();
+ virtual bool Work();
virtual float GetMemoryCopiedData() {return 0;}
// not verified.
void *block_buffer_; // Pointer to aligned block buffer.
- aio_context_t aio_ctx_; // Asynchronous I/O context for Linux native AIO.
+#ifdef HAVE_LIBAIO_H
+ io_context_t aio_ctx_; // Asynchronous I/O context for Linux native AIO.
+#endif
DiskBlockTable *block_table_; // Disk Block Table, shared by all disk
// threads that read / write at the same
public:
MemoryRegionThread();
~MemoryRegionThread();
- virtual int Work();
+ virtual bool Work();
void ProcessError(struct ErrorRecord *error, int priority,
const char *message);
bool SetRegion(void *region, int64 size);
DISALLOW_COPY_AND_ASSIGN(MemoryRegionThread);
};
+// Worker thread to check that the frequency of every cpu does not go below a
+// certain threshold.
+class CpuFreqThread : public WorkerThread {
+ public:
+ CpuFreqThread(int num_cpus, int freq_threshold, int round);
+ ~CpuFreqThread();
+
+ // This is the task function that the thread executes.
+ virtual bool Work();
+
+ // Returns true if this test can run on the current machine. Otherwise,
+ // returns false.
+ static bool CanRun();
+
+ private:
+ static const int kIntervalPause = 10; // The number of seconds to pause
+ // between acquiring the MSR data.
+ static const int kStartupDelay = 5; // The number of seconds to wait
+ // before acquiring MSR data.
+ static const int kMsrTscAddr = 0x10; // The address of the TSC MSR.
+ static const int kMsrAperfAddr = 0xE8; // The address of the APERF MSR.
+ static const int kMsrMperfAddr = 0xE7; // The address of the MPERF MSR.
+
+ // The index values into the CpuDataType.msr[] array.
+ enum MsrValues {
+ kMsrTsc = 0, // MSR index 0 = TSC.
+ kMsrAperf = 1, // MSR index 1 = APERF.
+ kMsrMperf = 2, // MSR index 2 = MPERF.
+ kMsrLast, // Last MSR index.
+ };
+
+ typedef struct {
+ uint32 msr; // The address of the MSR.
+ const char *name; // A human readable string for the MSR.
+ } CpuRegisterType;
+
+ typedef struct {
+ uint64 msrs[kMsrLast]; // The values of the MSRs.
+ struct timeval tv; // The time at which the MSRs were read.
+ } CpuDataType;
+
+ // The set of MSR addresses and register names.
+ static const CpuRegisterType kCpuRegisters[kMsrLast];
+
+ // Compute the change in values of the MSRs between current and previous,
+ // set the frequency in MHz of the cpu. If there is an error computing
+ // the delta, return false. Othewise, return true.
+ bool ComputeFrequency(CpuDataType *current, CpuDataType *previous,
+ int *frequency);
+
+ // Get the MSR values for this particular cpu and save them in data. If
+ // any error is encountered, returns false. Otherwise, returns true.
+ bool GetMsrs(int cpu, CpuDataType *data);
+
+ // Compute the difference between the currently read MSR values and the
+ // previously read values and store the results in delta. If any of the
+ // values did not increase, or the TSC value is too small, returns false.
+ // Otherwise, returns true.
+ bool ComputeDelta(CpuDataType *current, CpuDataType *previous,
+ CpuDataType *delta);
+
+ // The total number of cpus on the system.
+ int num_cpus_;
+
+ // The minimum frequency that each cpu must operate at (in MHz).
+ int freq_threshold_;
+
+ // The value to round the computed frequency to.
+ int round_;
+
+ // Precomputed value to add to the frequency to do the rounding.
+ double round_value_;
+
+ DISALLOW_COPY_AND_ASSIGN(CpuFreqThread);
+};
+
#endif // STRESSAPPTEST_WORKER_H_