Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/ci-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: patternia PR Check (Ubuntu)

on:
pull_request:
branches: [main, dev-main]
branches: [main]
types: [opened, synchronize, reopened, ready_for_review]

concurrency:
Expand Down
43 changes: 15 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ name: patternia CI

on:
push:
branches: [main, dev-main]
branches: [main]
paths-ignore:
- "README.md"
- "CONTRIBUTING.md"
- "docs/**"
- "LICENSE"
- ".github/ISSUE_TEMPLATE/**"
pull_request:
branches: [main, dev-main]
branches: [main]
paths-ignore:
- "README.md"
- "CONTRIBUTING.md"
Expand Down Expand Up @@ -93,9 +93,10 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.BENCH_BOT_TOKEN || github.token }}

- name: Configure
run: |
Expand Down Expand Up @@ -139,28 +140,14 @@ jobs:
--prefix latest \
--title "Patternia vs Standard C++"

- name: Create benchmark chart PR
uses: peter-evans/create-pull-request@v8
with:
add-paths: |
docs/assets/bench/latest.png
docs/assets/bench/latest.md
docs/assets/bench/latest.csv
branch: chore/update-benchmark-summary
commit-message: "ci: update benchmark summary chart"
title: "ci: update benchmark summary chart"
draft: always-true
body: |
## Summary

Updates generated benchmark summary assets from the latest `main` benchmark run.

## Tests

- Generated by the benchmark workflow.

## Notes

This PR is created as a draft because GitHub does not trigger required checks
from pull requests created with `GITHUB_TOKEN`. Mark it ready for review to
run the required PR check before merging.
- name: Commit and push chart update
run: |
if git diff --quiet -- docs/assets/bench/; then
echo "No chart changes."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add docs/assets/bench/
git commit -m "ci: update benchmark summary chart"
git push
2 changes: 1 addition & 1 deletion .github/workflows/clang-format-auto.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: clang-format Auto Format

on:
pull_request:
branches: [main, dev-main]
branches: [main]
paths:
- "**/*.h"
- "**/*.hpp"
Expand Down
11 changes: 6 additions & 5 deletions bench/bench_ptn_lit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
#define PTN_BENCH_ENABLE_SUITE_PACKET 0
#define PTN_BENCH_ENABLE_SUITE_PACKET_HEAVY_BIND 0

#define PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH 1
#define PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_16 1
#define PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_32 1
#define PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_64 1
#define PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_128 1
#define PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH 1
#define PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_16 1
#define PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_32 1
#define PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_64 1
#define PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_128 1
#define PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_RDENSE 1

#include "bench_suite.cpp"
143 changes: 143 additions & 0 deletions bench/bench_suite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@
#define PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_64 1
#endif

#ifndef PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_RDENSE
#define PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_RDENSE 1
#endif

#ifndef PTN_BENCH_ENABLE_SUITE_PACKET
#define PTN_BENCH_ENABLE_SUITE_PACKET 1
#endif
Expand Down Expand Up @@ -945,6 +949,102 @@ namespace {
}
}

// 15 literal values spanning [0, 98] → density ≈ 0.15
// (between 1/8 and 1/4), designed to exercise the
// literal_runtime_dense dispatch tier.

static int patternia_pipe_literal_match_rdense_route(int x) {
using namespace ptn;
return match(x)
| on(ptn::lit(0) >> 0,
ptn::lit(7) >> 7,
ptn::lit(14) >> 14,
ptn::lit(21) >> 21,
ptn::lit(28) >> 28,
ptn::lit(35) >> 35,
ptn::lit(42) >> 42,
ptn::lit(49) >> 49,
ptn::lit(56) >> 56,
ptn::lit(63) >> 63,
ptn::lit(70) >> 70,
ptn::lit(77) >> 77,
ptn::lit(84) >> 84,
ptn::lit(91) >> 91,
ptn::lit(98) >> 98,
__ >> 0);
}

static int if_else_literal_match_rdense_route(int x) {
if (x == 0)
return 0;
if (x == 7)
return 7;
if (x == 14)
return 14;
if (x == 21)
return 21;
if (x == 28)
return 28;
if (x == 35)
return 35;
if (x == 42)
return 42;
if (x == 49)
return 49;
if (x == 56)
return 56;
if (x == 63)
return 63;
if (x == 70)
return 70;
if (x == 77)
return 77;
if (x == 84)
return 84;
if (x == 91)
return 91;
if (x == 98)
return 98;
return 0;
}

