From 445cc63152303d50eb7a95ba20ae965fb0cac0d4 Mon Sep 17 00:00:00 2001 From: MincoMK Date: Sat, 3 May 2025 17:37:22 +0900 Subject: [PATCH] Add initial project files including CMake configuration, Python extractor, and CUDA implementation --- .gitignore | 3 + .vscode/c_cpp_properties.json | 22 +++++ .vscode/settings.json | 5 ++ CMakeLists.txt | 15 ++++ python/extractor.py | 28 ++++++ report.md | 70 +++++++++++++++ src/main.cu | 162 ++++++++++++++++++++++++++++++++++ 7 files changed, 305 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/settings.json create mode 100644 CMakeLists.txt create mode 100644 python/extractor.py create mode 100644 report.md create mode 100644 src/main.cu diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..51ce0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +build +output.txt +data \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..48ea2f3 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,22 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "windowsSdkVersion": "10.0.22621.0", + "compilerPath": "cl.exe", + "cStandard": "c17", + "cppStandard": "c++17", + "intelliSenseMode": "windows-msvc-x64", + "configurationProvider": "ms-vscode.cmake-tools" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..57c2030 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "algorithm": "cpp" + } +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..1455752 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.10) +project(MyCUDAProject LANGUAGES CXX CUDA) + +# add_compile_options("$<$:/source-charset:utf-8 /execution-charset:utf-8>") +set(CMAKE_CXX_STANDARD 17) + +set(SOURCES + src/main.cu +) + +add_executable(my_cuda_app ${SOURCES}) + +set_target_properties(my_cuda_app PROPERTIES + CUDA_ARCHITECTURES 89 +) diff --git a/python/extractor.py b/python/extractor.py new file mode 100644 index 0000000..188fb8b --- /dev/null +++ b/python/extractor.py @@ -0,0 +1,28 @@ +input_path = "../data/structures_end_ac.txt" +cities_output_path = "../data/cities.txt" +stronghold_output_path = "../data/strongholds.txt" + +import csv +import os + +def extract_structure_data(input_path): + cities = [] + strongholds = [] + with open(input_path, 'r') as file: + reader = csv.reader(file, delimiter=';') + for row in reader: + if len(row) > 1 and (row[1] == 'ancient_city'): + cities.append((row[2], row[3])) + if len(row) > 1 and (row[1] == 'stronghold'): + strongholds.append((row[2], row[3])) + + return cities, strongholds + +def write_to_file(data, output_path): + with open(output_path, 'w') as file: + for item in data: + file.write(f"{item[0]} 100 {item[1]}\n") + +cities, strongholds = extract_structure_data(input_path) +write_to_file(cities, cities_output_path) +write_to_file(strongholds, stronghold_output_path) \ No newline at end of file diff --git a/report.md b/report.md new file mode 100644 index 0000000..401d00e --- /dev/null +++ b/report.md @@ -0,0 +1,70 @@ +# 고대 도시 + 엔드 근접점 탐색 + +## 데이터 + +- 수집 범위: `AABB (-50000 -50000) (50000 50000)` +- 수집 대상: `minecraft:stronghold`, `minecraft:ancient_city` + +## 실험 환경 + +- CUDA 12.8 GPU 가속 +- 3차원 좌표 데이터 2쌍 -> Grid Search에 적합 +- y좌표 무시 필요성 있음 + +## 실험 결과 + +- 실험 시간: 183.18ms + |`minecraft:ancient_city (x, z)`|`minecraft:stronghold (x, z)`|`distance (blocks)`| + |---|---|---| + |2880, 7040|2900, 6996|48.3322| + |-736, 1600|-812, 1492|132.061| + |-320, -13648|-364, -13804|162.086| + |-20160, 80|-19980, 52|182.165| + |-20176, -3424|-20380, -3468|208.691| + |-19408, -6768|-19420, -6988|220.327| + |10464, 17488|10244, 17652|274.401| + |-15632, -12848|-15388, -12716|277.417| + |-19760, -160|-19980, 52|305.522| + |10560, 17712|10244, 17652|321.646| + |20064, -3376|20068, -3724|348.023| + |-20288, -144|-19980, 52|365.075| + |-6752, 5616|-6412, 5764|370.815| + |-14112, -688|-13772, -844|374.08| + |-14592, 3280|-14300, 3524|380.526| + |8832, 6704|8644, 6372|381.534| + |-1696, -16384|-1420, -16668|396.02| + |9040, 6352|8644, 6372|396.505| + |-19040, -7120|-19420, -6988|402.274| + |-5728, -656|-5356, -844|416.807| + |-7840, 208|-7884, 628|422.298| + |2800, -17648|2628, -17260|424.415| + |-20224, 416|-19980, 52|438.215| + |-14592, 3872|-14300, 3524|454.277| + |2400, -16864|2628, -17260|456.946| + |3952, 19632|3508, 19796|473.32| + |496, 19664|148, 19988|475.479| + |-544, -23648|-764, -23212|488.361| + |-272, -20576|-124, -21052|498.478| + |2160, -17088|2628, -17260|498.606| + |-720, 992|-812, 1492|508.394| + |-19440, 3616|-19948, 3636|508.394| + |-10656, 4736|-10284, 4388|509.4| + |2800, 7504|2900, 6996|517.749| + |-7664, 7440|-7308, 7828|526.574| + |17904, -9952|17908, -10508|556.014| + |-20544, 0|-19980, 52|566.392| + |10608, 18096|10244, 17652|574.136| + |-18000, 1536|-17468, 1300|581.997| + |-20960, -3360|-20380, -3468|589.969| + |-720, -20960|-124, -21052|603.059| + |-14896, 3680|-14300, 3524|616.078| + |-18816, -6864|-19420, -6988|616.597| + |-14400, -768|-13772, -844|632.582| + |-19808, -6480|-19420, -6988|639.225| + |16160, 12848|15556, 13060|640.125| + |2096, -17632|2628, -17260|649.159| + |-19424, -304|-19980, 52|660.206| + |-14432, -912|-13772, -844|663.494| + |-640, -21488|-124, -21052|675.538| + |13840, -5632|13172, -5500|680.917| + |16240, 13056|15556, 13060|684.012| diff --git a/src/main.cu b/src/main.cu new file mode 100644 index 0000000..a6a7ad2 --- /dev/null +++ b/src/main.cu @@ -0,0 +1,162 @@ +#include +#include +#include +#include +#include +#include +#include + +__global__ void find_nearest_B( + const float3 *__restrict__ A, + const float3 *__restrict__ B, + int *nearest_idx, + int N, int M) +{ + int idx = blockDim.x * blockIdx.x + threadIdx.x; + if (idx >= N) + return; + + float3 a = A[idx]; + float min_dist = 1e30f; + int min_j = -1; + + for (int j = 0; j < M; ++j) + { + float dx = a.x - B[j].x; + float dy = a.y - B[j].y; + float dz = a.z - B[j].z; + float dist = dx * dx + dy * dy + dz * dz; + + if (dist < min_dist) + { + min_dist = dist; + min_j = j; + } + } + + nearest_idx[idx] = min_j; +} + +std::vector load_coords_from_file(const std::string &filename) +{ + std::vector coords; + std::ifstream file(filename); + if (!file) + { + std::cerr << "Unable to open file: " << filename << std::endl; + return coords; + } + + std::string line; + while (std::getline(file, line)) + { + std::istringstream iss(line); + float x, y, z; + if (iss >> x >> y >> z) + { + coords.push_back(make_float3(x, y, z)); + } + } + + return coords; +} + +void save_results_sorted(const std::string &filename, + const std::vector &h_A, + const std::vector &h_B, + const std::vector &indices) +{ + struct Entry + { + float ax, az; + float bx, bz; + float dist; + }; + + std::vector entries; + + for (size_t i = 0; i < indices.size(); ++i) + { + float3 a = h_A[i]; + float3 b = h_B[indices[i]]; + + float dx = a.x - b.x; + float dy = a.y - b.y; + float dz = a.z - b.z; + float dist = sqrtf(dx * dx + dy * dy + dz * dz); + + entries.push_back({a.x, a.z, b.x, b.z, dist}); + } + + std::sort(entries.begin(), entries.end(), [](const Entry &e1, const Entry &e2) + { return e1.dist < e2.dist; }); + + std::ofstream file(filename); + for (const auto &e : entries) + { + file << e.ax << " " << e.az << " " + << e.bx << " " << e.bz << " " + << e.dist << std::endl; + } +} + +int main() +{ + auto t_start = std::chrono::high_resolution_clock::now(); + + std::vector h_A = load_coords_from_file("data/cities.txt"); + std::vector h_B = load_coords_from_file("data/strongholds.txt"); + + int N = h_A.size(); + int M = h_B.size(); + + if (N == 0 || M == 0) + { + std::cerr << "Coords empty." << std::endl; + return 1; + } + + float3 *d_A; + float3 *d_B; + int *d_nearest_idx; + cudaMalloc(&d_A, sizeof(float3) * N); + cudaMalloc(&d_B, sizeof(float3) * M); + cudaMalloc(&d_nearest_idx, sizeof(int) * N); + + cudaMemcpy(d_A, h_A.data(), sizeof(float3) * N, cudaMemcpyHostToDevice); + cudaMemcpy(d_B, h_B.data(), sizeof(float3) * M, cudaMemcpyHostToDevice); + + int threads = 256; + int blocks = (N + threads - 1) / threads; + + // ✅ CUDA 커널 시간 측정 시작 + cudaEvent_t start, stop; + cudaEventCreate(&start); + cudaEventCreate(&stop); + cudaEventRecord(start); + + find_nearest_B<<>>(d_A, d_B, d_nearest_idx, N, M); + + cudaEventRecord(stop); + cudaEventSynchronize(stop); + float milliseconds = 0; + cudaEventElapsedTime(&milliseconds, start, stop); + std::cout << "CUDA kernel time: " << milliseconds << " ms" << std::endl; + + std::vector h_nearest_idx(N); + cudaMemcpy(h_nearest_idx.data(), d_nearest_idx, sizeof(int) * N, cudaMemcpyDeviceToHost); + + save_results_sorted("output.txt", h_A, h_B, h_nearest_idx); + + cudaFree(d_A); + cudaFree(d_B); + cudaFree(d_nearest_idx); + + auto t_end = std::chrono::high_resolution_clock::now(); + std::chrono::duration elapsed = t_end - t_start; + std::cout << "Total time: " << elapsed.count() * 1000.0 << " ms" << std::endl; + + std::cout << "Saved to output.txt." << std::endl; + + return 0; +}