kernelmeter 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kernelmeter/__init__.py +28 -0
- kernelmeter/attrs.py +149 -0
- kernelmeter/bench.py +292 -0
- kernelmeter/ceiling.py +111 -0
- kernelmeter/cli.py +304 -0
- kernelmeter/cudadrv.py +129 -0
- kernelmeter/occupancy.py +102 -0
- kernelmeter/peaks.py +83 -0
- kernelmeter/roofline.py +89 -0
- kernelmeter-0.2.0.dist-info/METADATA +309 -0
- kernelmeter-0.2.0.dist-info/RECORD +15 -0
- kernelmeter-0.2.0.dist-info/WHEEL +5 -0
- kernelmeter-0.2.0.dist-info/entry_points.txt +2 -0
- kernelmeter-0.2.0.dist-info/licenses/LICENSE +21 -0
- kernelmeter-0.2.0.dist-info/top_level.txt +1 -0
kernelmeter/roofline.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""Roofline model: how fast a kernel *can* go at a given arithmetic intensity.
|
|
2
|
+
|
|
3
|
+
A kernel that does f FLOPs while moving b bytes has intensity f/b. Below
|
|
4
|
+
the ridge point the memory system is the limit, above it the ALUs are.
|
|
5
|
+
The attainable ceiling at intensity I is min(peak_flops, I * peak_bw),
|
|
6
|
+
and a kernel's quality is best judged against that, not against whichever
|
|
7
|
+
single peak happens to look more flattering.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import math
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def intensity(flops: int, nbytes: int) -> float:
|
|
16
|
+
return flops / nbytes
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def ridge_point(peak_tflops: float, peak_bw_gbs: float) -> float:
|
|
20
|
+
"""Intensity (flop/byte) where the memory roof meets the compute roof."""
|
|
21
|
+
return 1000.0 * peak_tflops / peak_bw_gbs
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def attainable_tflops(ai: float, peak_tflops: float, peak_bw_gbs: float) -> float:
|
|
25
|
+
return min(peak_tflops, ai * peak_bw_gbs / 1000.0)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def bound(ai: float, peak_tflops: float, peak_bw_gbs: float) -> str:
|
|
29
|
+
return "mem" if ai < ridge_point(peak_tflops, peak_bw_gbs) else "comp"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def render(
|
|
33
|
+
peak_tflops: float,
|
|
34
|
+
peak_bw_gbs: float,
|
|
35
|
+
ai: float | None = None,
|
|
36
|
+
width: int = 58,
|
|
37
|
+
height: int = 12,
|
|
38
|
+
) -> list[str]:
|
|
39
|
+
"""Draw the roofline as text. Log-log, x from 1/8 to 256 flop/byte.
|
|
40
|
+
|
|
41
|
+
The roof is drawn with '*', the ridge column is marked 'x', and the
|
|
42
|
+
optional ai argument puts an 'o' where the caller's kernel sits.
|
|
43
|
+
"""
|
|
44
|
+
lo, hi = -3.0, 8.0 # log2 of the intensity axis
|
|
45
|
+
ridge = ridge_point(peak_tflops, peak_bw_gbs)
|
|
46
|
+
|
|
47
|
+
def col_to_ai(c: int) -> float:
|
|
48
|
+
return 2.0 ** (lo + (hi - lo) * c / (width - 1))
|
|
49
|
+
|
|
50
|
+
def ai_to_col(a: float) -> int:
|
|
51
|
+
c = round((math.log2(a) - lo) / (hi - lo) * (width - 1))
|
|
52
|
+
return min(max(c, 0), width - 1)
|
|
53
|
+
|
|
54
|
+
ys = [attainable_tflops(col_to_ai(c), peak_tflops, peak_bw_gbs) for c in range(width)]
|
|
55
|
+
ymin, ymax = math.log10(ys[0]), math.log10(peak_tflops)
|
|
56
|
+
|
|
57
|
+
def y_to_row(y: float) -> int:
|
|
58
|
+
if ymax == ymin:
|
|
59
|
+
return height - 1
|
|
60
|
+
frac = (math.log10(y) - ymin) / (ymax - ymin)
|
|
61
|
+
return min(max(round(frac * (height - 1)), 0), height - 1)
|
|
62
|
+
|
|
63
|
+
grid = [[" "] * width for _ in range(height)]
|
|
64
|
+
for c, y in enumerate(ys):
|
|
65
|
+
grid[height - 1 - y_to_row(y)][c] = "*"
|
|
66
|
+
grid[height - 1 - y_to_row(attainable_tflops(ridge, peak_tflops, peak_bw_gbs))][
|
|
67
|
+
ai_to_col(ridge)
|
|
68
|
+
] = "x"
|
|
69
|
+
if ai is not None:
|
|
70
|
+
a = min(max(ai, 2.0**lo), 2.0**hi)
|
|
71
|
+
grid[height - 1 - y_to_row(attainable_tflops(a, peak_tflops, peak_bw_gbs))][
|
|
72
|
+
ai_to_col(a)
|
|
73
|
+
] = "o"
|
|
74
|
+
|
|
75
|
+
top_label = f"{peak_tflops:.2f} TF/s "
|
|
76
|
+
pad = len(top_label)
|
|
77
|
+
lines = []
|
|
78
|
+
for r, row in enumerate(grid):
|
|
79
|
+
label = top_label if r == 0 else " " * pad
|
|
80
|
+
lines.append(label + "|" + "".join(row))
|
|
81
|
+
lines.append(" " * pad + "+" + "-" * width)
|
|
82
|
+
ticks = {ai_to_col(2.0**e): f"2^{e}" for e in (-3, 0, 3, 6)}
|
|
83
|
+
axis = [" "] * (width + 1)
|
|
84
|
+
for col, text in ticks.items():
|
|
85
|
+
for i, ch in enumerate(text):
|
|
86
|
+
if col + i < len(axis):
|
|
87
|
+
axis[col + i] = ch
|
|
88
|
+
lines.append(" " * pad + " " + "".join(axis) + " flop/byte")
|
|
89
|
+
return lines
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kernelmeter
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Query every CUDA device attribute without profiling a kernel, and benchmark your kernels against the hardware's speed of light.
|
|
5
|
+
Author: nuemaan
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/nuemaan/kernelmeter
|
|
8
|
+
Project-URL: Issues, https://github.com/nuemaan/kernelmeter/issues
|
|
9
|
+
Keywords: cuda,gpu,benchmark,profiling,device-attributes,speed-of-light
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
15
|
+
Classifier: Topic :: System :: Hardware
|
|
16
|
+
Requires-Python: >=3.9
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Provides-Extra: bench
|
|
20
|
+
Requires-Dist: torch; extra == "bench"
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
# kernelmeter
|
|
26
|
+
|
|
27
|
+
Small tools for one question: **is my GPU kernel actually good, and if
|
|
28
|
+
not, what exactly is holding it back?** All in one package with zero
|
|
29
|
+
required dependencies.
|
|
30
|
+
|
|
31
|
+
* `kernelmeter info` prints every device attribute your GPU driver knows,
|
|
32
|
+
plus the card's theoretical peak bandwidth and FP32 throughput. No CUDA
|
|
33
|
+
toolkit, no torch, no kernel launch. It reads straight from `libcuda`,
|
|
34
|
+
which is part of the NVIDIA driver.
|
|
35
|
+
* `kernelmeter bench` times your kernel, checks the output against a
|
|
36
|
+
reference, and scores it against the roofline: the best your card could
|
|
37
|
+
possibly do for that kernel's mix of math and memory traffic. 240 GB/s
|
|
38
|
+
means nothing on its own; "76% of attainable" tells you how much room
|
|
39
|
+
is left.
|
|
40
|
+
* `kernelmeter roofline` draws your card's roofline in the terminal and
|
|
41
|
+
shows where a kernel sits on it.
|
|
42
|
+
* `kernelmeter occupancy` answers "why is my occupancy 50%?" from block
|
|
43
|
+
size, registers and shared memory, and shows which block sizes fix it.
|
|
44
|
+
* `kernelmeter ceiling` measures what the card *really* delivers
|
|
45
|
+
(STREAM-style bandwidth tests plus a big FP32 matmul), because spec
|
|
46
|
+
sheet numbers are never fully reachable.
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install kernelmeter # info only, no dependencies
|
|
52
|
+
pip install "kernelmeter[bench]" # adds torch for the bench harness
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or from source:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git clone https://github.com/nuemaan/kernelmeter
|
|
59
|
+
cd kernelmeter
|
|
60
|
+
pip install -e ".[bench]"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Querying your GPU
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
kernelmeter info
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Output from a Tesla T4:
|
|
70
|
+
|
|
71
|
+
```text
|
|
72
|
+
CUDA driver version : 13.0
|
|
73
|
+
|
|
74
|
+
Device 0: Tesla T4 (14.6 GiB)
|
|
75
|
+
compute capability : 7.5
|
|
76
|
+
theoretical mem bandwidth : 320.1 GB/s
|
|
77
|
+
theoretical FP32 peak : 8.14 TFLOP/s
|
|
78
|
+
|
|
79
|
+
attribute value
|
|
80
|
+
------------------------------------------------ ------------
|
|
81
|
+
max_threads_per_block 1024
|
|
82
|
+
max_block_dim_x 1024
|
|
83
|
+
max_shared_memory_per_block 49152
|
|
84
|
+
warp_size 32
|
|
85
|
+
clock_rate_khz 1590000
|
|
86
|
+
... (147 attributes total)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
These are the same values Nsight Compute shows as `device__attribute_*`,
|
|
90
|
+
except you don't need to profile a kernel to see them. Add `--json` for
|
|
91
|
+
machine-readable output.
|
|
92
|
+
|
|
93
|
+
Every attribute id is probed against the live driver, so the output always
|
|
94
|
+
matches the machine you run it on. Ids newer than the bundled name table
|
|
95
|
+
still show up, just under a generic `attribute_<id>` name.
|
|
96
|
+
|
|
97
|
+
## Benchmarking a kernel
|
|
98
|
+
|
|
99
|
+
Three steps.
|
|
100
|
+
|
|
101
|
+
**1. Write your kernel in a file and decorate it.** Anything callable from
|
|
102
|
+
Python works: Triton kernels, custom CUDA extensions, `torch.compile`
|
|
103
|
+
output, CuPy. Here is a complete file you can copy:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
# mybench.py
|
|
107
|
+
import torch
|
|
108
|
+
import kernelmeter as km
|
|
109
|
+
|
|
110
|
+
N = 1 << 26 # work on big inputs so you measure memory, not cache
|
|
111
|
+
|
|
112
|
+
def make_args():
|
|
113
|
+
return (torch.randn(N, device="cuda"), torch.randn(N, device="cuda"))
|
|
114
|
+
|
|
115
|
+
@km.benchmark(
|
|
116
|
+
"my_add",
|
|
117
|
+
args=make_args, # builds fresh inputs for the run
|
|
118
|
+
ref=torch.add, # trusted implementation to compare with
|
|
119
|
+
bytes_per_call=lambda x, y: 3 * x.numel() * x.element_size(),
|
|
120
|
+
)
|
|
121
|
+
def my_add(x, y):
|
|
122
|
+
return x + y # <- replace with your kernel
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`bytes_per_call` is how much memory the algorithm has to move (here: read
|
|
126
|
+
x, read y, write the result). The tool divides it by measured time to get
|
|
127
|
+
your effective bandwidth.
|
|
128
|
+
|
|
129
|
+
**2. Run it.**
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
kernelmeter bench mybench.py
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**3. Read the result.** From a T4, with the add written as a Triton kernel:
|
|
136
|
+
|
|
137
|
+
```text
|
|
138
|
+
kernel median ms GB/s TFLOP/s bound %roof vs ref correct
|
|
139
|
+
------------------------------------------------------------------------------------------
|
|
140
|
+
my_add 3.3393 241.2 - mem 75.3% 1.01x PASS
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
* **correct** - your output matched the reference. If this says FAIL,
|
|
144
|
+
nothing else on the line matters.
|
|
145
|
+
* **bound** - whether the memory system (`mem`) or the ALUs (`comp`) limit
|
|
146
|
+
this kernel, decided by its arithmetic intensity (flops per byte).
|
|
147
|
+
* **%roof** - how close you are to the best this card could possibly do
|
|
148
|
+
for that intensity. This is the score to improve. Above ~80% there is
|
|
149
|
+
little left to win.
|
|
150
|
+
* **vs ref** - speedup over the reference implementation.
|
|
151
|
+
|
|
152
|
+
Pass `flops_per_call` too and the roofline model places your kernel
|
|
153
|
+
precisely; pass `peak_tflops=...` if your kernel runs on tensor cores so
|
|
154
|
+
it gets judged against the right ceiling. Raw `%peak bw` and `%fp32`
|
|
155
|
+
numbers are always in the `--json` output.
|
|
156
|
+
|
|
157
|
+
Timing uses CUDA events with warmup, and the L2 cache is flushed between
|
|
158
|
+
iterations so small workloads can't fake huge bandwidth numbers from
|
|
159
|
+
cache hits. Pass `--no-flush-l2` if you want cache-hot numbers.
|
|
160
|
+
|
|
161
|
+
The [examples](examples/) folder has ready-to-run starting points: two
|
|
162
|
+
Triton kernels (vector add, fused softmax) and a compute-bound matmul.
|
|
163
|
+
|
|
164
|
+
## Seeing the roofline
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
kernelmeter roofline --ai 0.33 # mark a kernel at 0.33 flop/byte
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
```text
|
|
171
|
+
peak bandwidth : 320.0 GB/s
|
|
172
|
+
peak compute : 8.14 TFLOP/s
|
|
173
|
+
ridge point : 25.4 flop/byte
|
|
174
|
+
|
|
175
|
+
8.14 TF/s | **x*****************
|
|
176
|
+
| ***
|
|
177
|
+
| ****
|
|
178
|
+
| ***
|
|
179
|
+
| ****
|
|
180
|
+
| ****
|
|
181
|
+
| ***
|
|
182
|
+
| ****
|
|
183
|
+
| ***
|
|
184
|
+
| *o**
|
|
185
|
+
| ****
|
|
186
|
+
|**
|
|
187
|
+
+----------------------------------------------------------
|
|
188
|
+
2^-3 2^0 2^3 2^6
|
|
189
|
+
|
|
190
|
+
at 0.33 flop/byte the kernel is memory-bound; attainable: 0.11 TFLOP/s
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
The `o` is your kernel, the `x` is the ridge point. Left of the ridge,
|
|
194
|
+
more FLOPs are free: the memory traffic is the bill you are paying
|
|
195
|
+
anyway. That is the whole argument for kernel fusion, in one picture.
|
|
196
|
+
No GPU around? `--peak-bw` and `--peak-tflops` let you draw any card.
|
|
197
|
+
|
|
198
|
+
## Why is my occupancy low?
|
|
199
|
+
|
|
200
|
+
Feed it what `ptxas -v` or Nsight Compute tells you about your kernel:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
kernelmeter occupancy --block 256 --regs 64 --smem 8192 --cc 8.6
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
```text
|
|
207
|
+
occupancy for compute capability 8.6
|
|
208
|
+
block=256 regs/thread=64 smem/block=8192
|
|
209
|
+
|
|
210
|
+
occupancy : 66.7% (32/48 warps per SM)
|
|
211
|
+
blocks per SM: 4
|
|
212
|
+
limited by : registers
|
|
213
|
+
|
|
214
|
+
block size 64 128 192 256 384 512 768 1024
|
|
215
|
+
occupancy 46% 67% 62% 67% 50% 67% 50% 67%
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
It names the resource that is capping you and sweeps block sizes so you
|
|
219
|
+
can see if a different launch shape helps. Works with no GPU present:
|
|
220
|
+
pass `--cc` for any architecture from 7.0 (Volta) to 12.x (Blackwell).
|
|
221
|
+
|
|
222
|
+
## What can the card really do?
|
|
223
|
+
|
|
224
|
+
Theoretical peaks assume the max boost clock, which the card cannot hold.
|
|
225
|
+
Measure the real ceilings once and judge your kernels against those:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
kernelmeter ceiling
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
This runs the four STREAM kernels (copy, scale, add, triad) and a large
|
|
232
|
+
TF32-disabled matmul. On the same T4:
|
|
233
|
+
|
|
234
|
+
```text
|
|
235
|
+
test median ms GB/s TFLOP/s % of theoretical
|
|
236
|
+
---------------------------------------------------------------
|
|
237
|
+
copy 1.1495 233.5 - 73.0%
|
|
238
|
+
scale 1.1674 230.0 - 71.8%
|
|
239
|
+
add 1.6903 238.2 - 74.4%
|
|
240
|
+
triad 1.6878 238.6 - 74.5%
|
|
241
|
+
fp32 matmul 3.5563 - 4.83 59.3%
|
|
242
|
+
|
|
243
|
+
measured bandwidth ceiling: 238.6 GB/s (use this as the honest 100%
|
|
244
|
+
for memory-bound kernels)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
This reframes the bench results above: the vector add that scored "75.3%
|
|
248
|
+
of theoretical" was moving 241 GB/s on a card whose memory system tops
|
|
249
|
+
out at 238.6 GB/s in practice. It was already saturated. Without the
|
|
250
|
+
measured ceiling you would have kept optimizing a finished kernel.
|
|
251
|
+
|
|
252
|
+
## Catching regressions
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
kernelmeter bench mykernels.py --save baseline.json
|
|
256
|
+
# ...edit your kernels...
|
|
257
|
+
kernelmeter bench mykernels.py --compare baseline.json
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
The compare run prints a delta column per kernel and exits non-zero if
|
|
261
|
+
anything got more than 5% slower, so it slots straight into CI.
|
|
262
|
+
|
|
263
|
+
## A workflow that works
|
|
264
|
+
|
|
265
|
+
If you are learning CUDA (say, working through the PMPP book) and wondering
|
|
266
|
+
whether your kernels are any good:
|
|
267
|
+
|
|
268
|
+
1. Run `kernelmeter info` and `kernelmeter ceiling` once. Now you know
|
|
269
|
+
your card's real limits.
|
|
270
|
+
2. Benchmark your kernel with `bytes_per_call` and `flops_per_call` set.
|
|
271
|
+
The `bound` column tells you which resource you are fighting.
|
|
272
|
+
3. `%roof` under ~60%? If the kernel is memory-bound, check `occupancy`
|
|
273
|
+
first: too few warps in flight cannot hide memory latency. Then open
|
|
274
|
+
Nsight Compute. Now you know what you are looking for, instead of
|
|
275
|
+
staring at forty unfamiliar counters.
|
|
276
|
+
4. `%roof` above ~80%? Stop optimizing this kernel. The next win is
|
|
277
|
+
algorithmic (fuse it with a neighbor, move less data), and the
|
|
278
|
+
roofline chart shows why: left of the ridge, FLOPs are free.
|
|
279
|
+
|
|
280
|
+
## Caveats
|
|
281
|
+
|
|
282
|
+
* Theoretical peaks are computed from the max boost clock the driver
|
|
283
|
+
reports. Sustained clocks under load are lower; `kernelmeter ceiling`
|
|
284
|
+
measures what you can actually reach.
|
|
285
|
+
* The derived compute peak is for plain FP32 on CUDA cores. For
|
|
286
|
+
tensor-core kernels pass `peak_tflops=...` to the benchmark decorator
|
|
287
|
+
so the roofline uses the right roof.
|
|
288
|
+
* The occupancy command implements the standard calculator model. Real
|
|
289
|
+
occupancy can differ (launch bounds, driver decisions); confirm with
|
|
290
|
+
Nsight Compute when it matters.
|
|
291
|
+
* Attribute names above id 121 are best-effort against the CUDA 12.x
|
|
292
|
+
headers. Values are always read live from your driver. PRs that extend
|
|
293
|
+
the name table are welcome.
|
|
294
|
+
|
|
295
|
+
## Development
|
|
296
|
+
|
|
297
|
+
```bash
|
|
298
|
+
pip install -e ".[dev]"
|
|
299
|
+
pytest
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
The tests fake the driver, so they run anywhere, no GPU needed. CI runs
|
|
303
|
+
them on plain GitHub runners. For an end-to-end check on a real GPU there
|
|
304
|
+
is a [Modal](https://modal.com) script: `modal run scripts/modal_gpu_test.py`.
|
|
305
|
+
The numbers in this README come from that script on a T4.
|
|
306
|
+
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
MIT
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
kernelmeter/__init__.py,sha256=OpiOgyZfN4cRYJNB_FffmaOWjtaa0F5Fd88UuxxR2Hw,694
|
|
2
|
+
kernelmeter/attrs.py,sha256=_ecmq5ogS56zlq1kdR7lwQQyKiJYyr3719WSNs5QOas,5530
|
|
3
|
+
kernelmeter/bench.py,sha256=i963oZTAi7qitfMnZ_3_v6sD5CJHxogzlqAUxVUJMl4,9526
|
|
4
|
+
kernelmeter/ceiling.py,sha256=82MfdDAvANk3sd4enjJw9Pkz8wVnfPUw6UBJX-bpZYs,3710
|
|
5
|
+
kernelmeter/cli.py,sha256=TlSPGpaZLMOxAf95Or2v7gfjiK3j0ME2uA6enm-qGyU,11812
|
|
6
|
+
kernelmeter/cudadrv.py,sha256=lN2KjBdD1sxrfQTGZ0DKTuuGjyedy5rLo5FJdtIK4vQ,4487
|
|
7
|
+
kernelmeter/occupancy.py,sha256=P6GqCePxRPdEdy0Ndocv1I_yZUAOI4xht-uID3EZwjA,4390
|
|
8
|
+
kernelmeter/peaks.py,sha256=HNf_vTJzDzu593ftSy-cIDRYzC5KpDelG0EIdZTNYn8,3062
|
|
9
|
+
kernelmeter/roofline.py,sha256=wX1-qnoijW9vYe7RBLED_ORpipMvG4GtIIzpaPn5_H4,3132
|
|
10
|
+
kernelmeter-0.2.0.dist-info/licenses/LICENSE,sha256=EASEg34VB7YUVHkVvKfhQaKhmBPZimhHiuK3xKtZeOo,1064
|
|
11
|
+
kernelmeter-0.2.0.dist-info/METADATA,sha256=V7swYSC6tXGqTMazV14LhpGrQUDFXYEAWI1-Rb-4K8Y,11183
|
|
12
|
+
kernelmeter-0.2.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
13
|
+
kernelmeter-0.2.0.dist-info/entry_points.txt,sha256=3HIIMm9LY52xXVl64iOtmjp4dgsUHYobn3l9dX0uMQ8,53
|
|
14
|
+
kernelmeter-0.2.0.dist-info/top_level.txt,sha256=PKQS7ycXwZD23SKjrKVcKCRk6KIxVGdBOmOgKyhQUyQ,12
|
|
15
|
+
kernelmeter-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nuemaan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
kernelmeter
|