/*************************************************************************** Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved. ***************************************************************************/ #include #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 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); } }