Files
TheRock/rocm-libraries/projects/miopen/speedtests/sequences.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

487 lines
12 KiB
C++

// Copyright (c) Advanced Micro Devices, Inc., or its affiliates.
// SPDX-License-Identifier: MIT
#include <miopen/kernel.hpp>
#include <miopen/rank.hpp>
#include <miopen/sequences.hpp>
#include <driver.hpp>
#include <array>
#include <chrono>
#include <iostream>
#include <ranges>
namespace miopen {
namespace seq {
struct TestData
{
int x;
};
enum class Modes
{
Standard,
Template,
Native,
Range,
Unknown,
};
enum class Sequences
{
Seq,
Span,
IRange,
Join,
Unknown,
};
enum class Instances
{
Single,
PerCall,
Static,
Unknown,
};
template <class TType, class TContainer, TType TContainer::*field>
struct MemberPtr<std::integral_constant<TType TContainer::*, field>>
{
using Container = TContainer;
MemberPtr(const std::integral_constant<TType TContainer::*, field>&) {}
const TType& RV(const TContainer& cont) const { return cont.*field; }
TType& LV(TContainer& cont) const { return cont.*field; }
};
template <Sequences seq>
struct NativeImpl
{
};
template <>
struct NativeImpl<Sequences::Seq>
{
bool Next(TestData& v) const
{
if(v.x == 1)
{
v.x = 2;
return false;
}
if(v.x == 2)
{
v.x = 7;
return false;
}
v.x = 1;
return true;
}
};
template <>
struct NativeImpl<Sequences::Span>
{
bool Next(TestData& v) const
{
if(v.x == 8)
{
v.x = 0;
return true;
}
++v.x;
return false;
}
};
template <>
struct NativeImpl<Sequences::IRange>
{
bool Next(TestData&) const
{
std::cerr << "irange is only for range" << std::endl;
std::exit(-1); // NOLINT (concurrency-mt-unsafe)
}
};
template <>
struct NativeImpl<Sequences::Join>
{
bool Next(TestData& td) const
{
if(td.x < 8)
{
++td.x;
return false;
}
if(td.x == 8)
{
td.x = 10;
return false;
}
if(td.x == 10)
{
td.x = 11;
return false;
}
if(td.x == 10)
{
td.x = 11;
return false;
}
if(td.x == 11)
{
td.x = 14;
return false;
}
if(td.x == 14)
{
td.x = 15;
return false;
}
td.x = 0;
return true;
}
};
template <class TRange, class TValue>
bool Next(const TRange& range, TValue& value)
{
auto it = GenericFind(range, value);
assert(it != range.end());
if(++it == range.end())
{
value = *range.begin();
return true;
}
value = *it;
return false;
}
template <class TValue, TValue... values>
struct RangeSequence
{
using value_type = TValue;
using const_iterator = const TValue*;
#ifdef _MSC_VER
constexpr const_iterator begin() const { return arr.begin()._Unwrapped(); }
constexpr const_iterator end() const { return arr.end()._Unwrapped(); }
#else
constexpr const_iterator begin() const { return arr.begin(); }
constexpr const_iterator end() const { return arr.end(); }
#endif
private:
static constexpr std::size_t count = sizeof...(values);
static constexpr std::array<int, RangeSequence::count> arr = {{values...}};
};
template <class Start, class IntegerSequence>
struct span_impl;
template <class Start, class T, T... Ns>
struct span_impl<Start, std::integer_sequence<T, Ns...>>
{
using value_type = T;
using const_iterator = const T*;
T data[sizeof...(Ns)] = {(Ns + Start{})...};
constexpr const T* begin() const { return data; }
constexpr const T* end() const { return data + sizeof...(Ns); }
constexpr const T* find(T value) const
{
if(value < Start{} || value > (Start{} + sizeof...(Ns)))
{
return end();
}
else
{
return data + (value - Start{});
}
}
};
template <class T, T start, T end>
struct RangeSpan
: span_impl<std::integral_constant<T, start>, std::make_integer_sequence<T, end - start>>
{
};
template <Sequences seq>
struct RangeImpl
{
};
template <>
struct RangeImpl<Sequences::IRange>
{
bool Next(TestData& v) const { return miopen::seq::Next(std::views::iota(0, 9), v.x); }
};
struct SpeedTestDriver : public test_driver
{
SpeedTestDriver()
{
add(iterations, "iterations");
add(modeStr, "mode");
add(sequenceStr, "seq");
add(instance_str, "inst");
}
void run()
{
const auto seq = ParseSequence(sequenceStr);
mode = ParseMode(modeStr);
instance = ParseInstance(instance_str);
switch(seq)
{
case Sequences::Seq: RunCore<Sequences::Seq>(); break;
case Sequences::Span: RunCore<Sequences::Span>(); break;
case Sequences::IRange: RunCore<Sequences::IRange>(); break;
case Sequences::Join: RunCore<Sequences::Join>(); break;
case Sequences::Unknown:
std::cerr << "Unknown sequence." << std::endl;
std::exit(-1); // NOLINT (concurrency-mt-unsafe)
}
}
void show_help()
{
test_driver::show_help();
std::cout << "Permitted modes: nat, std, tmpl, range" << std::endl;
std::cout << "Permitted sequences: seq, span, irange (range), join(nat, std, tmpl)"
<< std::endl;
std::cout << "Permitted instances: single, percall, static" << std::endl;
}
private:
int iterations = 10;
Instances instance = Instances::Unknown;
Modes mode = Modes::Unknown;
std::string instance_str = "single";
std::string modeStr = "std";
std::string sequenceStr = "seq";
static Modes ParseMode(const std::string& str)
{
if(str == "std")
return Modes::Standard;
if(str == "tmpl")
return Modes::Template;
if(str == "nat")
return Modes::Native;
if(str == "range")
return Modes::Range;
return Modes::Unknown;
}
static Sequences ParseSequence(const std::string& str)
{
if(str == "seq")
return Sequences::Seq;
if(str == "span")
return Sequences::Span;
if(str == "join")
return Sequences::Join;
if(str == "irange")
return Sequences::IRange;
return Sequences::Unknown;
}
static Instances ParseInstance(const std::string& str)
{
if(str == "single")
return Instances::Single;
if(str == "percall")
return Instances::PerCall;
if(str == "static")
return Instances::Static;
return Instances::Unknown;
}
template <Sequences seq>
void RunCore() const
{
switch(mode)
{
case Modes::Standard: Standard<seq>(); break;
case Modes::Template: Template<seq>(); break;
case Modes::Native: Native<seq>(); break;
case Modes::Range: Range<seq>(); break;
case Modes::Unknown:
std::cerr << "Unknown mode." << std::endl;
std::exit(-1); // NOLINT (concurrency-mt-unsafe)
}
}
template <class TType>
void SaveDeadCode(const TType& value) const
{
static const std::string dead_code_saver;
if(dead_code_saver.data() == nullptr)
{
std::cout << value << std::endl;
std::terminate();
}
}
template <class TRule>
void PrintCollectionImpl(rank<0>, const TRule&) const
{
}
template <class TRule, class = decltype(&TRule::FillBegin)>
void PrintCollectionImpl(rank<1>, const TRule& rule) const
{
TestData td{1};
rule.FillBegin(td);
auto i = 0;
do
{
std::cout << td.x << " ";
} while(!rule.Next(td) && ++i < 1024);
std::cout << std::endl;
}
template <class TRule>
void PrintCollection(const TRule& rule) const
{
PrintCollectionImpl(rank<16>{}, rule);
}
template <class TRuleGetter>
void TestCore(const TRuleGetter& rule_getter) const
{
PrintCollection(rule_getter());
TestData td{1};
const auto start = std::chrono::steady_clock::now();
for(auto i = 0; i < iterations; i++)
{
for(auto j = 0; j < 128 * 1024 * 1024; j++)
rule_getter().Next(td);
}
const auto time = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - start)
.count() *
.001 * .001;
std::cout << "Test time: " << time << " seconds" << std::endl;
SaveDeadCode(td.x); // required in release builds
}
template <class TRuleGetter>
void Test(const TRuleGetter& rule_getter) const
{
switch(instance)
{
case Instances::PerCall: TestCore(rule_getter); break;
case Instances::Single: {
const auto inst = rule_getter();
TestCore([&inst]() -> const auto& { return inst; });
break;
}
case Instances::Static:
TestCore([&rule_getter]() -> const auto& {
static const auto inst = rule_getter();
return inst;
});
break;
case Instances::Unknown:
std::cerr << "Unknown instance type" << std::endl;
std::exit(-1); // NOLINT (concurrency-mt-unsafe)
}
}
template <Sequences seq>
void Native() const
{
Test([]() { return NativeImpl<seq>{}; });
}
static auto MakeSeq() { return Sequence<int, 1, 2, 7>{}; }
static auto MakeBSeq() { return RangeSequence<int, 1, 2, 7>{}; }
static auto MakeSpan() { return Span<int, 0, 8>{}; }
static auto MakeBSpan() { return RangeSpan<int, 0, 9>{}; }
static auto MakeJoin() { return Join<Span<int, 0, 8>, Sequence<int, 10, 11, 14, 15>>{}; }
static auto TmplMember() { return std::integral_constant<int TestData::*, &TestData::x>{}; }
template <class... TParams>
static auto RS(TParams... args)
{
return MakeRuleSet(std::make_tuple(args...));
}
template <Sequences seq>
void Standard() const
{
switch(seq)
{
case Sequences::Seq: Test([]() { return RS(MakeSeq(), &TestData::x); }); break;
case Sequences::Span: Test([]() { return RS(MakeSpan(), &TestData::x); }); break;
case Sequences::Join: Test([]() { return RS(MakeJoin(), &TestData::x); }); break;
case Sequences::IRange:
std::cerr << "irange is only for range" << std::endl;
std::exit(-1); // NOLINT (concurrency-mt-unsafe)
}
}
template <Sequences seq>
void Template() const
{
switch(seq)
{
case Sequences::Seq: Test([]() { return RS(MakeSeq(), TmplMember()); }); break;
case Sequences::Span: Test([]() { return RS(MakeSpan(), TmplMember()); }); break;
case Sequences::Join: Test([]() { return RS(MakeJoin(), TmplMember()); }); break;
case Sequences::IRange:
std::cerr << "irange is only for range" << std::endl;
std::exit(-1); // NOLINT (concurrency-mt-unsafe)
}
}
template <Sequences seq>
void Range() const
{
switch(seq)
{
case Sequences::Seq: Test([]() { return RS(MakeBSeq(), &TestData::x); }); break;
case Sequences::Span: Test([]() { return RS(MakeBSpan(), &TestData::x); }); break;
case Sequences::Join:
std::cerr << "join is only for nat/std/tmpl" << std::endl;
std::exit(-1); // NOLINT (concurrency-mt-unsafe)
case Sequences::IRange: Test([]() { return RangeImpl<Sequences::IRange>{}; }); break;
}
}
};
} // namespace seq
} // namespace miopen
int main(int argc, const char* argv[])
{
test_drive<miopen::seq::SpeedTestDriver>(argc, argv);
return 0;
}