chiark / gitweb /
PORT 22
[stressapptest] / src / worker.h
index b85f9267bc1c9a8f016698d458dea22b3bbd1465..091d96b6557533aa000d205c369e2d4d1e603e4f 100644 (file)
@@ -26,7 +26,9 @@
 #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>
@@ -42,7 +44,7 @@
 
 // Global Datastruture shared by the Cache Coherency Worker Threads.
 struct cc_cacheline_data {
-  int *num;
+  char *num;
 };
 
 // Typical usage:
@@ -125,10 +127,8 @@ class WorkerStatus {
   // 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!
@@ -138,9 +138,11 @@ class WorkerStatus {
   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() {
@@ -185,8 +187,10 @@ class WorkerStatus {
   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);
 };
@@ -207,11 +211,11 @@ class WorkerThread {
   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; }
@@ -222,13 +226,13 @@ class WorkerThread {
   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);}
@@ -236,7 +240,7 @@ class WorkerThread {
   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.
@@ -247,36 +251,49 @@ class WorkerThread {
   }
 
   // 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(&current_cpus);
+    return cpuset_format(&current_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
@@ -285,9 +302,10 @@ class WorkerThread {
   //   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();
@@ -326,17 +344,26 @@ class WorkerThread {
                                 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);
 
@@ -346,11 +373,11 @@ class WorkerThread {
  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.
@@ -383,7 +410,7 @@ class FileThread : public WorkerThread {
   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()
@@ -394,7 +421,7 @@ class FileThread : public WorkerThread {
   // 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.
   };
@@ -466,7 +493,7 @@ class NetworkThread : public WorkerThread {
   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()
@@ -493,7 +520,7 @@ class NetworkSlaveThread : public NetworkThread {
   NetworkSlaveThread();
   // Set socket for IO.
   virtual void SetSock(int sock);
-  virtual int Work();
+  virtual bool Work();
 
  protected:
   virtual bool IsNetworkStopSet();
@@ -506,7 +533,7 @@ class NetworkSlaveThread : public NetworkThread {
 class NetworkListenThread : public NetworkThread {
  public:
   NetworkListenThread();
-  virtual int Work();
+  virtual bool Work();
 
  private:
   virtual bool Listen();
@@ -530,7 +557,7 @@ class NetworkListenThread : public NetworkThread {
 class CopyThread : public WorkerThread {
  public:
   CopyThread() {}
-  virtual int Work();
+  virtual bool Work();
   // Calculate worker thread specific bandwidth.
   virtual float GetMemoryCopiedData()
     {return GetCopiedData()*2;}
@@ -543,7 +570,7 @@ class CopyThread : public WorkerThread {
 class InvertThread : public WorkerThread {
  public:
   InvertThread() {}
-  virtual int Work();
+  virtual bool Work();
   // Calculate worker thread specific bandwidth.
   virtual float GetMemoryCopiedData()
     {return GetCopiedData()*4;}
@@ -560,7 +587,7 @@ class FillThread : public WorkerThread {
   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.
@@ -575,7 +602,7 @@ class FillThread : public WorkerThread {
 class CheckThread : public WorkerThread {
  public:
   CheckThread() {}
-  virtual int Work();
+  virtual bool Work();
   // Calculate worker thread specific bandwidth.
   virtual float GetMemoryCopiedData()
     {return GetCopiedData();}
@@ -590,7 +617,7 @@ class CheckThread : public WorkerThread {
 class ErrorPollThread : public WorkerThread {
  public:
   ErrorPollThread() {}
-  virtual int Work();
+  virtual bool Work();
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ErrorPollThread);
@@ -600,7 +627,7 @@ class ErrorPollThread : public WorkerThread {
 class CpuStressThread : public WorkerThread {
  public:
   CpuStressThread() {}
-  virtual int Work();
+  virtual bool Work();
 
  private:
   DISALLOW_COPY_AND_ASSIGN(CpuStressThread);
@@ -613,16 +640,27 @@ class CpuCacheCoherencyThread : public WorkerThread {
   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:
@@ -651,7 +689,7 @@ class DiskThread : public WorkerThread {
                              int64 write_threshold,
                              int non_destructive);
 
-  virtual int Work();
+  virtual bool Work();
 
   virtual float GetMemoryCopiedData() {return 0;}
 
@@ -727,7 +765,9 @@ class DiskThread : public WorkerThread {
                                                 // 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
@@ -751,7 +791,7 @@ class MemoryRegionThread : public WorkerThread {
  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);
@@ -779,4 +819,80 @@ class MemoryRegionThread : public WorkerThread {
   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_