#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for stressapptest 1.0.1_autoconf.
+# Generated by GNU Autoconf 2.61 for stressapptest 1.0.2_autoconf.
#
# Report bugs to <opensource@google.com>.
#
# Identity of this package.
PACKAGE_NAME='stressapptest'
PACKAGE_TARNAME='stressapptest'
-PACKAGE_VERSION='1.0.1_autoconf'
-PACKAGE_STRING='stressapptest 1.0.1_autoconf'
+PACKAGE_VERSION='1.0.2_autoconf'
+PACKAGE_STRING='stressapptest 1.0.2_autoconf'
PACKAGE_BUGREPORT='opensource@google.com'
ac_unique_file="src/"
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures stressapptest 1.0.1_autoconf to adapt to many kinds of systems.
+\`configure' configures stressapptest 1.0.2_autoconf to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of stressapptest 1.0.1_autoconf:";;
+ short | recursive ) echo "Configuration of stressapptest 1.0.2_autoconf:";;
esac
cat <<\_ACEOF
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-stressapptest configure 1.0.1_autoconf
+stressapptest configure 1.0.2_autoconf
generated by GNU Autoconf 2.61
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by stressapptest $as_me 1.0.1_autoconf, which was
+It was created by stressapptest $as_me 1.0.2_autoconf, which was
generated by GNU Autoconf 2.61. Invocation command line was
$ $0 $@
# Define the identity of the package.
PACKAGE='stressapptest'
- VERSION='1.0.1_autoconf'
+ VERSION='1.0.2_autoconf'
cat >>confdefs.h <<_ACEOF
done
+
+for ac_header in pthread.h libaio.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_compile") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ ( cat <<\_ASBOX
+## ------------------------------------ ##
+## Report this to opensource@google.com ##
+## ------------------------------------ ##
+_ASBOX
+ ) | sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+ { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
# Checks for typedefs, structures, and compiler characteristics.
{ echo "$as_me:$LINENO: checking for stdbool.h that conforms to C99" >&5
echo $ECHO_N "checking for stdbool.h that conforms to C99... $ECHO_C" >&6; }
LDFLAGS="$LDFLAGS $pthread_arg"
fi
+# Checking for libaio
+libaio_arg="not_available"
+{ echo "$as_me:$LINENO: checking which argument is required to compile libaio" >&5
+echo $ECHO_N "checking which argument is required to compile libaio... $ECHO_C" >&6; }
+
+libaio_header="#include<libaio.h>"
+libaio_body="io_submit(0,0,0)"
+# Check if compile with no extra argument
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$libaio_header
+int
+main ()
+{
+$libaio_body
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ libaio_arg=""
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+
+if test x"$libaio_arg" = x"not_available"; then
+ bkp_LDFLAGS="$LDFLAGS"
+ for altheader in -laio; do
+ LDFLAGS="$bkp_LDFLAGS $altheader"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$libaio_header
+int
+main ()
+{
+$libaio_body
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext &&
+ $as_test_x conftest$ac_exeext; then
+ libaio_arg="$altheader"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$bkp_LDFLAGS"
+ done
+fi
+
+if test x"$libaio_arg" = x"not_available"; then
+ { { echo "$as_me:$LINENO: error: Cannot find libaio library, please install libaio-dev
+See \`config.log' for more details." >&5
+echo "$as_me: error: Cannot find libaio library, please install libaio-dev
+See \`config.log' for more details." >&2;}
+ { (exit 1); exit 1; }; }
+else
+ if test x"$libaio_arg" = x; then
+ { echo "$as_me:$LINENO: result: none" >&5
+echo "${ECHO_T}none" >&6; }
+ else
+ { echo "$as_me:$LINENO: result: $libaio_arg" >&5
+echo "${ECHO_T}$libaio_arg" >&6; }
+ fi
+ LDFLAGS="$LDFLAGS $libaio_arg"
+fi
+
# Checks for library functions.
{ echo "$as_me:$LINENO: checking whether closedir returns void" >&5
echo $ECHO_N "checking whether closedir returns void... $ECHO_C" >&6; }
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by stressapptest $as_me 1.0.1_autoconf, which was
+This file was extended by stressapptest $as_me 1.0.2_autoconf, which was
generated by GNU Autoconf 2.61. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-stressapptest config.status 1.0.1_autoconf
+stressapptest config.status 1.0.2_autoconf
configured by $0, generated by GNU Autoconf 2.61,
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
#include <sys/ioctl.h>
#include <linux/fs.h>
// For asynchronous I/O
-#include <linux/aio_abi.h>
+#include <libaio.h>
#include <sys/syscall.h>
// Linux aio syscalls.
#if !defined(__NR_io_setup)
-#define __NR_io_setup 206
-#define __NR_io_destroy 207
-#define __NR_io_getevents 208
-#define __NR_io_submit 209
-#define __NR_io_cancel 210
+#error "No aio headers inculded, please install libaio."
#endif
-#define io_setup(nr_events, ctxp) \
- syscall(__NR_io_setup, (nr_events), (ctxp))
-#define io_submit(ctx_id, nr, iocbpp) \
- syscall(__NR_io_submit, (ctx_id), (nr), (iocbpp))
-#define io_getevents(ctx_id, io_getevents, nr, events, timeout) \
- syscall(__NR_io_getevents, (ctx_id), (io_getevents), (nr), (events), \
- (timeout))
-#define io_cancel(ctx_id, iocb, result) \
- syscall(__NR_io_cancel, (ctx_id), (iocb), (result))
-#define io_destroy(ctx) \
- syscall(__NR_io_destroy, (ctx))
-
namespace {
// Get HW core ID from cpuid instruction.
inline int apicid(void) {
return NULL;
}
-
void WorkerStatus::Initialize() {
sat_assert(0 == pthread_mutex_init(&num_workers_mutex_, NULL));
sat_assert(0 == pthread_rwlock_init(&status_rwlock_, NULL));
// Parent thread class.
WorkerThread::WorkerThread() {
- status_ = 0;
+ status_ = false;
pages_copied_ = 0;
errorcount_ = 0;
- runduration_usec_ = 0;
+ runduration_usec_ = 1;
priority_ = Normal;
worker_status_ = NULL;
thread_spawner_ = &ThreadSpawnerGeneric;
patternlist_ = patternlist_init;
worker_status_ = worker_status;
- cpu_mask_ = AvailableCpus();
+ AvailableCpus(&cpu_mask_);
tag_ = 0xffffffff;
tag_mode_ = sat_->tag_mode();
bool WorkerThread::InitPriority() {
// This doesn't affect performance that much, and may not be too safe.
- bool ret = BindToCpus(cpu_mask_);
+ bool ret = BindToCpus(&cpu_mask_);
if (!ret)
- logprintf(11, "Log: Bind to %x failed.\n", cpu_mask_);
+ logprintf(11, "Log: Bind to %s failed.\n",
+ cpuset_format(&cpu_mask_).c_str());
- logprintf(11, "Log: Thread %d running on apic ID %d mask %x (%x).\n",
- thread_num_, apicid(), CurrentCpus(), cpu_mask_);
+ logprintf(11, "Log: Thread %d running on apic ID %d mask %s (%s).\n",
+ thread_num_, apicid(),
+ CurrentCpusFormat().c_str(),
+ cpuset_format(&cpu_mask_).c_str());
#if 0
if (priority_ == High) {
sched_param param;
logprintf(0, "Process Error: pthread_create "
"failed - error %d %s\n", result,
buf);
- status_ += 1;
+ status_ = false;
return false;
}
}
// Kill the worker thread with SIGINT.
-int WorkerThread::KillThread() {
- pthread_kill(thread_, SIGINT);
- return 0;
+bool WorkerThread::KillThread() {
+ return (pthread_kill(thread_, SIGINT) == 0);
}
// Block until thread has exited.
-int WorkerThread::JoinThread() {
+bool WorkerThread::JoinThread() {
int result = pthread_join(thread_, NULL);
if (result) {
logprintf(0, "Process Error: pthread_join failed - error %d\n", result);
- status_ = 0;
+ status_ = false;
}
// 0 is pthreads success.
// Thread work loop. Execute until marked finished.
-int WorkerThread::Work() {
+bool WorkerThread::Work() {
do {
logprintf(9, "Log: ...\n");
// Sleep for 1 second.
sat_sleep(1);
} while (IsReadyToRun());
- return 0;
+ return false;
}
// Conceptually, each bit represents a logical CPU, ie:
// mask = 3 (11b): cpu0, 1
// mask = 13 (1101b): cpu0, 2, 3
-uint32 WorkerThread::AvailableCpus() {
- cpu_set_t curr_cpus;
- CPU_ZERO(&curr_cpus);
- sched_getaffinity(getppid(), sizeof(curr_cpus), &curr_cpus);
- return cpuset_to_uint32(&curr_cpus);
+bool WorkerThread::AvailableCpus(cpu_set_t *cpuset) {
+ CPU_ZERO(cpuset);
+ return sched_getaffinity(getppid(), sizeof(*cpuset), cpuset) == 0;
}
// Conceptually, each bit represents a logical CPU, ie:
// mask = 3 (11b): cpu0, 1
// mask = 13 (1101b): cpu0, 2, 3
-uint32 WorkerThread::CurrentCpus() {
- cpu_set_t curr_cpus;
- CPU_ZERO(&curr_cpus);
- sched_getaffinity(0, sizeof(curr_cpus), &curr_cpus);
- return cpuset_to_uint32(&curr_cpus);
+bool WorkerThread::CurrentCpus(cpu_set_t *cpuset) {
+ CPU_ZERO(cpuset);
+ return sched_getaffinity(0, sizeof(*cpuset), cpuset) == 0;
}
// mask = 13 (1101b): cpu0, 2, 3
//
// Returns true on success, false otherwise.
-bool WorkerThread::BindToCpus(uint32 thread_mask) {
- uint32 process_mask = AvailableCpus();
- if (thread_mask == process_mask)
+bool WorkerThread::BindToCpus(const cpu_set_t *thread_mask) {
+ cpu_set_t process_mask;
+ AvailableCpus(&process_mask);
+ if (cpuset_isequal(thread_mask, &process_mask))
return true;
- logprintf(11, "Log: available CPU mask - %x\n", process_mask);
- if ((thread_mask | process_mask) != process_mask) {
+ logprintf(11, "Log: available CPU mask - %s\n",
+ cpuset_format(&process_mask).c_str());
+ if (!cpuset_issubset(thread_mask, &process_mask)) {
// Invalid cpu_mask, ie cpu not allocated to this process or doesn't exist.
- logprintf(0, "Log: requested CPUs %x not a subset of available %x\n",
- thread_mask, process_mask);
+ logprintf(0, "Log: requested CPUs %s not a subset of available %s\n",
+ cpuset_format(thread_mask).c_str(),
+ cpuset_format(&process_mask).c_str());
return false;
}
- cpu_set_t cpuset;
- cpuset_from_uint32(thread_mask, &cpuset);
- return (sched_setaffinity(gettid(), sizeof(cpuset), &cpuset) == 0);
+ return (sched_setaffinity(gettid(), sizeof(*thread_mask), thread_mask) == 0);
}
// Memory fill work loop. Execute until alloted pages filled.
-int FillThread::Work() {
- int result = 1;
+bool FillThread::Work() {
+ bool result = true;
logprintf(9, "Log: Starting fill thread %d\n", thread_num_);
struct page_entry pe;
int64 loops = 0;
while (IsReadyToRun() && (loops < num_pages_to_fill_)) {
- result &= sat_->GetEmpty(&pe);
+ result = result && sat_->GetEmpty(&pe);
if (!result) {
logprintf(0, "Process Error: fill_thread failed to pop pages, "
"bailing\n");
}
// Fill the page with pattern
- result &= FillPageRandom(&pe);
+ result = result && FillPageRandom(&pe);
if (!result) break;
// Put the page back on the queue.
- result &= sat_->PutValid(&pe);
+ result = result && sat_->PutValid(&pe);
if (!result) {
logprintf(0, "Process Error: fill_thread failed to push pages, "
"bailing\n");
status_ = result;
logprintf(9, "Log: Completed %d: Fill thread. Status %d, %d pages filled\n",
thread_num_, status_, pages_copied_);
- return 0;
+ return result;
}
char dimm_string[256] = "";
int apic_id = apicid();
- uint32 cpumask = CurrentCpus();
// Determine if this is a write or read error.
os_->Flush(error->vaddr);
(error->vaddr), 1);
logprintf(priority,
- "%s: miscompare on CPU %d(0x%x) at %p(0x%llx:%s): "
+ "%s: miscompare on CPU %d(0x%s) at %p(0x%llx:%s): "
"read:0x%016llx, reread:0x%016llx expected:0x%016llx\n",
message,
apic_id,
- cpumask,
+ CurrentCpusFormat().c_str(),
error->vaddr,
error->paddr,
dimm_string,
bool read_error = false;
int apic_id = apicid();
- uint32 cpumask = CurrentCpus();
// Determine if this is a write or read error.
os_->Flush(error->vaddr);
if (priority < 5) {
logprintf(priority,
"%s: Tag from %p(0x%llx:%s) (%s) "
- "miscompare on CPU %d(0x%x) at %p(0x%llx:%s): "
+ "miscompare on CPU %d(0x%s) at %p(0x%llx:%s): "
"read:0x%016llx, reread:0x%016llx expected:0x%016llx\n",
message,
error->tagvaddr, error->tagpaddr,
tag_dimm_string,
read_error ? "read error" : "write error",
apic_id,
- cpumask,
+ CurrentCpusFormat().c_str(),
error->vaddr,
error->paddr,
dimm_string,
return true;
}
+// x86_64 SSE2 assembly implementation of Adler memory copy, with address
+// tagging added as a second step. This is useful for debugging failures
+// that only occur when SSE / nontemporal writes are used.
+bool WorkerThread::AdlerAddrMemcpyWarm(uint64 *dstmem64,
+ uint64 *srcmem64,
+ unsigned int size_in_bytes,
+ AdlerChecksum *checksum,
+ struct page_entry *pe) {
+ // Do ASM copy, ignore checksum.
+ AdlerChecksum ignored_checksum;
+ os_->AdlerMemcpyWarm(dstmem64, srcmem64, size_in_bytes, &ignored_checksum);
+
+ // Force cache flush.
+ int length = size_in_bytes / sizeof(*dstmem64);
+ for (int i = 0; i < length; i += sizeof(*dstmem64)) {
+ os_->FastFlush(dstmem64 + i);
+ os_->FastFlush(srcmem64 + i);
+ }
+ // Check results.
+ AdlerAddrCrcC(srcmem64, size_in_bytes, checksum, pe);
+ // Patch up address tags.
+ TagAddrC(dstmem64, size_in_bytes);
+ return true;
+}
+
+// Retag pages..
+bool WorkerThread::TagAddrC(uint64 *memwords,
+ unsigned int size_in_bytes) {
+ // Mask is the bitmask of indexes used by the pattern.
+ // It is the pattern size -1. Size is always a power of 2.
+
+ // Select tag or data as appropriate.
+ int length = size_in_bytes / wordsize_;
+ for (int i = 0; i < length; i += 8) {
+ datacast_t data;
+ data.l64 = addr_to_tag(&memwords[i]);
+ memwords[i] = data.l64;
+ }
+ return true;
+}
// C implementation of Adler memory crc.
bool WorkerThread::AdlerAddrCrcC(uint64 *srcmem64,
if (data.l64 != src_tag)
ReportTagError(&srcmem64[i], data.l64, src_tag);
-
data.l32.l = pattern->pattern(i << 1);
data.l32.h = pattern->pattern((i << 1) + 1);
a1 = a1 + data.l32.l;
b1 = b1 + a1;
a1 = a1 + data.l32.h;
b1 = b1 + a1;
-
-
} else {
data.l64 = srcmem64[i];
a1 = a1 + data.l32.l;
currentblock * blocksize, 0);
if (errorcount == 0) {
int apic_id = apicid();
- uint32 cpumask = CurrentCpus();
- logprintf(0, "Process Error: CPU %d(0x%x) CrcCopyPage "
+ logprintf(0, "Process Error: CPU %d(0x%s) CrcCopyPage "
"CRC mismatch %s != %s, "
"but no miscompares found on second pass.\n",
- apic_id, cpumask,
+ apic_id, CurrentCpusFormat().c_str(),
crc.ToHexString().c_str(),
expectedcrc->ToHexString().c_str());
struct ErrorRecord er;
AdlerChecksum crc;
if (tag_mode_) {
- AdlerAddrMemcpyC(targetmem, sourcemem, blocksize, &crc, srcpe);
+ AdlerAddrMemcpyWarm(targetmem, sourcemem, blocksize, &crc, srcpe);
} else {
os_->AdlerMemcpyWarm(targetmem, sourcemem, blocksize, &crc);
}
blocksize,
currentblock * blocksize, 0);
if (errorcount == 0) {
- logprintf(0, "Process Error: CrcWarmCopyPage CRC mismatch %s "
- "!= %s, but no miscompares found on second pass.\n",
+ int apic_id = apicid();
+ logprintf(0, "Process Error: CPU %d(0x%s) CrciWarmCopyPage "
+ "CRC mismatch %s != %s, "
+ "but no miscompares found on second pass.\n",
+ apic_id, CurrentCpusFormat().c_str(),
crc.ToHexString().c_str(),
expectedcrc->ToHexString().c_str());
+ struct ErrorRecord er;
+ er.actual = sourcemem[0];
+ er.expected = 0x0;
+ er.vaddr = sourcemem;
+ ProcessError(&er, 0, "Hardware Error");
}
}
}
// Memory check work loop. Execute until done, then exhaust pages.
-int CheckThread::Work() {
+bool CheckThread::Work() {
struct page_entry pe;
- int result = 1;
+ bool result = true;
int64 loops = 0;
logprintf(9, "Log: Starting Check thread %d\n", thread_num_);
// We want to check all the pages, and
// stop when there aren't any left.
- while (1) {
- result &= sat_->GetValid(&pe);
+ while (true) {
+ result = result && sat_->GetValid(&pe);
if (!result) {
if (IsReadyToRunNoPause())
logprintf(0, "Process Error: check_thread failed to pop pages, "
"bailing\n");
else
- result = 1;
+ result = true;
break;
}
// Push pages back on the valid queue if we are still going,
// throw them out otherwise.
if (IsReadyToRunNoPause())
- result &= sat_->PutValid(&pe);
+ result = result && sat_->PutValid(&pe);
else
- result &= sat_->PutEmpty(&pe);
+ result = result && sat_->PutEmpty(&pe);
if (!result) {
logprintf(0, "Process Error: check_thread failed to push pages, "
"bailing\n");
status_ = result;
logprintf(9, "Log: Completed %d: Check thread. Status %d, %d pages checked\n",
thread_num_, status_, pages_copied_);
- return 1;
+ return result;
}
// Memory copy work loop. Execute until marked done.
-int CopyThread::Work() {
+bool CopyThread::Work() {
struct page_entry src;
struct page_entry dst;
- int result = 1;
+ bool result = true;
int64 loops = 0;
- logprintf(9, "Log: Starting copy thread %d: cpu %x, mem %x\n",
- thread_num_, cpu_mask_, tag_);
+ logprintf(9, "Log: Starting copy thread %d: cpu %s, mem %x\n",
+ thread_num_, cpuset_format(&cpu_mask_).c_str(), tag_);
while (IsReadyToRun()) {
// Pop the needed pages.
- result &= sat_->GetValid(&src, tag_);
- result &= sat_->GetEmpty(&dst, tag_);
+ result = result && sat_->GetValid(&src, tag_);
+ result = result && sat_->GetEmpty(&dst, tag_);
if (!result) {
logprintf(0, "Process Error: copy_thread failed to pop pages, "
"bailing\n");
dst.pattern = src.pattern;
}
- result &= sat_->PutValid(&dst);
- result &= sat_->PutEmpty(&src);
+ result = result && sat_->PutValid(&dst);
+ result = result && sat_->PutEmpty(&src);
// Copy worker-threads yield themselves at the end of each copy loop,
// to avoid threads from preempting each other in the middle of the inner
status_ = result;
logprintf(9, "Log: Completed %d: Copy thread. Status %d, %d pages copied\n",
thread_num_, status_, pages_copied_);
- return 1;
+ return result;
}
// Memory invert work loop. Execute until marked done.
-int InvertThread::Work() {
+bool InvertThread::Work() {
struct page_entry src;
- int result = 1;
+ bool result = true;
int64 loops = 0;
logprintf(9, "Log: Starting invert thread %d\n", thread_num_);
while (IsReadyToRun()) {
// Pop the needed pages.
- result &= sat_->GetValid(&src);
+ result = result && sat_->GetValid(&src);
if (!result) {
logprintf(0, "Process Error: invert_thread failed to pop pages, "
"bailing\n");
if (sat_->strict())
CrcCheckPage(&src);
- result &= sat_->PutValid(&src);
+ result = result && sat_->PutValid(&src);
if (!result) {
logprintf(0, "Process Error: invert_thread failed to push pages, "
"bailing\n");
status_ = result;
logprintf(9, "Log: Completed %d: Copy thread. Status %d, %d pages copied\n",
thread_num_, status_, pages_copied_);
- return 1;
+ return result;
}
logprintf(0, "Process Error: Failed to create file %s!!\n",
filename_.c_str());
pages_copied_ = 0;
- status_ = 0;
- return 0;
+ return false;
}
*pfile = fd;
- return 1;
+ return true;
}
// Close the file.
bool FileThread::CloseFile(int fd) {
close(fd);
- return 1;
+ return true;
}
// Check sector tagging.
int strict = sat_->strict();
// Start fresh at beginning of file for each batch of pages.
- lseek(fd, 0, SEEK_SET);
+ lseek64(fd, 0, SEEK_SET);
for (int i = 0; i < sat_->disk_pages(); i++) {
struct page_entry src;
if (!GetValidPage(&src))
logprintf(0, "Process Error: disk thread posix_memalign "
"returned %d (fail)\n",
result);
- status_ += 1;
+ status_ = false;
return false;
}
}
return true;
}
-
-
// Copy data from file into memory blocks.
bool FileThread::ReadPages(int fd) {
int page_length = sat_->page_length();
int strict = sat_->strict();
- int result = 1;
-
+ bool result = true;
// Read our data back out of the file, into it's new location.
- lseek(fd, 0, SEEK_SET);
+ lseek64(fd, 0, SEEK_SET);
for (int i = 0; i < sat_->disk_pages(); i++) {
struct page_entry dst;
if (!GetEmptyPage(&dst))
return result;
}
-
// File IO work loop. Execute until marked done.
-int FileThread::Work() {
- int result = 1;
- int fileresult = 1;
+bool FileThread::Work() {
+ bool result = true;
int64 loops = 0;
logprintf(9, "Log: Starting file thread %d, file %s, device %s\n",
filename_.c_str(),
devicename_.c_str());
- if (!PagePrepare())
- return 0;
+ if (!PagePrepare()) {
+ status_ = false;
+ return false;
+ }
// Open the data IO file.
int fd = 0;
- if (!OpenFile(&fd))
- return 0;
+ if (!OpenFile(&fd)) {
+ status_ = false;
+ return false;
+ }
pass_ = 0;
// Loop until done.
while (IsReadyToRun()) {
// Do the file write.
- if (!(fileresult &= WritePages(fd)))
+ if (!(result = result && WritePages(fd)))
break;
// Do the file read.
- if (!(fileresult &= ReadPages(fd)))
+ if (!(result = result && ReadPages(fd)))
break;
loops++;
logprintf(9, "Log: Completed %d: file thread status %d, %d pages copied\n",
thread_num_, status_, pages_copied_);
- return 1;
+ return result;
}
bool NetworkThread::IsNetworkStopSet() {
if (sock == -1) {
logprintf(0, "Process Error: Cannot open socket\n");
pages_copied_ = 0;
- status_ = 0;
+ status_ = false;
return false;
}
*psocket = sock;
if (inet_aton(ipaddr_, &dest_addr.sin_addr) == 0) {
logprintf(0, "Process Error: Cannot resolve %s\n", ipaddr_);
pages_copied_ = 0;
- status_ = 0;
+ status_ = false;
return false;
}
sizeof(struct sockaddr))) {
logprintf(0, "Process Error: Cannot connect %s\n", ipaddr_);
pages_copied_ = 0;
- status_ = 0;
+ status_ = false;
return false;
}
return true;
sat_strerror(errno, buf, sizeof(buf));
logprintf(0, "Process Error: Cannot bind socket: %s\n", buf);
pages_copied_ = 0;
- status_ = 0;
+ status_ = false;
return false;
}
listen(sock_, 3);
if (newsock < 0) {
logprintf(0, "Process Error: Did not receive connection\n");
pages_copied_ = 0;
- status_ = 0;
+ status_ = false;
return false;
}
*pnewsock = newsock;
return true;
}
+// Send a page, return false if a page was not sent.
bool NetworkThread::SendPage(int sock, struct page_entry *src) {
int page_length = sat_->page_length();
char *address = static_cast<char*>(src->addr);
logprintf(0, "Process Error: Thread %d, "
"Network write failed, bailing. (%s)\n",
thread_num_, buf);
+ status_ = false;
}
return false;
}
return true;
}
-
+// Receive a page. Return false if a page was not received.
bool NetworkThread::ReceivePage(int sock, struct page_entry *dst) {
int page_length = sat_->page_length();
char *address = static_cast<char*>(dst->addr);
logprintf(0, "Process Error: Thread %d, "
"Network read failed, bailing (%s).\n",
thread_num_, buf);
+ status_ = false;
// Print arguments and results.
logprintf(0, "Log: recv(%d, address %x, size %x, 0) == %x, err %d\n",
sock, address + (page_length - size),
return true;
}
-
// Network IO work loop. Execute until marked done.
-int NetworkThread::Work() {
+// Return true if the thread ran as expected.
+bool NetworkThread::Work() {
logprintf(9, "Log: Starting network thread %d, ip %s\n",
thread_num_,
ipaddr_);
// Make a socket.
int sock = 0;
if (!CreateSocket(&sock))
- return 0;
+ return false;
// Network IO loop requires network slave thread to have already initialized.
// We will sleep here for awhile to ensure that the slave thread will be
// Connect to a slave thread.
if (!Connect(sock))
- return 0;
+ return false;
// Loop until done.
- int result = 1;
+ bool result = true;
int strict = sat_->strict();
int64 loops = 0;
while (IsReadyToRun()) {
struct page_entry src;
struct page_entry dst;
- result &= sat_->GetValid(&src);
- result &= sat_->GetEmpty(&dst);
+ result = result && sat_->GetValid(&src);
+ result = result && sat_->GetEmpty(&dst);
if (!result) {
logprintf(0, "Process Error: net_thread failed to pop pages, "
"bailing\n");
CrcCheckPage(&src);
// Do the network write.
- if (!(result &= SendPage(sock, &src)))
+ if (!(result = result && SendPage(sock, &src)))
break;
// Update pattern reference to reflect new contents.
dst.pattern = src.pattern;
// Do the network read.
- if (!(result &= ReceivePage(sock, &dst)))
+ if (!(result = result && ReceivePage(sock, &dst)))
break;
// Ensure that the transfer ended up with correct data.
CrcCheckPage(&dst);
// Return all of our pages to the queue.
- result &= sat_->PutValid(&dst);
- result &= sat_->PutEmpty(&src);
+ result = result && sat_->PutValid(&dst);
+ result = result && sat_->PutEmpty(&src);
if (!result) {
logprintf(0, "Process Error: net_thread failed to push pages, "
"bailing\n");
logprintf(9, "Log: Completed %d: network thread status %d, "
"%d pages copied\n",
thread_num_, status_, pages_copied_);
- return 1;
+ return result;
}
// Spawn slave threads for incoming connections.
}
// Network listener IO work loop. Execute until marked done.
-int NetworkListenThread::Work() {
- int result = 1;
+// Return false on fatal software error.
+bool NetworkListenThread::Work() {
logprintf(9, "Log: Starting network listen thread %d\n",
thread_num_);
// Make a socket.
sock_ = 0;
- if (!CreateSocket(&sock_))
- return 0;
+ if (!CreateSocket(&sock_)) {
+ status_ = false;
+ return false;
+ }
logprintf(9, "Log: Listen thread created sock\n");
// Allows incoming connections to be queued up by socket library.
CloseSocket(sock_);
- status_ = result;
+ status_ = true;
logprintf(9,
"Log: Completed %d: network listen thread status %d, "
"%d pages copied\n",
thread_num_, status_, pages_copied_);
- return 1;
+ return true;
}
// Set network reflector socket struct.
}
// Network reflector IO work loop. Execute until marked done.
-int NetworkSlaveThread::Work() {
+// Return false on fatal software error.
+bool NetworkSlaveThread::Work() {
logprintf(9, "Log: Starting network slave thread %d\n",
thread_num_);
// Verify that we have a socket.
int sock = sock_;
- if (!sock)
- return 0;
+ if (!sock) {
+ status_ = false;
+ return false;
+ }
// Loop until done.
int64 loops = 0;
logprintf(0, "Process Error: net slave posix_memalign "
"returned %d (fail)\n",
result);
- status_ += 1;
+ status_ = false;
return false;
}
pages_copied_ = loops;
// No results provided from this type of thread.
- status_ = 1;
+ status_ = true;
// Clean up.
CloseSocket(sock);
"Log: Completed %d: network slave thread status %d, "
"%d pages copied\n",
thread_num_, status_, pages_copied_);
- return status_;
+ return true;
}
// Thread work loop. Execute until marked finished.
-int ErrorPollThread::Work() {
+bool ErrorPollThread::Work() {
logprintf(9, "Log: Starting system error poll thread %d\n", thread_num_);
// This calls a generic error polling function in the Os abstraction layer.
logprintf(9, "Log: Finished system error poll thread %d: %d errors\n",
thread_num_, errorcount_);
- status_ = 1;
- return 1;
+ status_ = true;
+ return true;
}
// Worker thread to heat up CPU.
-int CpuStressThread::Work() {
+// This thread does not evaluate pass/fail or software error.
+bool CpuStressThread::Work() {
logprintf(9, "Log: Starting CPU stress thread %d\n", thread_num_);
do {
logprintf(9, "Log: Finished CPU stress thread %d:\n",
thread_num_);
- status_ = 1;
- return 1;
+ status_ = true;
+ return true;
}
CpuCacheCoherencyThread::CpuCacheCoherencyThread(cc_cacheline_data *data,
}
// Worked thread to test the cache coherency of the CPUs
-int CpuCacheCoherencyThread::Work() {
+// Return false on fatal sw error.
+bool CpuCacheCoherencyThread::Work() {
logprintf(9, "Log: Starting the Cache Coherency thread %d\n",
cc_thread_num_);
uint64 time_start, time_end;
cc_thread_num_, us_elapsed, total_inc, inc_rate);
logprintf(9, "Log: Finished CPU Cache Coherency thread %d:\n",
cc_thread_num_);
- status_ = 1;
- return 1;
+ status_ = true;
+ return true;
}
DiskThread::DiskThread(DiskBlockTable *block_table) {
update_block_table_ = 1;
block_buffer_ = NULL;
+
+ blocks_written_ = 0;
+ blocks_read_ = 0;
}
DiskThread::~DiskThread() {
+ if (block_buffer_)
+ free(block_buffer_);
}
// Set filename for device file (in /dev).
return true;
}
+// Open a device, return false on failure.
bool DiskThread::OpenDevice(int *pfile) {
int fd = open(device_name_.c_str(),
O_RDWR | O_SYNC | O_DIRECT | O_LARGEFILE,
}
// Retrieves the size (in bytes) of the disk/file.
+// Return false on failure.
bool DiskThread::GetDiskSize(int fd) {
struct stat device_stat;
if (fstat(fd, &device_stat) == -1) {
if (block_size == 0) {
os_->ErrorReport(device_name_.c_str(), "device-size-zero", 1);
++errorcount_;
- status_ = 1; // Avoid a procedural error.
+ status_ = true; // Avoid a procedural error.
return false;
}
return tv.tv_sec * 1000000 + tv.tv_usec;
}
+// Do randomized reads and (possibly) writes on a device.
+// Return false on fatal error, either SW or HW.
bool DiskThread::DoWork(int fd) {
int64 block_num = 0;
- blocks_written_ = 0;
- blocks_read_ = 0;
int64 num_segments;
+ bool result = true;
if (segment_size_ == -1) {
num_segments = 1;
while (IsReadyToRun()) {
// Write blocks to disk.
- logprintf(16, "Write phase for disk %s (thread %d).\n",
+ logprintf(16, "Log: Write phase %sfor disk %s (thread %d).\n",
+ non_destructive_ ? "(disabled) " : "",
device_name_.c_str(), thread_num_);
while (IsReadyToRunNoPause() &&
in_flight_sectors_.size() < queue_size_ + 1) {
// Confine testing to a particular segment of the disk.
int64 segment = (block_num / blocks_per_segment_) % num_segments;
- if (block_num % blocks_per_segment_ == 0) {
+ if (!non_destructive_ &&
+ (block_num % blocks_per_segment_ == 0)) {
logprintf(20, "Log: Starting to write segment %lld out of "
"%lld on disk %s (thread %d).\n",
segment, num_segments, device_name_.c_str(),
if (!non_destructive_) {
if (!WriteBlockToDisk(fd, block)) {
block_table_->RemoveBlock(block);
- continue;
+ return false;
}
+ blocks_written_++;
}
+ // Block is either initialized by writing, or in nondestructive case,
+ // initialized by being added into the datastructure for later reading.
block->SetBlockAsInitialized();
- blocks_written_++;
in_flight_sectors_.push(block);
}
// Verify blocks on disk.
- logprintf(20, "Read phase for disk %s (thread %d).\n",
+ logprintf(20, "Log: Read phase for disk %s (thread %d).\n",
device_name_.c_str(), thread_num_);
while (IsReadyToRunNoPause() && !in_flight_sectors_.empty()) {
BlockData *block = in_flight_sectors_.front();
in_flight_sectors_.pop();
- ValidateBlockOnDisk(fd, block);
+ if (!ValidateBlockOnDisk(fd, block))
+ return false;
block_table_->RemoveBlock(block);
blocks_read_++;
}
}
pages_copied_ = blocks_written_ + blocks_read_;
- return true;
+ return result;
}
// Do an asynchronous disk I/O operation.
+// Return false if the IO is not set up.
bool DiskThread::AsyncDiskIO(IoOp op, int fd, void *buf, int64 size,
int64 offset, int64 timeout) {
// Use the Linux native asynchronous I/O interface for reading/writing.
const char *op_str;
const char *error_str;
} operations[2] = {
- { IOCB_CMD_PREAD, "read", "disk-read-error" },
- { IOCB_CMD_PWRITE, "write", "disk-write-error" }
+ { IO_CMD_PREAD, "read", "disk-read-error" },
+ { IO_CMD_PWRITE, "write", "disk-write-error" }
};
struct iocb cb;
cb.aio_fildes = fd;
cb.aio_lio_opcode = operations[op].opcode;
- cb.aio_buf = (__u64)buf;
- cb.aio_nbytes = size;
- cb.aio_offset = offset;
+ cb.u.c.buf = buf;
+ cb.u.c.nbytes = size;
+ cb.u.c.offset = offset;
struct iocb *cbs[] = { &cb };
if (io_submit(aio_ctx_, 1, cbs) != 1) {
+ int error = errno;
+ char buf[256];
+ sat_strerror(error, buf, sizeof(buf));
logprintf(0, "Process Error: Unable to submit async %s "
- "on disk %s (thread %d).\n",
+ "on disk %s (thread %d). Error %d, %s\n",
operations[op].op_str, device_name_.c_str(),
- thread_num_);
+ thread_num_, error, buf);
return false;
}
// A ctrl-c from the keyboard will cause io_getevents to fail with an
// EINTR error code. This is not an error and so don't treat it as such,
// but still log it.
- if (errno == EINTR) {
+ int error = errno;
+ if (error == EINTR) {
logprintf(5, "Log: %s interrupted on disk %s (thread %d).\n",
operations[op].op_str, device_name_.c_str(),
thread_num_);
io_destroy(aio_ctx_);
aio_ctx_ = 0;
if (io_setup(5, &aio_ctx_)) {
+ int error = errno;
+ char buf[256];
+ sat_strerror(error, buf, sizeof(buf));
logprintf(0, "Process Error: Unable to create aio context on disk %s"
- " (thread %d).\n",
- device_name_.c_str(), thread_num_);
+ " (thread %d) Error %d, %s\n",
+ device_name_.c_str(), thread_num_, error, buf);
}
return false;
}
// Write a block to disk.
+// Return false if the block is not written.
bool DiskThread::WriteBlockToDisk(int fd, BlockData *block) {
memset(block_buffer_, 0, block->GetSize());
}
// Verify a block on disk.
+// Return true if the block was read, also increment errorcount
+// if the block had data errors or performance problems.
bool DiskThread::ValidateBlockOnDisk(int fd, BlockData *block) {
int64 blocks = block->GetSize() / read_block_size_;
int64 bytes_read = 0;
// Read block from disk and time the read. If it takes longer than the
// threshold, complain.
- if (lseek(fd, address * kSectorSize, SEEK_SET) == -1) {
+ if (lseek64(fd, address * kSectorSize, SEEK_SET) == -1) {
logprintf(0, "Process Error: Unable to seek to sector %lld in "
"DiskThread::ValidateSectorsOnDisk on disk %s "
"(thread %d).\n", address, device_name_.c_str(), thread_num_);
// read them in groups of randomly-sized multiples of read block size.
// This assures all data written on disk by this particular block
// will be tested using a random reading pattern.
-
while (blocks != 0) {
// Test all read blocks in a written block.
current_blocks = (random() % blocks) + 1;
return true;
}
-int DiskThread::Work() {
+// Direct device access thread.
+// Return false on software error.
+bool DiskThread::Work() {
int fd;
logprintf(9, "Log: Starting disk thread %d, disk %s\n",
srandom(time(NULL));
if (!OpenDevice(&fd)) {
- return 0;
+ status_ = false;
+ return false;
}
// Allocate a block buffer aligned to 512 bytes since the kernel requires it
// when using direst IO.
-
- int result = posix_memalign(&block_buffer_, kBufferAlignment,
+ int memalign_result = posix_memalign(&block_buffer_, kBufferAlignment,
sat_->page_length());
- if (result) {
+ if (memalign_result) {
CloseDevice(fd);
logprintf(0, "Process Error: Unable to allocate memory for buffers "
"for disk %s (thread %d) posix memalign returned %d.\n",
- device_name_.c_str(), thread_num_, result);
- status_ += 1;
+ device_name_.c_str(), thread_num_, memalign_result);
+ status_ = false;
return false;
}
if (io_setup(5, &aio_ctx_)) {
+ CloseDevice(fd);
logprintf(0, "Process Error: Unable to create aio context for disk %s"
" (thread %d).\n",
device_name_.c_str(), thread_num_);
- return 0;
+ status_ = false;
+ return false;
}
- DoWork(fd);
+ bool result = DoWork(fd);
- status_ = 1;
+ status_ = result;
io_destroy(aio_ctx_);
CloseDevice(fd);
- free(block_buffer_);
logprintf(9, "Log: Completed %d (disk %s): disk thread status %d, "
"%d pages copied\n",
thread_num_, device_name_.c_str(), status_, pages_copied_);
- return 1;
+ return result;
}
RandomDiskThread::RandomDiskThread(DiskBlockTable *block_table)
RandomDiskThread::~RandomDiskThread() {
}
+// Workload for random disk thread.
bool RandomDiskThread::DoWork(int fd) {
- blocks_read_ = 0;
- blocks_written_ = 0;
- logprintf(11, "Random phase for disk %s (thread %d).\n",
+ logprintf(11, "Log: Random phase for disk %s (thread %d).\n",
device_name_.c_str(), thread_num_);
while (IsReadyToRun()) {
BlockData *block = block_table_->GetRandomBlock();
if (block == NULL) {
- logprintf(12, "No block available for device %s (thread %d).\n",
+ logprintf(12, "Log: No block available for device %s (thread %d).\n",
device_name_.c_str(), thread_num_);
} else {
ValidateBlockOnDisk(fd, block);
delete pages_;
}
+// Set a region of memory or MMIO to be tested.
+// Return false if region could not be mapped.
bool MemoryRegionThread::SetRegion(void *region, int64 size) {
int plength = sat_->page_length();
int npages = size / plength;
}
}
+// More detailed error printout for hardware errors in memory or MMIO
+// regions.
void MemoryRegionThread::ProcessError(struct ErrorRecord *error,
int priority,
const char *message) {
}
}
-int MemoryRegionThread::Work() {
+// Workload for testion memory or MMIO regions.
+// Return false on software error.
+bool MemoryRegionThread::Work() {
struct page_entry source_pe;
struct page_entry memregion_pe;
- int result = 1;
+ bool result = true;
int64 loops = 0;
const uint64 error_constant = 0x00ba00000000ba00LL;
while (IsReadyToRun()) {
// Getting pages from SAT and queue.
phase_ = kPhaseNoPhase;
- result &= sat_->GetValid(&source_pe);
+ result = result && sat_->GetValid(&source_pe);
if (!result) {
logprintf(0, "Process Error: memory region thread failed to pop "
"pages from SAT, bailing\n");
break;
}
- result &= pages_->PopRandom(&memregion_pe);
+ result = result && pages_->PopRandom(&memregion_pe);
if (!result) {
logprintf(0, "Process Error: memory region thread failed to pop "
"pages from queue, bailing\n");
phase_ = kPhaseNoPhase;
// Storing pages on their proper queues.
- result &= sat_->PutValid(&source_pe);
+ result = result && sat_->PutValid(&source_pe);
if (!result) {
logprintf(0, "Process Error: memory region thread failed to push "
"pages into SAT, bailing\n");
break;
}
- result &= pages_->Push(&memregion_pe);
+ result = result && pages_->Push(&memregion_pe);
if (!result) {
logprintf(0, "Process Error: memory region thread failed to push "
"pages into queue, bailing\n");
status_ = result;
logprintf(9, "Log: Completed %d: Memory Region thread. Status %d, %d "
"pages checked\n", thread_num_, status_, pages_copied_);
- return 1;
+ return result;
}