8#include "quest/include/config.h"
9#include "quest/include/environment.h"
10#include "quest/include/precision.h"
11#include "quest/include/modes.h"
13#include "quest/src/core/errors.hpp"
14#include "quest/src/core/memory.hpp"
15#include "quest/src/core/parser.hpp"
16#include "quest/src/core/printer.hpp"
17#include "quest/src/core/envvars.hpp"
18#include "quest/src/core/autodeployer.hpp"
19#include "quest/src/core/validation.hpp"
20#include "quest/src/core/randomiser.hpp"
21#include "quest/src/comm/comm_config.hpp"
22#include "quest/src/cpu/cpu_config.hpp"
23#include "quest/src/gpu/gpu_config.hpp"
52static QuESTEnv* global_envPtr =
nullptr;
66static bool global_hasEnvBeenFinalized =
false;
75void validateAndInitCustomQuESTEnv(
int useDistrib,
bool userOwnsMpi,
int useGpuAccel,
int useMultithread,
const char* caller) {
80 validate_envNeverInit(global_envPtr !=
nullptr, global_hasEnvBeenFinalized, caller);
87 envvars_validateAndLoadEnvVars(caller);
88 validateconfig_setEpsilonToDefault();
94 validate_newEnvDeploymentMode(useDistrib, useGpuAccel, useMultithread, caller);
98 autodep_chooseQuESTEnvDeployment(useDistrib, useGpuAccel, useMultithread);
101 validate_mpiInitStatus(useDistrib, userOwnsMpi, caller);
108 comm_init(userOwnsMpi);
110 validate_newEnvDistributedBetweenPower2Nodes(caller);
119 gpu_bindLocalGPUsToNodes();
123 bool permitGpuSharing = envvars_getWhetherGpuSharingIsPermitted();
131 if (useGpuAccel && useDistrib && ! permitGpuSharing)
132 validate_newEnvNodesEachHaveUniqueGpu(caller);
139 int initNumThreadsPerBlock = envvars_getDefaultNumGpuThreadsPerBlock();
140 validate_numGpuThreadsPerBlock(initNumThreadsPerBlock, useGpuAccel, caller);
141 gpu_setNumThreadsPerBlock(initNumThreadsPerBlock);
144 bool useCuQuantum = useGpuAccel && gpu_isCuQuantumCompiled();
146 validate_gpuIsCuQuantumCompatible(caller);
152 bool isMpiGpuAware = comm_isMpiGpuAware();
155 rand_setSeedsToDefault();
161 if (global_envPtr ==
nullptr)
162 error_allocOfQuESTEnvFailed();
165 global_envPtr->isMultithreaded = useMultithread;
166 global_envPtr->isGpuAccelerated = useGpuAccel;
167 global_envPtr->isDistributed = useDistrib;
168 global_envPtr->isMpiUserOwned = userOwnsMpi;
169 global_envPtr->isMpiGpuAware = isMpiGpuAware;
170 global_envPtr->isCuQuantumEnabled = useCuQuantum;
171 global_envPtr->isGpuSharingEnabled = permitGpuSharing;
174 global_envPtr->rank = (useDistrib)? comm_getRank() : 0;
175 global_envPtr->numNodes = (useDistrib)? comm_getNumNodes() : 1;
185void printPrecisionInfo() {
194 {
"qreal", printer_getQrealType() +
" (" + printer_getMemoryWithUnitStr(
sizeof(qreal)) +
")"},
198 {
"qcomp", printer_getQcompType() +
" (" + printer_getMemoryWithUnitStr(
sizeof(qcomp)) +
")"},
200 {
"qindex", printer_getQindexType() +
" (" + printer_getMemoryWithUnitStr(
sizeof(qindex)) +
")"},
203 {
"validationEpsilon", printer_toStr(validateconfig_getEpsilon())},
208void printCompilationInfo() {
212 {
"isOmpCompiled", cpu_isOpenmpCompiled()},
213 {
"isMpiCompiled", comm_isMpiCompiled()},
214 {
"isMpiSubCommCompiled", comm_isMpiSubCommCompiled()},
215 {
"isGpuCompiled", gpu_isGpuCompiled()},
216 {
"isHipCompiled", gpu_isHipCompiled()},
217 {
"isCuQuantumCompiled", gpu_isCuQuantumCompiled()},
218 {
"isCheckpointingCompiled", QUEST_COMPILE_ADIOS2},
223void printDeploymentInfo() {
227 {
"isOmpEnabled", global_envPtr->isMultithreaded},
228 {
"isMpiEnabled", global_envPtr->isDistributed},
229 {
"isGpuEnabled", global_envPtr->isGpuAccelerated},
230 {
"isCuQuantumEnabled", global_envPtr->isCuQuantumEnabled},
237 using namespace printer_substrings;
242 ram = printer_getMemoryWithUnitStr(mem_tryGetLocalRamCapacityInBytes()) + pm;
243 }
catch(mem::COULD_NOT_QUERY_RAM e){};
250 {
"numCpuCores", printer_toStr(std::thread::hardware_concurrency()) + pm},
251 {
"numOmpProcs", (cpu_isOpenmpCompiled())? printer_toStr(cpu_getNumOpenmpProcessors()) + pm : na},
252 {
"numOmpThrds", (cpu_isOpenmpCompiled())? printer_toStr(cpu_getAvailableNumThreads()) + pn : na},
254 {
"cpuMemoryFree", un},
261 using namespace printer_substrings;
268 bool isComp = gpu_isGpuCompiled();
269 bool isGpu = isComp && gpu_isGpuAvailable();
273 {
"numGpus", isComp? printer_toStr(gpu_getNumberOfLocalGpus()) : na},
274 {
"gpuDirect", isGpu? printer_toStr(gpu_isDirectGpuCommPossible()) : na},
275 {
"gpuMemPools", isGpu? printer_toStr(gpu_doesGpuSupportMemPools()) : na},
276 {
"gpuMemory", isGpu? printer_getMemoryWithUnitStr(gpu_getTotalMemoryInBytes()) + pg : na},
277 {
"gpuMemoryFree", isGpu? printer_getMemoryWithUnitStr(gpu_getCurrentAvailableMemoryInBytes()) + pg : na},
278 {
"gpuCache", isGpu? printer_getMemoryWithUnitStr(gpu_getCacheMemoryInBytes()) + pg : na},
279 {
"numThreadsPerBlock", isGpu? printer_toStr(gpu_getNumThreadsPerBlock()) : na},
284void printDistributionInfo() {
286 using namespace printer_substrings;
288 bool comm = global_envPtr->isDistributed;
289 bool gpu = global_envPtr->isGpuAccelerated;
290 bool both = comm && gpu;
294 {
"isMpiUserOwned", comm? printer_toStr(global_envPtr->isMpiUserOwned) : na},
295 {
"isMpiGpuAware", comm? printer_toStr(global_envPtr->isMpiGpuAware ) : na},
296 {
"isGpuSharingEnabled", both? printer_toStr(global_envPtr->isGpuSharingEnabled) : na},
297 {
"numMpiNodes", printer_toStr(global_envPtr->numNodes)},
302void printQuregSizeLimits(
bool isDensMatr) {
304 using namespace printer_substrings;
307 int numNodes = global_envPtr->numNodes;
310 string maxQbForCpu = un;
311 string maxQbForMpiCpu = un;
315 qindex cpuMem = mem_tryGetLocalRamCapacityInBytes();
316 maxQbForCpu = printer_toStr(mem_getMaxNumQuregQubitsWhichCanFitInMemory(isDensMatr, 1, cpuMem));
319 if (global_envPtr->isDistributed)
320 maxQbForMpiCpu = printer_toStr(mem_getMaxNumQuregQubitsWhichCanFitInMemory(isDensMatr, numNodes, cpuMem));
327 }
catch(mem::COULD_NOT_QUERY_RAM e) {};
330 string maxQbForGpu = na;
331 string maxQbForMpiGpu = na;
334 if (global_envPtr->isGpuAccelerated) {
335 qindex gpuMem = gpu_getCurrentAvailableMemoryInBytes();
336 maxQbForGpu = printer_toStr(mem_getMaxNumQuregQubitsWhichCanFitInMemory(isDensMatr, 1, gpuMem));
339 if (global_envPtr->isDistributed)
340 maxQbForMpiGpu = printer_toStr(mem_getMaxNumQuregQubitsWhichCanFitInMemory(isDensMatr, numNodes, gpuMem));
344 string prefix = (isDensMatr)?
"density matrix" :
"statevector";
345 string title = prefix +
" limits";
349 {
"minQubitsForMpi", (numNodes>1)? printer_toStr(mem_getMinNumQubitsForDistribution(numNodes)) : na},
350 {
"maxQubitsForCpu", maxQbForCpu},
351 {
"maxQubitsForGpu", maxQbForGpu},
352 {
"maxQubitsForMpiCpu", maxQbForMpiCpu},
353 {
"maxQubitsForMpiGpu", maxQbForMpiGpu},
354 {
"maxQubitsForMemOverflow", printer_toStr(mem_getMaxNumQuregQubitsBeforeGlobalMemSizeofOverflow(isDensMatr, numNodes))},
355 {
"maxQubitsForIndOverflow", printer_toStr(mem_getMaxNumQuregQubitsBeforeIndexOverflow(isDensMatr))},
360void printQuregAutoDeployments(
bool isDensMatr) {
363 std::vector<std::tuple<string, string>> rows;
366 int useDistrib, useGpuAccel, useMulti;
367 int prevDistrib, prevGpuAccel, prevMulti;
376 int maxQubits = mem_getMaxNumQuregQubitsBeforeGlobalMemSizeofOverflow(isDensMatr, global_envPtr->numNodes);
378 for (
int numQubits=1; numQubits<maxQubits; numQubits++) {
381 useDistrib = modeflag::USE_AUTO;
382 useGpuAccel = modeflag::USE_AUTO;
383 useMulti = modeflag::USE_AUTO;;
384 autodep_chooseQuregDeployment(numQubits, isDensMatr, useDistrib, useGpuAccel, useMulti, *global_envPtr);
387 if (useDistrib == prevDistrib &&
388 useGpuAccel == prevGpuAccel &&
389 useMulti == prevMulti)
402 rows.push_back({printer_toStr(numQubits) +
" qubits", value});
405 prevDistrib = useDistrib;
406 prevGpuAccel = useGpuAccel;
407 prevMulti = useMulti;
411 string prefix = (isDensMatr)?
"density matrix" :
"statevector";
412 string title = prefix +
" autodeployment";
414 print_table(title,
"(no parallelisations available)"):
415 print_table(title, rows);
431 const bool userOwnsMpi =
false;
432 validateAndInitCustomQuESTEnv(useDistrib, userOwnsMpi, useGpuAccel, useMultithread, __func__);
438 const bool userOwnsMpi =
false;
439 validateAndInitCustomQuESTEnv(modeflag::USE_AUTO, userOwnsMpi, modeflag::USE_AUTO, modeflag::USE_AUTO, __func__);
445 return (
int) (global_envPtr !=
nullptr);
450 validate_envIsInit(__func__);
453 return *global_envPtr;
458 validate_envIsInit(__func__);
464 if (global_envPtr->isGpuAccelerated)
467 if (global_envPtr->isGpuAccelerated && gpu_isCuQuantumCompiled())
468 gpu_finalizeCuQuantum();
470 if (global_envPtr->isDistributed) {
477 global_envPtr =
nullptr;
480 global_hasEnvBeenFinalized =
true;
485 validate_envIsInit(__func__);
487 if (global_envPtr->isGpuAccelerated)
490 if (global_envPtr->isDistributed)
496 validate_envIsInit(__func__);
497 validate_numReportedNewlinesAboveZero(__func__);
503 print_label(
"QuEST execution environment");
505 bool statevec =
false;
506 bool densmatr =
true;
511 printPrecisionInfo();
512 printCompilationInfo();
513 printDeploymentInfo();
516 printDistributionInfo();
517 printQuregSizeLimits(statevec);
518 printQuregSizeLimits(densmatr);
519 printQuregAutoDeployments(statevec);
520 printQuregAutoDeployments(densmatr);
523 print_oneFewerNewlines();
530 validate_envIsInit(__func__);
532 int numThreads = cpu_isOpenmpCompiled()? cpu_getAvailableNumThreads() : 1;
533 int cuQuantum = global_envPtr->isGpuAccelerated && gpu_isCuQuantumCompiled();
534 int gpuDirect = global_envPtr->isGpuAccelerated && gpu_isDirectGpuCommPossible();
536 snprintf(str, 200,
"CUDA=%d OpenMP=%d MPI=%d userOwnsMPI=%d threads=%d ranks=%d cuQuantum=%d gpuDirect=%d",
537 global_envPtr->isGpuAccelerated,
538 global_envPtr->isMultithreaded,
539 global_envPtr->isDistributed,
540 global_envPtr->isMpiUserOwned,
542 global_envPtr->numNodes,
void getQuESTEnvironmentString(char str[200])
void initCustomQuESTEnv(int useDistrib, int useGpuAccel, int useMultithread)