Files
2016-04-27 01:07:35 -04:00

230 lines
6.2 KiB
Java

//******************************************************************************
//
// File: ZombieGpu.java
// Package: edu.rit.gpu.example
// Unit: Class edu.rit.gpu.example.ZombieGpu
//
// This Java source file is copyright (C) 2014 by Alan Kaminsky. All rights
// reserved. For further information, contact the author, Alan Kaminsky, at
// ark@cs.rit.edu.
//
// This Java source file is part of the Parallel Java 2 Library ("PJ2"). PJ2 is
// free software; you can redistribute it and/or modify it under the terms of
// the GNU General Public License as published by the Free Software Foundation;
// either version 3 of the License, or (at your option) any later version.
//
// PJ2 is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU General Public License for more details.
//
// A copy of the GNU General Public License is provided in the file gpl.txt. You
// may also obtain a copy of the GNU General Public License on the World Wide
// Web at http://www.gnu.org/licenses/gpl.html.
//
//******************************************************************************
package edu.rit.gpu.example;
import edu.rit.gpu.CacheConfig;
import edu.rit.gpu.Gpu;
import edu.rit.gpu.GpuDoubleArray;
import edu.rit.gpu.GpuDoubleVbl;
import edu.rit.gpu.Kernel;
import edu.rit.gpu.Module;
import edu.rit.pj2.Task;
import edu.rit.util.Random;
/**
* Class ZombieGpu is a GPU parallel program to compute the motion of a group of
* zombies. This is a so-called "<I>N</I>-bodies" problem.
* <P>
* Usage: <TT>java pj2 edu.rit.gpu.example.ZombieGpu <I>seed</I> <I>N</I>
* <I>W</I> <I>G</I> <I>L</I> <I>dt</I> <I>eps</I> <I>steps</I> <I>snap</I></TT>
* <BR><TT><I>seed</I></TT> = Random seed
* <BR><TT><I>N</I></TT> = Number of bodies
* <BR><TT><I>W</I></TT> = Region size
* <BR><TT><I>G</I></TT> = Attraction factor
* <BR><TT><I>L</I></TT> = Attraction length scale
* <BR><TT><I>dt</I></TT> = Time step size
* <BR><TT><I>eps</I></TT> = Convergence threshold
* <BR><TT><I>steps</I></TT> = Number of time steps (0 = until convergence)
* <BR><TT><I>snap</I></TT> = Snapshot interval (0 = none)
*
* @author Alan Kaminsky
* @version 10-Oct-2014
*/
public class ZombieGpu
extends Task
{
// Command line arguments.
long seed;
int N;
double W;
double G;
double L;
double dt;
double eps;
int steps;
int snap;
// Current body positions.
GpuDoubleArray xpos;
GpuDoubleArray ypos;
// Next body positions.
GpuDoubleArray xnext;
GpuDoubleArray ynext;
// For detecting convergence.
GpuDoubleVbl delta;
/**
* Kernel function interface.
*/
private static interface ZombieKernel
extends Kernel
{
public void timeStep
(GpuDoubleArray xpos,
GpuDoubleArray ypos,
GpuDoubleArray xnext,
GpuDoubleArray ynext,
int N,
double G,
double L,
double dt);
}
/**
* Task main program.
*/
public void main
(String[] args)
throws Exception
{
// Parse command line arguments.
if (args.length != 9) usage();
seed = Long.parseLong (args[0]);
N = Integer.parseInt (args[1]);
W = Double.parseDouble (args[2]);
G = Double.parseDouble (args[3]);
L = Double.parseDouble (args[4]);
dt = Double.parseDouble (args[5]);
eps = Double.parseDouble (args[6]);
steps = Integer.parseInt (args[7]);
snap = Integer.parseInt (args[8]);
// Initialize GPU.
Gpu gpu = Gpu.gpu();
gpu.ensureComputeCapability (2, 0);
// Set up GPU variables.
Module module = gpu.getModule ("edu/rit/gpu/example/ZombieGpu.cubin");
xpos = gpu.getDoubleArray (N);
ypos = gpu.getDoubleArray (N);
xnext = gpu.getDoubleArray (N);
ynext = gpu.getDoubleArray (N);
delta = module.getDoubleVbl ("devDelta");
// Set up GPU kernel.
ZombieKernel kernel = module.getKernel (ZombieKernel.class);
kernel.setBlockDim (256);
kernel.setGridDim (N);
kernel.setCacheConfig (CacheConfig.CU_FUNC_CACHE_PREFER_L1);
// Set zombies' initial (x,y) coordinates at random in a WxW square
// region.
Random prng = new Random (seed);
for (int i = 0; i < N; ++ i)
{
xpos.item[i] = prng.nextDouble()*W;
ypos.item[i] = prng.nextDouble()*W;
}
xpos.hostToDev();
ypos.hostToDev();
// Snapshot all bodies' initial positions.
int t = 0;
snapshot (t);
// Do repeated time steps.
for (;;)
{
// Do one time step.
delta.item = 0.0;
delta.hostToDev();
kernel.timeStep (xpos, ypos, xnext, ynext, N, G, L, dt);
// Advance to next time step.
++ t;
// Update positions.
GpuDoubleArray tmp;
tmp = xpos; xpos = xnext; xnext = tmp;
tmp = ypos; ypos = ynext; ynext = tmp;
// Stop when position delta is less than convergence threshold or
// when the specified number of time steps have occurred.
delta.devToHost();
if ((steps == 0 && delta.item < eps) || (steps != 0 && t == steps))
break;
// Snapshot all bodies' positions every <snap> time steps.
if (snap > 0 && (t % snap) == 0)
snapshot (t);
}
// Snapshot all bodies' final positions.
snapshot (t);
}
/**
* Snapshot all bodies' positions.
*/
private void snapshot
(int t)
{
xpos.devToHost();
ypos.devToHost();
for (int i = 0; i < N; ++ i)
System.out.printf ("%d\t%d\t%g\t%g%n",
t, i, xpos.item[i], ypos.item[i]);
}
/**
* Print a usage message and exit.
*/
private static void usage()
{
System.err.println ("Usage: java pj2 edu.rit.pj2.example.ZombieGpu <seed> <N> <W> <G> <L> <dt> <eps> <steps> <snap>");
System.err.println ("<seed> = Random seed");
System.err.println ("<N> = Number of bodies");
System.err.println ("<W> = Region size");
System.err.println ("<G> = Attraction factor");
System.err.println ("<L> = Attraction length scale");
System.err.println ("<dt> = Time step size");
System.err.println ("<eps> = Convergence threshold");
System.err.println ("<steps> = Number of time steps (0 = until convergence)");
System.err.println ("<snap> = Snapshot interval (0 = none)");
throw new IllegalArgumentException();
}
/**
* Specify that this task requires one core.
*/
protected static int coresRequired()
{
return 1;
}
/**
* Specify that this task requires one GPU accelerator.
*/
protected static int gpusRequired()
{
return 1;
}
}