Home | History | Annotate | Download | only in src
      1 // Copyright 2006 Google Inc. All Rights Reserved.
      2 // Author: nsanders, menderico
      3 
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 
     16 #ifndef STRESSAPPTEST_OS_H_  // NOLINT
     17 #define STRESSAPPTEST_OS_H_
     18 
     19 #include <dirent.h>
     20 #include <string>
     21 #include <list>
     22 #include <map>
     23 #include <vector>
     24 
     25 // This file must work with autoconf on its public version,
     26 // so these includes are correct.
     27 #include "adler32memcpy.h"  // NOLINT
     28 #include "sattypes.h"       // NOLINT
     29 
     30 const char kSysfsPath[] = "/sys/bus/pci/devices";
     31 
     32 struct PCIDevice {
     33   int32 domain;
     34   uint16 bus;
     35   uint8 dev;
     36   uint8 func;
     37   uint16 vendor_id;
     38   uint16 device_id;
     39   uint64 base_addr[6];
     40   uint64 size[6];
     41 };
     42 
     43 typedef vector<PCIDevice*> PCIDevices;
     44 
     45 class ErrorDiag;
     46 
     47 // This class implements OS/Platform specific funtions.
     48 class OsLayer {
     49  public:
     50   OsLayer();
     51   virtual ~OsLayer();
     52 
     53   // Set the minimum amount of hugepages that should be available for testing.
     54   // Must be set before Initialize().
     55   void SetMinimumHugepagesSize(int64 min_bytes) {
     56     min_hugepages_bytes_ = min_bytes;
     57   }
     58 
     59   // Initializes data strctures and open files.
     60   // Returns false on error.
     61   virtual bool Initialize();
     62 
     63   // Virtual to physical. This implementation is optional for
     64   // subclasses to implement.
     65   // Takes a pointer, and returns the corresponding bus address.
     66   virtual uint64 VirtualToPhysical(void *vaddr);
     67 
     68   // Prints failed dimm. This implementation is optional for
     69   // subclasses to implement.
     70   // Takes a bus address and string, and prints the DIMM name
     71   // into the string. Returns error status.
     72   virtual int FindDimm(uint64 addr, char *buf, int len);
     73   // Print dimm info, plus more available info.
     74   virtual int FindDimmExtended(uint64 addr, char *buf, int len) {
     75     return FindDimm(addr, buf, len);
     76   }
     77 
     78 
     79   // Classifies addresses according to "regions"
     80   // This may mean different things on different platforms.
     81   virtual int32 FindRegion(uint64 paddr);
     82   // Find cpu cores associated with a region. Either NUMA or arbitrary.
     83   virtual cpu_set_t *FindCoreMask(int32 region);
     84   // Return cpu cores associated with a region in a hex string.
     85   virtual string FindCoreMaskFormat(int32 region);
     86 
     87   // Returns the HD device that contains this file.
     88   virtual string FindFileDevice(string filename);
     89 
     90   // Returns a list of paths coresponding to HD devices found on this machine.
     91   virtual list<string> FindFileDevices();
     92 
     93   // Polls for errors. This implementation is optional.
     94   // This will poll once for errors and return zero iff no errors were found.
     95   virtual int ErrorPoll();
     96 
     97   // Delay an appropriate amount of time between polling.
     98   virtual void ErrorWait();
     99 
    100   // Report errors. This implementation is mandatory.
    101   // This will output a machine readable line regarding the error.
    102   virtual bool ErrorReport(const char *part, const char *symptom, int count);
    103 
    104   // Flushes page cache. Used to circumvent the page cache when doing disk
    105   // I/O.  This will be a NOP until ActivateFlushPageCache() is called, which
    106   // is typically done when opening a file with O_DIRECT fails.
    107   // Returns false on error, true on success or NOP.
    108   // Subclasses may implement this in machine specific ways..
    109   virtual bool FlushPageCache(void);
    110   // Enable FlushPageCache() to actually do the flush instead of being a NOP.
    111   virtual void ActivateFlushPageCache(void);
    112 
    113   // Flushes cacheline. Used to distinguish read or write errors.
    114   // Subclasses may implement this in machine specific ways..
    115   // Takes a pointer, and flushed the cacheline containing that pointer.
    116   virtual void Flush(void *vaddr);
    117 
    118   // Fast flush, for use in performance critical code.
    119   // This is bound at compile time, and will not pick up
    120   // any runtime machine configuration info.
    121   inline static void FastFlush(void *vaddr) {
    122 #ifdef STRESSAPPTEST_CPU_PPC
    123     asm volatile("dcbf 0,%0; sync" : : "r" (vaddr));
    124 #elif defined(STRESSAPPTEST_CPU_X86_64) || defined(STRESSAPPTEST_CPU_I686)
    125     // Put mfence before and after clflush to make sure:
    126     // 1. The write before the clflush is committed to memory bus;
    127     // 2. The read after the clflush is hitting the memory bus.
    128     //
    129     // From Intel manual:
    130     // CLFLUSH is only ordered by the MFENCE instruction. It is not guaranteed
    131     // to be ordered by any other fencing, serializing or other CLFLUSH
    132     // instruction. For example, software can use an MFENCE instruction to
    133     // insure that previous stores are included in the write-back.
    134     asm volatile("mfence");
    135     asm volatile("clflush (%0)" :: "r" (vaddr));
    136     asm volatile("mfence");
    137 #elif defined(STRESSAPPTEST_CPU_ARMV7A)
    138   #warning "Unsupported CPU type ARMV7A: Unable to force cache flushes."
    139 #else
    140   #warning "Unsupported CPU type: Unable to force cache flushes."
    141 #endif
    142   }
    143 
    144   // Get time in cpu timer ticks. Useful for matching MCEs with software
    145   // actions.
    146   inline static uint64 GetTimestamp(void) {
    147     uint64 tsc;
    148 #ifdef STRESSAPPTEST_CPU_PPC
    149     uint32 tbl, tbu, temp;
    150     __asm __volatile(
    151       "1:\n"
    152       "mftbu  %2\n"
    153       "mftb   %0\n"
    154       "mftbu  %1\n"
    155       "cmpw   %2,%1\n"
    156       "bne    1b\n"
    157       : "=r"(tbl), "=r"(tbu), "=r"(temp)
    158       :
    159       : "cc");
    160 
    161     tsc = (static_cast<uint64>(tbu) << 32) | static_cast<uint64>(tbl);
    162 #elif defined(STRESSAPPTEST_CPU_X86_64) || defined(STRESSAPPTEST_CPU_I686)
    163     datacast_t data;
    164     __asm __volatile("rdtsc" : "=a" (data.l32.l), "=d"(data.l32.h));
    165     tsc = data.l64;
    166 #elif defined(STRESSAPPTEST_CPU_ARMV7A)
    167   #warning "Unsupported CPU type ARMV7A: your build may not function correctly"
    168     tsc = 0;
    169 #else
    170   #warning "Unsupported CPU type: your build may not function correctly"
    171     tsc = 0;
    172 #endif
    173     return (tsc);
    174   }
    175 
    176   // Find the free memory on the machine.
    177   virtual int64 FindFreeMemSize();
    178 
    179   // Allocates test memory of length bytes.
    180   // Subclasses must implement this.
    181   // Call PepareTestMem to get a pointer.
    182   virtual int64 AllocateAllMem();  // Returns length.
    183   // Returns success.
    184   virtual bool AllocateTestMem(int64 length, uint64 paddr_base);
    185   virtual void FreeTestMem();
    186 
    187   // Prepares the memory for use. You must call this
    188   // before using test memory, and after you are done.
    189   virtual void *PrepareTestMem(uint64 offset, uint64 length);
    190   virtual void ReleaseTestMem(void *addr, uint64 offset, uint64 length);
    191 
    192   // Machine type detected. Can we implement all these functions correctly?
    193   // Returns true if machine type is detected and implemented.
    194   virtual bool IsSupported();
    195 
    196   // Returns 32 for 32-bit, 64 for 64-bit.
    197   virtual int AddressMode();
    198   // Update OsLayer state regarding cpu support for various features.
    199   virtual void GetFeatures();
    200 
    201   // Open, read, write pci cfg through /proc/bus/pci. fd is /proc/pci file.
    202   virtual int PciOpen(int bus, int device, int function);
    203   virtual void PciWrite(int fd, uint32 offset, uint32 value, int width);
    204   virtual uint32 PciRead(int fd, uint32 offset, int width);
    205 
    206   // Read MSRs
    207   virtual bool ReadMSR(uint32 core, uint32 address, uint64 *data);
    208   virtual bool WriteMSR(uint32 core, uint32 address, uint64 *data);
    209 
    210   // Extract bits [n+len-1, n] from a 32 bit word.
    211   // so GetBitField(0x0f00, 8, 4) == 0xf.
    212   virtual uint32 GetBitField(uint32 val, uint32 n, uint32 len);
    213 
    214   // Platform and CPU specific CPU-stressing function.
    215   // Returns true on success, false otherwise.
    216   virtual bool CpuStressWorkload();
    217 
    218   // Causes false errors for unittesting.
    219   // Setting to "true" causes errors to be injected.
    220   void set_error_injection(bool errors) { error_injection_ = errors; }
    221   bool error_injection() const { return error_injection_; }
    222 
    223   // Is SAT using normal malloc'd memory, or exotic mmap'd memory.
    224   bool normal_mem() const { return normal_mem_; }
    225 
    226   // Get numa config, if available..
    227   int num_nodes() const { return num_nodes_; }
    228   int num_cpus() const { return num_cpus_; }
    229 
    230   // Handle to platform-specific error diagnoser.
    231   ErrorDiag *error_diagnoser_;
    232 
    233   // Detect all PCI Devices.
    234   virtual PCIDevices GetPCIDevices();
    235 
    236   // Disambiguate between different "warm" memcopies.
    237   virtual bool AdlerMemcpyWarm(uint64 *dstmem, uint64 *srcmem,
    238                                unsigned int size_in_bytes,
    239                                AdlerChecksum *checksum);
    240 
    241   // Store a callback to use to print
    242   // app-specific info about the last error location.
    243   // This call back is called with a physical address, and the app can fill in
    244   // the most recent transaction that occurred at that address.
    245   typedef bool (*ErrCallback)(uint64 paddr, string *buf);
    246   void set_err_log_callback(
    247     ErrCallback err_log_callback) {
    248     err_log_callback_ = err_log_callback;
    249   }
    250   ErrCallback get_err_log_callback() { return err_log_callback_; }
    251 
    252  protected:
    253   void *testmem_;                // Location of test memory.
    254   uint64 testmemsize_;           // Size of test memory.
    255   int64 totalmemsize_;           // Size of available memory.
    256   int64 min_hugepages_bytes_;    // Minimum hugepages size.
    257   bool  error_injection_;        // Do error injection?
    258   bool  normal_mem_;             // Memory DMA capable?
    259   bool  use_hugepages_;          // Use hugepage shmem?
    260   bool  use_posix_shm_;          // Use 4k page shmem?
    261   bool  dynamic_mapped_shmem_;   // Conserve virtual address space.
    262   int   shmid_;                  // Handle to shmem
    263 
    264   int64 regionsize_;             // Size of memory "regions"
    265   int   regioncount_;            // Number of memory "regions"
    266   int   num_cpus_;               // Number of cpus in the system.
    267   int   num_nodes_;              // Number of nodes in the system.
    268   int   num_cpus_per_node_;      // Number of cpus per node in the system.
    269   int   address_mode_;           // Are we running 32 or 64 bit?
    270   bool  has_sse2_;               // Do we have sse2 instructions?
    271   bool  has_clflush_;            // Do we have clflush instructions?
    272   bool  use_flush_page_cache_;   // Do we need to flush the page cache?
    273 
    274 
    275   time_t time_initialized_;      // Start time of test.
    276 
    277   vector<cpu_set_t> cpu_sets_;   // Cache for cpu masks.
    278   vector<bool> cpu_sets_valid_;  // If the cpu mask cache is valid.
    279 
    280   // Get file descriptor for dev msr.
    281   virtual int OpenMSR(uint32 core, uint32 address);
    282   // Auxiliary methods for PCI device configuration
    283   int PCIGetValue(string name, string object);
    284   int PCIGetResources(string name, PCIDevice *device);
    285 
    286   // Look up how many hugepages there are.
    287   virtual int64 FindHugePages();
    288 
    289   // Link to find last transaction at an error location.
    290   ErrCallback err_log_callback_;
    291 
    292  private:
    293   DISALLOW_COPY_AND_ASSIGN(OsLayer);
    294 };
    295 
    296 // Selects and returns the proper OS and hardware interface.  Does not call
    297 // OsLayer::Initialize() on the new object.
    298 OsLayer *OsLayerFactory(const std::map<std::string, std::string> &options);
    299 
    300 #endif  // STRESSAPPTEST_OS_H_ NOLINT
    301