chiark / gitweb /
Initial commit
[stressapptest] / src / sat.cc
1 // Copyright 2006 Google Inc. All Rights Reserved.
2
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
7 //      http://www.apache.org/licenses/LICENSE-2.0
8
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.
14
15 // sat.cc : a stress test for stressful testing
16
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.
20
21 // stressapptest can be run using memory only, or using many system components.
22
23 #include <errno.h>
24 #include <pthread.h>
25 #include <signal.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 #include <sys/stat.h>
33 #include <sys/times.h>
34
35 // #define __USE_GNU
36 // #define __USE_LARGEFILE64
37 #include <fcntl.h>
38
39 #include <list>
40 #include <string>
41
42 // This file must work with autoconf on its public version,
43 // so these includes are correct.
44 #include "disk_blocks.h"
45 #include "logger.h"
46 #include "os.h"
47 #include "sat.h"
48 #include "sattypes.h"
49 #include "worker.h"
50
51 // stressapptest versioning here.
52 #ifndef PACKAGE_VERSION
53 static const char* kVersion = "1.0.0";
54 #else
55 static const char* kVersion = PACKAGE_VERSION;
56 #endif
57
58 // Global stressapptest reference, for use by signal handler.
59 // This makes Sat objects not safe for multiple instances.
60 namespace {
61   Sat *g_sat = NULL;
62
63   // Signal handler for catching break or kill.
64   //
65   // This must be installed after g_sat is assigned and while there is a single
66   // thread.
67   //
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) {
71     g_sat->Break();
72   }
73 }
74
75 // Opens the logfile for writing if necessary
76 bool Sat::InitializeLogfile() {
77   // Open logfile.
78   if (use_logfile_) {
79     logfile_ = open(logfilename_,
80                     O_WRONLY | O_CREAT | O_DSYNC,
81                     S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
82     if (logfile_ < 0) {
83       printf("Fatal Error: cannot open file %s for logging\n",
84              logfilename_);
85       bad_status();
86       return false;
87     }
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",
92              logfilename_);
93       bad_status();
94       return false;
95     }
96     Logger::GlobalLogger()->SetLogFd(logfile_);
97   }
98   return true;
99 }
100
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.
106 #if !defined NDEBUG
107   if (run_on_anything_) {
108     logprintf(1, "Log: Running DEBUG version of SAT, "
109                  "with significantly reduced coverage.\n");
110   } else {
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");
114     bad_status();
115     return false;
116   }
117 #elif !defined CHECKOPTS
118   #error Build system regression - COPTS disregarded.
119 #endif
120
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_);
125   }
126
127   // Use all memory if no size is specified.
128   if (size_mb_ == 0)
129     size_mb_ = os_->FindFreeMemSize() / kMegabyte;
130   size_ = static_cast<int64>(size_mb_) * kMegabyte;
131
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();
136
137     // Extract each one.
138     while (!locations.empty()) {
139       // Copy and remove the disk name.
140       string disk = locations.back();
141       locations.pop_back();
142
143       logprintf(12, "Log: disk at %s\n", disk.c_str());
144       file_threads_++;
145       filename_.push_back(disk + "/sat_disk.a");
146       file_threads_++;
147       filename_.push_back(disk + "/sat_disk.b");
148     }
149   }
150
151   // We'd better have some memory by this point.
152   if (size_ < 1) {
153     logprintf(0, "Process Error: No memory found to test.\n");
154     bad_status();
155     return false;
156   }
157
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");
163     bad_status();
164     return false;
165   }
166
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",
173                 size_mb_,
174                 new_size_mb);
175       size_mb_ = new_size_mb;
176       size_ = size_mb_ * kMegabyte;
177     } else {
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");
182       bad_status();
183       return false;
184     }
185   }
186
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",
192               size_mb_);
193   }
194
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.
200     } else {
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");
204       bad_status();
205       return false;
206     }
207   }
208
209   return true;
210 }
211
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_);
216   if (!result) {
217     logprintf(0, "Process Error: failed to allocate memory\n");
218     bad_status();
219     return false;
220   }
221   return true;
222 }
223
224 // Sets up access to data patterns
225 bool Sat::InitializePatterns() {
226   // Initialize pattern data.
227   patternlist_ = new PatternList();
228   if (!patternlist_) {
229     logprintf(0, "Process Error: failed to allocate patterns\n");
230     bad_status();
231     return false;
232   }
233   if (!patternlist_->Initialize()) {
234     logprintf(0, "Process Error: failed to initialize patternlist\n");
235     bad_status();
236     return false;
237   }
238   return true;
239 }
240
241 // Get any valid page, no tag specified.
242 bool Sat::GetValid(struct page_entry *pe) {
243   return GetValid(pe, kDontCareTag);
244 }
245
246
247 // Fetch and return empty and full pages into the empty and full pools.
248 bool Sat::GetValid(struct page_entry *pe, int32 tag) {
249   bool result = false;
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);
255
256   if (result) {
257     pe->addr = os_->PrepareTestMem(pe->offset, page_length_);  // Map it.
258
259     // Tag this access and current pattern.
260     pe->ts = os_->GetTimestamp();
261     pe->lastpattern = pe->pattern;
262
263     return (pe->addr != 0);     // Return success or failure.
264   }
265   return false;
266 }
267
268 bool Sat::PutValid(struct page_entry *pe) {
269   if (pe->addr != 0)
270     os_->ReleaseTestMem(pe->addr, pe->offset, page_length_);  // Unmap the page.
271   pe->addr = 0;
272
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);
278   else
279     return false;
280 }
281
282 // Get an empty page with any tag.
283 bool Sat::GetEmpty(struct page_entry *pe) {
284   return GetEmpty(pe, kDontCareTag);
285 }
286
287 bool Sat::GetEmpty(struct page_entry *pe, int32 tag) {
288   bool result = false;
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);
294
295   if (result) {
296     pe->addr = os_->PrepareTestMem(pe->offset, page_length_);  // Map it.
297     return (pe->addr != 0);     // Return success or failure.
298   }
299   return false;
300 }
301
302 bool Sat::PutEmpty(struct page_entry *pe) {
303   if (pe->addr != 0)
304     os_->ReleaseTestMem(pe->addr, pe->offset, page_length_);  // Unmap the page.
305   pe->addr = 0;
306
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);
312   else
313     return false;
314 }
315
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() {
319   if (!do_page_map_)
320     return;
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);
326
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];
332   sat_assert(bitmap);
333
334   // Mark every page as 0, not seen.
335   memset(bitmap, 0, arraysize);
336
337   page_bitmap_size_ = maxsize;
338   page_bitmap_ = bitmap;
339 }
340
341 // Add the 4k pages in this block to the array of pages SAT has seen.
342 void Sat::AddrMapUpdate(struct page_entry *pe) {
343   if (!do_page_map_)
344     return;
345
346   // Go through 4k page blocks.
347   uint64 arraysize = page_bitmap_size_ / 4096 / 8;
348
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);
352
353     int offset = paddr / 4096 / 8;
354     unsigned char mask = 1 << ((paddr / 4096) % 8);
355
356     if (offset >= arraysize) {
357       logprintf(0, "Process Error: Physical address %#llx is "
358                    "greater than expected %#llx.\n",
359                 paddr, page_bitmap_size_);
360       sat_assert(0);
361     }
362     page_bitmap_[offset] |= mask;
363   }
364 }
365
366 // Print out the physical memory ranges that SAT has accessed.
367 void Sat::AddrMapPrint() {
368   if (!do_page_map_)
369     return;
370
371   uint64 pages = page_bitmap_size_ / 4096;
372
373   uint64 last_page = 0;
374   bool valid_range = false;
375
376   logprintf(4, "Log: Printing tested physical ranges.\n");
377
378   for (uint64 i = 0; i < pages; i ++) {
379     int offset = i / 8;
380     unsigned char mask = 1 << (i % 8);
381
382     bool touched = page_bitmap_[offset] & mask;
383     if (touched && !valid_range) {
384       valid_range = true;
385       last_page = i * 4096;
386     } else if (!touched && valid_range) {
387       valid_range = false;
388       logprintf(4, "Log: %#016llx - %#016llx\n", last_page, (i * 4096) - 1);
389     }
390   }
391   logprintf(4, "Log: Done printing physical ranges.\n");
392 }
393
394 // Initializes page lists and fills pages with data patterns.
395 bool Sat::InitializePages() {
396   int result = 1;
397   // Calculate needed page totals.
398   int64 neededpages = memory_threads_ +
399     invert_threads_ +
400     check_threads_ +
401     net_threads_ +
402     file_threads_;
403
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.
410   else
411     freepages_ = (pages_ / 100) + (2 * neededpages);
412
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_));
419     bad_status();
420     return false;
421   }
422
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));
429     bad_status();
430     return false;
431   }
432   logprintf(12, "Log: Allocating pages, Total: %lld Free: %lld\n",
433             pages_,
434             freepages_);
435
436   // Initialize page locations.
437   for (int64 i = 0; i < pages_; i++) {
438     struct page_entry pe;
439     init_pe(&pe);
440     pe.offset = i * page_length_;
441     result &= PutEmpty(&pe);
442   }
443
444   if (!result) {
445     logprintf(0, "Process Error: while initializing empty_ list\n");
446     bad_status();
447     return false;
448   }
449
450   // Fill valid pages with test patterns.
451   // Use fill threads to do this.
452   WorkerStatus fill_status;
453   WorkerVector fill_vector;
454
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.
466     } else {
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);
470     }
471     fill_vector.push_back(thread);
472   }
473
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();
479
480   // Reap the finished fill threads.
481   for (WorkerVector::const_iterator it = fill_vector.begin();
482        it != fill_vector.end(); ++it) {
483     (*it)->JoinThread();
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);
488       bad_status();
489       return false;
490     }
491     delete (*it);
492   }
493   fill_vector.clear();
494   fill_status.Destroy();
495   logprintf(12, "Log: Done filling pages.\n");
496   logprintf(12, "Log: Allocating pages.\n");
497
498   AddrMapInit();
499
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.
504     char buf[256];
505     if (GetValid(&pe, kInvalidTag)) {
506       int64 paddr = os_->VirtualToPhysical(pe.addr);
507       int32 region = os_->FindRegion(paddr);
508
509       os_->FindDimm(paddr, buf, sizeof(buf));
510       if (i < 256) {
511         logprintf(12, "Log: address: %#llx, %s\n", paddr, buf);
512       }
513       region_[region]++;
514       pe.paddr = paddr;
515       pe.tag = 1 << region;
516       region_mask_ |= pe.tag;
517
518       // Generate a physical region map
519       AddrMapUpdate(&pe);
520
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);
527       } else {
528         result &= PutValid(&pe);
529       }
530     } else {
531       logprintf(0, "Log: didn't tag all pages. %d - %d = %d\n",
532                 pages_, i, pages_ - i);
533       return false;
534     }
535   }
536   logprintf(12, "Log: Done allocating pages.\n");
537
538   AddrMapPrint();
539
540   for (int i = 0; i < 32; i++) {
541     if (region_mask_ & (1 << i)) {
542       region_count_++;
543       logprintf(12, "Log: Region %d: %d.\n", i, region_[i]);
544     }
545   }
546   logprintf(5, "Log: Region mask: 0x%x\n", region_mask_);
547
548   return true;
549 }
550
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());
556
557   return true;
558 }
559
560
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() {
565   g_sat = this;
566
567   // Initializes sync'd log file to ensure output is saved.
568   if (!InitializeLogfile())
569     return false;
570   Logger::GlobalLogger()->StartThread();
571
572   logprintf(5, "Log: Commandline - %s\n", cmdline_.c_str());
573   PrintVersion();
574
575   std::map<std::string, std::string> options;
576
577   GoogleOsOptions(&options);
578
579   // Initialize OS/Hardware interface.
580   os_ = OsLayerFactory(options);
581   if (!os_) {
582     bad_status();
583     return false;
584   }
585   if (error_injection_) os_->set_error_injection(true);
586
587   // Checks that OS/Build/Platform is supported.
588   if (!CheckEnvironment())
589     return false;
590
591   // Run SAT in monitor only mode, do not continue to allocate resources.
592   if (monitor_mode_) {
593     logprintf(5, "Log: Running in monitor-only mode. "
594                  "Will not allocate any memory nor run any stress test. "
595                  "Only polling ECC errors.\n");
596     return true;
597   }
598
599   // Allocate the memory to test.
600   if (!AllocateMemory())
601     return false;
602
603   logprintf(5, "Stats: Starting SAT, %dM, %d seconds\n",
604             static_cast<int>(size_/kMegabyte),
605             runtime_seconds_);
606
607   if (!InitializePatterns())
608     return false;
609
610   // Initialize memory allocation.
611   pages_ = size_ / page_length_;
612
613   // Allocate page queue depending on queue implementation switch.
614   if (pe_q_implementation_ == SAT_FINELOCK) {
615       finelock_q_ = new FineLockPEQueue(pages_, page_length_);
616       if (finelock_q_ == NULL)
617         return false;
618       finelock_q_->set_os(os_);
619       os_->set_err_log_callback(finelock_q_->get_err_log_callback());
620   } else if (pe_q_implementation_ == SAT_ONELOCK) {
621       empty_ = new PageEntryQueue(pages_);
622       valid_ = new PageEntryQueue(pages_);
623       if ((empty_ == NULL) || (valid_ == NULL))
624         return false;
625   }
626
627   if (!InitializePages()) {
628     logprintf(0, "Process Error: Initialize Pages failed\n");
629     return false;
630   }
631
632   return true;
633 }
634
635 // Constructor and destructor.
636 Sat::Sat() {
637   // Set defaults, command line might override these.
638   runtime_seconds_ = 20;
639   page_length_ = kSatPageSize;
640   disk_pages_ = kSatDiskPage;
641   pages_ = 0;
642   size_mb_ = 0;
643   size_ = size_mb_ * kMegabyte;
644   freepages_ = 0;
645   paddr_base_ = 0;
646
647   user_break_ = false;
648   verbosity_ = 8;
649   Logger::GlobalLogger()->SetVerbosity(verbosity_);
650   strict_ = 1;
651   warm_ = 0;
652   run_on_anything_ = 0;
653   use_logfile_ = 0;
654   logfile_ = 0;
655   // Detect 32/64 bit binary.
656   void *pvoid = 0;
657   address_mode_ = sizeof(pvoid) * 8;
658   error_injection_ = false;
659   crazy_error_injection_ = false;
660   max_errorcount_ = 0;  // Zero means no early exit.
661   stop_on_error_ = false;
662   error_poll_ = true;
663   findfiles_ = false;
664
665   do_page_map_ = false;
666   page_bitmap_ = 0;
667   page_bitmap_size_ = 0;
668
669   // Cache coherency data initialization.
670   cc_test_ = false;         // Flag to trigger cc threads.
671   cc_cacheline_count_ = 2;  // Two datastructures of cache line size.
672   cc_inc_count_ = 1000;     // Number of times to increment the shared variable.
673   cc_cacheline_data_ = 0;   // Cache Line size datastructure.
674
675   sat_assert(0 == pthread_mutex_init(&worker_lock_, NULL));
676   file_threads_ = 0;
677   net_threads_ = 0;
678   listen_threads_ = 0;
679   // Default to autodetect number of cpus, and run that many threads.
680   memory_threads_ = -1;
681   invert_threads_ = 0;
682   fill_threads_ = 8;
683   check_threads_ = 0;
684   cpu_stress_threads_ = 0;
685   disk_threads_ = 0;
686   total_threads_ = 0;
687
688   region_mask_ = 0;
689   region_count_ = 0;
690   for (int i = 0; i < 32; i++) {
691     region_[i] = 0;
692   }
693   region_mode_ = 0;
694
695   errorcount_ = 0;
696   statuscount_ = 0;
697
698   valid_ = 0;
699   empty_ = 0;
700   finelock_q_ = 0;
701   // Default to use fine-grain lock for better performance.
702   pe_q_implementation_ = SAT_FINELOCK;
703
704   os_ = 0;
705   patternlist_ = 0;
706   logfilename_[0] = 0;
707
708   read_block_size_ = 512;
709   write_block_size_ = -1;
710   segment_size_ = -1;
711   cache_size_ = -1;
712   blocks_per_segment_ = -1;
713   read_threshold_ = -1;
714   write_threshold_ = -1;
715   non_destructive_ = 1;
716   monitor_mode_ = 0;
717   tag_mode_ = 0;
718   random_threads_ = 0;
719
720   pause_delay_ = 600;
721   pause_duration_ = 15;
722 }
723
724 // Destructor.
725 Sat::~Sat() {
726   // We need to have called Cleanup() at this point.
727   // We should probably enforce this.
728 }
729
730
731 #define ARG_KVALUE(argument, variable, value)         \
732   if (!strcmp(argv[i], argument)) {                   \
733     variable = value;                                 \
734     continue;                                         \
735   }
736
737 #define ARG_IVALUE(argument, variable)                \
738   if (!strcmp(argv[i], argument)) {                   \
739     i++;                                              \
740     if (i < argc)                                     \
741       variable = strtoull(argv[i], NULL, 0);          \
742     continue;                                         \
743   }
744
745 #define ARG_SVALUE(argument, variable)                     \
746   if (!strcmp(argv[i], argument)) {                        \
747     i++;                                                   \
748     if (i < argc)                                          \
749       snprintf(variable, sizeof(variable), "%s", argv[i]); \
750     continue;                                              \
751   }
752
753 // Configures SAT from command line arguments.
754 // This will call exit() given a request for
755 // self-documentation or unexpected args.
756 bool Sat::ParseArgs(int argc, char **argv) {
757   int i;
758   uint64 filesize = page_length_ * disk_pages_;
759
760   // Parse each argument.
761   for (i = 1; i < argc; i++) {
762     // Switch to fall back to corase-grain-lock queue. (for benchmarking)
763     ARG_KVALUE("--coarse_grain_lock", pe_q_implementation_, SAT_ONELOCK);
764
765     // Set number of megabyte to use.
766     ARG_IVALUE("-M", size_mb_);
767
768     // Set number of seconds to run.
769     ARG_IVALUE("-s", runtime_seconds_);
770
771     // Set number of memory copy threads.
772     ARG_IVALUE("-m", memory_threads_);
773
774     // Set number of memory invert threads.
775     ARG_IVALUE("-i", invert_threads_);
776
777     // Set number of check-only threads.
778     ARG_IVALUE("-c", check_threads_);
779
780     // Set number of cache line size datastructures.
781     ARG_IVALUE("--cc_inc_count", cc_inc_count_);
782
783     // Set number of cache line size datastructures
784     ARG_IVALUE("--cc_line_count", cc_cacheline_count_);
785
786     // Flag set when cache coherency tests need to be run
787     ARG_KVALUE("--cc_test", cc_test_, 1);
788
789     // Set number of CPU stress threads.
790     ARG_IVALUE("-C", cpu_stress_threads_);
791
792     // Set logfile name.
793     ARG_SVALUE("-l", logfilename_);
794
795     // Verbosity level.
796     ARG_IVALUE("-v", verbosity_);
797
798     // Set maximum number of errors to collect. Stop running after this many.
799     ARG_IVALUE("--max_errors", max_errorcount_);
800
801     // Set pattern block size.
802     ARG_IVALUE("-p", page_length_);
803
804     // Set pattern block size.
805     ARG_IVALUE("--filesize", filesize);
806
807     // NUMA options.
808     ARG_KVALUE("--local_numa", region_mode_, kLocalNuma);
809     ARG_KVALUE("--remote_numa", region_mode_, kRemoteNuma);
810
811     // Autodetect tempfile locations.
812     ARG_KVALUE("--findfiles", findfiles_, 1);
813
814     // Inject errors to force miscompare code paths
815     ARG_KVALUE("--force_errors", error_injection_, true);
816     ARG_KVALUE("--force_errors_like_crazy", crazy_error_injection_, true);
817     if (crazy_error_injection_)
818       error_injection_ = true;
819
820     // Stop immediately on any arror, for debugging HW problems.
821     ARG_KVALUE("--stop_on_errors", stop_on_error_, 1);
822
823     // Don't use internal error polling, allow external detection.
824     ARG_KVALUE("--no_errors", error_poll_, 0);
825
826     // Never check data as you go.
827     ARG_KVALUE("-F", strict_, 0);
828
829     // Warm the cpu as you go.
830     ARG_KVALUE("-W", warm_, 1);
831
832     // Allow runnign on unknown systems with base unimplemented OsLayer
833     ARG_KVALUE("-A", run_on_anything_, 1);
834
835     // Size of read blocks for disk test.
836     ARG_IVALUE("--read-block-size", read_block_size_);
837
838     // Size of write blocks for disk test.
839     ARG_IVALUE("--write-block-size", write_block_size_);
840
841     // Size of segment for disk test.
842     ARG_IVALUE("--segment-size", segment_size_);
843
844     // Size of disk cache size for disk test.
845     ARG_IVALUE("--cache-size", cache_size_);
846
847     // Number of blocks to test per segment.
848     ARG_IVALUE("--blocks-per-segment", blocks_per_segment_);
849
850     // Maximum time a block read should take before warning.
851     ARG_IVALUE("--read-threshold", read_threshold_);
852
853     // Maximum time a block write should take before warning.
854     ARG_IVALUE("--write-threshold", write_threshold_);
855
856     // Do not write anything to disk in the disk test.
857     ARG_KVALUE("--destructive", non_destructive_, 0);
858
859     // Run SAT in monitor mode. No test load at all.
860     ARG_KVALUE("--monitor_mode", monitor_mode_, true);
861
862     // Run SAT in address mode. Tag all cachelines by virt addr.
863     ARG_KVALUE("--tag_mode", tag_mode_, true);
864
865     // Dump range map of tested pages..
866     ARG_KVALUE("--do_page_map", do_page_map_, true);
867
868     // Specify the physical address base to test.
869     ARG_IVALUE("--paddr_base", paddr_base_);
870
871     // Specify the frequency for power spikes.
872     ARG_IVALUE("--pause_delay", pause_delay_);
873
874     // Specify the duration of each pause (for power spikes).
875     ARG_IVALUE("--pause_duration", pause_duration_);
876
877     // Disk device names
878     if (!strcmp(argv[i], "-d")) {
879       i++;
880       if (i < argc) {
881         disk_threads_++;
882         diskfilename_.push_back(string(argv[i]));
883         blocktables_.push_back(new DiskBlockTable());
884       }
885       continue;
886     }
887
888     // Set number of disk random threads for each disk write thread.
889     ARG_IVALUE("--random-threads", random_threads_);
890
891     // Set a tempfile to use in a file thread.
892     if (!strcmp(argv[i], "-f")) {
893       i++;
894       if (i < argc) {
895         file_threads_++;
896         filename_.push_back(string(argv[i]));
897       }
898       continue;
899     }
900
901     // Set a hostname to use in a network thread.
902     if (!strcmp(argv[i], "-n")) {
903       i++;
904       if (i < argc) {
905         net_threads_++;
906         ipaddrs_.push_back(string(argv[i]));
907       }
908       continue;
909     }
910
911     // Run threads that listen for incoming SAT net connections.
912     ARG_KVALUE("--listen", listen_threads_, 1);
913
914     if (CheckGoogleSpecificArgs(argc, argv, &i)) {
915       continue;
916     }
917
918     // Default:
919     PrintVersion();
920     PrintHelp();
921     if (strcmp(argv[i], "-h") && strcmp(argv[i], "--help")) {
922       printf("\n Unknown argument %s\n", argv[i]);
923       bad_status();
924       exit(1);
925     }
926     // Forget it, we printed the help, just bail.
927     // We don't want to print test status, or any log parser stuff.
928     exit(0);
929   }
930
931   Logger::GlobalLogger()->SetVerbosity(verbosity_);
932
933   // Update relevant data members with parsed input.
934   // Translate MB into bytes.
935   size_ = static_cast<int64>(size_mb_) * kMegabyte;
936
937   // Set logfile flag.
938   if (strcmp(logfilename_, ""))
939     use_logfile_ = 1;
940   // Checks valid page length.
941   if (page_length_ &&
942       !(page_length_ & (page_length_ - 1)) &&
943       (page_length_ > 1023)) {
944     // Prints if we have changed from default.
945     if (page_length_ != kSatPageSize)
946       logprintf(12, "Log: Updating page size to %d\n", page_length_);
947   } else {
948     // Revert to default page length.
949     logprintf(6, "Process Error: "
950               "Invalid page size %d\n", page_length_);
951     page_length_ = kSatPageSize;
952     return false;
953   }
954
955   // Set disk_pages_ if filesize or page size changed.
956   if (filesize != page_length_ * disk_pages_) {
957     disk_pages_ = filesize / page_length_;
958     if (disk_pages_ == 0)
959       disk_pages_ = 1;
960   }
961
962   // Print each argument.
963   for (int i = 0; i < argc; i++) {
964     if (i)
965       cmdline_ += " ";
966     cmdline_ += argv[i];
967   }
968
969   return true;
970 }
971
972 void Sat::PrintHelp() {
973   printf("Usage: ./sat(32|64) [options]\n"
974          " -M mbytes        megabytes of ram to test\n"
975          " -s seconds       number of seconds to run\n"
976          " -m threads       number of memory copy threads to run\n"
977          " -i threads       number of memory invert threads to run\n"
978          " -C threads       number of memory CPU stress threads to run\n"
979          " --findfiles      find locations to do disk IO automatically\n"
980          " -d device        add a direct write disk thread with block "
981          "device (or file) 'device'\n"
982          " -f filename      add a disk thread with "
983          "tempfile 'filename'\n"
984          " -l logfile       log output to file 'logfile'\n"
985          " --max_errors n   exit early after finding 'n' errors\n"
986          " -v level         verbosity (0-20), default is 8\n"
987          " -W               Use more CPU-stressful memory copy\n"
988          " -A               run in degraded mode on incompatible systems\n"
989          " -p pagesize      size in bytes of memory chunks\n"
990          " --filesize size  size of disk IO tempfiles\n"
991          " -n ipaddr        add a network thread connecting to "
992          "system at 'ipaddr'\n"
993          " --listen         run a thread to listen for and respond "
994          "to network threads.\n"
995          " --no_errors      run without checking for ECC or other errors\n"
996          " --force_errors   inject false errors to test error handling\n"
997          " --force_errors_like_crazy   inject a lot of false errors "
998          "to test error handling\n"
999          " -F               don't result check each transaction\n"
1000          "--stop_on_errors  Stop after finding the first error.\n"
1001          " --read-block-size     size of block for reading (-d)\n"
1002          " --write-block-size    size of block for writing (-d). If not "
1003          "defined, the size of block for writing will be defined as the "
1004          "size of block for reading\n"
1005          " --segment-size   size of segments to split disk into (-d)\n"
1006          " --cache-size     size of disk cache (-d)\n"
1007          " --blocks-per-segment  number of blocks to read/write per "
1008          "segment per iteration (-d)\n"
1009          " --read-threshold      maximum time (in us) a block read should "
1010          "take (-d)\n"
1011          " --write-threshold     maximum time (in us) a block write "
1012          "should take (-d)\n"
1013          " --random-threads      number of random threads for each disk "
1014          "write thread (-d)\n"
1015          " --destructive    write/wipe disk partition (-d)\n"
1016          " --monitor_mode   only do ECC error polling, no stress load.\n"
1017          " --cc_test        do the cache coherency testing\n"
1018          " --cc_inc_count   number of times to increment the "
1019          "cacheline's member\n"
1020          " --cc_line_count  number of cache line sized datastructures "
1021          "to allocate for the cache coherency threads to operate\n"
1022          " --paddr_base     allocate memory starting from this address\n"
1023          " --pause_delay    delay (in seconds) between power spikes\n"
1024          " --pause_duration duration (in seconds) of each pause\n"
1025          " --local_numa : choose memory regions associated with "
1026          "each CPU to be tested by that CPU\n"
1027          "--remote_numa : choose memory regions not associated with "
1028          "each CPU to be tested by that CPU\n");
1029 }
1030
1031 bool Sat::CheckGoogleSpecificArgs(int argc, char **argv, int *i) {
1032   // Do nothing, no google-specific argument on public stressapptest
1033   return false;
1034 }
1035
1036 void Sat::GoogleOsOptions(std::map<std::string, std::string> *options) {
1037   // Do nothing, no OS-specific argument on public stressapptest
1038 }
1039
1040 namespace {
1041   // This counts the bits set in a bitmask.
1042   // This is used to determine number of cores in an available mask.
1043   int countbits(uint32 bitfield) {
1044     int numbits = 0;
1045     for (int i = 0; i < 32; i++) {
1046       if (bitfield & (1 << i)) {
1047         numbits++;
1048       }
1049     }
1050     return numbits;
1051   }
1052 }
1053
1054 // Launch the SAT task threads. Returns 0 on error.
1055 void Sat::InitializeThreads() {
1056   // Memory copy threads.
1057   AcquireWorkerLock();
1058
1059   logprintf(12, "Log: Starting worker threads\n");
1060   WorkerVector *memory_vector = new WorkerVector();
1061
1062   // Error polling thread.
1063   // This may detect ECC corrected errors, disk problems, or
1064   // any other errors normally hidden from userspace.
1065   WorkerVector *error_vector = new WorkerVector();
1066   if (error_poll_) {
1067     ErrorPollThread *thread = new ErrorPollThread();
1068     thread->InitThread(total_threads_++, this, os_, patternlist_,
1069                        &continuous_status_);
1070
1071     error_vector->insert(error_vector->end(), thread);
1072   } else {
1073     logprintf(5, "Log: Skipping error poll thread due to --no_errors flag\n");
1074   }
1075   workers_map_.insert(make_pair(kErrorType, error_vector));
1076
1077   // Only start error poll threads for monitor-mode SAT,
1078   // skip all other types of worker threads.
1079   if (monitor_mode_) {
1080     ReleaseWorkerLock();
1081     return;
1082   }
1083
1084   for (int i = 0; i < memory_threads_; i++) {
1085     CopyThread *thread = new CopyThread();
1086     thread->InitThread(total_threads_++, this, os_, patternlist_,
1087                        &power_spike_status_);
1088
1089     if ((region_count_ > 1) && (region_mode_)) {
1090       int32 region = region_find(i % region_count_);
1091       cpu_set_t *cpuset = os_->FindCoreMask(region);
1092       sat_assert(cpuset);
1093       int32 cpu_mask = cpuset_to_uint32(cpuset);
1094       if (region_mode_ == kLocalNuma) {
1095         // Choose regions associated with this CPU.
1096         thread->set_cpu_mask(cpu_mask);
1097         thread->set_tag(1 << region);
1098       } else if (region_mode_ == kRemoteNuma) {
1099         // Choose regions not associated with this CPU..
1100         thread->set_cpu_mask(cpu_mask);
1101         thread->set_tag(region_mask_ & ~(1 << region));
1102       }
1103     } else {
1104       int cores = countbits(thread->AvailableCpus());
1105       // Don't restrict thread location if we have more than one
1106       // thread per core. Not so good for performance.
1107       if (cpu_stress_threads_ + memory_threads_ <= cores) {
1108         // Place a thread on alternating cores first.
1109         // This assures interleaved core use with no overlap.
1110         int nthcore = i;
1111         int nthbit = (((2 * nthcore) % cores) +
1112                       (((2 * nthcore) / cores) % 2)) % cores;
1113         if (thread->AvailableCpus() != ((1 << cores) - 1)) {
1114           // We are assuming the bits are contiguous.
1115           // Complain if this is not so.
1116           logprintf(0, "Log: cores = %x, expected %x\n",
1117                     thread->AvailableCpus(), ((1 << (cores + 1)) - 1));
1118         }
1119
1120         // Set thread affinity.
1121         thread->set_cpu_mask(1 << nthbit);
1122       }
1123     }
1124     memory_vector->insert(memory_vector->end(), thread);
1125   }
1126   workers_map_.insert(make_pair(kMemoryType, memory_vector));
1127
1128   // File IO threads.
1129   WorkerVector *fileio_vector = new WorkerVector();
1130   for (int i = 0; i < file_threads_; i++) {
1131     FileThread *thread = new FileThread();
1132     thread->InitThread(total_threads_++, this, os_, patternlist_,
1133                        &power_spike_status_);
1134     thread->SetFile(filename_[i].c_str());
1135     // Set disk threads high priority. They don't take much processor time,
1136     // but blocking them will delay disk IO.
1137     thread->SetPriority(WorkerThread::High);
1138
1139     fileio_vector->insert(fileio_vector->end(), thread);
1140   }
1141   workers_map_.insert(make_pair(kFileIOType, fileio_vector));
1142
1143   // Net IO threads.
1144   WorkerVector *netio_vector = new WorkerVector();
1145   WorkerVector *netslave_vector = new WorkerVector();
1146   if (listen_threads_ > 0) {
1147     // Create a network slave thread. This listens for connections.
1148     NetworkListenThread *thread = new NetworkListenThread();
1149     thread->InitThread(total_threads_++, this, os_, patternlist_,
1150                        &continuous_status_);
1151
1152     netslave_vector->insert(netslave_vector->end(), thread);
1153   }
1154   for (int i = 0; i < net_threads_; i++) {
1155     NetworkThread *thread = new NetworkThread();
1156     thread->InitThread(total_threads_++, this, os_, patternlist_,
1157                        &continuous_status_);
1158     thread->SetIP(ipaddrs_[i].c_str());
1159
1160     netio_vector->insert(netio_vector->end(), thread);
1161   }
1162   workers_map_.insert(make_pair(kNetIOType, netio_vector));
1163   workers_map_.insert(make_pair(kNetSlaveType, netslave_vector));
1164
1165   // Result check threads.
1166   WorkerVector *check_vector = new WorkerVector();
1167   for (int i = 0; i < check_threads_; i++) {
1168     CheckThread *thread = new CheckThread();
1169     thread->InitThread(total_threads_++, this, os_, patternlist_,
1170                        &continuous_status_);
1171
1172     check_vector->insert(check_vector->end(), thread);
1173   }
1174   workers_map_.insert(make_pair(kCheckType, check_vector));
1175
1176   // Memory invert threads.
1177   logprintf(12, "Log: Starting invert threads\n");
1178   WorkerVector *invert_vector = new WorkerVector();
1179   for (int i = 0; i < invert_threads_; i++) {
1180     InvertThread *thread = new InvertThread();
1181     thread->InitThread(total_threads_++, this, os_, patternlist_,
1182                        &continuous_status_);
1183
1184     invert_vector->insert(invert_vector->end(), thread);
1185   }
1186   workers_map_.insert(make_pair(kInvertType, invert_vector));
1187
1188   // Disk stress threads.
1189   WorkerVector *disk_vector = new WorkerVector();
1190   WorkerVector *random_vector = new WorkerVector();
1191   logprintf(12, "Log: Starting disk stress threads\n");
1192   for (int i = 0; i < disk_threads_; i++) {
1193     // Creating write threads
1194     DiskThread *thread = new DiskThread(blocktables_[i]);
1195     thread->InitThread(total_threads_++, this, os_, patternlist_,
1196                        &power_spike_status_);
1197     thread->SetDevice(diskfilename_[i].c_str());
1198     if (thread->SetParameters(read_block_size_, write_block_size_,
1199                               segment_size_, cache_size_,
1200                               blocks_per_segment_,
1201                               read_threshold_, write_threshold_,
1202                               non_destructive_)) {
1203       disk_vector->insert(disk_vector->end(), thread);
1204     } else {
1205       logprintf(12, "Log: DiskThread::SetParameters() failed\n");
1206       delete thread;
1207     }
1208
1209     for (int j = 0; j < random_threads_; j++) {
1210       // Creating random threads
1211       RandomDiskThread *rthread = new RandomDiskThread(blocktables_[i]);
1212       rthread->InitThread(total_threads_++, this, os_, patternlist_,
1213                           &power_spike_status_);
1214       rthread->SetDevice(diskfilename_[i].c_str());
1215       if (rthread->SetParameters(read_block_size_, write_block_size_,
1216                                  segment_size_, cache_size_,
1217                                  blocks_per_segment_,
1218                                  read_threshold_, write_threshold_,
1219                                  non_destructive_)) {
1220         random_vector->insert(random_vector->end(), rthread);
1221       } else {
1222       logprintf(12, "Log: RandomDiskThread::SetParameters() failed\n");
1223         delete rthread;
1224       }
1225     }
1226   }
1227
1228   workers_map_.insert(make_pair(kDiskType, disk_vector));
1229   workers_map_.insert(make_pair(kRandomDiskType, random_vector));
1230
1231   // CPU stress threads.
1232   WorkerVector *cpu_vector = new WorkerVector();
1233   logprintf(12, "Log: Starting cpu stress threads\n");
1234   for (int i = 0; i < cpu_stress_threads_; i++) {
1235     CpuStressThread *thread = new CpuStressThread();
1236     thread->InitThread(total_threads_++, this, os_, patternlist_,
1237                        &continuous_status_);
1238
1239     // Don't restrict thread location if we have more than one
1240     // thread per core. Not so good for performance.
1241     int cores = countbits(thread->AvailableCpus());
1242     if (cpu_stress_threads_ + memory_threads_ <= cores) {
1243       // Place a thread on alternating cores first.
1244       // Go in reverse order for CPU stress threads. This assures interleaved
1245       // core use with no overlap.
1246       int nthcore = (cores - 1) - i;
1247       int nthbit = (((2 * nthcore) % cores) +
1248                     (((2 * nthcore) / cores) % 2)) % cores;
1249       if (thread->AvailableCpus() != ((1 << cores) - 1)) {
1250         logprintf(0, "Log: cores = %x, expected %x\n",
1251                   thread->AvailableCpus(), ((1 << (cores + 1)) - 1));
1252       }
1253
1254       // Set thread affinity.
1255       thread->set_cpu_mask(1 << nthbit);
1256     }
1257
1258
1259     cpu_vector->insert(cpu_vector->end(), thread);
1260   }
1261   workers_map_.insert(make_pair(kCPUType, cpu_vector));
1262
1263   // CPU Cache Coherency Threads - one for each core available.
1264   if (cc_test_) {
1265     WorkerVector *cc_vector = new WorkerVector();
1266     logprintf(12, "Log: Starting cpu cache coherency threads\n");
1267
1268     // Allocate the shared datastructure to be worked on by the threads.
1269     cc_cacheline_data_ = reinterpret_cast<cc_cacheline_data*>(
1270         malloc(sizeof(cc_cacheline_data) * cc_cacheline_count_));
1271     sat_assert(cc_cacheline_data_ != NULL);
1272
1273     // Initialize the strucutre.
1274     memset(cc_cacheline_data_, 0,
1275            sizeof(cc_cacheline_data) * cc_cacheline_count_);
1276
1277     int num_cpus = CpuCount();
1278     // Allocate all the nums once so that we get a single chunk
1279     // of contiguous memory.
1280     int *num;
1281     int err_result = posix_memalign(
1282         reinterpret_cast<void**>(&num),
1283         kCacheLineSize, sizeof(*num) * num_cpus * cc_cacheline_count_);
1284     sat_assert(err_result == 0);
1285
1286     int cline;
1287     for (cline = 0; cline < cc_cacheline_count_; cline++) {
1288       memset(num, 0, sizeof(num_cpus) * num_cpus);
1289       cc_cacheline_data_[cline].num = num;
1290       num += num_cpus;
1291     }
1292
1293     int tnum;
1294     for (tnum = 0; tnum < num_cpus; tnum++) {
1295       CpuCacheCoherencyThread *thread =
1296           new CpuCacheCoherencyThread(cc_cacheline_data_, cc_cacheline_count_,
1297                                       tnum, cc_inc_count_);
1298       thread->InitThread(total_threads_++, this, os_, patternlist_,
1299                          &continuous_status_);
1300       // Pin the thread to a particular core.
1301       thread->set_cpu_mask(1 << tnum);
1302
1303       // Insert the thread into the vector.
1304       cc_vector->insert(cc_vector->end(), thread);
1305     }
1306     workers_map_.insert(make_pair(kCCType, cc_vector));
1307   }
1308   ReleaseWorkerLock();
1309 }
1310
1311 // Return the number of cpus actually present in the machine.
1312 int Sat::CpuCount() {
1313   return sysconf(_SC_NPROCESSORS_CONF);
1314 }
1315
1316 // Notify and reap worker threads.
1317 void Sat::JoinThreads() {
1318   logprintf(12, "Log: Joining worker threads\n");
1319   power_spike_status_.StopWorkers();
1320   continuous_status_.StopWorkers();
1321
1322   AcquireWorkerLock();
1323   for (WorkerMap::const_iterator map_it = workers_map_.begin();
1324        map_it != workers_map_.end(); ++map_it) {
1325     for (WorkerVector::const_iterator it = map_it->second->begin();
1326          it != map_it->second->end(); ++it) {
1327       logprintf(12, "Log: Joining thread %d\n", (*it)->ThreadID());
1328       (*it)->JoinThread();
1329     }
1330   }
1331   ReleaseWorkerLock();
1332
1333   QueueStats();
1334
1335   // Finish up result checking.
1336   // Spawn 4 check threads to minimize check time.
1337   logprintf(12, "Log: Finished countdown, begin to result check\n");
1338   WorkerStatus reap_check_status;
1339   WorkerVector reap_check_vector;
1340
1341   // No need for check threads for monitor mode.
1342   if (!monitor_mode_) {
1343     // Initialize the check threads.
1344     for (int i = 0; i < fill_threads_; i++) {
1345       CheckThread *thread = new CheckThread();
1346       thread->InitThread(total_threads_++, this, os_, patternlist_,
1347                          &reap_check_status);
1348       logprintf(12, "Log: Finished countdown, begin to result check\n");
1349       reap_check_vector.push_back(thread);
1350     }
1351   }
1352
1353   reap_check_status.Initialize();
1354   // Check threads should be marked to stop ASAP.
1355   reap_check_status.StopWorkers();
1356
1357   // Spawn the check threads.
1358   for (WorkerVector::const_iterator it = reap_check_vector.begin();
1359        it != reap_check_vector.end(); ++it) {
1360     logprintf(12, "Log: Spawning thread %d\n", (*it)->ThreadID());
1361     (*it)->SpawnThread();
1362   }
1363
1364   // Join the check threads.
1365   for (WorkerVector::const_iterator it = reap_check_vector.begin();
1366        it != reap_check_vector.end(); ++it) {
1367     logprintf(12, "Log: Joining thread %d\n", (*it)->ThreadID());
1368     (*it)->JoinThread();
1369   }
1370
1371   // Reap all children. Stopped threads should have already ended.
1372   // Result checking threads will end when they have finished
1373   // result checking.
1374   logprintf(12, "Log: Join all outstanding threads\n");
1375
1376   // Find all errors.
1377   errorcount_ = GetTotalErrorCount();
1378
1379   AcquireWorkerLock();
1380   for (WorkerMap::const_iterator map_it = workers_map_.begin();
1381        map_it != workers_map_.end(); ++map_it) {
1382     for (WorkerVector::const_iterator it = map_it->second->begin();
1383          it != map_it->second->end(); ++it) {
1384       logprintf(12, "Log: Reaping thread status %d\n", (*it)->ThreadID());
1385       if ((*it)->GetStatus() != 1) {
1386         logprintf(0, "Process Error: Thread %d failed with status %d at "
1387                   "%.2f seconds\n",
1388                   (*it)->ThreadID(), (*it)->GetStatus(),
1389                   (*it)->GetRunDurationUSec()*1.0/1000000);
1390         bad_status();
1391       }
1392       int priority = 12;
1393       if ((*it)->GetErrorCount())
1394         priority = 5;
1395       logprintf(priority, "Log: Thread %d found %lld hardware incidents\n",
1396                 (*it)->ThreadID(), (*it)->GetErrorCount());
1397     }
1398   }
1399   ReleaseWorkerLock();
1400
1401
1402   // Add in any errors from check threads.
1403   for (WorkerVector::const_iterator it = reap_check_vector.begin();
1404        it != reap_check_vector.end(); ++it) {
1405     logprintf(12, "Log: Reaping thread status %d\n", (*it)->ThreadID());
1406     if ((*it)->GetStatus() != 1) {
1407       logprintf(0, "Process Error: Thread %d failed with status %d at "
1408                 "%.2f seconds\n",
1409                 (*it)->ThreadID(), (*it)->GetStatus(),
1410                 (*it)->GetRunDurationUSec()*1.0/1000000);
1411       bad_status();
1412     }
1413     errorcount_ += (*it)->GetErrorCount();
1414     int priority = 12;
1415     if ((*it)->GetErrorCount())
1416       priority = 5;
1417     logprintf(priority, "Log: Thread %d found %lld hardware incidents\n",
1418               (*it)->ThreadID(), (*it)->GetErrorCount());
1419     delete (*it);
1420   }
1421   reap_check_vector.clear();
1422   reap_check_status.Destroy();
1423 }
1424
1425 // Print queuing information.
1426 void Sat::QueueStats() {
1427   finelock_q_->QueueAnalysis();
1428 }
1429
1430 void Sat::AnalysisAllStats() {
1431   float max_runtime_sec = 0.;
1432   float total_data = 0.;
1433   float total_bandwidth = 0.;
1434   float thread_runtime_sec = 0.;
1435
1436   for (WorkerMap::const_iterator map_it = workers_map_.begin();
1437        map_it != workers_map_.end(); ++map_it) {
1438     for (WorkerVector::const_iterator it = map_it->second->begin();
1439          it != map_it->second->end(); ++it) {
1440       thread_runtime_sec = (*it)->GetRunDurationUSec()*1.0/1000000;
1441       total_data += (*it)->GetMemoryCopiedData();
1442       total_data += (*it)->GetDeviceCopiedData();
1443       if (thread_runtime_sec > max_runtime_sec) {
1444         max_runtime_sec = thread_runtime_sec;
1445       }
1446     }
1447   }
1448
1449   total_bandwidth = total_data / max_runtime_sec;
1450
1451   logprintf(0, "Stats: Completed: %.2fM in %.2fs %.2fMB/s, "
1452             "with %d hardware incidents, %d errors\n",
1453             total_data,
1454             max_runtime_sec,
1455             total_bandwidth,
1456             errorcount_,
1457             statuscount_);
1458 }
1459
1460 void Sat::MemoryStats() {
1461   float memcopy_data = 0.;
1462   float memcopy_bandwidth = 0.;
1463   WorkerMap::const_iterator mem_it = workers_map_.find(
1464       static_cast<int>(kMemoryType));
1465   WorkerMap::const_iterator file_it = workers_map_.find(
1466       static_cast<int>(kFileIOType));
1467   sat_assert(mem_it != workers_map_.end());
1468   sat_assert(file_it != workers_map_.end());
1469   for (WorkerVector::const_iterator it = mem_it->second->begin();
1470        it != mem_it->second->end(); ++it) {
1471     memcopy_data += (*it)->GetMemoryCopiedData();
1472     memcopy_bandwidth += (*it)->GetMemoryBandwidth();
1473   }
1474   for (WorkerVector::const_iterator it = file_it->second->begin();
1475        it != file_it->second->end(); ++it) {
1476     memcopy_data += (*it)->GetMemoryCopiedData();
1477     memcopy_bandwidth += (*it)->GetMemoryBandwidth();
1478   }
1479   GoogleMemoryStats(&memcopy_data, &memcopy_bandwidth);
1480   logprintf(4, "Stats: Memory Copy: %.2fM at %.2fMB/s\n",
1481             memcopy_data,
1482             memcopy_bandwidth);
1483 }
1484
1485 void Sat::GoogleMemoryStats(float *memcopy_data,
1486                             float *memcopy_bandwidth) {
1487   // Do nothing, should be implemented by subclasses.
1488 }
1489
1490 void Sat::FileStats() {
1491   float file_data = 0.;
1492   float file_bandwidth = 0.;
1493   WorkerMap::const_iterator file_it = workers_map_.find(
1494       static_cast<int>(kFileIOType));
1495   sat_assert(file_it != workers_map_.end());
1496   for (WorkerVector::const_iterator it = file_it->second->begin();
1497        it != file_it->second->end(); ++it) {
1498     file_data += (*it)->GetDeviceCopiedData();
1499     file_bandwidth += (*it)->GetDeviceBandwidth();
1500   }
1501   logprintf(4, "Stats: File Copy: %.2fM at %.2fMB/s\n",
1502             file_data,
1503             file_bandwidth);
1504 }
1505
1506 void Sat::CheckStats() {
1507   float check_data = 0.;
1508   float check_bandwidth = 0.;
1509   WorkerMap::const_iterator check_it = workers_map_.find(
1510       static_cast<int>(kCheckType));
1511   sat_assert(check_it != workers_map_.end());
1512   for (WorkerVector::const_iterator it = check_it->second->begin();
1513        it != check_it->second->end(); ++it) {
1514     check_data += (*it)->GetMemoryCopiedData();
1515     check_bandwidth += (*it)->GetMemoryBandwidth();
1516   }
1517   logprintf(4, "Stats: Data Check: %.2fM at %.2fMB/s\n",
1518             check_data,
1519             check_bandwidth);
1520 }
1521
1522 void Sat::NetStats() {
1523   float net_data = 0.;
1524   float net_bandwidth = 0.;
1525   WorkerMap::const_iterator netio_it = workers_map_.find(
1526       static_cast<int>(kNetIOType));
1527   WorkerMap::const_iterator netslave_it = workers_map_.find(
1528       static_cast<int>(kNetSlaveType));
1529   sat_assert(netio_it != workers_map_.end());
1530   sat_assert(netslave_it != workers_map_.end());
1531   for (WorkerVector::const_iterator it = netio_it->second->begin();
1532        it != netio_it->second->end(); ++it) {
1533     net_data += (*it)->GetDeviceCopiedData();
1534     net_bandwidth += (*it)->GetDeviceBandwidth();
1535   }
1536   for (WorkerVector::const_iterator it = netslave_it->second->begin();
1537        it != netslave_it->second->end(); ++it) {
1538     net_data += (*it)->GetDeviceCopiedData();
1539     net_bandwidth += (*it)->GetDeviceBandwidth();
1540   }
1541   logprintf(4, "Stats: Net Copy: %.2fM at %.2fMB/s\n",
1542             net_data,
1543             net_bandwidth);
1544 }
1545
1546 void Sat::InvertStats() {
1547   float invert_data = 0.;
1548   float invert_bandwidth = 0.;
1549   WorkerMap::const_iterator invert_it = workers_map_.find(
1550       static_cast<int>(kInvertType));
1551   sat_assert(invert_it != workers_map_.end());
1552   for (WorkerVector::const_iterator it = invert_it->second->begin();
1553        it != invert_it->second->end(); ++it) {
1554     invert_data += (*it)->GetMemoryCopiedData();
1555     invert_bandwidth += (*it)->GetMemoryBandwidth();
1556   }
1557   logprintf(4, "Stats: Invert Data: %.2fM at %.2fMB/s\n",
1558             invert_data,
1559             invert_bandwidth);
1560 }
1561
1562 void Sat::DiskStats() {
1563   float disk_data = 0.;
1564   float disk_bandwidth = 0.;
1565   WorkerMap::const_iterator disk_it = workers_map_.find(
1566       static_cast<int>(kDiskType));
1567   WorkerMap::const_iterator random_it = workers_map_.find(
1568       static_cast<int>(kRandomDiskType));
1569   sat_assert(disk_it != workers_map_.end());
1570   sat_assert(random_it != workers_map_.end());
1571   for (WorkerVector::const_iterator it = disk_it->second->begin();
1572        it != disk_it->second->end(); ++it) {
1573     disk_data += (*it)->GetDeviceCopiedData();
1574     disk_bandwidth += (*it)->GetDeviceBandwidth();
1575   }
1576   for (WorkerVector::const_iterator it = random_it->second->begin();
1577        it != random_it->second->end(); ++it) {
1578     disk_data += (*it)->GetDeviceCopiedData();
1579     disk_bandwidth += (*it)->GetDeviceBandwidth();
1580   }
1581
1582   logprintf(4, "Stats: Disk: %.2fM at %.2fMB/s\n",
1583             disk_data,
1584             disk_bandwidth);
1585 }
1586
1587 // Process worker thread data for bandwidth information, and error results.
1588 // You can add more methods here just subclassing SAT.
1589 void Sat::RunAnalysis() {
1590   AnalysisAllStats();
1591   MemoryStats();
1592   FileStats();
1593   NetStats();
1594   CheckStats();
1595   InvertStats();
1596   DiskStats();
1597 }
1598
1599 // Get total error count, summing across all threads..
1600 int64 Sat::GetTotalErrorCount() {
1601   int64 errors = 0;
1602
1603   AcquireWorkerLock();
1604   for (WorkerMap::const_iterator map_it = workers_map_.begin();
1605        map_it != workers_map_.end(); ++map_it) {
1606     for (WorkerVector::const_iterator it = map_it->second->begin();
1607          it != map_it->second->end(); ++it) {
1608       errors += (*it)->GetErrorCount();
1609     }
1610   }
1611   ReleaseWorkerLock();
1612   return errors;
1613 }
1614
1615
1616 void Sat::SpawnThreads() {
1617   logprintf(12, "Log: Initializing WorkerStatus objects\n");
1618   power_spike_status_.Initialize();
1619   continuous_status_.Initialize();
1620   logprintf(12, "Log: Spawning worker threads\n");
1621   for (WorkerMap::const_iterator map_it = workers_map_.begin();
1622        map_it != workers_map_.end(); ++map_it) {
1623     for (WorkerVector::const_iterator it = map_it->second->begin();
1624          it != map_it->second->end(); ++it) {
1625       logprintf(12, "Log: Spawning thread %d\n", (*it)->ThreadID());
1626       (*it)->SpawnThread();
1627     }
1628   }
1629 }
1630
1631 // Delete used worker thread objects.
1632 void Sat::DeleteThreads() {
1633   logprintf(12, "Log: Deleting worker threads\n");
1634   for (WorkerMap::const_iterator map_it = workers_map_.begin();
1635        map_it != workers_map_.end(); ++map_it) {
1636     for (WorkerVector::const_iterator it = map_it->second->begin();
1637          it != map_it->second->end(); ++it) {
1638       logprintf(12, "Log: Deleting thread %d\n", (*it)->ThreadID());
1639       delete (*it);
1640     }
1641     delete map_it->second;
1642   }
1643   workers_map_.clear();
1644   logprintf(12, "Log: Destroying WorkerStatus objects\n");
1645   power_spike_status_.Destroy();
1646   continuous_status_.Destroy();
1647 }
1648
1649 namespace {
1650 // Calculates the next time an action in Sat::Run() should occur, based on a
1651 // schedule derived from a start point and a regular frequency.
1652 //
1653 // Using frequencies instead of intervals with their accompanying drift allows
1654 // users to better predict when the actions will occur throughout a run.
1655 //
1656 // Arguments:
1657 //   frequency: seconds
1658 //   start: unixtime
1659 //   now: unixtime
1660 //
1661 // Returns: unixtime
1662 inline time_t NextOccurance(time_t frequency, time_t start, time_t now) {
1663   return start + frequency + (((now - start) / frequency) * frequency);
1664 }
1665 }
1666
1667 // Run the actual test.
1668 bool Sat::Run() {
1669   // Install signal handlers to gracefully exit in the middle of a run.
1670   //
1671   // Why go through this whole rigmarole?  It's the only standards-compliant
1672   // (C++ and POSIX) way to handle signals in a multithreaded program.
1673   // Specifically:
1674   //
1675   // 1) (C++) The value of a variable not of type "volatile sig_atomic_t" is
1676   //    unspecified upon entering a signal handler and, if modified by the
1677   //    handler, is unspecified after leaving the handler.
1678   //
1679   // 2) (POSIX) After the value of a variable is changed in one thread, another
1680   //    thread is only guaranteed to see the new value after both threads have
1681   //    acquired or released the same mutex or rwlock, synchronized to the
1682   //    same barrier, or similar.
1683   //
1684   // #1 prevents the use of #2 in a signal handler, so the signal handler must
1685   // be called in the same thread that reads the "volatile sig_atomic_t"
1686   // variable it sets.  We enforce that by blocking the signals in question in
1687   // the worker threads, forcing them to be handled by this thread.
1688   logprintf(12, "Log: Installing signal handlers\n");
1689   sigset_t new_blocked_signals;
1690   sigemptyset(&new_blocked_signals);
1691   sigaddset(&new_blocked_signals, SIGINT);
1692   sigaddset(&new_blocked_signals, SIGTERM);
1693   sigset_t prev_blocked_signals;
1694   pthread_sigmask(SIG_BLOCK, &new_blocked_signals, &prev_blocked_signals);
1695   sighandler_t prev_sigint_handler = signal(SIGINT, SatHandleBreak);
1696   sighandler_t prev_sigterm_handler = signal(SIGTERM, SatHandleBreak);
1697
1698   // Kick off all the worker threads.
1699   logprintf(12, "Log: Launching worker threads\n");
1700   InitializeThreads();
1701   SpawnThreads();
1702   pthread_sigmask(SIG_SETMASK, &prev_blocked_signals, NULL);
1703
1704   logprintf(12, "Log: Starting countdown with %d seconds\n", runtime_seconds_);
1705
1706   // In seconds.
1707   static const time_t kSleepFrequency = 5;
1708   // All of these are in seconds.  You probably want them to be >=
1709   // kSleepFrequency and multiples of kSleepFrequency, but neither is necessary.
1710   static const time_t kInjectionFrequency = 10;
1711   static const time_t kPrintFrequency = 10;
1712
1713   const time_t start = time(NULL);
1714   const time_t end = start + runtime_seconds_;
1715   time_t now = start;
1716   time_t next_print = start + kPrintFrequency;
1717   time_t next_pause = start + pause_delay_;
1718   time_t next_resume = 0;
1719   time_t next_injection;
1720   if (crazy_error_injection_) {
1721     next_injection = start + kInjectionFrequency;
1722   } else {
1723     next_injection = 0;
1724   }
1725
1726   while (now < end) {
1727     // This is an int because it's for logprintf().
1728     const int seconds_remaining = end - now;
1729
1730     if (user_break_) {
1731       // Handle early exit.
1732       logprintf(0, "Log: User exiting early (%d seconds remaining)\n",
1733                 seconds_remaining);
1734       break;
1735     }
1736
1737     // If we have an error limit, check it here and see if we should exit.
1738     if (max_errorcount_ != 0) {
1739       uint64 errors = GetTotalErrorCount();
1740       if (errors > max_errorcount_) {
1741         logprintf(0, "Log: Exiting early (%d seconds remaining) "
1742                      "due to excessive failures (%lld)\n",
1743                   seconds_remaining,
1744                   errors);
1745         break;
1746       }
1747     }
1748
1749     if (now >= next_print) {
1750       // Print a count down message.
1751       logprintf(5, "Log: Seconds remaining: %d\n", seconds_remaining);
1752       next_print = NextOccurance(kPrintFrequency, start, now);
1753     }
1754
1755     if (next_injection && now >= next_injection) {
1756       // Inject an error.
1757       logprintf(4, "Log: Injecting error (%d seconds remaining)\n",
1758                 seconds_remaining);
1759       struct page_entry src;
1760       GetValid(&src);
1761       src.pattern = patternlist_->GetPattern(0);
1762       PutValid(&src);
1763       next_injection = NextOccurance(kInjectionFrequency, start, now);
1764     }
1765
1766     if (next_pause && now >= next_pause) {
1767       // Tell worker threads to pause in preparation for a power spike.
1768       logprintf(4, "Log: Pausing worker threads in preparation for power spike "
1769                 "(%d seconds remaining)\n", seconds_remaining);
1770       power_spike_status_.PauseWorkers();
1771       logprintf(12, "Log: Worker threads paused\n");
1772       next_pause = 0;
1773       next_resume = now + pause_duration_;
1774     }
1775
1776     if (next_resume && now >= next_resume) {
1777       // Tell worker threads to resume in order to cause a power spike.
1778       logprintf(4, "Log: Resuming worker threads to cause a power spike (%d "
1779                 "seconds remaining)\n", seconds_remaining);
1780       power_spike_status_.ResumeWorkers();
1781       logprintf(12, "Log: Worker threads resumed\n");
1782       next_pause = NextOccurance(pause_delay_, start, now);
1783       next_resume = 0;
1784     }
1785
1786     sat_sleep(NextOccurance(kSleepFrequency, start, now) - now);
1787     now = time(NULL);
1788   }
1789
1790   JoinThreads();
1791
1792   logprintf(0, "Stats: Found %lld hardware incidents\n", errorcount_);
1793
1794   if (!monitor_mode_)
1795     RunAnalysis();
1796
1797   DeleteThreads();
1798
1799   logprintf(12, "Log: Uninstalling signal handlers\n");
1800   signal(SIGINT, prev_sigint_handler);
1801   signal(SIGTERM, prev_sigterm_handler);
1802
1803   return true;
1804 }
1805
1806 // Clean up all resources.
1807 bool Sat::Cleanup() {
1808   g_sat = NULL;
1809   Logger::GlobalLogger()->StopThread();
1810   Logger::GlobalLogger()->SetStdoutOnly();
1811   if (logfile_) {
1812     close(logfile_);
1813     logfile_ = 0;
1814   }
1815   if (patternlist_) {
1816     patternlist_->Destroy();
1817     delete patternlist_;
1818     patternlist_ = 0;
1819   }
1820   if (os_) {
1821     os_->FreeTestMem();
1822     delete os_;
1823     os_ = 0;
1824   }
1825   if (empty_) {
1826     delete empty_;
1827     empty_ = 0;
1828   }
1829   if (valid_) {
1830     delete valid_;
1831     valid_ = 0;
1832   }
1833   if (finelock_q_) {
1834     delete finelock_q_;
1835     finelock_q_ = 0;
1836   }
1837   if (page_bitmap_) {
1838     delete[] page_bitmap_;
1839   }
1840
1841   for (int i = 0; i < blocktables_.size(); i++) {
1842     delete blocktables_[i];
1843   }
1844
1845   if (cc_cacheline_data_) {
1846     // The num integer arrays for all the cacheline structures are
1847     // allocated as a single chunk. The pointers in the cacheline struct
1848     // are populated accordingly. Hence calling free on the first
1849     // cacheline's num's address is going to free the entire array.
1850     // TODO(aganti): Refactor this to have a class for the cacheline
1851     // structure (currently defined in worker.h) and clean this up
1852     // in the destructor of that class.
1853     if (cc_cacheline_data_[0].num) {
1854       free(cc_cacheline_data_[0].num);
1855     }
1856     free(cc_cacheline_data_);
1857   }
1858
1859   sat_assert(0 == pthread_mutex_destroy(&worker_lock_));
1860
1861   return true;
1862 }
1863
1864
1865 // Pretty print really obvious results.
1866 bool Sat::PrintResults() {
1867   bool result = true;
1868
1869   logprintf(4, "\n");
1870   if (statuscount_) {
1871     logprintf(4, "Status: FAIL - test encountered procedural errors\n");
1872     result = false;
1873   } else if (errorcount_) {
1874     logprintf(4, "Status: FAIL - test discovered HW problems\n");
1875     result = false;
1876   } else {
1877     logprintf(4, "Status: PASS - please verify no corrected errors\n");
1878   }
1879   logprintf(4, "\n");
1880
1881   return result;
1882 }
1883
1884 // Helper functions.
1885 void Sat::AcquireWorkerLock() {
1886   sat_assert(0 == pthread_mutex_lock(&worker_lock_));
1887 }
1888 void Sat::ReleaseWorkerLock() {
1889   sat_assert(0 == pthread_mutex_unlock(&worker_lock_));
1890 }
1891
1892 void logprintf(int priority, const char *format, ...) {
1893   va_list args;
1894   va_start(args, format);
1895   Logger::GlobalLogger()->VLogF(priority, format, args);
1896   va_end(args);
1897 }