diff --git a/.gitignore b/.gitignore index 51ce0f9..f039c89 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -build -output.txt +build +output.txt data \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 57c2030..96b4aa5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ -{ - "files.associations": { - "algorithm": "cpp" - } +{ + "files.associations": { + "algorithm": "cpp" + } } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 1455752..47b2987 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +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 -) +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 index 188fb8b..d70cbc9 100644 --- a/python/extractor.py +++ b/python/extractor.py @@ -1,28 +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) +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 index 401d00e..73f8189 100644 --- a/report.md +++ b/report.md @@ -1,70 +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| +# 고대 도시 + 엔드 근접점 탐색 + +## 데이터 + +- 수집 범위: `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 index a6a7ad2..67bf979 100644 --- a/src/main.cu +++ b/src/main.cu @@ -1,162 +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; -} +#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; +}