Files
wehub-resource-sync fc00954168
Build / build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:49:10 +08:00

149 lines
4.7 KiB
C++

#include <cstdint>
#include <folly/Random.h>
#include <folly/experimental/TestUtil.h>
#include <folly/logging/xlog.h>
#include <gflags/gflags.h>
#include <gtest/gtest.h>
#include "common/utils/Shuffle.h"
#include "fmt/core.h"
DEFINE_int32(test_shuffle, 10000, "shuffle times");
DEFINE_string(test_dump_path, "", "3fs meta dump path");
namespace hf3fs::test {
namespace {
TEST(TestShuffle, Basic) {
// most random seed should be safe if vector size is small
for (int i = 0; i < FLAGS_test_shuffle; i++) {
auto seed = folly::Random::rand64();
auto vecsize = folly::Random::rand32(200);
ASSERT_TRUE(safe_shuffle_seed(vecsize, seed)) << " " << seed << " " << vecsize;
}
}
TEST(TestShuffle, FindUnsafeSeed) {
// for large vector size, we can find mismatch seed
for (int i = 0; i < 10000; i++) {
auto seed = folly::Random::rand64();
auto vecsize = 10000;
if (!safe_shuffle_seed(vecsize, seed)) {
fmt::println("find unsafe seed {} for vecsize {}", seed, vecsize);
return;
}
}
ASSERT_TRUE(false);
}
TEST(TestShuffle, KnownUnsafeSeed) {
// we know some seed is not safe
std::vector<uint64_t> unsafeSeeds = {6853942027173882469ull,
12595889032228965821ull,
8619779154399616190ull,
12360005796445515182ull,
14687818431154681368ull,
17026414701752999916ull,
12928634241705049562ull,
5961001693986322440ull,
8264875872430788387ull,
8715369310580772031ull,
17199606764515290853ull,
15088078859152357184ull,
13543500868882399137ull,
472380080658457497ull};
for (auto seed : unsafeSeeds) {
ASSERT_FALSE(safe_shuffle_seed(200, seed)) << seed;
#if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE)
std::vector<uint32_t> vec1(200);
std::iota(vec1.begin(), vec1.end(), 0);
std::vector<uint32_t> vec2 = vec1;
std_shuffle(vec1, seed);
#if (_GLIBCXX_RELEASE >= 11)
gcc11_shuffle(vec2, seed);
#elif (_GLIBCXX_RELEASE >= 10)
gcc10_shuffle(vec2, seed);
#else
static_assert(false);
#endif
ASSERT_EQ(vec1, vec2) << "seed: " << seed;
#else
static_assert(false);
#endif
}
}
TEST(TestShuffle, CheckDump) {
if (FLAGS_test_dump_path.empty()) {
GTEST_SKIP();
}
std::ifstream file(FLAGS_test_dump_path);
ASSERT_TRUE(file.is_open()) << "failed to open: " << FLAGS_test_dump_path;
std::string line;
std::getline(file, line); // skip header
std::cerr << "id,seed,size,match_gcc10,match_gcc11" << std::endl;
uint64_t total = 0;
uint64_t mismatch_g10 = 0, mismatch_g11 = 0, mismatch_both = 0;
while (std::getline(file, line)) {
std::istringstream iss(line);
std::string id_str, seed_str, size_str;
std::getline(iss, id_str, ',');
std::getline(iss, seed_str, ',');
std::getline(iss, size_str, ',');
uint64_t id = std::stoull(id_str, nullptr, 16);
uint64_t seed = std::stoull(seed_str);
uint64_t size = std::stoull(size_str);
std::vector<uint64_t> vec_std(size), vec_g10(size), vec_g11(size);
std::iota(vec_std.begin(), vec_std.end(), 0);
std::iota(vec_g10.begin(), vec_g10.end(), 0);
std::iota(vec_g11.begin(), vec_g11.end(), 0);
std_shuffle(vec_std, seed);
gcc10_shuffle(vec_g10, seed);
gcc11_shuffle(vec_g11, seed);
bool match_g10 = (vec_std == vec_g10);
bool match_g11 = (vec_std == vec_g11);
if (!match_g10 || !match_g11) {
std::cerr << std::hex << id << std::dec << ","
<< seed << ","
<< size << ","
<< (match_g10 ? "true" : "false") << ","
<< (match_g11 ? "true" : "false") << std::endl;
}
if (!match_g10 && !match_g11) {
mismatch_both++;
} else if (!match_g10) {
mismatch_g10++;
} else if (!match_g11) {
mismatch_g11++;
}
total++;
if (total % 10000 == 0) {
std::cout << "Progress: " << total
<< ", g++10_only_mismatch: " << mismatch_g10
<< ", g++11_only_mismatch: " << mismatch_g11
<< ", both_mismatch: " << mismatch_both << std::endl;
}
}
std::cout << "Done. Total: " << total
<< ", g++10_only_mismatch: " << mismatch_g10
<< ", g++11_only_mismatch: " << mismatch_g11
<< ", both_mismatch: " << mismatch_both << std::endl;
}
} // namespace
} // namespace hf3fs::test