Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a standardized, consistent benchmark for hardware performance testing. #5354

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
349 changes: 349 additions & 0 deletions src/benchmark.cpp

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions src/benchmark.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ namespace Stockfish::Benchmark {

std::vector<std::string> setup_bench(const std::string&, std::istream&);

struct BenchmarkSetup {
int ttSize;
int threads;
std::vector<std::string> commands;
std::string originalInvocation;
std::string filledInvocation;
};

BenchmarkSetup setup_benchmark(std::istream&);

} // namespace Stockfish

#endif // #ifndef BENCHMARK_H_INCLUDED
37 changes: 27 additions & 10 deletions src/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,13 @@ Engine::Engine(std::optional<std::string> path) :

options["NumaPolicy"] << Option("auto", [this](const Option& o) {
set_numa_config_from_option(o);
return numa_config_information_as_string() + "\n" + thread_binding_information_as_string();
return numa_config_information_as_string() + "\n"
+ thread_allocation_information_as_string();
});

options["Threads"] << Option(1, 1, 1024, [this](const Option&) {
resize_threads();
return thread_binding_information_as_string();
return thread_allocation_information_as_string();
});

options["Hash"] << Option(16, 1, MaxHashMB, [this](const Option& o) {
Expand Down Expand Up @@ -156,6 +157,10 @@ void Engine::set_on_bestmove(std::function<void(std::string_view, std::string_vi
updateContext.onBestmove = std::move(f);
}

void Engine::set_on_verify_networks(std::function<void(std::string_view)>&& f) {
onVerifyNetworks = std::move(f);
}

void Engine::wait_for_search_finished() { threads.main_thread()->wait_for_search_finished(); }

void Engine::set_position(const std::string& fen, const std::vector<std::string>& moves) {
Expand Down Expand Up @@ -226,8 +231,8 @@ void Engine::set_ponderhit(bool b) { threads.main_manager()->ponder = b; }
// network related

void Engine::verify_networks() const {
networks->big.verify(options["EvalFile"]);
networks->small.verify(options["EvalFileSmall"]);
networks->big.verify(options["EvalFile"], onVerifyNetworks);
networks->small.verify(options["EvalFileSmall"], onVerifyNetworks);
}

void Engine::load_networks() {
Expand Down Expand Up @@ -285,6 +290,8 @@ std::string Engine::visualize() const {
return ss.str();
}

int Engine::get_hashfull(int maxAge) const { return tt.hashfull(maxAge); }

std::vector<std::pair<size_t, size_t>> Engine::get_bound_thread_count_by_numa_node() const {
auto counts = threads.get_bound_thread_count_by_numa_node();
const NumaConfig& cfg = numaContext.get_numa_config();
Expand All @@ -310,15 +317,9 @@ std::string Engine::numa_config_information_as_string() const {
std::string Engine::thread_binding_information_as_string() const {
auto boundThreadsByNode = get_bound_thread_count_by_numa_node();
std::stringstream ss;

size_t threadsSize = threads.size();
ss << "Using " << threadsSize << (threadsSize > 1 ? " threads" : " thread");

if (boundThreadsByNode.empty())
return ss.str();

ss << " with NUMA node thread binding: ";

bool isFirst = true;

for (auto&& [current, total] : boundThreadsByNode)
Expand All @@ -332,4 +333,20 @@ std::string Engine::thread_binding_information_as_string() const {
return ss.str();
}

std::string Engine::thread_allocation_information_as_string() const {
std::stringstream ss;

size_t threadsSize = threads.size();
ss << "Using " << threadsSize << (threadsSize > 1 ? " threads" : " thread");

auto boundThreadsByNodeStr = thread_binding_information_as_string();
if (boundThreadsByNodeStr.empty())
return ss.str();

ss << " with NUMA node thread binding: ";
ss << boundThreadsByNodeStr;

return ss.str();
}

}
7 changes: 6 additions & 1 deletion src/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class Engine {
void set_on_update_full(std::function<void(const InfoFull&)>&&);
void set_on_iter(std::function<void(const InfoIter&)>&&);
void set_on_bestmove(std::function<void(std::string_view, std::string_view)>&&);
void set_on_verify_networks(std::function<void(std::string_view)>&&);

// network related

Expand All @@ -97,12 +98,15 @@ class Engine {
const OptionsMap& get_options() const;
OptionsMap& get_options();

int get_hashfull(int maxAge = 0) const;

std::string fen() const;
void flip();
std::string visualize() const;
std::vector<std::pair<size_t, size_t>> get_bound_thread_count_by_numa_node() const;
std::string get_numa_config_as_string() const;
std::string numa_config_information_as_string() const;
std::string thread_allocation_information_as_string() const;
std::string thread_binding_information_as_string() const;

private:
Expand All @@ -119,7 +123,8 @@ class Engine {
TranspositionTable tt;
LazyNumaReplicated<Eval::NNUE::Networks> networks;

Search::SearchManager::UpdateContext updateContext;
Search::SearchManager::UpdateContext updateContext;
std::function<void(std::string_view)> onVerifyNetworks;
};

} // namespace Stockfish
Expand Down
31 changes: 31 additions & 0 deletions src/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,37 @@ void* aligned_large_pages_alloc(size_t allocSize) {

#endif

bool has_large_pages() {

#if defined(_WIN32)

constexpr size_t page_size = 2 * 1024 * 1024; // 2MB page size assumed
void* mem = aligned_large_pages_alloc_windows(page_size);
if (mem == nullptr)
{
return false;
}
else
{
aligned_large_pages_free(mem);
return true;
}

#elif defined(__linux__)

#if defined(MADV_HUGEPAGE)
return true;
#else
return false;
#endif

#else

return false;

#endif
}


// aligned_large_pages_free() will free the previously memory allocated
// by aligned_large_pages_alloc(). The effect is a nop if mem == nullptr.
Expand Down
2 changes: 2 additions & 0 deletions src/memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ void std_aligned_free(void* ptr);
void* aligned_large_pages_alloc(size_t size);
void aligned_large_pages_free(void* mem);

bool has_large_pages();

// Frees memory which was placed there with placement new.
// Works for both single objects and arrays of unknown bound.
template<typename T, typename FREE_FUNC>
Expand Down
11 changes: 7 additions & 4 deletions src/misc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ class Logger {
//
// For releases (non-dev builds) we only include the version number:
// Stockfish version
std::string engine_info(bool to_uci) {
std::string engine_version_info() {
std::stringstream ss;
ss << "Stockfish " << version << std::setfill('0');

Expand Down Expand Up @@ -151,11 +151,14 @@ std::string engine_info(bool to_uci) {
#endif
}

ss << (to_uci ? "\nid author " : " by ") << "the Stockfish developers (see AUTHORS file)";

return ss.str();
}

std::string engine_info(bool to_uci) {
return engine_version_info() + (to_uci ? "\nid author " : " by ")
+ "the Stockfish developers (see AUTHORS file)";
}


// Returns a string trying to describe the compiler we use
std::string compiler_info() {
Expand Down Expand Up @@ -451,7 +454,7 @@ void remove_whitespace(std::string& s) {
s.erase(std::remove_if(s.begin(), s.end(), [](char c) { return std::isspace(c); }), s.end());
}

bool is_whitespace(const std::string& s) {
bool is_whitespace(std::string_view s) {
return std::all_of(s.begin(), s.end(), [](char c) { return std::isspace(c); });
}

Expand Down
8 changes: 5 additions & 3 deletions src/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
#include <iosfwd>
#include <optional>
#include <string>
#include <string_view>
#include <vector>

#define stringify2(x) #x
#define stringify(x) stringify2(x)

namespace Stockfish {

std::string engine_version_info();
std::string engine_info(bool to_uci = false);
std::string compiler_info();

Expand Down Expand Up @@ -79,8 +81,8 @@ inline TimePoint now() {
.count();
}

inline std::vector<std::string> split(const std::string& s, const std::string& delimiter) {
std::vector<std::string> res;
inline std::vector<std::string_view> split(std::string_view s, std::string_view delimiter) {
std::vector<std::string_view> res;

if (s.empty())
return res;
Expand All @@ -102,7 +104,7 @@ inline std::vector<std::string> split(const std::string& s, const std::string& d
}

void remove_whitespace(std::string& s);
bool is_whitespace(const std::string& s);
bool is_whitespace(std::string_view s);

enum SyncCout {
IO_LOCK,
Expand Down
51 changes: 30 additions & 21 deletions src/nnue/network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,35 +234,44 @@ Network<Arch, Transformer>::evaluate(const Position& pos


template<typename Arch, typename Transformer>
void Network<Arch, Transformer>::verify(std::string evalfilePath) const {
void Network<Arch, Transformer>::verify(std::string evalfilePath,
const std::function<void(std::string_view)>& f) const {
if (evalfilePath.empty())
evalfilePath = evalFile.defaultName;

if (evalFile.current != evalfilePath)
{
std::string msg1 =
"Network evaluation parameters compatible with the engine must be available.";
std::string msg2 = "The network file " + evalfilePath + " was not loaded successfully.";
std::string msg3 = "The UCI option EvalFile might need to specify the full path, "
"including the directory name, to the network file.";
std::string msg4 = "The default net can be downloaded from: "
"https://tests.stockfishchess.org/api/nn/"
+ evalFile.defaultName;
std::string msg5 = "The engine will be terminated now.";

sync_cout << "info string ERROR: " << msg1 << sync_endl;
sync_cout << "info string ERROR: " << msg2 << sync_endl;
sync_cout << "info string ERROR: " << msg3 << sync_endl;
sync_cout << "info string ERROR: " << msg4 << sync_endl;
sync_cout << "info string ERROR: " << msg5 << sync_endl;
if (f)
{
std::string msg1 =
"Network evaluation parameters compatible with the engine must be available.";
std::string msg2 = "The network file " + evalfilePath + " was not loaded successfully.";
std::string msg3 = "The UCI option EvalFile might need to specify the full path, "
"including the directory name, to the network file.";
std::string msg4 = "The default net can be downloaded from: "
"https://tests.stockfishchess.org/api/nn/"
+ evalFile.defaultName;
std::string msg5 = "The engine will be terminated now.";

std::string msg = "ERROR: " + msg1 + '\n' + "ERROR: " + msg2 + '\n' + "ERROR: " + msg3
+ '\n' + "ERROR: " + msg4 + '\n' + "ERROR: " + msg5 + '\n';

f(msg);
}

exit(EXIT_FAILURE);
}

size_t size = sizeof(*featureTransformer) + sizeof(Arch) * LayerStacks;
sync_cout << "info string NNUE evaluation using " << evalfilePath << " ("
<< size / (1024 * 1024) << "MiB, (" << featureTransformer->InputDimensions << ", "
<< network[0].TransformedFeatureDimensions << ", " << network[0].FC_0_OUTPUTS << ", "
<< network[0].FC_1_OUTPUTS << ", 1))" << sync_endl;
if (f)
{
size_t size = sizeof(*featureTransformer) + sizeof(Arch) * LayerStacks;
f("info string NNUE evaluation using " + evalfilePath + " ("
+ std::to_string(size / (1024 * 1024)) + "MiB, ("
+ std::to_string(featureTransformer->InputDimensions) + ", "
+ std::to_string(network[0].TransformedFeatureDimensions) + ", "
+ std::to_string(network[0].FC_0_OUTPUTS) + ", " + std::to_string(network[0].FC_1_OUTPUTS)
+ ", 1))");
}
}


Expand Down
4 changes: 3 additions & 1 deletion src/nnue/network.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
#define NETWORK_H_INCLUDED

#include <cstdint>
#include <functional>
#include <iostream>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>

Expand Down Expand Up @@ -68,7 +70,7 @@ class Network {
void hint_common_access(const Position& pos,
AccumulatorCaches::Cache<FTDimensions>* cache) const;

void verify(std::string evalfilePath) const;
void verify(std::string evalfilePath, const std::function<void(std::string_view)>&) const;
NnueEvalTrace trace_evaluate(const Position& pos,
AccumulatorCaches::Cache<FTDimensions>* cache) const;

Expand Down
11 changes: 6 additions & 5 deletions src/numa.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <atomic>
#include <cstdint>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
Expand Down Expand Up @@ -653,7 +654,7 @@ class NumaConfig {
NumaIndex n = 0;
for (auto&& nodeStr : split(s, ":"))
{
auto indices = indices_from_shortened_string(nodeStr);
auto indices = indices_from_shortened_string(std::string(nodeStr));
if (!indices.empty())
{
for (auto idx : indices)
Expand Down Expand Up @@ -1015,21 +1016,21 @@ class NumaConfig {
if (s.empty())
return indices;

for (const std::string& ss : split(s, ","))
for (const auto& ss : split(s, ","))
{
if (ss.empty())
continue;

auto parts = split(ss, "-");
if (parts.size() == 1)
{
const CpuIndex c = CpuIndex{str_to_size_t(parts[0])};
const CpuIndex c = CpuIndex{str_to_size_t(std::string(parts[0]))};
indices.emplace_back(c);
}
else if (parts.size() == 2)
{
const CpuIndex cfirst = CpuIndex{str_to_size_t(parts[0])};
const CpuIndex clast = CpuIndex{str_to_size_t(parts[1])};
const CpuIndex cfirst = CpuIndex{str_to_size_t(std::string(parts[0]))};
const CpuIndex clast = CpuIndex{str_to_size_t(std::string(parts[1]))};
for (size_t c = cfirst; c <= clast; ++c)
{
indices.emplace_back(c);
Expand Down
Loading
Loading