blob: 3631fd7c67add15356c95b20069a7008a81556da [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <endian.h>
#include <optional>
#include <fbl/span.h>
#include "src/lib/fxl/strings/string_printf.h"
#include "util.h"
// This file contains functions for generating patterns, writing
// patterns to a span of memory, and verifying patterns from a span of
// memory.
namespace hwstress {
// Rotate the given multi-word pattern right by N bits.
std::vector<uint64_t> RotatePattern(std::vector<uint64_t> v, uint64_t n);
// Invert (bitwise negate) the words in the vector.
std::vector<uint64_t> NegateWords(std::vector<uint64_t> v);
// Return a constant word as a pattern.
//
// The word is always written in memory as a big-endian word. That is, the
// pattern 0x1122334455667788 will be written out as bytes 0x11, 0x22, ..., 0x88
// at increasing memory addresses.
inline auto SimplePattern(uint64_t word) {
return [w = htobe64(word)]() { return w; };
}
// Invert the given pattern.
template <typename Pattern>
inline auto InvertPattern(Pattern p) {
return [p = std::move(p)]() mutable { return ~p(); };
}
// Return a pseudo-random stream of values.
inline auto RandomPattern() {
std::random_device device;
fast_64bit_rng rng(device());
return [rng = rng]() mutable { return rng(); };
}
// Repeat the same multi-word pattern.
//
// The values are written to memory in big-endian format. That is, the
// vector [0x1122, 0x3344, 0x5566, 0x7788] will be written out as bytes
// 0x11, 0x22, ..., 0x88 at increasing memory addresses.
inline auto MultiWordPattern(std::vector<uint64_t> pattern) {
uint64_t i = 0;
// Convert to big-endian format.
for (uint64_t& word : pattern) {
word = htobe64(word);
}
return [i, pattern = std::move(pattern)]() mutable { return pattern[i++ % pattern.size()]; };
}
// Write the given pattern out to memory.
//
// Patterns are written out in native-endian format. If a particular
// endian conversion is required, it must be converted by the PatternGenerator.
template <typename PatternGenerator>
void WritePattern(fbl::Span<uint8_t> range, PatternGenerator pattern) {
auto* __restrict start = reinterpret_cast<uint64_t*>(range.begin());
size_t words = range.size_bytes() / sizeof(uint64_t);
for (size_t i = 0; i < words; i++) {
start[i] = pattern();
}
}
// Verify the given pattern is in memory.
template <typename PatternGenerator>
std::optional<std::string> VerifyPattern(fbl::Span<uint8_t> range, PatternGenerator pattern) {
auto* __restrict start = reinterpret_cast<uint64_t*>(range.begin());
size_t words = range.size_bytes() / sizeof(uint64_t);
// Find any mismatches.
for (size_t i = 0; i < words; i++) {
uint64_t expected = pattern();
uint64_t actual = start[i];
if (unlikely(expected != actual)) {
return fxl::StringPrintf("Expected 0x%016lx, got 0x%16lx at offset %ld.", expected, actual,
i * sizeof(uint64_t));
}
}
return std::nullopt;
}
} // namespace hwstress