diff --git a/README.md b/README.md index ee39093..6ef11d3 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,52 @@ **University of Pennsylvania, CIS 5650: GPU Programming and Architecture, Project 1 - Flocking** -* (TODO) YOUR NAME HERE - * (TODO) [LinkedIn](), [personal website](), [twitter](), etc. -* Tested on: (TODO) Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab) +* Jiahang Mao + * [LinkedIn](https://www.linkedin.com/in/jay-jiahang-m-b05608192/) +* Tested on: Windows 11, i5-13600kf @ 5.0GHz 64GB, RTX 4090 24GB, Personal Computer -### (TODO: Your README) +## Visual Results +5000 boids +![Boids Simulation](images/out.gif) -Include screenshots, analysis, etc. (Remember, this is public, so don't put -anything here that you don't want to share with the world.) + + +## Performance Results + +Performance testing config +* Avg FPS measured between 2 seconds and 7 seconds after program start, calculated as total_fps / total_duration +* run in Release model + +#### Visualization OFF + +| Method | Number of Boids | Block Size | Avg FPS | +|:-------- |:---------------:|:----------:|:-------:| +| Naive (baseline) | 5000 | 128 | 878 +| Naive | 5000 | 1024 | 603 +| Naive | 50000 | 128 | 135 +| Naive | 50000 | 1024 | 86 +| Uniform | 5000 | 128 | 1582 +| Uniform | 5000 | 1024 | 1617 +| Uniform | 50000 | 128 | 1279 +| Uniform | 50000 | 1024 | 1213 +| Coherent | 5000 | 128 | 1571 +| Coherent | 5000 | 1024 | 1555 +| Coherent | 50000 | 128 | 1027 +| Coherent | 50000 | 1024 | 1030 + +#### Visualization ON + +| Method | Number of Boids | Block Size | Avg FPS | +|:-------- |:---------------:|:----------:|:-------:| +| Naive (baseline) | 5000 | 128 | 715 +| Naive | 5000 | 1024 | 526 +| Naive | 50000 | 128 | 130 +| Naive | 50000 | 1024 | 84 +| Uniform | 5000 | 128 | 1226 +| Uniform | 5000 | 1024 | 1133 +| Uniform | 50000 | 128 | 961 +| Uniform | 50000 | 1024 | 880 +| Coherent | 5000 | 128 | 1042 +| Coherent | 5000 | 1024 | 1070 +| Coherent | 50000 | 128 | 764 +| Coherent | 50000 | 1024 | 773 diff --git a/images/out.gif b/images/out.gif new file mode 100644 index 0000000..050bca1 Binary files /dev/null and b/images/out.gif differ diff --git a/p3_writeup.md b/p3_writeup.md new file mode 100644 index 0000000..ebee2da --- /dev/null +++ b/p3_writeup.md @@ -0,0 +1,18 @@ + +## Part3 write-up +* For each implementation, how does changing the number of boids affect performance? Why do you think this is? + + As the number of boids increase, performance drop. Because more boids would require more frequent access to memory for accessing related position and velocity informatoin. Also once the number of boids exceed the maximum number of threads supported by hardware, we need more gpu cycles to run all boids. +* For each implementation, how does changing the block count and block size affect performance? Why do you think this is? + + According to my experiments. Increasing the block count causes worse performance in naive implementation ( 25% less fps). While for uniform and coherent grids it barely has any impact on performance.
+ For naive implementation, i think it was because more branches occured inside one block, causing wasted cycles. + For coherent and uniform grid, the branching is minizied since the number of neighbours to check decreased on each thread. + +* For the coherent uniform grid: did you experience any performance improvements with the more coherent uniform grid? Was this the outcome you expected? Why or why not? + + I saw slightly worse performance with coherent uniform grids. Maybe my implementation is faulty. I suspect the additional sorting required more time, and the memory coherency isn't utilized to local SM cache partitions + +* Did changing cell width and checking 27 vs 8 neighboring cells affect performance? Why or why not? Be careful: it is insufficient (and possibly incorrect) to say that 27-cell is slower simply because there are more cells to check! + + I observed checking 27 performs better than 8 about 2-3% with both uniform and coherent grids. I suppose because the total volume to check is smaller with 27, since 27 means checking 3^3 unit volumes while there is a chance that 8 end up checking (2*2)^3 unit volumes. But the difference is marginal. \ No newline at end of file diff --git a/src/kernel.cu b/src/kernel.cu index 74dffcb..01da43e 100644 --- a/src/kernel.cu +++ b/src/kernel.cu @@ -79,6 +79,8 @@ int *dev_particleGridIndices; // What grid cell is this particle in? // needed for use with thrust thrust::device_ptr dev_thrust_particleArrayIndices; thrust::device_ptr dev_thrust_particleGridIndices; +thrust::device_ptr dev_thrust_particlePosIndices; +thrust::device_ptr dev_thrust_particleVelIndices; int *dev_gridCellStartIndices; // What part of dev_particleArrayIndices belongs int *dev_gridCellEndIndices; // to this cell? @@ -88,6 +90,7 @@ int *dev_gridCellEndIndices; // to this cell? // LOOK-2.1 - Grid parameters based on simulation parameters. // These are automatically computed for you in Boids::initSimulation +float maxRuleDistance; int gridCellCount; int gridSideCount; float gridCellWidth; @@ -157,7 +160,8 @@ void Boids::initSimulation(int N) { checkCUDAErrorWithLine("kernGenerateRandomPosArray failed!"); // LOOK-2.1 computing grid params - gridCellWidth = 2.0f * std::max(std::max(rule1Distance, rule2Distance), rule3Distance); + maxRuleDistance = std::max(std::max(rule1Distance, rule2Distance), rule3Distance); + gridCellWidth = 2.0f * maxRuleDistance; // each cell is twice the size of maxRuleDistance int halfSideCount = (int)(scene_scale / gridCellWidth) + 1; gridSideCount = 2 * halfSideCount; @@ -170,6 +174,34 @@ void Boids::initSimulation(int N) { // TODO-2.1 TODO-2.3 - Allocate additional buffers here. cudaDeviceSynchronize(); + cudaMalloc((void**)&dev_particleArrayIndices, N * sizeof(int)); + checkCUDAErrorWithLine("cudaMalloc dev_particleArrayIndices failed!"); + cudaMalloc((void**)&dev_particleGridIndices, N * sizeof(int)); + checkCUDAErrorWithLine("cudaMalloc dev_particleGridIndices failed!"); + cudaMalloc((void**)&dev_gridCellStartIndices, gridCellCount * sizeof(int)); + checkCUDAErrorWithLine("cudaMalloc dev_gridCellStartIndices failed!"); + cudaMalloc((void**)&dev_gridCellEndIndices, gridCellCount * sizeof(int)); + checkCUDAErrorWithLine("cudaMalloc dev_gridCellEndIndices failed!"); + + // // set boid indices + // kernComputeIndices<<>> + // (N, gridSideCount, gridMinimum, gridInverseCellWidth, + // dev_pos, dev_particleArrayIndices, dev_particleGridIndices); + + // // sort boid indices by grid index, in place + // dev_thrust_particleArrayIndices = thrust::device_pointer_cast(dev_particleArrayIndices); + // dev_thrust_particleGridIndices = thrust::device_pointer_cast(dev_particleGridIndices); + // thrust::sort_by_key(dev_particleGridIndices, dev_particleGridIndices + N, dev_thrust_particleArrayIndices); + + // // set grid cell start and end indices to -1, indicating no boids in the cell + // cudaMemset(dev_gridCellStartIndices, -1, gridCellCount * sizeof(int)); + // checkCUDAErrorWithLine("cudaMemset dev_gridCellStartIndices failed!"); + // cudaMemset(dev_gridCellEndIndices, -1, gridCellCount * sizeof(int)); + // checkCUDAErrorWithLine("cudaMemset dev_gridCellEndIndices failed!"); + + // // identify cell start and end indices + // kernIdentifyCellStartEnd<<>> + // (N, dev_particleGridIndices, dev_gridCellStartIndices, dev_gridCellEndIndices); } @@ -233,7 +265,38 @@ __device__ glm::vec3 computeVelocityChange(int N, int iSelf, const glm::vec3 *po // Rule 1: boids fly towards their local perceived center of mass, which excludes themselves // Rule 2: boids try to stay a distance d away from each other // Rule 3: boids try to match the speed of surrounding boids - return glm::vec3(0.0f, 0.0f, 0.0f); + glm::vec3 perceived_center(0.0f, 0.0f, 0.0f); + glm::vec3 neightbour_distance(0.0f, 0.0f, 0.0f); + glm::vec3 perceived_velocity(0.0f, 0.0f, 0.0f); + int rule_1_count = 0; + int rule_3_count = 0; + for (int i = 0 ; i 0){ + perceived_center /= rule_1_count; + new_velocity += (perceived_center - pos[iSelf]) * rule1Scale; + } + if (rule_3_count > 0){ + perceived_velocity /= rule_3_count; + new_velocity += perceived_velocity * rule3Scale; + } + new_velocity += neightbour_distance * rule2Scale; + return new_velocity; } /** @@ -245,6 +308,22 @@ __global__ void kernUpdateVelocityBruteForce(int N, glm::vec3 *pos, // Compute a new velocity based on pos and vel1 // Clamp the speed // Record the new velocity into vel2. Question: why NOT vel1? + int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (index >= N) { + return; + } + + glm::vec3 velocityChange = computeVelocityChange(N, index, pos, vel1); + + glm::vec3 newVelocity = vel1[index] + velocityChange; + + // Clamp the speed + float speed = glm::length(newVelocity); + if (speed > maxSpeed) { + newVelocity = (newVelocity / speed) * maxSpeed; + } + + vel2[index] = newVelocity; } /** @@ -289,6 +368,17 @@ __global__ void kernComputeIndices(int N, int gridResolution, // - Label each boid with the index of its grid cell. // - Set up a parallel array of integer indices as pointers to the actual // boid data in pos and vel1/vel2 + // write to indices and gridIndices + int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (index >= N) { + return; + } + indices[index] = index; + + glm::vec3 curr_gird_index_3d= (pos[index] - gridMin) * inverseCellWidth; + int curr_grid_index = gridIndex3Dto1D(curr_gird_index_3d.x, curr_gird_index_3d.y, curr_gird_index_3d.z, gridResolution); + gridIndices[index] = curr_grid_index; + } // LOOK-2.1 Consider how this could be useful for indicating that a cell @@ -306,11 +396,32 @@ __global__ void kernIdentifyCellStartEnd(int N, int *particleGridIndices, // Identify the start point of each cell in the gridIndices array. // This is basically a parallel unrolling of a loop that goes // "this index doesn't match the one before it, must be a new cell!" + + // Only search to index + 1, not before. If find boundary then set both gridIndices + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if (index >= N) { + return; + } + + if (index == 0){ + gridCellStartIndices[particleGridIndices[0]] = 0; + } + if (index == N - 1){ + gridCellEndIndices[particleGridIndices[N - 1]] = N - 1; + return; + } + + int this_grid = particleGridIndices[index]; + int next_grid = particleGridIndices[index + 1]; + if (this_grid != next_grid){ + gridCellStartIndices[next_grid] = index + 1; + gridCellEndIndices[this_grid] = index; + } } __global__ void kernUpdateVelNeighborSearchScattered( int N, int gridResolution, glm::vec3 gridMin, - float inverseCellWidth, float cellWidth, + float inverseCellWidth, float cellWidth, float maxRuleDistance, int *gridCellStartIndices, int *gridCellEndIndices, int *particleArrayIndices, glm::vec3 *pos, glm::vec3 *vel1, glm::vec3 *vel2) { @@ -322,11 +433,76 @@ __global__ void kernUpdateVelNeighborSearchScattered( // - Access each boid in the cell and compute velocity change from // the boids rules, if this boid is within the neighborhood distance. // - Clamp the speed change before putting the new speed in vel2 + int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (index >= N) { + return; + } + glm::vec3 grid_to_search_start = (pos[index] - maxRuleDistance - gridMin) * inverseCellWidth; + glm::vec3 grid_to_search_end = (pos[index] + maxRuleDistance - gridMin) * inverseCellWidth; + // clamp to 0 and girdResolution + glm::vec3 grid_index_min = glm::vec3(0, 0, 0); + glm::vec3 grid_index_max = glm::vec3(gridResolution - 1, gridResolution - 1, gridResolution - 1); + grid_to_search_start = glm::clamp(grid_to_search_start, grid_index_min, grid_index_max); + grid_to_search_end = glm::clamp(grid_to_search_end, grid_index_min, grid_index_max); + + // next, search the valid grid cells and do original boid search + glm::vec3 perceived_center(0.0f, 0.0f, 0.0f); + glm::vec3 neightbour_distance(0.0f, 0.0f, 0.0f); + glm::vec3 perceived_velocity(0.0f, 0.0f, 0.0f); + int rule_1_count = 0; + int rule_3_count = 0; + for(int g_x = grid_to_search_start.x; g_x <= grid_to_search_end.x; g_x++){ + for(int g_y = grid_to_search_start.y; g_y <= grid_to_search_end.y; g_y++){ + for(int g_z = grid_to_search_start.z; g_z <= grid_to_search_end.z; g_z++){ + int curr_grid_index = gridIndex3Dto1D(g_x, g_y, g_z, gridResolution); + if (gridCellStartIndices[curr_grid_index] == -1){ + continue; + } + for(int i = gridCellStartIndices[curr_grid_index]; i <= gridCellEndIndices[curr_grid_index]; i++){ + int boid_index = particleArrayIndices[i]; + if (boid_index == index){ + continue; + } + float distance = glm::distance(pos[boid_index], pos[index]); + if (distance < rule1Distance){ + perceived_center += pos[boid_index]; + rule_1_count++; + } + if (distance < rule2Distance){ + neightbour_distance -= (pos[boid_index] - pos[index]); + } + if (distance < rule3Distance){ + perceived_velocity += vel1[boid_index]; + rule_3_count++; + } + } + } + } + } + glm::vec3 velocityChange = glm::vec3(0.0f, 0.0f, 0.0f); + glm::vec3 new_velocity = glm::vec3(0.0f, 0.0f, 0.0f); + if (rule_1_count > 0){ + perceived_center /= rule_1_count; + velocityChange += (perceived_center - pos[index]) * rule1Scale; + } + if (rule_3_count > 0){ + perceived_velocity /= rule_3_count; + velocityChange += perceived_velocity * rule3Scale; + } + velocityChange += neightbour_distance * rule2Scale; + + glm::vec3 newVelocity = vel1[index] + velocityChange; + // Clamp the speed + float speed = glm::length(newVelocity); + if (speed > maxSpeed) { + newVelocity = (newVelocity / speed) * maxSpeed; + } + vel2[index] = newVelocity; } __global__ void kernUpdateVelNeighborSearchCoherent( int N, int gridResolution, glm::vec3 gridMin, - float inverseCellWidth, float cellWidth, + float inverseCellWidth, float cellWidth, float maxRuleDistance, int *gridCellStartIndices, int *gridCellEndIndices, glm::vec3 *pos, glm::vec3 *vel1, glm::vec3 *vel2) { // TODO-2.3 - This should be very similar to kernUpdateVelNeighborSearchScattered, @@ -341,6 +517,70 @@ __global__ void kernUpdateVelNeighborSearchCoherent( // - Access each boid in the cell and compute velocity change from // the boids rules, if this boid is within the neighborhood distance. // - Clamp the speed change before putting the new speed in vel2 + int index = threadIdx.x + (blockIdx.x * blockDim.x); + if (index >= N) { + return; + } + glm::vec3 grid_to_search_start = (pos[index] - maxRuleDistance - gridMin) * inverseCellWidth; + glm::vec3 grid_to_search_end = (pos[index] + maxRuleDistance - gridMin) * inverseCellWidth; + // clamp to 0 and girdResolution + glm::vec3 grid_index_min = glm::vec3(0, 0, 0); + glm::vec3 grid_index_max = glm::vec3(gridResolution - 1, gridResolution - 1, gridResolution - 1); + grid_to_search_start = glm::clamp(grid_to_search_start, grid_index_min, grid_index_max); + grid_to_search_end = glm::clamp(grid_to_search_end, grid_index_min, grid_index_max); + + // next, search the valid grid cells and do original boid search + glm::vec3 perceived_center(0.0f, 0.0f, 0.0f); + glm::vec3 neightbour_distance(0.0f, 0.0f, 0.0f); + glm::vec3 perceived_velocity(0.0f, 0.0f, 0.0f); + int rule_1_count = 0; + int rule_3_count = 0; + for(int g_x = grid_to_search_start.x; g_x <= grid_to_search_end.x; g_x++){ + for(int g_y = grid_to_search_start.y; g_y <= grid_to_search_end.y; g_y++){ + for(int g_z = grid_to_search_start.z; g_z <= grid_to_search_end.z; g_z++){ + int curr_grid_index = gridIndex3Dto1D(g_x, g_y, g_z, gridResolution); + if (gridCellStartIndices[curr_grid_index] == -1){ + continue; + } + for(int i = gridCellStartIndices[curr_grid_index]; i <= gridCellEndIndices[curr_grid_index]; i++){ + int boid_index = i; + if (boid_index == index){ + continue; + } + float distance = glm::distance(pos[boid_index], pos[index]); + if (distance < rule1Distance){ + perceived_center += pos[boid_index]; + rule_1_count++; + } + if (distance < rule2Distance){ + neightbour_distance -= (pos[boid_index] - pos[index]); + } + if (distance < rule3Distance){ + perceived_velocity += vel1[boid_index]; + rule_3_count++; + } + } + } + } + } + glm::vec3 velocityChange = glm::vec3(0.0f, 0.0f, 0.0f); + if (rule_1_count > 0){ + perceived_center /= rule_1_count; + velocityChange += (perceived_center - pos[index]) * rule1Scale; + } + if (rule_3_count > 0){ + perceived_velocity /= rule_3_count; + velocityChange += perceived_velocity * rule3Scale; + } + velocityChange += neightbour_distance * rule2Scale; + + glm::vec3 newVelocity = vel1[index] + velocityChange; + // Clamp the speed + float speed = glm::length(newVelocity); + if (speed > maxSpeed) { + newVelocity = (newVelocity / speed) * maxSpeed; + } + vel2[index] = newVelocity; } /** @@ -348,7 +588,16 @@ __global__ void kernUpdateVelNeighborSearchCoherent( */ void Boids::stepSimulationNaive(float dt) { // TODO-1.2 - use the kernels you wrote to step the simulation forward in time. + dim3 fullBlocksPerGrid((numObjects + blockSize - 1) / blockSize); + kernUpdateVelocityBruteForce<<>>(numObjects, dev_pos, dev_vel1, dev_vel2); + cudaDeviceSynchronize(); + + kernUpdatePos<<>>(numObjects, dt, dev_pos, dev_vel2); + cudaDeviceSynchronize(); // TODO-1.2 ping-pong the velocity buffers + glm::vec3 *placeholder = dev_vel1; + dev_vel1 = dev_vel2; + dev_vel2 = placeholder; } void Boids::stepSimulationScatteredGrid(float dt) { @@ -364,6 +613,42 @@ void Boids::stepSimulationScatteredGrid(float dt) { // - Perform velocity updates using neighbor search // - Update positions // - Ping-pong buffers as needed + + // set boid indices + dim3 fullBlocksPerGrid((numObjects + blockSize - 1) / blockSize); + kernComputeIndices<<>> + (numObjects, gridSideCount, gridMinimum, gridInverseCellWidth, + dev_pos, dev_particleArrayIndices, dev_particleGridIndices); + + // sort boid indices by grid index, in place + dev_thrust_particleArrayIndices = thrust::device_pointer_cast(dev_particleArrayIndices); + dev_thrust_particleGridIndices = thrust::device_pointer_cast(dev_particleGridIndices); + thrust::sort_by_key(dev_particleGridIndices, dev_particleGridIndices + numObjects, dev_thrust_particleArrayIndices); + + // set grid cell start and end indices to -1, indicating no boids in the cell + cudaMemset(dev_gridCellStartIndices, -1, gridCellCount * sizeof(int)); + checkCUDAErrorWithLine("cudaMemset dev_gridCellStartIndices failed!"); + cudaMemset(dev_gridCellEndIndices, -1, gridCellCount * sizeof(int)); + checkCUDAErrorWithLine("cudaMemset dev_gridCellEndIndices failed!"); + + // identify cell start and end indices + kernIdentifyCellStartEnd<<>> + (numObjects, dev_particleGridIndices, dev_gridCellStartIndices, dev_gridCellEndIndices); + + // update velocity + kernUpdateVelNeighborSearchScattered<<>> + (numObjects, gridSideCount, gridMinimum, gridInverseCellWidth, gridCellWidth, maxRuleDistance, + dev_gridCellStartIndices, dev_gridCellEndIndices, dev_particleArrayIndices, + dev_pos, dev_vel1, dev_vel2); + cudaDeviceSynchronize(); + // update position + kernUpdatePos<<>>(numObjects, dt, dev_pos, dev_vel2); + cudaDeviceSynchronize(); + // ping-pong the velocity buffers + glm::vec3 *placeholder = dev_vel1; + dev_vel1 = dev_vel2; + dev_vel2 = placeholder; + } void Boids::stepSimulationCoherentGrid(float dt) { @@ -382,6 +667,51 @@ void Boids::stepSimulationCoherentGrid(float dt) { // - Perform velocity updates using neighbor search // - Update positions // - Ping-pong buffers as needed. THIS MAY BE DIFFERENT FROM BEFORE. + + // set boid indices + dim3 fullBlocksPerGrid((numObjects + blockSize - 1) / blockSize); + kernComputeIndices<<>> + (numObjects, gridSideCount, gridMinimum, gridInverseCellWidth, + dev_pos, dev_particleArrayIndices, dev_particleGridIndices); + + // sort boid indices by grid index, in place + dev_thrust_particleArrayIndices = thrust::device_pointer_cast(dev_particleArrayIndices); + dev_thrust_particleGridIndices = thrust::device_pointer_cast(dev_particleGridIndices); + dev_thrust_particlePosIndices = thrust::device_pointer_cast(dev_pos); + dev_thrust_particleVelIndices = thrust::device_pointer_cast(dev_vel1); + + auto zip_begin = thrust::make_zip_iterator(thrust::make_tuple( + dev_thrust_particleArrayIndices, + dev_thrust_particlePosIndices, + dev_thrust_particleVelIndices + )); + auto zip_end = zip_begin + numObjects; + + thrust::sort_by_key(dev_particleGridIndices, dev_particleGridIndices + numObjects, zip_begin); + + // set grid cell start and end indices to -1, indicating no boids in the cell + cudaMemset(dev_gridCellStartIndices, -1, gridCellCount * sizeof(int)); + checkCUDAErrorWithLine("cudaMemset dev_gridCellStartIndices failed!"); + cudaMemset(dev_gridCellEndIndices, -1, gridCellCount * sizeof(int)); + checkCUDAErrorWithLine("cudaMemset dev_gridCellEndIndices failed!"); + + // identify cell start and end indices + kernIdentifyCellStartEnd<<>> + (numObjects, dev_particleGridIndices, dev_gridCellStartIndices, dev_gridCellEndIndices); + + // update velocity + kernUpdateVelNeighborSearchCoherent<<>> + (numObjects, gridSideCount, gridMinimum, gridInverseCellWidth, gridCellWidth, maxRuleDistance, + dev_gridCellStartIndices, dev_gridCellEndIndices, + dev_pos, dev_vel1, dev_vel2); + cudaDeviceSynchronize(); + // update position + kernUpdatePos<<>>(numObjects, dt, dev_pos, dev_vel2); + cudaDeviceSynchronize(); + // ping-pong the velocity buffers + glm::vec3 *placeholder = dev_vel1; + dev_vel1 = dev_vel2; + dev_vel2 = placeholder; } void Boids::endSimulation() { @@ -390,6 +720,11 @@ void Boids::endSimulation() { cudaFree(dev_pos); // TODO-2.1 TODO-2.3 - Free any additional buffers here. + // 2.1 + cudaFree(dev_particleArrayIndices); + cudaFree(dev_particleGridIndices); + cudaFree(dev_gridCellStartIndices); + cudaFree(dev_gridCellEndIndices); } void Boids::unitTest() { diff --git a/src/kernel.h b/src/kernel.h index ab8b9ab..4b3e476 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include diff --git a/src/main.cpp b/src/main.cpp index fe657ed..f4c54f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,9 +16,9 @@ // ================ // LOOK-2.1 LOOK-2.3 - toggles for UNIFORM_GRID and COHERENT_GRID -#define VISUALIZE 1 -#define UNIFORM_GRID 0 -#define COHERENT_GRID 0 +#define VISUALIZE 0 +#define UNIFORM_GRID 1 +#define COHERENT_GRID 1 // LOOK-1.2 - change this to adjust particle count in the simulation const int N_FOR_VIS = 5000; @@ -219,11 +219,14 @@ void initShaders(GLuint * program) { double fps = 0; double timebase = 0; int frame = 0; + double startTime = glfwGetTime(); + double totalFps = 0; + int fpsCount = 0; Boids::unitTest(); // LOOK-1.2 We run some basic example code to make sure // your CUDA development setup is ready to go. - while (!glfwWindowShouldClose(window)) { + while (glfwGetTime() - startTime < 7.0) { glfwPollEvents(); frame++; @@ -233,6 +236,11 @@ void initShaders(GLuint * program) { fps = frame / (time - timebase); timebase = time; frame = 0; + + if (time - startTime >= 2.0 && time - startTime <= 7.0) { + totalFps += fps; + fpsCount++; + } } runCUDA(); @@ -259,6 +267,10 @@ void initShaders(GLuint * program) { glfwSwapBuffers(window); #endif } + + double avgFps = totalFps / fpsCount; + std::cout << "Average FPS: " << avgFps << std::endl; + glfwDestroyWindow(window); glfwTerminate(); }