scm2cpp-learn 0.18.0__py3-none-win_amd64.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.
- scm2cpp_learn/__init__.py +3836 -0
- scm2cpp_learn/_classifiers.cp312-win_amd64.pyd +0 -0
- scm2cpp_learn/_compat.py +284 -0
- scm2cpp_learn/_generated/__init__.py +0 -0
- scm2cpp_learn/_generated/_loader.py +41 -0
- scm2cpp_learn/_generated/_loader_accel_cublas.py +173 -0
- scm2cpp_learn/_generated/_loader_classifiers.py +308 -0
- scm2cpp_learn/_generated/_loader_derived_blas.py +29 -0
- scm2cpp_learn/_generated/_loader_derived_cublas.py +29 -0
- scm2cpp_learn/_generated/_loader_derived_loops.py +29 -0
- scm2cpp_learn/_generated/_loader_gpu_cuda.py +313 -0
- scm2cpp_learn/_generated/_loader_gramops_blas.py +692 -0
- scm2cpp_learn/_generated/_loader_gramops_loops.py +711 -0
- scm2cpp_learn/_generated/_loader_nmf_blas.py +29 -0
- scm2cpp_learn/_generated/_loader_nmf_cublas.py +29 -0
- scm2cpp_learn/_generated/_loader_nmf_loops.py +29 -0
- scm2cpp_learn/_generated/accel_cublas/accel.cpp +24 -0
- scm2cpp_learn/_generated/accel_cublas/accel.hpp +1178 -0
- scm2cpp_learn/_generated/accel_cublas/accel_capi.cpp +76 -0
- scm2cpp_learn/_generated/classifiers.cpp +37 -0
- scm2cpp_learn/_generated/classifiers.hpp +3745 -0
- scm2cpp_learn/_generated/classifiers_capi.cpp +115 -0
- scm2cpp_learn/_generated/derived_blas/lasso_design.cpp +5 -0
- scm2cpp_learn/_generated/derived_blas/lasso_design.hpp +156 -0
- scm2cpp_learn/_generated/derived_blas/lasso_design_capi.cpp +19 -0
- scm2cpp_learn/_generated/derived_cublas/lasso_design.cpp +5 -0
- scm2cpp_learn/_generated/derived_cublas/lasso_design.hpp +158 -0
- scm2cpp_learn/_generated/derived_cublas/lasso_design_capi.cpp +19 -0
- scm2cpp_learn/_generated/derived_loops/lasso_design.cpp +5 -0
- scm2cpp_learn/_generated/derived_loops/lasso_design.hpp +179 -0
- scm2cpp_learn/_generated/derived_loops/lasso_design_capi.cpp +19 -0
- scm2cpp_learn/_generated/gpu_cuda/gpu.cpp +37 -0
- scm2cpp_learn/_generated/gpu_cuda/gpu.hpp +3846 -0
- scm2cpp_learn/_generated/gpu_cuda/gpu_capi.cpp +308 -0
- scm2cpp_learn/_generated/gramops_blas/gramops.cpp +82 -0
- scm2cpp_learn/_generated/gramops_blas/gramops.hpp +5411 -0
- scm2cpp_learn/_generated/gramops_blas/gramops_capi.cpp +244 -0
- scm2cpp_learn/_generated/gramops_loops/gramops.cpp +82 -0
- scm2cpp_learn/_generated/gramops_loops/gramops.hpp +6395 -0
- scm2cpp_learn/_generated/gramops_loops/gramops_capi.cpp +250 -0
- scm2cpp_learn/_generated/lasso_cov.cpp +7 -0
- scm2cpp_learn/_generated/lasso_cov.hpp +152 -0
- scm2cpp_learn/_generated/lasso_cov_capi.cpp +25 -0
- scm2cpp_learn/_generated/nmf_blas/nmf_cd.cpp +5 -0
- scm2cpp_learn/_generated/nmf_blas/nmf_cd.hpp +132 -0
- scm2cpp_learn/_generated/nmf_blas/nmf_cd_capi.cpp +19 -0
- scm2cpp_learn/_generated/nmf_cublas/nmf_cd.cpp +5 -0
- scm2cpp_learn/_generated/nmf_cublas/nmf_cd.hpp +136 -0
- scm2cpp_learn/_generated/nmf_cublas/nmf_cd_capi.cpp +19 -0
- scm2cpp_learn/_generated/nmf_loops/nmf_cd.cpp +5 -0
- scm2cpp_learn/_generated/nmf_loops/nmf_cd.hpp +167 -0
- scm2cpp_learn/_generated/nmf_loops/nmf_cd_capi.cpp +19 -0
- scm2cpp_learn/_generated/scm2cpp-blas.hpp +158 -0
- scm2cpp_learn/_generated/scm2cpp-cublas.hpp +155 -0
- scm2cpp_learn/_generated/scm2cpp-cuda.hpp +285 -0
- scm2cpp_learn/_generated/scm2cpp.hpp +1627 -0
- scm2cpp_learn/_gramops_blas.cp312-win_amd64.pyd +0 -0
- scm2cpp_learn/_lasso_cov.cp312-win_amd64.pyd +0 -0
- scm2cpp_learn/_lasso_derived_blas.cp312-win_amd64.pyd +0 -0
- scm2cpp_learn/_libfind.py +153 -0
- scm2cpp_learn/_nmf_blas.cp312-win_amd64.pyd +0 -0
- scm2cpp_learn/batch_capi.cu +428 -0
- scm2cpp_learn-0.18.0.dist-info/DELVEWHEEL +2 -0
- scm2cpp_learn-0.18.0.dist-info/METADATA +1171 -0
- scm2cpp_learn-0.18.0.dist-info/RECORD +72 -0
- scm2cpp_learn-0.18.0.dist-info/WHEEL +5 -0
- scm2cpp_learn-0.18.0.dist-info/top_level.txt +1 -0
- scm2cpp_learn.libs/.load-order-scm2cpp_learn-0.18.0 +4 -0
- scm2cpp_learn.libs/libopenblas-0486735c359a67419d8832e3c40e2837.dll +4 -0
- scm2cpp_learn.libs/msvcp140-73438573e87f9a2fd944b01def13566d.dll +0 -0
- scm2cpp_learn.libs/vcruntime140-052ad6a20d375957e82aa6a3c441ea54.dll +0 -0
- scm2cpp_learn.libs/vcruntime140_1-a198370e11c6e7469d1cf0ef5b3f433d.dll +0 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
// The device back end of --cuda: arrays that live on the device across
|
|
2
|
+
// statements, the kernels the translator emits for parallel loops, and
|
|
3
|
+
// the products of the array algebra on those device arrays.
|
|
4
|
+
//
|
|
5
|
+
// Every host array a device statement touches gets a mirror: a device
|
|
6
|
+
// buffer of the same length and two flags, host_ok and dev_ok, saying
|
|
7
|
+
// which side holds the current values. The translator brackets each
|
|
8
|
+
// statement:
|
|
9
|
+
//
|
|
10
|
+
// a device statement (a kernel launch, a product) takes dev(v) for
|
|
11
|
+
// every array it uses -- uploading only when dev_ok is false -- and
|
|
12
|
+
// marks the arrays it writes with wrote_dev(v) (host_ok false);
|
|
13
|
+
//
|
|
14
|
+
// a host statement first calls need_host(v) for the arrays it uses --
|
|
15
|
+
// downloading only when host_ok is false -- and then wrote_host(v) for
|
|
16
|
+
// the arrays it may write (dev_ok false).
|
|
17
|
+
//
|
|
18
|
+
// So an array the host never touches between device statements stays on
|
|
19
|
+
// the device, and one only the host uses never goes there. A fresh
|
|
20
|
+
// allocation calls fresh(v), which drops a mirror left at the same
|
|
21
|
+
// address by an array that no longer exists. end_call() -- at the
|
|
22
|
+
// return of every extern "C" entry -- forgets what the host has not
|
|
23
|
+
// seen and frees every mirror; the caller may change its arrays before
|
|
24
|
+
// the next call, and nothing survives it. (The wrapper first brings back
|
|
25
|
+
// the caller's arrays with need_host; end_call itself copies nothing.)
|
|
26
|
+
//
|
|
27
|
+
// Compile with nvcc; link with -lcublas.
|
|
28
|
+
#ifndef SCM2CPP_CUDA_HPP
|
|
29
|
+
#define SCM2CPP_CUDA_HPP
|
|
30
|
+
|
|
31
|
+
#include <cublas_v2.h>
|
|
32
|
+
#include <cuda_runtime.h>
|
|
33
|
+
#include <cstdio>
|
|
34
|
+
#include <cstdlib>
|
|
35
|
+
#include <type_traits>
|
|
36
|
+
#include <unordered_map>
|
|
37
|
+
|
|
38
|
+
namespace scm2cpp {
|
|
39
|
+
namespace cu {
|
|
40
|
+
|
|
41
|
+
inline void check(cudaError_t e, const char* what) {
|
|
42
|
+
if (e != cudaSuccess) {
|
|
43
|
+
std::fprintf(stderr, "scm2cpp-cuda: %s: %s\n", what, cudaGetErrorString(e));
|
|
44
|
+
std::abort();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
inline void check_blas(cublasStatus_t s, const char* what) {
|
|
48
|
+
if (s != CUBLAS_STATUS_SUCCESS) {
|
|
49
|
+
std::fprintf(stderr, "scm2cpp-cuda: %s: status %d\n", what, (int)s);
|
|
50
|
+
std::abort();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// SCM2CPP_CUDA_DEBUG=1: every launch synchronised and checked, every
|
|
55
|
+
// transfer reported, on stderr
|
|
56
|
+
inline bool debug() {
|
|
57
|
+
static int d = -1;
|
|
58
|
+
if (d < 0) d = std::getenv("SCM2CPP_CUDA_DEBUG") ? 1 : 0;
|
|
59
|
+
return d == 1;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
inline cublasHandle_t handle() {
|
|
63
|
+
static cublasHandle_t h = 0;
|
|
64
|
+
if (!h) check_blas(cublasCreate(&h), "cublasCreate");
|
|
65
|
+
return h;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
struct mirror {
|
|
69
|
+
void* d;
|
|
70
|
+
size_t bytes;
|
|
71
|
+
bool host_ok, dev_ok;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
inline std::unordered_map<const void*, mirror>& registry() {
|
|
75
|
+
static std::unordered_map<const void*, mirror> r;
|
|
76
|
+
return r;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Containers are anything with data() and size(); a scalar takes the
|
|
80
|
+
// no-op overloads, so the translator may pass every variable a statement
|
|
81
|
+
// mentions without knowing which are arrays.
|
|
82
|
+
template <class V, class = void>
|
|
83
|
+
struct is_array : std::false_type {};
|
|
84
|
+
template <class V>
|
|
85
|
+
struct is_array<V, std::void_t<decltype(std::declval<V&>().data()),
|
|
86
|
+
decltype(std::declval<V&>().size())>> : std::true_type {};
|
|
87
|
+
|
|
88
|
+
template <class V>
|
|
89
|
+
inline mirror& entry(V& v) {
|
|
90
|
+
const void* key = (const void*)v.data();
|
|
91
|
+
auto& r = registry();
|
|
92
|
+
auto it = r.find(key);
|
|
93
|
+
size_t bytes = v.size() * sizeof(*v.data());
|
|
94
|
+
if (it != r.end() && it->second.bytes == bytes) return it->second;
|
|
95
|
+
if (it != r.end()) {
|
|
96
|
+
cudaFree(it->second.d);
|
|
97
|
+
r.erase(it);
|
|
98
|
+
}
|
|
99
|
+
mirror m{nullptr, bytes, true, false};
|
|
100
|
+
if (bytes) check(cudaMalloc(&m.d, bytes), "cudaMalloc");
|
|
101
|
+
return r.emplace(key, m).first->second;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
template <class V>
|
|
105
|
+
inline auto dev(V& v) -> typename std::remove_reference<decltype(*v.data())>::type* {
|
|
106
|
+
typedef typename std::remove_reference<decltype(*v.data())>::type T;
|
|
107
|
+
mirror& m = entry(v);
|
|
108
|
+
if (!m.dev_ok) {
|
|
109
|
+
if (debug()) std::fprintf(stderr, "cu: upload %p %zu bytes\n", (const void*)v.data(), m.bytes);
|
|
110
|
+
if (m.bytes)
|
|
111
|
+
check(cudaMemcpy(m.d, (const void*)v.data(), m.bytes, cudaMemcpyHostToDevice), "upload");
|
|
112
|
+
m.dev_ok = true;
|
|
113
|
+
}
|
|
114
|
+
return (T*)m.d;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
template <class V>
|
|
118
|
+
inline void wrote_dev(V& v) {
|
|
119
|
+
mirror& m = entry(v);
|
|
120
|
+
m.dev_ok = true;
|
|
121
|
+
m.host_ok = false;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
template <class V>
|
|
125
|
+
inline typename std::enable_if<is_array<V>::value>::type need_host(V& v) {
|
|
126
|
+
auto& r = registry();
|
|
127
|
+
auto it = r.find((const void*)v.data());
|
|
128
|
+
if (it == r.end() || it->second.host_ok) return;
|
|
129
|
+
if (debug()) std::fprintf(stderr, "cu: download %p %zu bytes (span %zu)\n", (const void*)v.data(), it->second.bytes, v.size() * sizeof(*v.data()));
|
|
130
|
+
check(cudaMemcpy((void*)v.data(), it->second.d, it->second.bytes, cudaMemcpyDeviceToHost),
|
|
131
|
+
"download");
|
|
132
|
+
it->second.host_ok = true;
|
|
133
|
+
}
|
|
134
|
+
template <class V>
|
|
135
|
+
inline typename std::enable_if<!is_array<V>::value>::type need_host(const V&) {}
|
|
136
|
+
|
|
137
|
+
template <class V>
|
|
138
|
+
inline typename std::enable_if<is_array<V>::value>::type wrote_host(V& v) {
|
|
139
|
+
auto& r = registry();
|
|
140
|
+
auto it = r.find((const void*)v.data());
|
|
141
|
+
if (it == r.end()) return;
|
|
142
|
+
it->second.dev_ok = false;
|
|
143
|
+
it->second.host_ok = true;
|
|
144
|
+
}
|
|
145
|
+
template <class V>
|
|
146
|
+
inline typename std::enable_if<!is_array<V>::value>::type wrote_host(const V&) {}
|
|
147
|
+
|
|
148
|
+
template <class V>
|
|
149
|
+
inline void fresh(V& v) {
|
|
150
|
+
auto& r = registry();
|
|
151
|
+
auto it = r.find((const void*)v.data());
|
|
152
|
+
if (it == r.end()) return;
|
|
153
|
+
cudaFree(it->second.d);
|
|
154
|
+
r.erase(it);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Every mirror goes, nothing copied back: the end of one extern "C" call,
|
|
158
|
+
// after the wrapper has called need_host on the caller's own arrays (the
|
|
159
|
+
// other mirrors belong to arrays that no longer exist, and copying into
|
|
160
|
+
// them would write freed memory).
|
|
161
|
+
inline void end_call() {
|
|
162
|
+
auto& r = registry();
|
|
163
|
+
for (auto& kv : r) cudaFree(kv.second.d);
|
|
164
|
+
r.clear();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// The sums the kernels' reductions add into: K doubles on the device,
|
|
168
|
+
// zeroed before a launch and read back after it.
|
|
169
|
+
inline double* reduction_slots(int k) {
|
|
170
|
+
static double* d = nullptr;
|
|
171
|
+
static int cap = 0;
|
|
172
|
+
if (k > cap) {
|
|
173
|
+
if (d) cudaFree(d);
|
|
174
|
+
check(cudaMalloc(&d, k * sizeof(double)), "cudaMalloc reduction");
|
|
175
|
+
cap = k;
|
|
176
|
+
}
|
|
177
|
+
check(cudaMemset(d, 0, k * sizeof(double)), "cudaMemset reduction");
|
|
178
|
+
return d;
|
|
179
|
+
}
|
|
180
|
+
inline double reduction_value(const double* d, int i) {
|
|
181
|
+
double v;
|
|
182
|
+
check(cudaMemcpy(&v, d + i, sizeof(double), cudaMemcpyDeviceToHost), "reduction read");
|
|
183
|
+
return v;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// The reductions' atomic sum: the hardware's on sm_60 and later, a
|
|
187
|
+
// compare-and-swap loop before that (nvcc's default target is older).
|
|
188
|
+
__device__ inline double atomic_add(double* a, double v) {
|
|
189
|
+
#if !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 600
|
|
190
|
+
return atomicAdd(a, v);
|
|
191
|
+
#else
|
|
192
|
+
unsigned long long* p = (unsigned long long*)a;
|
|
193
|
+
unsigned long long old = *p, assumed;
|
|
194
|
+
do {
|
|
195
|
+
assumed = old;
|
|
196
|
+
old = atomicCAS(p, assumed, __double_as_longlong(v + __longlong_as_double(assumed)));
|
|
197
|
+
} while (assumed != old);
|
|
198
|
+
return __longlong_as_double(old);
|
|
199
|
+
#endif
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
inline void launched(const char* what) {
|
|
203
|
+
check(cudaGetLastError(), what);
|
|
204
|
+
if (debug()) {
|
|
205
|
+
check(cudaDeviceSynchronize(), what);
|
|
206
|
+
std::fprintf(stderr, "cu: ran %s\n", what);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Below this many iterations a parallel loop runs on the host (the launch
|
|
211
|
+
// and the transfer it may force cost more than the loop); SCM2CPP_CUDA_MIN
|
|
212
|
+
// overrides it.
|
|
213
|
+
inline long min_trip() {
|
|
214
|
+
static long m = -1;
|
|
215
|
+
if (m < 0) {
|
|
216
|
+
const char* s = std::getenv("SCM2CPP_CUDA_MIN");
|
|
217
|
+
m = s ? std::atol(s) : 4096;
|
|
218
|
+
}
|
|
219
|
+
return m;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// The products, on device arrays: the same signatures as the cblas back
|
|
223
|
+
// end (scm2cpp-blas.hpp), every operand through dev(), the result marked.
|
|
224
|
+
template <class Y, class A, class B>
|
|
225
|
+
inline void blas_gemm(Y& y, A& a, B& b, double alpha, double beta, int ta, int tb, int m,
|
|
226
|
+
int n, int k) {
|
|
227
|
+
double* dy = beta != 0.0 ? dev(y) : (wrote_dev(y), (double*)entry(y).d);
|
|
228
|
+
check_blas(cublasDgemm(handle(), tb ? CUBLAS_OP_T : CUBLAS_OP_N, ta ? CUBLAS_OP_T : CUBLAS_OP_N,
|
|
229
|
+
n, m, k, &alpha, dev(b), tb ? k : n, dev(a), ta ? m : k, &beta, dy, n),
|
|
230
|
+
"cublasDgemm");
|
|
231
|
+
wrote_dev(y);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
template <class Y, class A, class B>
|
|
235
|
+
inline void blas_gemm_batched(Y& y, A& a, B& b, double alpha, double beta, int ta, int tb,
|
|
236
|
+
int m, int n, int k, int batch) {
|
|
237
|
+
double* dy = beta != 0.0 ? dev(y) : (wrote_dev(y), (double*)entry(y).d);
|
|
238
|
+
check_blas(cublasDgemmStridedBatched(
|
|
239
|
+
handle(), tb ? CUBLAS_OP_T : CUBLAS_OP_N, ta ? CUBLAS_OP_T : CUBLAS_OP_N, n, m,
|
|
240
|
+
k, &alpha, dev(b), tb ? k : n, (long long)k * n, dev(a), ta ? m : k,
|
|
241
|
+
(long long)m * k, &beta, dy, n, (long long)m * n, batch),
|
|
242
|
+
"cublasDgemmStridedBatched");
|
|
243
|
+
wrote_dev(y);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
template <class Y, class A, class V>
|
|
247
|
+
inline void blas_gemv(Y& y, A& a, V& v, double alpha, double beta, int ta, int m, int k) {
|
|
248
|
+
double* dy = beta != 0.0 ? dev(y) : (wrote_dev(y), (double*)entry(y).d);
|
|
249
|
+
if (ta)
|
|
250
|
+
check_blas(cublasDgemv(handle(), CUBLAS_OP_N, m, k, &alpha, dev(a), m, dev(v), 1, &beta, dy,
|
|
251
|
+
1),
|
|
252
|
+
"cublasDgemv");
|
|
253
|
+
else
|
|
254
|
+
check_blas(cublasDgemv(handle(), CUBLAS_OP_T, k, m, &alpha, dev(a), k, dev(v), 1, &beta, dy,
|
|
255
|
+
1),
|
|
256
|
+
"cublasDgemv");
|
|
257
|
+
wrote_dev(y);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// the row-major upper triangle from the lower one dsyrk wrote (a template
|
|
261
|
+
// so that the header may be included from several translation units)
|
|
262
|
+
template <int = 0>
|
|
263
|
+
__global__ void mirror_upper(double* y, int m) {
|
|
264
|
+
int i = blockIdx.y, j = blockIdx.x * blockDim.x + threadIdx.x;
|
|
265
|
+
if (j < m && j > i) y[i * m + j] = y[j * m + i];
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// y (m x m) = alpha op(a) op(a)^T + beta y: dsyrk fills one triangle of
|
|
269
|
+
// the column-major reading, a kernel mirrors it, all on the device.
|
|
270
|
+
template <class Y, class A>
|
|
271
|
+
inline void blas_syrk(Y& y, A& a, double alpha, double beta, int ta, int m, int k) {
|
|
272
|
+
double* dy = beta != 0.0 ? dev(y) : (wrote_dev(y), (double*)entry(y).d);
|
|
273
|
+
check_blas(cublasDsyrk(handle(), CUBLAS_FILL_MODE_UPPER, ta ? CUBLAS_OP_N : CUBLAS_OP_T, m, k,
|
|
274
|
+
&alpha, dev(a), ta ? m : k, &beta, dy, m),
|
|
275
|
+
"cublasDsyrk");
|
|
276
|
+
dim3 grid((m + 255) / 256, m);
|
|
277
|
+
mirror_upper<<<grid, 256>>>(dy, m);
|
|
278
|
+
launched("mirror_upper");
|
|
279
|
+
wrote_dev(y);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
} // namespace cu
|
|
283
|
+
} // namespace scm2cpp
|
|
284
|
+
|
|
285
|
+
#endif
|