static char help[] = "Tests several PetscLogHandler implementations.\n\n"; #include /* Create a phony perfstubs implementation for testing. The dynamic loading in perfstubs is only enabled with the following flags, so we only try to export these functions if they are present */ #if defined(__linux__) && PetscDefined(HAVE_DLFCN_H) PETSC_EXTERN void ps_tool_initialize(void) { PetscFunctionBegin; PetscCallContinue(PetscPrintf(PETSC_COMM_SELF, "ps_tool_initialize()\n")); PetscFunctionReturnVoid(); } PETSC_EXTERN void ps_tool_finalize(void) { PetscFunctionBegin; PetscCallContinue(PetscPrintf(PETSC_COMM_SELF, "ps_tool_finalize()\n")); PetscFunctionReturnVoid(); } PETSC_EXTERN void *ps_tool_timer_create(const char name[]) { PetscFunctionBegin; PetscCallContinue(PetscPrintf(PETSC_COMM_SELF, "ps_tool_timer_create(\"%s\")\n", name)); PetscFunctionReturn((void *)name); } PETSC_EXTERN void *ps_tool_timer_start(void *arg) { const char *name = (const char *)arg; PetscFunctionBegin; PetscCallContinue(PetscPrintf(PETSC_COMM_SELF, "ps_tool_timer_start() [%s]\n", name)); PetscFunctionReturn(NULL); } PETSC_EXTERN void *ps_tool_timer_stop(void *arg) { const char *name = (const char *)arg; PetscFunctionBegin; PetscCallContinue(PetscPrintf(PETSC_COMM_SELF, "ps_tool_timer_stop() [%s]\n", name)); PetscFunctionReturn(NULL); } #endif static PetscErrorCode CallEvents(PetscLogEvent event1, PetscLogEvent event2, PetscLogEvent event3) { char *data; PetscFunctionBegin; PetscCall(PetscLogEventBegin(event1, NULL, NULL, NULL, NULL)); PetscCall(PetscSleep(0.05)); PetscCall(PetscLogEventBegin(event2, NULL, NULL, NULL, NULL)); PetscCall(PetscSleep(0.1)); PetscCall(PetscLogEventBegin(event3, NULL, NULL, NULL, NULL)); PetscCall(PetscCalloc1(1048576, &data)); PetscCall(PetscFree(data)); PetscCall(PetscSleep(0.15)); PetscCall(PetscLogEventEnd(event3, NULL, NULL, NULL, NULL)); PetscCall(PetscLogEventEnd(event2, NULL, NULL, NULL, NULL)); PetscCall(PetscLogEventEnd(event1, NULL, NULL, NULL, NULL)); PetscFunctionReturn(PETSC_SUCCESS); } int main(int argc, char **argv) { PetscLogStage stage1, stage2, stage3 = -1; PetscLogEvent event1, event2, event3; PetscMPIInt rank; PetscContainer container1, container2; PetscFunctionBeginUser; PetscCall(PetscInitialize(&argc, &argv, NULL, help)); PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank)); if (rank) { PetscCall(PetscLogEventRegister("Event3", 0, &event3)); PetscCall(PetscLogEventRegister("Event2", 0, &event2)); PetscCall(PetscLogEventRegister("Event1", PETSC_CONTAINER_CLASSID, &event1)); PetscCall(PetscLogStageRegister("Stage2", &stage2)); PetscCall(PetscLogStageRegister("Stage1", &stage1)); PetscCall(PetscLogStageRegister("Stage3", &stage3)); (void)stage3; // stage3 intentionally not used } else { PetscCall(PetscLogEventRegister("Event2", 0, &event2)); PetscCall(PetscLogEventRegister("Event1", PETSC_CONTAINER_CLASSID, &event1)); PetscCall(PetscLogEventRegister("Event3", 0, &event3)); PetscCall(PetscLogStageRegister("Stage1", &stage1)); PetscCall(PetscLogStageRegister("Stage2", &stage2)); } for (PetscInt i = 0; i < 8; i++) { PetscCall(PetscLogEventSetDof(event3, i, (PetscLogDouble)i)); PetscCall(PetscLogEventSetError(event3, i, (PetscLogDouble)i + 8)); } PetscCall(CallEvents(event1, event2, event3)); PetscCall(PetscLogStagePush(stage1)); { PetscCall(PetscSleep(0.1)); PetscCall(CallEvents(event1, event2, event3)); } PetscCall(PetscLogStagePop()); PetscCall(PetscContainerCreate(PETSC_COMM_WORLD, &container1)); PetscCall(PetscContainerCreate(PETSC_COMM_WORLD, &container2)); PetscCall(PetscObjectSetName((PetscObject)container2, "Container 2")); PetscCall(PetscLogObjectState((PetscObject)container1, "Setting object state for testing purposes with %d self-referential format argument", 1)); PetscCall(PetscLogStagePush(stage2)); { PetscCall(PetscSleep(0.3)); PetscCall(CallEvents(event1, event2, event3)); PetscCall(PetscLogStagePush(stage1)); { PetscCall(PetscSleep(0.1)); PetscCall(CallEvents(event1, event2, event3)); } PetscCall(PetscLogStagePop()); PetscCall(PetscLogEventSync(event1, PETSC_COMM_WORLD)); PetscCall(PetscLogEventBegin(event1, container1, container2, NULL, NULL)); { PetscCall(PetscSleep(0.1)); PetscCall(PetscLogStagePush(stage1)); { PetscCall(PetscSleep(0.1)); PetscCall(CallEvents(event1, event2, event3)); } PetscCall(PetscLogStagePop()); } PetscCall(PetscLogEventEnd(event1, container1, container2, NULL, NULL)); } PetscCall(PetscLogStagePop()); PetscCall(PetscContainerDestroy(&container2)); PetscCall(PetscContainerDestroy(&container1)); PetscCall(PetscFinalize()); return 0; } /*TEST # smoke test: does this program run with / without PETSC_USE_LOG? test: suffix: 0 nsize: {{1 2}} # flamegraph: times of PetscSleep() are designed so the flamegraph should have reproducible entries test: suffix: 1 nsize: {{1 2}} requires: defined(PETSC_USE_LOG) args: -log_view ::ascii_flamegraph filter: sed -E "s/ [0-9]+/ time_removed/g" test: suffix: 2 requires: defined(PETSC_USE_LOG) nsize: 1 args: -log_trace # test PetscLogDump() with action and object logging test: suffix: 3 nsize: 1 requires: defined(PETSC_USE_LOG) args: -log_include_actions -log_include_objects -log_all temporaries: Log.0 filter: cat Log.0 | grep "\\(Actions accomplished\\|Objects created\\|Name\\|Info\\)" # -log_sync is not necessary for csv output, this is just a convenient test to add sync testing to test: suffix: 4 nsize: 2 requires: defined(PETSC_USE_LOG) args: -log_view ::ascii_csv -log_sync filter: grep "Event[123]" | grep -v "PCMPI" # we don't guarantee clog2print is available, so we just verify that our events are in the output file test: suffix: 5 nsize: 1 requires: defined(PETSC_USE_LOG) defined(PETSC_HAVE_MPE) args: -log_mpe ex30_mpe temporaries: ex30_mpe.clog2 filter: strings ex30_mpe.clog2 | grep "Event[123]" # we don't have tau as a dependency, so we test a dummy perfstubs tool test: suffix: 6 nsize: 1 requires: tau_perfstubs linux dlfcn_h defined(PETSC_USE_LOG) defined(PETSC_USE_SHARED_LIBRARIES) args: -log_perfstubs filter: grep "\\(Main Stage\\|Event1\\|Event2\\|Event3\\|Stage1\\|Stage2\\)" test: suffix: 7 nsize: 1 requires: defined(PETSC_USE_LOG) args: -log_view ::ascii_info_detail -log_handler_default_use_threadsafe_events filter: grep "Event[123]" | grep "\\(Main Stage\\|Stage[123]\\)" # test the sync warning test: suffix: 8 nsize: 2 requires: defined(PETSC_USE_LOG) args: -log_view -log_sync filter: grep "This program was run with logging synchronization" # test -log_trace with an output file test: suffix: 9 requires: defined(PETSC_USE_LOG) nsize: 1 output_file: output/ex30_2.out args: -log_trace trace.log temporaries: trace.log filter: cat trace.log.0 # test -log_nvtx test: suffix: 10 requires: cuda defined(PETSC_USE_LOG) args: -device_enable eager -log_nvtx -info :loghandler # test multiple view: default listed first test: suffix: 11 requires: defined(PETSC_USE_LOG) output_file: output/ex30_0.out temporaries: default.log flamegraph.log args: -log_view :default.log,:flamegraph.log:ascii_flamegraph # test multiple view: default listed second test: suffix: 12 requires: defined(PETSC_USE_LOG) output_file: output/ex30_0.out temporaries: default.log flamegraph.log args: -log_view :flamegraph.log:ascii_flamegraph,:default.log TEST*/