OpenSWMM Engine  6.0.0-alpha.4
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.4)
Loading...
Searching...
No Matches
KokkosPerfCounters.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2//
3// Copyright 2026 Caleb Buahin
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
53
54#ifndef OPENSWMM_ENGINE_2D_GPU_KOKKOS_PERF_COUNTERS_HPP
55#define OPENSWMM_ENGINE_2D_GPU_KOKKOS_PERF_COUNTERS_HPP
56
57#include <Kokkos_Core.hpp>
58
59#include <algorithm>
60#include <chrono>
61#include <cstdint>
62#include <cstdio>
63#include <cstdlib>
64#include <cstring>
65#include <map>
66#include <string>
67#include <vector>
68
70
72
74 std::string label;
75 long n = 0;
76 double sec = 0.0;
77};
78
79struct Counters {
80 long n_advance = 0;
81 long n_launch = 0;
82 long n_fence = 0;
83 double sec_fence = 0.0;
84 long n_deep_copy = 0;
85 unsigned long long bytes_h2d = 0, bytes_d2h = 0, bytes_same = 0;
86 std::vector<KernelEntry> kernels;
87 std::map<std::string, std::uint64_t> label_id;
88};
89
90inline Counters g;
91
92namespace detail {
93
94using clock = std::chrono::steady_clock;
95
99inline std::vector<clock::time_point> dispatch_t0;
100inline std::vector<clock::time_point> fence_t0;
101
102inline void begin_dispatch(const char* name, std::uint32_t /*devid*/,
103 std::uint64_t* kID) {
104 const auto it = g.label_id.find(name);
105 std::uint64_t id;
106 if (it == g.label_id.end()) {
107 id = g.kernels.size();
108 g.label_id.emplace(name, id);
109 g.kernels.push_back({name, 0, 0.0});
110 } else {
111 id = it->second;
112 }
113 *kID = id;
114 ++g.n_launch;
115 dispatch_t0.push_back(clock::now());
116}
117
118inline void end_dispatch(std::uint64_t kID) {
119 if (dispatch_t0.empty()) return;
120 const double dt = std::chrono::duration<double>(
121 clock::now() - dispatch_t0.back()).count();
122 dispatch_t0.pop_back();
123 if (kID < g.kernels.size()) {
124 ++g.kernels[kID].n;
125 g.kernels[kID].sec += dt;
126 }
127}
128
129inline void begin_fence(const char* /*name*/, std::uint32_t /*devid*/,
130 std::uint64_t* handle) {
131 *handle = 0;
132 fence_t0.push_back(clock::now());
133}
134
135inline void end_fence(std::uint64_t /*handle*/) {
136 if (fence_t0.empty()) return;
137 g.sec_fence += std::chrono::duration<double>(
138 clock::now() - fence_t0.back()).count();
139 fence_t0.pop_back();
140 ++g.n_fence;
141}
142
143inline void begin_deep_copy(Kokkos_Profiling_SpaceHandle dst, const char*,
144 const void*,
145 Kokkos_Profiling_SpaceHandle src, const char*,
146 const void*, std::uint64_t size) {
147 ++g.n_deep_copy;
148 const bool dst_host = std::strncmp(dst.name, "Host", 4) == 0;
149 const bool src_host = std::strncmp(src.name, "Host", 4) == 0;
150 if (src_host && !dst_host) g.bytes_h2d += size;
151 else if (dst_host && !src_host) g.bytes_d2h += size;
152 else g.bytes_same += size; // OMP backend: all
153}
154
155} // namespace detail
156
159inline void install() {
160 static const bool done = [] {
161 if (!perf::enabled()) return false;
162 if (std::getenv("KOKKOS_TOOLS_LIBS") ||
163 std::getenv("KOKKOS_PROFILE_LIBRARY")) {
164 std::fprintf(stderr,
165 "[PERF-2D-KOKKOS] external Kokkos tool loaded; in-process "
166 "counters disabled for this run.\n");
167 return false;
168 }
169 namespace KTE = Kokkos::Tools::Experimental;
170 KTE::set_begin_parallel_for_callback(detail::begin_dispatch);
171 KTE::set_end_parallel_for_callback(detail::end_dispatch);
172 KTE::set_begin_parallel_reduce_callback(detail::begin_dispatch);
173 KTE::set_end_parallel_reduce_callback(detail::end_dispatch);
174 KTE::set_begin_parallel_scan_callback(detail::begin_dispatch);
175 KTE::set_end_parallel_scan_callback(detail::end_dispatch);
176 KTE::set_begin_fence_callback(detail::begin_fence);
177 KTE::set_end_fence_callback(detail::end_fence);
178 KTE::set_begin_deep_copy_callback(detail::begin_deep_copy);
179 return true;
180 }();
181 (void)done;
182}
183
184inline void reset() {
185 g = Counters{};
186}
187
188inline void count_advance() {
189 if (perf::enabled()) ++g.n_advance;
190}
191
195inline void dump() {
196 if (!perf::enabled() || g.n_advance == 0) return;
197 const double adv = static_cast<double>(g.n_advance);
198 std::fprintf(stderr,
199 "[PERF-2D-KOKKOS] advances=%ld launches=%ld launches_per_advance=%.1f "
200 "fences=%ld fence_s=%.4f deep_copies=%ld "
201 "h2d_bytes=%llu d2h_bytes=%llu samespace_bytes=%llu "
202 "h2d_bytes_per_advance=%.0f d2h_bytes_per_advance=%.0f\n",
203 g.n_advance, g.n_launch, g.n_launch / adv,
204 g.n_fence, g.sec_fence, g.n_deep_copy,
205 g.bytes_h2d, g.bytes_d2h, g.bytes_same,
206 g.bytes_h2d / adv, g.bytes_d2h / adv);
207 std::vector<const KernelEntry*> order;
208 order.reserve(g.kernels.size());
209 for (const auto& k : g.kernels) order.push_back(&k);
210 std::sort(order.begin(), order.end(),
211 [](const KernelEntry* a, const KernelEntry* b) {
212 return a->sec > b->sec;
213 });
214 for (const KernelEntry* k : order)
215 std::fprintf(stderr,
216 "[PERF-2D-KOKKOS-KERNEL] name=%s n=%ld s=%.4f per_advance=%.1f\n",
217 k->label.c_str(), k->n, k->sec, k->n / adv);
218}
219
220} // namespace openswmm::twoD::gpu::kperf
221
222#endif // OPENSWMM_ENGINE_2D_GPU_KOKKOS_PERF_COUNTERS_HPP
bool enabled() noexcept
True when OPENSWMM_PERF is set. Cached — getenv is not free.
Definition PerfTimers.hpp:178
Definition KokkosPerfCounters.hpp:92
std::chrono::steady_clock clock
Definition KokkosPerfCounters.hpp:94
std::vector< clock::time_point > dispatch_t0
Definition KokkosPerfCounters.hpp:99
void end_dispatch(std::uint64_t kID)
Definition KokkosPerfCounters.hpp:118
void end_fence(std::uint64_t)
Definition KokkosPerfCounters.hpp:135
void begin_deep_copy(Kokkos_Profiling_SpaceHandle dst, const char *, const void *, Kokkos_Profiling_SpaceHandle src, const char *, const void *, std::uint64_t size)
Definition KokkosPerfCounters.hpp:143
std::vector< clock::time_point > fence_t0
Definition KokkosPerfCounters.hpp:100
void begin_dispatch(const char *name, std::uint32_t, std::uint64_t *kID)
Definition KokkosPerfCounters.hpp:102
void begin_fence(const char *, std::uint32_t, std::uint64_t *handle)
Definition KokkosPerfCounters.hpp:129
Definition KokkosPerfCounters.hpp:71
Counters g
Definition KokkosPerfCounters.hpp:90
void dump()
Definition KokkosPerfCounters.hpp:195
void reset()
Definition KokkosPerfCounters.hpp:184
void install()
Definition KokkosPerfCounters.hpp:159
void count_advance()
Definition KokkosPerfCounters.hpp:188
Definition KokkosPerfCounters.hpp:79
std::map< std::string, std::uint64_t > label_id
Definition KokkosPerfCounters.hpp:87
long n_advance
Definition KokkosPerfCounters.hpp:80
unsigned long long bytes_same
Definition KokkosPerfCounters.hpp:85
long n_deep_copy
Definition KokkosPerfCounters.hpp:84
long n_launch
parallel_for + reduce + scan
Definition KokkosPerfCounters.hpp:81
unsigned long long bytes_d2h
Definition KokkosPerfCounters.hpp:85
std::vector< KernelEntry > kernels
indexed by kernel id
Definition KokkosPerfCounters.hpp:86
double sec_fence
Definition KokkosPerfCounters.hpp:83
long n_fence
Definition KokkosPerfCounters.hpp:82
unsigned long long bytes_h2d
Definition KokkosPerfCounters.hpp:85
Definition KokkosPerfCounters.hpp:73
std::string label
Definition KokkosPerfCounters.hpp:74
double sec
host-side dispatch wall (== execution on OMP)
Definition KokkosPerfCounters.hpp:76
long n
launches
Definition KokkosPerfCounters.hpp:75