Files
TheRock/rocm-systems/projects/rocprofiler-systems/examples/hpc/jacobi-hip/JacobiSetup.hip
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

294 lines
9.0 KiB
Plaintext

/***************************************************************************
Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
***************************************************************************/
#include <unistd.h>
#include "Jacobi.hpp"
#include "markers.h"
Jacobi_t::Jacobi_t(grid_t& grid_, mesh_t& mesh_):
grid(grid_),
mesh(mesh_)
{
SafeHipCall(hipInit(0));
BEGIN_RANGE("Jacobi_t::Jacobi_t", "Top Level Init");
BEGIN_RANGE("ApplyTopology", "Init");
ApplyTopology();
END_RANGE();
BEGIN_RANGE("CreateMesh", "Init");
CreateMesh();
END_RANGE();
BEGIN_RANGE("InitializeData", "Init");
InitializeData();
END_RANGE();
END_RANGE();
}
Jacobi_t::~Jacobi_t() {
SafeHostFree(mesh.x);
SafeHostFree(mesh.y);
SafeHostFree(h_U);
SafeHostFree(h_AU);
SafeHostFree(h_RHS);
SafeHipCall(hipFree(d_U));
SafeHipCall(hipFree(d_AU));
SafeHipCall(hipFree(d_RHS));
SafeHipCall(hipHostFree(mesh.sendBuffer));
SafeHipCall(hipHostFree(mesh.recvBuffer));
SafeHipCall(hipFree(mesh.d_haloBuffer));
}
// ====================
// Topology application
// ====================
/**
* @brief Generates the 2D topology and establishes the neighbor relationships between MPI processes
*/
void Jacobi_t::ApplyTopology() {
// The number of MPI processes must fill the topology
int size = grid.Nrow * grid.Ncol;
if (size != grid.size) {
OneErrPrintf((!grid.rank),
"Error: The number of MPI processes (%d) doesn't match "
"the topology size (%d).\n", size, grid.size);
MPI_Abort(grid.comm, STATUS_ERR);
}
grid.mycol = grid.rank % grid.Ncol;
grid.myrow = grid.rank / grid.Ncol;
grid.Neighbor[SIDE_LEFT ] = (grid.mycol==0) ? -1 : grid.rank-1;
grid.Neighbor[SIDE_RIGHT] = (grid.mycol==grid.Ncol-1) ? -1 : grid.rank+1;
grid.Neighbor[SIDE_DOWN ] = (grid.myrow==0) ? -1 : grid.rank-grid.Ncol;
grid.Neighbor[SIDE_UP ] = (grid.myrow==grid.Nrow-1) ? -1 : grid.rank+grid.Ncol;
//select GPU
int devCount = 0;
SafeHipCall(hipGetDeviceCount(&devCount));
if (devCount == 0) {
fprintf(stderr, "Error: MPI rank %d detected no GPUs."
"Terminating...\n", grid.rank);
MPI_Abort(grid.comm, STATUS_ERR);
}
char name[255];
gethostname(name, 255);
long int hostId = gethostid();
long int* hostIds = (long int*) calloc(size,sizeof(long int));
MPI_Allgather(&hostId,1,MPI_LONG,hostIds,1,MPI_LONG,grid.comm);
//count how many ranks are on this node
int local_rank = 0;
for (int r=0;r<grid.rank;r++)
if (hostIds[r]==hostId) local_rank++;
//select gpu via round-robin
grid.device_id = local_rank % devCount;
SafeHipCall(hipSetDevice(grid.device_id));
printf("Rank %d selecting device %d on host %s\n", grid.rank, grid.device_id, name);
}
// ====================
// Mesh Creation
// ====================
/**
* @brief Generates the 2D mesh
*/
void Jacobi_t::CreateMesh() {
mesh.N = mesh.Nx * mesh.Ny;
mesh.Nhalo = 2*mesh.Nx + 2*mesh.Ny;
//domain dimensions
mesh.Lx = (X_MAX) - (X_MIN);
mesh.Ly = (Y_MAX) - (Y_MIN);
//mesh spacing
mesh.dx = mesh.Lx/(mesh.Nx*grid.Ncol+1);
mesh.dy = mesh.Ly/(mesh.Ny*grid.Nrow+1);
dfloat DX = mesh.dx*(mesh.Nx-1);
dfloat DY = mesh.dy*(mesh.Ny-1);
uint64 Ntotal = grid.size*mesh.N;
mesh.invNtotal = 1.0/Ntotal;
//coordinates (including boundary points)
mesh.x = (dfloat *) malloc((mesh.Nx+2)*sizeof(dfloat));
mesh.y = (dfloat *) malloc((mesh.Ny+2)*sizeof(dfloat));
for (int i=0;i<mesh.Nx;i++)
mesh.x[i] = mesh.dx + grid.mycol*(DX+mesh.dx) + i*mesh.dx;
for (int j=0;j<mesh.Ny;j++)
mesh.y[j] = mesh.dy + grid.myrow*(DY+mesh.dy) + j*mesh.dy;
//halo exchange storage
SafeHipCall(hipHostMalloc(&(mesh.sendBuffer), mesh.Nhalo*sizeof(dfloat),0));
SafeHipCall(hipHostMalloc(&(mesh.recvBuffer), mesh.Nhalo*sizeof(dfloat),0));
SafeHipCall(hipMalloc(&(mesh.d_haloBuffer), mesh.Nhalo*sizeof(dfloat)));
SafeHipCall(hipMemset(mesh.d_haloBuffer, 0, mesh.Nhalo*sizeof(dfloat)));
for (int i=0;i<2*NSIDES;i++) mesh.requests[i] = MPI_REQUEST_NULL;
//number of entries for each side in send/recv buffers
mesh.sideLength[SIDE_DOWN ] = mesh.Nx;
mesh.sideLength[SIDE_UP ] = mesh.Nx;
mesh.sideLength[SIDE_LEFT ] = mesh.Ny;
mesh.sideLength[SIDE_RIGHT] = mesh.Ny;
//offets of halo side data in send/recv buffers
mesh.sideOffset[SIDE_DOWN ] = 0;
mesh.sideOffset[SIDE_UP ] = mesh.Nx;
mesh.sideOffset[SIDE_LEFT ] = 2*mesh.Nx;
mesh.sideOffset[SIDE_RIGHT] = 2*mesh.Nx + mesh.Ny;
SafeHipCall(hipStreamCreate(&(computeStream)));
SafeHipCall(hipStreamCreate(&(dataStream)));
}
/**
* @brief This allocates and initializes all the relevant data buffers before the Jacobi run
*
*/
void Jacobi_t::InitializeData() {
//host buffers
h_U = (dfloat*) malloc(mesh.N*sizeof(dfloat));
h_AU = (dfloat*) malloc(mesh.N*sizeof(dfloat));
h_RHS = (dfloat*) malloc(mesh.N*sizeof(dfloat));
h_RES = (dfloat*) malloc(mesh.N*sizeof(dfloat));
for (int j=0;j<mesh.Ny;j++) {
for (int i=0;i<mesh.Nx;i++) {
int id = i+j*mesh.Nx;
h_U[id] = 0.0; //initial guess
h_RHS[id] = 0.0; //forcing
}
}
// add boundary contributions
uint64_t offsetX = grid.mycol*mesh.Nx+1;
uint64_t offsetY = grid.myrow*mesh.Ny+1;
dfloat totalX = grid.Ncol*mesh.Nx+2;
dfloat totalY = grid.Nrow*mesh.Ny+2;
if (grid.Neighbor[SIDE_DOWN]==-1) {
for (int i=0;i<mesh.Nx;i++) {
dfloat bc = sin(M_PI*(i+offsetX)/(totalX));
h_RHS[i] += bc/(mesh.dx*mesh.dx);
}
}
if (grid.Neighbor[SIDE_UP]==-1) {
for (int i=0;i<mesh.Nx;i++) {
dfloat bc = sin(M_PI*(i+offsetX)/(totalX));
h_RHS[i+(mesh.Ny-1)*mesh.Nx] += bc/(mesh.dx*mesh.dx);
}
}
if (grid.Neighbor[SIDE_LEFT]==-1) {
for (int j=0;j<mesh.Ny;j++) {
dfloat bc = sin(M_PI*(j+offsetY)/(totalY));
h_RHS[j*mesh.Nx] += bc/(mesh.dy*mesh.dy);
}
}
if (grid.Neighbor[SIDE_RIGHT]==-1) {
for (int j=0;j<mesh.Ny;j++) {
dfloat bc = sin(M_PI*(j+offsetY)/(totalY));
h_RHS[(mesh.Nx-1)+j*mesh.Nx] += bc/(mesh.dy*mesh.dy);
}
}
//device buffers
SafeHipCall(hipMalloc((void **)&d_U, mesh.N*sizeof(dfloat)));
SafeHipCall(hipMalloc((void **)&d_AU, mesh.N*sizeof(dfloat)));
SafeHipCall(hipMalloc((void **)&d_RHS, mesh.N*sizeof(dfloat)));
SafeHipCall(hipMalloc((void **)&d_RES, mesh.N*sizeof(dfloat)));
//send data to device
SafeHipCall(hipMemcpy(d_U, h_U, mesh.N*sizeof(dfloat), hipMemcpyHostToDevice));
SafeHipCall(hipMemcpy(d_AU, h_U, mesh.N*sizeof(dfloat), hipMemcpyHostToDevice));
SafeHipCall(hipMemcpy(d_RHS, h_RHS, mesh.N*sizeof(dfloat), hipMemcpyHostToDevice));
SafeHipCall(hipMemcpy(d_RES, h_RHS, mesh.N*sizeof(dfloat), hipMemcpyHostToDevice));
SafeHipCall(hipEventCreate(&JacobiLocalStart));
SafeHipCall(hipEventCreate(&JacobiLocalEnd));
}
// Display a number in a pretty format
char * FormatNumber(double value, const char * suffix, char * printBuf) {
std::string magnitude = " kMGT";
size_t orderIdx = 0;
value = fabs(value);
while ((value > 1000.0) && (orderIdx < magnitude.length() - 1))
{
++orderIdx;
value /= 1000.0;
}
sprintf(printBuf, "%.2lf %c%s", value, magnitude[orderIdx], suffix);
return printBuf;
}
// Print a performance counter in a specific format
void PrintPerfCounter(const char * counterDesc, const char * counterUnit,
double counter, double elapsedTime, int size) {
char printBuf[256];
double avgCounter = counter / elapsedTime;
double rankAvgCounter = avgCounter / size;
printf("%s: %s (total), ", counterDesc, FormatNumber(avgCounter, counterUnit, printBuf));
printf("%s (per process)\n", FormatNumber(rankAvgCounter, counterUnit, printBuf));
}
void Jacobi_t::PrintResults() {
double lattUpdates = 0.0, flops = 0.0, bandWidth = 0.0;
MPI_Barrier(grid.comm);
double localCommTime = totalCommTime;
double localComputeTime = totalLocalComputeTime;
MPI_Allreduce(&localCommTime, &totalCommTime, 1, MPI_DOUBLE, MPI_SUM, grid.comm);
MPI_Allreduce(&localComputeTime, &totalLocalComputeTime, 1, MPI_DOUBLE, MPI_SUM, grid.comm);
// Show the performance counters
if (!grid.rank) {
printf("Total Jacobi run time: %.4lf sec.\n", elasped);
// printf("Average per-process communication time: %.4lf sec.\n", avgTransferTime);
// Compute the performance counters over all MPI processes
lattUpdates = 1.0 * (grid.Ncol * mesh.Nx) * (grid.Nrow * mesh.Ny) * iterations;
flops = 17.0 * (lattUpdates); // Operations per Jacobi kernel run
bandWidth = 12.0 * (lattUpdates) * sizeof(dfloat); // Transfers per Jacobi kernel run
double extraCommTime = totalCommTime - totalLocalComputeTime;
extraCommTime = (extraCommTime<0) ? 0.0 : extraCommTime;
double fractionCommHidden = 100.0 - 100.0*extraCommTime/totalCommTime;
PrintPerfCounter("Measured lattice updates", "LU/s", lattUpdates, elasped, grid.size);
PrintPerfCounter("Measured FLOPS", "FLOPS", flops, elasped, grid.size);
PrintPerfCounter("Measured device bandwidth", "B/s", bandWidth, elasped, grid.size);
if (grid.size>1)
printf("Percentage of MPI traffic hidden by computation: %3.1f\n", fractionCommHidden);
}
}