681f5767b2
PiperOrigin-RevId: 808689636 Change-Id: Ia091fb597c171a33842e62690d06f32614fbe4eb
156 lines
4.2 KiB
C++
156 lines
4.2 KiB
C++
// Copyright 2025 DeepMind Technologies Limited
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#include <algorithm>
|
|
#include <random>
|
|
#include <vector>
|
|
|
|
#include "benchmark/benchmark.h"
|
|
#include <absl/base/attributes.h>
|
|
#include <mujoco/mujoco.h>
|
|
#include "src/engine/engine_sort.h"
|
|
|
|
namespace mujoco {
|
|
namespace {
|
|
|
|
// A struct with data to be sorted.
|
|
struct Sortable {
|
|
mjtNum value;
|
|
int id1;
|
|
int id2;
|
|
};
|
|
|
|
// Comparison function for Sortable struct.
|
|
int CompareSortable(const Sortable* a, const Sortable* b, void* context) {
|
|
if (a->value < b->value) {
|
|
return -1;
|
|
} else if (a->value == b->value) {
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Instantiate the sort function.
|
|
mjSORT(SortSortable, Sortable, CompareSortable);
|
|
|
|
// Generate data for sorting benchmarks.
|
|
std::vector<Sortable> GenerateData(int n, double unsorted_fraction) {
|
|
std::vector<Sortable> data(n);
|
|
for (int i = 0; i < n; ++i) {
|
|
data[i] = {static_cast<mjtNum>(i), i, -i};
|
|
}
|
|
|
|
if (unsorted_fraction > 0.0) {
|
|
std::mt19937 g(12345);
|
|
if (unsorted_fraction >= 1.0) {
|
|
std::shuffle(data.begin(), data.end(), g);
|
|
} else {
|
|
int num_to_shuffle = n * unsorted_fraction;
|
|
for (int i = 0; i < num_to_shuffle; ++i) {
|
|
int j = std::uniform_int_distribution<int>(i, n - 1)(g);
|
|
std::swap(data[i], data[j]);
|
|
}
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
|
|
// Run a sorting benchmark with the given size and unsorted fraction.
|
|
ABSL_ATTRIBUTE_NO_TAIL_CALL static void SortBenchmark(
|
|
benchmark::State& state, int n, double unsorted_fraction) {
|
|
auto data = GenerateData(n, unsorted_fraction);
|
|
std::vector<Sortable> buf(n);
|
|
std::vector<Sortable> copy = data;
|
|
|
|
for (auto s : state) {
|
|
state.PauseTiming();
|
|
copy = data;
|
|
state.ResumeTiming();
|
|
SortSortable(copy.data(), buf.data(), n, nullptr);
|
|
}
|
|
|
|
state.counters["items/s"] =
|
|
benchmark::Counter(state.iterations() * n, benchmark::Counter::kIsRate);
|
|
}
|
|
|
|
// Define benchmarks.
|
|
void BM_Sort_1k_AlmostSorted(benchmark::State& state) {
|
|
SortBenchmark(state, 1000, 0.05);
|
|
}
|
|
BENCHMARK(BM_Sort_1k_AlmostSorted);
|
|
|
|
void BM_Sort_1k_Random(benchmark::State& state) {
|
|
SortBenchmark(state, 1000, 1.0);
|
|
}
|
|
BENCHMARK(BM_Sort_1k_Random);
|
|
|
|
void BM_Sort_100k_AlmostSorted(benchmark::State& state) {
|
|
SortBenchmark(state, 100000, 0.05);
|
|
}
|
|
BENCHMARK(BM_Sort_100k_AlmostSorted);
|
|
|
|
void BM_Sort_100k_Random(benchmark::State& state) {
|
|
SortBenchmark(state, 100000, 1.0);
|
|
}
|
|
BENCHMARK(BM_Sort_100k_Random);
|
|
|
|
// Run a sorting benchmark with std::stable_sort
|
|
ABSL_ATTRIBUTE_NO_TAIL_CALL static void StdSortBenchmark(
|
|
benchmark::State& state, int n, double unsorted_fraction) {
|
|
auto data = GenerateData(n, unsorted_fraction);
|
|
std::vector<Sortable> copy = data;
|
|
|
|
for (auto s : state) {
|
|
state.PauseTiming();
|
|
copy = data;
|
|
state.ResumeTiming();
|
|
std::stable_sort(
|
|
copy.begin(), copy.end(),
|
|
[](const Sortable& a, const Sortable& b) { return a.value < b.value; });
|
|
}
|
|
|
|
state.counters["items/s"] =
|
|
benchmark::Counter(state.iterations() * n, benchmark::Counter::kIsRate);
|
|
}
|
|
|
|
void BM_StdSort_1k_AlmostSorted(benchmark::State& state) {
|
|
StdSortBenchmark(state, 1000, 0.05);
|
|
}
|
|
BENCHMARK(BM_StdSort_1k_AlmostSorted);
|
|
|
|
void BM_StdSort_1k_Random(benchmark::State& state) {
|
|
StdSortBenchmark(state, 1000, 1.0);
|
|
}
|
|
BENCHMARK(BM_StdSort_1k_Random);
|
|
|
|
void BM_StdSort_100k_AlmostSorted(benchmark::State& state) {
|
|
StdSortBenchmark(state, 100000, 0.05);
|
|
}
|
|
BENCHMARK(BM_StdSort_100k_AlmostSorted);
|
|
|
|
void BM_StdSort_100k_Random(benchmark::State& state) {
|
|
StdSortBenchmark(state, 100000, 1.0);
|
|
}
|
|
BENCHMARK(BM_StdSort_100k_Random);
|
|
|
|
} // namespace
|
|
} // namespace mujoco
|
|
|
|
int main(int argc, char** argv) {
|
|
benchmark::Initialize(&argc, argv);
|
|
benchmark::RunSpecifiedBenchmarks();
|
|
return 0;
|
|
}
|