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