| // 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 |