mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 10:35:50 +00:00
Compare commits
42 Commits
a1q123456/
...
a1q123456/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0d2168d34 | ||
|
|
62dbd3d1d3 | ||
|
|
4565e97af9 | ||
|
|
2169abc438 | ||
|
|
404ea567ef | ||
|
|
f59a3c81c1 | ||
|
|
c65b13c730 | ||
|
|
3e13bd036e | ||
|
|
0b29ff0bf7 | ||
|
|
af284bf23f | ||
|
|
47a73e6b0f | ||
|
|
c3a7ae3730 | ||
|
|
ac5ff24323 | ||
|
|
4ec90d7c73 | ||
|
|
0a21224c98 | ||
|
|
881f5d9d71 | ||
|
|
780816a2ec | ||
|
|
5e49158258 | ||
|
|
b82ec378c9 | ||
|
|
09bcaaa035 | ||
|
|
775e8e4af7 | ||
|
|
0dc0bc42ba | ||
|
|
41d9d9528c | ||
|
|
4483921eeb | ||
|
|
28c37ba244 | ||
|
|
e2a83c9205 | ||
|
|
6379bf1953 | ||
|
|
3e71229185 | ||
|
|
d2ee6f0c9d | ||
|
|
13410f2a76 | ||
|
|
e11e805c34 | ||
|
|
09abafd8d6 | ||
|
|
0f9f3a0834 | ||
|
|
f62e9c0ba5 | ||
|
|
0590c13de3 | ||
|
|
95b9a77126 | ||
|
|
f85432aee4 | ||
|
|
a6f97ed7b3 | ||
|
|
092c37f52e | ||
|
|
a3651b417c | ||
|
|
00697a49fe | ||
|
|
6d730f9ffb |
@@ -7,13 +7,13 @@ comment:
|
|||||||
show_carryforward_flags: false
|
show_carryforward_flags: false
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
range: "60..80"
|
range: "70..85"
|
||||||
precision: 1
|
precision: 1
|
||||||
round: nearest
|
round: nearest
|
||||||
status:
|
status:
|
||||||
project:
|
project:
|
||||||
default:
|
default:
|
||||||
target: 60%
|
target: 75%
|
||||||
threshold: 2%
|
threshold: 2%
|
||||||
patch:
|
patch:
|
||||||
default:
|
default:
|
||||||
|
|||||||
14
.github/workflows/macos.yml
vendored
14
.github/workflows/macos.yml
vendored
@@ -71,6 +71,9 @@ jobs:
|
|||||||
nproc --version
|
nproc --version
|
||||||
echo -n "nproc returns: "
|
echo -n "nproc returns: "
|
||||||
nproc
|
nproc
|
||||||
|
system_profiler SPHardwareDataType
|
||||||
|
sysctl -n hw.logicalcpu
|
||||||
|
clang --version
|
||||||
- name: configure Conan
|
- name: configure Conan
|
||||||
run : |
|
run : |
|
||||||
conan profile new default --detect || true
|
conan profile new default --detect || true
|
||||||
@@ -89,9 +92,8 @@ jobs:
|
|||||||
generator: ${{ matrix.generator }}
|
generator: ${{ matrix.generator }}
|
||||||
configuration: ${{ matrix.configuration }}
|
configuration: ${{ matrix.configuration }}
|
||||||
cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}"
|
cmake-args: "-Dassert=TRUE -Dwerr=TRUE ${{ matrix.cmake-args }}"
|
||||||
# TODO: Temporary disabled tests
|
- name: test
|
||||||
# - name: test
|
run: |
|
||||||
# run: |
|
n=$(nproc)
|
||||||
# n=$(nproc)
|
echo "Using $n test jobs"
|
||||||
# echo "Using $n test jobs"
|
${build_dir}/rippled --unittest --unittest-jobs $n
|
||||||
# ${build_dir}/rippled --unittest --unittest-jobs $n
|
|
||||||
|
|||||||
2
.github/workflows/nix.yml
vendored
2
.github/workflows/nix.yml
vendored
@@ -247,7 +247,7 @@ jobs:
|
|||||||
mkdir -p ~/.conan
|
mkdir -p ~/.conan
|
||||||
tar -xzf conan.tar -C ~/.conan
|
tar -xzf conan.tar -C ~/.conan
|
||||||
- name: install gcovr
|
- name: install gcovr
|
||||||
run: pip install "gcovr>=7,<8"
|
run: pip install "gcovr>=7,<9"
|
||||||
- name: check environment
|
- name: check environment
|
||||||
run: |
|
run: |
|
||||||
echo ${PATH} | tr ':' '\n'
|
echo ${PATH} | tr ':' '\n'
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
[](https://codecov.io/gh/XRPLF/rippled)
|
||||||
|
|
||||||
# The XRP Ledger
|
# The XRP Ledger
|
||||||
|
|
||||||
The [XRP Ledger](https://xrpl.org/) is a decentralized cryptographic ledger powered by a network of peer-to-peer nodes. The XRP Ledger uses a novel Byzantine Fault Tolerant consensus algorithm to settle and record transactions in a secure distributed database without a central operator.
|
The [XRP Ledger](https://xrpl.org/) is a decentralized cryptographic ledger powered by a network of peer-to-peer nodes. The XRP Ledger uses a novel Byzantine Fault Tolerant consensus algorithm to settle and record transactions in a secure distributed database without a central operator.
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#
|
#
|
||||||
# Examples:
|
# Examples:
|
||||||
# https://vl.ripple.com
|
# https://vl.ripple.com
|
||||||
# https://vl.xrplf.org
|
# https://unl.xrplf.org
|
||||||
# http://127.0.0.1:8000
|
# http://127.0.0.1:8000
|
||||||
# file:///etc/opt/ripple/vl.txt
|
# file:///etc/opt/ripple/vl.txt
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -98,6 +98,9 @@
|
|||||||
# 2024-04-03, Bronek Kozicki
|
# 2024-04-03, Bronek Kozicki
|
||||||
# - add support for output formats: jacoco, clover, lcov
|
# - add support for output formats: jacoco, clover, lcov
|
||||||
#
|
#
|
||||||
|
# 2025-05-12, Jingchen Wu
|
||||||
|
# - add -fprofile-update=atomic to ensure atomic profile generation
|
||||||
|
#
|
||||||
# USAGE:
|
# USAGE:
|
||||||
#
|
#
|
||||||
# 1. Copy this file into your cmake modules path.
|
# 1. Copy this file into your cmake modules path.
|
||||||
@@ -200,15 +203,27 @@ set(COVERAGE_COMPILER_FLAGS "-g --coverage"
|
|||||||
CACHE INTERNAL "")
|
CACHE INTERNAL "")
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
|
||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
|
include(CheckCCompilerFlag)
|
||||||
|
|
||||||
check_cxx_compiler_flag(-fprofile-abs-path HAVE_cxx_fprofile_abs_path)
|
check_cxx_compiler_flag(-fprofile-abs-path HAVE_cxx_fprofile_abs_path)
|
||||||
if(HAVE_cxx_fprofile_abs_path)
|
if(HAVE_cxx_fprofile_abs_path)
|
||||||
set(COVERAGE_CXX_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
|
set(COVERAGE_CXX_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
|
||||||
endif()
|
endif()
|
||||||
include(CheckCCompilerFlag)
|
|
||||||
check_c_compiler_flag(-fprofile-abs-path HAVE_c_fprofile_abs_path)
|
check_c_compiler_flag(-fprofile-abs-path HAVE_c_fprofile_abs_path)
|
||||||
if(HAVE_c_fprofile_abs_path)
|
if(HAVE_c_fprofile_abs_path)
|
||||||
set(COVERAGE_C_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
|
set(COVERAGE_C_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
check_cxx_compiler_flag(-fprofile-update HAVE_cxx_fprofile_update)
|
||||||
|
if(HAVE_cxx_fprofile_update)
|
||||||
|
set(COVERAGE_CXX_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-update=atomic")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
check_c_compiler_flag(-fprofile-update HAVE_c_fprofile_update)
|
||||||
|
if(HAVE_c_fprofile_update)
|
||||||
|
set(COVERAGE_C_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-update=atomic")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CMAKE_Fortran_FLAGS_COVERAGE
|
set(CMAKE_Fortran_FLAGS_COVERAGE
|
||||||
|
|||||||
120
include/xrpl/beast/core/FunctionProfiler.h
Normal file
120
include/xrpl/beast/core/FunctionProfiler.h
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
|
||||||
|
#ifndef RIPPLE_BASICS_FUNCTIONPROFILER_H_INCLUDED
|
||||||
|
#define RIPPLE_BASICS_FUNCTIONPROFILER_H_INCLUDED
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <csignal>
|
||||||
|
#include <mutex>
|
||||||
|
#include <source_location>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
#include <cmath>
|
||||||
|
#include <numeric> // std::accumulate
|
||||||
|
|
||||||
|
#define PROFILING 1
|
||||||
|
|
||||||
|
#if PROFILING && (defined(__x86_64__) || defined(_M_X64))
|
||||||
|
#include <x86intrin.h>
|
||||||
|
#else
|
||||||
|
#define __rdtsc() 0
|
||||||
|
#endif
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
double compute_stddev(const std::vector<T>& samples) {
|
||||||
|
if (samples.size() < 2) return 0.0;
|
||||||
|
|
||||||
|
double mean = std::accumulate(samples.begin(), samples.end(), 0.0) / samples.size();
|
||||||
|
double sum_sq = 0.0;
|
||||||
|
|
||||||
|
for (double x : samples) {
|
||||||
|
sum_sq += (x - mean) * (x - mean);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::sqrt(sum_sq / (samples.size() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
logProfilingResults();
|
||||||
|
|
||||||
|
class FunctionProfiler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string functionName;
|
||||||
|
std::chrono::steady_clock::time_point start;
|
||||||
|
std::uint64_t cpuCycleStart;
|
||||||
|
inline static std::mutex mutex_;
|
||||||
|
|
||||||
|
struct StatisticData
|
||||||
|
{
|
||||||
|
std::vector<std::chrono::nanoseconds> time;
|
||||||
|
std::vector<std::uint64_t> cpuCycles;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline static std::unordered_map<
|
||||||
|
std::string,
|
||||||
|
StatisticData>
|
||||||
|
funcionDurations;
|
||||||
|
FunctionProfiler(
|
||||||
|
std::string const& tag,
|
||||||
|
std::source_location location = std::source_location::current())
|
||||||
|
#if PROFILING
|
||||||
|
: functionName(location.function_name() + tag)
|
||||||
|
, start(std::chrono::steady_clock::now())
|
||||||
|
, cpuCycleStart(__rdtsc())
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~FunctionProfiler() noexcept
|
||||||
|
{
|
||||||
|
#if PROFILING
|
||||||
|
auto duration = std::chrono::steady_clock::now() - start;
|
||||||
|
std::lock_guard<std::mutex> lock{mutex_};
|
||||||
|
funcionDurations[functionName].time.emplace_back(duration);
|
||||||
|
funcionDurations[functionName].cpuCycles.emplace_back((__rdtsc() - cpuCycleStart));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::string
|
||||||
|
getProfilingResults()
|
||||||
|
{
|
||||||
|
#if PROFILING
|
||||||
|
std::lock_guard<std::mutex> lock{FunctionProfiler::mutex_};
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Function profiling results:" << std::endl;
|
||||||
|
ss << "name,time,cpu cycles,count,average time(ns),time standard deviation,average cpu cycles,cpu cycles standard deviation" << std::endl;
|
||||||
|
for (auto const& [name, duration] : FunctionProfiler::funcionDurations)
|
||||||
|
{
|
||||||
|
std::vector<std::int64_t> times;
|
||||||
|
times.reserve(duration.time.size());
|
||||||
|
|
||||||
|
std::transform(std::begin(duration.time), std::end(duration.time), std::back_inserter(times), [](const std::chrono::nanoseconds& time) {
|
||||||
|
return static_cast<std::int64_t>(time.count());
|
||||||
|
});
|
||||||
|
|
||||||
|
auto timeInTotal = std::accumulate(std::begin(times), std::end(times), std::int64_t{0});
|
||||||
|
auto cpuCyclesInTotal = std::accumulate(std::begin(duration.cpuCycles), std::end(duration.cpuCycles), std::int64_t{0});
|
||||||
|
|
||||||
|
ss << name << "," << timeInTotal << ","
|
||||||
|
<< cpuCyclesInTotal << ","
|
||||||
|
<< duration.time.size() << ","
|
||||||
|
<< timeInTotal / (double)duration.time.size() << ","
|
||||||
|
<< compute_stddev(times) << ","
|
||||||
|
<< cpuCyclesInTotal / (double)duration.cpuCycles.size() << ","
|
||||||
|
<< compute_stddev(duration.cpuCycles)
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
#else
|
||||||
|
return "";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace beast
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -20,24 +20,48 @@
|
|||||||
#ifndef BEAST_HASH_XXHASHER_H_INCLUDED
|
#ifndef BEAST_HASH_XXHASHER_H_INCLUDED
|
||||||
#define BEAST_HASH_XXHASHER_H_INCLUDED
|
#define BEAST_HASH_XXHASHER_H_INCLUDED
|
||||||
|
|
||||||
|
#include <xrpl/beast/core/FunctionProfiler.h>
|
||||||
|
|
||||||
#include <boost/endian/conversion.hpp>
|
#include <boost/endian/conversion.hpp>
|
||||||
|
|
||||||
#include <xxhash.h>
|
#include <xxhash.h>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <iostream>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
#include <span>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
#define ORIGINAL_HASH 0
|
||||||
|
#define BIT_SHIFT_HASH 0
|
||||||
|
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
class xxhasher
|
class xxhasher
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
using HashType = std::size_t;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// requires 64-bit std::size_t
|
// requires 64-bit std::size_t
|
||||||
static_assert(sizeof(std::size_t) == 8, "");
|
static_assert(sizeof(std::size_t) == 8, "");
|
||||||
|
|
||||||
|
#if ORIGINAL_HASH
|
||||||
XXH3_state_t* state_;
|
XXH3_state_t* state_;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if PROFILING
|
||||||
|
std::size_t totalSize_ = 0;
|
||||||
|
std::chrono::nanoseconds duration_{};
|
||||||
|
std::uint64_t cpuCycles = 0;
|
||||||
|
#endif
|
||||||
|
XXH64_hash_t seed_ = 0;
|
||||||
|
|
||||||
|
std::array<std::uint8_t, 40> buffer_;
|
||||||
|
std::span<std::uint8_t> readBuffer_;
|
||||||
|
std::span<std::uint8_t> writeBuffer_;
|
||||||
|
|
||||||
|
#if ORIGINAL_HASH
|
||||||
static XXH3_state_t*
|
static XXH3_state_t*
|
||||||
allocState()
|
allocState()
|
||||||
{
|
{
|
||||||
@@ -46,6 +70,24 @@ private:
|
|||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
setupBuffers()
|
||||||
|
{
|
||||||
|
writeBuffer_ = std::span{buffer_};
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
writeBuffer(void const* data, std::size_t len)
|
||||||
|
{
|
||||||
|
auto bytesToWrite = std::min(len, writeBuffer_.size());
|
||||||
|
|
||||||
|
std::memcpy(writeBuffer_.data(), data, bytesToWrite);
|
||||||
|
writeBuffer_ = writeBuffer_.subspan(bytesToWrite);
|
||||||
|
readBuffer_ = std::span{
|
||||||
|
std::begin(buffer_), buffer_.size() - writeBuffer_.size()};
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using result_type = std::size_t;
|
using result_type = std::size_t;
|
||||||
@@ -58,22 +100,48 @@ public:
|
|||||||
|
|
||||||
xxhasher()
|
xxhasher()
|
||||||
{
|
{
|
||||||
|
#if PROFILING
|
||||||
|
auto start = std::chrono::steady_clock::now();
|
||||||
|
auto cpuCyclesStart = __rdtsc();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ORIGINAL_HASH
|
||||||
state_ = allocState();
|
state_ = allocState();
|
||||||
XXH3_64bits_reset(state_);
|
XXH3_64bits_reset(state_);
|
||||||
|
#else
|
||||||
|
setupBuffers();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if PROFILING
|
||||||
|
duration_ += std::chrono::steady_clock::now() - start;
|
||||||
|
cpuCycles += (__rdtsc() - cpuCyclesStart);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ORIGINAL_HASH
|
||||||
~xxhasher() noexcept
|
~xxhasher() noexcept
|
||||||
{
|
{
|
||||||
XXH3_freeState(state_);
|
XXH3_freeState(state_);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
template <
|
template <
|
||||||
class Seed,
|
class Seed,
|
||||||
std::enable_if_t<std::is_unsigned<Seed>::value>* = nullptr>
|
std::enable_if_t<std::is_unsigned<Seed>::value>* = nullptr>
|
||||||
explicit xxhasher(Seed seed)
|
explicit xxhasher(Seed seed)
|
||||||
{
|
{
|
||||||
|
seed_ = seed;
|
||||||
|
|
||||||
|
|
||||||
|
#if ORIGINAL_HASH
|
||||||
|
auto start = std::chrono::steady_clock::now();
|
||||||
|
auto cpuCyclesStart = __rdtsc();
|
||||||
state_ = allocState();
|
state_ = allocState();
|
||||||
XXH3_64bits_reset_withSeed(state_, seed);
|
XXH3_64bits_reset_withSeed(state_, seed);
|
||||||
|
duration_ += (std::chrono::steady_clock::now() - start);
|
||||||
|
cpuCycles += (__rdtsc() - cpuCyclesStart);
|
||||||
|
#else
|
||||||
|
setupBuffers();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
@@ -81,20 +149,92 @@ public:
|
|||||||
std::enable_if_t<std::is_unsigned<Seed>::value>* = nullptr>
|
std::enable_if_t<std::is_unsigned<Seed>::value>* = nullptr>
|
||||||
xxhasher(Seed seed, Seed)
|
xxhasher(Seed seed, Seed)
|
||||||
{
|
{
|
||||||
|
#if PROFILING
|
||||||
|
auto start = std::chrono::steady_clock::now();
|
||||||
|
auto cpuCyclesStart = __rdtsc();
|
||||||
|
#endif
|
||||||
|
seed_ = seed;
|
||||||
|
|
||||||
|
#if ORIGINAL_HASH
|
||||||
state_ = allocState();
|
state_ = allocState();
|
||||||
XXH3_64bits_reset_withSeed(state_, seed);
|
XXH3_64bits_reset_withSeed(state_, seed);
|
||||||
|
#else
|
||||||
|
setupBuffers();
|
||||||
|
#endif
|
||||||
|
#if PROFILING
|
||||||
|
duration_ += (std::chrono::steady_clock::now() - start);
|
||||||
|
cpuCycles += (__rdtsc() - cpuCyclesStart);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
operator()(void const* key, std::size_t len) noexcept
|
operator()(void const* key, std::size_t len) noexcept
|
||||||
{
|
{
|
||||||
|
#if PROFILING
|
||||||
|
totalSize_ += len;
|
||||||
|
auto start = std::chrono::steady_clock::now();
|
||||||
|
auto cpuCyclesStart = __rdtsc();
|
||||||
|
#endif
|
||||||
|
#if ORIGINAL_HASH
|
||||||
XXH3_64bits_update(state_, key, len);
|
XXH3_64bits_update(state_, key, len);
|
||||||
|
#else
|
||||||
|
writeBuffer(key, len);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if PROFILING
|
||||||
|
duration_ += (std::chrono::steady_clock::now() - start);
|
||||||
|
cpuCycles += (__rdtsc() - cpuCyclesStart);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit
|
explicit
|
||||||
operator std::size_t() noexcept
|
operator HashType() noexcept
|
||||||
{
|
{
|
||||||
return XXH3_64bits_digest(state_);
|
#if ORIGINAL_HASH == 0
|
||||||
|
if (readBuffer_.size() == 0) return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if PROFILING
|
||||||
|
auto start = std::chrono::steady_clock::now();
|
||||||
|
auto cpuCyclesStart = __rdtsc();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BIT_SHIFT_HASH
|
||||||
|
const size_t bit_width = readBuffer_.size() * 8;
|
||||||
|
const size_t shift = seed_ % bit_width;
|
||||||
|
|
||||||
|
// Copy input into a buffer long enough to safely extract 64 bits with wraparound
|
||||||
|
std::uint64_t buffer = 0;
|
||||||
|
|
||||||
|
// Load the first 8 bytes (or wrap if input < 8 bytes)
|
||||||
|
for (size_t i = 0; i < 8; ++i) {
|
||||||
|
size_t index = readBuffer_.size() - 1 - (i % readBuffer_.size());
|
||||||
|
buffer <<= 8;
|
||||||
|
buffer |= readBuffer_[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rotate and return
|
||||||
|
auto result = (buffer << shift) | (buffer >> (64 - shift));
|
||||||
|
#elif ORIGINAL_HASH
|
||||||
|
auto result = XXH3_64bits_digest(state_);
|
||||||
|
#else
|
||||||
|
auto result = seed_ == 0 ?
|
||||||
|
XXH3_64bits(readBuffer_.data(), readBuffer_.size()) :
|
||||||
|
XXH3_64bits_withSeed(readBuffer_.data(), readBuffer_.size(), seed_);
|
||||||
|
#endif
|
||||||
|
#if PROFILING
|
||||||
|
duration_ += (std::chrono::steady_clock::now() - start);
|
||||||
|
cpuCycles += (__rdtsc() - cpuCyclesStart);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock{FunctionProfiler::mutex_};
|
||||||
|
FunctionProfiler::funcionDurations
|
||||||
|
["xxhasher-" + std::to_string(totalSize_)]
|
||||||
|
.time.emplace_back(duration_);
|
||||||
|
FunctionProfiler::funcionDurations
|
||||||
|
["xxhasher-" + std::to_string(totalSize_)]
|
||||||
|
.cpuCycles.emplace_back(cpuCycles);
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace BuildInfo {
|
|||||||
// and follow the format described at http://semver.org/
|
// and follow the format described at http://semver.org/
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// clang-format off
|
// clang-format off
|
||||||
char const* const versionString = "2.4.0"
|
char const* const versionString = "2.5.0-b1"
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
#if defined(DEBUG) || defined(SANITIZER)
|
#if defined(DEBUG) || defined(SANITIZER)
|
||||||
|
|||||||
@@ -37,6 +37,22 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <xrpl/beast/hash/xxhasher.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
void testHasher()
|
||||||
|
{
|
||||||
|
beast::xxhasher hasher{std::uint32_t{8}};
|
||||||
|
|
||||||
|
char a[] = "He";
|
||||||
|
hasher(&a, sizeof(a));
|
||||||
|
|
||||||
|
auto value = static_cast<beast::xxhasher::HashType>(hasher);
|
||||||
|
|
||||||
|
std::cout << value << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
@@ -7140,6 +7156,9 @@ private:
|
|||||||
void
|
void
|
||||||
run() override
|
run() override
|
||||||
{
|
{
|
||||||
|
testHasher();
|
||||||
|
|
||||||
|
return;
|
||||||
FeatureBitset const all{jtx::supported_amendments()};
|
FeatureBitset const all{jtx::supported_amendments()};
|
||||||
testInvalidInstance();
|
testInvalidInstance();
|
||||||
testInstanceCreate();
|
testInstanceCreate();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <barrier>
|
#include <barrier>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <condition_variable>
|
||||||
#include <latch>
|
#include <latch>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <random>
|
#include <random>
|
||||||
@@ -19,6 +20,55 @@
|
|||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace tests {
|
namespace tests {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Experimentally, we discovered that using std::barrier performs extremely
|
||||||
|
poorly (~1 hour vs ~1 minute to run the test suite) in certain macOS
|
||||||
|
environments. To unblock our macOS CI pipeline, we replaced std::barrier with a
|
||||||
|
custom mutex-based barrier (Barrier) that significantly improves performance
|
||||||
|
without compromising correctness. For future reference, if we ever consider
|
||||||
|
reintroducing std::barrier, the following configuration is known to exhibit the
|
||||||
|
problem:
|
||||||
|
|
||||||
|
Model Name: Mac mini
|
||||||
|
Model Identifier: Mac14,3
|
||||||
|
Model Number: Z16K000R4LL/A
|
||||||
|
Chip: Apple M2
|
||||||
|
Total Number of Cores: 8 (4 performance and 4 efficiency)
|
||||||
|
Memory: 24 GB
|
||||||
|
System Firmware Version: 11881.41.5
|
||||||
|
OS Loader Version: 11881.1.1
|
||||||
|
Apple clang version 16.0.0 (clang-1600.0.26.3)
|
||||||
|
Target: arm64-apple-darwin24.0.0
|
||||||
|
Thread model: posix
|
||||||
|
|
||||||
|
*/
|
||||||
|
struct Barrier
|
||||||
|
{
|
||||||
|
std::mutex mtx;
|
||||||
|
std::condition_variable cv;
|
||||||
|
int count;
|
||||||
|
int const initial;
|
||||||
|
|
||||||
|
Barrier(int n) : count(n), initial(n)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
arrive_and_wait()
|
||||||
|
{
|
||||||
|
std::unique_lock lock(mtx);
|
||||||
|
if (--count == 0)
|
||||||
|
{
|
||||||
|
count = initial;
|
||||||
|
cv.notify_all();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cv.wait(lock, [&] { return count == initial; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
enum class TrackedState : std::uint8_t {
|
enum class TrackedState : std::uint8_t {
|
||||||
uninitialized,
|
uninitialized,
|
||||||
@@ -500,9 +550,9 @@ public:
|
|||||||
constexpr int loopIters = 2 * 1024;
|
constexpr int loopIters = 2 * 1024;
|
||||||
constexpr int numThreads = 16;
|
constexpr int numThreads = 16;
|
||||||
std::vector<SharedIntrusive<TIBase>> toClone;
|
std::vector<SharedIntrusive<TIBase>> toClone;
|
||||||
std::barrier loopStartSyncPoint{numThreads};
|
Barrier loopStartSyncPoint{numThreads};
|
||||||
std::barrier postCreateToCloneSyncPoint{numThreads};
|
Barrier postCreateToCloneSyncPoint{numThreads};
|
||||||
std::barrier postCreateVecOfPointersSyncPoint{numThreads};
|
Barrier postCreateVecOfPointersSyncPoint{numThreads};
|
||||||
auto engines = [&]() -> std::vector<std::default_random_engine> {
|
auto engines = [&]() -> std::vector<std::default_random_engine> {
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
std::vector<std::default_random_engine> result;
|
std::vector<std::default_random_engine> result;
|
||||||
@@ -628,10 +678,10 @@ public:
|
|||||||
constexpr int flipPointersLoopIters = 256;
|
constexpr int flipPointersLoopIters = 256;
|
||||||
constexpr int numThreads = 16;
|
constexpr int numThreads = 16;
|
||||||
std::vector<SharedIntrusive<TIBase>> toClone;
|
std::vector<SharedIntrusive<TIBase>> toClone;
|
||||||
std::barrier loopStartSyncPoint{numThreads};
|
Barrier loopStartSyncPoint{numThreads};
|
||||||
std::barrier postCreateToCloneSyncPoint{numThreads};
|
Barrier postCreateToCloneSyncPoint{numThreads};
|
||||||
std::barrier postCreateVecOfPointersSyncPoint{numThreads};
|
Barrier postCreateVecOfPointersSyncPoint{numThreads};
|
||||||
std::barrier postFlipPointersLoopSyncPoint{numThreads};
|
Barrier postFlipPointersLoopSyncPoint{numThreads};
|
||||||
auto engines = [&]() -> std::vector<std::default_random_engine> {
|
auto engines = [&]() -> std::vector<std::default_random_engine> {
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
std::vector<std::default_random_engine> result;
|
std::vector<std::default_random_engine> result;
|
||||||
@@ -761,9 +811,9 @@ public:
|
|||||||
constexpr int lockWeakLoopIters = 256;
|
constexpr int lockWeakLoopIters = 256;
|
||||||
constexpr int numThreads = 16;
|
constexpr int numThreads = 16;
|
||||||
std::vector<SharedIntrusive<TIBase>> toLock;
|
std::vector<SharedIntrusive<TIBase>> toLock;
|
||||||
std::barrier loopStartSyncPoint{numThreads};
|
Barrier loopStartSyncPoint{numThreads};
|
||||||
std::barrier postCreateToLockSyncPoint{numThreads};
|
Barrier postCreateToLockSyncPoint{numThreads};
|
||||||
std::barrier postLockWeakLoopSyncPoint{numThreads};
|
Barrier postLockWeakLoopSyncPoint{numThreads};
|
||||||
|
|
||||||
// lockAndDestroy creates weak pointers from the strong pointer
|
// lockAndDestroy creates weak pointers from the strong pointer
|
||||||
// and runs a loop that locks the weak pointer. At the end of the loop
|
// and runs a loop that locks the weak pointer. At the end of the loop
|
||||||
|
|||||||
@@ -1424,9 +1424,9 @@ public:
|
|||||||
testPeersAgree();
|
testPeersAgree();
|
||||||
testSlowPeers();
|
testSlowPeers();
|
||||||
testCloseTimeDisagree();
|
testCloseTimeDisagree();
|
||||||
testWrongLCL();
|
// testWrongLCL();
|
||||||
testConsensusCloseTimeRounding();
|
testConsensusCloseTimeRounding();
|
||||||
testFork();
|
// testFork();
|
||||||
testHubNetwork();
|
testHubNetwork();
|
||||||
testPreferredByBranch();
|
testPreferredByBranch();
|
||||||
testPauseForLaggards();
|
testPauseForLaggards();
|
||||||
|
|||||||
@@ -69,6 +69,7 @@
|
|||||||
#include <xrpl/protocol/Protocol.h>
|
#include <xrpl/protocol/Protocol.h>
|
||||||
#include <xrpl/protocol/STParsedJSON.h>
|
#include <xrpl/protocol/STParsedJSON.h>
|
||||||
#include <xrpl/resource/Fees.h>
|
#include <xrpl/resource/Fees.h>
|
||||||
|
#include <xrpl/beast/core/FunctionProfiler.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/asio/steady_timer.hpp>
|
#include <boost/asio/steady_timer.hpp>
|
||||||
@@ -1647,6 +1648,10 @@ ApplicationImp::run()
|
|||||||
void
|
void
|
||||||
ApplicationImp::signalStop(std::string msg)
|
ApplicationImp::signalStop(std::string msg)
|
||||||
{
|
{
|
||||||
|
#if PROFILING
|
||||||
|
std::cout << "signal stop!!!" << std::endl;
|
||||||
|
JLOG(m_journal.warn()) << beast::getProfilingResults();
|
||||||
|
#endif
|
||||||
if (!isTimeToStop.exchange(true))
|
if (!isTimeToStop.exchange(true))
|
||||||
{
|
{
|
||||||
if (msg.empty())
|
if (msg.empty())
|
||||||
|
|||||||
Reference in New Issue
Block a user