static int switch_literal_match_rdense_route(int x) {
switch (x) {
case 0:
return 0;
case 7:
return 7;
case 14:
return 14;
case 21:
return 21;
case 28:
return 28;
case 35:
return 35;
case 42:
return 42;
case 49:
return 49;
case 56:
return 56;
case 63:
return 63;
case 70:
return 70;
case 77:
return 77;
case 84:
return 84;
case 91:
return 91;
case 98:
return 98;
default:
return 0;
}
}

#define PTN_LIT_CASE_128(n) ptn::val<n> >> (n)
#define PTN_SWITCH_CASE_128(n) \
case (n): \
Expand Down Expand Up @@ -1515,6 +1615,18 @@ namespace {
return literal_workload();
}

static const std::vector<int> &literal_rdense_workload() {
static const std::vector<int> data = {
0, 7, 14, 21, 28, 35, 42, 49,
56, 63, 70, 77, 84, 91, 98, // all 15 sparse values
3, 10, 17, 31, 55, 99, // misses
-1, 100, // out-of-range
98, 91, 84, 77, 70, 63, 56, 49,
42, 35, 28, 21, 14, 7, 0, // reverse hits
};
return data;
}

template <typename T, typename F>
static void run_workload(benchmark::State &state,
const std::vector<T> &workload,
Expand Down Expand Up @@ -1898,6 +2010,25 @@ namespace {
switch_literal_match_128_route);
}

static void
BM_PatterniaPipe_LiteralMatchRDense(benchmark::State &state) {
run_workload(state,
literal_rdense_workload(),
patternia_pipe_literal_match_rdense_route);
}

static void BM_IfElse_LiteralMatchRDense(benchmark::State &state) {
run_workload(state,
literal_rdense_workload(),
if_else_literal_match_rdense_route);
}

static void BM_Switch_LiteralMatchRDense(benchmark::State &state) {
run_workload(state,
literal_rdense_workload(),
switch_literal_match_rdense_route);
}

} // namespace

#define PTN_REGISTER_STABLE_BENCH(name) \
Expand Down Expand Up @@ -1983,6 +2114,12 @@ PTN_REGISTER_STABLE_BENCH(BM_IfElse_LiteralMatch64);
PTN_REGISTER_STABLE_BENCH(BM_Switch_LiteralMatch64);
#endif

#if PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_RDENSE
PTN_REGISTER_STABLE_BENCH(BM_PatterniaPipe_LiteralMatchRDense);
PTN_REGISTER_STABLE_BENCH(BM_IfElse_LiteralMatchRDense);
PTN_REGISTER_STABLE_BENCH(BM_Switch_LiteralMatchRDense);
#endif

#if PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_128
PTN_REGISTER_STABLE_BENCH(
BM_PatterniaPipe_LiteralMatch128StaticCases);
Expand Down Expand Up @@ -2063,6 +2200,12 @@ PTN_REGISTER_STABLE_BENCH(BM_IfElse_LiteralMatch64);
PTN_REGISTER_STABLE_BENCH(BM_Switch_LiteralMatch64);
#endif

#if PTN_BENCH_ENABLE_SUITE_LITERAL_MATCH_RDENSE
PTN_REGISTER_STABLE_BENCH(BM_PatterniaPipe_LiteralMatchRDense);
PTN_REGISTER_STABLE_BENCH(BM_IfElse_LiteralMatchRDense);
PTN_REGISTER_STABLE_BENCH(BM_Switch_LiteralMatchRDense);
#endif

#if PTN_BENCH_ENABLE_SUITE_PACKET
PTN_REGISTER_STABLE_BENCH(BM_Patternia_PacketMixed);
PTN_REGISTER_STABLE_BENCH(BM_PatterniaPipe_PacketMixed);
Expand Down
13 changes: 13 additions & 0 deletions bench/compile-time/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,18 @@ else()
target_compile_options(ptn_ct_compound PRIVATE -O3)
endif()

