renaming
This commit is contained in:
0
5/data science/1e/.Rhistory
Normal file
0
5/data science/1e/.Rhistory
Normal file
29
5/data science/1e/Makefile
Normal file
29
5/data science/1e/Makefile
Normal file
@ -0,0 +1,29 @@
|
||||
CC = nvcc -arch=sm_75
|
||||
DEBUG ?= false
|
||||
DIRS = dist build
|
||||
|
||||
ifeq ($(DEBUG), false)
|
||||
CC += -O3
|
||||
else
|
||||
CC += -g -G
|
||||
endif
|
||||
|
||||
.PHONY: all run
|
||||
|
||||
all: $(DIRS) dist/app
|
||||
|
||||
dist/app: build/main.o build/op.o
|
||||
$(CC) $^ -o $@ -lcuda
|
||||
|
||||
build/op.o: op.ptx
|
||||
$(CC) $^ -dc -o $@
|
||||
|
||||
build/main.o: main.cu
|
||||
$(CC) $^ -ptx -o build/main.ptx
|
||||
$(CC) $^ -rdc=true -dc -o $@
|
||||
|
||||
$(DIRS):
|
||||
mkdir -p $@
|
||||
|
||||
clean:
|
||||
rm -rf $(DIRS)
|
||||
23
5/data science/1e/README.md
Normal file
23
5/data science/1e/README.md
Normal file
@ -0,0 +1,23 @@
|
||||
[euclidean](https://web.archive.org/web/20230212044931/http://www-math.ucdenver.edu/~wcherowi/courses/m5410/exeucalg.html)
|
||||
[ecdsa1](https://sefiks.com/2018/02/16/elegant-signatures-with-elliptic-curve-cryptography/)
|
||||
[ecdsa2](https://learnmeabitcoin.com/technical/cryptography/elliptic-curve/ecdsa/)
|
||||
[ptx](https://philipfabianek.com/posts/cuda-ptx-introduction)
|
||||
|
||||
высокий приоритет
|
||||
|
||||
6, 7 State Spaces / Properties of State Spaces Ключевое отличие от CPU! В CPU память в основном плоская (RAM, кэш). В GPU есть много типов памяти: глобальная (.global), общая для блока потоков (.shared), константная (.const), локальная (.local) и т.д. Это фундамент для написания производительного кода.
|
||||
19 Cost Estimates for Accessing State-Spaces Прямое продолжение предыдущего пункта. Объясняет, какая память быстрая, а какая медленная. Критично для оптимизации.
|
||||
4 Operator Precedence Синтаксис PTX похож на ассемблер, но с выражениями. Знать приоритет операторов необходимо.
|
||||
8 Fundamental Type Specifiers Типы данных в PTX (.b8, .s16, .f32, .b64 и т.д.). Аналог byte, word, dword в x86, но с учетом специфики GPU.
|
||||
3 Predefined Identifiers Предопределенные константы, такие как %tid, %ctaid, %ntid. Это основа модели выполнения CUDA! Вместо одного потока (RIP/EIP) у вас есть идентификаторы потока, блока и сетки.
|
||||
20 Operation Types Классификация инструкций PTX. Поможет быстро ориентироваться в мануале.
|
||||
1 PTX Directives Директивы ассемблера (.version, .target, .global). Аналог секций и директив в NASM (SECTION .text, global _start)
|
||||
|
||||
средний приоритет
|
||||
|
||||
21 Scopes Области видимости для атомарных операций и барьеров (.cta, .cluster, .gpu, .sys). Важно для синхронизации.
|
||||
14, 40, 56 Различные таблицы про Swizzling и Layout Касаются продвинутых техник работы с памятью и матрицами для оптимизации доступа. Актуально для low-level оптимизаций, похоже на работу с выравниванием и SIMD в x86.
|
||||
29 Summary of Floating-Point Instructions Обзор инструкций для чисел с плавающей точкой. На GPU они крайне важны.
|
||||
30-32 Cache Operators / Eviction Priority Hints Управление кэшем. Продвинутая тема для тонкой настройки, аналогичная prefetch-инструкциям в x86.
|
||||
53, 55, 56 Таблицы про MMA (Matrix Multiply-Accumulate) Инструкции для тензорных ядер (аналог FMA в x86, но для матриц). Сердце производительности в AI/HPC.
|
||||
22-25 Comparison Operators Особенности сравнений для целых и вещественных чисел (учет NaN).
|
||||
161
5/data science/1e/main.cu
Normal file
161
5/data science/1e/main.cu
Normal file
@ -0,0 +1,161 @@
|
||||
#include <stdint.h>
|
||||
|
||||
template <typename T, int TILE_SIZE>
|
||||
__global__ void mat_mul(T *A, T *B, T *C, int N, int M, int K) {
|
||||
__shared__ T sA[TILE_SIZE][TILE_SIZE];
|
||||
__shared__ T sB[TILE_SIZE][TILE_SIZE];
|
||||
|
||||
int bx = blockIdx.x, by = blockIdx.y;
|
||||
int tx = threadIdx.x, ty = threadIdx.y;
|
||||
|
||||
int row = by * TILE_SIZE + ty;
|
||||
int col = bx * TILE_SIZE + tx;
|
||||
|
||||
if (col >= K || row >= M) return;
|
||||
|
||||
T sum = 0;
|
||||
|
||||
int tiles_len = (M + TILE_SIZE - 1) / TILE_SIZE;
|
||||
|
||||
for (int tile = 0; tile < tiles_len; tile++) {
|
||||
int aCol = tile * TILE_SIZE + tx;
|
||||
int bRow = tile * TILE_SIZE + ty;
|
||||
|
||||
if (aCol < M) {
|
||||
sA[ty][tx] = A[row * M + aCol];
|
||||
} else {
|
||||
sA[ty][tx] = 0;
|
||||
}
|
||||
|
||||
sB[ty][tx] = (T)((uint64_t)B[bRow * K + col] & ((uint64_t)(bRow >= M) - 1));
|
||||
__syncthreads();
|
||||
|
||||
for (int k = 0; k < TILE_SIZE; k++) {
|
||||
sum += sA[ty][k] * sB[k][tx];
|
||||
}
|
||||
}
|
||||
|
||||
C[row * K + col] = sum;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
__global__ void dumb_mat_mul(T *A, T *B, T *C, int N, int M, int K) {
|
||||
int col = blockIdx.x * blockDim.x + threadIdx.x;
|
||||
int row = blockIdx.y * blockDim.y + threadIdx.y;
|
||||
|
||||
if (col >= K || row >= M) return;
|
||||
|
||||
T sum = 0;
|
||||
for (int i = 0; i < M; i++) {
|
||||
sum += A[row * M + i] * B[i * K + col];
|
||||
}
|
||||
C[row * K + col] = sum;
|
||||
}
|
||||
|
||||
#define N 1024
|
||||
#define M 1024
|
||||
#define K 1024
|
||||
#define NO_PRINT 1
|
||||
#define GRID_DIM 1
|
||||
#define BLOCK_DIM 32
|
||||
|
||||
#define MAT_TYPE int
|
||||
#define MAT_FMT "%d\t"
|
||||
#define A_LEN (N * M)
|
||||
#define B_LEN (M * K)
|
||||
#define C_LEN (N * K)
|
||||
#define A_SIZE (sizeof(MAT_TYPE) * N * M)
|
||||
#define B_SIZE (sizeof(MAT_TYPE) * M * K)
|
||||
#define C_SIZE (sizeof(MAT_TYPE) * N * K)
|
||||
|
||||
#include <cstdio>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
using namespace std::chrono;
|
||||
|
||||
template <typename T>
|
||||
void mat_print(T *a, const char *fmt, int n, int m) {
|
||||
for (auto row = 0; row < n; row++) {
|
||||
for (auto col = 0; col < m; col++) {
|
||||
printf(fmt, a[row * m + col]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::random_device rd;
|
||||
std::mt19937 engine(rd());
|
||||
std::uniform_int_distribution<MAT_TYPE> dist(1, 10);
|
||||
|
||||
auto buf = (MAT_TYPE *)malloc(A_SIZE + B_SIZE + C_SIZE);
|
||||
for (auto i = 0; i < A_LEN + B_LEN; i++) {
|
||||
buf[i] = dist(engine);
|
||||
}
|
||||
|
||||
MAT_TYPE *a = buf;
|
||||
MAT_TYPE *b = a + A_LEN;
|
||||
MAT_TYPE *c = b + B_LEN;
|
||||
|
||||
#if NO_PRINT==0
|
||||
printf("\na\n");
|
||||
mat_print(a, MAT_FMT, N, M);
|
||||
printf("\nb\n");
|
||||
mat_print(b, MAT_FMT, M, K);
|
||||
#endif
|
||||
|
||||
MAT_TYPE *d_a, *d_b, *d_c;
|
||||
cudaMalloc(&d_a, A_SIZE);
|
||||
cudaMalloc(&d_b, B_SIZE);
|
||||
cudaMalloc(&d_c, C_SIZE);
|
||||
|
||||
cudaMemcpy(d_a, a, A_SIZE, cudaMemcpyHostToDevice);
|
||||
cudaMemcpy(d_b, b, B_SIZE, cudaMemcpyHostToDevice);
|
||||
|
||||
dim3 gridDim(GRID_DIM, GRID_DIM);
|
||||
dim3 blockDim(BLOCK_DIM, BLOCK_DIM);
|
||||
|
||||
int cycles = 0;
|
||||
microseconds duration(0);
|
||||
|
||||
while (duration.count() < 1e6) {
|
||||
auto start = high_resolution_clock::now();
|
||||
mat_mul<MAT_TYPE, BLOCK_DIM><<<gridDim, blockDim>>>(d_a, d_b, d_c, N, M, K);
|
||||
cudaDeviceSynchronize();
|
||||
auto end = high_resolution_clock::now();
|
||||
|
||||
cycles++;
|
||||
duration += duration_cast<microseconds>(end - start);
|
||||
}
|
||||
|
||||
#if NO_PRINT==0
|
||||
cudaMemcpy(c, d_c, C_SIZE, cudaMemcpyDeviceToHost);
|
||||
printf("\nc\n");
|
||||
mat_print(c, MAT_FMT, N, K);
|
||||
#endif
|
||||
printf("optimized mul take %f usec avg in %d cycles\n", (float)(duration.count()) / cycles, cycles);
|
||||
|
||||
cycles = 0;
|
||||
duration = microseconds(0);
|
||||
while (duration.count() < 1e6) {
|
||||
auto start = high_resolution_clock::now();
|
||||
dumb_mat_mul<MAT_TYPE><<<gridDim, blockDim>>>(d_a, d_b, d_c, N, M, K);
|
||||
cudaDeviceSynchronize();
|
||||
auto end = high_resolution_clock::now();
|
||||
|
||||
cycles++;
|
||||
duration += duration_cast<microseconds>(end - start);
|
||||
}
|
||||
|
||||
#if NO_PRINT==0
|
||||
cudaMemcpy(c, d_c, C_SIZE, cudaMemcpyDeviceToHost);
|
||||
printf("\nc\n");
|
||||
mat_print(c, MAT_FMT, N, K);
|
||||
#endif
|
||||
printf("dumb mul take %f usec avg in %d cycles\n", (float)(duration.count()) / cycles, cycles);
|
||||
|
||||
cudaFree(a);
|
||||
cudaFree(b);
|
||||
cudaFree(c);
|
||||
free(buf);
|
||||
}
|
||||
27
5/data science/1e/main.py
Normal file
27
5/data science/1e/main.py
Normal file
@ -0,0 +1,27 @@
|
||||
import sys, time, math
|
||||
import numpy as np
|
||||
import cupy as cp
|
||||
|
||||
def measure(a, b):
|
||||
duration = 0
|
||||
cycles = 0
|
||||
while (duration < 1):
|
||||
start = time.perf_counter()
|
||||
c = a @ b
|
||||
cp.cuda.Stream.null.synchronize()
|
||||
end = time.perf_counter()
|
||||
|
||||
duration += end - start
|
||||
cycles += 1
|
||||
|
||||
return duration / cycles
|
||||
|
||||
n = 1024
|
||||
|
||||
a = np.random.rand(n, n).astype(np.float32)
|
||||
b = np.random.rand(n, n).astype(np.float32)
|
||||
print('numpy take', measure(a, b) * 1e6, 'usec')
|
||||
|
||||
a = cp.random.rand(n, n, dtype = cp.float32)
|
||||
b = cp.random.rand(n, n, dtype = cp.float32)
|
||||
print('cupy take', measure(a, b) * 1e6, 'usec')
|
||||
171
5/data science/1e/op.ptx
Normal file
171
5/data science/1e/op.ptx
Normal file
@ -0,0 +1,171 @@
|
||||
.version 8.4
|
||||
.target sm_75
|
||||
.address_size 64
|
||||
|
||||
.visible .func add_u16(
|
||||
.param .b64 out_c,
|
||||
.param .align 16 .b8 in_a[16],
|
||||
.param .align 16 .b8 in_b[16]
|
||||
) {
|
||||
.reg .u64 %ra<2>, %rb<2>;
|
||||
.reg .b64 %rdc;
|
||||
|
||||
ld.param.b64 %rdc, [out_c];
|
||||
|
||||
ld.param.v2.u64 {%ra1, %ra0}, [in_a];
|
||||
ld.param.v2.u64 {%rb1, %rb0}, [in_b];
|
||||
|
||||
add.cc.u64 %ra0, %ra0, %rb0;
|
||||
addc.u64 %ra1, %ra1, %rb1;
|
||||
|
||||
st.v2.u64 [%rdc], {%ra1, %ra0};
|
||||
|
||||
ret;
|
||||
}
|
||||
|
||||
.visible .func sub_u16(
|
||||
.param .b64 out_c,
|
||||
.param .align 16 .b8 in_a[16],
|
||||
.param .align 16 .b8 in_b[16]
|
||||
) {
|
||||
.reg .u64 %ra<2>, %rb<2>;
|
||||
.reg .b64 %rdc;
|
||||
|
||||
ld.param.b64 %rdc, [out_c];
|
||||
|
||||
ld.param.v2.u64 {%ra1, %ra0}, [in_a];
|
||||
ld.param.v2.u64 {%rb1, %rb0}, [in_b];
|
||||
|
||||
sub.cc.u64 %ra0, %ra0, %rb0;
|
||||
subc.u64 %ra1, %ra1, %rb1;
|
||||
|
||||
st.v2.u64 [%rdc], {%ra1, %ra0};
|
||||
|
||||
ret;
|
||||
}
|
||||
|
||||
.visible .func add_u32(
|
||||
.param .b64 out_c,
|
||||
.param .align 16 .b8 in_a[32],
|
||||
.param .align 16 .b8 in_b[32]
|
||||
) {
|
||||
.reg .u64 %ra<4>, %rb<4>;
|
||||
.reg .b64 %rdc;
|
||||
|
||||
ld.param.b64 %rdc, [out_c];
|
||||
|
||||
ld.param.v2.u64 {%ra3, %ra2}, [in_a];
|
||||
ld.param.v2.u64 {%ra1, %ra0}, [in_a + 16];
|
||||
ld.param.v2.u64 {%rb3, %rb2}, [in_b];
|
||||
ld.param.v2.u64 {%rb1, %rb0}, [in_b + 16];
|
||||
|
||||
add.cc.u64 %ra0, %ra0, %rb0;
|
||||
addc.cc.u64 %ra1, %ra1, %rb1;
|
||||
addc.cc.u64 %ra2, %ra2, %rb2;
|
||||
addc.u64 %ra3, %ra3, %rb3;
|
||||
|
||||
st.v2.u64 [%rdc], {%ra3, %ra2};
|
||||
st.v2.u64 [%rdc + 16], {%ra1, %ra0};
|
||||
|
||||
ret;
|
||||
}
|
||||
|
||||
.visible .func sub_u32(
|
||||
.param .b64 out_c,
|
||||
.param .align 16 .b8 in_a[32],
|
||||
.param .align 16 .b8 in_b[32]
|
||||
) {
|
||||
.reg .u64 %ra<4>, %rb<4>;
|
||||
.reg .b64 %rdc;
|
||||
|
||||
ld.param.b64 %rdc, [out_c];
|
||||
|
||||
ld.param.v2.u64 {%ra3, %ra2}, [in_a];
|
||||
ld.param.v2.u64 {%ra1, %ra0}, [in_a + 16];
|
||||
ld.param.v2.u64 {%rb3, %rb2}, [in_b];
|
||||
ld.param.v2.u64 {%rb1, %rb0}, [in_b + 16];
|
||||
|
||||
sub.cc.u64 %ra0, %ra0, %rb0;
|
||||
subc.cc.u64 %ra1, %ra1, %rb1;
|
||||
subc.cc.u64 %ra2, %ra2, %rb2;
|
||||
subc.u64 %ra3, %ra3, %rb3;
|
||||
|
||||
st.v2.u64 [%rdc], {%ra3, %ra2};
|
||||
st.v2.u64 [%rdc + 16], {%ra1, %ra0};
|
||||
|
||||
ret;
|
||||
}
|
||||
|
||||
.visible .func mul_lo_u16(
|
||||
.param .b64 out_c,
|
||||
.param .align 16 .b8 in_a[16],
|
||||
.param .align 16 .b8 in_b[16]
|
||||
) {
|
||||
.reg .u64 %a, %b, %c, %d, %a_b, %c_d;
|
||||
.reg .u64 %ac, %bd_hi, %bd_lo, %p;
|
||||
.reg .b64 %rdc;
|
||||
|
||||
ld.param.b64 %rdc, [out_c];
|
||||
|
||||
ld.param.v2.u64 {%a, %b}, [in_a];
|
||||
ld.param.v2.u64 {%c, %d}, [in_b];
|
||||
|
||||
mul.lo.u64 %ac, %a, %c;
|
||||
mul.lo.u64 %bd_lo, %b, %d;
|
||||
mul.hi.u64 %bd_hi, %b, %d;
|
||||
|
||||
add.u64 %a_b, %a, %b;
|
||||
add.u64 %c_d, %c, %d;
|
||||
|
||||
mul.lo.u64 %p, %a_b, %c_d;
|
||||
|
||||
sub.u64 %p, %p, %ac;
|
||||
sub.u64 %p, %p, %bd_lo;
|
||||
|
||||
add.u64 %p, %p, %bd_hi;
|
||||
|
||||
st.v2.u64 [%rdc], {%p, %bd_lo};
|
||||
|
||||
ret;
|
||||
}
|
||||
|
||||
.visible .func mul_u16(
|
||||
.param .b64 out_c_hi,
|
||||
.param .b64 out_c_lo,
|
||||
.param .align 16 .b8 in_a[16],
|
||||
.param .align 16 .b8 in_b[16]
|
||||
) {
|
||||
.reg .u64 %a, %b, %c, %d;
|
||||
.reg .u64 %a_b_hi, %a_b_lo, %c_d_hi, %c_d_lo;
|
||||
.reg .u64 %p_hi, %p_lo, %p_hi2, %p_lo2;
|
||||
.reg .u64 %ac_hi, %ac_lo, %bd_hi, %bd_lo;
|
||||
.reg .b64 %rdc_hi, %rdc_lo;
|
||||
|
||||
ld.param.b64 %rdc_hi, [out_c_hi];
|
||||
ld.param.b64 %rdc_lo, [out_c_lo];
|
||||
|
||||
ld.param.v2.u64 {%a, %b}, [in_a];
|
||||
ld.param.v2.u64 {%c, %d}, [in_b];
|
||||
|
||||
mul.lo.u64 %ac_lo, %a, %c;
|
||||
mul.hi.u64 %ac_hi, %a, %c;
|
||||
mul.lo.u64 %bd_lo, %b, %d;
|
||||
mul.hi.u64 %bd_hi, %b, %d;
|
||||
|
||||
add.cc.u64 %a_b_lo, %a, %b;
|
||||
addc.u64 %a_b_hi, %a, %b;
|
||||
add.cc.u64 %c_d_lo, %c, %d;
|
||||
addc.u64 %c_d_hi, %c, %d;
|
||||
|
||||
mul.lo.u64 %p_lo, %a_b_lo, %c_d_lo;
|
||||
mul.hi.u64 %p_hi, %a_b_lo, %c_d_lo;
|
||||
mul.lo.u64 %p_hi2, %a_b_hi, %c_d_hi;
|
||||
|
||||
|
||||
|
||||
|
||||
st.v2.u64 [%rdc_lo], {%p_hi, %p_lo};
|
||||
st.v2.u64 [%rdc_hi], {%a_b_lo, %p_hi2};
|
||||
|
||||
ret;
|
||||
}
|
||||
205
5/data science/1e/secp256k1.cu
Normal file
205
5/data science/1e/secp256k1.cu
Normal file
@ -0,0 +1,205 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" __device__ void add_u16(
|
||||
ulonglong2 *out_c,
|
||||
ulonglong2 in_a,
|
||||
ulonglong2 in_b
|
||||
);
|
||||
|
||||
extern "C" __device__ void sub_u16(
|
||||
ulonglong2 *out_c,
|
||||
ulonglong2 in_a,
|
||||
ulonglong2 in_b
|
||||
);
|
||||
|
||||
extern "C" __device__ void add_u32(
|
||||
ulonglong4 *out_c,
|
||||
ulonglong4 in_a,
|
||||
ulonglong4 in_b
|
||||
);
|
||||
|
||||
extern "C" __device__ void sub_u32(
|
||||
ulonglong4 *out_c,
|
||||
ulonglong4 in_a,
|
||||
ulonglong4 in_b
|
||||
);
|
||||
|
||||
extern "C" __device__ void mul_lo_u16(
|
||||
ulonglong2 *out_c,
|
||||
ulonglong2 in_a,
|
||||
ulonglong2 in_b
|
||||
);
|
||||
|
||||
extern "C" __device__ void mul_u16(
|
||||
ulonglong2 *out_c_hi,
|
||||
ulonglong2 *out_c_lo,
|
||||
ulonglong2 in_a,
|
||||
ulonglong2 in_b
|
||||
);
|
||||
|
||||
__device__ bool equ_u16(ulonglong2 a, ulonglong2 b) {
|
||||
return a.x == b.x && a.y == b.y;
|
||||
}
|
||||
|
||||
__device__ bool equ_u32(ulonglong4 a, ulonglong4 b) {
|
||||
return a.x == b.x &&
|
||||
a.y == b.y &&
|
||||
a.z == b.z &&
|
||||
a.w == b.w;
|
||||
}
|
||||
|
||||
__device__ int cmp_u32(ulonglong4 a, ulonglong4 b) {
|
||||
if (a.x < b.x)
|
||||
return -1;
|
||||
else if (a.x > b.x)
|
||||
return 1;
|
||||
|
||||
if (a.y < b.y)
|
||||
return -1;
|
||||
else if (a.y > b.y)
|
||||
return 1;
|
||||
|
||||
if (a.z < b.z)
|
||||
return -1;
|
||||
else if (a.z > b.z)
|
||||
return 1;
|
||||
|
||||
if (a.w < b.w)
|
||||
return -1;
|
||||
else if (a.w > b.w)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__device__ void mul_lo_u32(
|
||||
ulonglong4 *out_c,
|
||||
ulonglong4 in_a,
|
||||
ulonglong4 in_b
|
||||
) {
|
||||
auto a = (ulonglong2 *)&in_a.x;
|
||||
auto b = (ulonglong2 *)&in_a.z;
|
||||
auto c = (ulonglong2 *)&in_b.x;
|
||||
auto d = (ulonglong2 *)&in_b.z;
|
||||
ulonglong2 a_b, c_d, ac, bd_hi, bd_lo, p;
|
||||
|
||||
mul_lo_u16(&ac, *a, *c);
|
||||
mul_u16(&bd_hi, &bd_lo, *b, *d);
|
||||
|
||||
add_u16(&a_b, *a, *b);
|
||||
add_u16(&c_d, *c, *d);
|
||||
|
||||
mul_lo_u16(&p, a_b, c_d);
|
||||
|
||||
sub_u16(&p, p, ac);
|
||||
sub_u16(&p, p, bd_lo);
|
||||
add_u16(&p, p, bd_hi);
|
||||
|
||||
out_c->x = p.x;
|
||||
out_c->y = p.y;
|
||||
out_c->z = bd_lo.x;
|
||||
out_c->w = bd_lo.y;
|
||||
}
|
||||
|
||||
__device__ void print_u16(ulonglong2 a) {
|
||||
printf("0x%016llx.%016llx\n", a.x, a.y);
|
||||
}
|
||||
|
||||
__device__ void print_u32(ulonglong4 a) {
|
||||
printf("0x%016llx.%016llx.%016llx.%016llx\n", a.x, a.y, a.z, a.w);
|
||||
}
|
||||
|
||||
#define U8_MAX 0xFFFFFFFFFFFFFFFF
|
||||
#define U16_MAX {U8_MAX, U8_MAX}
|
||||
#define U32_MAX {U8_MAX, U8_MAX, U8_MAX, U8_MAX}
|
||||
|
||||
__global__ void test(bool *passed) {
|
||||
*passed = true;
|
||||
{
|
||||
ulonglong4 a = U32_MAX;
|
||||
ulonglong4 b = {0, 0, 0, 1};
|
||||
ulonglong4 c = {0, 0, 0, 0};
|
||||
add_u32(&a, a, b);
|
||||
if (!equ_u32(a, c)) {
|
||||
printf("add_u32\n");
|
||||
print_u32(a);
|
||||
*passed = false;
|
||||
}
|
||||
}
|
||||
{
|
||||
ulonglong4 a = {0, 0, 0, 0};
|
||||
ulonglong4 b = {0, 0, 0, 1};
|
||||
ulonglong4 c = U32_MAX;
|
||||
sub_u32(&a, a, b);
|
||||
if (!equ_u32(a, c)) {
|
||||
printf("sub_u32\n");
|
||||
print_u32(a);
|
||||
*passed = false;
|
||||
}
|
||||
}
|
||||
{
|
||||
ulonglong2 a = U16_MAX;
|
||||
ulonglong2 b = {0, U8_MAX};
|
||||
ulonglong2 c = {U8_MAX, 1};
|
||||
mul_lo_u16(&a, a, b);
|
||||
if (!equ_u16(a, c)) {
|
||||
printf("mul_lo_u16\n");
|
||||
print_u16(a);
|
||||
*passed = false;
|
||||
}
|
||||
}
|
||||
{
|
||||
ulonglong2 a = U16_MAX;
|
||||
ulonglong2 b = {0, U8_MAX};
|
||||
ulonglong2 c_hi = {0, U8_MAX - 1};
|
||||
ulonglong2 c_lo = {U8_MAX, 1};
|
||||
mul_u16(&a, &b, a, b);
|
||||
if (!equ_u16(a, c_hi) || !equ_u16(b, c_lo)) {
|
||||
printf("mul_u16\n");
|
||||
print_u16(a);
|
||||
print_u16(b);
|
||||
*passed = false;
|
||||
}
|
||||
a = U16_MAX;
|
||||
b = U16_MAX;
|
||||
c_hi = {U8_MAX, U8_MAX - 1};
|
||||
c_lo = {0, 1};
|
||||
mul_u16(&a, &b, a, b);
|
||||
if (!equ_u16(a, c_hi) || !equ_u16(b, c_lo)) {
|
||||
printf("mul_u16\n");
|
||||
print_u16(a);
|
||||
print_u16(b);
|
||||
*passed = false;
|
||||
}
|
||||
}
|
||||
{
|
||||
ulonglong4 a = U32_MAX;
|
||||
ulonglong4 b = {0, 0, U8_MAX, U8_MAX};
|
||||
ulonglong4 c = {U8_MAX, U8_MAX, 0, 1};
|
||||
mul_lo_u32(&a, a, b);
|
||||
if (!equ_u32(a, c)) {
|
||||
printf("mul_lo_u32\n");
|
||||
print_u32(a);
|
||||
*passed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
bool test_passed, *d_test_passed;
|
||||
cudaMalloc(&d_test_passed, sizeof(bool));
|
||||
|
||||
test<<<1, 1>>>(d_test_passed);
|
||||
cudaDeviceSynchronize();
|
||||
|
||||
cudaMemcpy(&test_passed, d_test_passed, sizeof(bool), cudaMemcpyDeviceToHost);
|
||||
cudaFree(d_test_passed);
|
||||
|
||||
if (!test_passed) {
|
||||
printf("test not passed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
22
5/data science/1e/test.py
Normal file
22
5/data science/1e/test.py
Normal file
@ -0,0 +1,22 @@
|
||||
U8_MAX = 0xFFFFFFFFFFFFFFFF
|
||||
U16_MAX = U8_MAX << 64 | U8_MAX
|
||||
U32_MAX = U16_MAX << 128 | U16_MAX
|
||||
|
||||
|
||||
def dothex(num):
|
||||
strhex = hex(num)[2:]
|
||||
dothex = strhex[-16:]
|
||||
strhex = strhex[:-16]
|
||||
|
||||
while len(strhex) > 0:
|
||||
dothex = strhex[-16:] + '.' + dothex
|
||||
strhex = strhex[:-16]
|
||||
|
||||
return '0x' + dothex
|
||||
|
||||
print('mul_u16', dothex((U16_MAX * U8_MAX >> 128) %
|
||||
(U16_MAX + 1)), dothex(U16_MAX * U8_MAX % (U16_MAX + 1)))
|
||||
print('mul_u16', dothex((U16_MAX * U16_MAX >> 128) %
|
||||
(U16_MAX + 1)), dothex(U16_MAX * U16_MAX % (U16_MAX + 1)))
|
||||
print('mul_lo_u32', dothex(U32_MAX * U16_MAX % (U32_MAX + 1)))
|
||||
print('div_lo_u32', dothex(U32_MAX // U8_MAX), dothex(U32_MAX - U32_MAX // U8_MAX))
|
||||
Reference in New Issue
Block a user