$ man tshabbic.projects.sps
SPS(8)Simple Projectile SimulatorSPS(8)
Name

sps -- simple projectile simulator

Synopsis

sps [OPTIONS]

Description

[See the Source Code!] | [See the Presentation!] | [See the Summary Paper!]

[Run the Demo!] (Windows 10/11 x86-64; Requires CUDA 13.0+; CLI options below)

[Runtime Screenshot!] (without local gravity) [Runtime Screenshot!] (with local gravity)

Inspired by the general concept of a now-deprecated projectile simulator I'd seen for a video game, my project idea for my graduate parallel computing course was to build my own simple projectile simulation from scratch, then progressively apply a series of optimization techniques to it, measuring the performance impact of each one along the way.

Since the majority of the relevant technical challenges are well documented in the presentation and write up above, I'd like to briefly discuss the features of this program that were implemented that go beyond parallelism. By default this OpenGL program ran at a capped 60 frames per second (fps), and if the fps went below 60, the simulation would appear to run in slow motion. Simply disabling the 60 fps cap with an OpenGL function, letting it run at your monitor's refresh rate, say 300 fps, would make simulation appear 5x faster.
All of these aren't ideal, so I decided to adopt "delta time", which involves calculating the time since the last frame and adjusting the visuals of the simulation. What this effectively means is that say your simulation is running at a locked 300 fps with this technique, and travels through points A, B, C, D, and E -- if the simulation was instead running at a locked 60 fps, you could only see it travel to points A and E, skipping B, C, and D.
This approach isn't perfect however, because the simulation allows the use of sin and cos functions, which do not follow linearity (e.g., sin(x/2) + sin(x/2) != sin(x)) -- this necessarily changes program behavior, which for a proof of concept simulation where raw throughput and performance is the focus, is fine, but if this were a real product, such as a video game or accuracy-focused simulation, it would have to be adjusted for correctly or the technique abandoned for less appealing visuals.

Usage

The following options are available:

-c

sets projectile count to be spawned per use (default: 1)

-g

specifies arc gap between multiple projectiles in degrees (default: 5)

-f

sets projectile's wave frequency (default: 0)

-a

sets projectiles' wave amplitude (default: 0)

-s

sets the travel speed of projectiles (default: 240)

-r

specifies maximum amount of projectile bursts per second (default: 10)

-l

sets the lifetime of the projectile (default: 240)

-G

sets the 'gravity factor', or how attracted projectiles are to each other (default: 0)

-B

specifies the maximum amount of projectiles that a single bin can hold (default: 64)

-X

specifies how many bins are present horizontally (default: 32)

-Y

specifies how many bins are present vertically (default: 18)

-K

sets the type of kernel to be run on the GPU (0: naive GPU, 1: naive binning, 2: shared binning) (default: 2)

-t

sets the number of threads per block on the GPU (default: 128)

-h

prints program help text and returns


The following debug arguments are also understood:

-cpu

run the simulation on the CPU naively / without any optimization attempts. Useful as a baseline performance metric. (default: not enabled)

-benchmark


run the simulation in benchmark mode with pre-configured default values (default: not enabled)

-showbinlines


provides a graphical overlay of where each projectile bin is located (default: not enabled)

Bugs

The check responsible for determining whether or not the specified launch arguments would exceed the maximum amount of shared memory needed for each block on the GPU is not perfect; if the limit is being brushed up on / slightly exceeded, the kernel will fail silently instead of being caught here - leading to the ability to spawn projectiles like normal, but with no behavior of their own.

If the application is suspended or momentarily lacks sufficient time on the CPU, the time between the previous and current frames will be large, causing brief visual anomalies and differing program behavior. (Note that this is a non-issue when not trying to accommodate for FPS > 60).

When resizing the Window, the point at which projectiles spawn by left clicking is properly re-centered, but existing projectiles do not relocate.

See the write up and source code for more detailed, kernel-specific bugs and how they have been / would be overcome.

History

This project was carried out during Spring of 2026 for CS 677 - Parallel Programming for Many Core Processors @ Stevens Institute of Technology.