# ── runtime-dense compile-time bench ───────────────────────────
# 15 sparse literal values (density ≈ 0.15) to exercise the
# literal_runtime_dense dispatch tier at compile time.
add_library(ptn_ct_lit_rdense OBJECT ct_bench_lit_rdense.cpp)
target_link_libraries(ptn_ct_lit_rdense PRIVATE patternia Threads::Threads)
target_compile_features(ptn_ct_lit_rdense PRIVATE cxx_std_17)
if(MSVC)
target_compile_options(ptn_ct_lit_rdense PRIVATE /O2)
else()
target_compile_options(ptn_ct_lit_rdense PRIVATE -O3)
endif()

# ── aggregate convenience target ──────────────────────────────
# `cmake --build build --target ptn_bench_ct` compiles every TU.
add_custom_target(ptn_bench_ct)
Expand All @@ -90,4 +102,5 @@ add_dependencies(ptn_bench_ct
ptn_ct_lit_64 ptn_ct_lit_128
ptn_ct_variant_32
ptn_ct_compound
ptn_ct_lit_rdense
)
31 changes: 31 additions & 0 deletions bench/compile-time/ct_bench_lit_rdense.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "ptn/patternia.hpp"

namespace {
constexpr int ct_lit_rdense(int v) noexcept {
using namespace ptn;
return match(v)
| on(ptn::lit(0) >> 0,
ptn::lit(7) >> 7,
ptn::lit(14) >> 14,
ptn::lit(21) >> 21,
ptn::lit(28) >> 28,
ptn::lit(35) >> 35,
ptn::lit(42) >> 42,
ptn::lit(49) >> 49,
ptn::lit(56) >> 56,
ptn::lit(63) >> 63,
ptn::lit(70) >> 70,
ptn::lit(77) >> 77,
ptn::lit(84) >> 84,
ptn::lit(91) >> 91,
ptn::lit(98) >> 98,
__ >> 0);
}

static_assert(ct_lit_rdense(0) == 0, "");
static_assert(ct_lit_rdense(49) == 49, "");
static_assert(ct_lit_rdense(98) == 98, "");
static_assert(ct_lit_rdense(-1) == 0, "");
static_assert(ct_lit_rdense(99) == 0, "");
static_assert(ct_lit_rdense(35) == 35, "");
} // namespace
19 changes: 12 additions & 7 deletions include/ptn/core/common/eval.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,8 @@ namespace ptn::core::common {
return static_cast<bool>(guarded.pred(bound));
}
else {
return static_cast<bool>(invoke_from_tuple(guarded.pred, bound));
return static_cast<bool>(
invoke_from_tuple(guarded.pred, bound));
}
}

Expand Down Expand Up @@ -651,8 +652,8 @@ namespace ptn::core::common {

// Dispatches to the offset-specific handler through a dense jump
// table. The switch is kept small because the lowering analysis
// already limits range_size to 512, and the compiler turns a dense
// integer switch into a jump table with no call overhead.
// already limits range_size to 512, and the compiler turns a
// dense integer switch into a jump table with no call overhead.
template <typename Plan,
typename Result,
typename Subject,
Expand Down Expand Up @@ -725,9 +726,10 @@ namespace ptn::core::common {
Otherwise &&otherwise_handler) {
using key_t = typename Plan::key_t;

const key_t value = static_cast<key_t>(subject);
const auto offset = static_cast<std::size_t>(value)
- static_cast<std::size_t>(Plan::min_value);
const key_t value = static_cast<key_t>(subject);
const auto offset = static_cast<std::size_t>(value)
- static_cast<std::size_t>(
Plan::min_value);

if (offset < Plan::range_size) {
return dispatch_static_literal_offset<Plan, Result>(
Expand Down Expand Up @@ -1137,7 +1139,10 @@ namespace ptn::core::common {
CasesTuple &&cases,
Otherwise &&otherwise_handler) {
if constexpr (Plan::kind
== dispatch_plan_kind::static_literal_dense) {
== dispatch_plan_kind::static_literal_dense
|| Plan::kind
== dispatch_plan_kind::
literal_runtime_dense) {
return eval_cases_impl_static_literal_dispatch<Plan, Result>(
subject,
std::forward<CasesTuple>(cases),
Expand Down
Loading