1 // Copyright 2006 Google Inc. All Rights Reserved.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 // sat.cc : a stress test for stressful testing
17 // stressapptest (or SAT, from Stressful Application Test) is a test
18 // designed to stress the system, as well as provide a comprehensive
19 // memory interface test.
21 // stressapptest can be run using memory only, or using many system components.
33 #include <sys/times.h>
36 // #define __USE_LARGEFILE64
42 // This file must work with autoconf on its public version,
43 // so these includes are correct.
44 #include "disk_blocks.h"
51 // stressapptest versioning here.
52 #ifndef PACKAGE_VERSION
53 static const char* kVersion = "1.0.0";
55 static const char* kVersion = PACKAGE_VERSION;
58 // Global stressapptest reference, for use by signal handler.
59 // This makes Sat objects not safe for multiple instances.
63 // Signal handler for catching break or kill.
65 // This must be installed after g_sat is assigned and while there is a single
68 // This must be uninstalled while there is only a single thread, and of course
69 // before g_sat is cleared or deleted.
70 void SatHandleBreak(int signal) {
75 // Opens the logfile for writing if necessary
76 bool Sat::InitializeLogfile() {
79 logfile_ = open(logfilename_,
80 O_WRONLY | O_CREAT | O_DSYNC,
81 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
83 printf("Fatal Error: cannot open file %s for logging\n",
88 // We seek to the end once instead of opening in append mode because no
89 // other processes should be writing to it while this one exists.
90 if (lseek(logfile_, 0, SEEK_END) == -1) {
91 printf("Fatal Error: cannot seek to end of logfile (%s)\n",
96 Logger::GlobalLogger()->SetLogFd(logfile_);
101 // Check that the environment is known and safe to run on.
102 // Return 1 if good, 0 if unsuppported.
103 bool Sat::CheckEnvironment() {
104 // Check that this is not a debug build. Debug builds lack
105 // enough performance to stress the system.
107 if (run_on_anything_) {
108 logprintf(1, "Log: Running DEBUG version of SAT, "
109 "with significantly reduced coverage.\n");
111 logprintf(0, "Process Error: Running DEBUG version of SAT, "
112 "with significantly reduced coverage.\n");
113 logprintf(0, "Log: Command line option '-A' bypasses this error.\n");
117 #elif !defined CHECKOPTS
118 #error Build system regression - COPTS disregarded.
121 // Use all CPUs if nothing is specified.
122 if (memory_threads_ == -1) {
123 memory_threads_ = os_->num_cpus();
124 logprintf(7, "Log: Defaulting to %d copy threads\n", memory_threads_);
127 // Use all memory if no size is specified.
129 size_mb_ = os_->FindFreeMemSize() / kMegabyte;
130 size_ = static_cast<int64>(size_mb_) * kMegabyte;
132 // Autodetect file locations.
133 if (findfiles_ && (file_threads_ == 0)) {
134 // Get a space separated sting of disk locations.
135 list<string> locations = os_->FindFileDevices();
138 while (!locations.empty()) {
139 // Copy and remove the disk name.
140 string disk = locations.back();
141 locations.pop_back();
143 logprintf(12, "Log: disk at %s\n", disk.c_str());
145 filename_.push_back(disk + "/sat_disk.a");
147 filename_.push_back(disk + "/sat_disk.b");
151 // We'd better have some memory by this point.
153 logprintf(0, "Process Error: No memory found to test.\n");
158 if (tag_mode_ && ((file_threads_ > 0) ||
159 (disk_threads_ > 0) ||
160 (net_threads_ > 0))) {
161 logprintf(0, "Process Error: Memory tag mode incompatible "
162 "with disk/network DMA.\n");
167 if ((address_mode_ == 32) &&
168 (os_->normal_mem()) &&
169 (size_ >= 1499 * kMegabyte)) {
170 if (run_on_anything_) {
171 int64 new_size_mb = 1499;
172 logprintf(1, "Log: 32 bit binary: reducing from %lldMB to %lldMB\n",
175 size_mb_ = new_size_mb;
176 size_ = size_mb_ * kMegabyte;
178 logprintf(0, "Process Error: %dMB test memory too large "
179 "for 32 bit binary.\n",
180 static_cast<int>(size_ / kMegabyte));
181 logprintf(0, "Log: Command line option '-A' bypasses this error.\n");
187 // If platform is 32 bit Xeon, floor memory size to multiple of 4.
188 if (address_mode_ == 32) {
189 size_mb_ = (size_mb_ / 4) * 4;
190 size_ = size_mb_ * kMegabyte;
191 logprintf(1, "Log: Flooring memory allocation to multiple of 4: %lldMB\n",
195 // Check if this system is on the whitelist for supported systems.
196 if (!os_->IsSupported()) {
197 if (run_on_anything_) {
198 logprintf(1, "Log: Unsupported system. Running with reduced coverage.\n");
199 // This is ok, continue on.
201 logprintf(0, "Process Error: Unsupported system, "
202 "no error reporting available\n");
203 logprintf(0, "Log: Command line option '-A' bypasses this error.\n");
212 // Allocates memory to run the test on
213 bool Sat::AllocateMemory() {
214 // Allocate our test memory.
215 bool result = os_->AllocateTestMem(size_, paddr_base_);
217 logprintf(0, "Process Error: failed to allocate memory\n");
224 // Sets up access to data patterns
225 bool Sat::InitializePatterns() {
226 // Initialize pattern data.
227 patternlist_ = new PatternList();
229 logprintf(0, "Process Error: failed to allocate patterns\n");
233 if (!patternlist_->Initialize()) {
234 logprintf(0, "Process Error: failed to initialize patternlist\n");
241 // Get any valid page, no tag specified.
242 bool Sat::GetValid(struct page_entry *pe) {
243 return GetValid(pe, kDontCareTag);
247 // Fetch and return empty and full pages into the empty and full pools.
248 bool Sat::GetValid(struct page_entry *pe, int32 tag) {
250 // Get valid page depending on implementation.
251 if (pe_q_implementation_ == SAT_FINELOCK)
252 result = finelock_q_->GetValid(pe, tag);
253 else if (pe_q_implementation_ == SAT_ONELOCK)
254 result = valid_->PopRandom(pe);
257 pe->addr = os_->PrepareTestMem(pe->offset, page_length_); // Map it.
259 // Tag this access and current pattern.
260 pe->ts = os_->GetTimestamp();
261 pe->lastpattern = pe->pattern;
263 return (pe->addr != 0); // Return success or failure.
268 bool Sat::PutValid(struct page_entry *pe) {
270 os_->ReleaseTestMem(pe->addr, pe->offset, page_length_); // Unmap the page.
273 // Put valid page depending on implementation.
274 if (pe_q_implementation_ == SAT_FINELOCK)
275 return finelock_q_->PutValid(pe);
276 else if (pe_q_implementation_ == SAT_ONELOCK)
277 return valid_->Push(pe);
282 // Get an empty page with any tag.
283 bool Sat::GetEmpty(struct page_entry *pe) {
284 return GetEmpty(pe, kDontCareTag);
287 bool Sat::GetEmpty(struct page_entry *pe, int32 tag) {
289 // Get empty page depending on implementation.
290 if (pe_q_implementation_ == SAT_FINELOCK)
291 result = finelock_q_->GetEmpty(pe, tag);
292 else if (pe_q_implementation_ == SAT_ONELOCK)
293 result = empty_->PopRandom(pe);
296 pe->addr = os_->PrepareTestMem(pe->offset, page_length_); // Map it.
297 return (pe->addr != 0); // Return success or failure.
302 bool Sat::PutEmpty(struct page_entry *pe) {
304 os_->ReleaseTestMem(pe->addr, pe->offset, page_length_); // Unmap the page.
307 // Put empty page depending on implementation.
308 if (pe_q_implementation_ == SAT_FINELOCK)
309 return finelock_q_->PutEmpty(pe);
310 else if (pe_q_implementation_ == SAT_ONELOCK)
311 return empty_->Push(pe);
316 // Set up the bitmap of physical pages in case we want to see which pages were
317 // accessed under this run of SAT.
318 void Sat::AddrMapInit() {
321 // Find about how much physical mem is in the system.
322 // TODO(nsanders): Find some way to get the max
323 // and min phys addr in the system.
324 uint64 maxsize = os_->FindFreeMemSize() * 4;
325 sat_assert(maxsize != 0);
327 // Make a bitmask of this many pages. Assume that the memory is relatively
328 // zero based. This is true on x86, typically.
329 // This is one bit per page.
330 uint64 arraysize = maxsize / 4096 / 8;
331 unsigned char *bitmap = new unsigned char[arraysize];
334 // Mark every page as 0, not seen.
335 memset(bitmap, 0, arraysize);
337 page_bitmap_size_ = maxsize;
338 page_bitmap_ = bitmap;
341 // Add the 4k pages in this block to the array of pages SAT has seen.
342 void Sat::AddrMapUpdate(struct page_entry *pe) {
346 // Go through 4k page blocks.
347 uint64 arraysize = page_bitmap_size_ / 4096 / 8;
349 char *base = reinterpret_cast<char*>(pe->addr);
350 for (int i = 0; i < page_length_; i += 4096) {
351 uint64 paddr = os_->VirtualToPhysical(base + i);
353 int offset = paddr / 4096 / 8;
354 unsigned char mask = 1 << ((paddr / 4096) % 8);
356 if (offset >= arraysize) {
357 logprintf(0, "Process Error: Physical address %#llx is "
358 "greater than expected %#llx.\n",
359 paddr, page_bitmap_size_);
362 page_bitmap_[offset] |= mask;
366 // Print out the physical memory ranges that SAT has accessed.
367 void Sat::AddrMapPrint() {
371 uint64 pages = page_bitmap_size_ / 4096;
373 uint64 last_page = 0;
374 bool valid_range = false;
376 logprintf(4, "Log: Printing tested physical ranges.\n");
378 for (uint64 i = 0; i < pages; i ++) {
380 unsigned char mask = 1 << (i % 8);
382 bool touched = page_bitmap_[offset] & mask;
383 if (touched && !valid_range) {
385 last_page = i * 4096;
386 } else if (!touched && valid_range) {
388 logprintf(4, "Log: %#016llx - %#016llx\n", last_page, (i * 4096) - 1);
391 logprintf(4, "Log: Done printing physical ranges.\n");
394 // Initializes page lists and fills pages with data patterns.
395 bool Sat::InitializePages() {
397 // Calculate needed page totals.
398 int64 neededpages = memory_threads_ +
404 // Empty-valid page ratio is adjusted depending on queue implementation.
405 // since fine-grain-locked queue keeps both valid and empty entries in the
406 // same queue and randomly traverse to find pages, the empty-valid ratio
407 // should be more even.
408 if (pe_q_implementation_ == SAT_FINELOCK)
409 freepages_ = pages_ / 5 * 2; // Mark roughly 2/5 of all pages as Empty.
411 freepages_ = (pages_ / 100) + (2 * neededpages);
413 if (freepages_ < neededpages) {
414 logprintf(0, "Process Error: freepages < neededpages.\n");
415 logprintf(1, "Stats: Total: %lld, Needed: %lld, Marked free: %lld\n",
416 static_cast<int64>(pages_),
417 static_cast<int64>(neededpages),
418 static_cast<int64>(freepages_));
423 if (freepages_ > pages_/2) {
424 logprintf(0, "Process Error: not enough pages for IO\n");
425 logprintf(1, "Stats: Total: %lld, Needed: %lld, Available: %lld\n",
426 static_cast<int64>(pages_),
427 static_cast<int64>(freepages_),
428 static_cast<int64>(pages_/2));
432 logprintf(12, "Log: Allocating pages, Total: %lld Free: %lld\n",
436 // Initialize page locations.
437 for (int64 i = 0; i < pages_; i++) {
438 struct page_entry pe;
440 pe.offset = i * page_length_;
441 result &= PutEmpty(&pe);
445 logprintf(0, "Process Error: while initializing empty_ list\n");
450 // Fill valid pages with test patterns.
451 // Use fill threads to do this.
452 WorkerStatus fill_status;
453 WorkerVector fill_vector;
455 logprintf(12, "Starting Fill threads: %d threads, %d pages\n",
456 fill_threads_, pages_);
457 // Initialize the fill threads.
458 for (int i = 0; i < fill_threads_; i++) {
459 FillThread *thread = new FillThread();
460 thread->InitThread(i, this, os_, patternlist_, &fill_status);
461 if (i != fill_threads_ - 1) {
462 logprintf(12, "Starting Fill Threads %d: %d pages\n",
463 i, pages_ / fill_threads_);
464 thread->SetFillPages(pages_ / fill_threads_);
465 // The last thread finishes up all the leftover pages.
467 logprintf(12, "Starting Fill Threads %d: %d pages\n",
468 i, pages_ - pages_ / fill_threads_ * i);
469 thread->SetFillPages(pages_ - pages_ / fill_threads_ * i);
471 fill_vector.push_back(thread);
474 // Spawn the fill threads.
475 fill_status.Initialize();
476 for (WorkerVector::const_iterator it = fill_vector.begin();
477 it != fill_vector.end(); ++it)
478 (*it)->SpawnThread();
480 // Reap the finished fill threads.
481 for (WorkerVector::const_iterator it = fill_vector.begin();
482 it != fill_vector.end(); ++it) {
484 if ((*it)->GetStatus() != 1) {
485 logprintf(0, "Thread %d failed with status %d at %.2f seconds\n",
486 (*it)->ThreadID(), (*it)->GetStatus(),
487 (*it)->GetRunDurationUSec() * 1.0/1000000);
494 fill_status.Destroy();
495 logprintf(12, "Log: Done filling pages.\n");
496 logprintf(12, "Log: Allocating pages.\n");
500 // Initialize page locations.
501 for (int64 i = 0; i < pages_; i++) {
502 struct page_entry pe;
503 // Only get valid pages with uninitialized tags here.
505 if (GetValid(&pe, kInvalidTag)) {
506 int64 paddr = os_->VirtualToPhysical(pe.addr);
507 int32 region = os_->FindRegion(paddr);
509 os_->FindDimm(paddr, buf, sizeof(buf));
511 logprintf(12, "Log: address: %#llx, %s\n", paddr, buf);
515 pe.tag = 1 << region;
516 region_mask_ |= pe.tag;
518 // Generate a physical region map
521 // Note: this does not allocate free pages among all regions
522 // fairly. However, with large enough (thousands) random number
523 // of pages being marked free in each region, the free pages
524 // count in each region end up pretty balanced.
525 if (i < freepages_) {
526 result &= PutEmpty(&pe);
528 result &= PutValid(&pe);
531 logprintf(0, "Log: didn't tag all pages. %d - %d = %d\n",
532 pages_, i, pages_ - i);
536 logprintf(12, "Log: Done allocating pages.\n");
540 for (int i = 0; i < 32; i++) {
541 if (region_mask_ & (1 << i)) {
543 logprintf(12, "Log: Region %d: %d.\n", i, region_[i]);
546 logprintf(5, "Log: Region mask: 0x%x\n", region_mask_);
551 // Print SAT version info.
552 bool Sat::PrintVersion() {
553 logprintf(1, "Stats: SAT revision %s, %d bit binary\n",
554 kVersion, address_mode_);
555 logprintf(5, "Log: %s from %s\n", Timestamp(), BuildChangelist());
561 // Initializes the resources that SAT needs to run.
562 // This needs to be called before Run(), and after ParseArgs().
563 // Returns true on success, false on error, and will exit() on help message.
564 bool Sat::Initialize() {
567 // Initializes sync'd log file to ensure output is saved.
568 if (!InitializeLogfile())
570 Logger::GlobalLogger()->StartThread();
572 logprintf(5, "Log: Commandline - %s\n", cmdline_.c_str());
575 std::map<std::string, std::string> options;
577 GoogleOsOptions(&options);
579 // Initialize OS/Hardware interface.
580 os_ = OsLayerFactory(options);
586 if (min_hugepages_mbytes_ > 0)
587 os_->SetMinimumHugepagesSize(min_hugepages_mbytes_ * kMegabyte);
589 if (!os_->Initialize()) {
590 logprintf(0, "Process Error: Failed to initialize OS layer\n");
596 // Checks that OS/Build/Platform is supported.
597 if (!CheckEnvironment())
600 if (error_injection_)
601 os_->set_error_injection(true);
603 // Run SAT in monitor only mode, do not continue to allocate resources.
605 logprintf(5, "Log: Running in monitor-only mode. "
606 "Will not allocate any memory nor run any stress test. "
607 "Only polling ECC errors.\n");
611 // Allocate the memory to test.
612 if (!AllocateMemory())
615 logprintf(5, "Stats: Starting SAT, %dM, %d seconds\n",
616 static_cast<int>(size_/kMegabyte),
619 if (!InitializePatterns())
622 // Initialize memory allocation.
623 pages_ = size_ / page_length_;
625 // Allocate page queue depending on queue implementation switch.
626 if (pe_q_implementation_ == SAT_FINELOCK) {
627 finelock_q_ = new FineLockPEQueue(pages_, page_length_);
628 if (finelock_q_ == NULL)
630 finelock_q_->set_os(os_);
631 os_->set_err_log_callback(finelock_q_->get_err_log_callback());
632 } else if (pe_q_implementation_ == SAT_ONELOCK) {
633 empty_ = new PageEntryQueue(pages_);
634 valid_ = new PageEntryQueue(pages_);
635 if ((empty_ == NULL) || (valid_ == NULL))
639 if (!InitializePages()) {
640 logprintf(0, "Process Error: Initialize Pages failed\n");
647 // Constructor and destructor.
649 // Set defaults, command line might override these.
650 runtime_seconds_ = 20;
651 page_length_ = kSatPageSize;
652 disk_pages_ = kSatDiskPage;
655 size_ = size_mb_ * kMegabyte;
656 min_hugepages_mbytes_ = 0;
662 Logger::GlobalLogger()->SetVerbosity(verbosity_);
665 run_on_anything_ = 0;
668 // Detect 32/64 bit binary.
670 address_mode_ = sizeof(pvoid) * 8;
671 error_injection_ = false;
672 crazy_error_injection_ = false;
673 max_errorcount_ = 0; // Zero means no early exit.
674 stop_on_error_ = false;
678 do_page_map_ = false;
680 page_bitmap_size_ = 0;
682 // Cache coherency data initialization.
683 cc_test_ = false; // Flag to trigger cc threads.
684 cc_cacheline_count_ = 2; // Two datastructures of cache line size.
685 cc_inc_count_ = 1000; // Number of times to increment the shared variable.
686 cc_cacheline_data_ = 0; // Cache Line size datastructure.
688 sat_assert(0 == pthread_mutex_init(&worker_lock_, NULL));
692 // Default to autodetect number of cpus, and run that many threads.
693 memory_threads_ = -1;
697 cpu_stress_threads_ = 0;
703 for (int i = 0; i < 32; i++) {
714 // Default to use fine-grain lock for better performance.
715 pe_q_implementation_ = SAT_FINELOCK;
721 read_block_size_ = 512;
722 write_block_size_ = -1;
725 blocks_per_segment_ = -1;
726 read_threshold_ = -1;
727 write_threshold_ = -1;
728 non_destructive_ = 1;
734 pause_duration_ = 15;
739 // We need to have called Cleanup() at this point.
740 // We should probably enforce this.
744 #define ARG_KVALUE(argument, variable, value) \
745 if (!strcmp(argv[i], argument)) { \
750 #define ARG_IVALUE(argument, variable) \
751 if (!strcmp(argv[i], argument)) { \
754 variable = strtoull(argv[i], NULL, 0); \
758 #define ARG_SVALUE(argument, variable) \
759 if (!strcmp(argv[i], argument)) { \
762 snprintf(variable, sizeof(variable), "%s", argv[i]); \
766 // Configures SAT from command line arguments.
767 // This will call exit() given a request for
768 // self-documentation or unexpected args.
769 bool Sat::ParseArgs(int argc, char **argv) {
771 uint64 filesize = page_length_ * disk_pages_;
773 // Parse each argument.
774 for (i = 1; i < argc; i++) {
775 // Switch to fall back to corase-grain-lock queue. (for benchmarking)
776 ARG_KVALUE("--coarse_grain_lock", pe_q_implementation_, SAT_ONELOCK);
778 // Set number of megabyte to use.
779 ARG_IVALUE("-M", size_mb_);
781 // Set minimum megabytes of hugepages to require.
782 ARG_IVALUE("-H", min_hugepages_mbytes_);
784 // Set number of seconds to run.
785 ARG_IVALUE("-s", runtime_seconds_);
787 // Set number of memory copy threads.
788 ARG_IVALUE("-m", memory_threads_);
790 // Set number of memory invert threads.
791 ARG_IVALUE("-i", invert_threads_);
793 // Set number of check-only threads.
794 ARG_IVALUE("-c", check_threads_);
796 // Set number of cache line size datastructures.
797 ARG_IVALUE("--cc_inc_count", cc_inc_count_);
799 // Set number of cache line size datastructures
800 ARG_IVALUE("--cc_line_count", cc_cacheline_count_);
802 // Flag set when cache coherency tests need to be run
803 ARG_KVALUE("--cc_test", cc_test_, 1);
805 // Set number of CPU stress threads.
806 ARG_IVALUE("-C", cpu_stress_threads_);
809 ARG_SVALUE("-l", logfilename_);
812 ARG_IVALUE("-v", verbosity_);
814 // Set maximum number of errors to collect. Stop running after this many.
815 ARG_IVALUE("--max_errors", max_errorcount_);
817 // Set pattern block size.
818 ARG_IVALUE("-p", page_length_);
820 // Set pattern block size.
821 ARG_IVALUE("--filesize", filesize);
824 ARG_KVALUE("--local_numa", region_mode_, kLocalNuma);
825 ARG_KVALUE("--remote_numa", region_mode_, kRemoteNuma);
827 // Autodetect tempfile locations.
828 ARG_KVALUE("--findfiles", findfiles_, 1);
830 // Inject errors to force miscompare code paths
831 ARG_KVALUE("--force_errors", error_injection_, true);
832 ARG_KVALUE("--force_errors_like_crazy", crazy_error_injection_, true);
833 if (crazy_error_injection_)
834 error_injection_ = true;
836 // Stop immediately on any arror, for debugging HW problems.
837 ARG_KVALUE("--stop_on_errors", stop_on_error_, 1);
839 // Don't use internal error polling, allow external detection.
840 ARG_KVALUE("--no_errors", error_poll_, 0);
842 // Never check data as you go.
843 ARG_KVALUE("-F", strict_, 0);
845 // Warm the cpu as you go.
846 ARG_KVALUE("-W", warm_, 1);
848 // Allow runnign on unknown systems with base unimplemented OsLayer
849 ARG_KVALUE("-A", run_on_anything_, 1);
851 // Size of read blocks for disk test.
852 ARG_IVALUE("--read-block-size", read_block_size_);
854 // Size of write blocks for disk test.
855 ARG_IVALUE("--write-block-size", write_block_size_);
857 // Size of segment for disk test.
858 ARG_IVALUE("--segment-size", segment_size_);
860 // Size of disk cache size for disk test.
861 ARG_IVALUE("--cache-size", cache_size_);
863 // Number of blocks to test per segment.
864 ARG_IVALUE("--blocks-per-segment", blocks_per_segment_);
866 // Maximum time a block read should take before warning.
867 ARG_IVALUE("--read-threshold", read_threshold_);
869 // Maximum time a block write should take before warning.
870 ARG_IVALUE("--write-threshold", write_threshold_);
872 // Do not write anything to disk in the disk test.
873 ARG_KVALUE("--destructive", non_destructive_, 0);
875 // Run SAT in monitor mode. No test load at all.
876 ARG_KVALUE("--monitor_mode", monitor_mode_, true);
878 // Run SAT in address mode. Tag all cachelines by virt addr.
879 ARG_KVALUE("--tag_mode", tag_mode_, true);
881 // Dump range map of tested pages..
882 ARG_KVALUE("--do_page_map", do_page_map_, true);
884 // Specify the physical address base to test.
885 ARG_IVALUE("--paddr_base", paddr_base_);
887 // Specify the frequency for power spikes.
888 ARG_IVALUE("--pause_delay", pause_delay_);
890 // Specify the duration of each pause (for power spikes).
891 ARG_IVALUE("--pause_duration", pause_duration_);
894 if (!strcmp(argv[i], "-d")) {
898 diskfilename_.push_back(string(argv[i]));
899 blocktables_.push_back(new DiskBlockTable());
904 // Set number of disk random threads for each disk write thread.
905 ARG_IVALUE("--random-threads", random_threads_);
907 // Set a tempfile to use in a file thread.
908 if (!strcmp(argv[i], "-f")) {
912 filename_.push_back(string(argv[i]));
917 // Set a hostname to use in a network thread.
918 if (!strcmp(argv[i], "-n")) {
922 ipaddrs_.push_back(string(argv[i]));
927 // Run threads that listen for incoming SAT net connections.
928 ARG_KVALUE("--listen", listen_threads_, 1);
930 if (CheckGoogleSpecificArgs(argc, argv, &i)) {
937 if (strcmp(argv[i], "-h") && strcmp(argv[i], "--help")) {
938 printf("\n Unknown argument %s\n", argv[i]);
942 // Forget it, we printed the help, just bail.
943 // We don't want to print test status, or any log parser stuff.
947 Logger::GlobalLogger()->SetVerbosity(verbosity_);
949 // Update relevant data members with parsed input.
950 // Translate MB into bytes.
951 size_ = static_cast<int64>(size_mb_) * kMegabyte;
954 if (strcmp(logfilename_, ""))
956 // Checks valid page length.
958 !(page_length_ & (page_length_ - 1)) &&
959 (page_length_ > 1023)) {
960 // Prints if we have changed from default.
961 if (page_length_ != kSatPageSize)
962 logprintf(12, "Log: Updating page size to %d\n", page_length_);
964 // Revert to default page length.
965 logprintf(6, "Process Error: "
966 "Invalid page size %d\n", page_length_);
967 page_length_ = kSatPageSize;
971 // Set disk_pages_ if filesize or page size changed.
972 if (filesize != page_length_ * disk_pages_) {
973 disk_pages_ = filesize / page_length_;
974 if (disk_pages_ == 0)
978 // Print each argument.
979 for (int i = 0; i < argc; i++) {
988 void Sat::PrintHelp() {
989 printf("Usage: ./sat(32|64) [options]\n"
990 " -M mbytes megabytes of ram to test\n"
991 " -H mbytes minimum megabytes of hugepages to require\n"
992 " -s seconds number of seconds to run\n"
993 " -m threads number of memory copy threads to run\n"
994 " -i threads number of memory invert threads to run\n"
995 " -C threads number of memory CPU stress threads to run\n"
996 " --findfiles find locations to do disk IO automatically\n"
997 " -d device add a direct write disk thread with block "
998 "device (or file) 'device'\n"
999 " -f filename add a disk thread with "
1000 "tempfile 'filename'\n"
1001 " -l logfile log output to file 'logfile'\n"
1002 " --max_errors n exit early after finding 'n' errors\n"
1003 " -v level verbosity (0-20), default is 8\n"
1004 " -W Use more CPU-stressful memory copy\n"
1005 " -A run in degraded mode on incompatible systems\n"
1006 " -p pagesize size in bytes of memory chunks\n"
1007 " --filesize size size of disk IO tempfiles\n"
1008 " -n ipaddr add a network thread connecting to "
1009 "system at 'ipaddr'\n"
1010 " --listen run a thread to listen for and respond "
1011 "to network threads.\n"
1012 " --no_errors run without checking for ECC or other errors\n"
1013 " --force_errors inject false errors to test error handling\n"
1014 " --force_errors_like_crazy inject a lot of false errors "
1015 "to test error handling\n"
1016 " -F don't result check each transaction\n"
1017 "--stop_on_errors Stop after finding the first error.\n"
1018 " --read-block-size size of block for reading (-d)\n"
1019 " --write-block-size size of block for writing (-d). If not "
1020 "defined, the size of block for writing will be defined as the "
1021 "size of block for reading\n"
1022 " --segment-size size of segments to split disk into (-d)\n"
1023 " --cache-size size of disk cache (-d)\n"
1024 " --blocks-per-segment number of blocks to read/write per "
1025 "segment per iteration (-d)\n"
1026 " --read-threshold maximum time (in us) a block read should "
1028 " --write-threshold maximum time (in us) a block write "
1029 "should take (-d)\n"
1030 " --random-threads number of random threads for each disk "
1031 "write thread (-d)\n"
1032 " --destructive write/wipe disk partition (-d)\n"
1033 " --monitor_mode only do ECC error polling, no stress load.\n"
1034 " --cc_test do the cache coherency testing\n"
1035 " --cc_inc_count number of times to increment the "
1036 "cacheline's member\n"
1037 " --cc_line_count number of cache line sized datastructures "
1038 "to allocate for the cache coherency threads to operate\n"
1039 " --paddr_base allocate memory starting from this address\n"
1040 " --pause_delay delay (in seconds) between power spikes\n"
1041 " --pause_duration duration (in seconds) of each pause\n"
1042 " --local_numa : choose memory regions associated with "
1043 "each CPU to be tested by that CPU\n"
1044 "--remote_numa : choose memory regions not associated with "
1045 "each CPU to be tested by that CPU\n");
1048 bool Sat::CheckGoogleSpecificArgs(int argc, char **argv, int *i) {
1049 // Do nothing, no google-specific argument on public stressapptest
1053 void Sat::GoogleOsOptions(std::map<std::string, std::string> *options) {
1054 // Do nothing, no OS-specific argument on public stressapptest
1057 // Launch the SAT task threads. Returns 0 on error.
1058 void Sat::InitializeThreads() {
1059 // Memory copy threads.
1060 AcquireWorkerLock();
1062 logprintf(12, "Log: Starting worker threads\n");
1063 WorkerVector *memory_vector = new WorkerVector();
1065 // Error polling thread.
1066 // This may detect ECC corrected errors, disk problems, or
1067 // any other errors normally hidden from userspace.
1068 WorkerVector *error_vector = new WorkerVector();
1070 ErrorPollThread *thread = new ErrorPollThread();
1071 thread->InitThread(total_threads_++, this, os_, patternlist_,
1072 &continuous_status_);
1074 error_vector->insert(error_vector->end(), thread);
1076 logprintf(5, "Log: Skipping error poll thread due to --no_errors flag\n");
1078 workers_map_.insert(make_pair(kErrorType, error_vector));
1080 // Only start error poll threads for monitor-mode SAT,
1081 // skip all other types of worker threads.
1082 if (monitor_mode_) {
1083 ReleaseWorkerLock();
1087 for (int i = 0; i < memory_threads_; i++) {
1088 CopyThread *thread = new CopyThread();
1089 thread->InitThread(total_threads_++, this, os_, patternlist_,
1090 &power_spike_status_);
1092 if ((region_count_ > 1) && (region_mode_)) {
1093 int32 region = region_find(i % region_count_);
1094 cpu_set_t *cpuset = os_->FindCoreMask(region);
1096 if (region_mode_ == kLocalNuma) {
1097 // Choose regions associated with this CPU.
1098 thread->set_cpu_mask(cpuset);
1099 thread->set_tag(1 << region);
1100 } else if (region_mode_ == kRemoteNuma) {
1101 // Choose regions not associated with this CPU..
1102 thread->set_cpu_mask(cpuset);
1103 thread->set_tag(region_mask_ & ~(1 << region));
1106 cpu_set_t available_cpus;
1107 thread->AvailableCpus(&available_cpus);
1108 int cores = cpuset_count(&available_cpus);
1109 // Don't restrict thread location if we have more than one
1110 // thread per core. Not so good for performance.
1111 if (cpu_stress_threads_ + memory_threads_ <= cores) {
1112 // Place a thread on alternating cores first.
1113 // This assures interleaved core use with no overlap.
1115 int nthbit = (((2 * nthcore) % cores) +
1116 (((2 * nthcore) / cores) % 2)) % cores;
1117 cpu_set_t all_cores;
1118 cpuset_set_ab(&all_cores, 0, cores);
1119 if (!cpuset_isequal(&available_cpus, &all_cores)) {
1120 // We are assuming the bits are contiguous.
1121 // Complain if this is not so.
1122 logprintf(0, "Log: cores = %s, expected %s\n",
1123 cpuset_format(&available_cpus).c_str(),
1124 cpuset_format(&all_cores).c_str());
1127 // Set thread affinity.
1128 thread->set_cpu_mask_to_cpu(nthbit);
1131 memory_vector->insert(memory_vector->end(), thread);
1133 workers_map_.insert(make_pair(kMemoryType, memory_vector));
1136 WorkerVector *fileio_vector = new WorkerVector();
1137 for (int i = 0; i < file_threads_; i++) {
1138 FileThread *thread = new FileThread();
1139 thread->InitThread(total_threads_++, this, os_, patternlist_,
1140 &power_spike_status_);
1141 thread->SetFile(filename_[i].c_str());
1142 // Set disk threads high priority. They don't take much processor time,
1143 // but blocking them will delay disk IO.
1144 thread->SetPriority(WorkerThread::High);
1146 fileio_vector->insert(fileio_vector->end(), thread);
1148 workers_map_.insert(make_pair(kFileIOType, fileio_vector));
1151 WorkerVector *netio_vector = new WorkerVector();
1152 WorkerVector *netslave_vector = new WorkerVector();
1153 if (listen_threads_ > 0) {
1154 // Create a network slave thread. This listens for connections.
1155 NetworkListenThread *thread = new NetworkListenThread();
1156 thread->InitThread(total_threads_++, this, os_, patternlist_,
1157 &continuous_status_);
1159 netslave_vector->insert(netslave_vector->end(), thread);
1161 for (int i = 0; i < net_threads_; i++) {
1162 NetworkThread *thread = new NetworkThread();
1163 thread->InitThread(total_threads_++, this, os_, patternlist_,
1164 &continuous_status_);
1165 thread->SetIP(ipaddrs_[i].c_str());
1167 netio_vector->insert(netio_vector->end(), thread);
1169 workers_map_.insert(make_pair(kNetIOType, netio_vector));
1170 workers_map_.insert(make_pair(kNetSlaveType, netslave_vector));
1172 // Result check threads.
1173 WorkerVector *check_vector = new WorkerVector();
1174 for (int i = 0; i < check_threads_; i++) {
1175 CheckThread *thread = new CheckThread();
1176 thread->InitThread(total_threads_++, this, os_, patternlist_,
1177 &continuous_status_);
1179 check_vector->insert(check_vector->end(), thread);
1181 workers_map_.insert(make_pair(kCheckType, check_vector));
1183 // Memory invert threads.
1184 logprintf(12, "Log: Starting invert threads\n");
1185 WorkerVector *invert_vector = new WorkerVector();
1186 for (int i = 0; i < invert_threads_; i++) {
1187 InvertThread *thread = new InvertThread();
1188 thread->InitThread(total_threads_++, this, os_, patternlist_,
1189 &continuous_status_);
1191 invert_vector->insert(invert_vector->end(), thread);
1193 workers_map_.insert(make_pair(kInvertType, invert_vector));
1195 // Disk stress threads.
1196 WorkerVector *disk_vector = new WorkerVector();
1197 WorkerVector *random_vector = new WorkerVector();
1198 logprintf(12, "Log: Starting disk stress threads\n");
1199 for (int i = 0; i < disk_threads_; i++) {
1200 // Creating write threads
1201 DiskThread *thread = new DiskThread(blocktables_[i]);
1202 thread->InitThread(total_threads_++, this, os_, patternlist_,
1203 &power_spike_status_);
1204 thread->SetDevice(diskfilename_[i].c_str());
1205 if (thread->SetParameters(read_block_size_, write_block_size_,
1206 segment_size_, cache_size_,
1207 blocks_per_segment_,
1208 read_threshold_, write_threshold_,
1209 non_destructive_)) {
1210 disk_vector->insert(disk_vector->end(), thread);
1212 logprintf(12, "Log: DiskThread::SetParameters() failed\n");
1216 for (int j = 0; j < random_threads_; j++) {
1217 // Creating random threads
1218 RandomDiskThread *rthread = new RandomDiskThread(blocktables_[i]);
1219 rthread->InitThread(total_threads_++, this, os_, patternlist_,
1220 &power_spike_status_);
1221 rthread->SetDevice(diskfilename_[i].c_str());
1222 if (rthread->SetParameters(read_block_size_, write_block_size_,
1223 segment_size_, cache_size_,
1224 blocks_per_segment_,
1225 read_threshold_, write_threshold_,
1226 non_destructive_)) {
1227 random_vector->insert(random_vector->end(), rthread);
1229 logprintf(12, "Log: RandomDiskThread::SetParameters() failed\n");
1235 workers_map_.insert(make_pair(kDiskType, disk_vector));
1236 workers_map_.insert(make_pair(kRandomDiskType, random_vector));
1238 // CPU stress threads.
1239 WorkerVector *cpu_vector = new WorkerVector();
1240 logprintf(12, "Log: Starting cpu stress threads\n");
1241 for (int i = 0; i < cpu_stress_threads_; i++) {
1242 CpuStressThread *thread = new CpuStressThread();
1243 thread->InitThread(total_threads_++, this, os_, patternlist_,
1244 &continuous_status_);
1246 // Don't restrict thread location if we have more than one
1247 // thread per core. Not so good for performance.
1248 cpu_set_t available_cpus;
1249 thread->AvailableCpus(&available_cpus);
1250 int cores = cpuset_count(&available_cpus);
1251 if (cpu_stress_threads_ + memory_threads_ <= cores) {
1252 // Place a thread on alternating cores first.
1253 // Go in reverse order for CPU stress threads. This assures interleaved
1254 // core use with no overlap.
1255 int nthcore = (cores - 1) - i;
1256 int nthbit = (((2 * nthcore) % cores) +
1257 (((2 * nthcore) / cores) % 2)) % cores;
1258 cpu_set_t all_cores;
1259 cpuset_set_ab(&all_cores, 0, cores);
1260 if (!cpuset_isequal(&available_cpus, &all_cores)) {
1261 logprintf(0, "Log: cores = %s, expected %s\n",
1262 cpuset_format(&available_cpus).c_str(),
1263 cpuset_format(&all_cores).c_str());
1266 // Set thread affinity.
1267 thread->set_cpu_mask_to_cpu(nthbit);
1271 cpu_vector->insert(cpu_vector->end(), thread);
1273 workers_map_.insert(make_pair(kCPUType, cpu_vector));
1275 // CPU Cache Coherency Threads - one for each core available.
1277 WorkerVector *cc_vector = new WorkerVector();
1278 logprintf(12, "Log: Starting cpu cache coherency threads\n");
1280 // Allocate the shared datastructure to be worked on by the threads.
1281 cc_cacheline_data_ = reinterpret_cast<cc_cacheline_data*>(
1282 malloc(sizeof(cc_cacheline_data) * cc_cacheline_count_));
1283 sat_assert(cc_cacheline_data_ != NULL);
1285 // Initialize the strucutre.
1286 memset(cc_cacheline_data_, 0,
1287 sizeof(cc_cacheline_data) * cc_cacheline_count_);
1289 int num_cpus = CpuCount();
1290 // Allocate all the nums once so that we get a single chunk
1291 // of contiguous memory.
1293 int err_result = posix_memalign(
1294 reinterpret_cast<void**>(&num),
1295 kCacheLineSize, sizeof(*num) * num_cpus * cc_cacheline_count_);
1296 sat_assert(err_result == 0);
1299 for (cline = 0; cline < cc_cacheline_count_; cline++) {
1300 memset(num, 0, sizeof(num_cpus) * num_cpus);
1301 cc_cacheline_data_[cline].num = num;
1306 for (tnum = 0; tnum < num_cpus; tnum++) {
1307 CpuCacheCoherencyThread *thread =
1308 new CpuCacheCoherencyThread(cc_cacheline_data_, cc_cacheline_count_,
1309 tnum, cc_inc_count_);
1310 thread->InitThread(total_threads_++, this, os_, patternlist_,
1311 &continuous_status_);
1312 // Pin the thread to a particular core.
1313 thread->set_cpu_mask_to_cpu(tnum);
1315 // Insert the thread into the vector.
1316 cc_vector->insert(cc_vector->end(), thread);
1318 workers_map_.insert(make_pair(kCCType, cc_vector));
1320 ReleaseWorkerLock();
1323 // Return the number of cpus actually present in the machine.
1324 int Sat::CpuCount() {
1325 return sysconf(_SC_NPROCESSORS_CONF);
1328 // Notify and reap worker threads.
1329 void Sat::JoinThreads() {
1330 logprintf(12, "Log: Joining worker threads\n");
1331 power_spike_status_.StopWorkers();
1332 continuous_status_.StopWorkers();
1334 AcquireWorkerLock();
1335 for (WorkerMap::const_iterator map_it = workers_map_.begin();
1336 map_it != workers_map_.end(); ++map_it) {
1337 for (WorkerVector::const_iterator it = map_it->second->begin();
1338 it != map_it->second->end(); ++it) {
1339 logprintf(12, "Log: Joining thread %d\n", (*it)->ThreadID());
1340 (*it)->JoinThread();
1343 ReleaseWorkerLock();
1347 // Finish up result checking.
1348 // Spawn 4 check threads to minimize check time.
1349 logprintf(12, "Log: Finished countdown, begin to result check\n");
1350 WorkerStatus reap_check_status;
1351 WorkerVector reap_check_vector;
1353 // No need for check threads for monitor mode.
1354 if (!monitor_mode_) {
1355 // Initialize the check threads.
1356 for (int i = 0; i < fill_threads_; i++) {
1357 CheckThread *thread = new CheckThread();
1358 thread->InitThread(total_threads_++, this, os_, patternlist_,
1359 &reap_check_status);
1360 logprintf(12, "Log: Finished countdown, begin to result check\n");
1361 reap_check_vector.push_back(thread);
1365 reap_check_status.Initialize();
1366 // Check threads should be marked to stop ASAP.
1367 reap_check_status.StopWorkers();
1369 // Spawn the check threads.
1370 for (WorkerVector::const_iterator it = reap_check_vector.begin();
1371 it != reap_check_vector.end(); ++it) {
1372 logprintf(12, "Log: Spawning thread %d\n", (*it)->ThreadID());
1373 (*it)->SpawnThread();
1376 // Join the check threads.
1377 for (WorkerVector::const_iterator it = reap_check_vector.begin();
1378 it != reap_check_vector.end(); ++it) {
1379 logprintf(12, "Log: Joining thread %d\n", (*it)->ThreadID());
1380 (*it)->JoinThread();
1383 // Reap all children. Stopped threads should have already ended.
1384 // Result checking threads will end when they have finished
1386 logprintf(12, "Log: Join all outstanding threads\n");
1389 errorcount_ = GetTotalErrorCount();
1391 AcquireWorkerLock();
1392 for (WorkerMap::const_iterator map_it = workers_map_.begin();
1393 map_it != workers_map_.end(); ++map_it) {
1394 for (WorkerVector::const_iterator it = map_it->second->begin();
1395 it != map_it->second->end(); ++it) {
1396 logprintf(12, "Log: Reaping thread status %d\n", (*it)->ThreadID());
1397 if ((*it)->GetStatus() != 1) {
1398 logprintf(0, "Process Error: Thread %d failed with status %d at "
1400 (*it)->ThreadID(), (*it)->GetStatus(),
1401 (*it)->GetRunDurationUSec()*1.0/1000000);
1405 if ((*it)->GetErrorCount())
1407 logprintf(priority, "Log: Thread %d found %lld hardware incidents\n",
1408 (*it)->ThreadID(), (*it)->GetErrorCount());
1411 ReleaseWorkerLock();
1414 // Add in any errors from check threads.
1415 for (WorkerVector::const_iterator it = reap_check_vector.begin();
1416 it != reap_check_vector.end(); ++it) {
1417 logprintf(12, "Log: Reaping thread status %d\n", (*it)->ThreadID());
1418 if ((*it)->GetStatus() != 1) {
1419 logprintf(0, "Process Error: Thread %d failed with status %d at "
1421 (*it)->ThreadID(), (*it)->GetStatus(),
1422 (*it)->GetRunDurationUSec()*1.0/1000000);
1425 errorcount_ += (*it)->GetErrorCount();
1427 if ((*it)->GetErrorCount())
1429 logprintf(priority, "Log: Thread %d found %lld hardware incidents\n",
1430 (*it)->ThreadID(), (*it)->GetErrorCount());
1433 reap_check_vector.clear();
1434 reap_check_status.Destroy();
1437 // Print queuing information.
1438 void Sat::QueueStats() {
1439 finelock_q_->QueueAnalysis();
1442 void Sat::AnalysisAllStats() {
1443 float max_runtime_sec = 0.;
1444 float total_data = 0.;
1445 float total_bandwidth = 0.;
1446 float thread_runtime_sec = 0.;
1448 for (WorkerMap::const_iterator map_it = workers_map_.begin();
1449 map_it != workers_map_.end(); ++map_it) {
1450 for (WorkerVector::const_iterator it = map_it->second->begin();
1451 it != map_it->second->end(); ++it) {
1452 thread_runtime_sec = (*it)->GetRunDurationUSec()*1.0/1000000;
1453 total_data += (*it)->GetMemoryCopiedData();
1454 total_data += (*it)->GetDeviceCopiedData();
1455 if (thread_runtime_sec > max_runtime_sec) {
1456 max_runtime_sec = thread_runtime_sec;
1461 total_bandwidth = total_data / max_runtime_sec;
1463 logprintf(0, "Stats: Completed: %.2fM in %.2fs %.2fMB/s, "
1464 "with %d hardware incidents, %d errors\n",
1472 void Sat::MemoryStats() {
1473 float memcopy_data = 0.;
1474 float memcopy_bandwidth = 0.;
1475 WorkerMap::const_iterator mem_it = workers_map_.find(
1476 static_cast<int>(kMemoryType));
1477 WorkerMap::const_iterator file_it = workers_map_.find(
1478 static_cast<int>(kFileIOType));
1479 sat_assert(mem_it != workers_map_.end());
1480 sat_assert(file_it != workers_map_.end());
1481 for (WorkerVector::const_iterator it = mem_it->second->begin();
1482 it != mem_it->second->end(); ++it) {
1483 memcopy_data += (*it)->GetMemoryCopiedData();
1484 memcopy_bandwidth += (*it)->GetMemoryBandwidth();
1486 for (WorkerVector::const_iterator it = file_it->second->begin();
1487 it != file_it->second->end(); ++it) {
1488 memcopy_data += (*it)->GetMemoryCopiedData();
1489 memcopy_bandwidth += (*it)->GetMemoryBandwidth();
1491 GoogleMemoryStats(&memcopy_data, &memcopy_bandwidth);
1492 logprintf(4, "Stats: Memory Copy: %.2fM at %.2fMB/s\n",
1497 void Sat::GoogleMemoryStats(float *memcopy_data,
1498 float *memcopy_bandwidth) {
1499 // Do nothing, should be implemented by subclasses.
1502 void Sat::FileStats() {
1503 float file_data = 0.;
1504 float file_bandwidth = 0.;
1505 WorkerMap::const_iterator file_it = workers_map_.find(
1506 static_cast<int>(kFileIOType));
1507 sat_assert(file_it != workers_map_.end());
1508 for (WorkerVector::const_iterator it = file_it->second->begin();
1509 it != file_it->second->end(); ++it) {
1510 file_data += (*it)->GetDeviceCopiedData();
1511 file_bandwidth += (*it)->GetDeviceBandwidth();
1513 logprintf(4, "Stats: File Copy: %.2fM at %.2fMB/s\n",
1518 void Sat::CheckStats() {
1519 float check_data = 0.;
1520 float check_bandwidth = 0.;
1521 WorkerMap::const_iterator check_it = workers_map_.find(
1522 static_cast<int>(kCheckType));
1523 sat_assert(check_it != workers_map_.end());
1524 for (WorkerVector::const_iterator it = check_it->second->begin();
1525 it != check_it->second->end(); ++it) {
1526 check_data += (*it)->GetMemoryCopiedData();
1527 check_bandwidth += (*it)->GetMemoryBandwidth();
1529 logprintf(4, "Stats: Data Check: %.2fM at %.2fMB/s\n",
1534 void Sat::NetStats() {
1535 float net_data = 0.;
1536 float net_bandwidth = 0.;
1537 WorkerMap::const_iterator netio_it = workers_map_.find(
1538 static_cast<int>(kNetIOType));
1539 WorkerMap::const_iterator netslave_it = workers_map_.find(
1540 static_cast<int>(kNetSlaveType));
1541 sat_assert(netio_it != workers_map_.end());
1542 sat_assert(netslave_it != workers_map_.end());
1543 for (WorkerVector::const_iterator it = netio_it->second->begin();
1544 it != netio_it->second->end(); ++it) {
1545 net_data += (*it)->GetDeviceCopiedData();
1546 net_bandwidth += (*it)->GetDeviceBandwidth();
1548 for (WorkerVector::const_iterator it = netslave_it->second->begin();
1549 it != netslave_it->second->end(); ++it) {
1550 net_data += (*it)->GetDeviceCopiedData();
1551 net_bandwidth += (*it)->GetDeviceBandwidth();
1553 logprintf(4, "Stats: Net Copy: %.2fM at %.2fMB/s\n",
1558 void Sat::InvertStats() {
1559 float invert_data = 0.;
1560 float invert_bandwidth = 0.;
1561 WorkerMap::const_iterator invert_it = workers_map_.find(
1562 static_cast<int>(kInvertType));
1563 sat_assert(invert_it != workers_map_.end());
1564 for (WorkerVector::const_iterator it = invert_it->second->begin();
1565 it != invert_it->second->end(); ++it) {
1566 invert_data += (*it)->GetMemoryCopiedData();
1567 invert_bandwidth += (*it)->GetMemoryBandwidth();
1569 logprintf(4, "Stats: Invert Data: %.2fM at %.2fMB/s\n",
1574 void Sat::DiskStats() {
1575 float disk_data = 0.;
1576 float disk_bandwidth = 0.;
1577 WorkerMap::const_iterator disk_it = workers_map_.find(
1578 static_cast<int>(kDiskType));
1579 WorkerMap::const_iterator random_it = workers_map_.find(
1580 static_cast<int>(kRandomDiskType));
1581 sat_assert(disk_it != workers_map_.end());
1582 sat_assert(random_it != workers_map_.end());
1583 for (WorkerVector::const_iterator it = disk_it->second->begin();
1584 it != disk_it->second->end(); ++it) {
1585 disk_data += (*it)->GetDeviceCopiedData();
1586 disk_bandwidth += (*it)->GetDeviceBandwidth();
1588 for (WorkerVector::const_iterator it = random_it->second->begin();
1589 it != random_it->second->end(); ++it) {
1590 disk_data += (*it)->GetDeviceCopiedData();
1591 disk_bandwidth += (*it)->GetDeviceBandwidth();
1594 logprintf(4, "Stats: Disk: %.2fM at %.2fMB/s\n",
1599 // Process worker thread data for bandwidth information, and error results.
1600 // You can add more methods here just subclassing SAT.
1601 void Sat::RunAnalysis() {
1611 // Get total error count, summing across all threads..
1612 int64 Sat::GetTotalErrorCount() {
1615 AcquireWorkerLock();
1616 for (WorkerMap::const_iterator map_it = workers_map_.begin();
1617 map_it != workers_map_.end(); ++map_it) {
1618 for (WorkerVector::const_iterator it = map_it->second->begin();
1619 it != map_it->second->end(); ++it) {
1620 errors += (*it)->GetErrorCount();
1623 ReleaseWorkerLock();
1628 void Sat::SpawnThreads() {
1629 logprintf(12, "Log: Initializing WorkerStatus objects\n");
1630 power_spike_status_.Initialize();
1631 continuous_status_.Initialize();
1632 logprintf(12, "Log: Spawning worker threads\n");
1633 for (WorkerMap::const_iterator map_it = workers_map_.begin();
1634 map_it != workers_map_.end(); ++map_it) {
1635 for (WorkerVector::const_iterator it = map_it->second->begin();
1636 it != map_it->second->end(); ++it) {
1637 logprintf(12, "Log: Spawning thread %d\n", (*it)->ThreadID());
1638 (*it)->SpawnThread();
1643 // Delete used worker thread objects.
1644 void Sat::DeleteThreads() {
1645 logprintf(12, "Log: Deleting worker threads\n");
1646 for (WorkerMap::const_iterator map_it = workers_map_.begin();
1647 map_it != workers_map_.end(); ++map_it) {
1648 for (WorkerVector::const_iterator it = map_it->second->begin();
1649 it != map_it->second->end(); ++it) {
1650 logprintf(12, "Log: Deleting thread %d\n", (*it)->ThreadID());
1653 delete map_it->second;
1655 workers_map_.clear();
1656 logprintf(12, "Log: Destroying WorkerStatus objects\n");
1657 power_spike_status_.Destroy();
1658 continuous_status_.Destroy();
1662 // Calculates the next time an action in Sat::Run() should occur, based on a
1663 // schedule derived from a start point and a regular frequency.
1665 // Using frequencies instead of intervals with their accompanying drift allows
1666 // users to better predict when the actions will occur throughout a run.
1669 // frequency: seconds
1673 // Returns: unixtime
1674 inline time_t NextOccurance(time_t frequency, time_t start, time_t now) {
1675 return start + frequency + (((now - start) / frequency) * frequency);
1679 // Run the actual test.
1681 // Install signal handlers to gracefully exit in the middle of a run.
1683 // Why go through this whole rigmarole? It's the only standards-compliant
1684 // (C++ and POSIX) way to handle signals in a multithreaded program.
1687 // 1) (C++) The value of a variable not of type "volatile sig_atomic_t" is
1688 // unspecified upon entering a signal handler and, if modified by the
1689 // handler, is unspecified after leaving the handler.
1691 // 2) (POSIX) After the value of a variable is changed in one thread, another
1692 // thread is only guaranteed to see the new value after both threads have
1693 // acquired or released the same mutex or rwlock, synchronized to the
1694 // same barrier, or similar.
1696 // #1 prevents the use of #2 in a signal handler, so the signal handler must
1697 // be called in the same thread that reads the "volatile sig_atomic_t"
1698 // variable it sets. We enforce that by blocking the signals in question in
1699 // the worker threads, forcing them to be handled by this thread.
1700 logprintf(12, "Log: Installing signal handlers\n");
1701 sigset_t new_blocked_signals;
1702 sigemptyset(&new_blocked_signals);
1703 sigaddset(&new_blocked_signals, SIGINT);
1704 sigaddset(&new_blocked_signals, SIGTERM);
1705 sigset_t prev_blocked_signals;
1706 pthread_sigmask(SIG_BLOCK, &new_blocked_signals, &prev_blocked_signals);
1707 sighandler_t prev_sigint_handler = signal(SIGINT, SatHandleBreak);
1708 sighandler_t prev_sigterm_handler = signal(SIGTERM, SatHandleBreak);
1710 // Kick off all the worker threads.
1711 logprintf(12, "Log: Launching worker threads\n");
1712 InitializeThreads();
1714 pthread_sigmask(SIG_SETMASK, &prev_blocked_signals, NULL);
1716 logprintf(12, "Log: Starting countdown with %d seconds\n", runtime_seconds_);
1719 static const time_t kSleepFrequency = 5;
1720 // All of these are in seconds. You probably want them to be >=
1721 // kSleepFrequency and multiples of kSleepFrequency, but neither is necessary.
1722 static const time_t kInjectionFrequency = 10;
1723 static const time_t kPrintFrequency = 10;
1725 const time_t start = time(NULL);
1726 const time_t end = start + runtime_seconds_;
1728 time_t next_print = start + kPrintFrequency;
1729 time_t next_pause = start + pause_delay_;
1730 time_t next_resume = 0;
1731 time_t next_injection;
1732 if (crazy_error_injection_) {
1733 next_injection = start + kInjectionFrequency;
1739 // This is an int because it's for logprintf().
1740 const int seconds_remaining = end - now;
1743 // Handle early exit.
1744 logprintf(0, "Log: User exiting early (%d seconds remaining)\n",
1749 // If we have an error limit, check it here and see if we should exit.
1750 if (max_errorcount_ != 0) {
1751 uint64 errors = GetTotalErrorCount();
1752 if (errors > max_errorcount_) {
1753 logprintf(0, "Log: Exiting early (%d seconds remaining) "
1754 "due to excessive failures (%lld)\n",
1761 if (now >= next_print) {
1762 // Print a count down message.
1763 logprintf(5, "Log: Seconds remaining: %d\n", seconds_remaining);
1764 next_print = NextOccurance(kPrintFrequency, start, now);
1767 if (next_injection && now >= next_injection) {
1769 logprintf(4, "Log: Injecting error (%d seconds remaining)\n",
1771 struct page_entry src;
1773 src.pattern = patternlist_->GetPattern(0);
1775 next_injection = NextOccurance(kInjectionFrequency, start, now);
1778 if (next_pause && now >= next_pause) {
1779 // Tell worker threads to pause in preparation for a power spike.
1780 logprintf(4, "Log: Pausing worker threads in preparation for power spike "
1781 "(%d seconds remaining)\n", seconds_remaining);
1782 power_spike_status_.PauseWorkers();
1783 logprintf(12, "Log: Worker threads paused\n");
1785 next_resume = now + pause_duration_;
1788 if (next_resume && now >= next_resume) {
1789 // Tell worker threads to resume in order to cause a power spike.
1790 logprintf(4, "Log: Resuming worker threads to cause a power spike (%d "
1791 "seconds remaining)\n", seconds_remaining);
1792 power_spike_status_.ResumeWorkers();
1793 logprintf(12, "Log: Worker threads resumed\n");
1794 next_pause = NextOccurance(pause_delay_, start, now);
1798 sat_sleep(NextOccurance(kSleepFrequency, start, now) - now);
1804 logprintf(0, "Stats: Found %lld hardware incidents\n", errorcount_);
1811 logprintf(12, "Log: Uninstalling signal handlers\n");
1812 signal(SIGINT, prev_sigint_handler);
1813 signal(SIGTERM, prev_sigterm_handler);
1818 // Clean up all resources.
1819 bool Sat::Cleanup() {
1821 Logger::GlobalLogger()->StopThread();
1822 Logger::GlobalLogger()->SetStdoutOnly();
1828 patternlist_->Destroy();
1829 delete patternlist_;
1850 delete[] page_bitmap_;
1853 for (int i = 0; i < blocktables_.size(); i++) {
1854 delete blocktables_[i];
1857 if (cc_cacheline_data_) {
1858 // The num integer arrays for all the cacheline structures are
1859 // allocated as a single chunk. The pointers in the cacheline struct
1860 // are populated accordingly. Hence calling free on the first
1861 // cacheline's num's address is going to free the entire array.
1862 // TODO(aganti): Refactor this to have a class for the cacheline
1863 // structure (currently defined in worker.h) and clean this up
1864 // in the destructor of that class.
1865 if (cc_cacheline_data_[0].num) {
1866 free(cc_cacheline_data_[0].num);
1868 free(cc_cacheline_data_);
1871 sat_assert(0 == pthread_mutex_destroy(&worker_lock_));
1877 // Pretty print really obvious results.
1878 bool Sat::PrintResults() {
1883 logprintf(4, "Status: FAIL - test encountered procedural errors\n");
1885 } else if (errorcount_) {
1886 logprintf(4, "Status: FAIL - test discovered HW problems\n");
1889 logprintf(4, "Status: PASS - please verify no corrected errors\n");
1896 // Helper functions.
1897 void Sat::AcquireWorkerLock() {
1898 sat_assert(0 == pthread_mutex_lock(&worker_lock_));
1900 void Sat::ReleaseWorkerLock() {
1901 sat_assert(0 == pthread_mutex_unlock(&worker_lock_));
1904 void logprintf(int priority, const char *format, ...) {
1906 va_start(args, format);
1907 Logger::GlobalLogger()->VLogF(priority, format, args);