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