PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/external/stressapptest/src/os.cc

https://gitlab.com/brian0218/rk3188_r-box_android4.2.2_sdk
C++ | 909 lines | 676 code | 124 blank | 109 comment | 139 complexity | bf5ef2914dd3dd84aa7269062a722fd4 MD5 | raw file
  1. // Copyright 2006 Google Inc. All Rights Reserved.
  2. // Author: nsanders, menderico
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. // Unless required by applicable law or agreed to in writing, software
  8. // distributed under the License is distributed on an "AS IS" BASIS,
  9. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. // See the License for the specific language governing permissions and
  11. // limitations under the License.
  12. // os.cc : os and machine specific implementation
  13. // This file includes an abstracted interface
  14. // for linux-distro specific and HW specific
  15. // interfaces.
  16. #include "os.h"
  17. #include <errno.h>
  18. #include <fcntl.h>
  19. #include <linux/types.h>
  20. #include <malloc.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <sys/mman.h>
  25. #include <sys/ioctl.h>
  26. #include <sys/time.h>
  27. #include <sys/types.h>
  28. #include <sys/ipc.h>
  29. #ifdef HAVE_SYS_SHM_H
  30. #include <sys/shm.h>
  31. #endif
  32. #include <unistd.h>
  33. #ifndef SHM_HUGETLB
  34. #define SHM_HUGETLB 04000 // remove when glibc defines it
  35. #endif
  36. #include <string>
  37. #include <list>
  38. // This file must work with autoconf on its public version,
  39. // so these includes are correct.
  40. #include "sattypes.h"
  41. #include "error_diag.h"
  42. // OsLayer initialization.
  43. OsLayer::OsLayer() {
  44. testmem_ = 0;
  45. testmemsize_ = 0;
  46. totalmemsize_ = 0;
  47. min_hugepages_bytes_ = 0;
  48. normal_mem_ = true;
  49. use_hugepages_ = false;
  50. use_posix_shm_ = false;
  51. dynamic_mapped_shmem_ = false;
  52. shmid_ = 0;
  53. time_initialized_ = 0;
  54. regionsize_ = 0;
  55. regioncount_ = 1;
  56. num_cpus_ = 0;
  57. num_nodes_ = 0;
  58. num_cpus_per_node_ = 0;
  59. error_diagnoser_ = 0;
  60. err_log_callback_ = 0;
  61. error_injection_ = false;
  62. void *pvoid = 0;
  63. address_mode_ = sizeof(pvoid) * 8;
  64. has_clflush_ = false;
  65. has_sse2_ = false;
  66. use_flush_page_cache_ = false;
  67. }
  68. // OsLayer cleanup.
  69. OsLayer::~OsLayer() {
  70. if (error_diagnoser_)
  71. delete error_diagnoser_;
  72. }
  73. // OsLayer initialization.
  74. bool OsLayer::Initialize() {
  75. time_initialized_ = time(NULL);
  76. // Detect asm support.
  77. GetFeatures();
  78. if (num_cpus_ == 0) {
  79. num_nodes_ = 1;
  80. num_cpus_ = sysconf(_SC_NPROCESSORS_ONLN);
  81. num_cpus_per_node_ = num_cpus_ / num_nodes_;
  82. }
  83. logprintf(5, "Log: %d nodes, %d cpus.\n", num_nodes_, num_cpus_);
  84. sat_assert(CPU_SETSIZE >= num_cpus_);
  85. cpu_sets_.resize(num_nodes_);
  86. cpu_sets_valid_.resize(num_nodes_);
  87. // Create error diagnoser.
  88. error_diagnoser_ = new ErrorDiag();
  89. if (!error_diagnoser_->set_os(this))
  90. return false;
  91. return true;
  92. }
  93. // Machine type detected. Can we implement all these functions correctly?
  94. bool OsLayer::IsSupported() {
  95. if (kOpenSource) {
  96. // There are no explicitly supported systems in open source version.
  97. return true;
  98. }
  99. // This is the default empty implementation.
  100. // SAT won't report full error information.
  101. return false;
  102. }
  103. int OsLayer::AddressMode() {
  104. // Detect 32/64 bit binary.
  105. void *pvoid = 0;
  106. return sizeof(pvoid) * 8;
  107. }
  108. // Translates user virtual to physical address.
  109. uint64 OsLayer::VirtualToPhysical(void *vaddr) {
  110. // Needs platform specific implementation.
  111. return 0;
  112. }
  113. // Returns the HD device that contains this file.
  114. string OsLayer::FindFileDevice(string filename) {
  115. return "hdUnknown";
  116. }
  117. // Returns a list of locations corresponding to HD devices.
  118. list<string> OsLayer::FindFileDevices() {
  119. // No autodetection on unknown systems.
  120. list<string> locations;
  121. return locations;
  122. }
  123. // Get HW core features from cpuid instruction.
  124. void OsLayer::GetFeatures() {
  125. #if defined(STRESSAPPTEST_CPU_X86_64) || defined(STRESSAPPTEST_CPU_I686)
  126. // CPUID features documented at:
  127. // http://www.sandpile.org/ia32/cpuid.htm
  128. int ax, bx, cx, dx;
  129. __asm__ __volatile__ (
  130. "cpuid": "=a" (ax), "=b" (bx), "=c" (cx), "=d" (dx) : "a" (1));
  131. has_clflush_ = (dx >> 19) & 1;
  132. has_sse2_ = (dx >> 26) & 1;
  133. logprintf(9, "Log: has clflush: %s, has sse2: %s\n",
  134. has_clflush_ ? "true" : "false",
  135. has_sse2_ ? "true" : "false");
  136. #elif defined(STRESSAPPTEST_CPU_PPC)
  137. // All PPC implementations have cache flush instructions.
  138. has_clflush_ = true;
  139. #elif defined(STRESSAPPTEST_CPU_ARMV7A)
  140. #warning "Unsupported CPU type ARMV7A: unable to determine feature set."
  141. #else
  142. #warning "Unsupported CPU type: unable to determine feature set."
  143. #endif
  144. }
  145. // Enable FlushPageCache to be functional instead of a NOP.
  146. void OsLayer::ActivateFlushPageCache(void) {
  147. logprintf(9, "Log: page cache will be flushed as needed\n");
  148. use_flush_page_cache_ = true;
  149. }
  150. // Flush the page cache to ensure reads come from the disk.
  151. bool OsLayer::FlushPageCache(void) {
  152. if (!use_flush_page_cache_)
  153. return true;
  154. // First, ask the kernel to write the cache to the disk.
  155. sync();
  156. // Second, ask the kernel to empty the cache by writing "1" to
  157. // "/proc/sys/vm/drop_caches".
  158. static const char *drop_caches_file = "/proc/sys/vm/drop_caches";
  159. int dcfile = open(drop_caches_file, O_WRONLY);
  160. if (dcfile < 0) {
  161. int err = errno;
  162. string errtxt = ErrorString(err);
  163. logprintf(3, "Log: failed to open %s - err %d (%s)\n",
  164. drop_caches_file, err, errtxt.c_str());
  165. return false;
  166. }
  167. ssize_t bytes_written = write(dcfile, "1", 1);
  168. close(dcfile);
  169. if (bytes_written != 1) {
  170. int err = errno;
  171. string errtxt = ErrorString(err);
  172. logprintf(3, "Log: failed to write %s - err %d (%s)\n",
  173. drop_caches_file, err, errtxt.c_str());
  174. return false;
  175. }
  176. return true;
  177. }
  178. // We need to flush the cacheline here.
  179. void OsLayer::Flush(void *vaddr) {
  180. // Use the generic flush. This function is just so we can override
  181. // this if we are so inclined.
  182. if (has_clflush_)
  183. FastFlush(vaddr);
  184. }
  185. // Run C or ASM copy as appropriate..
  186. bool OsLayer::AdlerMemcpyWarm(uint64 *dstmem, uint64 *srcmem,
  187. unsigned int size_in_bytes,
  188. AdlerChecksum *checksum) {
  189. if (has_sse2_) {
  190. return AdlerMemcpyAsm(dstmem, srcmem, size_in_bytes, checksum);
  191. } else {
  192. return AdlerMemcpyWarmC(dstmem, srcmem, size_in_bytes, checksum);
  193. }
  194. }
  195. // Translate user virtual to physical address.
  196. int OsLayer::FindDimm(uint64 addr, char *buf, int len) {
  197. char tmpbuf[256];
  198. snprintf(tmpbuf, sizeof(tmpbuf), "DIMM Unknown");
  199. snprintf(buf, len, "%s", tmpbuf);
  200. return 0;
  201. }
  202. // Classifies addresses according to "regions"
  203. // This isn't really implemented meaningfully here..
  204. int32 OsLayer::FindRegion(uint64 addr) {
  205. static bool warned = false;
  206. if (regionsize_ == 0) {
  207. regionsize_ = totalmemsize_ / 8;
  208. if (regionsize_ < 512 * kMegabyte)
  209. regionsize_ = 512 * kMegabyte;
  210. regioncount_ = totalmemsize_ / regionsize_;
  211. if (regioncount_ < 1) regioncount_ = 1;
  212. }
  213. int32 region_num = addr / regionsize_;
  214. if (region_num >= regioncount_) {
  215. if (!warned) {
  216. logprintf(0, "Log: region number %d exceeds region count %d\n",
  217. region_num, regioncount_);
  218. warned = true;
  219. }
  220. region_num = region_num % regioncount_;
  221. }
  222. return region_num;
  223. }
  224. // Report which cores are associated with a given region.
  225. cpu_set_t *OsLayer::FindCoreMask(int32 region) {
  226. sat_assert(region >= 0);
  227. region %= num_nodes_;
  228. if (!cpu_sets_valid_[region]) {
  229. CPU_ZERO(&cpu_sets_[region]);
  230. for (int i = 0; i < num_cpus_per_node_; ++i) {
  231. CPU_SET(i + region * num_cpus_per_node_, &cpu_sets_[region]);
  232. }
  233. cpu_sets_valid_[region] = true;
  234. logprintf(5, "Log: Region %d mask 0x%s\n",
  235. region, FindCoreMaskFormat(region).c_str());
  236. }
  237. return &cpu_sets_[region];
  238. }
  239. // Return cores associated with a given region in hex string.
  240. string OsLayer::FindCoreMaskFormat(int32 region) {
  241. cpu_set_t* mask = FindCoreMask(region);
  242. string format = cpuset_format(mask);
  243. if (format.size() < 8)
  244. format = string(8 - format.size(), '0') + format;
  245. return format;
  246. }
  247. // Report an error in an easily parseable way.
  248. bool OsLayer::ErrorReport(const char *part, const char *symptom, int count) {
  249. time_t now = time(NULL);
  250. int ttf = now - time_initialized_;
  251. logprintf(0, "Report Error: %s : %s : %d : %ds\n", symptom, part, count, ttf);
  252. return true;
  253. }
  254. // Read the number of hugepages out of the kernel interface in proc.
  255. int64 OsLayer::FindHugePages() {
  256. char buf[65] = "0";
  257. // This is a kernel interface to query the numebr of hugepages
  258. // available in the system.
  259. static const char *hugepages_info_file = "/proc/sys/vm/nr_hugepages";
  260. int hpfile = open(hugepages_info_file, O_RDONLY);
  261. ssize_t bytes_read = read(hpfile, buf, 64);
  262. close(hpfile);
  263. if (bytes_read <= 0) {
  264. logprintf(12, "Log: /proc/sys/vm/nr_hugepages "
  265. "read did not provide data\n");
  266. return 0;
  267. }
  268. if (bytes_read == 64) {
  269. logprintf(0, "Process Error: /proc/sys/vm/nr_hugepages "
  270. "is surprisingly large\n");
  271. return 0;
  272. }
  273. // Add a null termintation to be string safe.
  274. buf[bytes_read] = '\0';
  275. // Read the page count.
  276. int64 pages = strtoull(buf, NULL, 10); // NOLINT
  277. return pages;
  278. }
  279. int64 OsLayer::FindFreeMemSize() {
  280. int64 size = 0;
  281. int64 minsize = 0;
  282. if (totalmemsize_ > 0)
  283. return totalmemsize_;
  284. int64 pages = sysconf(_SC_PHYS_PAGES);
  285. int64 avpages = sysconf(_SC_AVPHYS_PAGES);
  286. int64 pagesize = sysconf(_SC_PAGESIZE);
  287. int64 physsize = pages * pagesize;
  288. int64 avphyssize = avpages * pagesize;
  289. // Assume 2MB hugepages.
  290. int64 hugepagesize = FindHugePages() * 2 * kMegabyte;
  291. if ((pages == -1) || (pagesize == -1)) {
  292. logprintf(0, "Process Error: sysconf could not determine memory size.\n");
  293. return 0;
  294. }
  295. // We want to leave enough stuff for things to run.
  296. // If the user specified a minimum amount of memory to expect, require that.
  297. // Otherwise, if more than 2GB is present, leave 192M + 5% for other stuff.
  298. // If less than 2GB is present use 85% of what's available.
  299. // These are fairly arbitrary numbers that seem to work OK.
  300. //
  301. // TODO(nsanders): is there a more correct way to determine target
  302. // memory size?
  303. if (hugepagesize > 0 && min_hugepages_bytes_ > 0) {
  304. minsize = min_hugepages_bytes_;
  305. } else if (physsize < 2048LL * kMegabyte) {
  306. minsize = ((pages * 85) / 100) * pagesize;
  307. } else {
  308. minsize = ((pages * 95) / 100) * pagesize - (192 * kMegabyte);
  309. }
  310. // Use hugepage sizing if available.
  311. if (hugepagesize > 0) {
  312. if (hugepagesize < minsize) {
  313. logprintf(0, "Procedural Error: Not enough hugepages. "
  314. "%lldMB available < %lldMB required.\n",
  315. hugepagesize / kMegabyte,
  316. minsize / kMegabyte);
  317. // Require the calculated minimum amount of memory.
  318. size = minsize;
  319. } else {
  320. // Require that we get all hugepages.
  321. size = hugepagesize;
  322. }
  323. } else {
  324. // Require the calculated minimum amount of memory.
  325. size = minsize;
  326. }
  327. logprintf(5, "Log: Total %lld MB. Free %lld MB. Hugepages %lld MB. "
  328. "Targeting %lld MB (%lld%%)\n",
  329. physsize / kMegabyte,
  330. avphyssize / kMegabyte,
  331. hugepagesize / kMegabyte,
  332. size / kMegabyte,
  333. size * 100 / physsize);
  334. totalmemsize_ = size;
  335. return size;
  336. }
  337. // Allocates all memory available.
  338. int64 OsLayer::AllocateAllMem() {
  339. int64 length = FindFreeMemSize();
  340. bool retval = AllocateTestMem(length, 0);
  341. if (retval)
  342. return length;
  343. else
  344. return 0;
  345. }
  346. // Allocate the target memory. This may be from malloc, hugepage pool
  347. // or other platform specific sources.
  348. bool OsLayer::AllocateTestMem(int64 length, uint64 paddr_base) {
  349. // Try hugepages first.
  350. void *buf = 0;
  351. sat_assert(length >= 0);
  352. if (paddr_base)
  353. logprintf(0, "Process Error: non zero paddr_base %#llx is not supported,"
  354. " ignore.\n", paddr_base);
  355. // Determine optimal memory allocation path.
  356. bool prefer_hugepages = false;
  357. bool prefer_posix_shm = false;
  358. bool prefer_dynamic_mapping = false;
  359. // Are there enough hugepages?
  360. int64 hugepagesize = FindHugePages() * 2 * kMegabyte;
  361. // TODO(nsanders): Is there enough /dev/shm? Is there enough free memeory?
  362. if ((length >= 1400LL * kMegabyte) && (address_mode_ == 32)) {
  363. prefer_dynamic_mapping = true;
  364. prefer_posix_shm = true;
  365. logprintf(3, "Log: Prefer POSIX shared memory allocation.\n");
  366. logprintf(3, "Log: You may need to run "
  367. "'sudo mount -o remount,size=100\% /dev/shm.'\n");
  368. } else if (hugepagesize >= length) {
  369. prefer_hugepages = true;
  370. logprintf(3, "Log: Prefer using hugepace allocation.\n");
  371. } else {
  372. logprintf(3, "Log: Prefer plain malloc memory allocation.\n");
  373. }
  374. #ifdef HAVE_SYS_SHM_H
  375. // Allocate hugepage mapped memory.
  376. if (prefer_hugepages) {
  377. do { // Allow break statement.
  378. int shmid;
  379. void *shmaddr;
  380. if ((shmid = shmget(2, length,
  381. SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W)) < 0) {
  382. int err = errno;
  383. string errtxt = ErrorString(err);
  384. logprintf(3, "Log: failed to allocate shared hugepage "
  385. "object - err %d (%s)\n",
  386. err, errtxt.c_str());
  387. logprintf(3, "Log: sysctl -w vm.nr_hugepages=XXX allows hugepages.\n");
  388. break;
  389. }
  390. shmaddr = shmat(shmid, NULL, NULL);
  391. if (shmaddr == reinterpret_cast<void*>(-1)) {
  392. int err = errno;
  393. string errtxt = ErrorString(err);
  394. logprintf(0, "Log: failed to attach shared "
  395. "hugepage object - err %d (%s).\n",
  396. err, errtxt.c_str());
  397. if (shmctl(shmid, IPC_RMID, NULL) < 0) {
  398. int err = errno;
  399. string errtxt = ErrorString(err);
  400. logprintf(0, "Log: failed to remove shared "
  401. "hugepage object - err %d (%s).\n",
  402. err, errtxt.c_str());
  403. }
  404. break;
  405. }
  406. use_hugepages_ = true;
  407. shmid_ = shmid;
  408. buf = shmaddr;
  409. logprintf(0, "Log: Using shared hugepage object 0x%x at %p.\n",
  410. shmid, shmaddr);
  411. } while (0);
  412. }
  413. if ((!use_hugepages_) && prefer_posix_shm) {
  414. do {
  415. int shm_object;
  416. void *shmaddr = NULL;
  417. shm_object = shm_open("/stressapptest", O_CREAT | O_RDWR, S_IRWXU);
  418. if (shm_object < 0) {
  419. int err = errno;
  420. string errtxt = ErrorString(err);
  421. logprintf(3, "Log: failed to allocate shared "
  422. "smallpage object - err %d (%s)\n",
  423. err, errtxt.c_str());
  424. break;
  425. }
  426. if (0 > ftruncate(shm_object, length)) {
  427. int err = errno;
  428. string errtxt = ErrorString(err);
  429. logprintf(3, "Log: failed to ftruncate shared "
  430. "smallpage object - err %d (%s)\n",
  431. err, errtxt.c_str());
  432. break;
  433. }
  434. // 32 bit linux apps can only use ~1.4G of address space.
  435. // Use dynamic mapping for allocations larger than that.
  436. // Currently perf hit is ~10% for this.
  437. if (prefer_dynamic_mapping) {
  438. dynamic_mapped_shmem_ = true;
  439. } else {
  440. // Do a full mapping here otherwise.
  441. shmaddr = mmap64(NULL, length, PROT_READ | PROT_WRITE,
  442. MAP_SHARED | MAP_NORESERVE | MAP_LOCKED | MAP_POPULATE,
  443. shm_object, NULL);
  444. if (shmaddr == reinterpret_cast<void*>(-1)) {
  445. int err = errno;
  446. string errtxt = ErrorString(err);
  447. logprintf(0, "Log: failed to map shared "
  448. "smallpage object - err %d (%s).\n",
  449. err, errtxt.c_str());
  450. break;
  451. }
  452. }
  453. use_posix_shm_ = true;
  454. shmid_ = shm_object;
  455. buf = shmaddr;
  456. char location_message[256] = "";
  457. if (dynamic_mapped_shmem_) {
  458. sprintf(location_message, "mapped as needed");
  459. } else {
  460. sprintf(location_message, "at %p", shmaddr);
  461. }
  462. logprintf(0, "Log: Using posix shared memory object 0x%x %s.\n",
  463. shm_object, location_message);
  464. } while (0);
  465. shm_unlink("/stressapptest");
  466. }
  467. #endif // HAVE_SYS_SHM_H
  468. if (!use_hugepages_ && !use_posix_shm_) {
  469. // Use memalign to ensure that blocks are aligned enough for disk direct IO.
  470. buf = static_cast<char*>(memalign(4096, length));
  471. if (buf) {
  472. logprintf(0, "Log: Using memaligned allocation at %p.\n", buf);
  473. } else {
  474. logprintf(0, "Process Error: memalign returned 0\n");
  475. if ((length >= 1499LL * kMegabyte) && (address_mode_ == 32)) {
  476. logprintf(0, "Log: You are trying to allocate > 1.4G on a 32 "
  477. "bit process. Please setup shared memory.\n");
  478. }
  479. }
  480. }
  481. testmem_ = buf;
  482. if (buf || dynamic_mapped_shmem_) {
  483. testmemsize_ = length;
  484. } else {
  485. testmemsize_ = 0;
  486. }
  487. return (buf != 0) || dynamic_mapped_shmem_;
  488. }
  489. // Free the test memory.
  490. void OsLayer::FreeTestMem() {
  491. if (testmem_) {
  492. if (use_hugepages_) {
  493. #ifdef HAVE_SYS_SHM_H
  494. shmdt(testmem_);
  495. shmctl(shmid_, IPC_RMID, NULL);
  496. #endif
  497. } else if (use_posix_shm_) {
  498. if (!dynamic_mapped_shmem_) {
  499. munmap(testmem_, testmemsize_);
  500. }
  501. close(shmid_);
  502. } else {
  503. free(testmem_);
  504. }
  505. testmem_ = 0;
  506. testmemsize_ = 0;
  507. }
  508. }
  509. // Prepare the target memory. It may requre mapping in, or this may be a noop.
  510. void *OsLayer::PrepareTestMem(uint64 offset, uint64 length) {
  511. sat_assert((offset + length) <= testmemsize_);
  512. if (dynamic_mapped_shmem_) {
  513. // TODO(nsanders): Check if we can support MAP_NONBLOCK,
  514. // and evaluate performance hit from not using it.
  515. #ifdef HAVE_MMAP64
  516. void * mapping = mmap64(NULL, length, PROT_READ | PROT_WRITE,
  517. MAP_SHARED | MAP_NORESERVE | MAP_LOCKED | MAP_POPULATE,
  518. shmid_, offset);
  519. #else
  520. void * mapping = mmap(NULL, length, PROT_READ | PROT_WRITE,
  521. MAP_SHARED | MAP_NORESERVE | MAP_LOCKED | MAP_POPULATE,
  522. shmid_, offset);
  523. #endif
  524. if (mapping == MAP_FAILED) {
  525. string errtxt = ErrorString(errno);
  526. logprintf(0, "Process Error: PrepareTestMem mmap64(%llx, %llx) failed. "
  527. "error: %s.\n",
  528. offset, length, errtxt.c_str());
  529. sat_assert(0);
  530. }
  531. return mapping;
  532. }
  533. return reinterpret_cast<void*>(reinterpret_cast<char*>(testmem_) + offset);
  534. }
  535. // Release the test memory resources, if any.
  536. void OsLayer::ReleaseTestMem(void *addr, uint64 offset, uint64 length) {
  537. if (dynamic_mapped_shmem_) {
  538. int retval = munmap(addr, length);
  539. if (retval == -1) {
  540. string errtxt = ErrorString(errno);
  541. logprintf(0, "Process Error: ReleaseTestMem munmap(%p, %llx) failed. "
  542. "error: %s.\n",
  543. addr, length, errtxt.c_str());
  544. sat_assert(0);
  545. }
  546. }
  547. }
  548. // No error polling on unknown systems.
  549. int OsLayer::ErrorPoll() {
  550. return 0;
  551. }
  552. // Generally, poll for errors once per second.
  553. void OsLayer::ErrorWait() {
  554. sat_sleep(1);
  555. return;
  556. }
  557. // Open a PCI bus-dev-func as a file and return its file descriptor.
  558. // Error is indicated by return value less than zero.
  559. int OsLayer::PciOpen(int bus, int device, int function) {
  560. char dev_file[256];
  561. snprintf(dev_file, sizeof(dev_file), "/proc/bus/pci/%02x/%02x.%x",
  562. bus, device, function);
  563. int fd = open(dev_file, O_RDWR);
  564. if (fd == -1) {
  565. logprintf(0, "Process Error: Unable to open PCI bus %d, device %d, "
  566. "function %d (errno %d).\n",
  567. bus, device, function, errno);
  568. return -1;
  569. }
  570. return fd;
  571. }
  572. // Read and write functions to access PCI config.
  573. uint32 OsLayer::PciRead(int fd, uint32 offset, int width) {
  574. // Strict aliasing rules lawyers will cause data corruption
  575. // on cast pointers in some gccs.
  576. union {
  577. uint32 l32;
  578. uint16 l16;
  579. uint8 l8;
  580. } datacast;
  581. datacast.l32 = 0;
  582. uint32 size = width / 8;
  583. sat_assert((width == 32) || (width == 16) || (width == 8));
  584. sat_assert(offset <= (256 - size));
  585. if (lseek(fd, offset, SEEK_SET) < 0) {
  586. logprintf(0, "Process Error: Can't seek %x\n", offset);
  587. return 0;
  588. }
  589. if (read(fd, &datacast, size) != static_cast<ssize_t>(size)) {
  590. logprintf(0, "Process Error: Can't read %x\n", offset);
  591. return 0;
  592. }
  593. // Extract the data.
  594. switch (width) {
  595. case 8:
  596. sat_assert(&(datacast.l8) == reinterpret_cast<uint8*>(&datacast));
  597. return datacast.l8;
  598. case 16:
  599. sat_assert(&(datacast.l16) == reinterpret_cast<uint16*>(&datacast));
  600. return datacast.l16;
  601. case 32:
  602. return datacast.l32;
  603. }
  604. return 0;
  605. }
  606. void OsLayer::PciWrite(int fd, uint32 offset, uint32 value, int width) {
  607. // Strict aliasing rules lawyers will cause data corruption
  608. // on cast pointers in some gccs.
  609. union {
  610. uint32 l32;
  611. uint16 l16;
  612. uint8 l8;
  613. } datacast;
  614. datacast.l32 = 0;
  615. uint32 size = width / 8;
  616. sat_assert((width == 32) || (width == 16) || (width == 8));
  617. sat_assert(offset <= (256 - size));
  618. // Cram the data into the right alignment.
  619. switch (width) {
  620. case 8:
  621. sat_assert(&(datacast.l8) == reinterpret_cast<uint8*>(&datacast));
  622. datacast.l8 = value;
  623. case 16:
  624. sat_assert(&(datacast.l16) == reinterpret_cast<uint16*>(&datacast));
  625. datacast.l16 = value;
  626. case 32:
  627. datacast.l32 = value;
  628. }
  629. if (lseek(fd, offset, SEEK_SET) < 0) {
  630. logprintf(0, "Process Error: Can't seek %x\n", offset);
  631. return;
  632. }
  633. if (write(fd, &datacast, size) != static_cast<ssize_t>(size)) {
  634. logprintf(0, "Process Error: Can't write %x to %x\n", datacast.l32, offset);
  635. return;
  636. }
  637. return;
  638. }
  639. // Open dev msr.
  640. int OsLayer::OpenMSR(uint32 core, uint32 address) {
  641. char buf[256];
  642. snprintf(buf, sizeof(buf), "/dev/cpu/%d/msr", core);
  643. int fd = open(buf, O_RDWR);
  644. if (fd < 0)
  645. return fd;
  646. uint32 pos = lseek(fd, address, SEEK_SET);
  647. if (pos != address) {
  648. close(fd);
  649. logprintf(5, "Log: can't seek to msr %x, cpu %d\n", address, core);
  650. return -1;
  651. }
  652. return fd;
  653. }
  654. bool OsLayer::ReadMSR(uint32 core, uint32 address, uint64 *data) {
  655. int fd = OpenMSR(core, address);
  656. if (fd < 0)
  657. return false;
  658. // Read from the msr.
  659. bool res = (sizeof(*data) == read(fd, data, sizeof(*data)));
  660. if (!res)
  661. logprintf(5, "Log: Failed to read msr %x core %d\n", address, core);
  662. close(fd);
  663. return res;
  664. }
  665. bool OsLayer::WriteMSR(uint32 core, uint32 address, uint64 *data) {
  666. int fd = OpenMSR(core, address);
  667. if (fd < 0)
  668. return false;
  669. // Write to the msr
  670. bool res = (sizeof(*data) == write(fd, data, sizeof(*data)));
  671. if (!res)
  672. logprintf(5, "Log: Failed to write msr %x core %d\n", address, core);
  673. close(fd);
  674. return res;
  675. }
  676. // Extract bits [n+len-1, n] from a 32 bit word.
  677. // so GetBitField(0x0f00, 8, 4) == 0xf.
  678. uint32 OsLayer::GetBitField(uint32 val, uint32 n, uint32 len) {
  679. return (val >> n) & ((1<<len) - 1);
  680. }
  681. // Generic CPU stress workload that would work on any CPU/Platform.
  682. // Float-point array moving average calculation.
  683. bool OsLayer::CpuStressWorkload() {
  684. double float_arr[100];
  685. double sum = 0;
  686. unsigned int seed = 12345;
  687. // Initialize array with random numbers.
  688. for (int i = 0; i < 100; i++) {
  689. #ifdef HAVE_RAND_R
  690. float_arr[i] = rand_r(&seed);
  691. if (rand_r(&seed) % 2)
  692. float_arr[i] *= -1.0;
  693. #else
  694. float_arr[i] = rand();
  695. if (rand() % 2)
  696. float_arr[i] *= -1.0;
  697. #endif
  698. }
  699. // Calculate moving average.
  700. for (int i = 0; i < 100000000; i++) {
  701. float_arr[i % 100] =
  702. (float_arr[i % 100] + float_arr[(i + 1) % 100] +
  703. float_arr[(i + 99) % 100]) / 3;
  704. sum += float_arr[i % 100];
  705. }
  706. // Artificial printf so the loops do not get optimized away.
  707. if (sum == 0.0)
  708. logprintf(12, "Log: I'm Feeling Lucky!\n");
  709. return true;
  710. }
  711. PCIDevices OsLayer::GetPCIDevices() {
  712. PCIDevices device_list;
  713. DIR *dir;
  714. struct dirent *buf = new struct dirent();
  715. struct dirent *entry;
  716. dir = opendir(kSysfsPath);
  717. if (!dir)
  718. logprintf(0, "Process Error: Cannot open %s", kSysfsPath);
  719. while (readdir_r(dir, buf, &entry) == 0 && entry) {
  720. PCIDevice *device;
  721. unsigned int dev, func;
  722. // ".", ".." or a special non-device perhaps.
  723. if (entry->d_name[0] == '.')
  724. continue;
  725. device = new PCIDevice();
  726. if (sscanf(entry->d_name, "%04x:%02hx:%02x.%d",
  727. &device->domain, &device->bus, &dev, &func) < 4) {
  728. logprintf(0, "Process Error: Couldn't parse %s", entry->d_name);
  729. free(device);
  730. continue;
  731. }
  732. device->dev = dev;
  733. device->func = func;
  734. device->vendor_id = PCIGetValue(entry->d_name, "vendor");
  735. device->device_id = PCIGetValue(entry->d_name, "device");
  736. PCIGetResources(entry->d_name, device);
  737. device_list.insert(device_list.end(), device);
  738. }
  739. closedir(dir);
  740. delete buf;
  741. return device_list;
  742. }
  743. int OsLayer::PCIGetValue(string name, string object) {
  744. int fd, len;
  745. char filename[256];
  746. char buf[256];
  747. snprintf(filename, sizeof(filename), "%s/%s/%s", kSysfsPath,
  748. name.c_str(), object.c_str());
  749. fd = open(filename, O_RDONLY);
  750. if (fd < 0)
  751. return 0;
  752. len = read(fd, buf, 256);
  753. close(fd);
  754. buf[len] = '\0';
  755. return strtol(buf, NULL, 0); // NOLINT
  756. }
  757. int OsLayer::PCIGetResources(string name, PCIDevice *device) {
  758. char filename[256];
  759. char buf[256];
  760. FILE *file;
  761. int64 start;
  762. int64 end;
  763. int64 size;
  764. int i;
  765. snprintf(filename, sizeof(filename), "%s/%s/%s", kSysfsPath,
  766. name.c_str(), "resource");
  767. file = fopen(filename, "r");
  768. if (!file) {
  769. logprintf(0, "Process Error: impossible to find resource file for %s",
  770. filename);
  771. return errno;
  772. }
  773. for (i = 0; i < 6; i++) {
  774. if (!fgets(buf, 256, file))
  775. break;
  776. sscanf(buf, "%llx %llx", &start, &end); // NOLINT
  777. size = 0;
  778. if (start)
  779. size = end - start + 1;
  780. device->base_addr[i] = start;
  781. device->size[i] = size;
  782. }
  783. fclose(file);
  784. return 0;
  785. }