From 7ac480a2b43b94abfd5d5bf2f40b2c1ed75a6fcb Mon Sep 17 00:00:00 2001 From: Aurele MAHEO Date: Wed, 30 Nov 2016 15:46:53 -0800 Subject: [PATCH 01/60] MPC: When running mm example with several processes (p>1), some profile files are missing or empty (zero bytes), and when export TAU_PROFILE_FORMAT=merged, xml file is not generated. TAU MPI functions especially MPI_Finalize() are not called. BUG FIX: it seems the MPC wrapper for MPI_Finalize() inside src/wrappers/mpc_mpi is calling MPC internals. So we add code for generating profile files inside this wrapping function. Seems to solve the bug. Bug fix to be improved. Former-commit-id: b446cbe40bf19f631a2868d7bc6aee05a7b7b8ed --- examples/mm/matmult.c | 6 ++++-- src/Profile/TauMpi.c | 11 ++++++++++- src/wrappers/mpc_mpi/wr.c | 22 ++++++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/examples/mm/matmult.c b/examples/mm/matmult.c index 0c14948b9..8cda9998c 100644 --- a/examples/mm/matmult.c +++ b/examples/mm/matmult.c @@ -100,7 +100,7 @@ void compute(double **a, double **b, double **c, int rows_a, int cols_a, int col { /*** Do matrix multiply sharing iterations on outer loop ***/ /*** Display who does which iterations for demonstration purposes ***/ -#pragma omp for nowait +#pragma omp for schedule(dynamic) nowait for (i=0; i #include +#include /********************************************************** MPI_Default_error @@ -2153,10 +2154,31 @@ int __real_MPI_Finalize() ; int __wrap_MPI_Finalize() { int retval; + fprintf(stdout, "Wrapper to MPI_Finalize() for MPC\n"); TAU_PROFILE_TIMER(t,"int MPI_Finalize() C", "", TAU_USER); + +Tau_metadataMerge_mergeMetaData(); + + /* Create a merged profile if requested */ + if (TauEnv_get_profile_format() == TAU_FORMAT_MERGED) { + /* *CWL* - properly record intermediate values (the same way snapshots work). + * Note that we do not want to shut down the timers as yet. There is + * still potentially life after MPI_Finalize where TAU is concerned. + * */ + /* KAH - NO! this is the wrong time to do this. THis is also done in the + * * snapshot writer. If you do it twice, you get double values for main... */ + /* TauProfiler_updateAllIntermediateStatistics(); */ + Tau_mergeProfiles(); + } + + TAU_PROFILE_START(t); retval = __real_MPI_Finalize(); TAU_PROFILE_STOP(t); + + Tau_stop_top_level_timer_if_necessary(); + //tau_mpi_finalized = 1; + return retval; } From 5758cf15d646a120f75dcff4a1f3e786fa433b9d Mon Sep 17 00:00:00 2001 From: Aurele MAHEO Date: Tue, 6 Dec 2016 19:59:16 -0800 Subject: [PATCH 02/60] declare function in a separate cpp file to generate profiling inside MPC wrapper of MPI_Finalize() function: still buggy when P (number of processes) <> N (number of tasks) Former-commit-id: afa025c11003e6b215c68a9ee5661d6accc8af29 --- examples/mm/Makefile | 1 + src/Profile/TauMetaDataMerge.cpp | 90 ++++++++++++++++++++ src/Profile/TauMpi.c | 1 + src/wrappers/mpc_mpi/Makefile | 21 ++++- src/wrappers/mpc_mpi/gen_prof.cpp | 99 ++++++++++++++++++++++ src/wrappers/mpc_mpi/link_options.tau | 2 +- src/wrappers/mpc_mpi/wr.c | 113 +++++++++++++++++++++++++- 7 files changed, 320 insertions(+), 7 deletions(-) create mode 100644 src/wrappers/mpc_mpi/gen_prof.cpp diff --git a/examples/mm/Makefile b/examples/mm/Makefile index 955cd1914..4d84920b6 100644 --- a/examples/mm/Makefile +++ b/examples/mm/Makefile @@ -18,6 +18,7 @@ include $(TAU_MAKEFILE) #CC = TAU_MAKEFILE=$(TAU_MAKEFILE) $(TAU_PREFIX_INSTALL_DIR)/$(CONFIG_ARCH)/bin/tau_cc.sh -optKeepFiles -optNoCompInst -optLinkOnly CC = TAU_MAKEFILE=$(TAU_MAKEFILE) $(TAU_PREFIX_INSTALL_DIR)/$(CONFIG_ARCH)/bin/tau_cc.sh +#CC = TAU_MAKEFILE=$(TAU_MAKEFILE) $(TAU_PREFIX_INSTALL_DIR)/$(CONFIG_ARCH)/bin/tau_cxx.sh #CC = opencc -fopenmp #CC = icc -pthread -DPTHREADS #CC = $(TAU_CC) -fopenmp diff --git a/src/Profile/TauMetaDataMerge.cpp b/src/Profile/TauMetaDataMerge.cpp index e26f3183e..ac8309743 100644 --- a/src/Profile/TauMetaDataMerge.cpp +++ b/src/Profile/TauMetaDataMerge.cpp @@ -29,6 +29,81 @@ using namespace std; extern "C" int TAU_MPI_Finalized(); +extern "C" int Tau_metadataMerge_mergeMetaData_bis() { +//extern int Tau_metadataMerge_mergeMetaData_bis() { + + Tau_metadata_fillMetaData(); + + static int merged = 0; + if (merged == 1) { + return 0; + } + merged = 1; + + int rank = 0; + +#ifdef TAU_MPI + int numRanks; + if (TAU_MPI_Finalized()) { + fprintf(stdout, "TAU_MPI_Finalized() called\n"); + return 0; + } + + PMPI_Comm_rank(MPI_COMM_WORLD, &rank); + PMPI_Comm_size(MPI_COMM_WORLD, &numRanks); + + TAU_VERBOSE("TAU: rank=%d, numRanks=%d\n", rank, numRanks); +#endif /* TAU_MPI */ + + x_uint64 start, end; + +#if 1 + if (rank == 0) { + + TAU_VERBOSE("TAU: Merging MetaData...\n"); + start = TauMetrics_getTimeOfDay(); + +#if 1 +#ifdef TAU_MPI + Tau_util_outputDevice *out = Tau_metadata_generateMergeBuffer(); + char *defBuf = Tau_util_getOutputBuffer(out); + int defBufSize = Tau_util_getOutputBufferLength(out); + + //PMPI_Bcast(&defBufSize, 1, MPI_INT, 0, MPI_COMM_WORLD); + //PMPI_Bcast(defBuf, defBufSize, MPI_CHAR, 0, MPI_COMM_WORLD); +#endif /* TAU_MPI */ +#endif + + end = TauMetrics_getTimeOfDay(); + TAU_VERBOSE("TAU: MetaData Merging Complete, duration = %.4G seconds\n", ((double)(end-start))/1000000.0f); + char tmpstr[256]; + sprintf(tmpstr, "%.4G seconds", ((double)(end-start))/1000000.0f); + TAU_METADATA("TAU MetaData Merge Time", tmpstr); + +#if 0 +#ifdef TAU_MPI + Tau_util_destroyOutputDevice(out); +#endif /* TAU_MPI */ +#endif + + } else { + +#if 0 +#ifdef TAU_MPI + TAU_VERBOSE("TAU: Metadata, rank different from 0\n"); + int BufferSize; + PMPI_Bcast(&BufferSize, 1, MPI_INT, 0, MPI_COMM_WORLD); + char *Buffer = (char*) TAU_UTIL_MALLOC(BufferSize); + PMPI_Bcast(Buffer, BufferSize, MPI_CHAR, 0, MPI_COMM_WORLD); + Tau_metadata_removeDuplicates(Buffer, BufferSize); + free(Buffer); +#endif /* TAU_MPI */ +#endif + } +#endif + + return 0; +} extern "C" int Tau_metadataMerge_mergeMetaData() { @@ -45,20 +120,25 @@ extern "C" int Tau_metadataMerge_mergeMetaData() { #ifdef TAU_MPI int numRanks; if (TAU_MPI_Finalized()) { + fprintf(stdout, "TAU_MPI_Finalized() called\n"); return 0; } PMPI_Comm_rank(MPI_COMM_WORLD, &rank); PMPI_Comm_size(MPI_COMM_WORLD, &numRanks); + + TAU_VERBOSE("TAU: rank=%d, numRanks=%d\n", rank, numRanks); #endif /* TAU_MPI */ x_uint64 start, end; +#if 1 if (rank == 0) { TAU_VERBOSE("TAU: Merging MetaData...\n"); start = TauMetrics_getTimeOfDay(); +#if 1 #ifdef TAU_MPI Tau_util_outputDevice *out = Tau_metadata_generateMergeBuffer(); char *defBuf = Tau_util_getOutputBuffer(out); @@ -67,18 +147,25 @@ extern "C" int Tau_metadataMerge_mergeMetaData() { PMPI_Bcast(&defBufSize, 1, MPI_INT, 0, MPI_COMM_WORLD); PMPI_Bcast(defBuf, defBufSize, MPI_CHAR, 0, MPI_COMM_WORLD); #endif /* TAU_MPI */ +#endif end = TauMetrics_getTimeOfDay(); TAU_VERBOSE("TAU: MetaData Merging Complete, duration = %.4G seconds\n", ((double)(end-start))/1000000.0f); char tmpstr[256]; sprintf(tmpstr, "%.4G seconds", ((double)(end-start))/1000000.0f); TAU_METADATA("TAU MetaData Merge Time", tmpstr); + +#if 1 #ifdef TAU_MPI Tau_util_destroyOutputDevice(out); #endif /* TAU_MPI */ +#endif } else { + +#if 1 #ifdef TAU_MPI + TAU_VERBOSE("TAU: Metadata, rank different from 0\n"); int BufferSize; PMPI_Bcast(&BufferSize, 1, MPI_INT, 0, MPI_COMM_WORLD); char *Buffer = (char*) TAU_UTIL_MALLOC(BufferSize); @@ -86,7 +173,10 @@ extern "C" int Tau_metadataMerge_mergeMetaData() { Tau_metadata_removeDuplicates(Buffer, BufferSize); free(Buffer); #endif /* TAU_MPI */ +#endif } +#endif + return 0; } diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index b8c994aa8..f5b1520e9 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -1473,6 +1473,7 @@ MPI_Errhandler errhandler; int tau_mpi_finalized = 0; int TAU_MPI_Finalized() { + fprintf(stdout, "In TAU_MPI_Finalized(): tau_mpi_finalized=%d\n", tau_mpi_finalized); return tau_mpi_finalized; } diff --git a/src/wrappers/mpc_mpi/Makefile b/src/wrappers/mpc_mpi/Makefile index cc980deb2..e1476e878 100644 --- a/src/wrappers/mpc_mpi/Makefile +++ b/src/wrappers/mpc_mpi/Makefile @@ -1,8 +1,12 @@ include ../../../include/Makefile include ../Makefile +OBJS=mpc_mpi_wrap.o gen_prof.o +#OBJS=mpc_mpi_wrap.o gen_trace.o + CC=$(TAU_CC) -CFLAGS=$(TAU_DEFS) $(TAU_INCLUDE) $(TAU_MPI_INCLUDE) -I.. +CXX=$(TAU_CXX) +CFLAGS=$(TAU_DEFS) $(TAU_INCLUDE) $(TAU_MPI_INCLUDE) -I. -I.. -I$(TAUROOT)/include/Profile EXTRA_FLAGS= AR=$(TAU_AR) @@ -17,11 +21,20 @@ install: install-static-mpc install-static-mpc: libmpc_mpi_wrap.a $(TAU_STATIC_INSTALL_CMD) -libmpc_mpi_wrap.a: mpc_mpi_wrap.o - $(AR) $(ARFLAGS) $@ $< +#libmpc_mpi_wrap.a: $(OBJS) +# $(AR) $(ARFLAGS) $@ $< + +libmpc_mpi_wrap.a: $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) mpc_mpi_wrap.o: wr.c $(CC) $(CFLAGS) $(EXTRA_FLAGS) -c $< -o $@ + +gen_prof.o: gen_prof.cpp + $(CXX) $(CFLAGS) $(EXTRA_FLAGS) -c $< -o $@ + +gen_trace.o: gen_trace.c + $(CC) $(CFLAGS) $(EXTRA_FLAGS) -c $< -o $@ clean: - /bin/rm -f mpc_mpi_wrap.o libmpc_mpi_wrap.a + /bin/rm -f mpc_mpi_wrap.o gen_prof.o libmpc_mpi_wrap.a diff --git a/src/wrappers/mpc_mpi/gen_prof.cpp b/src/wrappers/mpc_mpi/gen_prof.cpp new file mode 100644 index 000000000..5c22628d6 --- /dev/null +++ b/src/wrappers/mpc_mpi/gen_prof.cpp @@ -0,0 +1,99 @@ +#include +#include +#include + +#include + +#ifdef TAU_MPI +#include +#endif /* TAU_MPI */ +#include +#include + +//#include "gen_prof.h" + +#if 1 +extern "C" int genProfile() +{ + + //int numRanks; + //PMPI_Comm_rank(MPI_COMM_WORLD, &rank); + //PMPI_Comm_size(MPI_COMM_WORLD, &numRanks); + + //TAU_VERBOSE("TAU - inside genProfile(): rank=%d, numRanks=%d\n", rank, numRanks); + + Tau_metadata_fillMetaData(); + + static int merged = 0; + if (merged == 1) { + return 0; + } + merged = 1; + + int rank = 0; + +#ifdef TAU_MPI + int numRanks; + //if (TAU_MPI_Finalized()) { + // fprintf(stdout, "TAU_MPI_Finalized() called\n"); + // return 0; + //} + + PMPI_Comm_rank(MPI_COMM_WORLD, &rank); + PMPI_Comm_size(MPI_COMM_WORLD, &numRanks); + + TAU_VERBOSE("TAU genProfile: rank=%d, numRanks=%d\n", rank, numRanks); +#endif /* TAU_MPI */ + + x_uint64 start, end; + +#if 1 + if (rank == 0) { + + TAU_VERBOSE("TAU: Merging MetaData...\n"); + start = TauMetrics_getTimeOfDay(); + +#if 1 +#ifdef TAU_MPI + Tau_util_outputDevice *out = Tau_metadata_generateMergeBuffer(); + char *defBuf = Tau_util_getOutputBuffer(out); + int defBufSize = Tau_util_getOutputBufferLength(out); + + PMPI_Bcast(&defBufSize, 1, MPI_INT, 0, MPI_COMM_WORLD); + PMPI_Bcast(defBuf, defBufSize, MPI_CHAR, 0, MPI_COMM_WORLD); +#endif /* TAU_MPI */ +#endif + + end = TauMetrics_getTimeOfDay(); + TAU_VERBOSE("TAU: MetaData Merging Complete, duration = %.4G seconds\n", ((double)(end-start))/1000000.0f); + char tmpstr[256]; + sprintf(tmpstr, "%.4G seconds", ((double)(end-start))/1000000.0f); + TAU_METADATA("TAU MetaData Merge Time", tmpstr); + +#if 1 +#ifdef TAU_MPI + Tau_util_destroyOutputDevice(out); +#endif /* TAU_MPI */ +#endif + + } else { + +#if 1 +#ifdef TAU_MPI + TAU_VERBOSE("TAU: Metadata, rank different from 0\n"); + int BufferSize; + PMPI_Bcast(&BufferSize, 1, MPI_INT, 0, MPI_COMM_WORLD); + char *Buffer = (char*) TAU_UTIL_MALLOC(BufferSize); + PMPI_Bcast(Buffer, BufferSize, MPI_CHAR, 0, MPI_COMM_WORLD); + Tau_metadata_removeDuplicates(Buffer, BufferSize); + free(Buffer); +#endif /* TAU_MPI */ +#endif + } +#endif + + return 0; +} +#endif + + diff --git a/src/wrappers/mpc_mpi/link_options.tau b/src/wrappers/mpc_mpi/link_options.tau index 96f20454d..118df6abb 100644 --- a/src/wrappers/mpc_mpi/link_options.tau +++ b/src/wrappers/mpc_mpi/link_options.tau @@ -1 +1 @@ --Wl,-wrap,MPI_Default_error -Wl,-wrap,MPI_Send -Wl,-wrap,MPI_Recv -Wl,-wrap,MPI_Get_count -Wl,-wrap,MPI_Bsend -Wl,-wrap,MPI_Ssend -Wl,-wrap,MPI_Rsend -Wl,-wrap,MPI_Buffer_attach -Wl,-wrap,MPI_Buffer_detach -Wl,-wrap,MPI_Isend -Wl,-wrap,MPI_Ibsend -Wl,-wrap,MPI_Issend -Wl,-wrap,MPI_Irsend -Wl,-wrap,MPI_Irecv -Wl,-wrap,MPI_Wait -Wl,-wrap,MPI_Test -Wl,-wrap,MPI_Request_free -Wl,-wrap,MPI_Waitany -Wl,-wrap,MPI_Testany -Wl,-wrap,MPI_Waitall -Wl,-wrap,MPI_Testall -Wl,-wrap,MPI_Waitsome -Wl,-wrap,MPI_Testsome -Wl,-wrap,MPI_Iprobe -Wl,-wrap,MPI_Probe -Wl,-wrap,MPI_Cancel -Wl,-wrap,MPI_Test_cancelled -Wl,-wrap,MPI_Send_init -Wl,-wrap,MPI_Bsend_init -Wl,-wrap,MPI_Ssend_init -Wl,-wrap,MPI_Rsend_init -Wl,-wrap,MPI_Recv_init -Wl,-wrap,MPI_Start -Wl,-wrap,MPI_Startall -Wl,-wrap,MPI_Sendrecv -Wl,-wrap,MPI_Sendrecv_replace -Wl,-wrap,MPI_Type_contiguous -Wl,-wrap,MPI_Type_vector -Wl,-wrap,MPI_Type_hvector -Wl,-wrap,MPI_Type_indexed -Wl,-wrap,MPI_Type_hindexed -Wl,-wrap,MPI_Type_struct -Wl,-wrap,MPI_Address -Wl,-wrap,MPI_Type_extent -Wl,-wrap,MPI_Type_size -Wl,-wrap,MPI_Type_lb -Wl,-wrap,MPI_Type_ub -Wl,-wrap,MPI_Type_commit -Wl,-wrap,MPI_Type_free -Wl,-wrap,MPI_Get_elements -Wl,-wrap,MPI_Pack -Wl,-wrap,MPI_Unpack -Wl,-wrap,MPI_Pack_size -Wl,-wrap,MPI_Barrier -Wl,-wrap,MPI_Bcast -Wl,-wrap,MPI_Gather -Wl,-wrap,MPI_Gatherv -Wl,-wrap,MPI_Scatter -Wl,-wrap,MPI_Scatterv -Wl,-wrap,MPI_Allgather -Wl,-wrap,MPI_Allgatherv -Wl,-wrap,MPI_Alltoall -Wl,-wrap,MPI_Alltoallv -Wl,-wrap,MPI_Reduce -Wl,-wrap,MPI_Op_create -Wl,-wrap,MPI_Op_free -Wl,-wrap,MPI_Allreduce -Wl,-wrap,MPI_Reduce_scatter -Wl,-wrap,MPI_Scan -Wl,-wrap,MPI_Group_size -Wl,-wrap,MPI_Group_rank -Wl,-wrap,MPI_Group_translate_ranks -Wl,-wrap,MPI_Group_compare -Wl,-wrap,MPI_Comm_group -Wl,-wrap,MPI_Group_union -Wl,-wrap,MPI_Group_intersection -Wl,-wrap,MPI_Group_difference -Wl,-wrap,MPI_Group_incl -Wl,-wrap,MPI_Group_excl -Wl,-wrap,MPI_Group_range_incl -Wl,-wrap,MPI_Group_range_excl -Wl,-wrap,MPI_Group_free -Wl,-wrap,MPI_Comm_size -Wl,-wrap,MPI_Comm_rank -Wl,-wrap,MPI_Comm_compare -Wl,-wrap,MPI_Comm_dup -Wl,-wrap,MPI_Comm_create -Wl,-wrap,MPI_Comm_split -Wl,-wrap,MPI_Comm_free -Wl,-wrap,MPI_Comm_test_inter -Wl,-wrap,MPI_Comm_remote_size -Wl,-wrap,MPI_Comm_remote_group -Wl,-wrap,MPI_Intercomm_create -Wl,-wrap,MPI_Intercomm_merge -Wl,-wrap,MPI_Keyval_create -Wl,-wrap,MPI_Keyval_free -Wl,-wrap,MPI_Attr_put -Wl,-wrap,MPI_Attr_get -Wl,-wrap,MPI_Attr_delete -Wl,-wrap,MPI_Topo_test -Wl,-wrap,MPI_Cart_create -Wl,-wrap,MPI_Dims_create -Wl,-wrap,MPI_Graph_create -Wl,-wrap,MPI_Graphdims_get -Wl,-wrap,MPI_Graph_get -Wl,-wrap,MPI_Cartdim_get -Wl,-wrap,MPI_Cart_get -Wl,-wrap,MPI_Cart_rank -Wl,-wrap,MPI_Cart_coords -Wl,-wrap,MPI_Graph_neighbors_count -Wl,-wrap,MPI_Graph_neighbors -Wl,-wrap,MPI_Cart_shift -Wl,-wrap,MPI_Cart_sub -Wl,-wrap,MPI_Cart_map -Wl,-wrap,MPI_Graph_map -Wl,-wrap,MPI_Get_processor_name -Wl,-wrap,MPI_Get_version -Wl,-wrap,MPI_Errhandler_create -Wl,-wrap,MPI_Errhandler_set -Wl,-wrap,MPI_Errhandler_get -Wl,-wrap,MPI_Errhandler_free -Wl,-wrap,MPI_Error_string -Wl,-wrap,MPI_Error_class -Wl,-wrap,MPI_Wtime -Wl,-wrap,MPI_Wtick -Wl,-wrap,MPI_Init -Wl,-wrap,MPI_Finalize -Wl,-wrap,MPI_Initialized -Wl,-wrap,MPI_Abort -Wl,-wrap,MPI_Comm_get_name -Wl,-wrap,MPI_Comm_set_name -Wl,-wrap,PMPI_Send -Wl,-wrap,PMPI_Recv -Wl,-wrap,PMPI_Get_count -Wl,-wrap,PMPI_Bsend -Wl,-wrap,PMPI_Ssend -Wl,-wrap,PMPI_Rsend -Wl,-wrap,PMPI_Isend -Wl,-wrap,PMPI_Ibsend -Wl,-wrap,PMPI_Issend -Wl,-wrap,PMPI_Irsend -Wl,-wrap,PMPI_Irecv -Wl,-wrap,PMPI_Wait -Wl,-wrap,PMPI_Test -Wl,-wrap,PMPI_Waitany -Wl,-wrap,PMPI_Testany -Wl,-wrap,PMPI_Waitall -Wl,-wrap,PMPI_Testall -Wl,-wrap,PMPI_Waitsome -Wl,-wrap,PMPI_Testsome -Wl,-wrap,PMPI_Iprobe -Wl,-wrap,PMPI_Probe -Wl,-wrap,PMPI_Send_init -Wl,-wrap,PMPI_Bsend_init -Wl,-wrap,PMPI_Ssend_init -Wl,-wrap,PMPI_Rsend_init -Wl,-wrap,PMPI_Recv_init -Wl,-wrap,PMPI_Startall -Wl,-wrap,PMPI_Sendrecv -Wl,-wrap,PMPI_Sendrecv_replace -Wl,-wrap,PMPI_Type_contiguous -Wl,-wrap,PMPI_Type_vector -Wl,-wrap,PMPI_Type_hvector -Wl,-wrap,PMPI_Type_indexed -Wl,-wrap,PMPI_Type_hindexed -Wl,-wrap,PMPI_Type_struct -Wl,-wrap,PMPI_Address -Wl,-wrap,PMPI_Type_extent -Wl,-wrap,PMPI_Type_lb -Wl,-wrap,PMPI_Type_ub -Wl,-wrap,PMPI_Get_elements -Wl,-wrap,PMPI_Pack -Wl,-wrap,PMPI_Unpack -Wl,-wrap,PMPI_Pack_size -Wl,-wrap,PMPI_Bcast -Wl,-wrap,PMPI_Gather -Wl,-wrap,PMPI_Gatherv -Wl,-wrap,PMPI_Scatter -Wl,-wrap,PMPI_Scatterv -Wl,-wrap,PMPI_Allgather -Wl,-wrap,PMPI_Allgatherv -Wl,-wrap,PMPI_Alltoall -Wl,-wrap,PMPI_Alltoallv -Wl,-wrap,PMPI_Reduce -Wl,-wrap,PMPI_Op_create -Wl,-wrap,PMPI_Allreduce -Wl,-wrap,PMPI_Reduce_scatter -Wl,-wrap,PMPI_Scan -Wl,-wrap,PMPI_Group_translate_ranks -Wl,-wrap,PMPI_Group_compare -Wl,-wrap,PMPI_Comm_group -Wl,-wrap,PMPI_Group_union -Wl,-wrap,PMPI_Group_intersection -Wl,-wrap,PMPI_Group_difference -Wl,-wrap,PMPI_Group_incl -Wl,-wrap,PMPI_Group_excl -Wl,-wrap,PMPI_Group_range_incl -Wl,-wrap,PMPI_Group_range_excl -Wl,-wrap,PMPI_Comm_compare -Wl,-wrap,PMPI_Comm_dup -Wl,-wrap,PMPI_Comm_create -Wl,-wrap,PMPI_Comm_split -Wl,-wrap,PMPI_Comm_remote_group -Wl,-wrap,PMPI_Intercomm_create -Wl,-wrap,PMPI_Intercomm_merge -Wl,-wrap,PMPI_Keyval_create -Wl,-wrap,PMPI_Cart_create -Wl,-wrap,PMPI_Graph_create -Wl,-wrap,PMPI_Cart_sub -Wl,-wrap,PMPI_Errhandler_create -Wl,-wrap,PMPI_Errhandler_set -Wl,-wrap,PMPI_Errhandler_get -Wl,-wrap,MPI_Init_thread -lmpc_mpi_wrap +-Wl,-wrap,MPI_Default_error -Wl,-wrap,MPI_Send -Wl,-wrap,MPI_Recv -Wl,-wrap,MPI_Get_count -Wl,-wrap,MPI_Bsend -Wl,-wrap,MPI_Ssend -Wl,-wrap,MPI_Rsend -Wl,-wrap,MPI_Buffer_attach -Wl,-wrap,MPI_Buffer_detach -Wl,-wrap,MPI_Isend -Wl,-wrap,MPI_Ibsend -Wl,-wrap,MPI_Issend -Wl,-wrap,MPI_Irsend -Wl,-wrap,MPI_Irecv -Wl,-wrap,MPI_Wait -Wl,-wrap,MPI_Test -Wl,-wrap,MPI_Request_free -Wl,-wrap,MPI_Waitany -Wl,-wrap,MPI_Testany -Wl,-wrap,MPI_Waitall -Wl,-wrap,MPI_Testall -Wl,-wrap,MPI_Waitsome -Wl,-wrap,MPI_Testsome -Wl,-wrap,MPI_Iprobe -Wl,-wrap,MPI_Probe -Wl,-wrap,MPI_Cancel -Wl,-wrap,MPI_Test_cancelled -Wl,-wrap,MPI_Send_init -Wl,-wrap,MPI_Bsend_init -Wl,-wrap,MPI_Ssend_init -Wl,-wrap,MPI_Rsend_init -Wl,-wrap,MPI_Recv_init -Wl,-wrap,MPI_Start -Wl,-wrap,MPI_Startall -Wl,-wrap,MPI_Sendrecv -Wl,-wrap,MPI_Sendrecv_replace -Wl,-wrap,MPI_Type_contiguous -Wl,-wrap,MPI_Type_vector -Wl,-wrap,MPI_Type_hvector -Wl,-wrap,MPI_Type_indexed -Wl,-wrap,MPI_Type_hindexed -Wl,-wrap,MPI_Type_struct -Wl,-wrap,MPI_Address -Wl,-wrap,MPI_Type_extent -Wl,-wrap,MPI_Type_size -Wl,-wrap,MPI_Type_lb -Wl,-wrap,MPI_Type_ub -Wl,-wrap,MPI_Type_commit -Wl,-wrap,MPI_Type_free -Wl,-wrap,MPI_Get_elements -Wl,-wrap,MPI_Pack -Wl,-wrap,MPI_Unpack -Wl,-wrap,MPI_Pack_size -Wl,-wrap,MPI_Barrier -Wl,-wrap,MPI_Bcast -Wl,-wrap,MPI_Gather -Wl,-wrap,MPI_Gatherv -Wl,-wrap,MPI_Scatter -Wl,-wrap,MPI_Scatterv -Wl,-wrap,MPI_Allgather -Wl,-wrap,MPI_Allgatherv -Wl,-wrap,MPI_Alltoall -Wl,-wrap,MPI_Alltoallv -Wl,-wrap,MPI_Reduce -Wl,-wrap,MPI_Op_create -Wl,-wrap,MPI_Op_free -Wl,-wrap,MPI_Allreduce -Wl,-wrap,MPI_Reduce_scatter -Wl,-wrap,MPI_Scan -Wl,-wrap,MPI_Group_size -Wl,-wrap,MPI_Group_rank -Wl,-wrap,MPI_Group_translate_ranks -Wl,-wrap,MPI_Group_compare -Wl,-wrap,MPI_Comm_group -Wl,-wrap,MPI_Group_union -Wl,-wrap,MPI_Group_intersection -Wl,-wrap,MPI_Group_difference -Wl,-wrap,MPI_Group_incl -Wl,-wrap,MPI_Group_excl -Wl,-wrap,MPI_Group_range_incl -Wl,-wrap,MPI_Group_range_excl -Wl,-wrap,MPI_Group_free -Wl,-wrap,MPI_Comm_size -Wl,-wrap,MPI_Comm_rank -Wl,-wrap,MPI_Comm_compare -Wl,-wrap,MPI_Comm_dup -Wl,-wrap,MPI_Comm_create -Wl,-wrap,MPI_Comm_split -Wl,-wrap,MPI_Comm_free -Wl,-wrap,MPI_Comm_test_inter -Wl,-wrap,MPI_Comm_remote_size -Wl,-wrap,MPI_Comm_remote_group -Wl,-wrap,MPI_Intercomm_create -Wl,-wrap,MPI_Intercomm_merge -Wl,-wrap,MPI_Keyval_create -Wl,-wrap,MPI_Keyval_free -Wl,-wrap,MPI_Attr_put -Wl,-wrap,MPI_Attr_get -Wl,-wrap,MPI_Attr_delete -Wl,-wrap,MPI_Topo_test -Wl,-wrap,MPI_Cart_create -Wl,-wrap,MPI_Dims_create -Wl,-wrap,MPI_Graph_create -Wl,-wrap,MPI_Graphdims_get -Wl,-wrap,MPI_Graph_get -Wl,-wrap,MPI_Cartdim_get -Wl,-wrap,MPI_Cart_get -Wl,-wrap,MPI_Cart_rank -Wl,-wrap,MPI_Cart_coords -Wl,-wrap,MPI_Graph_neighbors_count -Wl,-wrap,MPI_Graph_neighbors -Wl,-wrap,MPI_Cart_shift -Wl,-wrap,MPI_Cart_sub -Wl,-wrap,MPI_Cart_map -Wl,-wrap,MPI_Graph_map -Wl,-wrap,MPI_Get_processor_name -Wl,-wrap,MPI_Get_version -Wl,-wrap,MPI_Errhandler_create -Wl,-wrap,MPI_Errhandler_set -Wl,-wrap,MPI_Errhandler_get -Wl,-wrap,MPI_Errhandler_free -Wl,-wrap,MPI_Error_string -Wl,-wrap,MPI_Error_class -Wl,-wrap,MPI_Wtime -Wl,-wrap,MPI_Wtick -Wl,-wrap,MPI_Init -Wl,-wrap,MPI_Finalize -Wl,-wrap,MPI_Initialized -Wl,-wrap,MPI_Abort -Wl,-wrap,MPI_Comm_get_name -Wl,-wrap,MPI_Comm_set_name -Wl,-wrap,PMPI_Send -Wl,-wrap,PMPI_Recv -Wl,-wrap,PMPI_Get_count -Wl,-wrap,PMPI_Bsend -Wl,-wrap,PMPI_Ssend -Wl,-wrap,PMPI_Rsend -Wl,-wrap,PMPI_Isend -Wl,-wrap,PMPI_Ibsend -Wl,-wrap,PMPI_Issend -Wl,-wrap,PMPI_Irsend -Wl,-wrap,PMPI_Irecv -Wl,-wrap,PMPI_Wait -Wl,-wrap,PMPI_Test -Wl,-wrap,PMPI_Waitany -Wl,-wrap,PMPI_Testany -Wl,-wrap,PMPI_Waitall -Wl,-wrap,PMPI_Testall -Wl,-wrap,PMPI_Waitsome -Wl,-wrap,PMPI_Testsome -Wl,-wrap,PMPI_Iprobe -Wl,-wrap,PMPI_Probe -Wl,-wrap,PMPI_Send_init -Wl,-wrap,PMPI_Bsend_init -Wl,-wrap,PMPI_Ssend_init -Wl,-wrap,PMPI_Rsend_init -Wl,-wrap,PMPI_Recv_init -Wl,-wrap,PMPI_Startall -Wl,-wrap,PMPI_Sendrecv -Wl,-wrap,PMPI_Sendrecv_replace -Wl,-wrap,PMPI_Type_contiguous -Wl,-wrap,PMPI_Type_vector -Wl,-wrap,PMPI_Type_hvector -Wl,-wrap,PMPI_Type_indexed -Wl,-wrap,PMPI_Type_hindexed -Wl,-wrap,PMPI_Type_struct -Wl,-wrap,PMPI_Address -Wl,-wrap,PMPI_Type_extent -Wl,-wrap,PMPI_Type_lb -Wl,-wrap,PMPI_Type_ub -Wl,-wrap,PMPI_Get_elements -Wl,-wrap,PMPI_Pack -Wl,-wrap,PMPI_Unpack -Wl,-wrap,PMPI_Pack_size -Wl,-wrap,PMPI_Bcast -Wl,-wrap,PMPI_Gather -Wl,-wrap,PMPI_Gatherv -Wl,-wrap,PMPI_Scatter -Wl,-wrap,PMPI_Scatterv -Wl,-wrap,PMPI_Allgather -Wl,-wrap,PMPI_Allgatherv -Wl,-wrap,PMPI_Alltoall -Wl,-wrap,PMPI_Alltoallv -Wl,-wrap,PMPI_Reduce -Wl,-wrap,PMPI_Op_create -Wl,-wrap,PMPI_Allreduce -Wl,-wrap,PMPI_Reduce_scatter -Wl,-wrap,PMPI_Scan -Wl,-wrap,PMPI_Group_translate_ranks -Wl,-wrap,PMPI_Group_compare -Wl,-wrap,PMPI_Comm_group -Wl,-wrap,PMPI_Group_union -Wl,-wrap,PMPI_Group_intersection -Wl,-wrap,PMPI_Group_difference -Wl,-wrap,PMPI_Group_incl -Wl,-wrap,PMPI_Group_excl -Wl,-wrap,PMPI_Group_range_incl -Wl,-wrap,PMPI_Group_range_excl -Wl,-wrap,PMPI_Comm_compare -Wl,-wrap,PMPI_Comm_dup -Wl,-wrap,PMPI_Comm_create -Wl,-wrap,PMPI_Comm_split -Wl,-wrap,PMPI_Comm_remote_group -Wl,-wrap,PMPI_Intercomm_create -Wl,-wrap,PMPI_Intercomm_merge -Wl,-wrap,PMPI_Keyval_create -Wl,-wrap,PMPI_Cart_create -Wl,-wrap,PMPI_Graph_create -Wl,-wrap,PMPI_Cart_sub -Wl,-wrap,PMPI_Errhandler_create -Wl,-wrap,PMPI_Errhandler_set -Wl,-wrap,PMPI_Errhandler_get -Wl,-wrap,MPI_Init_thread -lmpc_mpi_wrap diff --git a/src/wrappers/mpc_mpi/wr.c b/src/wrappers/mpc_mpi/wr.c index 7ffb93f26..86b4f8432 100644 --- a/src/wrappers/mpc_mpi/wr.c +++ b/src/wrappers/mpc_mpi/wr.c @@ -4,6 +4,14 @@ #include +#ifdef TAU_MPI +#include +#endif /* TAU_MPI */ +//#include "gen_prof.h" +//#include +//#include + + /********************************************************** MPI_Default_error **********************************************************/ @@ -2145,6 +2153,94 @@ int __wrap_MPI_Init(int * a1, char *** a2) { } +int genProfileFake() +{ + return 0; +} + +#if 0 +int genProfile() +{ + + //int numRanks; + //PMPI_Comm_rank(MPI_COMM_WORLD, &rank); + //PMPI_Comm_size(MPI_COMM_WORLD, &numRanks); + + //TAU_VERBOSE("TAU - inside genProfile(): rank=%d, numRanks=%d\n", rank, numRanks); + + Tau_metadata_fillMetaData(); + + static int merged = 0; + if (merged == 1) { + return 0; + } + merged = 1; + + int rank = 0; + +#ifdef TAU_MPI + int numRanks; + //if (TAU_MPI_Finalized()) { + // fprintf(stdout, "TAU_MPI_Finalized() called\n"); + // return 0; + //} + + PMPI_Comm_rank(MPI_COMM_WORLD, &rank); + PMPI_Comm_size(MPI_COMM_WORLD, &numRanks); + + TAU_VERBOSE("TAU: rank=%d, numRanks=%d\n", rank, numRanks); +#endif /* TAU_MPI */ + + x_uint64 start, end; + +#if 1 + if (rank == 0) { + + TAU_VERBOSE("TAU: Merging MetaData...\n"); + start = TauMetrics_getTimeOfDay(); + +#if 1 +#ifdef TAU_MPI + Tau_util_outputDevice *out = Tau_metadata_generateMergeBuffer(); + char *defBuf = Tau_util_getOutputBuffer(out); + int defBufSize = Tau_util_getOutputBufferLength(out); + + PMPI_Bcast(&defBufSize, 1, MPI_INT, 0, MPI_COMM_WORLD); + PMPI_Bcast(defBuf, defBufSize, MPI_CHAR, 0, MPI_COMM_WORLD); +#endif /* TAU_MPI */ +#endif + + end = TauMetrics_getTimeOfDay(); + TAU_VERBOSE("TAU: MetaData Merging Complete, duration = %.4G seconds\n", ((double)(end-start))/1000000.0f); + char tmpstr[256]; + sprintf(tmpstr, "%.4G seconds", ((double)(end-start))/1000000.0f); + TAU_METADATA("TAU MetaData Merge Time", tmpstr); + +#if 1 +#ifdef TAU_MPI + Tau_util_destroyOutputDevice(out); +#endif /* TAU_MPI */ +#endif + + } else { + +#if 1 +#ifdef TAU_MPI + TAU_VERBOSE("TAU: Metadata, rank different from 0\n"); + int BufferSize; + PMPI_Bcast(&BufferSize, 1, MPI_INT, 0, MPI_COMM_WORLD); + char *Buffer = (char*) TAU_UTIL_MALLOC(BufferSize); + PMPI_Bcast(Buffer, BufferSize, MPI_CHAR, 0, MPI_COMM_WORLD); + Tau_metadata_removeDuplicates(Buffer, BufferSize); + free(Buffer); +#endif /* TAU_MPI */ +#endif + } +#endif + + return 0; +} +#endif /********************************************************** MPI_Finalize @@ -2157,7 +2253,17 @@ int __wrap_MPI_Finalize() { fprintf(stdout, "Wrapper to MPI_Finalize() for MPC\n"); TAU_PROFILE_TIMER(t,"int MPI_Finalize() C", "", TAU_USER); -Tau_metadataMerge_mergeMetaData(); +#if 1 + int rank = 0; + int numRanks; + PMPI_Comm_rank(MPI_COMM_WORLD, &rank); + PMPI_Comm_size(MPI_COMM_WORLD, &numRanks); + + TAU_VERBOSE("TAU - inside MPI_Finalize MPC wrapper: rank=%d, numRanks=%d\n", rank, numRanks); + + //Tau_metadataMerge_mergeMetaData_bis(); + //genTrace(); + genProfile(); /* Create a merged profile if requested */ if (TauEnv_get_profile_format() == TAU_FORMAT_MERGED) { @@ -2168,16 +2274,19 @@ Tau_metadataMerge_mergeMetaData(); /* KAH - NO! this is the wrong time to do this. THis is also done in the * * snapshot writer. If you do it twice, you get double values for main... */ /* TauProfiler_updateAllIntermediateStatistics(); */ + fprintf(stdout, "Merge profiles\n"); Tau_mergeProfiles(); } - +#endif TAU_PROFILE_START(t); retval = __real_MPI_Finalize(); TAU_PROFILE_STOP(t); +#if 1 Tau_stop_top_level_timer_if_necessary(); //tau_mpi_finalized = 1; +#endif return retval; From 23d96042ddbe80a3ef1e7c3f16e8039297c8225c Mon Sep 17 00:00:00 2001 From: Aurele MAHEO Date: Wed, 7 Dec 2016 17:23:19 -0800 Subject: [PATCH 03/60] Use function in Profile sources to generate profiling in MPI_Finalize wrapper: do not tests MPI_Finalized() function Former-commit-id: a44e6575e125f0dd5c428aa1fcc6becddabc81b8 --- src/Profile/TauMetaDataMerge.cpp | 21 +++++++++++---------- src/wrappers/mpc_mpi/gen_prof.cpp | 19 ++++++++++++++++++- src/wrappers/mpc_mpi/wr.c | 14 ++++++++++++-- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/Profile/TauMetaDataMerge.cpp b/src/Profile/TauMetaDataMerge.cpp index ac8309743..b633c6820 100644 --- a/src/Profile/TauMetaDataMerge.cpp +++ b/src/Profile/TauMetaDataMerge.cpp @@ -30,29 +30,30 @@ using namespace std; extern "C" int TAU_MPI_Finalized(); extern "C" int Tau_metadataMerge_mergeMetaData_bis() { -//extern int Tau_metadataMerge_mergeMetaData_bis() { Tau_metadata_fillMetaData(); +#if 1 static int merged = 0; if (merged == 1) { return 0; } merged = 1; +#endif int rank = 0; #ifdef TAU_MPI int numRanks; - if (TAU_MPI_Finalized()) { - fprintf(stdout, "TAU_MPI_Finalized() called\n"); - return 0; - } + //if (TAU_MPI_Finalized()) { + // fprintf(stdout, "TAU_MPI_Finalized() called\n"); + // return 0; + //} PMPI_Comm_rank(MPI_COMM_WORLD, &rank); PMPI_Comm_size(MPI_COMM_WORLD, &numRanks); - TAU_VERBOSE("TAU: rank=%d, numRanks=%d\n", rank, numRanks); + TAU_VERBOSE("TAU Nerge bis: rank=%d, numRanks=%d\n", rank, numRanks); #endif /* TAU_MPI */ x_uint64 start, end; @@ -69,8 +70,8 @@ extern "C" int Tau_metadataMerge_mergeMetaData_bis() { char *defBuf = Tau_util_getOutputBuffer(out); int defBufSize = Tau_util_getOutputBufferLength(out); - //PMPI_Bcast(&defBufSize, 1, MPI_INT, 0, MPI_COMM_WORLD); - //PMPI_Bcast(defBuf, defBufSize, MPI_CHAR, 0, MPI_COMM_WORLD); + PMPI_Bcast(&defBufSize, 1, MPI_INT, 0, MPI_COMM_WORLD); + PMPI_Bcast(defBuf, defBufSize, MPI_CHAR, 0, MPI_COMM_WORLD); #endif /* TAU_MPI */ #endif @@ -80,7 +81,7 @@ extern "C" int Tau_metadataMerge_mergeMetaData_bis() { sprintf(tmpstr, "%.4G seconds", ((double)(end-start))/1000000.0f); TAU_METADATA("TAU MetaData Merge Time", tmpstr); -#if 0 +#if 1 #ifdef TAU_MPI Tau_util_destroyOutputDevice(out); #endif /* TAU_MPI */ @@ -88,7 +89,7 @@ extern "C" int Tau_metadataMerge_mergeMetaData_bis() { } else { -#if 0 +#if 1 #ifdef TAU_MPI TAU_VERBOSE("TAU: Metadata, rank different from 0\n"); int BufferSize; diff --git a/src/wrappers/mpc_mpi/gen_prof.cpp b/src/wrappers/mpc_mpi/gen_prof.cpp index 5c22628d6..bce79a26c 100644 --- a/src/wrappers/mpc_mpi/gen_prof.cpp +++ b/src/wrappers/mpc_mpi/gen_prof.cpp @@ -12,6 +12,21 @@ //#include "gen_prof.h" + +extern "C" int genProfileFakeExtern() +{ + int rank = 0; + int numRanks; + + PMPI_Comm_rank(MPI_COMM_WORLD, &rank); + PMPI_Comm_size(MPI_COMM_WORLD, &numRanks); + + TAU_VERBOSE("TAU - genProfileFake Extern C: rank=%d, numRanks=%d\n", rank, numRanks); + + return 0; +} + + #if 1 extern "C" int genProfile() { @@ -24,11 +39,13 @@ extern "C" int genProfile() Tau_metadata_fillMetaData(); +#if 0 static int merged = 0; if (merged == 1) { return 0; } merged = 1; +#endif int rank = 0; @@ -42,7 +59,7 @@ extern "C" int genProfile() PMPI_Comm_rank(MPI_COMM_WORLD, &rank); PMPI_Comm_size(MPI_COMM_WORLD, &numRanks); - TAU_VERBOSE("TAU genProfile: rank=%d, numRanks=%d\n", rank, numRanks); + TAU_VERBOSE("TAU genProfile extern C: rank=%d, numRanks=%d\n", rank, numRanks); #endif /* TAU_MPI */ x_uint64 start, end; diff --git a/src/wrappers/mpc_mpi/wr.c b/src/wrappers/mpc_mpi/wr.c index 86b4f8432..0013c9d43 100644 --- a/src/wrappers/mpc_mpi/wr.c +++ b/src/wrappers/mpc_mpi/wr.c @@ -2155,6 +2155,14 @@ int __wrap_MPI_Init(int * a1, char *** a2) { int genProfileFake() { + int rank = 0; + int numRanks; + + PMPI_Comm_rank(MPI_COMM_WORLD, &rank); + PMPI_Comm_size(MPI_COMM_WORLD, &numRanks); + + TAU_VERBOSE("TAU - genProfileFake C: rank=%d, numRanks=%d\n", rank, numRanks); + return 0; } @@ -2261,9 +2269,11 @@ int __wrap_MPI_Finalize() { TAU_VERBOSE("TAU - inside MPI_Finalize MPC wrapper: rank=%d, numRanks=%d\n", rank, numRanks); - //Tau_metadataMerge_mergeMetaData_bis(); + Tau_metadataMerge_mergeMetaData_bis(); //genTrace(); - genProfile(); + //genProfile(); + //genProfileFake(); + //genProfileFakeExtern(); /* Create a merged profile if requested */ if (TauEnv_get_profile_format() == TAU_FORMAT_MERGED) { From 24c65d39ce212e55fbeb7e2e6158b2b37569a2c4 Mon Sep 17 00:00:00 2001 From: Aurele MAHEO Date: Wed, 7 Dec 2016 19:50:05 -0800 Subject: [PATCH 04/60] In current state of the code, profiling is buggy with MPC including OMPT support, and TAU built with openmp and ompt flags Former-commit-id: 5a7c3dbc76dc857aedb93944849a2e5ef0e34e14 --- src/Profile/TauMetaDataMerge.cpp | 11 +++++++---- src/wrappers/mpc_mpi/wr.c | 6 +----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Profile/TauMetaDataMerge.cpp b/src/Profile/TauMetaDataMerge.cpp index b633c6820..1ae262d7b 100644 --- a/src/Profile/TauMetaDataMerge.cpp +++ b/src/Profile/TauMetaDataMerge.cpp @@ -45,10 +45,13 @@ extern "C" int Tau_metadataMerge_mergeMetaData_bis() { #ifdef TAU_MPI int numRanks; - //if (TAU_MPI_Finalized()) { - // fprintf(stdout, "TAU_MPI_Finalized() called\n"); - // return 0; - //} + +#if 1 + if (TAU_MPI_Finalized()) { + TAU_VERBOSE("TAU_MPI_Finalized() called\n"); + return 0; + } +#endif PMPI_Comm_rank(MPI_COMM_WORLD, &rank); PMPI_Comm_size(MPI_COMM_WORLD, &numRanks); diff --git a/src/wrappers/mpc_mpi/wr.c b/src/wrappers/mpc_mpi/wr.c index 0013c9d43..1db80b6cf 100644 --- a/src/wrappers/mpc_mpi/wr.c +++ b/src/wrappers/mpc_mpi/wr.c @@ -2270,10 +2270,6 @@ int __wrap_MPI_Finalize() { TAU_VERBOSE("TAU - inside MPI_Finalize MPC wrapper: rank=%d, numRanks=%d\n", rank, numRanks); Tau_metadataMerge_mergeMetaData_bis(); - //genTrace(); - //genProfile(); - //genProfileFake(); - //genProfileFakeExtern(); /* Create a merged profile if requested */ if (TauEnv_get_profile_format() == TAU_FORMAT_MERGED) { @@ -2284,7 +2280,7 @@ int __wrap_MPI_Finalize() { /* KAH - NO! this is the wrong time to do this. THis is also done in the * * snapshot writer. If you do it twice, you get double values for main... */ /* TauProfiler_updateAllIntermediateStatistics(); */ - fprintf(stdout, "Merge profiles\n"); + //fprintf(stdout, "Merge profiles\n"); Tau_mergeProfiles(); } #endif From 2ddd389ba559e52b43385ca49e87e0eb80c6a6b3 Mon Sep 17 00:00:00 2001 From: Aurele MAHEO Date: Wed, 14 Dec 2016 10:59:06 -0800 Subject: [PATCH 05/60] Force using thread identifier 0 when merging profile files and generate xml output (TAU_PROFILE_FORMAT=merged): BUG FIX Former-commit-id: 518938bbd12f269b9218f0c26c2c192369aff4bf --- src/Profile/TauMetaDataMerge.cpp | 16 +++++- src/Profile/TauMpi.c | 2 +- src/Profile/TauProfileMerge.cpp | 2 + src/Profile/TauSnapshot.cpp | 8 ++- src/wrappers/mpc_mpi/wr.c | 90 ++++++++++++++++++++++++++++++-- 5 files changed, 109 insertions(+), 9 deletions(-) diff --git a/src/Profile/TauMetaDataMerge.cpp b/src/Profile/TauMetaDataMerge.cpp index 1ae262d7b..1f7f60a09 100644 --- a/src/Profile/TauMetaDataMerge.cpp +++ b/src/Profile/TauMetaDataMerge.cpp @@ -36,6 +36,7 @@ extern "C" int Tau_metadataMerge_mergeMetaData_bis() { #if 1 static int merged = 0; if (merged == 1) { + TAU_VERBOSE("merged = 1, return\n"); return 0; } merged = 1; @@ -48,7 +49,7 @@ extern "C" int Tau_metadataMerge_mergeMetaData_bis() { #if 1 if (TAU_MPI_Finalized()) { - TAU_VERBOSE("TAU_MPI_Finalized() called\n"); + TAU_VERBOSE("TAU_MPI_Finalized() called, return\n"); return 0; } #endif @@ -56,7 +57,7 @@ extern "C" int Tau_metadataMerge_mergeMetaData_bis() { PMPI_Comm_rank(MPI_COMM_WORLD, &rank); PMPI_Comm_size(MPI_COMM_WORLD, &numRanks); - TAU_VERBOSE("TAU Nerge bis: rank=%d, numRanks=%d\n", rank, numRanks); + TAU_VERBOSE("TAU Merge bis: rank=%d, numRanks=%d\n", rank, numRanks); #endif /* TAU_MPI */ x_uint64 start, end; @@ -90,6 +91,8 @@ extern "C" int Tau_metadataMerge_mergeMetaData_bis() { #endif /* TAU_MPI */ #endif + TAU_VERBOSE("TAU - MetaData bis: end if condition for rank 0\n"); + } else { #if 1 @@ -103,21 +106,30 @@ extern "C" int Tau_metadataMerge_mergeMetaData_bis() { free(Buffer); #endif /* TAU_MPI */ #endif + + TAU_VERBOSE("TAU - MetaData bis: end if condition for other ranks\n"); } #endif + TAU_VERBOSE("Tau_metadataMerge_mergeMetaData_bis END for rank #%d\n", rank); + return 0; } extern "C" int Tau_metadataMerge_mergeMetaData() { + TAU_VERBOSE("Tau_metadataMerge_mergeMetaData() begin\n"); + Tau_metadata_fillMetaData(); +#if 0 static int merged = 0; if (merged == 1) { + TAU_VERBOSE("merged = 1, return\n"); return 0; } merged = 1; +#endif int rank = 0; diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index f5b1520e9..cf05369d0 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -1484,7 +1484,7 @@ int MPI_Finalize( ) char procname[MPI_MAX_PROCESSOR_NAME]; int procnamelength; - fprintf(stdout, "TAU: Call MPI_Finalize()\n"); + TAU_VERBOSE("TAU: Call MPI_Finalize()\n"); TAU_PROFILE_TIMER(tautimer, "MPI_Finalize()", " ", TAU_MESSAGE); TAU_PROFILE_START(tautimer); diff --git a/src/Profile/TauProfileMerge.cpp b/src/Profile/TauProfileMerge.cpp index 92478b044..bfbb0e4a5 100644 --- a/src/Profile/TauProfileMerge.cpp +++ b/src/Profile/TauProfileMerge.cpp @@ -318,10 +318,12 @@ int Tau_mergeProfiles() if (TauEnv_get_summary_only()) { /* write only rank one metadata for summary profile */ if (rank == 0) { + TAU_VERBOSE("Tau Profile merge - rank = 0: write meta data block\n"); Tau_snapshot_writeMetaDataBlock(); } } else { + TAU_VERBOSE("Tau Profile merge - rank <> 0: write meta data block\n"); Tau_snapshot_writeMetaDataBlock(); } diff --git a/src/Profile/TauSnapshot.cpp b/src/Profile/TauSnapshot.cpp index 3c931094a..bb9df9640 100644 --- a/src/Profile/TauSnapshot.cpp +++ b/src/Profile/TauSnapshot.cpp @@ -42,6 +42,8 @@ static Tau_util_outputDevice **Tau_snapshot_getFiles() { snapshotFiles[i] = NULL; } } + + TAU_VERBOSE("Tau_snapshot_getFiles() end: out=%p\n", snapshotFiles); return snapshotFiles; } @@ -118,10 +120,14 @@ extern "C" int Tau_snapshot_writeIntermediate(const char *name) { extern "C" int Tau_snapshot_writeMetaDataBlock() { int tid = RtsLayer::myThread(); - Tau_util_outputDevice *out = Tau_snapshot_getFiles()[tid]; + int totalThreads = RtsLayer::getTotalThreads(); + //Tau_util_outputDevice *out = Tau_snapshot_getFiles()[tid]; + Tau_util_outputDevice *out = Tau_snapshot_getFiles()[0]; char threadid[4096]; sprintf(threadid, "%d.%d.%d.%d", RtsLayer::myNode(), RtsLayer::myContext(), tid, RtsLayer::getPid()); + TAU_VERBOSE("tid=%d, totalThreads=%d\n", tid, totalThreads); + // start of a profile block Tau_util_output (out, "\n"); diff --git a/src/wrappers/mpc_mpi/wr.c b/src/wrappers/mpc_mpi/wr.c index 1db80b6cf..e6da58ba6 100644 --- a/src/wrappers/mpc_mpi/wr.c +++ b/src/wrappers/mpc_mpi/wr.c @@ -2250,6 +2250,14 @@ int genProfile() } #endif +static int procid_0; + +int tau_mpi_finalized = 0; +int TAU_MPI_Finalized() { + fprintf(stdout, "In TAU_MPI_Finalized(): tau_mpi_finalized=%d\n", tau_mpi_finalized); + return tau_mpi_finalized; +} + /********************************************************** MPI_Finalize **********************************************************/ @@ -2258,9 +2266,73 @@ int __real_MPI_Finalize() ; int __wrap_MPI_Finalize() { int retval; - fprintf(stdout, "Wrapper to MPI_Finalize() for MPC\n"); + TAU_VERBOSE("Wrapper to MPI_Finalize() for MPC\n"); TAU_PROFILE_TIMER(t,"int MPI_Finalize() C", "", TAU_USER); + char procname[MPI_MAX_PROCESSOR_NAME]; + int procnamelength; + + TAU_VERBOSE("TAU: Call MPI_Finalize()\n"); + + TAU_PROFILE_TIMER(tautimer, "MPI_Finalize()", " ", TAU_MESSAGE); + TAU_PROFILE_START(tautimer); + +#ifdef TAU_MPI_T + Tau_track_mpi_t_here(); +#endif /* TAU_MPI_T */ + writeMetaDataAfterMPI_Init(); + + if (TauEnv_get_synchronize_clocks()) { + TauSyncFinalClocks(); + } + + PMPI_Get_processor_name(procname, &procnamelength); + TAU_METADATA("MPI Processor Name", procname); + + if (Tau_get_node() < 0) { + /* Grab the node id, we don't always wrap mpi_init */ + PMPI_Comm_rank( MPI_COMM_WORLD, &procid_0 ); + TAU_PROFILE_SET_NODE(procid_0 ); + Tau_set_usesMPI(1); + } + +#ifdef TAU_BGP + /* BGP counters */ + int numCounters, mode, upcErr; + x_uint64 counterVals[1024]; + + if (TauEnv_get_ibm_bg_hwp_counters()) { + PMPI_Barrier(MPI_COMM_WORLD); + Tau_Bg_hwp_counters_stop(&numCounters, counterVals, &mode, &upcErr); + if (upcErr != 0) { + printf(" ** Error stopping UPC performance counters"); + } + + Tau_Bg_hwp_counters_output(&numCounters, counterVals, &mode, &upcErr); + } +#endif /* TAU_BGP */ + +#ifndef TAU_WINDOWS +#ifndef _AIX + /* Shutdown EBS after Finalize to allow Profiles to be written out + * correctly. Also allows profile merging (or unification) to be + * done correctly. */ + if (TauEnv_get_callsite()) { + finalizeCallSites_if_necessary(); + } +#endif /* _AIX */ +#endif /* TAU_WINDOWS */ + +#ifndef TAU_WINDOWS +#ifndef _AIX + if (TauEnv_get_ebs_enabled()) { + // Tau_sampling_finalizeNode(); + // + Tau_sampling_finalize_if_necessary(Tau_get_local_tid()); + } +#endif /* _AIX */ +#endif /* TAU_WINDOWS */ + #if 1 int rank = 0; int numRanks; @@ -2269,8 +2341,12 @@ int __wrap_MPI_Finalize() { TAU_VERBOSE("TAU - inside MPI_Finalize MPC wrapper: rank=%d, numRanks=%d\n", rank, numRanks); - Tau_metadataMerge_mergeMetaData_bis(); + //Tau_metadataMerge_mergeMetaData_bis(); + Tau_metadataMerge_mergeMetaData(); +#endif + TAU_VERBOSE("Merge profile files if MERGED format specified\n"); +#if 1 /* Create a merged profile if requested */ if (TauEnv_get_profile_format() == TAU_FORMAT_MERGED) { /* *CWL* - properly record intermediate values (the same way snapshots work). @@ -2285,13 +2361,17 @@ int __wrap_MPI_Finalize() { } #endif - TAU_PROFILE_START(t); + TAU_VERBOSE("Call real MPI_Finalize\n"); + + //TAU_PROFILE_START(t); retval = __real_MPI_Finalize(); - TAU_PROFILE_STOP(t); + TAU_PROFILE_STOP(tautimer); + + TAU_VERBOSE("Stop timer\n"); #if 1 Tau_stop_top_level_timer_if_necessary(); - //tau_mpi_finalized = 1; + tau_mpi_finalized = 1; #endif return retval; From 1c838ab133e30519a2a2eed35ad35f0ee3084b86 Mon Sep 17 00:00:00 2001 From: Aurele MAHEO Date: Wed, 29 Nov 2017 16:35:25 -0800 Subject: [PATCH 06/60] [TAU MPC] Bug fix: Add necessary TAU functions to wrappers of MPI_Init() and MPI_Finalize() to generate profile files => profile files are generated on matmult example for n=2 and n=4 Former-commit-id: f2847d0db26e348188f7e4d5ec8c7ea39eae86c3 --- src/Profile/TauMpi.c | 2 + src/wrappers/mpc_mpi/wr.c | 239 +++++++++++++++++++++++++++++++++++++- 2 files changed, 238 insertions(+), 3 deletions(-) diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index 69ae49626..465a812ee 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -1820,6 +1820,8 @@ char *** argv; char procname[MPI_MAX_PROCESSOR_NAME]; int procnamelength; + fprintf(stdout, "TAU: MPI_Init() MPC after wrapping\n"); + if(Tau_get_usesMPI() == 0) { diff --git a/src/wrappers/mpc_mpi/wr.c b/src/wrappers/mpc_mpi/wr.c index e6da58ba6..e92b7b908 100644 --- a/src/wrappers/mpc_mpi/wr.c +++ b/src/wrappers/mpc_mpi/wr.c @@ -12,6 +12,8 @@ //#include +static int procid_0; + /********************************************************** MPI_Default_error **********************************************************/ @@ -2144,12 +2146,101 @@ double __wrap_MPI_Wtick() { int __real_MPI_Init(int * a1, char *** a2) ; int __wrap_MPI_Init(int * a1, char *** a2) { +#if 0 int retval; + fprintf(stdout, "TAU wrap MPI_Init for MPC\n"); TAU_PROFILE_TIMER(t,"int MPI_Init(int *, char ***) C", "", TAU_USER); TAU_PROFILE_START(t); retval = __real_MPI_Init(a1, a2); TAU_PROFILE_STOP(t); return retval; +#endif + + int returnVal; + int size; + char procname[MPI_MAX_PROCESSOR_NAME]; + int procnamelength; + + fprintf(stdout, "TAU: MPI_Init() MPC after wrapping\n"); + + if(Tau_get_usesMPI() == 0) + { + + + TAU_PROFILE_TIMER(tautimer, "MPI_Init()", " ", TAU_MESSAGE); + Tau_create_top_level_timer_if_necessary(); + TAU_PROFILE_START(tautimer); + + tau_mpi_init_predefined_constants(); +#ifdef TAU_MPI_T + Tau_MPI_T_initialization(); + Tau_track_mpi_t(); +#endif /* TAU_MPI_T */ + +#ifdef TAU_ADIOS + // this is only here to force the linker to resolve the adiost_tool symbol + // before the weak one in the ADIOS static library gets pulled in, and prevents + // TAU from replacing it. + adiost_tool(); +#endif + +#ifdef TAU_SOS + int provided = 0; + returnVal = PMPI_Init_thread( a1, a2, MPI_THREAD_FUNNELED, &provided ); + if (TauEnv_get_sos_enabled()) { + TAU_SOS_init(argc, argv, true); + } +#else + returnVal = PMPI_Init( a1, a2 ); +#endif + +#ifndef TAU_WINDOWS +#ifndef _AIX + if (TauEnv_get_ebs_enabled()) { + Tau_sampling_init_if_necessary(); + } +#endif /* _AIX */ +#endif /* TAU_WINDOWS */ + + Tau_signal_initialization(); + +#ifdef TAU_MONITORING + Tau_mon_connect(); +#endif /* TAU_MONITORING */ + +#ifdef TAU_BGP + if (TauEnv_get_ibm_bg_hwp_counters()) { + int upcErr; + Tau_Bg_hwp_counters_start(&upcErr); + if (upcErr != 0) { + printf("TAU ERROR: ** Error starting IBM BGP UPC hardware performance counters\n"); + } + PMPI_Barrier(MPI_COMM_WORLD); + } +#endif /* TAU_BGP */ + TAU_PROFILE_STOP(tautimer); + + PMPI_Comm_rank( MPI_COMM_WORLD, &procid_0 ); + TAU_PROFILE_SET_NODE(procid_0 ); + Tau_set_usesMPI(1); + + PMPI_Comm_size( MPI_COMM_WORLD, &size ); + tau_totalnodes(1, size); /* Set the totalnodes */ + + PMPI_Get_processor_name(procname, &procnamelength); + TAU_METADATA("MPI Processor Name", procname); + + if (TauEnv_get_synchronize_clocks()) { + TauSyncClocks(); + } + } + else { + returnVal = 0; + } + + writeMetaDataAfterMPI_Init(); + + return returnVal; } @@ -2250,18 +2341,160 @@ int genProfile() } #endif -static int procid_0; -int tau_mpi_finalized = 0; +//int tau_mpi_finalized = 0; + +#if 0 int TAU_MPI_Finalized() { fprintf(stdout, "In TAU_MPI_Finalized(): tau_mpi_finalized=%d\n", tau_mpi_finalized); return tau_mpi_finalized; } +#endif /********************************************************** MPI_Finalize **********************************************************/ + +int __real_MPI_Finalize() ; +int __wrap_MPI_Finalize() { + + + int returnVal; + char procname[MPI_MAX_PROCESSOR_NAME]; + int procnamelength; + + TAU_VERBOSE("TAU: Call MPI_Finalize()\n"); + + TAU_PROFILE_TIMER(tautimer, "MPI_Finalize()", " ", TAU_MESSAGE); + TAU_PROFILE_START(tautimer); + +#ifdef TAU_MPI_T + Tau_track_mpi_t_here(); + + /*Clean up and finalize the MPI_T interface*/ + Tau_mpi_t_cleanup(); + + returnVal = PMPI_T_finalize(); + if (returnVal != MPI_SUCCESS) { + printf("TAU: Call to MPI_T_finalize failed\n"); + } + +#endif /* TAU_MPI_T */ + +#ifdef TAU_SOS + //TAU_SOS_stop_worker(); +#endif + + if (TauEnv_get_synchronize_clocks()) { + TauSyncFinalClocks(); + } + Tau_metadata_writeEndingTimeStamp(); + + PMPI_Get_processor_name(procname, &procnamelength); + TAU_METADATA("MPI Processor Name", procname); + + if (Tau_get_node() < 0) { + /* Grab the node id, we don't always wrap mpi_init */ + PMPI_Comm_rank( MPI_COMM_WORLD, &procid_0 ); + TAU_PROFILE_SET_NODE(procid_0 ); + Tau_set_usesMPI(1); + } + +#ifdef TAU_BGP + /* BGP counters */ + int numCounters, mode, upcErr; + x_uint64 counterVals[1024]; + + if (TauEnv_get_ibm_bg_hwp_counters()) { + PMPI_Barrier(MPI_COMM_WORLD); + Tau_Bg_hwp_counters_stop(&numCounters, counterVals, &mode, &upcErr); + if (upcErr != 0) { + printf(" ** Error stopping UPC performance counters"); + } + + Tau_Bg_hwp_counters_output(&numCounters, counterVals, &mode, &upcErr); + } +#endif /* TAU_BGP */ + +#ifndef TAU_WINDOWS +#ifndef _AIX + /* Shutdown EBS after Finalize to allow Profiles to be written out + correctly. Also allows profile merging (or unification) to be + done correctly. */ + if (TauEnv_get_callsite()) { + finalizeCallSites_if_necessary(); + } +#endif /* _AIX */ +#endif /* TAU_WINDOWS */ + + Tau_MemMgr_finalizeIfNecessary(); + +#ifndef TAU_WINDOWS +#ifndef _AIX + if (TauEnv_get_ebs_enabled()) { + // Tau_sampling_finalizeNode(); + + Tau_sampling_finalize_if_necessary(Tau_get_local_tid()); + } +#endif /* _AIX */ +#endif /* TAU_WINDOWS */ + + /* *CWL* This might be generalized to perform a final monitoring dump. + For now, we should let merging handle the data. +#ifdef TAU_MON_MPI + Tau_collate_writeProfile(); +#else + */ + + // merge TAU metadata + if (TauEnv_get_merge_metadata()) { + Tau_metadataMerge_mergeMetaData(); + } + + /* Create a merged profile if requested */ + if (TauEnv_get_profile_format() == TAU_FORMAT_MERGED) { + /* *CWL* - properly record intermediate values (the same way snapshots work). + Note that we do not want to shut down the timers as yet. There is + still potentially life after MPI_Finalize where TAU is concerned. + */ + /* KAH - NO! this is the wrong time to do this. THis is also done in the + * snapshot writer. If you do it twice, you get double values for main... */ + //TauProfiler_updateAllIntermediateStatistics(); + Tau_mergeProfiles_MPI(); + } + +#ifdef TAU_MONITORING + Tau_mon_disconnect(); +#endif /* TAU_MONITORING */ + +#ifdef TAU_SOS + if (TauEnv_get_sos_enabled()) { + TAU_SOS_finalize(); + } +#endif + +#ifdef TAU_OTF2 + if(TauEnv_get_trace_format() == TAU_TRACE_FORMAT_OTF2) { + TauTraceOTF2ShutdownComms(Tau_get_local_tid()); + } +#endif + + returnVal = __real_MPI_Finalize(); + + fprintf(stdout, "PMPI_Finalize() return=%d\n", returnVal); + + TAU_PROFILE_STOP(tautimer); + + Tau_stop_top_level_timer_if_necessary(); + //tau_mpi_finalized = 1; + + return returnVal; + + +} + +#if 0 int __real_MPI_Finalize() ; int __wrap_MPI_Finalize() { @@ -2377,7 +2610,7 @@ int __wrap_MPI_Finalize() { return retval; } - +#endif /********************************************************** MPI_Initialized From 3034ee050f79108ad538b9355d6f66932ba873f7 Mon Sep 17 00:00:00 2001 From: Aurele MAHEO Date: Wed, 29 Nov 2017 17:16:26 -0800 Subject: [PATCH 07/60] [TAU MPC] Declare TAU_MPI_Finalized() function and tau_mpi_finalized variable in MPC MPI wrapper instead of in TauMpi.c to avoid duplication: to be improved Former-commit-id: 226b2ce4ecd22fb548d6548e32384783d29c22e6 --- src/Profile/TauMpi.c | 5 +++-- src/wrappers/mpc_mpi/wr.c | 8 +++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index 465a812ee..851336742 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -1633,12 +1633,13 @@ MPI_Errhandler errhandler; return returnVal; } - +#if 0 int tau_mpi_finalized = 0; int TAU_MPI_Finalized() { fprintf(stdout, "In TAU_MPI_Finalized(): tau_mpi_finalized=%d\n", tau_mpi_finalized); return tau_mpi_finalized; } +#endif void finalizeCallSites_if_necessary(); int MPI_Finalize( ) @@ -1770,7 +1771,7 @@ int MPI_Finalize( ) TAU_PROFILE_STOP(tautimer); Tau_stop_top_level_timer_if_necessary(); - tau_mpi_finalized = 1; + //tau_mpi_finalized = 1; return returnVal; } diff --git a/src/wrappers/mpc_mpi/wr.c b/src/wrappers/mpc_mpi/wr.c index e92b7b908..5a313b859 100644 --- a/src/wrappers/mpc_mpi/wr.c +++ b/src/wrappers/mpc_mpi/wr.c @@ -2342,9 +2342,9 @@ int genProfile() #endif -//int tau_mpi_finalized = 0; +int tau_mpi_finalized = 0; -#if 0 +#if 1 int TAU_MPI_Finalized() { fprintf(stdout, "In TAU_MPI_Finalized(): tau_mpi_finalized=%d\n", tau_mpi_finalized); return tau_mpi_finalized; @@ -2487,11 +2487,9 @@ int __wrap_MPI_Finalize() { TAU_PROFILE_STOP(tautimer); Tau_stop_top_level_timer_if_necessary(); - //tau_mpi_finalized = 1; + tau_mpi_finalized = 1; return returnVal; - - } #if 0 From 9ddc46b2cf168ce04656357d65d738ae448c55c6 Mon Sep 17 00:00:00 2001 From: Naookie Sato Date: Mon, 7 May 2018 16:17:19 -0700 Subject: [PATCH 08/60] passing -dyninst=download works to download and build dyninst for tau. Proper environment variables must be set for rewriting, and currently the only way to get proper instrumentation is with rewriting. Former-commit-id: 5fb140593b3dd207c650ef839de86a8fb5768423 --- configure | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/configure b/configure index f3255c2a3..7141b47f8 100755 --- a/configure +++ b/configure @@ -1881,6 +1881,13 @@ for arg in "$@"; do # shift # ;; + -dyninst=download) + dyninst=yes + download_dyninst=yes + echo "Downloading Dyninst..." + shift + ;; + -dyninst=*) dyninst=yes dyninstdir=`echo $arg | sed -e 's/-dyninst=//'` @@ -6673,6 +6680,143 @@ if [ "x$download_unwind" = xyes ] ; then cd $prebfddir fi #unwind=download +###################################################################### +# Install Dyninst and its dependencies, if requested +###################################################################### +libboost=boost_1_67_0 +libboosttgz=$libboost.tar.gz +libboosturl=http://www.cs.uoregon.edu/research/paracomp/tau/tauprofile/dist/$libboosttgz + +libdyninst=dyninst-9.3.2-working +libdyninsttgz=$libdyninst.tar.gz +libdyninsturl=http://www.cs.uoregon.edu/research/paracomp/tau/tauprofile/dist/$libdyninsttgz + +if [ "x$dyninstdir" = "x" ]; then + libdyninstdir=${targetdir}/${architecture} +else + libdyninstdir=$dyninstdir +fi + +libdyninst_name=dyninst + +## Check for boost (for making tau_run) +#TODO: This should probably be moved to wherever the tau_run make args are set +if [ "x$boostdir" != "x" -a -d "$boostdir" ] ; then + dyninstboostdir=${boostdir} +else + dyninstboostdir=${libdyninstdir}/${libboost} +fi +if [ "x$dyninstboostdir" != "x" -a -d "$dyninstboostdir" ] ; then + fixmakeargs="$fixmakeargs boostinc=-I${dyninstboostdir}/include" +fi + +if [ "x$dyninstdir" != "x" -a -d "$dyninstdir" ] ; then + if [ -r $dyninstdir/$libdyninsttgz ]; then + echo "NOTE: Copying $dyninstdir/$libdyninsttgz " + cp $dyninstdir/$libunwindtgz . + download_dyninst=yes + fi +fi + +if [ "x$download_dyninst" = xyes ] ; then + + dyninstdir=${libdyninstdir}/${libdyninst} + prebfddir=`pwd` + + #check Cmake exists + cmake_cmd=`which cmake` + if [ "x$cmake_cmd" = "x" ] ; then + echo 'ERROR: cmake version 2.8.11 or higher required to build Dyninst.' + exit 1; + fi + + ## Check for boost + if [ "x$boostdir" != "x" -a -d "$boostdir" ] ; then + dyninstboostdir=${boostdir} + else + dyninstboostdir=${libdyninstdir}/${libboost} + fi + if [ "x$dyninstboostdir" != "x" -a -d "$dyninstboostdir" ] ; then + echo "Dyninst dependency : boost : found : $dyninstboostdir" + fixmakeargs="$fixmakeargs boostinc=-I${dyninstboostdir}/include" + else + echo "Dyninst dependency : boost : not found, downloading..." + download_boost=yes + fi + ## Download and install boost if necessary + if [ "x$download_boost" = xyes ] ; then + # get the tar file + if [ ! -f $libboosttgz ] ; then + download "$libboosturl" "$libboosttgz" + fi + # check the tar file + if [ ! -f $libboosttgz ] ; then + echo "$libboosttgz did not download. Please download it manually from: " + echo "$libboosturl" + echo "Please enter the directory containing the tarball: ${nnl}" + read RESPONSE + cp $RESPONSE/$libboosttgz . + else + echo "expanding $libboosttgz..." + rm -rf $dyninstboostdir + mkdir $dyninstboostdir + tar -xzf $libboosttgz -C $dyninstboostdir --strip-components=1 + echo "removing $libboosttgz..." + rm $libboosttgz + cd $dyninstboostdir + ./bootstrap.sh --prefix=${dyninstboostdir} # dyninst wants boost to be built in its src dir + ./b2 install -j4 + fixmakeargs="$fixmakeargs boostinc=-I${dyninstboostdir}/include" + fi + fi #end dowload_boost + cd $prebfddir + + if [ -r "$dyninstdir/lib/libdyninstAPI.so" -o \ + -r "$dyninstdir/lib/libdyninstAPI_RT.so" -o \ + -r "$dyninstdir/lib/libdynElf.so" ] ; then + echo "Found: dyninst" + echo "dyninst download already found, skipping" + else + echo "Not found in ${dyninstdir}: ${libdyninst_name}" + # get the tar file + if [ ! -f $libdyninsttgz ] ; then + download "$libdyninsturl" "$libdyninsttgz" + fi + + # check the tar file + if [ ! -f $libdyninsttgz ] ; then + echo "$libdyninsttgz did not download. Please download it manually from: " + echo "$libdyninsturl" + echo "Please enter the directory containing the tarball: ${nnl}" + read RESPONSE + cp $RESPONSE/$libdyninsttgz . + else + echo "expanding $libdyninsttgz..." + rm -rf $libdyninst + mkdir $libdyninst + tar -xzf $libdyninsttgz -C $libdyninst --strip-components=1 + echo "removing $libdyninsttgz..." + rm $libdyninsttgz + rm -rf $dyninstdir # remove and make the build dir + mkdir $dyninstdir + cd $dyninstdir # go to the build dir + cmake ${prebfddir}/${libdyninst} -DBoost_INCLUDE_DIR=${dyninstboostdir} -DCMAKE_INSTALL_PREFIX=${dyninstdir} + make -j8 + make install + if [ -f ${dyninstdir}/elfutils/lib/libdw.so ]; then + cp ${dyninstdir}/elfutils/lib/libdw* ${dyninstdir}/lib + mv ${dyninstdir}/lib/libdw.so ${dyninstdir}/lib/libdwarf.so + fi + if [ -f ${dyninstdir}/elfutils/lib/libelf.so ]; then + cp ${dyninstdir}/elfutils/lib/libelf* ${dyninstdir}/lib + fi + if [ -f ${dyninstdir}/libiberty/libiberty.a ]; then + cp ${dyninstdir}/libiberty/libiberty.a ${dyninstdir}/lib + fi + fi + fi + cd $prebfddir +fi #dyninst=download ###################################################################### # Install Scalable Observation System (SOS) if requested From 2744527a93fb483750c2948a1b3fcd5158187d47 Mon Sep 17 00:00:00 2001 From: Naookie Sato Date: Tue, 8 May 2018 15:46:09 -0700 Subject: [PATCH 09/60] added automatic download and build of libiberty for dyninst Former-commit-id: 61ecb5aabb2fc16e46096bab18968b20e53de0c0 --- configure | 293 +++++++++++++++++++++++++++++------------------------- 1 file changed, 155 insertions(+), 138 deletions(-) diff --git a/configure b/configure index 7141b47f8..283d99b30 100755 --- a/configure +++ b/configure @@ -6680,144 +6680,6 @@ if [ "x$download_unwind" = xyes ] ; then cd $prebfddir fi #unwind=download -###################################################################### -# Install Dyninst and its dependencies, if requested -###################################################################### -libboost=boost_1_67_0 -libboosttgz=$libboost.tar.gz -libboosturl=http://www.cs.uoregon.edu/research/paracomp/tau/tauprofile/dist/$libboosttgz - -libdyninst=dyninst-9.3.2-working -libdyninsttgz=$libdyninst.tar.gz -libdyninsturl=http://www.cs.uoregon.edu/research/paracomp/tau/tauprofile/dist/$libdyninsttgz - -if [ "x$dyninstdir" = "x" ]; then - libdyninstdir=${targetdir}/${architecture} -else - libdyninstdir=$dyninstdir -fi - -libdyninst_name=dyninst - -## Check for boost (for making tau_run) -#TODO: This should probably be moved to wherever the tau_run make args are set -if [ "x$boostdir" != "x" -a -d "$boostdir" ] ; then - dyninstboostdir=${boostdir} -else - dyninstboostdir=${libdyninstdir}/${libboost} -fi -if [ "x$dyninstboostdir" != "x" -a -d "$dyninstboostdir" ] ; then - fixmakeargs="$fixmakeargs boostinc=-I${dyninstboostdir}/include" -fi - -if [ "x$dyninstdir" != "x" -a -d "$dyninstdir" ] ; then - if [ -r $dyninstdir/$libdyninsttgz ]; then - echo "NOTE: Copying $dyninstdir/$libdyninsttgz " - cp $dyninstdir/$libunwindtgz . - download_dyninst=yes - fi -fi - -if [ "x$download_dyninst" = xyes ] ; then - - dyninstdir=${libdyninstdir}/${libdyninst} - prebfddir=`pwd` - - #check Cmake exists - cmake_cmd=`which cmake` - if [ "x$cmake_cmd" = "x" ] ; then - echo 'ERROR: cmake version 2.8.11 or higher required to build Dyninst.' - exit 1; - fi - - ## Check for boost - if [ "x$boostdir" != "x" -a -d "$boostdir" ] ; then - dyninstboostdir=${boostdir} - else - dyninstboostdir=${libdyninstdir}/${libboost} - fi - if [ "x$dyninstboostdir" != "x" -a -d "$dyninstboostdir" ] ; then - echo "Dyninst dependency : boost : found : $dyninstboostdir" - fixmakeargs="$fixmakeargs boostinc=-I${dyninstboostdir}/include" - else - echo "Dyninst dependency : boost : not found, downloading..." - download_boost=yes - fi - ## Download and install boost if necessary - if [ "x$download_boost" = xyes ] ; then - # get the tar file - if [ ! -f $libboosttgz ] ; then - download "$libboosturl" "$libboosttgz" - fi - # check the tar file - if [ ! -f $libboosttgz ] ; then - echo "$libboosttgz did not download. Please download it manually from: " - echo "$libboosturl" - echo "Please enter the directory containing the tarball: ${nnl}" - read RESPONSE - cp $RESPONSE/$libboosttgz . - else - echo "expanding $libboosttgz..." - rm -rf $dyninstboostdir - mkdir $dyninstboostdir - tar -xzf $libboosttgz -C $dyninstboostdir --strip-components=1 - echo "removing $libboosttgz..." - rm $libboosttgz - cd $dyninstboostdir - ./bootstrap.sh --prefix=${dyninstboostdir} # dyninst wants boost to be built in its src dir - ./b2 install -j4 - fixmakeargs="$fixmakeargs boostinc=-I${dyninstboostdir}/include" - fi - fi #end dowload_boost - cd $prebfddir - - if [ -r "$dyninstdir/lib/libdyninstAPI.so" -o \ - -r "$dyninstdir/lib/libdyninstAPI_RT.so" -o \ - -r "$dyninstdir/lib/libdynElf.so" ] ; then - echo "Found: dyninst" - echo "dyninst download already found, skipping" - else - echo "Not found in ${dyninstdir}: ${libdyninst_name}" - # get the tar file - if [ ! -f $libdyninsttgz ] ; then - download "$libdyninsturl" "$libdyninsttgz" - fi - - # check the tar file - if [ ! -f $libdyninsttgz ] ; then - echo "$libdyninsttgz did not download. Please download it manually from: " - echo "$libdyninsturl" - echo "Please enter the directory containing the tarball: ${nnl}" - read RESPONSE - cp $RESPONSE/$libdyninsttgz . - else - echo "expanding $libdyninsttgz..." - rm -rf $libdyninst - mkdir $libdyninst - tar -xzf $libdyninsttgz -C $libdyninst --strip-components=1 - echo "removing $libdyninsttgz..." - rm $libdyninsttgz - rm -rf $dyninstdir # remove and make the build dir - mkdir $dyninstdir - cd $dyninstdir # go to the build dir - cmake ${prebfddir}/${libdyninst} -DBoost_INCLUDE_DIR=${dyninstboostdir} -DCMAKE_INSTALL_PREFIX=${dyninstdir} - make -j8 - make install - if [ -f ${dyninstdir}/elfutils/lib/libdw.so ]; then - cp ${dyninstdir}/elfutils/lib/libdw* ${dyninstdir}/lib - mv ${dyninstdir}/lib/libdw.so ${dyninstdir}/lib/libdwarf.so - fi - if [ -f ${dyninstdir}/elfutils/lib/libelf.so ]; then - cp ${dyninstdir}/elfutils/lib/libelf* ${dyninstdir}/lib - fi - if [ -f ${dyninstdir}/libiberty/libiberty.a ]; then - cp ${dyninstdir}/libiberty/libiberty.a ${dyninstdir}/lib - fi - fi - fi - cd $prebfddir -fi #dyninst=download - ###################################################################### # Install Scalable Observation System (SOS) if requested ###################################################################### @@ -8879,6 +8741,161 @@ fi /bin/rm -f conftest_bfd.o conftest_bfd.c conftest_bfd.so ###################################################################### +###################################################################### +# Install Dyninst and its dependencies, if requested +###################################################################### +libboost=boost_1_67_0 +libboosttgz=$libboost.tar.gz +libboosturl=http://www.cs.uoregon.edu/research/paracomp/tau/tauprofile/dist/$libboosttgz + +libdyninst=dyninst-9.3.2-working +libdyninsttgz=$libdyninst.tar.gz +libdyninsturl=http://www.cs.uoregon.edu/research/paracomp/tau/tauprofile/dist/$libdyninsttgz + +dynlibiberty=dynlibiberty +dynlibibertytgz=${dynlibiberty}.tar.gz +dynlibibertyurl=http://www.cs.uoregon.edu/research/paracomp/tau/tauprofile/dist/$dynlibibertytgz + +if [ "x$dyninstdir" = "x" ]; then + libdyninstdir=${targetdir}/${architecture} +else + libdyninstdir=$dyninstdir +fi + +libdyninst_name=dyninst + +## Check for boost (for making tau_run) +#TODO: This should probably be moved to wherever the tau_run make args are set +if [ "x$boostdir" != "x" -a -d "$boostdir" ] ; then + dyninstboostdir=${boostdir} +else + dyninstboostdir=${libdyninstdir}/${libboost} +fi +if [ "x$dyninstboostdir" != "x" -a -d "$dyninstboostdir" ] ; then + fixmakeargs="$fixmakeargs boostinc=-I${dyninstboostdir}/include" +fi + +if [ "x$dyninstdir" != "x" -a -d "$dyninstdir" ] ; then + if [ -r $dyninstdir/$libdyninsttgz ]; then + echo "NOTE: Copying $dyninstdir/$libdyninsttgz " + cp $dyninstdir/$libunwindtgz . + download_dyninst=yes + fi +fi + +if [ "x$download_dyninst" = xyes ] ; then + + dyninstdir=${libdyninstdir}/${libdyninst} + prebfddir=`pwd` + + #check Cmake exists + cmake_cmd=`which cmake` + if [ "x$cmake_cmd" = "x" ] ; then + echo 'ERROR: cmake version 2.8.11 or higher required to build Dyninst.' + exit 1; + fi + + ## Check for boost + if [ "x$boostdir" != "x" -a -d "$boostdir" ] ; then + dyninstboostdir=${boostdir} + else + dyninstboostdir=${libdyninstdir}/${libboost} + fi + if [ "x$dyninstboostdir" != "x" -a -d "$dyninstboostdir" ] ; then + echo "Dyninst dependency : boost : found : $dyninstboostdir" + fixmakeargs="$fixmakeargs boostinc=-I${dyninstboostdir}/include" + else + echo "Dyninst dependency : boost : not found, downloading..." + download_boost=yes + fi + ## Download and install boost if necessary + if [ "x$download_boost" = xyes ] ; then + # get the tar file + if [ ! -f $libboosttgz ] ; then + download "$libboosturl" "$libboosttgz" + fi + # check the tar file + if [ ! -f $libboosttgz ] ; then + echo "$libboosttgz did not download. Please download it manually from: " + echo "$libboosturl" + echo "Please enter the directory containing the tarball: ${nnl}" + read RESPONSE + cp $RESPONSE/$libboosttgz . + else + echo "expanding $libboosttgz..." + rm -rf $dyninstboostdir + mkdir $dyninstboostdir + tar -xzf $libboosttgz -C $dyninstboostdir --strip-components=1 + echo "removing $libboosttgz..." + rm $libboosttgz + cd $dyninstboostdir + ./bootstrap.sh --prefix=${dyninstboostdir} # dyninst wants boost to be built in its src dir + ./b2 install -j4 + fixmakeargs="$fixmakeargs boostinc=-I${dyninstboostdir}/include" + fi + fi #end dowload_boost + cd $prebfddir + + if [ -r "$dyninstdir/lib/libdyninstAPI.so" -o \ + -r "$dyninstdir/lib/libdyninstAPI_RT.so" -o \ + -r "$dyninstdir/lib/libdynElf.so" ] ; then + echo "Found: dyninst" + echo "dyninst download already found, skipping" + else + echo "Not found in ${dyninstdir}: ${libdyninst_name}" + # get the tar file + if [ ! -f $libdyninsttgz ] ; then + download "$libdyninsturl" "$libdyninsttgz" + fi + + # check the tar file + if [ ! -f $libdyninsttgz ] ; then + echo "$libdyninsttgz did not download. Please download it manually from: " + echo "$libdyninsturl" + echo "Please enter the directory containing the tarball: ${nnl}" + read RESPONSE + cp $RESPONSE/$libdyninsttgz . + else + echo "expanding $libdyninsttgz..." + rm -rf $libdyninst + mkdir $libdyninst + tar -xzf $libdyninsttgz -C $libdyninst --strip-components=1 + echo "removing $libdyninsttgz..." + rm $libdyninsttgz + rm -rf $dyninstdir # remove and make the build dir + mkdir $dyninstdir + cd $dyninstdir # go to the build dir + ## Build shared libiberty + mkdir ${dyninstdir}/libiberty + download "$dynlibibertyurl" "$dynlibibertytgz" + tar -xzf $dynlibibertytgz + cd $dynlibiberty/libiberty + ./configure --enable-shared --prefix=$PWD + make + ar rcs libiberty.a pic/*.o + cp libiberty.a ${dyninstdir}/libiberty + cd ../.. + rm -rf $dynlibiberty $dynlibibertytgz + ## Now we can make Dyninst + cmake ${prebfddir}/${libdyninst} -DBoost_INCLUDE_DIR=${dyninstboostdir} -DCMAKE_INSTALL_PREFIX=${dyninstdir} -DIBERTY_LIBRARIES=${dyninstdir}/libiberty/libiberty.a + make -j8 + make install + if [ -f ${dyninstdir}/elfutils/lib/libdw.so ]; then + cp ${dyninstdir}/elfutils/lib/libdw* ${dyninstdir}/lib + mv ${dyninstdir}/lib/libdw.so ${dyninstdir}/lib/libdwarf.so + fi + if [ -f ${dyninstdir}/elfutils/lib/libelf.so ]; then + cp ${dyninstdir}/elfutils/lib/libelf* ${dyninstdir}/lib + fi + if [ -f ${dyninstdir}/libiberty/libiberty.a ]; then + cp ${dyninstdir}/libiberty/libiberty.a ${dyninstdir}/lib + fi + fi + fi + cd $prebfddir +fi #dyninst=download + + ###################################################################### # Check that the Sampling allocator code is supported by compiler ###################################################################### From a48c348ae55fcfded609a5d5e4697ff9355c6362 Mon Sep 17 00:00:00 2001 From: Naookie Sato Date: Wed, 9 May 2018 12:27:54 -0700 Subject: [PATCH 10/60] build elfutils before dyninst Former-commit-id: 4735abeff1e3bfafb9dfbe8b26a07e7a187a3fc0 --- configure | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 283d99b30..da08198fe 100755 --- a/configure +++ b/configure @@ -8756,6 +8756,10 @@ dynlibiberty=dynlibiberty dynlibibertytgz=${dynlibiberty}.tar.gz dynlibibertyurl=http://www.cs.uoregon.edu/research/paracomp/tau/tauprofile/dist/$dynlibibertytgz +dynelfutils=elfutils-0.168 +dynelfutilsbz=${dynelfutils}.tar.bz2 +dynelfutilsurl=http://www.cs.uoregon.edu/research/paracomp/tau/tauprofile/dist/$dynelfutilsbz + if [ "x$dyninstdir" = "x" ]; then libdyninstdir=${targetdir}/${architecture} else @@ -8765,7 +8769,6 @@ fi libdyninst_name=dyninst ## Check for boost (for making tau_run) -#TODO: This should probably be moved to wherever the tau_run make args are set if [ "x$boostdir" != "x" -a -d "$boostdir" ] ; then dyninstboostdir=${boostdir} else @@ -8876,8 +8879,18 @@ if [ "x$download_dyninst" = xyes ] ; then cp libiberty.a ${dyninstdir}/libiberty cd ../.. rm -rf $dynlibiberty $dynlibibertytgz + ## Build shared elfutils + mkdir ${dyninstdir}/elfutils + download "$dynelfutilsurl" "$dynelfutilsbz" + tar -xf $dynelfutilsbz -C ${dyninstdir}/elfutils --strip-components=1 + cd ${dyninstdir}/elfutils + ./configure --enable-shared --prefix=$PWD + make + make install + cd .. + rm -rf $dynelfutilsbz ## Now we can make Dyninst - cmake ${prebfddir}/${libdyninst} -DBoost_INCLUDE_DIR=${dyninstboostdir} -DCMAKE_INSTALL_PREFIX=${dyninstdir} -DIBERTY_LIBRARIES=${dyninstdir}/libiberty/libiberty.a + cmake ${prebfddir}/${libdyninst} -DBoost_INCLUDE_DIR=${dyninstboostdir} -DCMAKE_INSTALL_PREFIX=${dyninstdir} -DIBERTY_LIBRARIES=${dyninstdir}/libiberty/libiberty.a -DLIBDWARF_INCLUDE_DIR=${dyninstdir}/elfutils/include -DLIBDWARF_LIBRARIES=${dyninstdir}/elfutils/lib/libdw.so -DLIBELF_INCLUDE_DIR=${dyninstdir}/elfutils/include -DLIBELF_LIBRARIES=${dyninstdir}/elfutils/lib/libelf.so make -j8 make install if [ -f ${dyninstdir}/elfutils/lib/libdw.so ]; then From aebb0d34a3f8098453a2fcc1d5353e4e58f37b4b Mon Sep 17 00:00:00 2001 From: Naookie Sato Date: Wed, 9 May 2018 13:15:24 -0700 Subject: [PATCH 11/60] --boost=download should work to download and build boost 1.67.0 Former-commit-id: 2ee79098d14c02d0349e72106eae1290af1ff3b0 --- configure | 98 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/configure b/configure index da08198fe..c36803f0a 100755 --- a/configure +++ b/configure @@ -1840,6 +1840,12 @@ for arg in "$@"; do shift ;; + -boost=download) + boost=yes + echo "Downloading Boost..." + shift + ;; + -boost=*) boost=yes boostdir=`echo $arg | sed -e 's/-boost=//'` @@ -1883,6 +1889,7 @@ for arg in "$@"; do -dyninst=download) dyninst=yes + boost=yes download_dyninst=yes echo "Downloading Dyninst..." shift @@ -8768,23 +8775,59 @@ fi libdyninst_name=dyninst -## Check for boost (for making tau_run) +if [ "x$dyninstdir" != "x" -a -d "$dyninstdir" ] ; then + if [ -r $dyninstdir/$libdyninsttgz ]; then + echo "NOTE: Copying $dyninstdir/$libdyninsttgz " + cp $dyninstdir/$libunwindtgz . + download_dyninst=yes + fi +fi + +## Check for boost if [ "x$boostdir" != "x" -a -d "$boostdir" ] ; then dyninstboostdir=${boostdir} else dyninstboostdir=${libdyninstdir}/${libboost} + boostdir=${dyninstboostdir} fi if [ "x$dyninstboostdir" != "x" -a -d "$dyninstboostdir" ] ; then + echo "Boost : found : $dyninstboostdir" fixmakeargs="$fixmakeargs boostinc=-I${dyninstboostdir}/include" +else + if [ "x$boost" = xyes ] ; then + echo "Boost : not found, downloading..." + download_boost=yes + fi fi -if [ "x$dyninstdir" != "x" -a -d "$dyninstdir" ] ; then - if [ -r $dyninstdir/$libdyninsttgz ]; then - echo "NOTE: Copying $dyninstdir/$libdyninsttgz " - cp $dyninstdir/$libunwindtgz . - download_dyninst=yes +## Download and install boost if necessary +if [ "x$download_boost" = xyes ] ; then + prebfddir=`pwd` + # get the tar file + if [ ! -f $libboosttgz ] ; then + download "$libboosturl" "$libboosttgz" fi -fi + # check the tar file + if [ ! -f $libboosttgz ] ; then + echo "$libboosttgz did not download. Please download it manually from: " + echo "$libboosturl" + echo "Please enter the directory containing the tarball: ${nnl}" + read RESPONSE + cp $RESPONSE/$libboosttgz . + else + echo "expanding $libboosttgz..." + rm -rf $dyninstboostdir + mkdir $dyninstboostdir + tar -xzf $libboosttgz -C $dyninstboostdir --strip-components=1 + echo "removing $libboosttgz..." + rm $libboosttgz + cd $dyninstboostdir + ./bootstrap.sh --prefix=${dyninstboostdir} # dyninst wants boost to be built in its src dir + ./b2 install -j4 + fixmakeargs="$fixmakeargs boostinc=-I${dyninstboostdir}/include" + fi + cd $prebfddir +fi #end dowload_boost if [ "x$download_dyninst" = xyes ] ; then @@ -8798,47 +8841,6 @@ if [ "x$download_dyninst" = xyes ] ; then exit 1; fi - ## Check for boost - if [ "x$boostdir" != "x" -a -d "$boostdir" ] ; then - dyninstboostdir=${boostdir} - else - dyninstboostdir=${libdyninstdir}/${libboost} - fi - if [ "x$dyninstboostdir" != "x" -a -d "$dyninstboostdir" ] ; then - echo "Dyninst dependency : boost : found : $dyninstboostdir" - fixmakeargs="$fixmakeargs boostinc=-I${dyninstboostdir}/include" - else - echo "Dyninst dependency : boost : not found, downloading..." - download_boost=yes - fi - ## Download and install boost if necessary - if [ "x$download_boost" = xyes ] ; then - # get the tar file - if [ ! -f $libboosttgz ] ; then - download "$libboosturl" "$libboosttgz" - fi - # check the tar file - if [ ! -f $libboosttgz ] ; then - echo "$libboosttgz did not download. Please download it manually from: " - echo "$libboosturl" - echo "Please enter the directory containing the tarball: ${nnl}" - read RESPONSE - cp $RESPONSE/$libboosttgz . - else - echo "expanding $libboosttgz..." - rm -rf $dyninstboostdir - mkdir $dyninstboostdir - tar -xzf $libboosttgz -C $dyninstboostdir --strip-components=1 - echo "removing $libboosttgz..." - rm $libboosttgz - cd $dyninstboostdir - ./bootstrap.sh --prefix=${dyninstboostdir} # dyninst wants boost to be built in its src dir - ./b2 install -j4 - fixmakeargs="$fixmakeargs boostinc=-I${dyninstboostdir}/include" - fi - fi #end dowload_boost - cd $prebfddir - if [ -r "$dyninstdir/lib/libdyninstAPI.so" -o \ -r "$dyninstdir/lib/libdyninstAPI_RT.so" -o \ -r "$dyninstdir/lib/libdynElf.so" ] ; then From 20a5d68f56a421531852c82b5fc52f8f030fd6ce Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Wed, 30 May 2018 12:38:03 -0400 Subject: [PATCH 12/60] Fixing ADIOS write dimensions and cleaning up other ADIOS trace events for the SOS plugin. Also fixing a bug in the plugin where temporary strings go out of scope before they are copied. Former-commit-id: a9f0289b6a9ae08494c80c355013c5143ba57cde --- plugins/examples/TauSOS.cpp | 7 +- src/Profile/TauADIOS.cpp | 305 +++++++++++++++++++++--------------- 2 files changed, 188 insertions(+), 124 deletions(-) diff --git a/plugins/examples/TauSOS.cpp b/plugins/examples/TauSOS.cpp index 5469aa260..16524fae3 100644 --- a/plugins/examples/TauSOS.cpp +++ b/plugins/examples/TauSOS.cpp @@ -214,6 +214,11 @@ void TAU_SOS_send_shutdown_message(void) { TAU_VERBOSE("Sending SOS_MSG_TYPE_SHUTDOWN ...\n"); SOS_send_to_daemon(buffer, buffer); SOS_buffer_destroy(buffer); + char * exporting = getenv("SOS_EXPORT_DB_AT_EXIT"); + if (exporting != NULL) { + TAU_VERBOSE("Waiting %d seconds for SOS to write (if necessary)...\n", thePluginOptions().env_sos_shutdown_delay); + sleep(thePluginOptions().env_sos_shutdown_delay); + } #endif } @@ -517,7 +522,7 @@ void TAU_SOS_finalize(void) { // shutdown the daemon, if necessary if (shutdown_daemon) { if (my_rank == daemon_rank) { - TAU_VERBOSE("Waiting for SOS to flush...\n"); + TAU_VERBOSE("Waiting %d seconds for SOS to flush...\n", thePluginOptions().env_sos_shutdown_delay); sleep(thePluginOptions().env_sos_shutdown_delay); TAU_SOS_send_shutdown_message(); } diff --git a/src/Profile/TauADIOS.cpp b/src/Profile/TauADIOS.cpp index eb8596dce..77ba3a7d8 100644 --- a/src/Profile/TauADIOS.cpp +++ b/src/Profile/TauADIOS.cpp @@ -98,12 +98,15 @@ void Tau_SOS_conditionally_pack_current_timer(const char * name) { #define TAU_SOS_COLLECTIVE_ADIOS_EVENT(__detail) \ std::stringstream __ss; \ __ss << EVENT_TRACE_PREFIX << __detail << "()"; \ - Tau_SOS_conditionally_pack_current_timer(__ss.str().c_str()); + char * _tmp = strdup(__ss.str().c_str()); \ + Tau_SOS_conditionally_pack_current_timer(_tmp); \ + free(_tmp); void TAU_SOS_collective_ADIOS_write_event(const char * detail, const char * var_name, enum ADIOS_DATATYPES data_type, const int ndims, const char * dims, const void * value) { std::stringstream ss; + printf("Write Dimensions: %s\n", dims); fflush(stdout); ss << EVENT_TRACE_PREFIX << detail << "(" << var_name << ","; switch(data_type) { case adios_byte: @@ -172,8 +175,9 @@ void TAU_SOS_collective_ADIOS_write_event(const char * detail, ss << "[" << dims << "]"; } ss << ")"; - //printf("%s\n", ss.str().c_str()); - Tau_SOS_conditionally_pack_current_timer(ss.str().c_str()); + char * tmp = strdup(ss.str().c_str()); + Tau_SOS_conditionally_pack_current_timer(tmp); + free(tmp); } #else #define TAU_SOS_COLLECTIVE_ADIOS_EVENT // do nuthin. @@ -230,7 +234,19 @@ ADIOST_EXTERN void tau_adiost_open ( adiost_event_type_t type, TAU_PROFILE_START(tautimer); Tau_increment_stack_height(); } else if (type == adiost_event_exit) { - TAU_SOS_COLLECTIVE_ADIOS_EVENT(function_name); + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " file_descriptor: " << std::hex << file_descriptor << ","; + ss << " group_name: '" << group_name << "',"; + ss << " file_name: '" << file_name << "',"; + ss << " mode: '" << mode << "',"; + ss << " comm: " << std::hex << "0x" << comm << ") " << type; + // need to make a copy of the temporary that comes + // out of this call + char * tmp = strdup(ss.str().c_str()); + Tau_SOS_conditionally_pack_current_timer(tmp); + // delete our copy + free(tmp); TAU_PROFILE_STOP(tautimer); } else { } @@ -244,7 +260,15 @@ ADIOST_EXTERN void tau_adiost_close(adiost_event_type_t type, TAU_PROFILE_START(tautimer); Tau_increment_stack_height(); } else if (type == adiost_event_exit) { - TAU_SOS_COLLECTIVE_ADIOS_EVENT(function_name); + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " file_descriptor: " << std::hex << file_descriptor << ")"; + // need to make a copy of the temporary that comes + // out of this call + char * tmp = strdup(ss.str().c_str()); + Tau_SOS_conditionally_pack_current_timer(tmp); + // delete our copy + free(tmp); TAU_PROFILE_STOP(tautimer); } else { } @@ -784,29 +808,35 @@ ADIOST_EXTERN void tau_adiost_read_init_method( const char * parameters) { const char * function_name = "adios_read_init_method"; TAU_PROFILE_TIMER(tautimer, function_name, " ", TAU_IO); - std::stringstream ss; - ss << EVENT_TRACE_PREFIX << function_name << "("; - ss << " method: " << method << ","; - ss << " comm: " << std::hex << "0x" << comm << ","; - // The parameters has newlines in it - strip them out. - std::string s(parameters); - std::replace(s.begin(), s.end(), '\n', ' '); - std::replace(s.begin(), s.end(), '\r', ' '); - // The parameters are corrupting the SQL insert later, disabled for now - //ss << " parameters: [" << s.c_str() << "]"; - ss << ")"; if (type == adiost_event_enter) { TAU_PROFILE_START(tautimer); + Tau_increment_stack_height(); } else if (type == adiost_event_exit) { + TAU_decrement_stack_height(); TAU_PROFILE_STOP(tautimer); - Tau_increment_stack_height(); } else { // not conditional! neither start nor stop. /*Invoke plugins only if both plugin path and plugins are specified*/ if(TauEnv_get_plugins_enabled()) { + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " method: " << method << ","; + ss << " comm: " << std::hex << "0x" << comm << ","; + // The parameters has newlines in it - strip them out. + std::string s(parameters); + std::replace(s.begin(), s.end(), '\n', ' '); + std::replace(s.begin(), s.end(), '\r', ' '); + // The parameters are corrupting the SQL insert later, disabled for now + ss << " parameters: [" << s.c_str() << "]"; + ss << ")"; Tau_plugin_event_current_timer_exit_data plugin_data; - plugin_data.name_prefix = ss.str().c_str(); + // need to make a copy of the temporary that comes + // out of this call + char * tmp = strdup(ss.str().c_str()); + plugin_data.name_prefix = tmp; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_CURRENT_TIMER_EXIT, &plugin_data); + // delete our copy + free(tmp); } } } @@ -816,20 +846,26 @@ ADIOST_EXTERN void tau_adiost_read_finalize_method( enum ADIOS_READ_METHOD method ) { const char * function_name = "adios_read_finalize_method"; TAU_PROFILE_TIMER(tautimer, function_name, " ", TAU_IO); - std::stringstream ss; - ss << EVENT_TRACE_PREFIX << function_name << "("; - ss << " method: " << method << ")"; if (type == adiost_event_enter) { TAU_PROFILE_START(tautimer); + Tau_increment_stack_height(); } else if (type == adiost_event_exit) { + TAU_decrement_stack_height(); TAU_PROFILE_STOP(tautimer); - Tau_increment_stack_height(); } else { /*Invoke plugins only if both plugin path and plugins are specified*/ if(TauEnv_get_plugins_enabled()) { + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " method: " << method << ")"; Tau_plugin_event_current_timer_exit_data plugin_data; - plugin_data.name_prefix = ss.str().c_str(); + // need to make a copy of the temporary that comes + // out of this call + char * tmp = strdup(ss.str().c_str()); + plugin_data.name_prefix = tmp; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_CURRENT_TIMER_EXIT, &plugin_data); + // delete our copy + free(tmp); } } } @@ -843,18 +879,20 @@ ADIOST_EXTERN void tau_adiost_read_open( ADIOS_FILE * file_descriptor) { const char * function_name = "adios_read_open"; TAU_PROFILE_TIMER(tautimer, function_name, " ", TAU_IO); - std::stringstream ss; - ss << EVENT_TRACE_PREFIX << function_name << "("; - ss << " method: " << method << ","; - ss << " comm: " << std::hex << "0x" << comm << ","; - ss << " lock_mode: " << lock_mode << ","; - ss << " timeout_sec: " << timeout_sec << ","; - ss << " file_descriptor: " << std::hex << file_descriptor << ")"; if (type == adiost_event_enter) { TAU_PROFILE_START(tautimer); Tau_increment_stack_height(); } else if (type == adiost_event_exit) { - Tau_SOS_conditionally_pack_current_timer(ss.str().c_str()); + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " method: " << method << ","; + ss << " comm: " << std::hex << "0x" << comm << ","; + ss << " lock_mode: " << lock_mode << ","; + ss << " timeout_sec: " << timeout_sec << ","; + ss << " file_descriptor: " << std::hex << file_descriptor << ")"; + char * tmp = strdup(ss.str().c_str()); + Tau_SOS_conditionally_pack_current_timer(tmp); + free(tmp); TAU_PROFILE_STOP(tautimer); } else { } @@ -868,17 +906,19 @@ ADIOST_EXTERN void tau_adiost_read_open_file( ADIOS_FILE * file_descriptor) { const char * function_name = "adios_read_open_file"; TAU_PROFILE_TIMER(tautimer, function_name, " ", TAU_IO); - std::stringstream ss; - ss << EVENT_TRACE_PREFIX << function_name << "("; - ss << " fname: '" << fname << "',"; - ss << " method: " << method << ","; - ss << " comm: " << std::hex << "0x" << comm << ","; - ss << " file_descriptor: " << std::hex << file_descriptor << ")"; if (type == adiost_event_enter) { TAU_PROFILE_START(tautimer); Tau_increment_stack_height(); } else if (type == adiost_event_exit) { - Tau_SOS_conditionally_pack_current_timer(ss.str().c_str()); + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " fname: '" << fname << "',"; + ss << " method: " << method << ","; + ss << " comm: " << std::hex << "0x" << comm << ","; + ss << " file_descriptor: " << std::hex << file_descriptor << ")"; + char * tmp = strdup(ss.str().c_str()); + Tau_SOS_conditionally_pack_current_timer(tmp); + free(tmp); TAU_PROFILE_STOP(tautimer); } else { } @@ -891,17 +931,20 @@ ADIOST_EXTERN void tau_adiost_advance_step( float timeout_sec) { const char * function_name = "adios_advance_step"; TAU_PROFILE_TIMER(tautimer, function_name, " ", TAU_IO); - std::stringstream ss; - ss << EVENT_TRACE_PREFIX << function_name << "("; - ss << " fp: " << std::hex << fp << ","; - ss << " last: " << last << ","; - ss << " timeout_sec: " << timeout_sec << ")"; if (type == adiost_event_enter) { TAU_PROFILE_START(tautimer); Tau_increment_stack_height(); } else if (type == adiost_event_exit) { + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " fp: " << std::hex << fp << ","; + ss << " last: " << last << ","; + ss << " timeout_sec: " << timeout_sec << ")"; + char * tmp = strdup(ss.str().c_str()); + printf("%s\n", tmp); fflush(stdout); + Tau_SOS_conditionally_pack_current_timer(tmp); + free(tmp); TAU_PROFILE_STOP(tautimer); - Tau_SOS_conditionally_pack_current_timer(ss.str().c_str()); } else { } } @@ -913,16 +956,18 @@ ADIOST_EXTERN void tau_adiost_inq_var( ADIOS_VARINFO * varinfo) { const char * function_name = "adios_inq_var"; TAU_PROFILE_TIMER(tautimer, function_name, " ", TAU_IO); - std::stringstream ss; - ss << EVENT_TRACE_PREFIX << function_name << "("; - ss << " fp: " << std::hex << fp << ","; - ss << " varname: '" << varname << "',"; - ss << " varinfo: " << std::hex << varinfo << ")"; if (type == adiost_event_enter) { TAU_PROFILE_START(tautimer); Tau_increment_stack_height(); } else if (type == adiost_event_exit) { - Tau_SOS_conditionally_pack_current_timer(ss.str().c_str()); + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " fp: " << std::hex << fp << ","; + ss << " varname: '" << varname << "',"; + ss << " varinfo: " << std::hex << varinfo << ")"; + char * tmp = strdup(ss.str().c_str()); + Tau_SOS_conditionally_pack_current_timer(tmp); + free(tmp); TAU_PROFILE_STOP(tautimer); } else { } @@ -935,16 +980,18 @@ ADIOST_EXTERN void tau_adiost_inq_var_byid( ADIOS_VARINFO * varinfo) { const char * function_name = "adios_inq_var_byid"; TAU_PROFILE_TIMER(tautimer, function_name, " ", TAU_IO); - std::stringstream ss; - ss << EVENT_TRACE_PREFIX << function_name << "("; - ss << " fp: " << std::hex << fp << ","; - ss << " varid: " << varid << ","; - ss << " varinfo: " << std::hex << varinfo << ")"; if (type == adiost_event_enter) { TAU_PROFILE_START(tautimer); Tau_increment_stack_height(); } else if (type == adiost_event_exit) { - Tau_SOS_conditionally_pack_current_timer(ss.str().c_str()); + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " fp: " << std::hex << fp << ","; + ss << " varid: " << varid << ","; + ss << " varinfo: " << std::hex << varinfo << ")"; + char * tmp = strdup(ss.str().c_str()); + Tau_SOS_conditionally_pack_current_timer(tmp); + free(tmp); TAU_PROFILE_STOP(tautimer); } else { } @@ -955,14 +1002,16 @@ ADIOST_EXTERN void tau_adiost_free_varinfo( ADIOS_VARINFO * varinfo) { const char * function_name = "adios_free_varinfo"; TAU_PROFILE_TIMER(tautimer, function_name, " ", TAU_IO); - std::stringstream ss; - ss << EVENT_TRACE_PREFIX << function_name << "("; - ss << " varinfo: " << std::hex << varinfo << ")"; if (type == adiost_event_enter) { TAU_PROFILE_START(tautimer); Tau_increment_stack_height(); } else if (type == adiost_event_exit) { - Tau_SOS_conditionally_pack_current_timer(ss.str().c_str()); + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " varinfo: " << std::hex << varinfo << ")"; + char * tmp = strdup(ss.str().c_str()); + Tau_SOS_conditionally_pack_current_timer(tmp); + free(tmp); TAU_PROFILE_STOP(tautimer); } else { } @@ -1006,30 +1055,32 @@ ADIOST_EXTERN void tau_adiost_selection_boundingbox( ADIOS_SELECTION * selection) { const char * function_name = "adios_selection_boundingbox"; TAU_PROFILE_TIMER(tautimer, function_name, " ", TAU_IO); - std::stringstream ss; - ss << EVENT_TRACE_PREFIX << function_name << "("; - ss << " ndim: " << ndim << ", start: ["; - int i; - if (ndim > 0) { - ss << start[0]; - } - for (i = 1 ; i < ndim ; i++) { - ss << "," << start[i]; - } - ss << "], end: ["; - if (ndim > 0) { - ss << count[0]; - } - for (i = 1 ; i < ndim ; i++) { - ss << "," << count[i]; - } - ss << "],"; - ss << " selection: " << std::hex << selection << ")"; if (type == adiost_event_enter) { TAU_PROFILE_START(tautimer); Tau_increment_stack_height(); } else if (type == adiost_event_exit) { - Tau_SOS_conditionally_pack_current_timer(ss.str().c_str()); + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " ndim: " << ndim << ", start: ["; + int i; + if (ndim > 0) { + ss << start[0]; + } + for (i = 1 ; i < ndim ; i++) { + ss << "," << start[i]; + } + ss << "], end: ["; + if (ndim > 0) { + ss << count[0]; + } + for (i = 1 ; i < ndim ; i++) { + ss << "," << count[i]; + } + ss << "],"; + ss << " selection: " << std::hex << selection << ")"; + char * tmp = strdup(ss.str().c_str()); + Tau_SOS_conditionally_pack_current_timer(tmp); + free(tmp); TAU_PROFILE_STOP(tautimer); } else { } @@ -1086,14 +1137,16 @@ ADIOST_EXTERN void tau_adiost_selection_delete( ADIOS_SELECTION * selection) { const char * function_name = "adios_selection_delete"; TAU_PROFILE_TIMER(tautimer, function_name, " ", TAU_IO); - std::stringstream ss; - ss << EVENT_TRACE_PREFIX << function_name << "("; - ss << " selection: " << std::hex << selection << ")"; if (type == adiost_event_enter) { TAU_PROFILE_START(tautimer); Tau_increment_stack_height(); } else if (type == adiost_event_exit) { - Tau_SOS_conditionally_pack_current_timer(ss.str().c_str()); + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " selection: " << std::hex << selection << ")"; + char * tmp = strdup(ss.str().c_str()); + Tau_SOS_conditionally_pack_current_timer(tmp); + free(tmp); TAU_PROFILE_STOP(tautimer); } else { } @@ -1110,27 +1163,29 @@ ADIOST_EXTERN void tau_adiost_schedule_read( void * data) { const char * function_name = "adios_schedule_read"; TAU_PROFILE_TIMER(tautimer, function_name, " ", TAU_IO); - std::stringstream ss; - ss << EVENT_TRACE_PREFIX << function_name << "("; - ss << " fp: " << std::hex << fp << ","; - ss << " selection: " << std::hex << selection << ","; - ss << " varname: '" << varname << "',"; - ss << " from_steps: " << from_steps << ","; - ss << " nsteps: " << nsteps << ", param: '"; - if (param != NULL) { - std::string s(param); - std::replace(s.begin(), s.end(), '\n', ' '); - std::replace(s.begin(), s.end(), '\r', ' '); - std::replace(s.begin(), s.end(), ';', ','); - ss << s.c_str(); - } - ss << "',"; - ss << " data: " << std::hex << data << ")"; if (type == adiost_event_enter) { TAU_PROFILE_START(tautimer); Tau_increment_stack_height(); } else if (type == adiost_event_exit) { - Tau_SOS_conditionally_pack_current_timer(ss.str().c_str()); + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " fp: " << std::hex << fp << ","; + ss << " selection: " << std::hex << selection << ","; + ss << " varname: '" << varname << "',"; + ss << " from_steps: " << from_steps << ","; + ss << " nsteps: " << nsteps << ", param: '"; + if (param != NULL) { + std::string s(param); + std::replace(s.begin(), s.end(), '\n', ' '); + std::replace(s.begin(), s.end(), '\r', ' '); + std::replace(s.begin(), s.end(), ';', ','); + ss << s.c_str(); + } + ss << "',"; + ss << " data: " << std::hex << data << ")"; + char * tmp = strdup(ss.str().c_str()); + Tau_SOS_conditionally_pack_current_timer(tmp); + free(tmp); TAU_PROFILE_STOP(tautimer); } else { } @@ -1147,27 +1202,29 @@ ADIOST_EXTERN void tau_adiost_schedule_read_byid( void * data) { const char * function_name = "adios_schedule_read_byid"; TAU_PROFILE_TIMER(tautimer, function_name, " ", TAU_IO); - std::stringstream ss; - ss << EVENT_TRACE_PREFIX << function_name << "("; - ss << " fp: " << std::hex << fp << ","; - ss << " selection: " << std::hex << selection << ","; - ss << " varid: " << varid << ","; - ss << " from_steps: " << from_steps << ","; - ss << " nsteps: " << nsteps << ", param: '"; - if (param != NULL) { - std::string s(param); - std::replace(s.begin(), s.end(), '\n', ' '); - std::replace(s.begin(), s.end(), '\r', ' '); - std::replace(s.begin(), s.end(), ';', ','); - ss << s.c_str(); - } - ss << "',"; - ss << " data: " << std::hex << data << ")"; if (type == adiost_event_enter) { TAU_PROFILE_START(tautimer); Tau_increment_stack_height(); } else if (type == adiost_event_exit) { - Tau_SOS_conditionally_pack_current_timer(ss.str().c_str()); + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " fp: " << std::hex << fp << ","; + ss << " selection: " << std::hex << selection << ","; + ss << " varid: " << varid << ","; + ss << " from_steps: " << from_steps << ","; + ss << " nsteps: " << nsteps << ", param: '"; + if (param != NULL) { + std::string s(param); + std::replace(s.begin(), s.end(), '\n', ' '); + std::replace(s.begin(), s.end(), '\r', ' '); + std::replace(s.begin(), s.end(), ';', ','); + ss << s.c_str(); + } + ss << "',"; + ss << " data: " << std::hex << data << ")"; + char * tmp = strdup(ss.str().c_str()); + Tau_SOS_conditionally_pack_current_timer(tmp); + free(tmp); TAU_PROFILE_STOP(tautimer); } else { } @@ -1179,15 +1236,17 @@ ADIOST_EXTERN void tau_adiost_perform_reads( int blocking) { const char * function_name = "adios_perform_reads"; TAU_PROFILE_TIMER(tautimer, function_name, " ", TAU_IO); - std::stringstream ss; - ss << EVENT_TRACE_PREFIX << function_name << "("; - ss << " fp: " << std::hex << fp << ","; - ss << " blocking: " << blocking << ")"; if (type == adiost_event_enter) { TAU_PROFILE_START(tautimer); Tau_increment_stack_height(); } else if (type == adiost_event_exit) { - Tau_SOS_conditionally_pack_current_timer(ss.str().c_str()); + std::stringstream ss; + ss << EVENT_TRACE_PREFIX << function_name << "("; + ss << " fp: " << std::hex << fp << ","; + ss << " blocking: " << blocking << ")"; + char * tmp = strdup(ss.str().c_str()); + Tau_SOS_conditionally_pack_current_timer(tmp); + free(tmp); TAU_PROFILE_STOP(tautimer); } else { } From 8712b7deb8f168789e53ddd1fc80a229109991f7 Mon Sep 17 00:00:00 2001 From: Sameer Shende Date: Thu, 31 May 2018 10:14:21 -0700 Subject: [PATCH 13/60] LLNL has a weird icpc compiler. icpc -v returns icpc.orig version 18... instead of icpc version 18... This checks for such strangeness and allows it. We need to watch out for Intel 20x later in a couple of years. Former-commit-id: 7b5d8cfc255c88cbf3b41f8a567f219649a8a44d --- configure | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 4bcd7ecec..4ab1f2bff 100755 --- a/configure +++ b/configure @@ -10396,10 +10396,13 @@ if [ $cxx_compiler = icpc -o $cxx_compiler = mpiicpc ] ; then version=`icpc -v 2>&1` t="Version 1" t1="icpc version 1" + t2="icpc.orig version 1" testarg=${version#$t} testarg1=${version#$t1} + testarg2=${version#$t2} - if [ "y$testarg" != "y$version" -o "y$testarg1" != "y$version" ] ; then + + if [ "y$testarg" != "y$version" -o "y$testarg1" != "y$version" -o "y$testarg2" != "y$version" ] ; then echo "Intel v10.0+ compilers found" fixmakeargs="$fixmakeargs INTEL10FIX COMPINST_GNU" else From 226b5540a163b9609d800fc2c4efc076c4b9e462 Mon Sep 17 00:00:00 2001 From: Sameer Shende Date: Thu, 31 May 2018 18:28:03 -0700 Subject: [PATCH 14/60] Added a fix for getting EXTRADIR for IBM XL compilers with MVAPICH2. They changed the lib directory to alllibs. Former-commit-id: 2f5bb5d41185438aa353237e488e89c4a08b7a2c --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 4ab1f2bff..47b5044e9 100755 --- a/configure +++ b/configure @@ -4126,8 +4126,8 @@ case $cxx_compiler in if [ "$machine" = ibm64linux ] ; then if [ ! -r $extradircxx/lib/libibmc++.a ]; then - cxxpath=`find $extradircxx -name libibmc++.a -print ` - extradircxx=`echo $cxxpath | sed -e 's@lib/libibmc++.a@@g' ` + cxxpath=`find $extradircxx -name libibmc++.a -print | tail -1` + extradircxx=`echo $cxxpath | sed -e 's@lib/libibmc++.a@@g' -e 's@alllibs/libibmc++.a@@g'` fi fi From 492386d9f58d730035f6f42c01bd705e2dd9d4aa Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Fri, 1 Jun 2018 13:21:25 -0700 Subject: [PATCH 15/60] Removing debug message Former-commit-id: bb6538f5ac3d8cddc4f355882a6d4d7d300adc65 --- src/Profile/TauADIOS.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Profile/TauADIOS.cpp b/src/Profile/TauADIOS.cpp index 77ba3a7d8..8bd3411f4 100644 --- a/src/Profile/TauADIOS.cpp +++ b/src/Profile/TauADIOS.cpp @@ -106,7 +106,6 @@ void TAU_SOS_collective_ADIOS_write_event(const char * detail, const char * var_name, enum ADIOS_DATATYPES data_type, const int ndims, const char * dims, const void * value) { std::stringstream ss; - printf("Write Dimensions: %s\n", dims); fflush(stdout); ss << EVENT_TRACE_PREFIX << detail << "(" << var_name << ","; switch(data_type) { case adios_byte: From 151a6ce360a3f8d9d11b6d4db34f98de9a2199d9 Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Fri, 1 Jun 2018 13:37:10 -0700 Subject: [PATCH 16/60] Removing debug message Former-commit-id: 8cf98bc3d9cce48438a30bff362f958a485fd0b5 --- src/Profile/TauADIOS.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Profile/TauADIOS.cpp b/src/Profile/TauADIOS.cpp index 8bd3411f4..43cf6a88d 100644 --- a/src/Profile/TauADIOS.cpp +++ b/src/Profile/TauADIOS.cpp @@ -940,7 +940,6 @@ ADIOST_EXTERN void tau_adiost_advance_step( ss << " last: " << last << ","; ss << " timeout_sec: " << timeout_sec << ")"; char * tmp = strdup(ss.str().c_str()); - printf("%s\n", tmp); fflush(stdout); Tau_SOS_conditionally_pack_current_timer(tmp); free(tmp); TAU_PROFILE_STOP(tautimer); From 0ff66a764658d254d81c3adc4d4b540ba0b0ad22 Mon Sep 17 00:00:00 2001 From: Wyatt Spear Date: Mon, 4 Jun 2018 14:45:53 -0700 Subject: [PATCH 17/60] Wrapped cray metadata calls in ifdef TAU_CRAYCNL. Invalid metadata entries could result otherwise. Former-commit-id: c9d489d1b15fbd9255b6d87db1a1676ea241cb3c --- src/Profile/TauMetaData.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Profile/TauMetaData.cpp b/src/Profile/TauMetaData.cpp index c764f62bb..d90215433 100644 --- a/src/Profile/TauMetaData.cpp +++ b/src/Profile/TauMetaData.cpp @@ -797,7 +797,7 @@ extern "C" int writeMetaDataAfterMPI_Init(void) { #endif /* TAU_FUJITSU && TAU_MPI */ /****** CRAY RELATED DATA *********/ - +#ifdef TAU_CRAYCNL FILE* procfile = fopen("/proc/self/stat", "r"); long to_read = 8192; char buffer[to_read]; @@ -814,6 +814,7 @@ extern "C" int writeMetaDataAfterMPI_Init(void) { } line = strtok(NULL, " "); + printf("WEIRD CRAY LINE: %s", line); Tau_metadata_register("CRAY_CORE_ID", line); } @@ -855,7 +856,7 @@ extern "C" int writeMetaDataAfterMPI_Init(void) { Tau_metadata_register("CRAY_TOPO_SLOT_ID", slot); Tau_metadata_register("CRAY_TOPO_NODE_ID", node); } - +#endif /****** END CRAY RELATED DATA *********/ return 0; From 5495525f1e645607352e7ca8a49bcf692fc34338 Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Mon, 4 Jun 2018 16:05:58 -0700 Subject: [PATCH 18/60] Adding the caching parameter to SOS config Former-commit-id: 41c9adc8d9fd854b03b517f0410ae3fbcdf5b1aa --- plugins/examples/TauSOS.cpp | 5 +++-- plugins/examples/TauSOS.h | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/examples/TauSOS.cpp b/plugins/examples/TauSOS.cpp index 5469aa260..24d02990d 100644 --- a/plugins/examples/TauSOS.cpp +++ b/plugins/examples/TauSOS.cpp @@ -116,11 +116,10 @@ void TAU_SOS_make_pub() { _runtime->config.comm_size = comm_size; #endif -/* Fixme! Replace these with values from TAU metadata. */ sprintf(pub_name, "TAU_SOS_SUPPORT"); sprintf(app_version, "v0.alpha"); -/* Fixme! Replace these with values from TAU metadata. */ SOS_pub_init(_runtime, &tau_sos_pub, pub_name, SOS_NATURE_DEFAULT); + SOS_pub_config(tau_sos_pub, SOS_PUB_OPTION_CACHE, thePluginOptions().env_sos_cache_depth); strcpy(tau_sos_pub->prog_ver, app_version); tau_sos_pub->meta.channel = 1; @@ -341,6 +340,8 @@ void TAU_SOS_parse_environment_variables(void) { if (parse_bool(tmp, TAU_SOS_TRACING_DEFAULT)) { thePluginOptions().env_sos_tracing = 1; } + tmp = getenv("TAU_SOS_CACHE_DEPTH"); + thePluginOptions().env_sos_cache_depth = parse_int(tmp, TAU_SOS_CACHE_DEPTH_DEFAULT); tmp = getenv("TAU_SOS_PERIODIC"); if (parse_bool(tmp, TAU_SOS_PERIODIC_DEFAULT)) { thePluginOptions().env_sos_periodic = 1; diff --git a/plugins/examples/TauSOS.h b/plugins/examples/TauSOS.h index ae0a1a1ec..ce497e5f7 100644 --- a/plugins/examples/TauSOS.h +++ b/plugins/examples/TauSOS.h @@ -13,6 +13,7 @@ #define TAU_SOS_PERIOD_DEFAULT 2000000 // microseconds #define TAU_SOS_SHUTDOWN_DELAY_DEFAULT 10 // seconds #define TAU_SOS_USE_SELECTION_DEFAULT 0 // microseconds +#define TAU_SOS_CACHE_DEPTH_DEFAULT 10 // SOS frames class SOS_plugin_options { private: @@ -23,7 +24,8 @@ class SOS_plugin_options { env_sos_periodic(TAU_SOS_PERIODIC_DEFAULT), env_sos_period(TAU_SOS_PERIOD_DEFAULT), env_sos_shutdown_delay(TAU_SOS_SHUTDOWN_DELAY_DEFAULT), - env_sos_use_selection(TAU_SOS_USE_SELECTION_DEFAULT) {} + env_sos_use_selection(TAU_SOS_USE_SELECTION_DEFAULT), + env_sos_cache_depth(TAU_SOS_CACHE_DEPTH_DEFAULT) {} public: int env_sos_enabled; int env_sos_tracing; @@ -32,6 +34,7 @@ class SOS_plugin_options { int env_sos_period; int env_sos_shutdown_delay; int env_sos_use_selection; + int env_sos_cache_depth; std::set included_timers; std::set excluded_timers; std::set included_counters; From 18a1b9fe3a329afcdfc2f7bf82f61073d2e1c998 Mon Sep 17 00:00:00 2001 From: Aurele MAHEO Date: Tue, 5 Jun 2018 14:31:39 -0700 Subject: [PATCH 19/60] [MPC] Remove internal print statements Former-commit-id: 5003c996cfbfd4e8d2720e6996ae4224200a0ecc --- src/Profile/TauMpi.c | 4 ---- src/wrappers/mpc_mpi/wr.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index 26a01784f..45a13389d 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -1928,8 +1928,6 @@ int MPI_Finalize( ) returnVal = PMPI_Finalize(); - fprintf(stdout, "PMPI_Finalize() return=%d\n", returnVal); - TAU_PROFILE_STOP(tautimer); Tau_stop_top_level_timer_if_necessary(); @@ -1983,8 +1981,6 @@ char *** argv; char procname[MPI_MAX_PROCESSOR_NAME]; int procnamelength; - fprintf(stdout, "TAU: MPI_Init() MPC after wrapping\n"); - if(Tau_get_usesMPI() == 0) { diff --git a/src/wrappers/mpc_mpi/wr.c b/src/wrappers/mpc_mpi/wr.c index 5a313b859..a837001a3 100644 --- a/src/wrappers/mpc_mpi/wr.c +++ b/src/wrappers/mpc_mpi/wr.c @@ -2161,8 +2161,6 @@ int __wrap_MPI_Init(int * a1, char *** a2) { char procname[MPI_MAX_PROCESSOR_NAME]; int procnamelength; - fprintf(stdout, "TAU: MPI_Init() MPC after wrapping\n"); - if(Tau_get_usesMPI() == 0) { @@ -2482,8 +2480,6 @@ int __wrap_MPI_Finalize() { returnVal = __real_MPI_Finalize(); - fprintf(stdout, "PMPI_Finalize() return=%d\n", returnVal); - TAU_PROFILE_STOP(tautimer); Tau_stop_top_level_timer_if_necessary(); From 42339df5d5e2bdc2c8e5596b732aeac7a6a37b2b Mon Sep 17 00:00:00 2001 From: Aurele MAHEO Date: Tue, 5 Jun 2018 18:36:03 -0700 Subject: [PATCH 20/60] Activate TAU_MPI_Finalized() function for any MPI implementation (including MPC) Former-commit-id: aed3f693199cab7cbea15ee6af120d7334a9ba53 --- src/Profile/TauMpi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index 45a13389d..f56bc0b46 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -1793,13 +1793,11 @@ MPI_Errhandler errhandler; return returnVal; } -#if 0 int tau_mpi_finalized = 0; int TAU_MPI_Finalized() { - fprintf(stdout, "In TAU_MPI_Finalized(): tau_mpi_finalized=%d\n", tau_mpi_finalized); + //fprintf(stdout, "In TAU_MPI_Finalized(): tau_mpi_finalized=%d\n", tau_mpi_finalized); return tau_mpi_finalized; } -#endif void finalizeCallSites_if_necessary(); int MPI_Finalize( ) From 4b6249a1ab9bda089e2e87196edaf0981ce4ffa9 Mon Sep 17 00:00:00 2001 From: Aurele MAHEO Date: Tue, 5 Jun 2018 20:58:34 -0700 Subject: [PATCH 21/60] [MPC] Implement TAU_MPI_Finalized() function in TauMpi.c only if using non MPC MPI support Former-commit-id: f49293ffb10c2d8473cb76c609d3594f59c5ca7a --- src/Profile/TauMpi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index f56bc0b46..09ab04017 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -1793,11 +1793,13 @@ MPI_Errhandler errhandler; return returnVal; } +#if !defined(TAU_MPC) int tau_mpi_finalized = 0; int TAU_MPI_Finalized() { //fprintf(stdout, "In TAU_MPI_Finalized(): tau_mpi_finalized=%d\n", tau_mpi_finalized); return tau_mpi_finalized; } +#endif void finalizeCallSites_if_necessary(); int MPI_Finalize( ) From 1ea9e03ffeca534d562b72f72b7b63601c40e02a Mon Sep 17 00:00:00 2001 From: Sameer Shende Date: Sat, 9 Jun 2018 00:40:00 +0000 Subject: [PATCH 22/60] Added support for -c++=armclang++ -cc=armclang -fortran=armflang and -c++=mpicxx -cc=mpicc -fortran=mpif90 where these compilers internally call the ARM CLANG/FLANG compilers. Former-commit-id: fe86b5a2cbc46ff37ebfec2ee3114404c15c5938 --- Changes | 1 + configure | 33 ++++++++++++++++++++------------- include/Makefile.skel | 2 ++ utils/FixMakefile | 4 ++++ 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/Changes b/Changes index 029242ac6..b2d347e00 100644 --- a/Changes +++ b/Changes @@ -29,6 +29,7 @@ Version 2.27 changes (from 2.26): 16. Added support for OMPT TR6 (configure -ompt=download-tr6 with export TAU_OMPT_SUPPORT_LEVEL=full). 17. Added support for LIKWID 4.3.2. 18. Added Python args support. +19. Added support for armflang and armclang/armclang++ compilers. Version 2.26 changes (from 2.25): 1. Upgraded OMPT to LLVM-0.2 and introduced TAU_OPENMP_RUNTIME_EVENTS=0. diff --git a/configure b/configure index 47b5044e9..284f28a5b 100755 --- a/configure +++ b/configure @@ -478,12 +478,13 @@ for arg in "$@"; do echo "Compiler Options:" echo "-c++= ............................ specify the C++ compiler." echo " options [CC|KCC|g++|*xlC*|cxx|pgc++|pgcpp|FCC|guidec++|aCC|c++|ecpc|" - echo " clang++|bgclang++|g++4|g++-*|icpc|scgcc|scpathCC|pathCC|orCC]." + echo " armclang++|clang++|bgclang++|g++4|g++-*|icpc|scgcc|scpathCC|pathCC|orCC]." echo "-cc= ................................ specify the C compiler." - echo " options [cc|gcc|clang|bgclang|gcc4|scgcc|KCC|pgcc|guidec|*xlc*|ecc|pathcc|orcc]." + echo " options [cc|gcc|clang|bgclang|gcc4|scgcc|KCC|pgcc|guidec|*xlc*|ecc|" + echo " armclang|pathcc|orcc]." echo "-fortran= ..................... specify the Fortran compiler." echo " options [gnu|sgi|ibm|ibm64|hp|cray|pgi|absoft|fujitsu|sun|compaq|" - echo " g95|open64|kai|nec|hitachi|intel|absoft|lahey|nagware|pathscale}" + echo " armflang|g95|open64|kai|nec|hitachi|intel|absoft|lahey|nagware|pathscale}" echo " gfortran|gfortran-*|gfortran4]" echo "-upc= ............................. specify the UPC compiler." echo " options [upc|gcc(GNU UPC) |upcc (Berkeley UPC) | cc (Cray CCE UPC)" @@ -630,13 +631,13 @@ for arg in "$@"; do echo " where [OPTIONS] are:" echo "-c++= ............................ specify the C++ compiler." echo " options [CC|KCC|g++|*xlC*|cxx|pgc++|pgcpp|FCC|guidec++|aCC|c++|ecpc|" - echo " clang++|bgclang++|g++4|icpc|scgcc|scpathCC|pathCC|orCC]." + echo " armclang++|clang++|bgclang++|g++4|icpc|scgcc|scpathCC|pathCC|orCC]." echo "-cc= ................................ specify the C compiler." - echo " options [cc|gcc|gcc4|scgcc|clang|pgcc|guidec|*xlc*|ecc|pathcc|orcc]." + echo " options [cc|gcc|gcc4|scgcc|clang|pgcc|guidec|*xlc*|ecc|pathcc|orcc|armclang]." echo "-fortran= ..................... specify the Fortran compiler." echo " options [gnu|sgi|ibm|ibm64|hp|cray|pgi|absoft|fujitsu|sun|compaq|" - echo " g95|open64|kai|nec|hitachi|intel|absoft|lahey|nag|nagware|pathscale}" - echo " gfortran|gfortran-*|gfortran4]" + echo " g95|open64|kai|nec|hitachi|intel|absoft|lahey|nag|nagware|pathscale}" + echo " armflang|gfortran|gfortran-*|gfortran4]" echo "-upc= ............................. specify the UPC compiler." echo " options [upc|gcc(GNU UPC) |upcc (Berkeley UPC) | cc (Cray CCE UPC)" echo "-host= ................ the type of system on which TAU runs" @@ -1113,7 +1114,7 @@ for arg in "$@"; do -cc=*) myarg=`echo $arg | sed 's/-cc=//'` - if [ $myarg = cc -o $myarg = gcc -o $myarg = gcc4 -o $myarg = gcc-5 -o $myarg = gcc-6 -o $myarg = gcc-7 -o $myarg = gcc-8 -o $myarg = KCC -o $myarg = pgcc -o $myarg = guidec -o $myarg = xlc -o $myarg = ecc -o $myarg = icc -o $myarg = powerpc64-linux-gcc -o $myarg = pathcc -o $myarg = fcc -o $myarg = orcc -o $myarg = opencc -o $myarg = qk-pgcc -o $myarg = scgcc -o $myarg = scpathcc -o $myarg = mips64el-gentoo-linux-gnu-gcc -o $myarg = powerpc64-bgq-linux-gcc -o $myarg = powerpc-bgp-linux-gcc -o $myarg = x86_64-w64-mingw32-gcc -o $myarg = mpiicc -o $myarg = mpifcc -o $myarg = mpifccpx -o $myarg = clang -o $myarg = bgclang -o $myarg = mpc_cc -o $myarg = mpc_icc -o $myarg = mpicc -o $myarg = mcc -o $myarg = oshcc ] + if [ $myarg = cc -o $myarg = gcc -o $myarg = gcc4 -o $myarg = gcc-5 -o $myarg = gcc-6 -o $myarg = gcc-7 -o $myarg = gcc-8 -o $myarg = KCC -o $myarg = pgcc -o $myarg = guidec -o $myarg = xlc -o $myarg = ecc -o $myarg = icc -o $myarg = powerpc64-linux-gcc -o $myarg = pathcc -o $myarg = fcc -o $myarg = orcc -o $myarg = opencc -o $myarg = qk-pgcc -o $myarg = scgcc -o $myarg = scpathcc -o $myarg = mips64el-gentoo-linux-gnu-gcc -o $myarg = powerpc64-bgq-linux-gcc -o $myarg = powerpc-bgp-linux-gcc -o $myarg = x86_64-w64-mingw32-gcc -o $myarg = mpiicc -o $myarg = mpifcc -o $myarg = mpifccpx -o $myarg = clang -o $myarg = bgclang -o $myarg = mpc_cc -o $myarg = mpc_icc -o $myarg = mpicc -o $myarg = mcc -o $myarg = oshcc -o $myarg = armclang ] then c_compiler=$myarg @@ -1142,7 +1143,7 @@ for arg in "$@"; do -c++=*) myarg=`echo $arg | sed 's/-c++=//'` - if [ $myarg = CC -o $myarg = KCC -o $myarg = g++ -o $myarg = g++4 -o $myarg = g++-5 -o $myarg = g++-6 -o $myarg = g++-7 -o $myarg = g++-8 -o $myarg = cxx -o $myarg = NCC -o $myarg = pgc++ -o $myarg = pgCC -o $myarg = pgcpp -o $myarg = egcs -o $myarg = FCC -o $myarg = guidec++ -o $myarg = aCC -o $myarg = c++ -o $myarg = ecpc -o $myarg = icpc -o $myarg = powerpc64-linux-g++ -o $myarg = pathCC -o $myarg = orCC -o $myarg = openCC -o $myarg = qk-pgCC -o $myarg = scg++ -o $myarg = scpathCC -o $myarg = mips64el-gentoo-linux-gnu-g++ -o $myarg = powerpc-bgp-linux-g++ -o $myarg = powerpc64-bgq-linux-g++ -o $myarg = mpicxx -o $myarg = x86_64-w64-mingw32-g++ -o $myarg = mpiicpc -o $myarg = mpiFCC -o $myarg = mpiFCCpx -o $myarg = mpc_cxx -o $myarg = mpc_icpc -o $myarg = clang++ -o $myarg = bgclang++ -o $myarg = mpicxx -o $myarg = mcxx -o $myarg = oshCC -o $myarg = oshc++ -o $myarg = oshcxx ] + if [ $myarg = CC -o $myarg = KCC -o $myarg = g++ -o $myarg = g++4 -o $myarg = g++-5 -o $myarg = g++-6 -o $myarg = g++-7 -o $myarg = g++-8 -o $myarg = cxx -o $myarg = NCC -o $myarg = pgc++ -o $myarg = pgCC -o $myarg = pgcpp -o $myarg = egcs -o $myarg = FCC -o $myarg = guidec++ -o $myarg = aCC -o $myarg = c++ -o $myarg = ecpc -o $myarg = icpc -o $myarg = powerpc64-linux-g++ -o $myarg = pathCC -o $myarg = orCC -o $myarg = openCC -o $myarg = qk-pgCC -o $myarg = scg++ -o $myarg = scpathCC -o $myarg = mips64el-gentoo-linux-gnu-g++ -o $myarg = powerpc-bgp-linux-g++ -o $myarg = powerpc64-bgq-linux-g++ -o $myarg = mpicxx -o $myarg = x86_64-w64-mingw32-g++ -o $myarg = mpiicpc -o $myarg = mpiFCC -o $myarg = mpiFCCpx -o $myarg = mpc_cxx -o $myarg = mpc_icpc -o $myarg = clang++ -o $myarg = bgclang++ -o $myarg = mpicxx -o $myarg = mcxx -o $myarg = oshCC -o $myarg = oshc++ -o $myarg = oshcxx -o $myarg = armclang++ ] then cxx_compiler=$myarg if [ $cxx_compiler = mpc_cxx -o $cxx_compiler = mpc_icpc ] @@ -1156,7 +1157,7 @@ for arg in "$@"; do testmp=`echo $myarg | sed -e 's/^mp//'` if [ "y$testxlc" = "y$myarg" -a "y$testmp" = "y$myarg" ] then - echo "WARNING: valid options for c++ are 'CC', 'KCC', 'g++', 'g++4', '*xlC*', 'cxx' , 'NCC', 'egcs', 'pgCC', 'pgcpp', 'FCC', 'guidec++', 'aCC', 'ecpc', 'icpc', 'pathCC', 'c++', 'qk-pgCC', 'x86_64-w64-mingw32-g++', 'mpiicpc', 'mpiFCC', 'mpiFCCpx', 'orCC', 'openCC', 'mpc_cxx', 'mpc_icpc', 'clang++', 'bgclang++', 'mpicxx', 'mcxx', 'oshCC', oshcxx, or 'oshc++' " + echo "WARNING: valid options for c++ are 'CC', 'KCC', 'g++', 'g++4', '*xlC*', 'cxx' , 'NCC', 'egcs', 'pgCC', 'pgcpp', 'FCC', 'guidec++', 'aCC', 'ecpc', 'icpc', 'pathCC', 'c++', 'qk-pgCC', 'x86_64-w64-mingw32-g++', 'mpiicpc', 'mpiFCC', 'mpiFCCpx', 'orCC', 'openCC', 'mpc_cxx', 'mpc_icpc', 'clang++', 'bgclang++', 'mpicxx', 'mcxx', 'oshCC', oshcxx, 'oshc++', or 'armclang++' " # exit 1 else if [ "y$testxlc" != "y$myarg" ] @@ -1180,14 +1181,14 @@ for arg in "$@"; do -fortran=*) myarg=`echo $arg | sed 's/-fortran=//'` - if [ $myarg = gnu -o $myarg = sgi -o $myarg = ibm -o $myarg = ibm64 -o $myarg = hp -o $myarg = cray -o $myarg = pgi -o $myarg = pgf90 -o $myarg = absoft -o $myarg = fujitsu -o $myarg = sun -o $myarg = compaq -o $myarg = kai -o $myarg = hitachi -o $myarg = intel -o $myarg = ifort -o $myarg = nec -o $myarg = absoft -o $myarg = lahey -o $myarg = nagware -o $myarg = nag -o $myarg = pathscale -o $myarg = gfortran -o $myarg = gfortran-5 -o $myarg = gfortran-6 -o $myarg = gfortran-7 -o $myarg = gfortran-8 -o $myarg = gfortran4 -o $myarg = g95 -o $myarg = open64 -o $myarg = openf90 -o $myarg = mpiifort -o $myarg = mpifrtpx -o $myarg = mpifrt -o $myarg = frt -o $myarg = mpif90 -o $myarg = mpc_f77 -o $myarg = mpc_ifort -o $myarg = mpc_gfortran -o $myarg = oshfort -o $myarg = caf ] ; then + if [ $myarg = gnu -o $myarg = sgi -o $myarg = ibm -o $myarg = ibm64 -o $myarg = hp -o $myarg = cray -o $myarg = pgi -o $myarg = pgf90 -o $myarg = absoft -o $myarg = fujitsu -o $myarg = sun -o $myarg = compaq -o $myarg = kai -o $myarg = hitachi -o $myarg = intel -o $myarg = ifort -o $myarg = nec -o $myarg = absoft -o $myarg = lahey -o $myarg = nagware -o $myarg = nag -o $myarg = pathscale -o $myarg = gfortran -o $myarg = gfortran-5 -o $myarg = gfortran-6 -o $myarg = gfortran-7 -o $myarg = gfortran-8 -o $myarg = gfortran4 -o $myarg = g95 -o $myarg = open64 -o $myarg = openf90 -o $myarg = mpiifort -o $myarg = mpifrtpx -o $myarg = mpifrt -o $myarg = frt -o $myarg = mpif90 -o $myarg = mpc_f77 -o $myarg = mpc_ifort -o $myarg = mpc_gfortran -o $myarg = oshfort -o $myarg = caf -o $myarg = armflang ] ; then if [ $myarg = gnu ] ; then fortran_compiler=gfortran else fortran_compiler=$myarg fi else - echo "WARNING: valid options for fortran are 'gnu', 'sgi', 'ibm', 'ibm64', 'hp', 'cray', 'pgi', 'pgf90', 'absoft', 'fujitsu', 'sun', 'compaq', 'kai', 'hitachi', 'intel', 'ifort', 'nec' , 'absoft', 'lahey', 'nag/nagware', 'pathscale', 'gfortran', 'gfortran-*', 'g95', 'open64', 'openf90', 'mpiifort', 'mpifrtpx', 'frtpx', 'frt', 'mpifrt', 'mpif90', 'mpc_f77', or 'mpc_ifort', 'mpc_gfortran', 'oshfort', or 'caf' " + echo "WARNING: valid options for fortran are 'gnu', 'sgi', 'ibm', 'ibm64', 'hp', 'cray', 'pgi', 'pgf90', 'absoft', 'fujitsu', 'sun', 'compaq', 'kai', 'hitachi', 'intel', 'ifort', 'nec' , 'absoft', 'lahey', 'nag/nagware', 'pathscale', 'gfortran', 'gfortran-*', 'g95', 'open64', 'openf90', 'mpiifort', 'mpifrtpx', 'frtpx', 'frt', 'mpifrt', 'mpif90', 'mpc_f77', or 'mpc_ifort', 'mpc_gfortran', 'oshfort', 'caf', or 'armflang' " exit 1 fi shift @@ -3523,6 +3524,9 @@ case $machine in fortran_compiler=gfortran fi fi + if [ "x$fortran_compiler" = "xarmflang" ]; then + fixmakeargs="$fixmakeargs ARMFLANG" + fi if [ $c_compiler = default ] then @@ -3892,6 +3896,9 @@ if [ $cxx_compiler = mpicxx ] ; then if [ "x$fortran_compiler" = "xxlflang" ]; then fixmakeargs="$fixmakeargs XLFLANG" fi + if [ "x$fortran_compiler" = "xarmflang" ]; then + fixmakeargs="$fixmakeargs ARMFLANG" + fi if [ "x$orig_fortran_compiler" = "xcaf" ]; then fortran_compiler=caf fi @@ -6966,7 +6973,7 @@ if [ "x$mpiinc" != "x" -o "x$mpilib" != "x" -o $mpi = yes ] ; then then mpiwarnings="-qhalt=w" fi - if [ $c_compiler = "clang" ] + if [ $c_compiler = "clang" -o $c_compiler = "armclang" ] then mpiwarnings="-Werror" fi diff --git a/include/Makefile.skel b/include/Makefile.skel index 1ee120c7c..f51a6bdf4 100644 --- a/include/Makefile.skel +++ b/include/Makefile.skel @@ -416,6 +416,7 @@ TAU_OPENMP_OPTION = #IBM_FORTRAN#TAU_F90 = xlf90$(TAU_R) $(F90_ABI) $(TAU_F90_OPT) #ENDIF# #IBM64LINUX_XLF#TAU_F90 = xlf90$(TAU_R) $(F90_ABI) $(TAU_F90_OPT) #ENDIF# #XLFLANG#TAU_F90 = xlflang $(F90_ABI) $(TAU_F90_OPT) #ENDIF# +#ARMFLANG#TAU_F90 = armflang $(F90_ABI) $(TAU_F90_OPT) #ENDIF# #BGP#TAU_F90 = /bgsys/drivers/ppcfloor/comm/xl/bin/mpixlf90$(TAU_R) $(F90_ABI) $(TAU_F90_OPT) #ENDIF# #BGP_GFORTRAN#TAU_F90 = mpif90 $(F90_ABI) $(TAU_F90_OPT) #ENDIF# #BGQ#TAU_F90 = /bgsys/drivers/ppcfloor/comm/xl/bin/mpixlf90$(TAU_R) $(F90_ABI) $(TAU_F90_OPT) #ENDIF# @@ -771,6 +772,7 @@ TAU_GCCLIB = -lgcc_s #GNU#TAU_FORTRANLIBS = -L$(TAUGCCLIBDIR) $(TAUGCCLIBOPTS) -lstdc++ $(TAU_GCCLIB) #ENDIF# #OPEN64ORC_FORTRAN#TAU_FORTRANLIBS = -lfortran -lffio #ENDIF# #PATHSCALE_FORTRAN#TAU_FORTRANLIBS = -lpathfstart -lpathfortran #ENDIF# +#ARMFLANG#TAU_FORTRANLIBS = -lflangmain -lflang -lflangrti -lompstub -lm -lrt #ENDIF# #SC_PATHSCALE#TAU_FORTRANLIBS = -lpathfstart -lpathfortran #ENDIF# #NAGWARE_FORTRAN#TAU_FORTRANLIBS = $(EXTRADIR)/lib/quickfit.o $(EXTRADIR)/lib/f90_init.o $(EXTRADIR)/lib/libf??.so $(EXTRADIR)/lib/libf??.a -lm -Wl,-rpath,$(EXTRADIR)/lib #ENDIF# #G95_FORTRAN#TAU_FORTRANLIBS = -L$(EXTRADIR) -lf95 #ENDIF# diff --git a/utils/FixMakefile b/utils/FixMakefile index 98a327100..256266dd3 100755 --- a/utils/FixMakefile +++ b/utils/FixMakefile @@ -2157,6 +2157,10 @@ case $1 in echo "NOTE: IBM xlflang compiler for Linux options used" echo "s/#$1#\(.*\)/$bs\1#$1#/g" >> $sedout ;; + ARMFLANG) + echo "NOTE: ARM armflang compiler for Linux options used" + echo "s/#$1#\(.*\)/$bs\1#$1#/g" >> $sedout + ;; MPIIFORT) echo "NOTE: Intel mpiifort compiler options used" echo "s/#$1#\(.*\)/$bs\1#$1#/g" >> $sedout From 1d2dadc8deaf87abb4fa7711ca4327107057b160 Mon Sep 17 00:00:00 2001 From: Nicholas Chaimov Date: Fri, 8 Jun 2018 18:19:03 -0700 Subject: [PATCH 23/60] Fix segfault in pprof when header > 64K chars Former-commit-id: 6fedeb478b87b8ba521d5f74c2e2c8820e2ee0d1 --- utils/pprof.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/utils/pprof.cpp b/utils/pprof.cpp index 966b73afa..57436aa21 100644 --- a/utils/pprof.cpp +++ b/utils/pprof.cpp @@ -439,6 +439,13 @@ int FillFunctionDB(int node, int ctx, int thr, char *prefix){ perror("Error: fgets returns NULL in format string "); return 0; }//if + size_t line_len = strlen(line); + if(line[line_len] - 1 != '\n') { + // Header was too long to read + while(getc(fp) != '\n') { + // skip to next line + } + } if (line[0] == '#') { // new data format sprintf(header,"# Name Calls Subrs Excl Incl "); hlen = strlen(header); @@ -756,6 +763,13 @@ int ProcessFileDynamic(int node, int ctx, int thr, int max, char *prefix){ perror("Error: fgets returns NULL in format string "); return 0; }//if + size_t line_len = strlen(line); + if(line[line_len] - 1 != '\n') { + // Header was too long to read + while(getc(fp) != '\n') { + // skip to next line + } + } //check to make sure first character is the #. If not, then we //are using the old data format, so note accordingly. if (line[0] != '#') { // Old data format without '#' From 93f110baec3616dbecab7ca76a5ff1e61f356c13 Mon Sep 17 00:00:00 2001 From: Nicholas Chaimov Date: Tue, 12 Jun 2018 13:07:15 -0700 Subject: [PATCH 24/60] Fix segfault in pprof when header > 64K chars Former-commit-id: 42508e064014f6d8867e60174dd55a1016f031bb --- utils/pprof.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/utils/pprof.cpp b/utils/pprof.cpp index 57436aa21..d8c2a04d5 100644 --- a/utils/pprof.cpp +++ b/utils/pprof.cpp @@ -440,7 +440,7 @@ int FillFunctionDB(int node, int ctx, int thr, char *prefix){ return 0; }//if size_t line_len = strlen(line); - if(line[line_len] - 1 != '\n') { + if(line[line_len-1] != '\n') { // Header was too long to read while(getc(fp) != '\n') { // skip to next line @@ -764,7 +764,7 @@ int ProcessFileDynamic(int node, int ctx, int thr, int max, char *prefix){ return 0; }//if size_t line_len = strlen(line); - if(line[line_len] - 1 != '\n') { + if(line[line_len-1] != '\n') { // Header was too long to read while(getc(fp) != '\n') { // skip to next line From 7eef7674425d9ecf77220eed987c9921e022c152 Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Tue, 12 Jun 2018 13:18:01 -0700 Subject: [PATCH 25/60] Updating filtering support to include wildcards, and also added filtering for SOS trace collection. Former-commit-id: 202d3bad3b2b7fd55732ac588afac209ac6508b9 --- plugins/examples/TauSOS.cpp | 183 +++++++++++++++++++++++++--- plugins/examples/TauSOS.h | 10 +- plugins/examples/Tau_plugin_sos.cpp | 99 ++++++++++----- src/Profile/TauCAPI.cpp | 8 ++ 4 files changed, 252 insertions(+), 48 deletions(-) diff --git a/plugins/examples/TauSOS.cpp b/plugins/examples/TauSOS.cpp index 24d02990d..1766b2037 100644 --- a/plugins/examples/TauSOS.cpp +++ b/plugins/examples/TauSOS.cpp @@ -365,7 +365,7 @@ void Tau_SOS_parse_selection_file(const char * filename) { bool excluding_timers = false; bool including_counters = false; bool excluding_counters = false; - thePluginOptions().env_sos_use_selection = 1; + thePluginOptions().env_sos_use_selection = true; while (std::getline(file, str)) { // trim right whitespace str.erase(str.find_last_not_of(" \n\r\t")+1); @@ -397,13 +397,29 @@ void Tau_SOS_parse_selection_file(const char * filename) { excluding_counters = false; } else { if (including_timers) { - thePluginOptions().included_timers.insert(str); + if (str.find("#") == string::npos && str.find("?") == string::npos) { + thePluginOptions().included_timers.insert(str); + } else { + thePluginOptions().included_timers_with_wildcards.insert(str); + } } else if (excluding_timers) { - thePluginOptions().excluded_timers.insert(str); + if (str.find("#") == string::npos && str.find("?") == string::npos) { + thePluginOptions().excluded_timers.insert(str); + } else { + thePluginOptions().excluded_timers_with_wildcards.insert(str); + } } else if (including_counters) { - thePluginOptions().included_counters.insert(str); + if (str.find("#") == string::npos && str.find("?") == string::npos) { + thePluginOptions().included_counters.insert(str); + } else { + thePluginOptions().included_counters_with_wildcards.insert(str); + } } else if (excluding_counters) { - thePluginOptions().excluded_counters.insert(str); + if (str.find("#") == string::npos && str.find("?") == string::npos) { + thePluginOptions().excluded_counters.insert(str); + } else { + thePluginOptions().excluded_counters_with_wildcards.insert(str); + } } else { std::cerr << "Warning, selection outside of include/exclude section: " << str << std::endl; @@ -648,11 +664,8 @@ void TAU_SOS_pack_profile() { for (it = TheFunctionDB().begin(); it != TheFunctionDB().end(); it++) { FunctionInfo *fi = *it; /* First, check to see if we are including/excluding this timer */ - if (thePluginOptions().env_sos_use_selection == 1) { - if (Tau_SOS_contains(thePluginOptions().excluded_timers, fi->GetName(), false) || - !Tau_SOS_contains(thePluginOptions().included_timers, fi->GetName(), true)) { - continue; - } + if (skip_timer(fi->GetName())) { + continue; } // get the number of calls int tid = 0; // todo: get ALL thread data. @@ -703,11 +716,8 @@ void TAU_SOS_pack_profile() { for (it2 = tau::TheEventDB().begin(); it2 != tau::TheEventDB().end(); it2++) { tau::TauUserEvent *ue = (*it2); /* First, check to see if we are including/excluding this counter */ - if (thePluginOptions().env_sos_use_selection == 1) { - if (Tau_SOS_contains(thePluginOptions().excluded_counters, ue->GetName().c_str(), false) || - !Tau_SOS_contains(thePluginOptions().included_counters, ue->GetName().c_str(), true)) { - continue; - } + if (skip_counter(ue->GetName().c_str())) { + continue; } double tmp_accum = 0.0; std::string counter_name; @@ -779,4 +789,147 @@ void TAU_SOS_send_data(void) { Tau_global_decr_insideTAU(); } +// C++ program to implement wildcard +// pattern matching algorithm +// from: https://www.geeksforgeeks.org/wildcard-pattern-matching/ +#include +using namespace std; + +// Function that matches input str with +// given wildcard pattern +bool strmatch(const char str[], const char pattern[], + int n, int m) +{ + // empty pattern can only match with + // empty string + if (m == 0) + return (n == 0); + + // lookup table for storing results of + // subproblems + bool lookup[n + 1][m + 1] = {false}; + + // initailze lookup table to false + //memset(lookup, false, sizeof(lookup)); + + // empty pattern can match with empty string + lookup[0][0] = true; + + // Only '#' can match with empty string + for (int j = 1; j <= m; j++) + if (pattern[j - 1] == '#') + lookup[0][j] = lookup[0][j - 1]; + + // fill the table in bottom-up fashion + for (int i = 1; i <= n; i++) + { + for (int j = 1; j <= m; j++) + { + // Two cases if we see a '#' + // a) We ignore ‘#’ character and move + // to next character in the pattern, + // i.e., ‘#’ indicates an empty sequence. + // b) '#' character matches with ith + // character in input + if (pattern[j - 1] == '#') + lookup[i][j] = lookup[i][j - 1] || + lookup[i - 1][j]; + + // Current characters are considered as + // matching in two cases + // (a) current character of pattern is '?' + // (b) characters actually match + else if (pattern[j - 1] == '?' || + str[i - 1] == pattern[j - 1]) + lookup[i][j] = lookup[i - 1][j - 1]; + + // If characters don't match + else lookup[i][j] = false; + } + } + + return lookup[n][m]; +} + +bool skip_timer(const char * key) { + // are we filtering at all? + if (!thePluginOptions().env_sos_use_selection) { + return false; + } + // check to see if this label is excluded + if (Tau_SOS_contains(thePluginOptions().excluded_timers, key, false)) { + return true; + // check to see if this label is included + } else if (Tau_SOS_contains(thePluginOptions().included_timers, key, false)) { + return false; + } else { + // check to see if it's in the excluded wildcards + for (auto it=thePluginOptions().excluded_timers_with_wildcards.begin(); + it!=thePluginOptions().excluded_timers_with_wildcards.end(); ++it) { + if (strmatch(key, it->c_str(), strlen(key), it->length())) { + // make the lookup faster next time + thePluginOptions().excluded_timers.insert(key); + return true; + } + } + // check to see if it's in the included wildcards + for (auto it=thePluginOptions().included_timers_with_wildcards.begin(); + it!=thePluginOptions().included_timers_with_wildcards.end(); ++it) { + if (strmatch(key, it->c_str(), strlen(key), it->length())) { + // make the lookup faster next time + thePluginOptions().included_timers.insert(key); + return false; + } + } + } + // neither included nor excluded? + // do we have an inclusion list? If so, then skip (because we didn't match it). + if (!thePluginOptions().included_timers.empty() || + !thePluginOptions().included_timers_with_wildcards.empty()) { + return true; + } + // by default, don't skip it. + return false; +} + +bool skip_counter(const char * key) { + // are we filtering at all? + if (!thePluginOptions().env_sos_use_selection) { + return false; + } + // check to see if this label is excluded + if (Tau_SOS_contains(thePluginOptions().excluded_counters, key, false)) { + return true; + // check to see if this label is included + } else if (Tau_SOS_contains(thePluginOptions().included_counters, key, false)) { + return false; + } else { + // check to see if it's in the excluded wildcards + for (auto it=thePluginOptions().excluded_counters_with_wildcards.begin(); + it!=thePluginOptions().excluded_counters_with_wildcards.end(); ++it) { + if (strmatch(key, it->c_str(), strlen(key), it->length())) { + // make the lookup faster next time + thePluginOptions().excluded_counters.insert(key); + return true; + } + } + // check to see if it's in the included wildcards + for (auto it=thePluginOptions().included_counters_with_wildcards.begin(); + it!=thePluginOptions().included_counters_with_wildcards.end(); ++it) { + if (strmatch(key, it->c_str(), strlen(key), it->length())) { + // make the lookup faster next time + thePluginOptions().included_counters.insert(key); + return false; + } + } + } + // neither included nor excluded? + // do we have an inclusion list? If so, then skip (because we didn't match it). + if (!thePluginOptions().included_counters.empty() || + !thePluginOptions().included_counters_with_wildcards.empty()) { + return true; + } + return false; +} + #endif // TAU_SOS diff --git a/plugins/examples/TauSOS.h b/plugins/examples/TauSOS.h index ce497e5f7..94088a162 100644 --- a/plugins/examples/TauSOS.h +++ b/plugins/examples/TauSOS.h @@ -12,7 +12,7 @@ #define TAU_SOS_PERIODIC_DEFAULT 0 #define TAU_SOS_PERIOD_DEFAULT 2000000 // microseconds #define TAU_SOS_SHUTDOWN_DELAY_DEFAULT 10 // seconds -#define TAU_SOS_USE_SELECTION_DEFAULT 0 // microseconds +#define TAU_SOS_USE_SELECTION_DEFAULT false // microseconds #define TAU_SOS_CACHE_DEPTH_DEFAULT 10 // SOS frames class SOS_plugin_options { @@ -33,12 +33,16 @@ class SOS_plugin_options { int env_sos_periodic; int env_sos_period; int env_sos_shutdown_delay; - int env_sos_use_selection; + bool env_sos_use_selection; int env_sos_cache_depth; std::set included_timers; std::set excluded_timers; + std::set included_timers_with_wildcards; + std::set excluded_timers_with_wildcards; std::set included_counters; std::set excluded_counters; + std::set included_counters_with_wildcards; + std::set excluded_counters_with_wildcards; static SOS_plugin_options& thePluginOptions() { static SOS_plugin_options tpo; return tpo; @@ -65,5 +69,7 @@ void Tau_SOS_pack_double(const char * name, double value); void Tau_SOS_pack_integer(const char * name, int value); void Tau_SOS_pack_long(const char * name, long int value); void * Tau_sos_thread_function(void* data); +bool skip_timer(const char * key); +bool skip_counter(const char * key); #endif // TAU_SOS_H diff --git a/plugins/examples/Tau_plugin_sos.cpp b/plugins/examples/Tau_plugin_sos.cpp index 8e00a8058..cc5a51543 100644 --- a/plugins/examples/Tau_plugin_sos.cpp +++ b/plugins/examples/Tau_plugin_sos.cpp @@ -18,9 +18,15 @@ #include #include #include +#include + +extern tau::Profiler* Tau_get_timer_at_stack_depth(int pos); + +static std::atomic enabled(false); /* Only dump data to SOS if we aren't doing periodic dumps */ int Tau_plugin_sos_dump(Tau_plugin_event_dump_data data) { + if (!enabled) return 0; //printf("TAU PLUGIN SOS: dump\n"); if (thePluginOptions().env_sos_periodic != 1) { TAU_SOS_send_data(); @@ -35,6 +41,7 @@ int Tau_plugin_finalize(Tau_plugin_event_function_finalize_data data) { /* This happens from MPI_Finalize, before MPI is torn down. */ int Tau_plugin_sos_pre_end_of_execution(Tau_plugin_event_pre_end_of_execution_data data) { + if (!enabled) return 0; //fprintf(stdout, "TAU PLUGIN SOS Pre-Finalize\n"); fflush(stdout); // OK to do it from any thread, because it came from MPI_Finalize TAU_SOS_send_data(); @@ -48,18 +55,10 @@ int Tau_plugin_sos_pre_end_of_execution(Tau_plugin_event_pre_end_of_execution_da return 0; } -/* This happens from Profiler.cpp, when data is written out. */ -int Tau_plugin_sos_end_of_execution(Tau_plugin_event_end_of_execution_data data) { - //fprintf(stdout, "TAU PLUGIN SOS Finalize\n"); fflush(stdout); - if (data.tid == 0) { - TAU_SOS_finalize(); - } - return 0; -} - /* This happens after MPI_Init, and after all TAU metadata variables have been * read */ int Tau_plugin_sos_post_init(Tau_plugin_event_post_init_data data) { + if (!enabled) return 0; //fprintf(stdout, "TAU PLUGIN SOS Post Init\n"); fflush(stdout); TAU_SOS_send_data(); return 0; @@ -67,15 +66,11 @@ int Tau_plugin_sos_post_init(Tau_plugin_event_post_init_data data) { /* This happens on Tau_start() */ int Tau_plugin_sos_function_entry(Tau_plugin_event_function_entry_data data) { + if (!enabled) return 0; /* First, check to see if we are including/excluding this timer */ - /* - if (thePluginOptions().env_sos_use_selection == 1) { - if (Tau_SOS_contains(thePluginOptions().excluded_timers, data.timer_name, false) || - !Tau_SOS_contains(thePluginOptions().included_timers, data.timer_name, true)) { - return 0; - } + if (skip_timer(data.timer_name)) { + return 0; } - */ /* todo: filter on group, timer name */ std::stringstream ss; ss << "TAU_EVENT_ENTRY:" << data.tid << ":" << data.timer_name; @@ -86,15 +81,11 @@ int Tau_plugin_sos_function_entry(Tau_plugin_event_function_entry_data data) { /* This happens on Tau_stop() */ int Tau_plugin_sos_function_exit(Tau_plugin_event_function_exit_data data) { + if (!enabled) return 0; /* First, check to see if we are including/excluding this timer */ - /* - if (thePluginOptions().env_sos_use_selection == 1) { - if (Tau_SOS_contains(thePluginOptions().excluded_timers, data.timer_name, false) || - !Tau_SOS_contains(thePluginOptions().included_timers, data.timer_name, true)) { - return 0; - } + if (skip_timer(data.timer_name)) { + return 0; } - */ /* todo: filter on group, timer name */ std::stringstream ss; ss << "TAU_EVENT_EXIT:" << data.tid << ":" << data.timer_name; @@ -105,15 +96,11 @@ int Tau_plugin_sos_function_exit(Tau_plugin_event_function_exit_data data) { /* This happens on Tau_userevent() */ int Tau_plugin_sos_atomic_trigger(Tau_plugin_event_atomic_event_trigger_data data) { + if (!enabled) return 0; /* First, check to see if we are including/excluding this counter */ - /* - if (thePluginOptions().env_sos_use_selection == 1) { - if (Tau_SOS_contains(thePluginOptions().excluded_counters, data.counter_name, false) || - !Tau_SOS_contains(thePluginOptions().included_counters, data.counter_name, true)) { - return 0; - } + if (skip_counter(data.counter_name)) { + return 0; } - */ std::stringstream ss; ss << "TAU_EVENT_COUNTER:" << data.tid << ":" << data.counter_name; //std::cout << ss.str() << " = " << data.value << std::endl; @@ -123,12 +110,14 @@ int Tau_plugin_sos_atomic_trigger(Tau_plugin_event_atomic_event_trigger_data dat /* This happens for special events from ADIOS, MPI */ int Tau_plugin_sos_current_timer_exit(Tau_plugin_event_current_timer_exit_data data) { + if (!enabled) return 0; Tau_SOS_pack_current_timer(data.name_prefix); return 0; } /* This happens on MPI_Send events (and similar) */ int Tau_plugin_sos_send(Tau_plugin_event_send_data data) { + if (!enabled) return 0; /* todo: filter on group, timer name */ std::stringstream ss; ss << "TAU_EVENT_SEND:" << data.tid @@ -142,6 +131,7 @@ int Tau_plugin_sos_send(Tau_plugin_event_send_data data) { /* This happens on MPI_Recv events (and similar) */ int Tau_plugin_sos_recv(Tau_plugin_event_recv_data data) { + if (!enabled) return 0; /* todo: filter on group, timer name */ std::stringstream ss; ss << "TAU_EVENT_RECV:" << data.tid @@ -155,6 +145,7 @@ int Tau_plugin_sos_recv(Tau_plugin_event_recv_data data) { /* This happens when a Metadata field is saved. */ int Tau_plugin_metadata_registration_complete_func(Tau_plugin_event_metadata_registration_data data) { + if (!enabled) return 0; //fprintf(stdout, "TAU Metadata registration\n"); fflush(stdout); std::stringstream ss; ss << "TAU_Metadata:" << 0 << ":" << data.name; @@ -183,6 +174,39 @@ int Tau_plugin_metadata_registration_complete_func(Tau_plugin_event_metadata_reg return 0; } +/* This happens from Profiler.cpp, when data is written out. */ +int Tau_plugin_sos_end_of_execution(Tau_plugin_event_end_of_execution_data data) { + if (!enabled) return 0; + /* If we are tracing, we need to "stop" all of the remaining timers on the stack */ + if (thePluginOptions().env_sos_tracing) { + Tau_plugin_event_function_exit_data data; + // safe to assume 0? + // for (int t = 0 ; t < TAU_MAX_THREADS ; t++) { + int t = RtsLayer::myThread(); + int depth = Tau_get_current_stack_depth(t); + for (int i = depth ; i > -1 ; i--) { + tau::Profiler *profiler = Tau_get_timer_at_stack_depth(i); + if (profiler->ThisFunction->GetName() == NULL) { + // small memory leak, but at shutdown. + data.timer_name = strdup(".TAU application"); + } else { + data.timer_name = profiler->ThisFunction->GetName(); + } + data.tid = t; + //printf("Stopping %s\n", data.timer_name); + Tau_plugin_sos_function_exit(data); + } + // } + } + enabled = false; + //fprintf(stdout, "TAU PLUGIN SOS Finalize\n"); fflush(stdout); + if (data.tid == 0) { + TAU_SOS_finalize(); + } + return 0; +} + + /*This is the init function that gets invoked by the plugin mechanism inside TAU. * Every plugin MUST implement this function to register callbacks for various events * that the plugin is interested in listening to*/ @@ -223,9 +247,22 @@ extern "C" int Tau_plugin_init_func(int argc, char **argv) { /* Register the callback object */ TAU_UTIL_PLUGIN_REGISTER_CALLBACKS(cb); + enabled = true; + + /* If we are tracing, we need to "start" all of the timers on the stack */ + if (thePluginOptions().env_sos_tracing) { + Tau_plugin_event_function_entry_data data; + // safe to assume 0? + int depth = Tau_get_current_stack_depth(RtsLayer::myThread()); + for (int i = 0 ; i <= depth ; i++) { + tau::Profiler *profiler = Tau_get_timer_at_stack_depth(i); + data.timer_name = profiler->ThisFunction->GetName(); + data.tid = RtsLayer::myThread(); + Tau_plugin_sos_function_entry(data); + } + } return 0; } - #endif // TAU_SOS diff --git a/src/Profile/TauCAPI.cpp b/src/Profile/TauCAPI.cpp index a25b15ae1..e6d5efb78 100644 --- a/src/Profile/TauCAPI.cpp +++ b/src/Profile/TauCAPI.cpp @@ -857,6 +857,14 @@ extern "C" int Tau_show_profiles() return 0; } +/* Used by SOS plugin to start all currently running timers + * because "tracing" is not enabled until after some timers + * are started. */ +extern Profiler * Tau_get_timer_at_stack_depth(int pos) +{ + return &(Tau_thread_flags[RtsLayer::myThread()].Tau_global_stack[pos]); +} + extern "C" void Tau_stop_all_timers(int tid) { TauInternalFunctionGuard protects_this_function; From b4c507ec5386191ed8d9ff8d92c6eefd496e9639 Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Tue, 12 Jun 2018 14:57:02 -0700 Subject: [PATCH 26/60] Removing atomic so that TAU comiles with 4.9 Former-commit-id: daa6900c4fd29ed361152eebfc120d308db2ff1b --- plugins/examples/Tau_plugin_sos.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/examples/Tau_plugin_sos.cpp b/plugins/examples/Tau_plugin_sos.cpp index cc5a51543..aa2dd0d8e 100644 --- a/plugins/examples/Tau_plugin_sos.cpp +++ b/plugins/examples/Tau_plugin_sos.cpp @@ -18,11 +18,10 @@ #include #include #include -#include extern tau::Profiler* Tau_get_timer_at_stack_depth(int pos); -static std::atomic enabled(false); +static bool enabled(false); /* Only dump data to SOS if we aren't doing periodic dumps */ int Tau_plugin_sos_dump(Tau_plugin_event_dump_data data) { From ce5e5793ffa26f1b80f4af2573e97fbf3711ce37 Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Wed, 13 Jun 2018 09:26:15 -0700 Subject: [PATCH 27/60] regressing to gcc 4.9 level C++ Former-commit-id: 8ff0bacb1c9c9f4b21cd5a6edf12d5fe849b08b9 --- plugins/examples/TauSOS.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/plugins/examples/TauSOS.cpp b/plugins/examples/TauSOS.cpp index 1766b2037..183efaeb8 100644 --- a/plugins/examples/TauSOS.cpp +++ b/plugins/examples/TauSOS.cpp @@ -864,7 +864,8 @@ bool skip_timer(const char * key) { return false; } else { // check to see if it's in the excluded wildcards - for (auto it=thePluginOptions().excluded_timers_with_wildcards.begin(); + for (std::set::iterator + it=thePluginOptions().excluded_timers_with_wildcards.begin(); it!=thePluginOptions().excluded_timers_with_wildcards.end(); ++it) { if (strmatch(key, it->c_str(), strlen(key), it->length())) { // make the lookup faster next time @@ -873,7 +874,8 @@ bool skip_timer(const char * key) { } } // check to see if it's in the included wildcards - for (auto it=thePluginOptions().included_timers_with_wildcards.begin(); + for (std::set::iterator + it=thePluginOptions().included_timers_with_wildcards.begin(); it!=thePluginOptions().included_timers_with_wildcards.end(); ++it) { if (strmatch(key, it->c_str(), strlen(key), it->length())) { // make the lookup faster next time @@ -905,7 +907,8 @@ bool skip_counter(const char * key) { return false; } else { // check to see if it's in the excluded wildcards - for (auto it=thePluginOptions().excluded_counters_with_wildcards.begin(); + for (std::set::iterator + it=thePluginOptions().excluded_counters_with_wildcards.begin(); it!=thePluginOptions().excluded_counters_with_wildcards.end(); ++it) { if (strmatch(key, it->c_str(), strlen(key), it->length())) { // make the lookup faster next time @@ -914,7 +917,8 @@ bool skip_counter(const char * key) { } } // check to see if it's in the included wildcards - for (auto it=thePluginOptions().included_counters_with_wildcards.begin(); + for (std::set::iterator + it=thePluginOptions().included_counters_with_wildcards.begin(); it!=thePluginOptions().included_counters_with_wildcards.end(); ++it) { if (strmatch(key, it->c_str(), strlen(key), it->length())) { // make the lookup faster next time From 34945b1c2119e829881bf5dfe07a17718b6629a7 Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Wed, 13 Jun 2018 21:31:11 +0000 Subject: [PATCH 28/60] Minor flag-checking fixes. Former-commit-id: 1fec44931be27bada8162934c4cd557115bbb055 --- plugins/examples/TauSOS.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/examples/TauSOS.cpp b/plugins/examples/TauSOS.cpp index 1766b2037..20bc40a92 100644 --- a/plugins/examples/TauSOS.cpp +++ b/plugins/examples/TauSOS.cpp @@ -467,8 +467,8 @@ void TAU_SOS_init() { } } - if (_threaded && thePluginOptions().env_sos_periodic) { - period_microseconds = thePluginOptions().env_sos_period; + if (thePluginOptions().env_sos_periodic) { + period_microseconds = thePluginOptions().env_sos_period; TAU_VERBOSE("Spawning thread for SOS.\n"); int ret = pthread_create(&worker_thread, NULL, &Tau_sos_thread_function, NULL); if (ret != 0) { @@ -488,7 +488,7 @@ void TAU_SOS_stop_worker(void) { pthread_mutex_lock(&_my_mutex); done = true; pthread_mutex_unlock(&_my_mutex); - if (_threaded && thePluginOptions().env_sos_periodic) { + if (thePluginOptions().env_sos_periodic) { TAU_VERBOSE("TAU SOS thread joining...\n"); fflush(stderr); pthread_cond_signal(&_my_cond); int ret = pthread_join(worker_thread, NULL); @@ -535,7 +535,7 @@ void TAU_SOS_finalize(void) { if (shutdown_daemon) { if (my_rank == daemon_rank) { TAU_VERBOSE("Waiting for SOS to flush...\n"); - sleep(thePluginOptions().env_sos_shutdown_delay); + sleep(thePluginOptions().env_sos_shutdown_delay); TAU_SOS_send_shutdown_message(); } // shouldn't be necessary, but sometimes the shutdown message is ignored? From 086c551af49eeb95b82b872d5b0a7314a8320c0d Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Wed, 13 Jun 2018 21:43:11 +0000 Subject: [PATCH 29/60] Making some TAU/SOS defaults more reasonable. Former-commit-id: 4766f7308c48805dddd62ff5be3ebbc10ef263c3 --- plugins/examples/TauSOS.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/examples/TauSOS.h b/plugins/examples/TauSOS.h index 94088a162..162585d50 100644 --- a/plugins/examples/TauSOS.h +++ b/plugins/examples/TauSOS.h @@ -11,9 +11,9 @@ #define TAU_SOS_TRACE_ADIOS_DEFAULT 0 #define TAU_SOS_PERIODIC_DEFAULT 0 #define TAU_SOS_PERIOD_DEFAULT 2000000 // microseconds -#define TAU_SOS_SHUTDOWN_DELAY_DEFAULT 10 // seconds +#define TAU_SOS_SHUTDOWN_DELAY_DEFAULT 1 // seconds #define TAU_SOS_USE_SELECTION_DEFAULT false // microseconds -#define TAU_SOS_CACHE_DEPTH_DEFAULT 10 // SOS frames +#define TAU_SOS_CACHE_DEPTH_DEFAULT 1 // SOS frames class SOS_plugin_options { private: From fe4404e78bb0261d4e4542a802be0dc40f8934d6 Mon Sep 17 00:00:00 2001 From: Wyatt Spear Date: Fri, 15 Jun 2018 14:12:42 -0700 Subject: [PATCH 30/60] Updated CubeReader.jar to version 4.4 Former-commit-id: fc45988a93545165a04932f12c7f2c1e5fdd8454 --- tools/src/contrib/CubeReader.jar | Bin 133236 -> 134424 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/src/contrib/CubeReader.jar b/tools/src/contrib/CubeReader.jar index 19785ac92f5eeb2243bc36a313615b2dc7762b84..40ee29214d3de8d281b1c01465b1abf589a11c6d 100644 GIT binary patch delta 111389 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 delta 110098 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

6h@i@Yzm02cNe6BqKV}=Y?2H6% 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 Date: Wed, 20 Jun 2018 10:00:42 -0400 Subject: [PATCH 31/60] Making PGI happy Former-commit-id: b338ac04005b52a435f3cff9756ec3e282b92dcf --- plugins/examples/TauSOS.cpp | 16 +++++++++------- plugins/examples/TauSOS.h | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/plugins/examples/TauSOS.cpp b/plugins/examples/TauSOS.cpp index 04a1179dc..303006c01 100644 --- a/plugins/examples/TauSOS.cpp +++ b/plugins/examples/TauSOS.cpp @@ -103,6 +103,7 @@ void * Tau_sos_thread_function(void* data) { // unlock after being signalled. pthread_mutex_unlock(&_my_mutex); pthread_exit((void*)0L); + return(NULL); } void TAU_SOS_make_pub() { @@ -165,7 +166,6 @@ void TAU_SOS_do_fork(std::string forkCommand) { void TAU_SOS_fork_exec_sosd_shutdown(void) { #ifdef TAU_MPI // first, figure out who should fork a daemon on this node - int i; if (my_rank == daemon_rank) { int pid = vfork(); if (pid == 0) { @@ -189,7 +189,6 @@ void TAU_SOS_fork_exec_sosd_shutdown(void) { void TAU_SOS_send_shutdown_message(void) { #ifdef TAU_MPI - int i; SOS_buffer *buffer; SOS_msg_header header; int offset; @@ -631,7 +630,7 @@ void Tau_SOS_pack_long(const char * name, long int value) { /* Necessary to use const char * because UserEvents use TauSafeString objects, * not std::string. We use the "if_empty" parameter to tell us how to treat * an empty set. For exclude lists, it's false, for include lists, it's true */ -const bool Tau_SOS_contains(std::set& myset, +bool Tau_SOS_contains(std::set& myset, const char * key, bool if_empty) { // if the set has contents, and we are in the set, then return true. std::string _key(key); @@ -678,8 +677,6 @@ void TAU_SOS_pack_profile() { //foreach: THREAD for (tid = 0; tid < RtsLayer::getTotalThreads(); tid++) { calls = fi->GetCalls(tid); - int vec_index = 0; - std::stringstream calls_str; calls_str << "TAU_TIMER:" << tid << ":calls:" << fi->GetAllGroups() << ":" << fi->GetName(); const std::string& tmpcalls = calls_str.str(); @@ -719,7 +716,6 @@ void TAU_SOS_pack_profile() { if (skip_counter(ue->GetName().c_str())) { continue; } - double tmp_accum = 0.0; std::string counter_name; int tid = 0; @@ -807,7 +803,13 @@ bool strmatch(const char str[], const char pattern[], // lookup table for storing results of // subproblems - bool lookup[n + 1][m + 1] = {false}; + bool lookup[n + 1][m + 1]; // = {false}; + // PGI compiler doesn't like initialization during declaration... + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= m; j++) { + lookup[i][j] = false; + } + } // initailze lookup table to false //memset(lookup, false, sizeof(lookup)); diff --git a/plugins/examples/TauSOS.h b/plugins/examples/TauSOS.h index 162585d50..7b0cb147a 100644 --- a/plugins/examples/TauSOS.h +++ b/plugins/examples/TauSOS.h @@ -55,7 +55,7 @@ inline SOS_plugin_options& thePluginOptions() { void TAU_SOS_parse_environment_variables(void); void Tau_SOS_parse_selection_file(const char * filename); -const bool Tau_SOS_contains(std::set& myset, +bool Tau_SOS_contains(std::set& myset, const char * key, bool if_empty); void TAU_SOS_send_data(void); From 1482aa970940431c748cb96b9148a2db43c3624b Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Wed, 20 Jun 2018 10:02:49 -0400 Subject: [PATCH 32/60] PGI compiler doesn't like the usage of TAU_LIB_DIR. Former-commit-id: e62750540592d74b1e804e3aa0a891bcedca7e94 --- src/Profile/TauEnv.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Profile/TauEnv.cpp b/src/Profile/TauEnv.cpp index 3234cb134..40959fc15 100644 --- a/src/Profile/TauEnv.cpp +++ b/src/Profile/TauEnv.cpp @@ -1901,7 +1901,8 @@ void TauEnv_initialize() } else { if ((env_plugins == NULL) && (env_plugins_path == NULL)) { TAU_VERBOSE("TAU: TAU_SELECT_FILE is set to %s when TAU plugins are not initialized\n", env_select_file); - env_plugins_path=strdup(TAU_LIB_DIR); + //env_plugins_path=strdup(TAU_LIB_DIR); + env_plugins_path=strdup("."); TAU_VERBOSE("TAU: TAU_PLUGINS_PATH is now %s\n", env_plugins_path); //sprintf(env_plugins,"libTAU-filter-plugin.so(%s)", env_select_file); char *plugins = (char *) malloc(1024); @@ -1911,7 +1912,10 @@ void TauEnv_initialize() TAU_VERBOSE("TAU: TAU plugin is now %s\n", env_plugins); TAU_METADATA("TAU_SELECT_FILE", filename); } else { - TAU_VERBOSE("TAU: Ignoring TAU_SELECT_FILE because TAU_PLUGINS and/or TAU_PLUGINS_PATH is set.\nPlease use export TAU_PLUGINS_PATH=%s and export TAU_PLUGINS=\"libTAU-filter-plugin.so(%s)\"\n", strdup(TAU_LIB_DIR), strdup(env_select_file)); + TAU_VERBOSE("TAU: Ignoring TAU_SELECT_FILE because TAU_PLUGINS and/or TAU_PLUGINS_PATH is set.\nPlease use export TAU_PLUGINS_PATH=%s and export TAU_PLUGINS=\"libTAU-filter-plugin.so(%s)\"\n", + //strdup(TAU_LIB_DIR), + strdup("."), + strdup(env_select_file)); } } From e0a21b22c83d8322c6a3855b969def5d87a6885f Mon Sep 17 00:00:00 2001 From: Nicholas Chaimov Date: Thu, 5 Jul 2018 12:22:06 -0400 Subject: [PATCH 33/60] Fix broken -ompt= build in taucmdr For some reason setting -ompt=, as TAU commander does, also forced download_ompt_tr6 on, which caused the built to subsequently fail. Former-commit-id: 143c6bb34bb2ff59f21e076ad3984337475e84e9 --- configure | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure b/configure index 6019982f1..e55d690e7 100755 --- a/configure +++ b/configure @@ -6765,9 +6765,9 @@ if [ "x$ompt_dir" != "x" -a -d "$ompt_dir" ] ; then if [ -r $ompt_dir/$libomp_osstgz ]; then echo "NOTE: Copying $ompt_dir/$libomp_osstgz" cp $ompt_dir/$libomp_osstgz . - if [ "x$download_ompt" != "xyes" ] ; then - download_ompt_tr6=yes - fi + #if [ "x$download_ompt" != "xyes" ] ; then + # download_ompt_tr6=yes + #fi fi fi @@ -6788,7 +6788,7 @@ fi if [ "x$download_ompt" = "xyes" -o "x$download_ompt_tr6" = "xyes" ] ; then install_ompt=yes - if [ ! -f ${libomp_ossdir_shared}/lib${libomp_oss_name}.so -o ${libomp_ossdir_shared}/lib${libomp_oss_name}.so -ot ${libomp_oss} ]; then + if [ ! -f "${libomp_ossdir_shared}/lib${libomp_oss_name}.so" -o "${libomp_ossdir_shared}/lib${libomp_oss_name}.so" -ot "${libomp_oss}" ]; then preomptdir=`pwd` #check Cmake exists From 68098818f0ec9bd466ff1177c2a101d4dc623dbd Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Tue, 10 Jul 2018 13:11:16 -0700 Subject: [PATCH 34/60] Minor changes for SOS cache trace management Former-commit-id: 60e6ca377ec3f7638f2007d1dbba86f0e896a075 --- plugins/examples/TauSOS.cpp | 13 ++++++++ plugins/examples/Tau_plugin_sos.cpp | 48 ++++++++++++++++++----------- 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/plugins/examples/TauSOS.cpp b/plugins/examples/TauSOS.cpp index 303006c01..4d51e264c 100644 --- a/plugins/examples/TauSOS.cpp +++ b/plugins/examples/TauSOS.cpp @@ -564,6 +564,7 @@ void Tau_SOS_pack_current_timer(const char * event_name) { // assume time is the first counter! // also convert it to microseconds double value = (current[0] - p->StartTime[0]) * CONVERT_TO_USEC; + if (strlen(event_name) > 256) { printf("long string, %d: '%s'\n", strlen(event_name), event_name); } SOS_pack(tau_sos_pub, event_name, SOS_VAL_TYPE_DOUBLE, &value); } @@ -579,6 +580,7 @@ void Tau_SOS_pack_string(const char * name, char * value) { } RtsLayer::UnLockDB(); } + if (strlen(name) > 256) { printf("long string, %d: '%s'\n", strlen(name), name); } SOS_pack(tau_sos_pub, name, SOS_VAL_TYPE_STRING, value); } @@ -594,6 +596,7 @@ void Tau_SOS_pack_double(const char * name, double value) { } RtsLayer::UnLockDB(); } + if (strlen(name) > 256) { printf("long string, %d: '%s'\n", strlen(name), name); } SOS_pack(tau_sos_pub, name, SOS_VAL_TYPE_DOUBLE, &value); } @@ -609,6 +612,7 @@ void Tau_SOS_pack_integer(const char * name, int value) { } RtsLayer::UnLockDB(); } + if (strlen(name) > 256) { printf("long string, %d: '%s'\n", strlen(name), name); } SOS_pack(tau_sos_pub, name, SOS_VAL_TYPE_INT, &value); } @@ -624,6 +628,7 @@ void Tau_SOS_pack_long(const char * name, long int value) { } RtsLayer::UnLockDB(); } + if (strlen(name) > 256) { printf("long string, %d: '%s'\n", strlen(name), name); } SOS_pack(tau_sos_pub, name, SOS_VAL_TYPE_LONG, &value); } @@ -680,6 +685,7 @@ void TAU_SOS_pack_profile() { std::stringstream calls_str; calls_str << "TAU_TIMER:" << tid << ":calls:" << fi->GetAllGroups() << ":" << fi->GetName(); const std::string& tmpcalls = calls_str.str(); + if (strlen(tmpcalls.c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmpcalls.c_str()), tmpcalls.c_str()); } SOS_pack(tau_sos_pub, tmpcalls.c_str(), SOS_VAL_TYPE_INT, &calls); // todo - subroutines @@ -695,6 +701,8 @@ void TAU_SOS_pack_profile() { excl_str.str(std::string()); excl_str << "TAU_TIMER:" << tid << ":exclusive_" << counterNames[m] << ":" << fi->GetAllGroups() << ":" << fi->GetName(); const std::string& tmpexcl = excl_str.str(); + if (strlen(tmpexcl.c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmpexcl.c_str()), tmpexcl.c_str()); } + if (strlen(tmpincl.c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmpincl.c_str()), tmpincl.c_str()); } SOS_pack(tau_sos_pub, tmpincl.c_str(), SOS_VAL_TYPE_DOUBLE, &inclusive); SOS_pack(tau_sos_pub, tmpexcl.c_str(), SOS_VAL_TYPE_DOUBLE, &exclusive); } @@ -728,18 +736,23 @@ void TAU_SOS_pack_profile() { min = ue->GetMin(tid); sumsqr = ue->GetSumSqr(tid); tmp_str << "TAU_COUNTER:" << tid << ":NumEvents:" << ue->GetName(); + if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } SOS_pack(tau_sos_pub, tmp_str.str().c_str(), SOS_VAL_TYPE_INT, &numEvents); tmp_str.str(std::string()); tmp_str << "TAU_COUNTER:" << tid << ":Max:" << ue->GetName(); + if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } SOS_pack(tau_sos_pub, tmp_str.str().c_str(), SOS_VAL_TYPE_DOUBLE, &max); tmp_str.str(std::string()); tmp_str << "TAU_COUNTER:" << tid << ":Min:" << ue->GetName(); + if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } SOS_pack(tau_sos_pub, tmp_str.str().c_str(), SOS_VAL_TYPE_DOUBLE, &min); tmp_str.str(std::string()); tmp_str << "TAU_COUNTER:" << tid << ":Mean:" << ue->GetName(); + if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } SOS_pack(tau_sos_pub, tmp_str.str().c_str(), SOS_VAL_TYPE_DOUBLE, &mean); tmp_str.str(std::string()); tmp_str << "TAU_COUNTER:" << tid << ":SumSqr:" << ue->GetName(); + if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } SOS_pack(tau_sos_pub, tmp_str.str().c_str(), SOS_VAL_TYPE_DOUBLE, &sumsqr); tmp_str.str(std::string()); } diff --git a/plugins/examples/Tau_plugin_sos.cpp b/plugins/examples/Tau_plugin_sos.cpp index aa2dd0d8e..83165412d 100644 --- a/plugins/examples/Tau_plugin_sos.cpp +++ b/plugins/examples/Tau_plugin_sos.cpp @@ -175,14 +175,15 @@ int Tau_plugin_metadata_registration_complete_func(Tau_plugin_event_metadata_reg /* This happens from Profiler.cpp, when data is written out. */ int Tau_plugin_sos_end_of_execution(Tau_plugin_event_end_of_execution_data data) { - if (!enabled) return 0; + if (!enabled || data.tid != 0) return 0; /* If we are tracing, we need to "stop" all of the remaining timers on the stack */ if (thePluginOptions().env_sos_tracing) { Tau_plugin_event_function_exit_data data; // safe to assume 0? - // for (int t = 0 ; t < TAU_MAX_THREADS ; t++) { - int t = RtsLayer::myThread(); - int depth = Tau_get_current_stack_depth(t); + //int tid = data.tid; + RtsLayer::UnLockDB(); + for (int tid = TAU_MAX_THREADS-1 ; tid >= 0 ; tid--) { + int depth = Tau_get_current_stack_depth(tid); for (int i = depth ; i > -1 ; i--) { tau::Profiler *profiler = Tau_get_timer_at_stack_depth(i); if (profiler->ThisFunction->GetName() == NULL) { @@ -190,18 +191,21 @@ int Tau_plugin_sos_end_of_execution(Tau_plugin_event_end_of_execution_data data) data.timer_name = strdup(".TAU application"); } else { data.timer_name = profiler->ThisFunction->GetName(); + data.timer_group = profiler->ThisFunction->GetAllGroups(); } - data.tid = t; - //printf("Stopping %s\n", data.timer_name); + data.tid = tid; + double CurrentTime[TAU_MAX_COUNTERS] = { 0 }; + RtsLayer::getUSecD(tid, CurrentTime); + data.timestamp = (x_uint64)CurrentTime[0]; // USE COUNTER1 for tracing + //printf("%d,%d Stopping %s\n", getpid(), tid, data.timer_name); Tau_plugin_sos_function_exit(data); } - // } + } + RtsLayer::UnLockDB(); } enabled = false; //fprintf(stdout, "TAU PLUGIN SOS Finalize\n"); fflush(stdout); - if (data.tid == 0) { - TAU_SOS_finalize(); - } + TAU_SOS_finalize(); return 0; } @@ -250,15 +254,23 @@ extern "C" int Tau_plugin_init_func(int argc, char **argv) { /* If we are tracing, we need to "start" all of the timers on the stack */ if (thePluginOptions().env_sos_tracing) { - Tau_plugin_event_function_entry_data data; - // safe to assume 0? - int depth = Tau_get_current_stack_depth(RtsLayer::myThread()); - for (int i = 0 ; i <= depth ; i++) { - tau::Profiler *profiler = Tau_get_timer_at_stack_depth(i); - data.timer_name = profiler->ThisFunction->GetName(); - data.tid = RtsLayer::myThread(); - Tau_plugin_sos_function_entry(data); + RtsLayer::LockDB(); + //int tid = RtsLayer::myThread(); + for (int tid = TAU_MAX_THREADS-1 ; tid >= 0 ; tid--) { + Tau_plugin_event_function_entry_data data; + // safe to assume 0? + int depth = Tau_get_current_stack_depth(tid); + for (int i = 0 ; i <= depth ; i++) { + tau::Profiler *profiler = Tau_get_timer_at_stack_depth(i); + data.timer_name = profiler->ThisFunction->GetName(); + data.timer_group = profiler->ThisFunction->GetAllGroups(); + data.tid = tid; + data.timestamp = (x_uint64)profiler->StartTime[0]; + //printf("%d,%d Starting %s\n", getpid(), tid, data.timer_name); + Tau_plugin_sos_function_entry(data); + } } + RtsLayer::UnLockDB(); } return 0; } From fa95c7e0ee93d6173c2cf27da9a808fbfc137d9e Mon Sep 17 00:00:00 2001 From: Nicholas Chaimov Date: Wed, 18 Jul 2018 19:07:25 -0700 Subject: [PATCH 35/60] Don't start sampling until MPI_Init in MPI config Former-commit-id: d38a81b51391e7d375b64e5171157464b2ceea02 --- src/Profile/TauSampling.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Profile/TauSampling.cpp b/src/Profile/TauSampling.cpp index 1ab811078..ec839c48e 100644 --- a/src/Profile/TauSampling.cpp +++ b/src/Profile/TauSampling.cpp @@ -121,6 +121,7 @@ using namespace tau; extern FunctionInfo * Tau_create_thread_state_if_necessary(const char* thread_state); extern FunctionInfo * Tau_create_thread_state_if_necessary_string(const string & thread_state); extern "C" void Tau_ompt_resolve_callsite(FunctionInfo &fi, char * resolved_address); +extern "C" int Tau_get_usesMPI(); #if defined(TAU_OPENMP) && !defined (TAU_USE_OMPT_TR6) && (defined(TAU_USE_OMPT) || defined (TAU_IBM_OMPT)) extern "C" int Tau_get_thread_omp_state(int tid); @@ -1869,6 +1870,13 @@ extern "C" void Tau_sampling_init_if_necessary(void) // sanity check - does the user want sampling at all? if (!TauEnv_get_ebs_enabled()) return; + // If this is an MPI configuration of TAU, don't initialize sampling + // if MPI_Init hasn't been called yet. This is necessary to prevent + // problems where the sampling signal interferes with MPI startup. +#ifdef TAU_MPI + if(Tau_get_usesMPI() == 0) return; +#endif + int tid = RtsLayer::localThreadId(); // have we initialized already? if (samplingThrInitialized[tid]) return; From 64d0cab1a88bd64c04808d7da0b076f7f4661942 Mon Sep 17 00:00:00 2001 From: Nicholas Chaimov Date: Thu, 19 Jul 2018 15:19:45 -0700 Subject: [PATCH 36/60] First attempt at MPI_Comm_spawn support. Works ONLY for a single level of processes and does NOT work with tau_exec. Former-commit-id: e9fd5a70322e464804fe14e89a678dc7a7f5b547 --- include/Profile/TauEnv.h | 2 ++ src/Profile/TauEnv.cpp | 8 +++++ src/Profile/TauMpi.c | 78 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/include/Profile/TauEnv.h b/include/Profile/TauEnv.h index aa5d5a584..19fee0f30 100644 --- a/include/Profile/TauEnv.h +++ b/include/Profile/TauEnv.h @@ -111,6 +111,8 @@ extern "C" { double TAUDECL TauEnv_get_throttle_percall(); const char* TAUDECL TauEnv_get_profiledir(); const char* TAUDECL TauEnv_get_tracedir(); + void TAUDECL TauEnv_set_profiledir(const char * new_profiledir); + void TAUDECL TauEnv_set_tracedir(const char * new_tracedir); const char* TAUDECL TauEnv_get_metrics(); const char* TAUDECL TauEnv_get_cvar_metrics(); const char* TAUDECL TauEnv_get_cvar_values(); diff --git a/src/Profile/TauEnv.cpp b/src/Profile/TauEnv.cpp index 257690556..e428ea108 100644 --- a/src/Profile/TauEnv.cpp +++ b/src/Profile/TauEnv.cpp @@ -760,6 +760,14 @@ extern "C" const char *TauEnv_get_tracedir() { return env_tracedir; } +extern "C" void TauEnv_set_profiledir(const char * new_profiledir) { + env_profiledir = strdup(new_profiledir); +} + +extern "C" void TauEnv_set_tracedir(const char * new_tracedir) { + env_tracedir = strdup(new_tracedir); +} + int TauEnv_get_synchronize_clocks() { return env_synchronize_clocks; } diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index 09ab04017..08d46174c 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -1361,6 +1361,54 @@ MPI_Comm * comm_out; return returnVal; } +void Tau_handle_comm_spawn(MPI_Comm comm, MPI_Comm intercomm) { + static int tau_comm_spawn_num = 0; + tau_comm_spawn_num++; + int comm_rank; + MPI_Comm_rank(comm, &comm_rank); + // Send the generation number to the spawned processes, which + // will join the Bcast in MPI_Init + if(comm_rank == 0) { + PMPI_Bcast(&tau_comm_spawn_num, 1, MPI_INT, MPI_ROOT, intercomm); + } else { + PMPI_Bcast(&tau_comm_spawn_num, 1, MPI_INT, MPI_PROC_NULL, intercomm); + } +} + +int MPI_Comm_spawn(const char *command, char *argv[], int maxprocs, + MPI_Info info, int root, MPI_Comm comm, + MPI_Comm *intercomm, int array_of_errcodes[]) { + int returnVal; + + TAU_PROFILE_TIMER(tautimer, "MPI_Comm_spawn()", " ", TAU_MESSAGE); + TAU_PROFILE_START(tautimer); + + returnVal = PMPI_Comm_spawn(command, argv, maxprocs, info, root, comm, intercomm, array_of_errcodes); + Tau_handle_comm_spawn(comm, *intercomm); + + TAU_PROFILE_STOP(tautimer); + + return returnVal; +} + +int MPI_Comm_spawn_multiple(int count, char *array_of_commands[], + char **array_of_argv[], const int array_of_maxprocs[], const MPI_Info + array_of_info[], int root, MPI_Comm comm, MPI_Comm *intercomm, + int array_of_errcodes[]) { + int returnVal; + + TAU_PROFILE_TIMER(tautimer, "MPI_Comm_spawn_multiple()", " ", TAU_MESSAGE); + TAU_PROFILE_START(tautimer); + + returnVal = PMPI_Comm_spawn_multiple(count, array_of_commands, array_of_argv, array_of_maxprocs, array_of_info, root, comm, intercomm, array_of_errcodes); + Tau_handle_comm_spawn(comm, intercomm); + + TAU_PROFILE_STOP(tautimer); + + return returnVal; +} + + int MPI_Comm_test_inter( comm, flag ) MPI_Comm comm; int * flag; @@ -1972,10 +2020,25 @@ int Tau_MPI_T_initialization(void) { #endif /* TAU_MPI_T */ } +void Tau_handle_spawned_init(MPI_Comm intercomm) { + int generation_num; + PMPI_Bcast(&generation_num, 1, MPI_INT, 0, intercomm); + const char * profiledir = TauEnv_get_profiledir(); + const char * tracedir = TauEnv_get_profiledir(); + char new_profiledir[4096]; + char new_tracedir[4096]; + snprintf(new_profiledir, 4096, "%s/%d", profiledir, generation_num); + snprintf(new_tracedir, 4096, "%s/%d", tracedir, generation_num); + TauEnv_set_profiledir(new_profiledir); + TauEnv_set_tracedir(new_tracedir); + TAU_VERBOSE("TAU_INIT: MPI_Comm_spawn generation %d\n", generation_num); +} + int MPI_Init( argc, argv ) int * argc; char *** argv; { + fprintf(stderr, "MPI INIT wrapper\n"); int returnVal; int size; char procname[MPI_MAX_PROCESSOR_NAME]; @@ -2004,6 +2067,13 @@ char *** argv; returnVal = PMPI_Init( argc, argv ); + MPI_Comm parent; + PMPI_Comm_get_parent(&parent); + if(parent != MPI_COMM_NULL) { + // This process was created through MPI_Comm_spawn + Tau_handle_spawned_init(parent); + } + /*Initialize the plugin system only if both plugin path and plugins are specified*/ if(TauEnv_get_plugins_enabled()) { TAU_VERBOSE("TAU INIT: Initializing plugin system...\n"); @@ -2073,6 +2143,7 @@ char *** argv; int required; int *provided; { + fprintf(stderr, "MPI INIT THREAD WRAPPER\n"); int returnVal; int size; char procname[MPI_MAX_PROCESSOR_NAME]; @@ -2091,6 +2162,13 @@ int *provided; returnVal = PMPI_Init_thread( argc, argv, required, provided ); + MPI_Comm parent; + MPI_Comm_get_parent(&parent); + if(parent != MPI_COMM_NULL) { + // This process was created through MPI_Comm_spawn + Tau_handle_spawned_init(parent); + } + /*Initialize the plugin system only if both plugin path and plugins are specified*/ if(TauEnv_get_plugins_enabled()) { TAU_VERBOSE("TAU INIT: Initializing plugin system...\n"); From 3a95bf241cc70a872ff76f619cfa37d66f91154b Mon Sep 17 00:00:00 2001 From: Nicholas Chaimov Date: Thu, 19 Jul 2018 17:23:46 -0700 Subject: [PATCH 37/60] Fix MPI_Comm_spawn_multiple Former-commit-id: 2d159054c8da35c861cfd2ffcfea6ea7d91443b7 --- src/Profile/TauMpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index 08d46174c..185367b3d 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -1401,7 +1401,7 @@ int MPI_Comm_spawn_multiple(int count, char *array_of_commands[], TAU_PROFILE_START(tautimer); returnVal = PMPI_Comm_spawn_multiple(count, array_of_commands, array_of_argv, array_of_maxprocs, array_of_info, root, comm, intercomm, array_of_errcodes); - Tau_handle_comm_spawn(comm, intercomm); + Tau_handle_comm_spawn(comm, *intercomm); TAU_PROFILE_STOP(tautimer); From 813641fc0ca291695ab2d890d896fabe75c45b1c Mon Sep 17 00:00:00 2001 From: Nicholas Chaimov Date: Fri, 20 Jul 2018 14:19:19 -0700 Subject: [PATCH 38/60] Save tau_exec args into env var for later use Former-commit-id: 773825ae9d8868b0669a302f5fac0d7726851292 --- include/Profile/TauEnv.h | 1 + src/Profile/TauEnv.cpp | 19 ++++++++++++++-- tools/src/tau_exec | 49 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/include/Profile/TauEnv.h b/include/Profile/TauEnv.h index 19fee0f30..cf9f717c9 100644 --- a/include/Profile/TauEnv.h +++ b/include/Profile/TauEnv.h @@ -163,6 +163,7 @@ extern "C" { int TAUDECL TauEnv_get_mem_callpath(); const char * TAUDECL TauEnv_get_mem_classes(); int TAUDECL TauEnv_get_mem_class_present(const char * name); + const char * TAUDECL TauEnv_get_tau_exec_args(); #ifdef __cplusplus void Tau_util_replaceStringInPlace(std::string& subject, const std::string& search, const std::string& replace); diff --git a/src/Profile/TauEnv.cpp b/src/Profile/TauEnv.cpp index e428ea108..7b10a35b6 100644 --- a/src/Profile/TauEnv.cpp +++ b/src/Profile/TauEnv.cpp @@ -343,6 +343,8 @@ static const char *env_mem_classes = NULL; static std::set * env_mem_classes_set = NULL; static int env_region_addresses = TAU_REGION_ADDRESSES_DEFAULT; +static const char *env_tau_exec_args = NULL; + } // extern "C" /********************************************************************* @@ -1200,11 +1202,17 @@ int TauEnv_get_mem_class_present(const char * name) { return env_mem_classes_set->count(name); } +const char * TauEnv_get_tau_exec_args() { + return env_tau_exec_args; +} + + /********************************************************************* * Initialize the TauEnv module, get configuration values ********************************************************************/ void TauEnv_initialize() { + fprintf(stderr, "TAUENV INITIALIZE\n"); char tmpstr[512]; /* unset LD_PRELOAD so that vt_unify and elg_unify work */ @@ -2451,9 +2459,9 @@ void TauEnv_initialize() if ((env_mem_classes = getconf("TAU_MEM_CLASSES")) == NULL) { env_mem_classes = ""; - TAU_VERBOSE("TAU: MEM_CLASSES is not set\n", env_metrics); + TAU_VERBOSE("TAU: MEM_CLASSES is not set\n"); } else { - TAU_VERBOSE("TAU: MEM_CLASSES is \"%s\"\n", env_metrics); + TAU_VERBOSE("TAU: MEM_CLASSES is \"%s\"\n", env_mem_classes); if(strcmp(env_mem_classes, "all") == 0) { env_mem_all = 1; TAU_VERBOSE("TAU: Tracking All Class Allocations\n"); @@ -2466,6 +2474,13 @@ void TauEnv_initialize() } } + if ((env_tau_exec_args = getconf("TAU_EXEC_ARGS")) == NULL) { + env_tau_exec_args = ""; + TAU_VERBOSE("TAU: TAU_EXEC_ARGS is not set\n"); + } else { + TAU_VERBOSE("TAU: TAU_EXEC_ARGS is \"%s\"\n", env_tau_exec_args); + } + initialized = 1; TAU_VERBOSE("TAU: Initialized TAU (TAU_VERBOSE=1)\n"); diff --git a/tools/src/tau_exec b/tools/src/tau_exec index 5b432a3a4..173e767e7 100755 --- a/tools/src/tau_exec +++ b/tools/src/tau_exec @@ -305,6 +305,14 @@ py_interp_args="" ptts_sample_flags="${TAU_TS_SAMPLE_FLAGS:-}" # Set these from environment vars if they exist, don't complain even ptts_report_flags="${TAU_TS_REPORT_FLAGS:-}" # if set -o nounset +# This saves the args to tau_exec so they can be reused later. +# This is used for MPI_Comm_spawn support, in which TAU spawns the child +# through tau_exec, since the child doesn't inherit environment variables. +save_arg() +{ + export TAU_EXEC_ARGS="${TAU_EXEC_ARGS} $@" +} + for arg in "$@" ; do # Thanks to Bernd Mohr for the following that handles quotes and spaces (see configure for explanation) modarg=`echo "x$arg" | sed -e 's/^x//' -e 's/"/\\\"/g' -e s,\',%@%\',g -e 's/%@%/\\\/g' -e 's/ /\\\ /g'` @@ -316,167 +324,205 @@ for arg in "$@" ; do if [ "x$test_arg" != "x$arg" ]; then scorep=true fi + save_arg $arg shift else case $arg in -v|-d|-verbose|--verbose) verbose=true + save_arg $arg shift ;; -h|-help|--help) usage + save_arg $arg ;; -io) track_io=true + save_arg $arg shift ;; -numa) track_numa=true + save_arg $arg shift ;; -memory) track_memory=true + save_arg $arg shift ;; -memory_debug) memory_debug=true + save_arg $arg shift ;; -cuda) track_cuda=true + save_arg $arg shift ;; -ompt) track_ompt=true + save_arg $arg shift ;; -power) track_power=true + save_arg $arg shift ;; -cupti) track_cupti=true + save_arg $arg shift ;; -um | -uvm) unified_memory=true + save_arg $arg shift ;; -sass=*) track_sass=true myarg=`echo $arg | sed 's/-sass=//'` sass_type="$myarg" + save_arg $arg shift ;; -csv) csv_output=true + save_arg $arg shift ;; -opencl) track_opencl=true + save_arg $arg shift ;; -openacc) track_openacc=true + save_arg $arg shift ;; -gomp) track_gomp=true + save_arg $arg shift ;; -armci) track_armci=true + save_arg $arg shift ;; -shmem) track_shmem=true + save_arg $arg shift ;; -pin) use_pin=true + save_arg $arg shift ;; -ptts) use_ptts=true + save_arg $arg shift ;; -ptts-post) use_ptts=true ptts_post=true + save_arg $arg shift ;; -ptts-num=*) myarg=`echo $arg | sed 's/-ptts-num=//'` ptts_num="$myarg" + save_arg $arg shift ;; -ptts-sample-flags=*) ptts_sample_flags="${arg/#-ptts-sample-flags=/}" # bash parameter expansion, bash 3 and up + save_arg $arg shift ;; -ptts-report-flags=*) ptts_report_flags="${arg/#-ptts-report-flags=/}" # Also propper quoting must be used when multiple passed + save_arg $arg shift ;; -ebs) tau_use_ebs=true + save_arg $arg shift ;; -ebs_period=*) tau_use_ebs=true myarg=`echo $arg | sed 's/-ebs_period=//'` tau_ebs_period="$myarg" + save_arg $arg shift ;; -ebs_source=*) tau_use_ebs=true myarg=`echo $arg | sed 's/-ebs_source=//'` tau_ebs_source="$myarg" + save_arg $arg shift ;; -qsub) qsub_mode=true + save_arg $arg shift ;; -s) dryrun=echo + save_arg $arg shift ;; -gdb) use_gdb=true + save_arg $arg shift ;; -T) processT=true + save_arg $arg shift ;; -tau:*) binding_options="$binding_options `echo $arg | sed -e 's/-tau://' -e 's/,/ /g'`" + save_arg $arg shift ;; -loadlib=*) myarg=`echo $arg | sed 's/-loadlib=//'` extraloadlibs="$extraloadlibs:$myarg" + save_arg $arg shift ;; -XrunTAU-*) myarg=`echo $arg | sed 's/-XrunTAU-//'` binding_specified="shared-$myarg" + save_arg $arg shift ;; -XrunTAUsh-*) myarg=`echo $arg | sed 's/-XrunTAUsh-//'` binding_specified="shared-$myarg" + save_arg $arg shift ;; -spark-python) spark_wrapper=true + save_arg $arg shift ;; -tau-python-args=*) if [ $python_wrapper = "true" ] ; then myarg=`echo $arg | sed 's/-tau-python-args=//'` py_interp_args="$myarg" + save_arg $arg shift else echo "Unknown option: $arg" >&2 @@ -485,6 +531,7 @@ for arg in "$@" ; do ;; -c) if [ $python_wrapper = "true" ] ; then + save_arg $arg break else echo "Unknown option: $arg" >&2 @@ -493,6 +540,7 @@ for arg in "$@" ; do ;; -m) if [ $python_wrapper = "true" ] ; then + save_arg $arg shift break else @@ -501,6 +549,7 @@ for arg in "$@" ; do fi ;; --) + save_arg $arg shift break ;; From ab6337719059ee9b4db5c211d6c963e7d5851c7f Mon Sep 17 00:00:00 2001 From: Nicholas Chaimov Date: Fri, 20 Jul 2018 14:20:01 -0700 Subject: [PATCH 39/60] Add MPI_Comm_spawn example code Former-commit-id: 090a8ba7ae9992baf3db080cd8591f92a1b9835e --- examples/mpi_comm_spawn/mpi_comm_spawn.c | 114 +++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 examples/mpi_comm_spawn/mpi_comm_spawn.c diff --git a/examples/mpi_comm_spawn/mpi_comm_spawn.c b/examples/mpi_comm_spawn/mpi_comm_spawn.c new file mode 100644 index 000000000..3c30d38e6 --- /dev/null +++ b/examples/mpi_comm_spawn/mpi_comm_spawn.c @@ -0,0 +1,114 @@ +/* +** Program to illustrate the use of MPI_Comm_spawn() to create +** new processes on-the-fly. +*/ + +#include +#include +#include +#include +#include "mpi.h" + +#define MASTER 0 +#define BUFSIZE 1024 +#define NUM2SPAWN 2 + +int main( int argc, char *argv[], char ** envp ) +{ + int rank; + int size; + int np = NUM2SPAWN; + char message[BUFSIZE]; + MPI_Comm parentcomm, spawnedcomm, allcomm; + + pid_t pid = getpid(); + /* the usual start-up for any process */ + //fprintf(stderr, "\n"); + //for (char **env = envp; *env != 0; env++) { + // char *thisEnv = *env; + // fprintf(stderr, "[%ld] %s\n", (long)pid, thisEnv); + //} + fprintf(stderr, "\n"); + fprintf(stderr, "[%ld] Going to call MPI_Init\n", (long)pid); + MPI_Init( &argc, &argv ); + fprintf(stderr, "[%ld] Returning from MPI_Init\n", (long)pid); + + /* This function provides a convenient way to determine whether + ** this process is part of the original communicator (has a null + ** parent), or part of the newly spawned communicator */ + MPI_Comm_get_parent( &parentcomm ); + + /* write output according to which communicator this process is a part of */ + if (parentcomm == MPI_COMM_NULL) { + /* Create 2 more processes. + ** Here we spawn 2 more instances of this program. + ** argv[0] contains the name of the executable for this program. */ + MPI_Comm_spawn( argv[0], MPI_ARGV_NULL, np, MPI_INFO_NULL, 0, + MPI_COMM_WORLD, &spawnedcomm, MPI_ERRCODES_IGNORE ); + /* get the process rank, in this case within the parent communicator */ + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + MPI_Comm_size(MPI_COMM_WORLD,&size); + printf("rank %d (of %d) in the parent intra-communicator.\n",rank,size); + } + else { + /* notice that the spawned processes have an intra-communicator + ** called MPI_COMM_WORLD, too */ + MPI_Comm_rank(MPI_COMM_WORLD,&rank); + MPI_Comm_size(MPI_COMM_WORLD,&size); + printf("rank %d (of %d) in the spawned intra-communicator.\n",rank,size); + } + + /* we can broadcast to all processes associated with an + ** inter-communicator, e.g. the spawned processes */ + if (rank == MASTER) { + message[0] = 'g'; message[1] = 'a'; message[2] = 'l'; message[3] = 'o'; + message[4] = 'r'; message[5] = 'e'; message[6] = '!'; message[7] = '\0'; + } + /* BUT remember that broadcast is a collective operation, so all must call.. + ** but it's a tad fiddly with all the different groups of processors that + ** we have. + ** Note also that the inter-communicator has different names + ** according to the (parent/spawned) perspective. */ + if (parentcomm == MPI_COMM_NULL) { + if (rank == MASTER) { + MPI_Bcast(message,BUFSIZE,MPI_CHAR,MPI_ROOT,spawnedcomm); + } + MPI_Bcast(message,BUFSIZE,MPI_CHAR,MPI_PROC_NULL,spawnedcomm); + } + else { + MPI_Bcast(message,BUFSIZE,MPI_CHAR,MASTER,parentcomm); + printf("spawned rank %d (of %d). Master broadcasts: %s\n",rank,size,message); + } + + /* A simpler manoeuvre is to (collectively) merge + ** the processes associated with an inter-communicator: */ + if (parentcomm == MPI_COMM_NULL) { + MPI_Intercomm_merge(spawnedcomm, 0, &allcomm); + } + else { + MPI_Intercomm_merge(parentcomm, 0, &allcomm); + } + + /* all processes can make calls associated with the + ** merged communicator */ + MPI_Comm_rank(allcomm,&rank); + MPI_Comm_size(allcomm,&size); + printf("rank %d (of %d) in the merged intra-communicator.\n",rank,size); + + /* free communicators when we've finished with them + ** remembering the different names as seen from different + ** perspectives */ + if (parentcomm == MPI_COMM_NULL) { + MPI_Comm_free(&spawnedcomm); + MPI_Comm_free(&allcomm); + } + else { + MPI_Comm_free(&parentcomm); + MPI_Comm_free(&allcomm); + } + + /* and finalise */ + fflush(stdout); + MPI_Finalize(); + return 0; +} From 628fefbbd8e283db83b717c70e31024d9a29bed5 Mon Sep 17 00:00:00 2001 From: Nicholas Chaimov Date: Fri, 20 Jul 2018 16:39:53 -0700 Subject: [PATCH 40/60] Support tau_exec with MPI_Comm_spawn When tau_exec is used, rewrite the MPI_Comm_spawn call, changing 'command' to tau_exec and argv to the args to tau_exec, the orignal command, and the original argv Former-commit-id: 3643ba40987d98303503232274cbb7031c11e9b3 --- examples/mpi_comm_spawn/mpi_comm_spawn.c | 23 ++----- include/Profile/TauEnv.h | 1 + src/Profile/TauEnv.cpp | 13 +++- src/Profile/TauMpi.c | 83 +++++++++++++++++++++++- tools/src/tau_exec | 1 + 5 files changed, 101 insertions(+), 20 deletions(-) diff --git a/examples/mpi_comm_spawn/mpi_comm_spawn.c b/examples/mpi_comm_spawn/mpi_comm_spawn.c index 3c30d38e6..032a15ad4 100644 --- a/examples/mpi_comm_spawn/mpi_comm_spawn.c +++ b/examples/mpi_comm_spawn/mpi_comm_spawn.c @@ -21,18 +21,8 @@ int main( int argc, char *argv[], char ** envp ) char message[BUFSIZE]; MPI_Comm parentcomm, spawnedcomm, allcomm; + MPI_Init(&argc, &argv); pid_t pid = getpid(); - /* the usual start-up for any process */ - //fprintf(stderr, "\n"); - //for (char **env = envp; *env != 0; env++) { - // char *thisEnv = *env; - // fprintf(stderr, "[%ld] %s\n", (long)pid, thisEnv); - //} - fprintf(stderr, "\n"); - fprintf(stderr, "[%ld] Going to call MPI_Init\n", (long)pid); - MPI_Init( &argc, &argv ); - fprintf(stderr, "[%ld] Returning from MPI_Init\n", (long)pid); - /* This function provides a convenient way to determine whether ** this process is part of the original communicator (has a null ** parent), or part of the newly spawned communicator */ @@ -43,19 +33,20 @@ int main( int argc, char *argv[], char ** envp ) /* Create 2 more processes. ** Here we spawn 2 more instances of this program. ** argv[0] contains the name of the executable for this program. */ - MPI_Comm_spawn( argv[0], MPI_ARGV_NULL, np, MPI_INFO_NULL, 0, + char * spawn_args[] = {"-n", "1", NULL}; + MPI_Comm_spawn( argv[0], spawn_args, np, MPI_INFO_NULL, 0, MPI_COMM_WORLD, &spawnedcomm, MPI_ERRCODES_IGNORE ); /* get the process rank, in this case within the parent communicator */ MPI_Comm_rank(MPI_COMM_WORLD,&rank); MPI_Comm_size(MPI_COMM_WORLD,&size); - printf("rank %d (of %d) in the parent intra-communicator.\n",rank,size); + printf("[%ld] rank %d (of %d) in the parent intra-communicator.\n", (long)pid, rank, size); } else { /* notice that the spawned processes have an intra-communicator ** called MPI_COMM_WORLD, too */ MPI_Comm_rank(MPI_COMM_WORLD,&rank); MPI_Comm_size(MPI_COMM_WORLD,&size); - printf("rank %d (of %d) in the spawned intra-communicator.\n",rank,size); + printf("[%ld] rank %d (of %d) in the spawned intra-communicator.\n", (long)pid, rank, size); } /* we can broadcast to all processes associated with an @@ -77,7 +68,7 @@ int main( int argc, char *argv[], char ** envp ) } else { MPI_Bcast(message,BUFSIZE,MPI_CHAR,MASTER,parentcomm); - printf("spawned rank %d (of %d). Master broadcasts: %s\n",rank,size,message); + printf("[%ld] spawned rank %d (of %d). Master broadcasts: %s\n", (long)pid, rank, size, message); } /* A simpler manoeuvre is to (collectively) merge @@ -93,7 +84,7 @@ int main( int argc, char *argv[], char ** envp ) ** merged communicator */ MPI_Comm_rank(allcomm,&rank); MPI_Comm_size(allcomm,&size); - printf("rank %d (of %d) in the merged intra-communicator.\n",rank,size); + printf("[%ld] rank %d (of %d) in the merged intra-communicator.\n", (long)pid, rank, size); /* free communicators when we've finished with them ** remembering the different names as seen from different diff --git a/include/Profile/TauEnv.h b/include/Profile/TauEnv.h index cf9f717c9..9f177dd85 100644 --- a/include/Profile/TauEnv.h +++ b/include/Profile/TauEnv.h @@ -164,6 +164,7 @@ extern "C" { const char * TAUDECL TauEnv_get_mem_classes(); int TAUDECL TauEnv_get_mem_class_present(const char * name); const char * TAUDECL TauEnv_get_tau_exec_args(); + const char * TAUDECL TauEnv_get_tau_exec_path(); #ifdef __cplusplus void Tau_util_replaceStringInPlace(std::string& subject, const std::string& search, const std::string& replace); diff --git a/src/Profile/TauEnv.cpp b/src/Profile/TauEnv.cpp index 7b10a35b6..c038d69a1 100644 --- a/src/Profile/TauEnv.cpp +++ b/src/Profile/TauEnv.cpp @@ -344,6 +344,7 @@ static std::set * env_mem_classes_set = NULL; static int env_region_addresses = TAU_REGION_ADDRESSES_DEFAULT; static const char *env_tau_exec_args = NULL; +static const char *env_tau_exec_path = NULL; } // extern "C" @@ -1206,13 +1207,16 @@ const char * TauEnv_get_tau_exec_args() { return env_tau_exec_args; } +const char * TauEnv_get_tau_exec_path() { + return env_tau_exec_path; +} + /********************************************************************* * Initialize the TauEnv module, get configuration values ********************************************************************/ void TauEnv_initialize() { - fprintf(stderr, "TAUENV INITIALIZE\n"); char tmpstr[512]; /* unset LD_PRELOAD so that vt_unify and elg_unify work */ @@ -2481,6 +2485,13 @@ void TauEnv_initialize() TAU_VERBOSE("TAU: TAU_EXEC_ARGS is \"%s\"\n", env_tau_exec_args); } + if ((env_tau_exec_path = getconf("TAU_EXEC_PATH")) == NULL) { + env_tau_exec_path = ""; + TAU_VERBOSE("TAU: TAU_EXEC_PATH is not set\n"); + } else { + TAU_VERBOSE("TAU: TAU_EXEC_PATH is \"%s\"\n", env_tau_exec_path); + } + initialized = 1; TAU_VERBOSE("TAU: Initialized TAU (TAU_VERBOSE=1)\n"); diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index 185367b3d..2b64b11c9 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -35,6 +35,9 @@ #include #include #include +#include +#include +#include #include #ifdef TAU_BEACON @@ -1382,10 +1385,46 @@ int MPI_Comm_spawn(const char *command, char *argv[], int maxprocs, TAU_PROFILE_TIMER(tautimer, "MPI_Comm_spawn()", " ", TAU_MESSAGE); TAU_PROFILE_START(tautimer); + + const char * tau_exec_args = TauEnv_get_tau_exec_args(); + const char * tau_exec_path = TauEnv_get_tau_exec_path(); + int allocated_argv = 0; + wordexp_t p; + if(tau_exec_args != NULL && tau_exec_args[0] != '\0') { + // This program was launched through tau_exec + const char * old_command = command; + char ** old_argv = argv; + size_t old_argc = 0; + if(old_argv != NULL) { + char * arg; + for(arg = old_argv[old_argc]; arg != NULL; arg = old_argv[++old_argc]); + } + wordexp(tau_exec_args, &p, WRDE_NOCMD); + argv = malloc((p.we_wordc + old_argc + 2) * sizeof(char*)); + int offset; + for(offset = 0; offset < p.we_wordc; ++offset) { + argv[offset] = p.we_wordv[offset]; + } + argv[offset++] = old_command; + int i; + for(i = 0; i < old_argc; ++i) { + argv[offset++] = old_argv[i]; + } + argv[offset] = NULL; + + command = tau_exec_path; + allocated_argv = 1; + + } returnVal = PMPI_Comm_spawn(command, argv, maxprocs, info, root, comm, intercomm, array_of_errcodes); Tau_handle_comm_spawn(comm, *intercomm); + if(allocated_argv == 1) { + free(argv); + wordfree(&p); + } + TAU_PROFILE_STOP(tautimer); return returnVal; @@ -2020,6 +2059,43 @@ int Tau_MPI_T_initialization(void) { #endif /* TAU_MPI_T */ } +int mkdirp(const char *path) { + const size_t len = strlen(path); + char _path[4096]; + char *p; + + errno = 0; + + /* Copy string so its mutable */ + if (len > sizeof(_path)-1) { + errno = ENAMETOOLONG; + return -1; + } + strcpy(_path, path); + + /* Iterate the string */ + for (p = _path + 1; *p; p++) { + if (*p == '/') { + /* Temporarily truncate */ + *p = '\0'; + + if (mkdir(_path, S_IRWXU) != 0) { + if (errno != EEXIST) + return -1; + } + + *p = '/'; + } + } + + if (mkdir(_path, S_IRWXU) != 0) { + if (errno != EEXIST) + return -1; + } + + return 0; +} + void Tau_handle_spawned_init(MPI_Comm intercomm) { int generation_num; PMPI_Bcast(&generation_num, 1, MPI_INT, 0, intercomm); @@ -2027,8 +2103,10 @@ void Tau_handle_spawned_init(MPI_Comm intercomm) { const char * tracedir = TauEnv_get_profiledir(); char new_profiledir[4096]; char new_tracedir[4096]; - snprintf(new_profiledir, 4096, "%s/%d", profiledir, generation_num); - snprintf(new_tracedir, 4096, "%s/%d", tracedir, generation_num); + snprintf(new_profiledir, 4096, "%s/spawn-%d", profiledir, generation_num); + snprintf(new_tracedir, 4096, "%s/spawn-%d", tracedir, generation_num); + mkdirp(new_profiledir); + mkdirp(new_tracedir); TauEnv_set_profiledir(new_profiledir); TauEnv_set_tracedir(new_tracedir); TAU_VERBOSE("TAU_INIT: MPI_Comm_spawn generation %d\n", generation_num); @@ -2038,7 +2116,6 @@ int MPI_Init( argc, argv ) int * argc; char *** argv; { - fprintf(stderr, "MPI INIT wrapper\n"); int returnVal; int size; char procname[MPI_MAX_PROCESSOR_NAME]; diff --git a/tools/src/tau_exec b/tools/src/tau_exec index 173e767e7..5d99d7b4a 100755 --- a/tools/src/tau_exec +++ b/tools/src/tau_exec @@ -564,6 +564,7 @@ for arg in "$@" ; do esac fi done +export TAU_EXEC_PATH=${BASH_SOURCE[0]} # choose TAU library From dd002b93fc8d7499f1a2863ab028b6e11af8f81e Mon Sep 17 00:00:00 2001 From: Nicholas Chaimov Date: Wed, 25 Jul 2018 10:39:37 -0700 Subject: [PATCH 41/60] Workaround for MPC's MPI_Comm_spawn declaration Former-commit-id: e8c05554070a309e68e7bc0bb5e9c2b911be512e --- src/Profile/TauMpi.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index 2b64b11c9..62dd699df 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -1378,7 +1378,12 @@ void Tau_handle_comm_spawn(MPI_Comm comm, MPI_Comm intercomm) { } } -int MPI_Comm_spawn(const char *command, char *argv[], int maxprocs, +#if defined(TAU_MPC) +#define MPI_COMM_SPAWN_QUALIFIER +#else +#define MPI_COMM_SPAWN_QUALIFIER const +#endif +int MPI_Comm_spawn(MPI_COMM_SPAWN_QUALIFIER char *command, char *argv[], int maxprocs, MPI_Info info, int root, MPI_Comm comm, MPI_Comm *intercomm, int array_of_errcodes[]) { int returnVal; @@ -1431,7 +1436,7 @@ int MPI_Comm_spawn(const char *command, char *argv[], int maxprocs, } int MPI_Comm_spawn_multiple(int count, char *array_of_commands[], - char **array_of_argv[], const int array_of_maxprocs[], const MPI_Info + char **array_of_argv[], MPI_COMM_SPAWN_QUALIFIER int array_of_maxprocs[], MPI_COMM_SPAWN_QUALIFIER MPI_Info array_of_info[], int root, MPI_Comm comm, MPI_Comm *intercomm, int array_of_errcodes[]) { int returnVal; From 42589b4e13912e2a953945350dd640b1f7401d51 Mon Sep 17 00:00:00 2001 From: Nicholas Chaimov Date: Wed, 25 Jul 2018 14:24:05 -0700 Subject: [PATCH 42/60] Move MPC const check with other const checks Former-commit-id: d6d09bc8ca4011fdaa7f4937e2a30c6de1ec9f5a --- src/Profile/TauMpi.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index 62dd699df..9718c096e 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -70,6 +70,12 @@ #define TAU_OPENMPI3_CONST #endif +#if defined(TAU_MPC) +#define TAU_NONMPC_CONST +#else +#define TAU_NONMPC_CONST const +#endif + /* These functions and macros are for creating MPI "events" in the SOS stream. */ #ifdef TAU_SOS @@ -1378,12 +1384,7 @@ void Tau_handle_comm_spawn(MPI_Comm comm, MPI_Comm intercomm) { } } -#if defined(TAU_MPC) -#define MPI_COMM_SPAWN_QUALIFIER -#else -#define MPI_COMM_SPAWN_QUALIFIER const -#endif -int MPI_Comm_spawn(MPI_COMM_SPAWN_QUALIFIER char *command, char *argv[], int maxprocs, +int MPI_Comm_spawn(TAU_NONMPC_CONST char *command, char *argv[], int maxprocs, MPI_Info info, int root, MPI_Comm comm, MPI_Comm *intercomm, int array_of_errcodes[]) { int returnVal; @@ -1436,7 +1437,7 @@ int MPI_Comm_spawn(MPI_COMM_SPAWN_QUALIFIER char *command, char *argv[], int max } int MPI_Comm_spawn_multiple(int count, char *array_of_commands[], - char **array_of_argv[], MPI_COMM_SPAWN_QUALIFIER int array_of_maxprocs[], MPI_COMM_SPAWN_QUALIFIER MPI_Info + char **array_of_argv[], TAU_NONMPC_CONST int array_of_maxprocs[], TAU_NONMPC_CONST MPI_Info array_of_info[], int root, MPI_Comm comm, MPI_Comm *intercomm, int array_of_errcodes[]) { int returnVal; From a031f7f12818c28a840afd86aff6e6f3f33c195a Mon Sep 17 00:00:00 2001 From: Nicholas Chaimov Date: Wed, 25 Jul 2018 14:31:17 -0700 Subject: [PATCH 43/60] Fix runtime overlap in OMPT TR6 Don't try to stop a timer at the exit of a work region if a timer wasn't started at the entry Former-commit-id: c5a1d6a33b18eaf96f7f0f42315ee755564c0abd --- src/Profile/TauOMPT.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Profile/TauOMPT.cpp b/src/Profile/TauOMPT.cpp index 9bcf02318..13e89af7a 100644 --- a/src/Profile/TauOMPT.cpp +++ b/src/Profile/TauOMPT.cpp @@ -275,6 +275,7 @@ on_ompt_callback_work( switch(endpoint) { case ompt_scope_begin: + task_data->ptr = NULL; if(TauEnv_get_ompt_resolve_address_eagerly()) { Tau_ompt_resolve_callsite_eagerly(addr, resolved_address); switch(wstype) @@ -342,8 +343,10 @@ on_ompt_callback_work( task_data->ptr = (void*)handle; break; case ompt_scope_end: - TAU_PROFILER_STOP(task_data->ptr); - break; + if(task_data->ptr != NULL) { + TAU_PROFILER_STOP(task_data->ptr); + } + break; } } } From b77048d4d9b303a14594e118ed993f14f635df3e Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Mon, 30 Jul 2018 11:39:15 -0700 Subject: [PATCH 44/60] Major refactor to clean up plugin code. Properly declare structs and typedefs, and pass pointers rather than copies of structs for efficiency. Former-commit-id: 1d3d116606389aa29f2e327c1bb475ed5d82a9dd --- include/Profile/TauPlugin.h | 4 +- include/Profile/TauPluginInternals.h | 10 +- include/Profile/TauPluginTypes.h | 248 ++++++++---------- include/Profile/TauUtil.h | 4 +- plugins/examples/TauSOS.cpp | 41 ++- ...xample_disable_instrumentation_runtime.cpp | 8 +- ...n_example_mpit_mvapich_free_unused_vbufs.c | 4 +- ...gin_example_mpit_recommend_sharp_usage.cpp | 4 +- plugins/examples/Tau_plugin_sos.cpp | 119 +++++---- ...gin_atomic_event_registration_complete.cpp | 4 +- .../Tau_plugin_atomic_event_trigger.cpp | 4 +- .../Tau_plugin_end_of_execution.cpp | 4 +- ..._plugin_function_registration_complete.cpp | 4 +- .../Tau_plugin_interrupt_trigger.cpp | 4 +- src/Profile/FunctionInfo.cpp | 4 +- src/Profile/PapiLayer.cpp | 16 +- src/Profile/Profiler.cpp | 22 +- src/Profile/TauADIOS.cpp | 21 +- src/Profile/TauCAPI.cpp | 16 +- src/Profile/TauHandler.cpp | 4 +- src/Profile/TauMetaData.cpp | 11 +- src/Profile/TauMpi.c | 85 +++++- src/Profile/TauUtil.cpp | 111 ++++---- src/Profile/UserEvent.cpp | 13 +- 24 files changed, 436 insertions(+), 329 deletions(-) diff --git a/include/Profile/TauPlugin.h b/include/Profile/TauPlugin.h index 0279fb60f..0adeac9c2 100644 --- a/include/Profile/TauPlugin.h +++ b/include/Profile/TauPlugin.h @@ -21,8 +21,8 @@ extern "C" { #endif /* __cplusplus */ -void Tau_util_init_tau_plugin_callbacks(Tau_plugin_callbacks * cb); -void Tau_util_plugin_register_callbacks(Tau_plugin_callbacks * cb); +void Tau_util_init_tau_plugin_callbacks(Tau_plugin_callbacks_t * cb); +void Tau_util_plugin_register_callbacks(Tau_plugin_callbacks_t * cb); #ifdef __cplusplus } diff --git a/include/Profile/TauPluginInternals.h b/include/Profile/TauPluginInternals.h index 47a2e592c..563425b9e 100644 --- a/include/Profile/TauPluginInternals.h +++ b/include/Profile/TauPluginInternals.h @@ -25,15 +25,17 @@ extern "C" { #define TAU_PLUGIN_INIT_FUNC "Tau_plugin_init_func" int Tau_initialize_plugin_system(); -int Tau_util_load_and_register_plugins(PluginManager* plugin_manager); -void* Tau_util_load_plugin(const char *name, const char *path, PluginManager* plugin_manager); -void* Tau_util_register_plugin(const char *name, char **args, int num_args, void* handle, PluginManager* plugin_manager); +int Tau_util_load_and_register_plugins(PluginManager_t* plugin_manager); +void* Tau_util_load_plugin(const char *name, const char *path, PluginManager_t* plugin_manager); +void* Tau_util_register_plugin(const char *name, char **args, int num_args, void* handle, PluginManager_t* plugin_manager); int Tau_util_cleanup_all_plugins(); -PluginManager* Tau_util_get_plugin_manager(); +PluginManager_t* Tau_util_get_plugin_manager(); void Tau_util_invoke_callbacks(Tau_plugin_event_t event, const void * data); +extern Tau_plugin_callbacks_active_t Tau_plugins_enabled; + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/include/Profile/TauPluginTypes.h b/include/Profile/TauPluginTypes.h index c993818eb..fd151aa69 100644 --- a/include/Profile/TauPluginTypes.h +++ b/include/Profile/TauPluginTypes.h @@ -22,175 +22,159 @@ extern "C" { #endif /* __cplusplus */ -//Forward declarations -struct Tau_plugin_event_function_registration_data; -struct Tau_plugin_event_metadata_registration_data; -struct Tau_plugin_event_post_init_data; -struct Tau_plugin_event_dump; -struct Tau_plugin_event_function_entry; -struct Tau_plugin_event_function_exit; -struct Tau_plugin_event_current_timer_exit; -struct Tau_plugin_event_send; -struct Tau_plugin_event_recv; -struct Tau_plugin_event_atomic_event_trigger_data; -struct Tau_plugin_event_atomic_event_registration_data; -struct Tau_plugin_event_pre_end_of_execution_data; -struct Tau_plugin_event_end_of_execution_data; -struct Tau_plugin_event_function_finalize_data; -struct Tau_plugin_event_interrupt_trigger_data; - -/*Define callbacks for specific events*/ -typedef int (*Tau_plugin_function_registration_complete)(struct Tau_plugin_event_function_registration_data); -typedef int (*Tau_plugin_metadata_registration_complete)(struct Tau_plugin_event_metadata_registration_data); -typedef int (*Tau_plugin_post_init)(struct Tau_plugin_event_post_init_data); -typedef int (*Tau_plugin_dump)(struct Tau_plugin_event_dump_data); -typedef int (*Tau_plugin_function_entry)(struct Tau_plugin_event_function_entry_data); -typedef int (*Tau_plugin_function_exit)(struct Tau_plugin_event_function_exit_data); -typedef int (*Tau_plugin_current_timer_exit)(struct Tau_plugin_event_current_timer_exit_data); -typedef int (*Tau_plugin_send)(struct Tau_plugin_event_send_data); -typedef int (*Tau_plugin_recv)(struct Tau_plugin_event_recv_data); -typedef int (*Tau_plugin_atomic_event_registration_complete)(struct Tau_plugin_event_atomic_event_registration_data); -typedef int (*Tau_plugin_atomic_event_trigger)(struct Tau_plugin_event_atomic_event_trigger_data); -typedef int (*Tau_plugin_pre_end_of_execution)(struct Tau_plugin_event_pre_end_of_execution_data); -typedef int (*Tau_plugin_end_of_execution)(struct Tau_plugin_event_end_of_execution_data); -typedef int (*Tau_plugin_function_finalize)(struct Tau_plugin_event_function_finalize_data); -typedef int (*Tau_plugin_interrupt_trigger)(struct Tau_plugin_event_interrupt_trigger_data); - -/*Define the callback structure*/ -struct Tau_plugin_callbacks { - Tau_plugin_function_registration_complete FunctionRegistrationComplete; - Tau_plugin_metadata_registration_complete MetadataRegistrationComplete; - Tau_plugin_post_init PostInit; - Tau_plugin_dump Dump; - Tau_plugin_function_entry FunctionEntry; - Tau_plugin_function_exit FunctionExit; - Tau_plugin_current_timer_exit CurrentTimerExit; - Tau_plugin_send Send; - Tau_plugin_recv Recv; - Tau_plugin_atomic_event_registration_complete AtomicEventRegistrationComplete; - Tau_plugin_atomic_event_trigger AtomicEventTrigger; - Tau_plugin_pre_end_of_execution PreEndOfExecution; - Tau_plugin_end_of_execution EndOfExecution; - Tau_plugin_function_finalize FunctionFinalize; - Tau_plugin_interrupt_trigger InterruptTrigger; -}; - -/*Define all the events currently supported*/ -typedef enum Tau_plugin_event { - TAU_PLUGIN_EVENT_FUNCTION_REGISTRATION, - TAU_PLUGIN_EVENT_METADATA_REGISTRATION, - TAU_PLUGIN_EVENT_POST_INIT, - TAU_PLUGIN_EVENT_DUMP, - TAU_PLUGIN_EVENT_FUNCTION_ENTRY, - TAU_PLUGIN_EVENT_FUNCTION_EXIT, - TAU_PLUGIN_EVENT_CURRENT_TIMER_EXIT, - TAU_PLUGIN_EVENT_SEND, - TAU_PLUGIN_EVENT_RECV, - TAU_PLUGIN_EVENT_ATOMIC_EVENT_REGISTRATION, - TAU_PLUGIN_EVENT_ATOMIC_EVENT_TRIGGER, - TAU_PLUGIN_EVENT_PRE_END_OF_EXECUTION, - TAU_PLUGIN_EVENT_END_OF_EXECUTION, - TAU_PLUGIN_EVENT_FUNCTION_FINALIZE, - TAU_PLUGIN_EVENT_INTERRUPT_TRIGGER -} Tau_plugin_event_t; - /*Define data structures that define how TAU and the plugin exchange information*/ -struct Tau_plugin_event_function_registration_data { +typedef struct Tau_plugin_event_function_registration_data { void * function_info_ptr; int tid; -}; +} Tau_plugin_event_function_registration_data_t; -struct Tau_plugin_event_metadata_registration_data { +typedef struct Tau_plugin_event_metadata_registration_data { const char * name; Tau_metadata_value_t * value; -}; +} Tau_plugin_event_metadata_registration_data_t; -struct Tau_plugin_event_post_init_data { +typedef struct Tau_plugin_event_post_init_data { int dummy; -}; +} Tau_plugin_event_post_init_data_t; -struct Tau_plugin_event_dump_data { +typedef struct Tau_plugin_event_dump_data { int tid; -}; +} Tau_plugin_event_dump_data_t; -struct Tau_plugin_event_function_entry_data { +typedef struct Tau_plugin_event_function_entry_data { const char * timer_name; const char * timer_group; int tid; long unsigned int timestamp; -}; +} Tau_plugin_event_function_entry_data_t; -struct Tau_plugin_event_function_exit_data { +typedef struct Tau_plugin_event_function_exit_data { const char * timer_name; const char * timer_group; int tid; long unsigned int timestamp; -}; +} Tau_plugin_event_function_exit_data_t; -struct Tau_plugin_event_current_timer_exit_data { +typedef struct Tau_plugin_event_current_timer_exit_data { const char * name_prefix; -}; +} Tau_plugin_event_current_timer_exit_data_t; -struct Tau_plugin_event_send_data { +typedef struct Tau_plugin_event_send_data { long unsigned int message_tag; long unsigned int destination; long unsigned int bytes_sent; long unsigned int tid; long unsigned int timestamp; -}; +} Tau_plugin_event_send_data_t; -struct Tau_plugin_event_recv_data { +typedef struct Tau_plugin_event_recv_data { long unsigned int message_tag; long unsigned int source; long unsigned int bytes_received; long unsigned int tid; long unsigned int timestamp; -}; +} Tau_plugin_event_recv_data_t; -struct Tau_plugin_event_atomic_event_registration_data { +typedef struct Tau_plugin_event_atomic_event_registration_data { void * user_event_ptr; -}; +} Tau_plugin_event_atomic_event_registration_data_t; -struct Tau_plugin_event_atomic_event_trigger_data { +typedef struct Tau_plugin_event_atomic_event_trigger_data { const char * counter_name; int tid; long unsigned int value; long unsigned int timestamp; -}; +} Tau_plugin_event_atomic_event_trigger_data_t; -struct Tau_plugin_event_pre_end_of_execution_data { +typedef struct Tau_plugin_event_pre_end_of_execution_data { int tid; -}; +} Tau_plugin_event_pre_end_of_execution_data_t; -struct Tau_plugin_event_end_of_execution_data { +typedef struct Tau_plugin_event_end_of_execution_data { int tid; -}; +} Tau_plugin_event_end_of_execution_data_t; -struct Tau_plugin_event_function_finalize_data { +typedef struct Tau_plugin_event_function_finalize_data { int junk; -}; +} Tau_plugin_event_function_finalize_data_t; -struct Tau_plugin_event_interrupt_trigger_data { +typedef struct Tau_plugin_event_interrupt_trigger_data { int signum; -}; - -typedef struct Tau_plugin_event_function_registration_data Tau_plugin_event_function_registration_data; -typedef struct Tau_plugin_event_metadata_registration_data Tau_plugin_event_metadata_registration_data; -typedef struct Tau_plugin_event_post_init_data Tau_plugin_event_post_init_data; -typedef struct Tau_plugin_event_dump_data Tau_plugin_event_dump_data; -typedef struct Tau_plugin_event_function_entry_data Tau_plugin_event_function_entry_data; -typedef struct Tau_plugin_event_function_exit_data Tau_plugin_event_function_exit_data; -typedef struct Tau_plugin_event_current_timer_exit_data Tau_plugin_event_current_timer_exit_data; -typedef struct Tau_plugin_event_send_data Tau_plugin_event_send_data; -typedef struct Tau_plugin_event_recv_data Tau_plugin_event_recv_data; -typedef struct Tau_plugin_event_atomic_event_registration_data Tau_plugin_event_atomic_event_registration_data; -typedef struct Tau_plugin_event_atomic_event_trigger_data Tau_plugin_event_atomic_event_trigger_data; -typedef struct Tau_plugin_event_pre_end_of_execution_data Tau_plugin_event_pre_end_of_execution_data; -typedef struct Tau_plugin_event_end_of_execution_data Tau_plugin_event_end_of_execution_data; -typedef struct Tau_plugin_event_function_finalize_data Tau_plugin_event_function_finalize_data; -typedef struct Tau_plugin_event_interrupt_trigger_data Tau_plugin_event_interrupt_trigger_data; - -typedef struct Tau_plugin_callbacks Tau_plugin_callbacks; +} Tau_plugin_event_interrupt_trigger_data_t ; + +/*Define callbacks for specific events*/ +typedef int (*Tau_plugin_function_registration_complete)(Tau_plugin_event_function_registration_data_t*); +typedef int (*Tau_plugin_metadata_registration_complete)(Tau_plugin_event_metadata_registration_data_t*); +typedef int (*Tau_plugin_post_init)(Tau_plugin_event_post_init_data_t*); +typedef int (*Tau_plugin_dump)(Tau_plugin_event_dump_data_t*); +typedef int (*Tau_plugin_function_entry)(Tau_plugin_event_function_entry_data_t*); +typedef int (*Tau_plugin_function_exit)(Tau_plugin_event_function_exit_data_t*); +typedef int (*Tau_plugin_current_timer_exit)(Tau_plugin_event_current_timer_exit_data_t*); +typedef int (*Tau_plugin_send)(Tau_plugin_event_send_data_t*); +typedef int (*Tau_plugin_recv)(Tau_plugin_event_recv_data_t*); +typedef int (*Tau_plugin_atomic_event_registration_complete)(Tau_plugin_event_atomic_event_registration_data_t*); +typedef int (*Tau_plugin_atomic_event_trigger)(Tau_plugin_event_atomic_event_trigger_data_t*); +typedef int (*Tau_plugin_pre_end_of_execution)(Tau_plugin_event_pre_end_of_execution_data_t*); +typedef int (*Tau_plugin_end_of_execution)(Tau_plugin_event_end_of_execution_data_t*); +typedef int (*Tau_plugin_function_finalize)(Tau_plugin_event_function_finalize_data_t*); +typedef int (*Tau_plugin_interrupt_trigger)(Tau_plugin_event_interrupt_trigger_data_t*); + +/*Define the callback structure*/ +typedef struct Tau_plugin_callbacks { + Tau_plugin_function_registration_complete FunctionRegistrationComplete; + Tau_plugin_metadata_registration_complete MetadataRegistrationComplete; + Tau_plugin_post_init PostInit; + Tau_plugin_dump Dump; + Tau_plugin_function_entry FunctionEntry; + Tau_plugin_function_exit FunctionExit; + Tau_plugin_current_timer_exit CurrentTimerExit; + Tau_plugin_send Send; + Tau_plugin_recv Recv; + Tau_plugin_atomic_event_registration_complete AtomicEventRegistrationComplete; + Tau_plugin_atomic_event_trigger AtomicEventTrigger; + Tau_plugin_pre_end_of_execution PreEndOfExecution; + Tau_plugin_end_of_execution EndOfExecution; + Tau_plugin_function_finalize FunctionFinalize; + Tau_plugin_interrupt_trigger InterruptTrigger; +} Tau_plugin_callbacks_t; + +/*Define all the events currently supported*/ +typedef enum Tau_plugin_event { + TAU_PLUGIN_EVENT_FUNCTION_REGISTRATION, + TAU_PLUGIN_EVENT_METADATA_REGISTRATION, + TAU_PLUGIN_EVENT_POST_INIT, + TAU_PLUGIN_EVENT_DUMP, + TAU_PLUGIN_EVENT_FUNCTION_ENTRY, + TAU_PLUGIN_EVENT_FUNCTION_EXIT, + TAU_PLUGIN_EVENT_SEND, + TAU_PLUGIN_EVENT_RECV, + TAU_PLUGIN_EVENT_CURRENT_TIMER_EXIT, + TAU_PLUGIN_EVENT_ATOMIC_EVENT_REGISTRATION, + TAU_PLUGIN_EVENT_ATOMIC_EVENT_TRIGGER, + TAU_PLUGIN_EVENT_PRE_END_OF_EXECUTION, + TAU_PLUGIN_EVENT_END_OF_EXECUTION, + TAU_PLUGIN_EVENT_FUNCTION_FINALIZE, + TAU_PLUGIN_EVENT_INTERRUPT_TRIGGER +} Tau_plugin_event_t; + +/* Is the event registered with a callback? */ +typedef struct Tau_plugin_callbacks_active { + unsigned int function_registration; + unsigned int metadata_registration; + unsigned int post_init; + unsigned int dump; + unsigned int function_entry; + unsigned int function_exit; + unsigned int send; + unsigned int recv; + unsigned int current_timer_exit; + unsigned int atomic_event_registration; + unsigned int atomic_event_trigger; + unsigned int pre_end_of_execution; + unsigned int end_of_execution; + unsigned int function_finalize; + unsigned int interrupt_trigger; +} Tau_plugin_callbacks_active_t; /*Define data structures to hold information about currently loaded plugins. * Only relevant for TAU internals - not a concern to plugins themselves*/ @@ -198,25 +182,25 @@ typedef struct Tau_plugin { char plugin_name[1024]; void* handle; struct Tau_plugin * next; -} Tau_plugin; +} Tau_plugin_t; typedef struct Tau_plugin_list { - struct Tau_plugin * head; -} Tau_plugin_list; + Tau_plugin_t * head; +} Tau_plugin_list_t; -typedef struct Tau_plugin_callback_ { - Tau_plugin_callbacks cb; - struct Tau_plugin_callback_ * next; -} Tau_plugin_callback_; +typedef struct Tau_plugin_callback { + Tau_plugin_callbacks_t cb; + struct Tau_plugin_callback * next; +} Tau_plugin_callback_t; typedef struct Tau_plugin_callback_list { - Tau_plugin_callback_ * head; -} Tau_plugin_callback_list; + Tau_plugin_callback_t * head; +} Tau_plugin_callback_list_t; typedef struct PluginManager { - Tau_plugin_list * plugin_list; - Tau_plugin_callback_list * callback_list; -} PluginManager; + Tau_plugin_list_t * plugin_list; + Tau_plugin_callback_list_t * callback_list; +} PluginManager_t; typedef int (*PluginInitFunc) (int argc, char **argv); diff --git a/include/Profile/TauUtil.h b/include/Profile/TauUtil.h index bc1b77bc0..655a5bd33 100644 --- a/include/Profile/TauUtil.h +++ b/include/Profile/TauUtil.h @@ -61,8 +61,8 @@ void Tau_plugin_recvmsg(long unsigned int type, long unsigned int source, long u // Use a macro so we can compile it out if too much overhead. -#define TAU_PLUGIN_SENDMSG(t, d, l, r) Tau_plugin_sendmsg((long unsigned int)t, (long unsigned int)d, (long unsigned int)l, (long unsigned int)r) -#define TAU_PLUGIN_RECVMSG(t, s, l, r) Tau_plugin_recvmsg((long unsigned int)t, (long unsigned int)s, (long unsigned int)l, (long unsigned int)r) +#define TAU_PLUGIN_SENDMSG(t, d, l, r) if (Tau_plugins_enabled.send) { Tau_plugin_sendmsg((long unsigned int)t, (long unsigned int)d, (long unsigned int)l, (long unsigned int)r); } +#define TAU_PLUGIN_RECVMSG(t, s, l, r) if (Tau_plugins_enabled.recv) { Tau_plugin_recvmsg((long unsigned int)t, (long unsigned int)s, (long unsigned int)l, (long unsigned int)r); } /* The following macros help create a local array and assign to elements of the local C array, values from Fortran array after conversion using f2c diff --git a/plugins/examples/TauSOS.cpp b/plugins/examples/TauSOS.cpp index 4d51e264c..6b9692e30 100644 --- a/plugins/examples/TauSOS.cpp +++ b/plugins/examples/TauSOS.cpp @@ -337,7 +337,19 @@ void TAU_SOS_parse_environment_variables(void) { } tmp = getenv("TAU_SOS_TRACING"); if (parse_bool(tmp, TAU_SOS_TRACING_DEFAULT)) { - thePluginOptions().env_sos_tracing = 1; +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. + thePluginOptions().env_sos_tracing = 1; +#else + fprintf(stderr, "ERROR! TAU was configured without plugin trace support!\n"); + fprintf(stderr, "Please reconfigure TAU with:\n"); + fprintf(stderr, "'-useropt=-DTAU_PLUGIN_TRACE_SUPPORT#-O2#-g', recompile, and reinstall.\n"); +#ifdef TAU_MPI + MPI_Abort(MPI_COMM_WORLD, 999); +#else + abort(); +#endif +#endif } tmp = getenv("TAU_SOS_CACHE_DEPTH"); thePluginOptions().env_sos_cache_depth = parse_int(tmp, TAU_SOS_CACHE_DEPTH_DEFAULT); @@ -540,6 +552,7 @@ void TAU_SOS_finalize(void) { // shouldn't be necessary, but sometimes the shutdown message is ignored? //TAU_SOS_fork_exec_sosd_shutdown(); } + printf("}\n"); SOS_finalize(_runtime); } @@ -564,7 +577,7 @@ void Tau_SOS_pack_current_timer(const char * event_name) { // assume time is the first counter! // also convert it to microseconds double value = (current[0] - p->StartTime[0]) * CONVERT_TO_USEC; - if (strlen(event_name) > 256) { printf("long string, %d: '%s'\n", strlen(event_name), event_name); } + // if (strlen(event_name) > 256) { printf("long string, %d: '%s'\n", strlen(event_name), event_name); } SOS_pack(tau_sos_pub, event_name, SOS_VAL_TYPE_DOUBLE, &value); } @@ -580,7 +593,7 @@ void Tau_SOS_pack_string(const char * name, char * value) { } RtsLayer::UnLockDB(); } - if (strlen(name) > 256) { printf("long string, %d: '%s'\n", strlen(name), name); } + // if (strlen(name) > 256) { printf("long string, %d: '%s'\n", strlen(name), name); } SOS_pack(tau_sos_pub, name, SOS_VAL_TYPE_STRING, value); } @@ -596,7 +609,7 @@ void Tau_SOS_pack_double(const char * name, double value) { } RtsLayer::UnLockDB(); } - if (strlen(name) > 256) { printf("long string, %d: '%s'\n", strlen(name), name); } + // if (strlen(name) > 256) { printf("long string, %d: '%s'\n", strlen(name), name); } SOS_pack(tau_sos_pub, name, SOS_VAL_TYPE_DOUBLE, &value); } @@ -612,7 +625,7 @@ void Tau_SOS_pack_integer(const char * name, int value) { } RtsLayer::UnLockDB(); } - if (strlen(name) > 256) { printf("long string, %d: '%s'\n", strlen(name), name); } + // if (strlen(name) > 256) { printf("long string, %d: '%s'\n", strlen(name), name); } SOS_pack(tau_sos_pub, name, SOS_VAL_TYPE_INT, &value); } @@ -628,7 +641,7 @@ void Tau_SOS_pack_long(const char * name, long int value) { } RtsLayer::UnLockDB(); } - if (strlen(name) > 256) { printf("long string, %d: '%s'\n", strlen(name), name); } + // if (strlen(name) > 256) { printf("long string, %d: '%s'\n", strlen(name), name); } SOS_pack(tau_sos_pub, name, SOS_VAL_TYPE_LONG, &value); } @@ -685,7 +698,7 @@ void TAU_SOS_pack_profile() { std::stringstream calls_str; calls_str << "TAU_TIMER:" << tid << ":calls:" << fi->GetAllGroups() << ":" << fi->GetName(); const std::string& tmpcalls = calls_str.str(); - if (strlen(tmpcalls.c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmpcalls.c_str()), tmpcalls.c_str()); } + // if (strlen(tmpcalls.c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmpcalls.c_str()), tmpcalls.c_str()); } SOS_pack(tau_sos_pub, tmpcalls.c_str(), SOS_VAL_TYPE_INT, &calls); // todo - subroutines @@ -701,8 +714,8 @@ void TAU_SOS_pack_profile() { excl_str.str(std::string()); excl_str << "TAU_TIMER:" << tid << ":exclusive_" << counterNames[m] << ":" << fi->GetAllGroups() << ":" << fi->GetName(); const std::string& tmpexcl = excl_str.str(); - if (strlen(tmpexcl.c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmpexcl.c_str()), tmpexcl.c_str()); } - if (strlen(tmpincl.c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmpincl.c_str()), tmpincl.c_str()); } + // if (strlen(tmpexcl.c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmpexcl.c_str()), tmpexcl.c_str()); } + // if (strlen(tmpincl.c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmpincl.c_str()), tmpincl.c_str()); } SOS_pack(tau_sos_pub, tmpincl.c_str(), SOS_VAL_TYPE_DOUBLE, &inclusive); SOS_pack(tau_sos_pub, tmpexcl.c_str(), SOS_VAL_TYPE_DOUBLE, &exclusive); } @@ -736,23 +749,23 @@ void TAU_SOS_pack_profile() { min = ue->GetMin(tid); sumsqr = ue->GetSumSqr(tid); tmp_str << "TAU_COUNTER:" << tid << ":NumEvents:" << ue->GetName(); - if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } + // if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } SOS_pack(tau_sos_pub, tmp_str.str().c_str(), SOS_VAL_TYPE_INT, &numEvents); tmp_str.str(std::string()); tmp_str << "TAU_COUNTER:" << tid << ":Max:" << ue->GetName(); - if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } + // if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } SOS_pack(tau_sos_pub, tmp_str.str().c_str(), SOS_VAL_TYPE_DOUBLE, &max); tmp_str.str(std::string()); tmp_str << "TAU_COUNTER:" << tid << ":Min:" << ue->GetName(); - if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } + // if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } SOS_pack(tau_sos_pub, tmp_str.str().c_str(), SOS_VAL_TYPE_DOUBLE, &min); tmp_str.str(std::string()); tmp_str << "TAU_COUNTER:" << tid << ":Mean:" << ue->GetName(); - if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } + // if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } SOS_pack(tau_sos_pub, tmp_str.str().c_str(), SOS_VAL_TYPE_DOUBLE, &mean); tmp_str.str(std::string()); tmp_str << "TAU_COUNTER:" << tid << ":SumSqr:" << ue->GetName(); - if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } + // if (strlen(tmp_str.str().c_str()) > 256) { printf("long string, %d: '%s'\n", strlen(tmp_str.str().c_str()), tmp_str.str().c_str()); } SOS_pack(tau_sos_pub, tmp_str.str().c_str(), SOS_VAL_TYPE_DOUBLE, &sumsqr); tmp_str.str(std::string()); } diff --git a/plugins/examples/Tau_plugin_example_disable_instrumentation_runtime.cpp b/plugins/examples/Tau_plugin_example_disable_instrumentation_runtime.cpp index eb61803f7..eb166085b 100644 --- a/plugins/examples/Tau_plugin_example_disable_instrumentation_runtime.cpp +++ b/plugins/examples/Tau_plugin_example_disable_instrumentation_runtime.cpp @@ -492,9 +492,9 @@ char *Tau_preprocess_function_info_name(const char *name) { /*This function gets invoked at function registration. * It checks if the function getting registrtion is present in the exclude list specified by the instrumentation file * and is so, sets the function group to TAU_DISABLE, effectively disabling function from getting instrumented*/ -int Tau_plugin_example_check_and_set_disable_group(Tau_plugin_event_function_registration_data data) { +int Tau_plugin_example_check_and_set_disable_group(Tau_plugin_event_function_registration_data* data) { - const char * before_preprocessing = ((FunctionInfo *)data.function_info_ptr)->GetName(); + const char * before_preprocessing = ((FunctionInfo *)data->function_info_ptr)->GetName(); const char * name = Tau_preprocess_function_info_name(before_preprocessing); const char * pch = strchr(name, '['); @@ -528,7 +528,7 @@ int Tau_plugin_example_check_and_set_disable_group(Tau_plugin_event_function_reg if(!instrumentEntity(std::string(name, position)) || (instrument_file == false)) { RtsLayer::LockDB(); - Tau_profile_set_group(data.function_info_ptr, TAU_DISABLE); + Tau_profile_set_group(data->function_info_ptr, TAU_DISABLE); RtsLayer::UnLockDB(); } @@ -539,7 +539,7 @@ int Tau_plugin_example_check_and_set_disable_group(Tau_plugin_event_function_reg * Every plugin MUST implement this function to register callbacks for various events * that the plugin is interested in listening to*/ extern "C" int Tau_plugin_init_func(int argc, char **argv) { - Tau_plugin_callbacks * cb = (Tau_plugin_callbacks*)malloc(sizeof(Tau_plugin_callbacks)); + Tau_plugin_callbacks_t * cb = (Tau_plugin_callbacks*)malloc(sizeof(Tau_plugin_callbacks_t)); if(argc == 0) { printf("TAU PLUGIN: Please provide a selective instrumentation by setting TAU_SELECT_FILE=\n"); diff --git a/plugins/examples/Tau_plugin_example_mpit_mvapich_free_unused_vbufs.c b/plugins/examples/Tau_plugin_example_mpit_mvapich_free_unused_vbufs.c index 62576e911..cbf78fabb 100644 --- a/plugins/examples/Tau_plugin_example_mpit_mvapich_free_unused_vbufs.c +++ b/plugins/examples/Tau_plugin_example_mpit_mvapich_free_unused_vbufs.c @@ -37,7 +37,7 @@ unsigned long long int * pvar_vbuf_allocated = NULL; static int num_vbuf_pools = 0; -int Tau_plugin_example_mpit_recommend_sharp_usage(Tau_plugin_event_interrupt_trigger_data data) { +int Tau_plugin_example_mpit_recommend_sharp_usage(Tau_plugin_event_interrupt_trigger_data_t* data) { char metric_string[TAU_NAME_LENGTH], value_string[TAU_NAME_LENGTH]; unsigned long long int reduced_value_array[5] = {0}; static char reduced_value_cvar_string[TAU_NAME_LENGTH] = ""; @@ -117,7 +117,7 @@ int Tau_plugin_init_func(int argc, char **argv) { return -1; } - Tau_plugin_callbacks * cb = (Tau_plugin_callbacks*)malloc(sizeof(Tau_plugin_callbacks)); + Tau_plugin_callbacks_t * cb = (Tau_plugin_callbacks_t*)malloc(sizeof(Tau_plugin_callbacks_t)); TAU_UTIL_INIT_TAU_PLUGIN_CALLBACKS(cb); cb->InterruptTrigger = Tau_plugin_example_mpit_recommend_sharp_usage; TAU_UTIL_PLUGIN_REGISTER_CALLBACKS(cb); diff --git a/plugins/examples/Tau_plugin_example_mpit_recommend_sharp_usage.cpp b/plugins/examples/Tau_plugin_example_mpit_recommend_sharp_usage.cpp index 738b51c92..9cc6d3270 100644 --- a/plugins/examples/Tau_plugin_example_mpit_recommend_sharp_usage.cpp +++ b/plugins/examples/Tau_plugin_example_mpit_recommend_sharp_usage.cpp @@ -28,7 +28,7 @@ extern "C" int TauProfiler_updateAllIntermediateStatistics(void); * versus the total application execution time, along with the message size for MPI_Allreduce. * If the application spends a signigicant time in MPI_Allreduce, and if the message size involved in MPI_Allreduce * is low, then it recommends the user to enable SHArP through a message on TAU_METADATA*/ -extern "C" int Tau_plugin_example_mpit_recommend_sharp_usage(Tau_plugin_event_end_of_execution_data data) { +extern "C" int Tau_plugin_example_mpit_recommend_sharp_usage(Tau_plugin_event_end_of_execution_data_t* data) { double exclusiveTimeAllReduce, inclusiveTimeApp = 0.0; double meanAllReduceMessageSize = 0; @@ -102,7 +102,7 @@ extern "C" int Tau_plugin_example_mpit_recommend_sharp_usage(Tau_plugin_event_en * * Every plugin MUST implement this function to register callbacks for various events * * that the plugin is interested in listening to*/ extern "C" int Tau_plugin_init_func(int argc, char **argv) { - Tau_plugin_callbacks * cb = (Tau_plugin_callbacks*)malloc(sizeof(Tau_plugin_callbacks)); + Tau_plugin_callbacks_t * cb = (Tau_plugin_callbacks_t*)malloc(sizeof(Tau_plugin_callbacks_t)); TAU_UTIL_INIT_TAU_PLUGIN_CALLBACKS(cb); cb->EndOfExecution = Tau_plugin_example_mpit_recommend_sharp_usage; TAU_UTIL_PLUGIN_REGISTER_CALLBACKS(cb); diff --git a/plugins/examples/Tau_plugin_sos.cpp b/plugins/examples/Tau_plugin_sos.cpp index 83165412d..9813ce91f 100644 --- a/plugins/examples/Tau_plugin_sos.cpp +++ b/plugins/examples/Tau_plugin_sos.cpp @@ -24,7 +24,7 @@ extern tau::Profiler* Tau_get_timer_at_stack_depth(int pos); static bool enabled(false); /* Only dump data to SOS if we aren't doing periodic dumps */ -int Tau_plugin_sos_dump(Tau_plugin_event_dump_data data) { +int Tau_plugin_sos_dump(Tau_plugin_event_dump_data_t* data) { if (!enabled) return 0; //printf("TAU PLUGIN SOS: dump\n"); if (thePluginOptions().env_sos_periodic != 1) { @@ -34,12 +34,12 @@ int Tau_plugin_sos_dump(Tau_plugin_event_dump_data data) { } /* This is a weird event, not sure what for */ -int Tau_plugin_finalize(Tau_plugin_event_function_finalize_data data) { +int Tau_plugin_finalize(Tau_plugin_event_function_finalize_data_t* data) { return 0; } /* This happens from MPI_Finalize, before MPI is torn down. */ -int Tau_plugin_sos_pre_end_of_execution(Tau_plugin_event_pre_end_of_execution_data data) { +int Tau_plugin_sos_pre_end_of_execution(Tau_plugin_event_pre_end_of_execution_data_t* data) { if (!enabled) return 0; //fprintf(stdout, "TAU PLUGIN SOS Pre-Finalize\n"); fflush(stdout); // OK to do it from any thread, because it came from MPI_Finalize @@ -47,7 +47,7 @@ int Tau_plugin_sos_pre_end_of_execution(Tau_plugin_event_pre_end_of_execution_da /* We used to finalize now, but we no longer use MPI in the finalization * so it's ok to wait until all timers are done */ /* - if (data.tid == 0) { + if (data->tid == 0) { TAU_SOS_finalize(); } */ @@ -56,7 +56,7 @@ int Tau_plugin_sos_pre_end_of_execution(Tau_plugin_event_pre_end_of_execution_da /* This happens after MPI_Init, and after all TAU metadata variables have been * read */ -int Tau_plugin_sos_post_init(Tau_plugin_event_post_init_data data) { +int Tau_plugin_sos_post_init(Tau_plugin_event_post_init_data_t* data) { if (!enabled) return 0; //fprintf(stdout, "TAU PLUGIN SOS Post Init\n"); fflush(stdout); TAU_SOS_send_data(); @@ -64,99 +64,99 @@ int Tau_plugin_sos_post_init(Tau_plugin_event_post_init_data data) { } /* This happens on Tau_start() */ -int Tau_plugin_sos_function_entry(Tau_plugin_event_function_entry_data data) { +int Tau_plugin_sos_function_entry(Tau_plugin_event_function_entry_data_t* data) { if (!enabled) return 0; /* First, check to see if we are including/excluding this timer */ - if (skip_timer(data.timer_name)) { + if (skip_timer(data->timer_name)) { return 0; } /* todo: filter on group, timer name */ std::stringstream ss; - ss << "TAU_EVENT_ENTRY:" << data.tid << ":" << data.timer_name; + ss << "TAU_EVENT_ENTRY:" << data->tid << ":" << data->timer_name; //std::cout << ss.str() << std::endl; - Tau_SOS_pack_long(ss.str().c_str(), data.timestamp); + Tau_SOS_pack_long(ss.str().c_str(), data->timestamp); return 0; } /* This happens on Tau_stop() */ -int Tau_plugin_sos_function_exit(Tau_plugin_event_function_exit_data data) { +int Tau_plugin_sos_function_exit(Tau_plugin_event_function_exit_data_t* data) { if (!enabled) return 0; /* First, check to see if we are including/excluding this timer */ - if (skip_timer(data.timer_name)) { + if (skip_timer(data->timer_name)) { return 0; } /* todo: filter on group, timer name */ std::stringstream ss; - ss << "TAU_EVENT_EXIT:" << data.tid << ":" << data.timer_name; + ss << "TAU_EVENT_EXIT:" << data->tid << ":" << data->timer_name; //std::cout << ss.str() << std::endl; - Tau_SOS_pack_long(ss.str().c_str(), data.timestamp); + Tau_SOS_pack_long(ss.str().c_str(), data->timestamp); return 0; } /* This happens on Tau_userevent() */ -int Tau_plugin_sos_atomic_trigger(Tau_plugin_event_atomic_event_trigger_data data) { +int Tau_plugin_sos_atomic_trigger(Tau_plugin_event_atomic_event_trigger_data_t* data) { if (!enabled) return 0; /* First, check to see if we are including/excluding this counter */ - if (skip_counter(data.counter_name)) { + if (skip_counter(data->counter_name)) { return 0; } std::stringstream ss; - ss << "TAU_EVENT_COUNTER:" << data.tid << ":" << data.counter_name; - //std::cout << ss.str() << " = " << data.value << std::endl; - Tau_SOS_pack_long(ss.str().c_str(), data.value); + ss << "TAU_EVENT_COUNTER:" << data->tid << ":" << data->counter_name; + //std::cout << ss.str() << " = " << data->value << std::endl; + Tau_SOS_pack_long(ss.str().c_str(), data->value); return 0; } /* This happens for special events from ADIOS, MPI */ -int Tau_plugin_sos_current_timer_exit(Tau_plugin_event_current_timer_exit_data data) { +int Tau_plugin_sos_current_timer_exit(Tau_plugin_event_current_timer_exit_data_t* data) { if (!enabled) return 0; - Tau_SOS_pack_current_timer(data.name_prefix); + Tau_SOS_pack_current_timer(data->name_prefix); return 0; } /* This happens on MPI_Send events (and similar) */ -int Tau_plugin_sos_send(Tau_plugin_event_send_data data) { +int Tau_plugin_sos_send(Tau_plugin_event_send_data_t* data) { if (!enabled) return 0; /* todo: filter on group, timer name */ std::stringstream ss; - ss << "TAU_EVENT_SEND:" << data.tid - << ":" << data.message_tag - << ":" << data.destination - << ":" << data.bytes_sent; + ss << "TAU_EVENT_SEND:" << data->tid + << ":" << data->message_tag + << ":" << data->destination + << ":" << data->bytes_sent; //std::cout << ss.str() << std::endl; - Tau_SOS_pack_long(ss.str().c_str(), data.timestamp); + Tau_SOS_pack_long(ss.str().c_str(), data->timestamp); return 0; } /* This happens on MPI_Recv events (and similar) */ -int Tau_plugin_sos_recv(Tau_plugin_event_recv_data data) { +int Tau_plugin_sos_recv(Tau_plugin_event_recv_data_t* data) { if (!enabled) return 0; /* todo: filter on group, timer name */ std::stringstream ss; - ss << "TAU_EVENT_RECV:" << data.tid - << ":" << data.message_tag - << ":" << data.source - << ":" << data.bytes_received; + ss << "TAU_EVENT_RECV:" << data->tid + << ":" << data->message_tag + << ":" << data->source + << ":" << data->bytes_received; //std::cout << ss.str() << std::endl; - Tau_SOS_pack_long(ss.str().c_str(), data.timestamp); + Tau_SOS_pack_long(ss.str().c_str(), data->timestamp); return 0; } /* This happens when a Metadata field is saved. */ -int Tau_plugin_metadata_registration_complete_func(Tau_plugin_event_metadata_registration_data data) { +int Tau_plugin_metadata_registration_complete_func(Tau_plugin_event_metadata_registration_data_t* data) { if (!enabled) return 0; //fprintf(stdout, "TAU Metadata registration\n"); fflush(stdout); std::stringstream ss; - ss << "TAU_Metadata:" << 0 << ":" << data.name; - switch(data.value->type) { + ss << "TAU_Metadata:" << 0 << ":" << data->name; + switch(data->value->type) { case TAU_METADATA_TYPE_STRING: - Tau_SOS_pack_string(ss.str().c_str(), data.value->data.cval); + Tau_SOS_pack_string(ss.str().c_str(), data->value->data.cval); break; case TAU_METADATA_TYPE_INTEGER: - Tau_SOS_pack_integer(ss.str().c_str(), data.value->data.ival); + Tau_SOS_pack_integer(ss.str().c_str(), data->value->data.ival); break; case TAU_METADATA_TYPE_DOUBLE: - Tau_SOS_pack_double(ss.str().c_str(), data.value->data.dval); + Tau_SOS_pack_double(ss.str().c_str(), data->value->data.dval); break; case TAU_METADATA_TYPE_TRUE: Tau_SOS_pack_string(ss.str().c_str(), const_cast("true")); @@ -174,13 +174,15 @@ int Tau_plugin_metadata_registration_complete_func(Tau_plugin_event_metadata_reg } /* This happens from Profiler.cpp, when data is written out. */ -int Tau_plugin_sos_end_of_execution(Tau_plugin_event_end_of_execution_data data) { - if (!enabled || data.tid != 0) return 0; +int Tau_plugin_sos_end_of_execution(Tau_plugin_event_end_of_execution_data_t* data) { + if (!enabled || data->tid != 0) return 0; +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. /* If we are tracing, we need to "stop" all of the remaining timers on the stack */ if (thePluginOptions().env_sos_tracing) { - Tau_plugin_event_function_exit_data data; + Tau_plugin_event_function_exit_data_t exit_data; // safe to assume 0? - //int tid = data.tid; + //int tid = exit_data.tid; RtsLayer::UnLockDB(); for (int tid = TAU_MAX_THREADS-1 ; tid >= 0 ; tid--) { int depth = Tau_get_current_stack_depth(tid); @@ -188,21 +190,22 @@ int Tau_plugin_sos_end_of_execution(Tau_plugin_event_end_of_execution_data data) tau::Profiler *profiler = Tau_get_timer_at_stack_depth(i); if (profiler->ThisFunction->GetName() == NULL) { // small memory leak, but at shutdown. - data.timer_name = strdup(".TAU application"); + exit_data.timer_name = strdup(".TAU application"); } else { - data.timer_name = profiler->ThisFunction->GetName(); - data.timer_group = profiler->ThisFunction->GetAllGroups(); + exit_data.timer_name = profiler->ThisFunction->GetName(); + exit_data.timer_group = profiler->ThisFunction->GetAllGroups(); } - data.tid = tid; + exit_data.tid = tid; double CurrentTime[TAU_MAX_COUNTERS] = { 0 }; RtsLayer::getUSecD(tid, CurrentTime); - data.timestamp = (x_uint64)CurrentTime[0]; // USE COUNTER1 for tracing + exit_data.timestamp = (x_uint64)CurrentTime[0]; // USE COUNTER1 for tracing //printf("%d,%d Stopping %s\n", getpid(), tid, data.timer_name); - Tau_plugin_sos_function_exit(data); + Tau_plugin_sos_function_exit(&exit_data); } } RtsLayer::UnLockDB(); } +#endif enabled = false; //fprintf(stdout, "TAU PLUGIN SOS Finalize\n"); fflush(stdout); TAU_SOS_finalize(); @@ -214,7 +217,7 @@ int Tau_plugin_sos_end_of_execution(Tau_plugin_event_end_of_execution_data data) * Every plugin MUST implement this function to register callbacks for various events * that the plugin is interested in listening to*/ extern "C" int Tau_plugin_init_func(int argc, char **argv) { - Tau_plugin_callbacks * cb = (Tau_plugin_callbacks*)malloc(sizeof(Tau_plugin_callbacks)); + Tau_plugin_callbacks_t * cb = (Tau_plugin_callbacks_t*)malloc(sizeof(Tau_plugin_callbacks_t)); //fprintf(stdout, "TAU PLUGIN SOS Init\n"); fflush(stdout); // Parse our settings TAU_SOS_parse_environment_variables(); @@ -233,6 +236,8 @@ extern "C" int Tau_plugin_init_func(int argc, char **argv) { cb->PostInit = Tau_plugin_sos_post_init; cb->PreEndOfExecution = Tau_plugin_sos_pre_end_of_execution; cb->EndOfExecution = Tau_plugin_sos_end_of_execution; +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. /* Event tracing support */ if (thePluginOptions().env_sos_tracing) { cb->Send = Tau_plugin_sos_send; @@ -241,6 +246,7 @@ extern "C" int Tau_plugin_init_func(int argc, char **argv) { cb->FunctionExit = Tau_plugin_sos_function_exit; cb->AtomicEventTrigger = Tau_plugin_sos_atomic_trigger; } +#endif /* Specialized support for ADIOS, MPI events (ADIOS Skel/Pooky support) */ if (thePluginOptions().env_sos_trace_adios) { cb->CurrentTimerExit = Tau_plugin_sos_current_timer_exit; @@ -252,26 +258,29 @@ extern "C" int Tau_plugin_init_func(int argc, char **argv) { TAU_UTIL_PLUGIN_REGISTER_CALLBACKS(cb); enabled = true; +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. /* If we are tracing, we need to "start" all of the timers on the stack */ if (thePluginOptions().env_sos_tracing) { RtsLayer::LockDB(); //int tid = RtsLayer::myThread(); for (int tid = TAU_MAX_THREADS-1 ; tid >= 0 ; tid--) { - Tau_plugin_event_function_entry_data data; + Tau_plugin_event_function_entry_data_t entry_data; // safe to assume 0? int depth = Tau_get_current_stack_depth(tid); for (int i = 0 ; i <= depth ; i++) { tau::Profiler *profiler = Tau_get_timer_at_stack_depth(i); - data.timer_name = profiler->ThisFunction->GetName(); - data.timer_group = profiler->ThisFunction->GetAllGroups(); - data.tid = tid; - data.timestamp = (x_uint64)profiler->StartTime[0]; + entry_data.timer_name = profiler->ThisFunction->GetName(); + entry_data.timer_group = profiler->ThisFunction->GetAllGroups(); + entry_data.tid = tid; + entry_data.timestamp = (x_uint64)profiler->StartTime[0]; //printf("%d,%d Starting %s\n", getpid(), tid, data.timer_name); - Tau_plugin_sos_function_entry(data); + Tau_plugin_sos_function_entry(&entry_data); } } RtsLayer::UnLockDB(); } +#endif return 0; } diff --git a/plugins/testplugins/Tau_plugin_atomic_event_registration_complete.cpp b/plugins/testplugins/Tau_plugin_atomic_event_registration_complete.cpp index 3142393bb..7f55afa36 100644 --- a/plugins/testplugins/Tau_plugin_atomic_event_registration_complete.cpp +++ b/plugins/testplugins/Tau_plugin_atomic_event_registration_complete.cpp @@ -15,9 +15,9 @@ #include -int Tau_plugin_test_event_atomic_event_registration_complete(Tau_plugin_event_atomic_event_registration_data data) { +int Tau_plugin_test_event_atomic_event_registration_complete(Tau_plugin_event_atomic_event_registration_data_t *data) { - std::cout << "TAU PLUGIN: Event with name " << ((tau::TauUserEvent *)data.user_event_ptr)->GetName() << " has been registered" << std::endl; + std::cout << "TAU PLUGIN: Event with name " << ((tau::TauUserEvent *)data->user_event_ptr)->GetName() << " has been registered" << std::endl; return 0; } diff --git a/plugins/testplugins/Tau_plugin_atomic_event_trigger.cpp b/plugins/testplugins/Tau_plugin_atomic_event_trigger.cpp index dd332d6d6..754a8333d 100644 --- a/plugins/testplugins/Tau_plugin_atomic_event_trigger.cpp +++ b/plugins/testplugins/Tau_plugin_atomic_event_trigger.cpp @@ -15,9 +15,9 @@ #include -int Tau_plugin_test_event_atomic_event_trigger(Tau_plugin_event_atomic_event_trigger_data data) { +int Tau_plugin_test_event_atomic_event_trigger(Tau_plugin_event_atomic_event_trigger_data_t*data) { - std::cout << "TAU PLUGIN: Event with name " << data.counter_name << " has been triggered with value " << data.value << std::endl; + std::cout << "TAU PLUGIN: Event with name " << data->counter_name << " has been triggered with value " << data->value << std::endl; return 0; } diff --git a/plugins/testplugins/Tau_plugin_end_of_execution.cpp b/plugins/testplugins/Tau_plugin_end_of_execution.cpp index bb6629a21..517f6b8aa 100644 --- a/plugins/testplugins/Tau_plugin_end_of_execution.cpp +++ b/plugins/testplugins/Tau_plugin_end_of_execution.cpp @@ -15,9 +15,9 @@ #include -int Tau_plugin_test_event_end_of_execution(Tau_plugin_event_end_of_execution_data data) { +int Tau_plugin_test_event_end_of_execution(Tau_plugin_event_end_of_execution_data_t* data) { - std::cout << "TAU PLUGIN: End of execution reached for threadId: " << data.tid << std::endl; + std::cout << "TAU PLUGIN: End of execution reached for threadId: " << data->tid << std::endl; return 0; } diff --git a/plugins/testplugins/Tau_plugin_function_registration_complete.cpp b/plugins/testplugins/Tau_plugin_function_registration_complete.cpp index a51e53fe2..9cc9bb410 100644 --- a/plugins/testplugins/Tau_plugin_function_registration_complete.cpp +++ b/plugins/testplugins/Tau_plugin_function_registration_complete.cpp @@ -16,8 +16,8 @@ #include #include -int Tau_plugin_test_event_function_registration_complete(Tau_plugin_event_function_registration_data data) { - printf("TAU PLUGIN: Function %s has been registered for tid: %d\n", Tau_profile_get_name(data.function_info_ptr), data.tid); +int Tau_plugin_test_event_function_registration_complete(Tau_plugin_event_function_registration_data_t* data) { + printf("TAU PLUGIN: Function %s has been registered for tid: %d\n", Tau_profile_get_name(data->function_info_ptr), data->tid); return 0; } diff --git a/plugins/testplugins/Tau_plugin_interrupt_trigger.cpp b/plugins/testplugins/Tau_plugin_interrupt_trigger.cpp index 109107ee7..5b3a1b3fa 100644 --- a/plugins/testplugins/Tau_plugin_interrupt_trigger.cpp +++ b/plugins/testplugins/Tau_plugin_interrupt_trigger.cpp @@ -15,9 +15,9 @@ #include -int Tau_plugin_test_event_interrupt_trigger(Tau_plugin_event_interrupt_trigger_data data) { +int Tau_plugin_test_event_interrupt_trigger(Tau_plugin_event_interrupt_trigger_data_t *data) { - std::cout << "TAU PLUGIN: Interrupt has been triggered for signal: " << data.signum << std::endl; + std::cout << "TAU PLUGIN: Interrupt has been triggered for signal: " << data->signum << std::endl; return 0; } diff --git a/src/Profile/FunctionInfo.cpp b/src/Profile/FunctionInfo.cpp index 501c2dbda..7260002c4 100644 --- a/src/Profile/FunctionInfo.cpp +++ b/src/Profile/FunctionInfo.cpp @@ -306,8 +306,8 @@ void FunctionInfo::FunctionInfoInit(TauGroup_t ProfileGroup, const char *Profile #endif //RENCI_STFF /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_function_registration_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.function_registration) { + Tau_plugin_event_function_registration_data_t plugin_data; plugin_data.function_info_ptr = this; plugin_data.tid = tid; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_FUNCTION_REGISTRATION, &plugin_data); diff --git a/src/Profile/PapiLayer.cpp b/src/Profile/PapiLayer.cpp index 0421167b5..9d8bc45f7 100644 --- a/src/Profile/PapiLayer.cpp +++ b/src/Profile/PapiLayer.cpp @@ -780,15 +780,15 @@ int PapiLayer::initializePerfRAPL(int tid) { /* Check paranoid setting */ FILE *para = fopen("/proc/sys/kernel/perf_event_paranoid", "r"); int para_val; - fscanf(para, "%d", ¶_val); - if (para_val != -1) { + int scanned = fscanf(para, "%d", ¶_val); + if (para_val != -1 || scanned == EOF) { fprintf(stderr, "Error: To use TAU's PAPI Perf interface please ensure that /proc/sys/kernel/perf_event_paranoid has a -1 in it.\n"); exit(1); } fclose(para); numCounters = 0; - ret = PAPI_add_named_event(ThreadList[tid]->EventSet[rapl_cid], "rapl::RAPL_ENERGY_CORES"); + ret = PAPI_add_named_event(ThreadList[tid]->EventSet[rapl_cid], (char*)"rapl::RAPL_ENERGY_CORES"); if (PAPI_OK != ret) { #ifdef DEBUG_PROF fprintf(stderr,"Error: PAPI_add_named_event(RAPL_ENERGY_CORES) because %s.\nPlease ensure that /proc/sys/kernel/perf_event_paranoid has a -1 and your system has /sys/devices/power/events/energy-pkg.scale.\n", PAPI_strerror(ret)); @@ -800,7 +800,7 @@ int PapiLayer::initializePerfRAPL(int tid) { numCounters++; } - ret = PAPI_add_named_event(ThreadList[tid]->EventSet[rapl_cid], "rapl::RAPL_ENERGY_PKG"); + ret = PAPI_add_named_event(ThreadList[tid]->EventSet[rapl_cid], (char*)"rapl::RAPL_ENERGY_PKG"); if (PAPI_OK != ret) { #ifdef DEBUG_PROF @@ -816,7 +816,7 @@ int PapiLayer::initializePerfRAPL(int tid) { #endif /* TAU_BEACON */ } - ret = PAPI_add_named_event(ThreadList[tid]->EventSet[rapl_cid], "rapl::RAPL_ENERGY_GPU"); + ret = PAPI_add_named_event(ThreadList[tid]->EventSet[rapl_cid], (char*)"rapl::RAPL_ENERGY_GPU"); if (PAPI_OK != ret) { #ifdef DEBUG_PROF fprintf(stderr,"Error: PAPI_add_named_event(RAPL_ENERGY_GPU) because %s.\nPlease ensure that /proc/sys/kernel/perf_event_paranoid has a -1 and your system has /sys/devices/power/events/energy-pkg.scale.\n", PAPI_strerror(ret)); @@ -828,7 +828,7 @@ int PapiLayer::initializePerfRAPL(int tid) { numCounters++; } - ret = PAPI_add_named_event(ThreadList[tid]->EventSet[rapl_cid], "rapl::RAPL_ENERGY_DRAM"); + ret = PAPI_add_named_event(ThreadList[tid]->EventSet[rapl_cid], (char*)"rapl::RAPL_ENERGY_DRAM"); if (PAPI_OK != ret) { // OK: this event is only available on servers } else { @@ -844,8 +844,8 @@ int PapiLayer::initializePerfRAPL(int tid) { } char line[100]; - fgets( line,100,fp ); - if( sscanf(line,"%lf",&scalingFactor) != 1 ) { + char *tmp = fgets( line,100,fp ); + if( tmp == NULL || sscanf(line,"%lf",&scalingFactor) != 1 ) { printf("%s: /sys/devices/power/events/energy-pkg.scale doesn't contain a double", line); exit(1); } diff --git a/src/Profile/Profiler.cpp b/src/Profile/Profiler.cpp index a50679be5..bcdee123a 100644 --- a/src/Profile/Profiler.cpp +++ b/src/Profile/Profiler.cpp @@ -362,15 +362,18 @@ void Profiler::Start(int tid) ThisKtauProfiler->Start(this); #endif /* TAUKTAU */ +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_function_entry_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.function_entry) { + Tau_plugin_event_function_entry_data_t plugin_data; plugin_data.timer_name = ThisFunction->GetName(); plugin_data.timer_group = ThisFunction->GetAllGroups(); plugin_data.tid = tid; plugin_data.timestamp = TimeStamp; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_FUNCTION_ENTRY, &plugin_data); } +#endif } void Profiler::Stop(int tid, bool useLastTimeStamp) @@ -699,15 +702,18 @@ void Profiler::Stop(int tid, bool useLastTimeStamp) KtauProfiler::PutKtauProfiler(); #endif /* TAUKTAU */ +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_function_exit_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.function_exit) { + Tau_plugin_event_function_exit_data_t plugin_data; plugin_data.timer_name = ThisFunction->GetName(); plugin_data.timer_group = ThisFunction->GetAllGroups(); plugin_data.tid = tid; plugin_data.timestamp = TimeStamp; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_FUNCTION_EXIT, &plugin_data); } +#endif } ////////////////////////////////////////////////////////////////////// @@ -1469,8 +1475,8 @@ int TauProfiler_StoreData(int tid) #ifndef TAU_MPI /*Invoke plugins only if both plugin path and plugins are specified *Do this first, because the plugin can write TAU_METADATA as recommendations to the user*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_pre_end_of_execution_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.pre_end_of_execution) { + Tau_plugin_event_pre_end_of_execution_data_t plugin_data; plugin_data.tid = tid; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_PRE_END_OF_EXECUTION, &plugin_data); } @@ -1571,8 +1577,8 @@ int TauProfiler_StoreData(int tid) TAU_VERBOSE("TAU<%d,%d>: TauProfiler_StoreData 5\n", RtsLayer::myNode(), tid); /*Invoke plugins only if both plugin path and plugins are specified *Do this first, because the plugin can write TAU_METADATA as recommendations to the user*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_end_of_execution_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.end_of_execution) { + Tau_plugin_event_end_of_execution_data_t plugin_data; plugin_data.tid = tid; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_END_OF_EXECUTION, &plugin_data); } diff --git a/src/Profile/TauADIOS.cpp b/src/Profile/TauADIOS.cpp index eb8596dce..8df52c099 100644 --- a/src/Profile/TauADIOS.cpp +++ b/src/Profile/TauADIOS.cpp @@ -85,14 +85,17 @@ extern "C" int TAU_inside_ADIOS(void) { void Tau_SOS_conditionally_pack_current_timer(const char * name) { int foo = TAU_decrement_stack_height(); +#if defined(TAU_PLUGIN_TRACE_SUPPORT) +// This is protected by a macro to avoid unnecessary overhead. if (foo == 0) { /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_current_timer_exit_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.current_timer_exit) { + Tau_plugin_event_current_timer_exit_data_t plugin_data; plugin_data.name_prefix = name; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_CURRENT_TIMER_EXIT, &plugin_data); } } +#endif } #define TAU_SOS_COLLECTIVE_ADIOS_EVENT(__detail) \ @@ -802,12 +805,15 @@ ADIOST_EXTERN void tau_adiost_read_init_method( Tau_increment_stack_height(); } else { // not conditional! neither start nor stop. +#if defined(TAU_PLUGIN_TRACE_SUPPORT) +// This is protected by a macro to avoid unnecessary overhead. /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_current_timer_exit_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.current_timer_exit) { + Tau_plugin_event_current_timer_exit_data_t plugin_data; plugin_data.name_prefix = ss.str().c_str(); Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_CURRENT_TIMER_EXIT, &plugin_data); } +#endif } } @@ -825,12 +831,15 @@ ADIOST_EXTERN void tau_adiost_read_finalize_method( TAU_PROFILE_STOP(tautimer); Tau_increment_stack_height(); } else { +#if defined(TAU_PLUGIN_TRACE_SUPPORT) +// This is protected by a macro to avoid unnecessary overhead. /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_current_timer_exit_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.current_timer_exit) { + Tau_plugin_event_current_timer_exit_data_t plugin_data; plugin_data.name_prefix = ss.str().c_str(); Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_CURRENT_TIMER_EXIT, &plugin_data); } +#endif } } diff --git a/src/Profile/TauCAPI.cpp b/src/Profile/TauCAPI.cpp index e6d5efb78..ed563028e 100644 --- a/src/Profile/TauCAPI.cpp +++ b/src/Profile/TauCAPI.cpp @@ -939,8 +939,8 @@ extern "C" void Tau_exit(const char * msg) { /*Invoke plugins only if both plugin path and plugins are specified * *Do this first, because the plugin can write TAU_METADATA as recommendations to the user*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_function_finalize_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.function_finalize) { + Tau_plugin_event_function_finalize_data_t plugin_data; plugin_data.junk = -1; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_FUNCTION_FINALIZE, &plugin_data); } @@ -977,8 +977,8 @@ extern "C" void Tau_init(int argc, char **argv) { /////////////////////////////////////////////////////////////////////////// extern "C" void Tau_post_init(void) { /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_post_init_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.post_init) { + Tau_plugin_event_post_init_data_t plugin_data; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_POST_INIT, &plugin_data); } } @@ -1029,8 +1029,8 @@ extern "C" int Tau_dump(void) { TauProfiler_DumpData(); /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_dump_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.dump) { + Tau_plugin_event_dump_data_t plugin_data; plugin_data.tid = RtsLayer::myThread(); Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_DUMP, &plugin_data); } @@ -2531,8 +2531,8 @@ extern "C" void Tau_dynamic_stop(char const * name, int isPhase) Tau_stop_timer(fi, Tau_get_thread()); /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_dump_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.dump) { + Tau_plugin_event_dump_data_t plugin_data; plugin_data.tid = RtsLayer::myThread(); Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_DUMP, &plugin_data); } diff --git a/src/Profile/TauHandler.cpp b/src/Profile/TauHandler.cpp index f74a931e8..e7471dff8 100644 --- a/src/Profile/TauHandler.cpp +++ b/src/Profile/TauHandler.cpp @@ -334,8 +334,8 @@ void TauAlarmHandler(int signum) { alarm(TheTauInterruptInterval()); #endif /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_interrupt_trigger_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.interrupt_trigger) { + Tau_plugin_event_interrupt_trigger_data_t plugin_data; plugin_data.signum = signum; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_INTERRUPT_TRIGGER, &plugin_data); } diff --git a/src/Profile/TauMetaData.cpp b/src/Profile/TauMetaData.cpp index c764f62bb..0a32faa94 100644 --- a/src/Profile/TauMetaData.cpp +++ b/src/Profile/TauMetaData.cpp @@ -259,8 +259,8 @@ extern "C" void Tau_metadata_task(const char *name, const char *value, int tid) //printf("%s : %s\n", key.name, tmv->data.cval); /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_metadata_registration_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.metadata_registration) { + Tau_plugin_event_metadata_registration_data_t plugin_data; plugin_data.name = name; plugin_data.value = tmv; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_METADATA_REGISTRATION, &plugin_data); @@ -279,8 +279,8 @@ void Tau_metadata_push_to_plugins(void) { char tmp[128] = {0}; /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_metadata_registration_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.metadata_registration) { + Tau_plugin_event_metadata_registration_data_t plugin_data; plugin_data.name = it->first.name; plugin_data.value = it->second; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_METADATA_REGISTRATION, &plugin_data); @@ -835,7 +835,8 @@ extern "C" int writeMetaDataAfterMPI_Init(void) { FILE *cfile; cfile = fopen("/proc/cray_xt/cname", "r"); if (cfile != NULL) { - fscanf(cfile, "%s", cname); + int scanned = fscanf(cfile, "%s", cname); + if (scanned == EOF) { perror("Error scanning /proc/cray_xt/cname !\n"); return 0; } fclose(cfile); Tau_metadata_register("CRAY_NODENAME", cname); diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index e5c70d198..988a64e1a 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -74,12 +74,15 @@ int TAU_inside_ADIOS(void); inline void Tau_plugin_trace_current_timer(const char * name) { +#if defined(TAU_PLUGIN_TRACE_SUPPORT) +// This is protected by a macro to avoid unnecessary overhead. /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled() && TAU_inside_ADIOS() == 0) { - Tau_plugin_event_current_timer_exit_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { + Tau_plugin_event_current_timer_exit_data_t plugin_data; plugin_data.name_prefix = name; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_CURRENT_TIMER_EXIT, &plugin_data); } +#endif } #define EVENT_TRACE_PREFIX "TAU_EVENT::MPI" @@ -529,9 +532,12 @@ char *note; otherid = status->MPI_SOURCE; /* if (rq->tag == MPI_ANY_TAG) */ othertag = status->MPI_TAG; +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. /* post the receive message */ TAU_TRACE_RECVMSG(othertag, TauTranslateRankToWorld(rq->comm, otherid), rq->size); TAU_PLUGIN_RECVMSG(othertag, TauTranslateRankToWorld(rq->comm, otherid), rq->size, 0); +#endif TAU_WAIT_DATA(rq->size); } @@ -578,9 +584,12 @@ char *note; { otherid = TauTranslateRankToWorld(rq->comm, rq->otherParty); othertag = rq->tag; +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. /* post the send message */ TAU_TRACE_SENDMSG(othertag, otherid, rq->size); TAU_PLUGIN_SENDMSG(othertag, otherid, rq->size, 0); +#endif } return; @@ -1910,8 +1919,8 @@ int MPI_Finalize( ) /*Invoke plugins only if both plugin path and plugins are specified *Do this first, because the plugin can write TAU_METADATA as recommendations to the user*/ - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_pre_end_of_execution_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.pre_end_of_execution) { + Tau_plugin_event_pre_end_of_execution_data_t plugin_data; plugin_data.tid = Tau_get_local_tid(); Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_PRE_END_OF_EXECUTION, &plugin_data); } @@ -2248,12 +2257,15 @@ MPI_Comm comm; TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize ); +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count, 0); +#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Bsend( buf, count, datatype, dest, tag, comm ); @@ -2408,9 +2420,12 @@ MPI_Request * request; /* we need to store the request and associate it with the size/tag so MPI_Start can retrieve it and log the TAU_TRACE_SENDMSG */ +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { TauAddRequestData(RQ_SEND, count, datatype, dest, tag, comm, request, returnVal, 1); } +#endif TAU_PROFILE_STOP(tautimer); @@ -2467,12 +2482,15 @@ MPI_Request * request; TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize ); +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize, 0); +#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Ibsend( buf, count, datatype, dest, tag, comm, request ); @@ -2554,12 +2572,15 @@ MPI_Request * request; TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize3 ); +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize3); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize3, 0); +#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Irsend( buf, count, datatype, dest, tag, comm, request ); @@ -2586,12 +2607,15 @@ MPI_Request * request; TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize3 ); +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize3); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize3, 0); +#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Isend( buf, count, datatype, dest, tag, comm, request ); @@ -2615,12 +2639,15 @@ MPI_Request * request; TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize3 ); +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize3); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize3, 0); +#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Issend( buf, count, datatype, dest, tag, comm, request ); @@ -2716,17 +2743,23 @@ MPI_Status * status; if (source != MPI_PROC_NULL && returnVal == MPI_SUCCESS) { /* note that status->MPI_COMM must == comm */ +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { PMPI_Get_count( status, MPI_BYTE, &size ); TAU_TRACE_RECVMSG(status->MPI_TAG, TauTranslateRankToWorld(comm, status->MPI_SOURCE), size); } +#endif int typesize = 0; PMPI_Type_size( datatype, &typesize ); +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (status == NULL) { TAU_PLUGIN_RECVMSG(tag, TauTranslateRankToWorld(comm, source), count*typesize, 0); } else { TAU_PLUGIN_RECVMSG(status->MPI_TAG, TauTranslateRankToWorld(comm, status->MPI_SOURCE), count*typesize, 0); } +#endif } TAU_PROFILE_STOP(tautimer); @@ -2748,12 +2781,15 @@ MPI_Comm comm; TAU_PROFILE_TIMER(tautimer, "MPI_Rsend()", " ", TAU_MESSAGE); TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize ); +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count, 0); +#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Rsend( buf, count, datatype, dest, tag, comm ); @@ -2804,12 +2840,15 @@ MPI_Comm comm; TAU_PROFILE_TIMER(tautimer, "MPI_Send()", " ", TAU_MESSAGE); TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize ); +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count, 0); +#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Send( buf, count, datatype, dest, tag, comm ); @@ -2840,32 +2879,42 @@ MPI_Status * status; TAU_PROFILE_TIMER(tautimer, "MPI_Sendrecv()", " ", TAU_MESSAGE); TAU_PROFILE_START(tautimer); PMPI_Type_size( sendtype, &typesize1 ); - if (TauEnv_get_track_message()) { - if (dest != MPI_PROC_NULL) { - TAU_TRACE_SENDMSG(sendtag, TauTranslateRankToWorld(comm, dest), typesize1*sendcount); - } if (status == MPI_STATUS_IGNORE) { status = &local_status; } + +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. + if (TauEnv_get_track_message()) { + if (dest != MPI_PROC_NULL) { + TAU_TRACE_SENDMSG(sendtag, TauTranslateRankToWorld(comm, dest), typesize1*sendcount); + } } TAU_PLUGIN_SENDMSG(sendtag, TauTranslateRankToWorld(comm, dest), typesize1*sendcount, 0); +#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Sendrecv( sendbuf, sendcount, sendtype, dest, sendtag, recvbuf, recvcount, recvtype, source, recvtag, comm, status ); if (source != MPI_PROC_NULL && returnVal == MPI_SUCCESS) { +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { PMPI_Get_count( status, MPI_BYTE, &count ); TAU_TRACE_RECVMSG(status->MPI_TAG, TauTranslateRankToWorld(comm, status->MPI_SOURCE), count); } +#endif int typesize = 0; PMPI_Type_size( recvtype, &typesize ); +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (status == NULL) { TAU_PLUGIN_RECVMSG(recvtag, TauTranslateRankToWorld(comm, source), count*typesize, 0); } else { TAU_PLUGIN_RECVMSG(status->MPI_TAG, TauTranslateRankToWorld(comm, status->MPI_SOURCE), count*typesize, 0); } +#endif } TAU_PROFILE_STOP(tautimer); @@ -2892,32 +2941,41 @@ MPI_Status * status; TAU_PROFILE_TIMER(tautimer, "MPI_Sendrecv_replace()", " ", TAU_MESSAGE); TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize2 ); - if (TauEnv_get_track_message()) { - if (dest != MPI_PROC_NULL) { - TAU_TRACE_SENDMSG(sendtag, TauTranslateRankToWorld(comm, dest), typesize2*count); - } if (status == MPI_STATUS_IGNORE) { status = &local_status; } +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. + if (TauEnv_get_track_message()) { + if (dest != MPI_PROC_NULL) { + TAU_TRACE_SENDMSG(sendtag, TauTranslateRankToWorld(comm, dest), typesize2*count); + } } TAU_PLUGIN_SENDMSG(sendtag, TauTranslateRankToWorld(comm, dest), typesize2*count, 0); +#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Sendrecv_replace( buf, count, datatype, dest, sendtag, source, recvtag, comm, status ); if (dest != MPI_PROC_NULL && returnVal == MPI_SUCCESS) { +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { PMPI_Get_count( status, MPI_BYTE, &size1 ); TAU_TRACE_RECVMSG(status->MPI_TAG, TauTranslateRankToWorld(comm, status->MPI_SOURCE), size1); } +#endif int typesize = 0; PMPI_Type_size( datatype, &typesize ); +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (status == NULL) { TAU_PLUGIN_RECVMSG(recvtag, TauTranslateRankToWorld(comm, source), count*typesize, 0); } else { TAU_PLUGIN_RECVMSG(status->MPI_TAG, TauTranslateRankToWorld(comm, status->MPI_SOURCE), count*typesize, 0); } +#endif } TAU_PROFILE_STOP(tautimer); @@ -2938,12 +2996,15 @@ MPI_Comm comm; TAU_PROFILE_TIMER(tautimer, "MPI_Ssend()", " ", TAU_MESSAGE); TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize ); +#if defined(TAU_PLUGIN_TRACE_SUPPORT) + // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count, 0); +#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Ssend( buf, count, datatype, dest, tag, comm ); diff --git a/src/Profile/TauUtil.cpp b/src/Profile/TauUtil.cpp index 9e1182a17..7aa012293 100644 --- a/src/Profile/TauUtil.cpp +++ b/src/Profile/TauUtil.cpp @@ -31,6 +31,8 @@ #define strtok_r(a,b,c) strtok(a,b) #endif /* TAU_WINDOWS */ +Tau_plugin_callbacks_active_t Tau_plugin_enabled; + #define TAU_NAME_LENGTH 1024 /********************************************************************* @@ -197,6 +199,7 @@ PluginManager* Tau_util_get_plugin_manager() { plugin_manager->callback_list = (Tau_plugin_callback_list*)malloc(sizeof(Tau_plugin_callback_list)); (plugin_manager->callback_list)->head = NULL; + memset(&Tau_plugin_enabled, 0, sizeof(Tau_plugin_callbacks_active_t)); is_plugin_system_initialized = 1; } @@ -438,20 +441,37 @@ void Tau_util_make_callback_copy(Tau_plugin_callbacks * dest, Tau_plugin_callbac extern "C" void Tau_util_plugin_register_callbacks(Tau_plugin_callbacks * cb) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); - Tau_plugin_callback_ * callback = (Tau_plugin_callback_ *)malloc(sizeof(Tau_plugin_callback_)); + Tau_plugin_callback_t * callback = (Tau_plugin_callback_t *)malloc(sizeof(Tau_plugin_callback_t)); Tau_util_make_callback_copy(&(callback->cb), cb); callback->next = (plugin_manager->callback_list)->head; (plugin_manager->callback_list)->head = callback; + + /* Set some flags to make runtime conditional processing more efficient */ + if (cb->FunctionRegistrationComplete != 0) { Tau_plugin_enabled.function_registration = 1; } + if (cb->MetadataRegistrationComplete != 0) { Tau_plugin_enabled.metadata_registration = 1; } + if (cb->PostInit != 0) { Tau_plugin_enabled.post_init = 1; } + if (cb->Dump != 0) { Tau_plugin_enabled.dump = 1; } + if (cb->FunctionEntry != 0) { Tau_plugin_enabled.function_entry = 1; } + if (cb->FunctionExit != 0) { Tau_plugin_enabled.function_exit = 1; } + if (cb->Send != 0) { Tau_plugin_enabled.send = 1; } + if (cb->Recv != 0) { Tau_plugin_enabled.recv = 1; } + if (cb->CurrentTimerExit != 0) { Tau_plugin_enabled.current_timer_exit = 1; } + if (cb->AtomicEventRegistrationComplete != 0) { Tau_plugin_enabled.atomic_event_registration = 1; } + if (cb->AtomicEventTrigger != 0) { Tau_plugin_enabled.atomic_event_trigger = 1; } + if (cb->PreEndOfExecution != 0) { Tau_plugin_enabled.pre_end_of_execution = 1; } + if (cb->EndOfExecution != 0) { Tau_plugin_enabled.end_of_execution = 1; } + if (cb->FunctionFinalize != 0) { Tau_plugin_enabled.function_finalize = 1; } + if (cb->InterruptTrigger != 0) { Tau_plugin_enabled.interrupt_trigger = 1; } } /************************************************************************************************************************** * Overloaded function that invokes all registered callbacks for the function registration event ***************************************************************************************************************************/ -void Tau_util_invoke_callbacks_(Tau_plugin_event_function_registration_data data) { +void Tau_util_invoke_callbacks_(Tau_plugin_event_function_registration_data_t* data) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin_callback_list * callback_list = plugin_manager->callback_list; - Tau_plugin_callback_ * callback = callback_list->head; + Tau_plugin_callback_t * callback = callback_list->head; while(callback != NULL) { if(callback->cb.FunctionRegistrationComplete != 0) { @@ -464,10 +484,10 @@ void Tau_util_invoke_callbacks_(Tau_plugin_event_function_registration_data data /************************************************************************************************************************** * Overloaded function that invokes all registered callbacks for the dump event ***************************************************************************************************************************/ -void Tau_util_invoke_callbacks_(Tau_plugin_event_dump_data data) { +void Tau_util_invoke_callbacks_(Tau_plugin_event_dump_data_t* data) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin_callback_list * callback_list = plugin_manager->callback_list; - Tau_plugin_callback_ * callback = callback_list->head; + Tau_plugin_callback_t * callback = callback_list->head; while(callback != NULL) { if(callback->cb.Dump != 0) { @@ -480,10 +500,10 @@ void Tau_util_invoke_callbacks_(Tau_plugin_event_dump_data data) { /************************************************************************************************************************** * Overloaded function that invokes all registered callbacks for the function entry event ***************************************************************************************************************************/ -void Tau_util_invoke_callbacks_(Tau_plugin_event_function_entry_data data) { +void Tau_util_invoke_callbacks_(Tau_plugin_event_function_entry_data_t* data) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin_callback_list * callback_list = plugin_manager->callback_list; - Tau_plugin_callback_ * callback = callback_list->head; + Tau_plugin_callback_t * callback = callback_list->head; while(callback != NULL) { if(callback->cb.FunctionEntry != 0) { @@ -496,10 +516,10 @@ void Tau_util_invoke_callbacks_(Tau_plugin_event_function_entry_data data) { /************************************************************************************************************************** * Overloaded function that invokes all registered callbacks for the function exit event ***************************************************************************************************************************/ -void Tau_util_invoke_callbacks_(Tau_plugin_event_function_exit_data data) { +void Tau_util_invoke_callbacks_(Tau_plugin_event_function_exit_data_t* data) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin_callback_list * callback_list = plugin_manager->callback_list; - Tau_plugin_callback_ * callback = callback_list->head; + Tau_plugin_callback_t * callback = callback_list->head; while(callback != NULL) { if(callback->cb.FunctionExit != 0) { @@ -512,10 +532,10 @@ void Tau_util_invoke_callbacks_(Tau_plugin_event_function_exit_data data) { /************************************************************************************************************************** * Overloaded function that invokes all registered callbacks for the "current timer" exit event ***************************************************************************************************************************/ -void Tau_util_invoke_callbacks_(Tau_plugin_event_current_timer_exit_data data) { +void Tau_util_invoke_callbacks_(Tau_plugin_event_current_timer_exit_data_t* data) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin_callback_list * callback_list = plugin_manager->callback_list; - Tau_plugin_callback_ * callback = callback_list->head; + Tau_plugin_callback_t * callback = callback_list->head; while(callback != NULL) { if(callback->cb.CurrentTimerExit != 0) { @@ -528,10 +548,10 @@ void Tau_util_invoke_callbacks_(Tau_plugin_event_current_timer_exit_data data) { /************************************************************************************************************************** * Overloaded function that invokes all registered callbacks for the send event ***************************************************************************************************************************/ -void Tau_util_invoke_callbacks_(Tau_plugin_event_send_data data) { +void Tau_util_invoke_callbacks_(Tau_plugin_event_send_data_t* data) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin_callback_list * callback_list = plugin_manager->callback_list; - Tau_plugin_callback_ * callback = callback_list->head; + Tau_plugin_callback_t * callback = callback_list->head; while(callback != NULL) { if(callback->cb.Send != 0) { @@ -544,10 +564,10 @@ void Tau_util_invoke_callbacks_(Tau_plugin_event_send_data data) { /************************************************************************************************************************** * Overloaded function that invokes all registered callbacks for the recv event ***************************************************************************************************************************/ -void Tau_util_invoke_callbacks_(Tau_plugin_event_recv_data data) { +void Tau_util_invoke_callbacks_(Tau_plugin_event_recv_data_t* data) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin_callback_list * callback_list = plugin_manager->callback_list; - Tau_plugin_callback_ * callback = callback_list->head; + Tau_plugin_callback_t * callback = callback_list->head; while(callback != NULL) { if(callback->cb.Recv != 0) { @@ -560,10 +580,10 @@ void Tau_util_invoke_callbacks_(Tau_plugin_event_recv_data data) { /************************************************************************************************************************** * Overloaded function that invokes all registered callbacks for the metadata registration event ***************************************************************************************************************************/ -void Tau_util_invoke_callbacks_(Tau_plugin_event_metadata_registration_data data) { +void Tau_util_invoke_callbacks_(Tau_plugin_event_metadata_registration_data_t* data) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin_callback_list * callback_list = plugin_manager->callback_list; - Tau_plugin_callback_ * callback = callback_list->head; + Tau_plugin_callback_t * callback = callback_list->head; while(callback != NULL) { if(callback->cb.MetadataRegistrationComplete != 0) { @@ -576,10 +596,10 @@ void Tau_util_invoke_callbacks_(Tau_plugin_event_metadata_registration_data data /************************************************************************************************************************** * Overloaded function that invokes all registered callbacks for the post init event ***************************************************************************************************************************/ -void Tau_util_invoke_callbacks_(Tau_plugin_event_post_init_data data) { +void Tau_util_invoke_callbacks_(Tau_plugin_event_post_init_data_t* data) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin_callback_list * callback_list = plugin_manager->callback_list; - Tau_plugin_callback_ * callback = callback_list->head; + Tau_plugin_callback_t * callback = callback_list->head; while(callback != NULL) { if(callback->cb.PostInit != 0) { @@ -592,10 +612,10 @@ void Tau_util_invoke_callbacks_(Tau_plugin_event_post_init_data data) { /************************************************************************************************************************** * Overloaded function that invokes all registered callbacks for the atomic event registration event ****************************************************************************************************************************/ -void Tau_util_invoke_callbacks_(Tau_plugin_event_atomic_event_registration_data data) { +void Tau_util_invoke_callbacks_(Tau_plugin_event_atomic_event_registration_data_t* data) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin_callback_list * callback_list = plugin_manager->callback_list; - Tau_plugin_callback_ * callback = callback_list->head; + Tau_plugin_callback_t * callback = callback_list->head; while(callback != NULL) { if(callback->cb.AtomicEventRegistrationComplete != 0) { @@ -608,10 +628,10 @@ void Tau_util_invoke_callbacks_(Tau_plugin_event_atomic_event_registration_data /************************************************************************************************************************** * Overloaded function that invokes all registered callbacks for the atomic event trigger event *****************************************************************************************************************************/ -void Tau_util_invoke_callbacks_(Tau_plugin_event_atomic_event_trigger_data data) { +void Tau_util_invoke_callbacks_(Tau_plugin_event_atomic_event_trigger_data_t* data) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin_callback_list * callback_list = plugin_manager->callback_list; - Tau_plugin_callback_ * callback = callback_list->head; + Tau_plugin_callback_t * callback = callback_list->head; while(callback != NULL) { if(callback->cb.AtomicEventTrigger != 0) { @@ -624,10 +644,10 @@ void Tau_util_invoke_callbacks_(Tau_plugin_event_atomic_event_trigger_data data) /************************************************************************************************************************** * Overloaded function that invokes all registered callbacks for the pre end of execution event ******************************************************************************************************************************/ -void Tau_util_invoke_callbacks_(Tau_plugin_event_pre_end_of_execution_data data) { +void Tau_util_invoke_callbacks_(Tau_plugin_event_pre_end_of_execution_data_t* data) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin_callback_list * callback_list = plugin_manager->callback_list; - Tau_plugin_callback_ * callback = callback_list->head; + Tau_plugin_callback_t * callback = callback_list->head; while(callback != NULL) { if(callback->cb.PreEndOfExecution != 0) { @@ -640,10 +660,10 @@ void Tau_util_invoke_callbacks_(Tau_plugin_event_pre_end_of_execution_data data) /************************************************************************************************************************** * Overloaded function that invokes all registered callbacks for the end of execution event ******************************************************************************************************************************/ -void Tau_util_invoke_callbacks_(Tau_plugin_event_end_of_execution_data data) { +void Tau_util_invoke_callbacks_(Tau_plugin_event_end_of_execution_data_t* data) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin_callback_list * callback_list = plugin_manager->callback_list; - Tau_plugin_callback_ * callback = callback_list->head; + Tau_plugin_callback_t * callback = callback_list->head; while(callback != NULL) { if(callback->cb.EndOfExecution != 0) { @@ -656,10 +676,10 @@ void Tau_util_invoke_callbacks_(Tau_plugin_event_end_of_execution_data data) { /************************************************************************************************************************** * Overloaded function that invokes all registered callbacks for interrupt trigger event *******************************************************************************************************************************/ -void Tau_util_invoke_callbacks_(Tau_plugin_event_interrupt_trigger_data data) { +void Tau_util_invoke_callbacks_(Tau_plugin_event_interrupt_trigger_data_t* data) { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin_callback_list * callback_list = plugin_manager->callback_list; - Tau_plugin_callback_ * callback = callback_list->head; + Tau_plugin_callback_t * callback = callback_list->head; while(callback != NULL) { if(callback->cb.InterruptTrigger != 0) { @@ -676,60 +696,59 @@ extern "C" void Tau_util_invoke_callbacks(Tau_plugin_event event, const void * d switch(event) { case TAU_PLUGIN_EVENT_FUNCTION_REGISTRATION: { - Tau_util_invoke_callbacks_(*(Tau_plugin_event_function_registration_data*)data); + Tau_util_invoke_callbacks_((Tau_plugin_event_function_registration_data_t*)data); break; } case TAU_PLUGIN_EVENT_METADATA_REGISTRATION: { - Tau_util_invoke_callbacks_(*(Tau_plugin_event_metadata_registration_data*)data); + Tau_util_invoke_callbacks_((Tau_plugin_event_metadata_registration_data_t*)data); break; } case TAU_PLUGIN_EVENT_POST_INIT: { - Tau_util_invoke_callbacks_(*(Tau_plugin_event_post_init_data*)data); + Tau_util_invoke_callbacks_((Tau_plugin_event_post_init_data_t*)data); break; } case TAU_PLUGIN_EVENT_DUMP: { - Tau_util_invoke_callbacks_(*(Tau_plugin_event_dump_data*)data); + Tau_util_invoke_callbacks_((Tau_plugin_event_dump_data_t*)data); break; } case TAU_PLUGIN_EVENT_FUNCTION_ENTRY: { - Tau_util_invoke_callbacks_(*(Tau_plugin_event_function_entry_data*)data); + Tau_util_invoke_callbacks_((Tau_plugin_event_function_entry_data_t*)data); break; } case TAU_PLUGIN_EVENT_FUNCTION_EXIT: { - Tau_util_invoke_callbacks_(*(Tau_plugin_event_function_exit_data*)data); + Tau_util_invoke_callbacks_((Tau_plugin_event_function_exit_data_t*)data); break; } case TAU_PLUGIN_EVENT_CURRENT_TIMER_EXIT: { - Tau_util_invoke_callbacks_(*(Tau_plugin_event_current_timer_exit_data*)data); + Tau_util_invoke_callbacks_((Tau_plugin_event_current_timer_exit_data_t*)data); break; } case TAU_PLUGIN_EVENT_SEND: { - Tau_util_invoke_callbacks_(*(Tau_plugin_event_send_data*)data); + Tau_util_invoke_callbacks_((Tau_plugin_event_send_data_t*)data); break; } case TAU_PLUGIN_EVENT_RECV: { - Tau_util_invoke_callbacks_(*(Tau_plugin_event_recv_data*)data); + Tau_util_invoke_callbacks_((Tau_plugin_event_recv_data_t*)data); break; } case TAU_PLUGIN_EVENT_ATOMIC_EVENT_REGISTRATION: { - Tau_util_invoke_callbacks_(*(Tau_plugin_event_atomic_event_registration_data*)data); + Tau_util_invoke_callbacks_((Tau_plugin_event_atomic_event_registration_data_t*)data); break; } - case TAU_PLUGIN_EVENT_ATOMIC_EVENT_TRIGGER: { - Tau_util_invoke_callbacks_(*(Tau_plugin_event_atomic_event_trigger_data*)data); + Tau_util_invoke_callbacks_((Tau_plugin_event_atomic_event_trigger_data_t*)data); break; } case TAU_PLUGIN_EVENT_PRE_END_OF_EXECUTION: { - Tau_util_invoke_callbacks_(*(Tau_plugin_event_pre_end_of_execution_data*)data); + Tau_util_invoke_callbacks_((Tau_plugin_event_pre_end_of_execution_data_t*)data); break; } case TAU_PLUGIN_EVENT_END_OF_EXECUTION: { - Tau_util_invoke_callbacks_(*(Tau_plugin_event_end_of_execution_data*)data); + Tau_util_invoke_callbacks_((Tau_plugin_event_end_of_execution_data_t*)data); break; } case TAU_PLUGIN_EVENT_INTERRUPT_TRIGGER: { - Tau_util_invoke_callbacks_(*(Tau_plugin_event_interrupt_trigger_data*)data); + Tau_util_invoke_callbacks_((Tau_plugin_event_interrupt_trigger_data_t*)data); break; } } @@ -743,10 +762,10 @@ int Tau_util_cleanup_all_plugins() { PluginManager* plugin_manager = Tau_util_get_plugin_manager(); Tau_plugin * temp_plugin; - Tau_plugin_callback_ * temp_callback; + Tau_plugin_callback_t * temp_callback; Tau_plugin * plugin = (plugin_manager->plugin_list)->head; - Tau_plugin_callback_ * callback = (plugin_manager->callback_list)->head; + Tau_plugin_callback_t * callback = (plugin_manager->callback_list)->head; /*Two separate while loops to handle the weird case that a plugin is loaded but doesn't register anything*/ while(plugin) { diff --git a/src/Profile/UserEvent.cpp b/src/Profile/UserEvent.cpp index 1a1485d31..06c27f0f8 100644 --- a/src/Profile/UserEvent.cpp +++ b/src/Profile/UserEvent.cpp @@ -125,8 +125,8 @@ void TauUserEvent::AddEventToDB() DEBUGPROFMSG("Size of eventDB is " << TheEventDB().size() <") == std::string::npos)) { - if(TauEnv_get_plugins_enabled()) { - Tau_plugin_event_atomic_event_trigger_data plugin_data; + if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.atomic_event_trigger) { + Tau_plugin_event_atomic_event_trigger_data_t plugin_data; plugin_data.counter_name = name.c_str(); plugin_data.tid = tid; plugin_data.timestamp = timestamp; @@ -309,6 +311,7 @@ void TauUserEvent::TriggerEvent(TAU_EVENT_DATATYPE data, int tid, double timesta Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_ATOMIC_EVENT_TRIGGER, &plugin_data); } } +#endif } // Tau_global_getLightsOut } From bd3481325ca334755d10d737d29d06679f2e29a4 Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Mon, 30 Jul 2018 21:12:16 -0700 Subject: [PATCH 45/60] More refactoring of plugin integrtion points. Reduced overhead by simplifying checks and moving all code under the check. Former-commit-id: 396eeac421e6641870b5fa6fd65c2fefbca10237 --- plugins/examples/TauSOS.cpp | 12 -- plugins/examples/Tau_plugin_sos.cpp | 42 +++++-- src/Profile/FunctionInfo.cpp | 2 +- src/Profile/Profiler.cpp | 10 +- src/Profile/TauADIOS.cpp | 18 +-- src/Profile/TauCAPI.cpp | 8 +- src/Profile/TauHandler.cpp | 2 +- src/Profile/TauInit.cpp | 11 +- src/Profile/TauMetaData.cpp | 4 +- src/Profile/TauMpi.c | 171 +++++++++++----------------- src/Profile/TauUtil.cpp | 49 ++++---- src/Profile/UserEvent.cpp | 7 +- 12 files changed, 145 insertions(+), 191 deletions(-) diff --git a/plugins/examples/TauSOS.cpp b/plugins/examples/TauSOS.cpp index 6b9692e30..1e9ee1cc5 100644 --- a/plugins/examples/TauSOS.cpp +++ b/plugins/examples/TauSOS.cpp @@ -337,19 +337,7 @@ void TAU_SOS_parse_environment_variables(void) { } tmp = getenv("TAU_SOS_TRACING"); if (parse_bool(tmp, TAU_SOS_TRACING_DEFAULT)) { -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. thePluginOptions().env_sos_tracing = 1; -#else - fprintf(stderr, "ERROR! TAU was configured without plugin trace support!\n"); - fprintf(stderr, "Please reconfigure TAU with:\n"); - fprintf(stderr, "'-useropt=-DTAU_PLUGIN_TRACE_SUPPORT#-O2#-g', recompile, and reinstall.\n"); -#ifdef TAU_MPI - MPI_Abort(MPI_COMM_WORLD, 999); -#else - abort(); -#endif -#endif } tmp = getenv("TAU_SOS_CACHE_DEPTH"); thePluginOptions().env_sos_cache_depth = parse_int(tmp, TAU_SOS_CACHE_DEPTH_DEFAULT); diff --git a/plugins/examples/Tau_plugin_sos.cpp b/plugins/examples/Tau_plugin_sos.cpp index 9813ce91f..ba6a24bfd 100644 --- a/plugins/examples/Tau_plugin_sos.cpp +++ b/plugins/examples/Tau_plugin_sos.cpp @@ -18,6 +18,9 @@ #include #include #include +#if TAU_MPI +#include "mpi.h" +#endif extern tau::Profiler* Tau_get_timer_at_stack_depth(int pos); @@ -176,8 +179,6 @@ int Tau_plugin_metadata_registration_complete_func(Tau_plugin_event_metadata_reg /* This happens from Profiler.cpp, when data is written out. */ int Tau_plugin_sos_end_of_execution(Tau_plugin_event_end_of_execution_data_t* data) { if (!enabled || data->tid != 0) return 0; -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. /* If we are tracing, we need to "stop" all of the remaining timers on the stack */ if (thePluginOptions().env_sos_tracing) { Tau_plugin_event_function_exit_data_t exit_data; @@ -205,7 +206,6 @@ int Tau_plugin_sos_end_of_execution(Tau_plugin_event_end_of_execution_data_t* da } RtsLayer::UnLockDB(); } -#endif enabled = false; //fprintf(stdout, "TAU PLUGIN SOS Finalize\n"); fflush(stdout); TAU_SOS_finalize(); @@ -236,19 +236,46 @@ extern "C" int Tau_plugin_init_func(int argc, char **argv) { cb->PostInit = Tau_plugin_sos_post_init; cb->PreEndOfExecution = Tau_plugin_sos_pre_end_of_execution; cb->EndOfExecution = Tau_plugin_sos_end_of_execution; -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. /* Event tracing support */ if (thePluginOptions().env_sos_tracing) { +#if !defined(TAU_PLUGIN_TRACE_SUPPORT) +#if TAU_MPI + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) { + std::cerr << "Error! Plugin trace support was not configured.\n"; + std::cerr << "Please reconfigure TAU with '-useropt=-DTAU_PLUGIN_TRACE_SUPPORT'.\n" << std::endl; + } + MPI_Abort(MPI_COMM_WORLD, 999); +#else + std::cerr << "Error! Plugin trace support was not configured.\n"; + std::cerr << "Please reconfigure TAU with '-useropt=-DTAU_PLUGIN_TRACE_SUPPORT'.\n" << std::endl; + abort(); +#endif +#endif cb->Send = Tau_plugin_sos_send; cb->Recv = Tau_plugin_sos_recv; cb->FunctionEntry = Tau_plugin_sos_function_entry; cb->FunctionExit = Tau_plugin_sos_function_exit; cb->AtomicEventTrigger = Tau_plugin_sos_atomic_trigger; } -#endif /* Specialized support for ADIOS, MPI events (ADIOS Skel/Pooky support) */ if (thePluginOptions().env_sos_trace_adios) { +#if !defined(TAU_PLUGIN_TRACE_SUPPORT) +#if TAU_MPI + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) { + std::cerr << "Error! Plugin trace support was not configured.\n"; + std::cerr << "Please reconfigure TAU with '-useropt=-DTAU_PLUGIN_TRACE_SUPPORT'.\n" << std::endl; + } + MPI_Abort(MPI_COMM_WORLD, 999); +#else + std::cerr << "Error! Plugin trace support was not configured.\n"; + std::cerr << "Please reconfigure TAU with '-useropt=-DTAU_PLUGIN_TRACE_SUPPORT'.\n" << std::endl; + abort(); +#endif +#endif cb->CurrentTimerExit = Tau_plugin_sos_current_timer_exit; } /* Not sure what this thing does */ @@ -258,8 +285,6 @@ extern "C" int Tau_plugin_init_func(int argc, char **argv) { TAU_UTIL_PLUGIN_REGISTER_CALLBACKS(cb); enabled = true; -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. /* If we are tracing, we need to "start" all of the timers on the stack */ if (thePluginOptions().env_sos_tracing) { RtsLayer::LockDB(); @@ -280,7 +305,6 @@ extern "C" int Tau_plugin_init_func(int argc, char **argv) { } RtsLayer::UnLockDB(); } -#endif return 0; } diff --git a/src/Profile/FunctionInfo.cpp b/src/Profile/FunctionInfo.cpp index 7260002c4..8c630b83b 100644 --- a/src/Profile/FunctionInfo.cpp +++ b/src/Profile/FunctionInfo.cpp @@ -306,7 +306,7 @@ void FunctionInfo::FunctionInfoInit(TauGroup_t ProfileGroup, const char *Profile #endif //RENCI_STFF /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.function_registration) { + if(Tau_plugins_enabled.function_registration) { Tau_plugin_event_function_registration_data_t plugin_data; plugin_data.function_info_ptr = this; plugin_data.tid = tid; diff --git a/src/Profile/Profiler.cpp b/src/Profile/Profiler.cpp index bcdee123a..56a22468a 100644 --- a/src/Profile/Profiler.cpp +++ b/src/Profile/Profiler.cpp @@ -363,9 +363,8 @@ void Profiler::Start(int tid) #endif /* TAUKTAU */ #if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.function_entry) { + if(Tau_plugins_enabled.function_entry) { Tau_plugin_event_function_entry_data_t plugin_data; plugin_data.timer_name = ThisFunction->GetName(); plugin_data.timer_group = ThisFunction->GetAllGroups(); @@ -703,9 +702,8 @@ void Profiler::Stop(int tid, bool useLastTimeStamp) #endif /* TAUKTAU */ #if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.function_exit) { + if(Tau_plugins_enabled.function_exit) { Tau_plugin_event_function_exit_data_t plugin_data; plugin_data.timer_name = ThisFunction->GetName(); plugin_data.timer_group = ThisFunction->GetAllGroups(); @@ -1475,7 +1473,7 @@ int TauProfiler_StoreData(int tid) #ifndef TAU_MPI /*Invoke plugins only if both plugin path and plugins are specified *Do this first, because the plugin can write TAU_METADATA as recommendations to the user*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.pre_end_of_execution) { + if(Tau_plugins_enabled.pre_end_of_execution) { Tau_plugin_event_pre_end_of_execution_data_t plugin_data; plugin_data.tid = tid; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_PRE_END_OF_EXECUTION, &plugin_data); @@ -1577,7 +1575,7 @@ int TauProfiler_StoreData(int tid) TAU_VERBOSE("TAU<%d,%d>: TauProfiler_StoreData 5\n", RtsLayer::myNode(), tid); /*Invoke plugins only if both plugin path and plugins are specified *Do this first, because the plugin can write TAU_METADATA as recommendations to the user*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.end_of_execution) { + if(Tau_plugins_enabled.end_of_execution) { Tau_plugin_event_end_of_execution_data_t plugin_data; plugin_data.tid = tid; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_END_OF_EXECUTION, &plugin_data); diff --git a/src/Profile/TauADIOS.cpp b/src/Profile/TauADIOS.cpp index 8df52c099..fd4f1a67d 100644 --- a/src/Profile/TauADIOS.cpp +++ b/src/Profile/TauADIOS.cpp @@ -84,18 +84,14 @@ extern "C" int TAU_inside_ADIOS(void) { output a trace event if we aren't currently timing another ADIOS call. */ void Tau_SOS_conditionally_pack_current_timer(const char * name) { - int foo = TAU_decrement_stack_height(); -#if defined(TAU_PLUGIN_TRACE_SUPPORT) -// This is protected by a macro to avoid unnecessary overhead. - if (foo == 0) { + if (TAU_decrement_stack_height() == 0) { /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.current_timer_exit) { + if(Tau_plugins_enabled.current_timer_exit) { Tau_plugin_event_current_timer_exit_data_t plugin_data; plugin_data.name_prefix = name; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_CURRENT_TIMER_EXIT, &plugin_data); } } -#endif } #define TAU_SOS_COLLECTIVE_ADIOS_EVENT(__detail) \ @@ -805,15 +801,12 @@ ADIOST_EXTERN void tau_adiost_read_init_method( Tau_increment_stack_height(); } else { // not conditional! neither start nor stop. -#if defined(TAU_PLUGIN_TRACE_SUPPORT) -// This is protected by a macro to avoid unnecessary overhead. /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.current_timer_exit) { + if(Tau_plugins_enabled.current_timer_exit) { Tau_plugin_event_current_timer_exit_data_t plugin_data; plugin_data.name_prefix = ss.str().c_str(); Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_CURRENT_TIMER_EXIT, &plugin_data); } -#endif } } @@ -831,15 +824,12 @@ ADIOST_EXTERN void tau_adiost_read_finalize_method( TAU_PROFILE_STOP(tautimer); Tau_increment_stack_height(); } else { -#if defined(TAU_PLUGIN_TRACE_SUPPORT) -// This is protected by a macro to avoid unnecessary overhead. /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.current_timer_exit) { + if(Tau_plugins_enabled.current_timer_exit) { Tau_plugin_event_current_timer_exit_data_t plugin_data; plugin_data.name_prefix = ss.str().c_str(); Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_CURRENT_TIMER_EXIT, &plugin_data); } -#endif } } diff --git a/src/Profile/TauCAPI.cpp b/src/Profile/TauCAPI.cpp index ed563028e..20f2fc75f 100644 --- a/src/Profile/TauCAPI.cpp +++ b/src/Profile/TauCAPI.cpp @@ -939,7 +939,7 @@ extern "C" void Tau_exit(const char * msg) { /*Invoke plugins only if both plugin path and plugins are specified * *Do this first, because the plugin can write TAU_METADATA as recommendations to the user*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.function_finalize) { + if(Tau_plugins_enabled.function_finalize) { Tau_plugin_event_function_finalize_data_t plugin_data; plugin_data.junk = -1; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_FUNCTION_FINALIZE, &plugin_data); @@ -977,7 +977,7 @@ extern "C" void Tau_init(int argc, char **argv) { /////////////////////////////////////////////////////////////////////////// extern "C" void Tau_post_init(void) { /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.post_init) { + if(Tau_plugins_enabled.post_init) { Tau_plugin_event_post_init_data_t plugin_data; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_POST_INIT, &plugin_data); } @@ -1029,7 +1029,7 @@ extern "C" int Tau_dump(void) { TauProfiler_DumpData(); /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.dump) { + if(Tau_plugins_enabled.dump) { Tau_plugin_event_dump_data_t plugin_data; plugin_data.tid = RtsLayer::myThread(); Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_DUMP, &plugin_data); @@ -2531,7 +2531,7 @@ extern "C" void Tau_dynamic_stop(char const * name, int isPhase) Tau_stop_timer(fi, Tau_get_thread()); /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.dump) { + if(Tau_plugins_enabled.dump) { Tau_plugin_event_dump_data_t plugin_data; plugin_data.tid = RtsLayer::myThread(); Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_DUMP, &plugin_data); diff --git a/src/Profile/TauHandler.cpp b/src/Profile/TauHandler.cpp index e7471dff8..4d8fa88ce 100644 --- a/src/Profile/TauHandler.cpp +++ b/src/Profile/TauHandler.cpp @@ -334,7 +334,7 @@ void TauAlarmHandler(int signum) { alarm(TheTauInterruptInterval()); #endif /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.interrupt_trigger) { + if(Tau_plugins_enabled.interrupt_trigger) { Tau_plugin_event_interrupt_trigger_data_t plugin_data; plugin_data.signum = signum; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_INTERRUPT_TRIGGER, &plugin_data); diff --git a/src/Profile/TauInit.cpp b/src/Profile/TauInit.cpp index 3e7adb368..fc22493a5 100644 --- a/src/Profile/TauInit.cpp +++ b/src/Profile/TauInit.cpp @@ -443,15 +443,8 @@ extern "C" int Tau_init_initializeTAU() TauEnv_initialize(); #ifndef TAU_MPI - /*Initialize the plugin system only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - TAU_VERBOSE("TAU INIT: Initializing plugin system...\n"); - if(!Tau_initialize_plugin_system()) { - TAU_VERBOSE("TAU INIT: Successfully Initialized the plugin system.\n"); - } else { - printf("TAU INIT: Error initializing the plugin system\n"); - } - } + /* Initialize the plugin system */ + Tau_initialize_plugin_system(); #endif // TAU_MPI #ifdef TAU_EPILOG diff --git a/src/Profile/TauMetaData.cpp b/src/Profile/TauMetaData.cpp index 0a32faa94..cfd078f1d 100644 --- a/src/Profile/TauMetaData.cpp +++ b/src/Profile/TauMetaData.cpp @@ -259,7 +259,7 @@ extern "C" void Tau_metadata_task(const char *name, const char *value, int tid) //printf("%s : %s\n", key.name, tmv->data.cval); /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.metadata_registration) { + if(Tau_plugins_enabled.metadata_registration) { Tau_plugin_event_metadata_registration_data_t plugin_data; plugin_data.name = name; plugin_data.value = tmv; @@ -279,7 +279,7 @@ void Tau_metadata_push_to_plugins(void) { char tmp[128] = {0}; /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.metadata_registration) { + if(Tau_plugins_enabled.metadata_registration) { Tau_plugin_event_metadata_registration_data_t plugin_data; plugin_data.name = it->first.name; plugin_data.value = it->second; diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index 988a64e1a..20f0b96b7 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -69,67 +69,77 @@ /* These functions and macros are for creating MPI "events" in the SOS stream. */ -#ifdef TAU_SOS +#if defined(TAU_SOS) && defined(TAU_PLUGIN_TRACE_SUPPORT) int TAU_inside_ADIOS(void); inline void Tau_plugin_trace_current_timer(const char * name) { -#if defined(TAU_PLUGIN_TRACE_SUPPORT) -// This is protected by a macro to avoid unnecessary overhead. - /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { - Tau_plugin_event_current_timer_exit_data_t plugin_data; - plugin_data.name_prefix = name; - Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_CURRENT_TIMER_EXIT, &plugin_data); - } -#endif + Tau_plugin_event_current_timer_exit_data_t plugin_data; + plugin_data.name_prefix = name; + Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_CURRENT_TIMER_EXIT, &plugin_data); } #define EVENT_TRACE_PREFIX "TAU_EVENT::MPI" #define TAU_SOS_COLLECTIVE_SYNC_EVENT(__desc,__comm) \ +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ char __tmp[128]; \ sprintf(__tmp, "%s collective synchronize %s 0x%08x", EVENT_TRACE_PREFIX, __desc, __comm); \ -Tau_plugin_trace_current_timer(__tmp); +Tau_plugin_trace_current_timer(__tmp); \ +} #define TAU_SOS_COLLECTIVE_EXCH_EVENT(__desc,__size,__comm) \ +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ char __tmp[128]; \ sprintf(__tmp, "%s collective exchange %s (%d) 0x%08x", EVENT_TRACE_PREFIX, __desc, __size, __comm); \ -Tau_plugin_trace_current_timer(__tmp); +Tau_plugin_trace_current_timer(__tmp); \ +} #define TAU_SOS_COLLECTIVE_EXCH_V_EVENT(__desc,__stats,__comm) \ +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ char __tmp[128]; \ sprintf(__tmp, "%s collective exchangev %s ([%f,%f,%f,%f,%f]) 0x%08x", \ EVENT_TRACE_PREFIX, __desc, __stats[0],__stats[1],__stats[2],__stats[3],__stats[4], __comm); \ -Tau_plugin_trace_current_timer(__tmp); +Tau_plugin_trace_current_timer(__tmp); \ +} #define TAU_SOS_COLLECTIVE_EXCH_AAV_EVENT(__desc,__stats1,__stats2,__comm) \ +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ char __tmp[256]; \ sprintf(__tmp, \ "%s collective exchangev %s ([%f,%f,%f,%f,%f],[%f,%f,%f,%f,%f]) 0x%08x", \ EVENT_TRACE_PREFIX, __desc, __stats1[0],__stats1[1],__stats1[2],__stats1[3],__stats1[4], \ __stats2[0],__stats2[1],__stats2[2],__stats2[3],__stats2[4], __comm); \ -Tau_plugin_trace_current_timer(__tmp); +Tau_plugin_trace_current_timer(__tmp); \ +} #define TAU_SOS_COMM_SPLIT_EVENT(__comm,__color,__key,__comm_out) \ +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ char __tmp[128]; \ sprintf(__tmp, "%s_Comm_split (%p, %d, %d) 0x%08x", EVENT_TRACE_PREFIX, __comm,__color,__key,__comm_out); \ -Tau_plugin_trace_current_timer(__tmp); +Tau_plugin_trace_current_timer(__tmp); \ +} #define TAU_SOS_COMM_DUP_EVENT(__comm,__comm_out) \ +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ char __tmp[128]; \ sprintf(__tmp, "%s_Comm_dup (%p) 0x%08x", EVENT_TRACE_PREFIX, __comm, __comm_out); \ -Tau_plugin_trace_current_timer(__tmp); +Tau_plugin_trace_current_timer(__tmp); \ +} #define TAU_SOS_COMM_CREATE_EVENT(__comm,__group,__comm_out) \ +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ char __tmp[128]; \ sprintf(__tmp, "%s_Comm_create (%p, %p) 0x%08x", EVENT_TRACE_PREFIX, __comm, __group, __comm_out); \ -Tau_plugin_trace_current_timer(__tmp); +Tau_plugin_trace_current_timer(__tmp); \ +} #define TAU_SOS_COMM_GROUP_EVENT(__comm,__group_addr) \ +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ char __tmp[128]; \ sprintf(__tmp, "%s_Comm_group (%p) %p", EVENT_TRACE_PREFIX, __comm, __group_addr); \ -Tau_plugin_trace_current_timer(__tmp); +Tau_plugin_trace_current_timer(__tmp); \ +} void Tau_sos_group_incl_event(MPI_Group group, int count, int ranks[], MPI_Group new_group) { // assume 128 for letters, and 10 digits for each rank (plus a comma) @@ -145,7 +155,9 @@ void Tau_sos_group_incl_event(MPI_Group group, int count, int ranks[], MPI_Group } #define TAU_SOS_GROUP_INCL_EVENT(__group,__count,__ranks,__group_addr) \ - Tau_sos_group_incl_event(__group, __count, __ranks, __group_addr); +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ + Tau_sos_group_incl_event(__group, __count, __ranks, __group_addr); \ +} void Tau_sos_group_excl_event(MPI_Group group, int count, int ranks[], MPI_Group new_group) { // assume 128 for letters, and 10 digits for each rank (plus a comma) @@ -161,7 +173,9 @@ void Tau_sos_group_excl_event(MPI_Group group, int count, int ranks[], MPI_Group } #define TAU_SOS_GROUP_EXCL_EVENT(__group,__count,__ranks,__group_addr) \ - Tau_sos_group_excl_event(__group, __count, __ranks, __group_addr); +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ + Tau_sos_group_excl_event(__group, __count, __ranks, __group_addr); \ +} void Tau_sos_group_range_incl_event(MPI_Group group, int count, int ranges[][3], MPI_Group new_group) { // assume 128 for letters, and 10 digits for each rank (plus a comma) @@ -177,7 +191,9 @@ void Tau_sos_group_range_incl_event(MPI_Group group, int count, int ranges[][3], } #define TAU_SOS_GROUP_RANGE_INCL_EVENT(__group,__count,__ranges,__newgroup) \ - Tau_sos_group_range_incl_event(__group, __count, __ranges, __newgroup); +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ + Tau_sos_group_range_incl_event(__group, __count, __ranges, __newgroup); \ +} void Tau_sos_group_range_excl_event(MPI_Group group, int count, int ranges[][3], MPI_Group new_group) { // assume 128 for letters, and 10 digits for each rank (plus a comma) @@ -193,7 +209,9 @@ void Tau_sos_group_range_excl_event(MPI_Group group, int count, int ranges[][3], } #define TAU_SOS_GROUP_RANGE_EXCL_EVENT(__group,__count,__ranges,__newgroup) \ - Tau_sos_group_range_excl_event(__group, __count, __ranges, __newgroup); +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ + Tau_sos_group_range_excl_event(__group, __count, __ranges, __newgroup); \ +} void Tau_sos_group_translate_ranks_event(MPI_Group group1, int count, int *ranks1, MPI_Group group2, int *ranks2) { // assume 128 for letters, and 10 digits for each rank (plus a comma) @@ -213,22 +231,30 @@ void Tau_sos_group_translate_ranks_event(MPI_Group group1, int count, int *ranks } #define TAU_SOS_GROUP_TRANSLATE_RANKS_EVENT(__group,__count,__ranks1,__group2,__ranks2) \ - Tau_sos_group_translate_ranks_event(__group, __count, __ranks1, __group2, __ranks2); +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ + Tau_sos_group_translate_ranks_event(__group, __count, __ranks1, __group2, __ranks2); \ +} #define TAU_SOS_GROUP_DIFFERENCE_EVENT(__group1,__group2,__newgroup) \ +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ char __tmp[128]; \ sprintf(__tmp, "%s_Group_difference (%p,%p) %p", EVENT_TRACE_PREFIX, __group1, __group2, __newgroup); \ -Tau_plugin_trace_current_timer(__tmp); +Tau_plugin_trace_current_timer(__tmp); \ +} #define TAU_SOS_GROUP_INTERSECTION_EVENT(__group1,__group2,__newgroup) \ +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ char __tmp[128]; \ sprintf(__tmp, "%s_Group_intersection (%p,%p) %p", EVENT_TRACE_PREFIX, __group1, __group2, __newgroup); \ -Tau_plugin_trace_current_timer(__tmp); +Tau_plugin_trace_current_timer(__tmp); \ +} #define TAU_SOS_GROUP_UNION_EVENT(__group1,__group2,__newgroup) \ +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ char __tmp[128]; \ sprintf(__tmp, "%s_Group_union (%p,%p) %p", EVENT_TRACE_PREFIX, __group1, __group2, __newgroup); \ -Tau_plugin_trace_current_timer(__tmp); +Tau_plugin_trace_current_timer(__tmp); \ +} // this is used between cart_create and cart_sub calls... may not be safe, but... static int __cart_dims = 1; @@ -252,7 +278,9 @@ void Tau_sos_cart_create_event(MPI_Comm comm, int ndims, TAU_MPICH3_CONST int * } #define TAU_SOS_CART_CREATE_EVENT(__comm,__ndims,__dims,__periods,__reorder,__comm_out) \ - Tau_sos_cart_create_event(__comm,__ndims,__dims,__periods,__reorder,__comm_out); +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ + Tau_sos_cart_create_event(__comm,__ndims,__dims,__periods,__reorder,__comm_out); \ +} void Tau_sos_cart_coords_event(MPI_Comm comm, int rank, int maxdims, int * coords) { // assume 128 for letters, and 10 digits for each rank (plus a comma) @@ -268,7 +296,9 @@ void Tau_sos_cart_coords_event(MPI_Comm comm, int rank, int maxdims, int * coord } #define TAU_SOS_CART_COORDS_EVENT(__comm,__rank,__maxdims,__coords) \ - Tau_sos_cart_coords_event(__comm,__rank,__maxdims,__coords); +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ + Tau_sos_cart_coords_event(__comm,__rank,__maxdims,__coords); \ +} void Tau_sos_cart_sub_event(MPI_Comm comm, TAU_MPICH3_CONST int * remains, MPI_Comm comm_out) { // assume 128 for letters, and 10 digits for each rank (plus a comma) @@ -284,7 +314,9 @@ void Tau_sos_cart_sub_event(MPI_Comm comm, TAU_MPICH3_CONST int * remains, MPI_C } #define TAU_SOS_CART_SUB_EVENT(__comm,__remains,__comm_out) \ - Tau_sos_cart_sub_event(__comm,__remains,__comm_out); +if(Tau_plugins_enabled.current_timer_exit && TAU_inside_ADIOS() == 0) { \ + Tau_sos_cart_sub_event(__comm,__remains,__comm_out); \ +} #else #define TAU_SOS_COLLECTIVE_SYNC_EVENT(__desc,__comm) @@ -532,12 +564,9 @@ char *note; otherid = status->MPI_SOURCE; /* if (rq->tag == MPI_ANY_TAG) */ othertag = status->MPI_TAG; -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. /* post the receive message */ TAU_TRACE_RECVMSG(othertag, TauTranslateRankToWorld(rq->comm, otherid), rq->size); TAU_PLUGIN_RECVMSG(othertag, TauTranslateRankToWorld(rq->comm, otherid), rq->size, 0); -#endif TAU_WAIT_DATA(rq->size); } @@ -584,12 +613,9 @@ char *note; { otherid = TauTranslateRankToWorld(rq->comm, rq->otherParty); othertag = rq->tag; -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. /* post the send message */ TAU_TRACE_SENDMSG(othertag, otherid, rq->size); TAU_PLUGIN_SENDMSG(othertag, otherid, rq->size, 0); -#endif } return; @@ -1919,7 +1945,7 @@ int MPI_Finalize( ) /*Invoke plugins only if both plugin path and plugins are specified *Do this first, because the plugin can write TAU_METADATA as recommendations to the user*/ - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.pre_end_of_execution) { + if(Tau_plugins_enabled.pre_end_of_execution) { Tau_plugin_event_pre_end_of_execution_data_t plugin_data; plugin_data.tid = Tau_get_local_tid(); Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_PRE_END_OF_EXECUTION, &plugin_data); @@ -2009,15 +2035,8 @@ char *** argv; returnVal = PMPI_Init( argc, argv ); - /*Initialize the plugin system only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - TAU_VERBOSE("TAU INIT: Initializing plugin system...\n"); - if(!Tau_initialize_plugin_system()) { - TAU_VERBOSE("TAU INIT: Successfully Initialized the plugin system.\n"); - } else { - printf("TAU INIT: Error initializing the plugin system\n"); - } - } + /* Initialize the plugin system */ + Tau_initialize_plugin_system(); #ifndef TAU_WINDOWS #ifndef _AIX @@ -2094,15 +2113,8 @@ int *provided; returnVal = PMPI_Init_thread( argc, argv, required, provided ); - /*Initialize the plugin system only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { - TAU_VERBOSE("TAU INIT: Initializing plugin system...\n"); - if(!Tau_initialize_plugin_system()) { - TAU_VERBOSE("TAU INIT: Successfully Initialized the plugin system.\n"); - } else { - printf("TAU INIT: Error initializing the plugin system\n"); - } - } + /* Initialize the plugin system */ + Tau_initialize_plugin_system(); #ifndef TAU_WINDOWS #ifndef _AIX @@ -2257,15 +2269,12 @@ MPI_Comm comm; TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize ); -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count, 0); -#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Bsend( buf, count, datatype, dest, tag, comm ); @@ -2420,12 +2429,9 @@ MPI_Request * request; /* we need to store the request and associate it with the size/tag so MPI_Start can retrieve it and log the TAU_TRACE_SENDMSG */ -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { TauAddRequestData(RQ_SEND, count, datatype, dest, tag, comm, request, returnVal, 1); } -#endif TAU_PROFILE_STOP(tautimer); @@ -2482,15 +2488,12 @@ MPI_Request * request; TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize ); -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize, 0); -#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Ibsend( buf, count, datatype, dest, tag, comm, request ); @@ -2572,15 +2575,12 @@ MPI_Request * request; TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize3 ); -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize3); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize3, 0); -#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Irsend( buf, count, datatype, dest, tag, comm, request ); @@ -2607,15 +2607,12 @@ MPI_Request * request; TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize3 ); -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize3); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize3, 0); -#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Isend( buf, count, datatype, dest, tag, comm, request ); @@ -2639,15 +2636,12 @@ MPI_Request * request; TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize3 ); -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize3); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), count * typesize3, 0); -#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Issend( buf, count, datatype, dest, tag, comm, request ); @@ -2743,23 +2737,17 @@ MPI_Status * status; if (source != MPI_PROC_NULL && returnVal == MPI_SUCCESS) { /* note that status->MPI_COMM must == comm */ -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { PMPI_Get_count( status, MPI_BYTE, &size ); TAU_TRACE_RECVMSG(status->MPI_TAG, TauTranslateRankToWorld(comm, status->MPI_SOURCE), size); } -#endif int typesize = 0; PMPI_Type_size( datatype, &typesize ); -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (status == NULL) { TAU_PLUGIN_RECVMSG(tag, TauTranslateRankToWorld(comm, source), count*typesize, 0); } else { TAU_PLUGIN_RECVMSG(status->MPI_TAG, TauTranslateRankToWorld(comm, status->MPI_SOURCE), count*typesize, 0); } -#endif } TAU_PROFILE_STOP(tautimer); @@ -2781,15 +2769,12 @@ MPI_Comm comm; TAU_PROFILE_TIMER(tautimer, "MPI_Rsend()", " ", TAU_MESSAGE); TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize ); -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count, 0); -#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Rsend( buf, count, datatype, dest, tag, comm ); @@ -2840,15 +2825,12 @@ MPI_Comm comm; TAU_PROFILE_TIMER(tautimer, "MPI_Send()", " ", TAU_MESSAGE); TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize ); -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count, 0); -#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Send( buf, count, datatype, dest, tag, comm ); @@ -2884,37 +2866,28 @@ MPI_Status * status; status = &local_status; } -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(sendtag, TauTranslateRankToWorld(comm, dest), typesize1*sendcount); } } TAU_PLUGIN_SENDMSG(sendtag, TauTranslateRankToWorld(comm, dest), typesize1*sendcount, 0); -#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Sendrecv( sendbuf, sendcount, sendtype, dest, sendtag, recvbuf, recvcount, recvtype, source, recvtag, comm, status ); if (source != MPI_PROC_NULL && returnVal == MPI_SUCCESS) { -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { PMPI_Get_count( status, MPI_BYTE, &count ); TAU_TRACE_RECVMSG(status->MPI_TAG, TauTranslateRankToWorld(comm, status->MPI_SOURCE), count); } -#endif int typesize = 0; PMPI_Type_size( recvtype, &typesize ); -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (status == NULL) { TAU_PLUGIN_RECVMSG(recvtag, TauTranslateRankToWorld(comm, source), count*typesize, 0); } else { TAU_PLUGIN_RECVMSG(status->MPI_TAG, TauTranslateRankToWorld(comm, status->MPI_SOURCE), count*typesize, 0); } -#endif } TAU_PROFILE_STOP(tautimer); @@ -2945,37 +2918,28 @@ MPI_Status * status; if (status == MPI_STATUS_IGNORE) { status = &local_status; } -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(sendtag, TauTranslateRankToWorld(comm, dest), typesize2*count); } } TAU_PLUGIN_SENDMSG(sendtag, TauTranslateRankToWorld(comm, dest), typesize2*count, 0); -#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Sendrecv_replace( buf, count, datatype, dest, sendtag, source, recvtag, comm, status ); if (dest != MPI_PROC_NULL && returnVal == MPI_SUCCESS) { -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { PMPI_Get_count( status, MPI_BYTE, &size1 ); TAU_TRACE_RECVMSG(status->MPI_TAG, TauTranslateRankToWorld(comm, status->MPI_SOURCE), size1); } -#endif int typesize = 0; PMPI_Type_size( datatype, &typesize ); -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (status == NULL) { TAU_PLUGIN_RECVMSG(recvtag, TauTranslateRankToWorld(comm, source), count*typesize, 0); } else { TAU_PLUGIN_RECVMSG(status->MPI_TAG, TauTranslateRankToWorld(comm, status->MPI_SOURCE), count*typesize, 0); } -#endif } TAU_PROFILE_STOP(tautimer); @@ -2996,15 +2960,12 @@ MPI_Comm comm; TAU_PROFILE_TIMER(tautimer, "MPI_Ssend()", " ", TAU_MESSAGE); TAU_PROFILE_START(tautimer); PMPI_Type_size( datatype, &typesize ); -#if defined(TAU_PLUGIN_TRACE_SUPPORT) - // This is protected by a macro to avoid unnecessary overhead. if (TauEnv_get_track_message()) { if (dest != MPI_PROC_NULL) { TAU_TRACE_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count); } } TAU_PLUGIN_SENDMSG(tag, TauTranslateRankToWorld(comm, dest), typesize*count, 0); -#endif TAU_TRACK_COMM(comm); returnVal = PMPI_Ssend( buf, count, datatype, dest, tag, comm ); diff --git a/src/Profile/TauUtil.cpp b/src/Profile/TauUtil.cpp index 7aa012293..beb21d65c 100644 --- a/src/Profile/TauUtil.cpp +++ b/src/Profile/TauUtil.cpp @@ -31,7 +31,7 @@ #define strtok_r(a,b,c) strtok(a,b) #endif /* TAU_WINDOWS */ -Tau_plugin_callbacks_active_t Tau_plugin_enabled; +Tau_plugin_callbacks_active_t Tau_plugins_enabled; #define TAU_NAME_LENGTH 1024 @@ -199,7 +199,6 @@ PluginManager* Tau_util_get_plugin_manager() { plugin_manager->callback_list = (Tau_plugin_callback_list*)malloc(sizeof(Tau_plugin_callback_list)); (plugin_manager->callback_list)->head = NULL; - memset(&Tau_plugin_enabled, 0, sizeof(Tau_plugin_callbacks_active_t)); is_plugin_system_initialized = 1; } @@ -210,7 +209,15 @@ PluginManager* Tau_util_get_plugin_manager() { * Initializes the plugin system by loading and registering all plugins ********************************************************************/ int Tau_initialize_plugin_system() { - return(Tau_util_load_and_register_plugins(Tau_util_get_plugin_manager())); + memset(&Tau_plugins_enabled, 0, sizeof(Tau_plugin_callbacks_active_t)); + if(TauEnv_get_plugins_enabled()) { + TAU_VERBOSE("TAU INIT: Initializing plugin system...\n"); + if(!Tau_util_load_and_register_plugins(Tau_util_get_plugin_manager())) { + TAU_VERBOSE("TAU INIT: Successfully Initialized the plugin system.\n"); + } else { + printf("TAU INIT: Error initializing the plugin system\n"); + } + } } /********************************************************************* @@ -447,21 +454,21 @@ extern "C" void Tau_util_plugin_register_callbacks(Tau_plugin_callbacks * cb) { (plugin_manager->callback_list)->head = callback; /* Set some flags to make runtime conditional processing more efficient */ - if (cb->FunctionRegistrationComplete != 0) { Tau_plugin_enabled.function_registration = 1; } - if (cb->MetadataRegistrationComplete != 0) { Tau_plugin_enabled.metadata_registration = 1; } - if (cb->PostInit != 0) { Tau_plugin_enabled.post_init = 1; } - if (cb->Dump != 0) { Tau_plugin_enabled.dump = 1; } - if (cb->FunctionEntry != 0) { Tau_plugin_enabled.function_entry = 1; } - if (cb->FunctionExit != 0) { Tau_plugin_enabled.function_exit = 1; } - if (cb->Send != 0) { Tau_plugin_enabled.send = 1; } - if (cb->Recv != 0) { Tau_plugin_enabled.recv = 1; } - if (cb->CurrentTimerExit != 0) { Tau_plugin_enabled.current_timer_exit = 1; } - if (cb->AtomicEventRegistrationComplete != 0) { Tau_plugin_enabled.atomic_event_registration = 1; } - if (cb->AtomicEventTrigger != 0) { Tau_plugin_enabled.atomic_event_trigger = 1; } - if (cb->PreEndOfExecution != 0) { Tau_plugin_enabled.pre_end_of_execution = 1; } - if (cb->EndOfExecution != 0) { Tau_plugin_enabled.end_of_execution = 1; } - if (cb->FunctionFinalize != 0) { Tau_plugin_enabled.function_finalize = 1; } - if (cb->InterruptTrigger != 0) { Tau_plugin_enabled.interrupt_trigger = 1; } + if (cb->FunctionRegistrationComplete != 0) { Tau_plugins_enabled.function_registration = 1; } + if (cb->MetadataRegistrationComplete != 0) { Tau_plugins_enabled.metadata_registration = 1; } + if (cb->PostInit != 0) { Tau_plugins_enabled.post_init = 1; } + if (cb->Dump != 0) { Tau_plugins_enabled.dump = 1; } + if (cb->FunctionEntry != 0) { Tau_plugins_enabled.function_entry = 1; } + if (cb->FunctionExit != 0) { Tau_plugins_enabled.function_exit = 1; } + if (cb->Send != 0) { Tau_plugins_enabled.send = 1; } + if (cb->Recv != 0) { Tau_plugins_enabled.recv = 1; } + if (cb->CurrentTimerExit != 0) { Tau_plugins_enabled.current_timer_exit = 1; } + if (cb->AtomicEventRegistrationComplete != 0) { Tau_plugins_enabled.atomic_event_registration = 1; } + if (cb->AtomicEventTrigger != 0) { Tau_plugins_enabled.atomic_event_trigger = 1; } + if (cb->PreEndOfExecution != 0) { Tau_plugins_enabled.pre_end_of_execution = 1; } + if (cb->EndOfExecution != 0) { Tau_plugins_enabled.end_of_execution = 1; } + if (cb->FunctionFinalize != 0) { Tau_plugins_enabled.function_finalize = 1; } + if (cb->InterruptTrigger != 0) { Tau_plugins_enabled.interrupt_trigger = 1; } } @@ -801,8 +808,6 @@ int Tau_util_cleanup_all_plugins() { /////////////////////////////////////////////////////////////////////////// extern "C" void Tau_plugin_sendmsg(long unsigned int type, long unsigned int destination, long unsigned int length, long unsigned int remoteid) { - /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { Tau_plugin_event_send_data plugin_data; plugin_data.message_tag = type; plugin_data.destination = destination; @@ -812,12 +817,9 @@ extern "C" void Tau_plugin_sendmsg(long unsigned int type, long unsigned int des RtsLayer::getUSecD(plugin_data.tid, timeStamp); plugin_data.timestamp = (unsigned long)(timeStamp[0]); Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_SEND, &plugin_data); - } } /////////////////////////////////////////////////////////////////////////// extern "C" void Tau_plugin_recvmsg(long unsigned int type, long unsigned int source, long unsigned int length, long unsigned int remoteid) { - /*Invoke plugins only if both plugin path and plugins are specified*/ - if(TauEnv_get_plugins_enabled()) { Tau_plugin_event_recv_data plugin_data; plugin_data.message_tag = type; plugin_data.source = source; @@ -827,6 +829,5 @@ extern "C" void Tau_plugin_recvmsg(long unsigned int type, long unsigned int sou RtsLayer::getUSecD(plugin_data.tid, timeStamp); plugin_data.timestamp = (unsigned long)(timeStamp[0]); Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_RECV, &plugin_data); - } } diff --git a/src/Profile/UserEvent.cpp b/src/Profile/UserEvent.cpp index 06c27f0f8..9a843420b 100644 --- a/src/Profile/UserEvent.cpp +++ b/src/Profile/UserEvent.cpp @@ -125,7 +125,7 @@ void TauUserEvent::AddEventToDB() DEBUGPROFMSG("Size of eventDB is " << TheEventDB().size() <") == std::string::npos)) { - if(TauEnv_get_plugins_enabled() && Tau_plugins_enabled.atomic_event_trigger) { Tau_plugin_event_atomic_event_trigger_data_t plugin_data; plugin_data.counter_name = name.c_str(); plugin_data.tid = tid; From d4f3bf89d8176c9efec4c4e75d202b3eb99f2938 Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Tue, 31 Jul 2018 07:20:56 -0700 Subject: [PATCH 46/60] Removing macros, using just runtime decisions for plugins. Don't use a -Dxxx macro for enabling plugin tracing, the lower overhead flag checking seems to be adequate. Former-commit-id: c137cb6bd16df810d7d5ce8659e432ba988731de --- plugins/examples/Tau_plugin_sos.cpp | 30 ----------------------------- src/Profile/Profiler.cpp | 4 ---- src/Profile/TauMpi.c | 2 +- src/Profile/UserEvent.cpp | 2 -- 4 files changed, 1 insertion(+), 37 deletions(-) diff --git a/plugins/examples/Tau_plugin_sos.cpp b/plugins/examples/Tau_plugin_sos.cpp index ba6a24bfd..e6c328693 100644 --- a/plugins/examples/Tau_plugin_sos.cpp +++ b/plugins/examples/Tau_plugin_sos.cpp @@ -238,21 +238,6 @@ extern "C" int Tau_plugin_init_func(int argc, char **argv) { cb->EndOfExecution = Tau_plugin_sos_end_of_execution; /* Event tracing support */ if (thePluginOptions().env_sos_tracing) { -#if !defined(TAU_PLUGIN_TRACE_SUPPORT) -#if TAU_MPI - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if (rank == 0) { - std::cerr << "Error! Plugin trace support was not configured.\n"; - std::cerr << "Please reconfigure TAU with '-useropt=-DTAU_PLUGIN_TRACE_SUPPORT'.\n" << std::endl; - } - MPI_Abort(MPI_COMM_WORLD, 999); -#else - std::cerr << "Error! Plugin trace support was not configured.\n"; - std::cerr << "Please reconfigure TAU with '-useropt=-DTAU_PLUGIN_TRACE_SUPPORT'.\n" << std::endl; - abort(); -#endif -#endif cb->Send = Tau_plugin_sos_send; cb->Recv = Tau_plugin_sos_recv; cb->FunctionEntry = Tau_plugin_sos_function_entry; @@ -261,21 +246,6 @@ extern "C" int Tau_plugin_init_func(int argc, char **argv) { } /* Specialized support for ADIOS, MPI events (ADIOS Skel/Pooky support) */ if (thePluginOptions().env_sos_trace_adios) { -#if !defined(TAU_PLUGIN_TRACE_SUPPORT) -#if TAU_MPI - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if (rank == 0) { - std::cerr << "Error! Plugin trace support was not configured.\n"; - std::cerr << "Please reconfigure TAU with '-useropt=-DTAU_PLUGIN_TRACE_SUPPORT'.\n" << std::endl; - } - MPI_Abort(MPI_COMM_WORLD, 999); -#else - std::cerr << "Error! Plugin trace support was not configured.\n"; - std::cerr << "Please reconfigure TAU with '-useropt=-DTAU_PLUGIN_TRACE_SUPPORT'.\n" << std::endl; - abort(); -#endif -#endif cb->CurrentTimerExit = Tau_plugin_sos_current_timer_exit; } /* Not sure what this thing does */ diff --git a/src/Profile/Profiler.cpp b/src/Profile/Profiler.cpp index 56a22468a..f7946d4bf 100644 --- a/src/Profile/Profiler.cpp +++ b/src/Profile/Profiler.cpp @@ -362,7 +362,6 @@ void Profiler::Start(int tid) ThisKtauProfiler->Start(this); #endif /* TAUKTAU */ -#if defined(TAU_PLUGIN_TRACE_SUPPORT) /*Invoke plugins only if both plugin path and plugins are specified*/ if(Tau_plugins_enabled.function_entry) { Tau_plugin_event_function_entry_data_t plugin_data; @@ -372,7 +371,6 @@ void Profiler::Start(int tid) plugin_data.timestamp = TimeStamp; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_FUNCTION_ENTRY, &plugin_data); } -#endif } void Profiler::Stop(int tid, bool useLastTimeStamp) @@ -701,7 +699,6 @@ void Profiler::Stop(int tid, bool useLastTimeStamp) KtauProfiler::PutKtauProfiler(); #endif /* TAUKTAU */ -#if defined(TAU_PLUGIN_TRACE_SUPPORT) /*Invoke plugins only if both plugin path and plugins are specified*/ if(Tau_plugins_enabled.function_exit) { Tau_plugin_event_function_exit_data_t plugin_data; @@ -711,7 +708,6 @@ void Profiler::Stop(int tid, bool useLastTimeStamp) plugin_data.timestamp = TimeStamp; Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_FUNCTION_EXIT, &plugin_data); } -#endif } ////////////////////////////////////////////////////////////////////// diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index 20f0b96b7..703836040 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -69,7 +69,7 @@ /* These functions and macros are for creating MPI "events" in the SOS stream. */ -#if defined(TAU_SOS) && defined(TAU_PLUGIN_TRACE_SUPPORT) +#if defined(TAU_SOS) int TAU_inside_ADIOS(void); diff --git a/src/Profile/UserEvent.cpp b/src/Profile/UserEvent.cpp index 9a843420b..5ac25fd9d 100644 --- a/src/Profile/UserEvent.cpp +++ b/src/Profile/UserEvent.cpp @@ -296,7 +296,6 @@ void TauUserEvent::TriggerEvent(TAU_EVENT_DATATYPE data, int tid, double timesta } #endif /* PROFILING_ON */ /*Invoke plugins only if both plugin path and plugins are specified*/ -#if defined(TAU_PLUGIN_TRACE_SUPPORT) /* and only output the counter if it's not a context counter */ if(Tau_plugins_enabled.atomic_event_trigger) { if ((name[0] != '[') @@ -310,7 +309,6 @@ void TauUserEvent::TriggerEvent(TAU_EVENT_DATATYPE data, int tid, double timesta Tau_util_invoke_callbacks(TAU_PLUGIN_EVENT_ATOMIC_EVENT_TRIGGER, &plugin_data); } } -#endif } // Tau_global_getLightsOut } From 861fca53e755eac7490cfdc0475b0fa83d8d46aa Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Wed, 1 Aug 2018 18:21:35 -0700 Subject: [PATCH 47/60] Fixing OMPT library location, configuration checks Not sure how this was working before...the OMPT settings for the makefile fixing was looking in the wrong location for -lomp. Also, regardless of the compiler used, the library can be the name -lomp. The library name doesn't matter as long as the symbols are defined. Finally, opari can be used with pthread if openmp is also selected (in the case of SOS configurations). Former-commit-id: 259a890f43818e11172118d69f29af17b52baec5 --- configure | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/configure b/configure index e55d690e7..fe5f06f21 100755 --- a/configure +++ b/configure @@ -6776,13 +6776,13 @@ fi if [ $gnu = yes ] ; then ompt_c_compiler=gcc ompt_cxx_compiler=g++ - libomp_oss_name=gomp + libomp_oss_name=omp fi if [ "${architecture}" = "craycnl" ] ; then if [ "${intel}" = "yes" ] ; then ompt_c_compiler=icc ompt_cxx_compiler=icpc - libomp_oss_name=iomp5 + libomp_oss_name=omp fi fi @@ -10392,7 +10392,7 @@ if [ $papi = yes ] ; then fi if [ $opari = yes ] ; then - if [ $pthread = yes -o $smarts = yes -o $java = yes ] ; then + if [ [[ $pthread = yes -a $openmp = no ]] -o $smarts = yes -o $java = yes ] ; then echo "ERROR: -opari option requires OpenMP threads package." echo "*****************************************************" exit 1 @@ -11021,7 +11021,7 @@ if [ $ompt = yes -a $install_ompt = yes -a -r ${libomp_ossdir_shared}/lib${libom echo "BGQ ompt" else echo "TAU: Copying lib${libomp_oss_name}.so to ${targetdir}/${architecture}/lib/shared${tauoptions} ..." - ompt_instdir=${targetdir}/${architecture}/lib/shared${tauoptions} + ompt_instdir=${targetdir}/${architecture}/lib mkdir -p ${ompt_instdir} cp ${libomp_ossdir_shared}/lib${libomp_oss_name}.so ${ompt_instdir}/lib${libomp_oss_name}.so ; cp ${libomp_ossdir_shared}/libomp.so ${ompt_instdir}/libomp.so ; From 3d696d2c2dfc93b133d98deb50d51763ee9382bf Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Thu, 2 Aug 2018 12:18:41 -0700 Subject: [PATCH 48/60] When CUDA and OpenMP are configured at the same time, the link options for tau_cupti_avail requires the openmp flag in order to link. Former-commit-id: df4ab7148b44e6dd46d038aeec778786fab6dadf --- utils/tau_cupti_avail/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/tau_cupti_avail/Makefile b/utils/tau_cupti_avail/Makefile index 356b521df..bbcc32125 100644 --- a/utils/tau_cupti_avail/Makefile +++ b/utils/tau_cupti_avail/Makefile @@ -13,7 +13,7 @@ all: $(TAU_CUPTI_AVAIL) install: $(INSTALLTAU_CUPTI_AVAIL) $(TAU_CUPTI_AVAIL): tau_cupti_avail.o $(TAU_PREFIX_INSTALL_DIR)/$(CONFIG_ARCH)/lib/libTAUsh$(TAU_CONFIG).so - $(CXX) -o $@ $< -L$(TAU_LIB_DIR) $(TAU_LINKER_RPATH_OPT) $(TAU_SHLIBS) -lcuda + $(CXX) -o $@ $< -L$(TAU_LIB_DIR) $(TAU_LINKER_RPATH_OPT) $(TAU_SHLIBS) $(TAU_OPENMP_OPTION) -lcuda tau_cupti_avail.o: tau_cupti_avail.cpp $(TAU_CUDA_CXX) $(CFLAGS) -I$(TAU_CUDA_INC) -I$(TAU_CUPTI_INC) -I$(TAU_INC_DIR) -c $< From 4b1af6e5755faa49a50fd35621a51a2ea3a050f1 Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Thu, 2 Aug 2018 14:48:17 -0700 Subject: [PATCH 49/60] Removing debug messages from TauMpi.c Former-commit-id: 444e4abc09e0656607c081ae5daabad9e7dbc291 --- apex | 2 +- src/Profile/TauMpi.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apex b/apex index d524984d3..bc636daa5 160000 --- a/apex +++ b/apex @@ -1 +1 @@ -Subproject commit d524984d3dfedc77e07378e3d9093098b4094216 +Subproject commit bc636daa54f158a733a5d7cb0e1349d0af80faaa diff --git a/src/Profile/TauMpi.c b/src/Profile/TauMpi.c index f0208ce99..3a14d1e30 100644 --- a/src/Profile/TauMpi.c +++ b/src/Profile/TauMpi.c @@ -2254,13 +2254,12 @@ char *** argv; int required; int *provided; { - fprintf(stderr, "MPI INIT THREAD WRAPPER\n"); int returnVal; int size; char procname[MPI_MAX_PROCESSOR_NAME]; int procnamelength; - fprintf(stdout, "call TAU MPI_Init_thread()\n"); + TAU_VERBOSE("call TAU MPI_Init_thread()\n"); TAU_PROFILE_TIMER(tautimer, "MPI_Init_thread()", " ", TAU_MESSAGE); Tau_create_top_level_timer_if_necessary(); From b4a63f9314d4705c7958caca8699c074a5999b8b Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Thu, 2 Aug 2018 16:25:25 -0700 Subject: [PATCH 50/60] Creating "scripts" directory for building on known systems. Former-commit-id: 2f68c998142dc0f683f2f973284341984e324515 --- bootstrap.sh => scripts/bootstrap.sh | 0 scripts/titan_gcc.sh | 118 +++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) rename bootstrap.sh => scripts/bootstrap.sh (100%) create mode 100755 scripts/titan_gcc.sh diff --git a/bootstrap.sh b/scripts/bootstrap.sh similarity index 100% rename from bootstrap.sh rename to scripts/bootstrap.sh diff --git a/scripts/titan_gcc.sh b/scripts/titan_gcc.sh new file mode 100755 index 000000000..f58d3d344 --- /dev/null +++ b/scripts/titan_gcc.sh @@ -0,0 +1,118 @@ +#!/bin/bash + +source $MODULESHOME/init/bash +module swap PrgEnv-pgi PrgEnv-gnu +module load cmake3/3.9.0 +module load cudatoolkit +module load wget +module load papi +module load python +module load perl +module list + +set -x + +WORK_DIR=$PWD +INSTALL_ROOT=/ccs/proj/super/TOOLS + +if [ ! -d ${INSTALL_ROOT} ] ; then + mkdir -p ${INSTALL_ROOT} +fi + +PDT_VERSION=3.25 +TAU_VERSION=2018-07-31 + +echo_start() +{ + echo -e "====== BUILDING $1 ======" +} + +echo_done() +{ + echo -e "====== DONE BUILDING $1 ======" +} + +build_pdt() { + echo_start "pdt" + subdir=pdtoolkit-${PDT_VERSION} + if [ ! -d ${subdir} ] ; then + if [ ! -f pdt-3.25.tar.gz ] ; then + wget https://www.cs.uoregon.edu/research/tau/pdt_releases/pdt-${PDT_VERSION}.tar.gz + fi + tar -xzf pdt-${PDT_VERSION}.tar.gz + fi + cd ${subdir} + CC=gcc CXX=g++ ./configure -GNU -prefix=${INSTALL_ROOT}/pdt/pdtoolkit-${PDT_VERSION} + make -j8 -l24 + make install + cd .. + echo_done "pdt" +} + +build_tau() +{ + echo_start "tau" + if [ ! -d tau2-${TAU_VERSION} ] ; then + if [ ! -f tau2-${TAU_VERSION}.tar.gz ] ; then + wget http://www.nic.uoregon.edu/~khuck/tau2-${TAU_VERSION}.tar.gz + fi + tar -xzf tau2-${TAU_VERSION}.tar.gz + fi + cd tau2-${TAU_VERSION} + + PAPI_PATH=`pkg-config --cflags papi | sed -r 's/^-I//' | xargs dirname` + + # base configure for front-end tools + CC=gcc CXX=g++ ./configure \ + -prefix=${INSTALL_ROOT}/tau/tau-${TAU_VERSION} \ + -pdt=${INSTALL_ROOT}/pdt/pdtoolkit-${PDT_VERSION} \ + -pdt_c++=g++ \ + -bfd=download -unwind=download -otf=download \ + -arch=craycnl + make -j8 -l32 install + +# rm -rf LLVM-openmp-0.2 +# wget http://tau.uoregon.edu/LLVM-openmp-0.2.tar.gz +# tar -xzf LLVM-openmp-0.2.tar.gz +# cd LLVM-openmp-0.2 +# mkdir build-g++ +# cd build-g++ +# cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ \ +# -DCMAKE_C_FLAGS=-fPIC -DCMAKE_CXX_FLAGS=-fPIC \ +# -DCMAKE_INSTALL_PREFIX=${INSTALL_ROOT}/tau/tau-${TAU_VERSION}/craycnl/LLVM-openmp-0.2 .. +# make libomp-needed-headers +# make +# make install +# cd ../.. + + # different configurations for mutually exclusive config options. + for cuda_settings in "" "-cuda=${CUDATOOLKIT_HOME}" ; do + #for thread_settings in "-pthread" "-openmp -ompt=${INSTALL_ROOT}/tau/tau-${TAU_VERSION}/craycnl/LLVM-openmp-0.2" "-openmp -opari" ; do + for thread_settings in "-pthread" ; do + for python_settings in "" "-python" ; do + # build config with all RAPIDS support + ./configure \ + -prefix=${INSTALL_ROOT}/tau/tau-${TAU_VERSION} \ + -pdt=${INSTALL_ROOT}/pdt/pdtoolkit-${PDT_VERSION} \ + -pdt_c++=g++ \ + -bfd=download -unwind=download -otf=download \ + -arch=craycnl \ + -cc=gcc -c++=g++ -fortran=gfortran \ + -iowrapper -mpi \ + -papi=${PAPI_PATH} \ + ${thread_settings} ${cuda_settings} ${python_settings} + make -j8 -l32 install + done + done + done + + cd .. + echo_done "tau" +} + +#============================================================================== + +# build_pdt +build_tau + +rm *tar.gz From 518ae9fdc60139e1e89031108268e8c0bc5234e5 Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Fri, 3 Aug 2018 07:12:00 -0700 Subject: [PATCH 51/60] Handle context event case where timer depth = -1. Former-commit-id: 7c134161546ddc56d8466f2eb2155ca01fc5efbe --- src/Profile/UserEvent.cpp | 62 ++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/src/Profile/UserEvent.cpp b/src/Profile/UserEvent.cpp index 5ac25fd9d..173d713c1 100644 --- a/src/Profile/UserEvent.cpp +++ b/src/Profile/UserEvent.cpp @@ -427,36 +427,44 @@ TauSafeString TauContextUserEvent::FormulateContextNameString(Profiler * current buff << userEvent->GetName(); int depth = Tau_get_current_stack_depth(tid); - Profiler ** path = new Profiler*[depth]; - - // Reverse the callpath to avoid string copies - int i=depth-1; - for (; current && i >= 0; --i) { - path[i] = current; - current = current->ParentProfiler; - } - // Now we can construct the name string by appending rather than prepending - buff << " : "; FunctionInfo * fi; - for (++i; i < depth-1; ++i) { - fi = path[i]->ThisFunction; - buff << fi->GetName(); - if (strlen(fi->GetType()) > 0) - buff << " " << fi->GetType(); - buff << " => "; - } - if (depth == 0) { - fi = current->ThisFunction; + if (depth > 0) { + Profiler ** path = new Profiler*[depth]; + + // Reverse the callpath to avoid string copies + int i=depth-1; + for (; current && i >= 0; --i) { + path[i] = current; + current = current->ParentProfiler; + } + // Now we can construct the name string by appending rather than prepending + buff << " : "; + for (++i; i < depth-1; ++i) { + fi = path[i]->ThisFunction; + buff << fi->GetName(); + if (strlen(fi->GetType()) > 0) + buff << " " << fi->GetType(); + buff << " => "; + } + if (depth == 0) { + fi = current->ThisFunction; + } else { + fi = path[i]->ThisFunction; + } + buff << fi->GetName(); + if (strlen(fi->GetType()) > 0) + buff << " " << fi->GetType(); + + delete[] path; } else { - fi = path[i]->ThisFunction; + fi = current->ThisFunction; + buff << " : " << fi->GetName(); + if (strlen(fi->GetType()) > 0) { + buff << " " << fi->GetType(); + } } - buff << fi->GetName(); - if (strlen(fi->GetType()) > 0) - buff << " " << fi->GetType(); - - delete[] path; - // Return a new string object. - // A smart STL implementation will not allocate a new buffer. + // Return a new string object. + // A smart STL implementation will not allocate a new buffer. return buff.str().c_str(); } else { return ""; From e5f3dd5575ec96446aa0d33f957f14a5b1326839 Mon Sep 17 00:00:00 2001 From: Kevin Huck Date: Fri, 3 Aug 2018 13:21:08 -0700 Subject: [PATCH 52/60] Prevent OTF2 crash when thread does nothing. Former-commit-id: 04b3d6f158088bc3e07f638c26f02df50a8793e8 --- src/Profile/TracerOTF2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Profile/TracerOTF2.cpp b/src/Profile/TracerOTF2.cpp index d169e75fc..eed409f43 100755 --- a/src/Profile/TracerOTF2.cpp +++ b/src/Profile/TracerOTF2.cpp @@ -549,7 +549,7 @@ void TauTraceOTF2EventWithNodeId(long int ev, x_int64 par, int tid, x_uint64 ts, // The event file for a thread needs to be written by that thread, so we write // the temporary buffers the first time we get an event from that thread after // intialization has completed. - if(!buffers_written[tid]) { + if(!buffers_written[tid] && !otf2_comms_shutdown) { TauTraceOTF2WriteTempBuffer(tid, node_id); } #endif From c8f858b3347f36921ef4e8330f502b7e65824d89 Mon Sep 17 00:00:00 2001 From: Nicholas Chaimov Date: Sat, 4 Aug 2018 14:10:43 -0700 Subject: [PATCH 53/60] Add -ptts-start and -ptts-stop options to tau_exec to control region instrumentation in PTTS Former-commit-id: fd6f426d147a2b24d91862d8f577fa051c06056c --- tools/src/tau_exec | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tools/src/tau_exec b/tools/src/tau_exec index 5d99d7b4a..a704d66da 100755 --- a/tools/src/tau_exec +++ b/tools/src/tau_exec @@ -56,6 +56,8 @@ usage() echo " -ptts-post Skip application sampling and post-process existing PTTS sample files" echo " -ptts-num= Number of ranks used for ThreadSpotter" echo " -ptts-sample-flags= Flags to pass to PTTS sample_ts command. Overrides TAU_TS_SAMPLE_FLAGS env. var." + echo " -ptts-start= Address at which to start a PTTS sampling region" + echo " -ptts-stop= Address at which to stop a PTTS sampling region" echo " -ptts-report-flags= Flags to pass to PTTS report_ts command. Overrides TAU_TS_REPORT_FLAGS env. var." echo " -ebs Enable event-based sampling" echo " -ebs_period= Sampling period (default 1000)" @@ -446,6 +448,16 @@ for arg in "$@" ; do save_arg $arg shift ;; + -ptts-start=*) + ptts_start="${arg/#-ptts-start=/}" # bash parameter expansion, bash 3 and up + save_arg $arg + shift + ;; + -ptts-stop=*) + ptts_stop="${arg/#-ptts-stop=/}" # bash parameter expansion, bash 3 and up + save_arg $arg + shift + ;; -ptts-report-flags=*) ptts_report_flags="${arg/#-ptts-report-flags=/}" # Also propper quoting must be used when multiple passed save_arg $arg @@ -566,6 +578,19 @@ for arg in "$@" ; do done export TAU_EXEC_PATH=${BASH_SOURCE[0]} +if [ "x$ptts_start" != "x" ]; then + ptts_sample_flags="$ptts_sample_flags --start-at-address $ptts_start" + ptts_restart=true +fi + +if [ "x$ptts_stop" != "x" ]; then + ptts_sample_flags="$ptts_sample_flags --stop-at-address $ptts_stop" + ptts_restart=true +fi + +if [ "x$ptts_restart" != "x" ]; then + ptts_sample_flags="$ptts_sample_flags --sample-restart" +fi # choose TAU library new_binding_options="" From 226cf8e8d6f4c28725c930dae126ee7119436f2b Mon Sep 17 00:00:00 2001 From: Nicholas Chaimov Date: Sat, 4 Aug 2018 14:20:52 -0700 Subject: [PATCH 54/60] Add -ptts-restart flag for manually instrumented PTTS Former-commit-id: a1f8301d092e09ac862301122ff9cc912ed75fb1 --- tools/src/tau_exec | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/src/tau_exec b/tools/src/tau_exec index a704d66da..54c83d2ea 100755 --- a/tools/src/tau_exec +++ b/tools/src/tau_exec @@ -56,6 +56,7 @@ usage() echo " -ptts-post Skip application sampling and post-process existing PTTS sample files" echo " -ptts-num= Number of ranks used for ThreadSpotter" echo " -ptts-sample-flags= Flags to pass to PTTS sample_ts command. Overrides TAU_TS_SAMPLE_FLAGS env. var." + echo " -ptts-restart Enable restart support within PTTS, allowing application to continue running and be reinstrumented after stop." echo " -ptts-start= Address at which to start a PTTS sampling region" echo " -ptts-stop= Address at which to stop a PTTS sampling region" echo " -ptts-report-flags= Flags to pass to PTTS report_ts command. Overrides TAU_TS_REPORT_FLAGS env. var." @@ -448,6 +449,11 @@ for arg in "$@" ; do save_arg $arg shift ;; + -ptts-restart) + ptts_restart="true" + save_arg $arg + shift + ;; -ptts-start=*) ptts_start="${arg/#-ptts-start=/}" # bash parameter expansion, bash 3 and up save_arg $arg From f1cda325bcc23ad3a4e56e5261df43f5fb1452a7 Mon Sep 17 00:00:00 2001 From: Sameer Shende Date: Sun, 5 Aug 2018 09:55:30 -0700 Subject: [PATCH 55/60] Updates ready for release. Former-commit-id: 7a984510faaf96c9326e8c0f0df4a34ce7e40021 --- Changes | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Changes b/Changes index b2d347e00..989d289b4 100644 --- a/Changes +++ b/Changes @@ -30,6 +30,12 @@ Version 2.27 changes (from 2.26): 17. Added support for LIKWID 4.3.2. 18. Added Python args support. 19. Added support for armflang and armclang/armclang++ compilers. +20. Added -dyninst=download option to simplify installation of DyninstAPI and use with TAU. +21. Updated support for TAU's OMPT TR6 (-download=ompt-tr6). +22. Updated TAU's ParaTools Threadspotter [www.threadspotter.com] support in tau_exec (-ptts). +23. Added support for IBM XL compilers with MVAPICH2 under IBM Power Linux Power 9 + GPU platform. +24. Updated MPC support in TAU. + Version 2.26 changes (from 2.25): 1. Upgraded OMPT to LLVM-0.2 and introduced TAU_OPENMP_RUNTIME_EVENTS=0. From 39805548bfce8135907e1514afba731f9432b8be Mon Sep 17 00:00:00 2001 From: Sameer Shende Date: Sun, 5 Aug 2018 13:48:22 -0700 Subject: [PATCH 56/60] Increased the sampling period for Python when not on a CRAY_CNL system. Earlier it was 10000, now it is 30000. This is needed for CANDLE ECP. Former-commit-id: e279088e660d7c719b29ed4cdcc3bcc6e449c958 --- src/Profile/TauEnv.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Profile/TauEnv.cpp b/src/Profile/TauEnv.cpp index 3e5da728a..f1670263a 100644 --- a/src/Profile/TauEnv.cpp +++ b/src/Profile/TauEnv.cpp @@ -116,6 +116,12 @@ using namespace std; #define TAU_EBS_PERIOD_DEFAULT 50000 // Sameer made this bigger, #else #define TAU_EBS_PERIOD_DEFAULT 10000 // Kevin made this bigger, + +#ifdef TAU_PYTHON +#undef TAU_EBS_PERIOD_DEFAULT +#define TAU_EBS_PERIOD_DEFAULT 30000 // Sameer made this bigger, +#endif /* TAU_PYTHON */ + #endif /* CRAYCNL */ #endif // because smaller causes problems sometimes. From 9ca0add9b5bcd31b5ebe16ce4e07f8c5e4eb582a Mon Sep 17 00:00:00 2001 From: Sameer Shende Date: Sun, 5 Aug 2018 20:53:11 -0700 Subject: [PATCH 57/60] A better python example. Calculates first prime number beyond a given number. Contribution by Devin Shende. Former-commit-id: 33664247ff797f5175f55bb767c4b3293a4020db --- examples/python/firstprime.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100755 examples/python/firstprime.py diff --git a/examples/python/firstprime.py b/examples/python/firstprime.py new file mode 100755 index 000000000..067dc671b --- /dev/null +++ b/examples/python/firstprime.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +#Program written by Devin Shende on August 5th 2018 + +def firstPrimeAfter(x): + import math + current = x + 1 + sqrtno = math.sqrt(current) + while True: + #search for primes starting at x until it finds one + #break once found a prime + for potentialfactor in range(2,current): + # start at 2 because 1 will always be a factor + # go all the way up to the sqrt of current looking for a factor + if current % potentialfactor == 0: + # Found factor. not prime + break # move on to next number + elif potentialfactor >= sqrtno: + print("The first prime number after {} is {}".format(x,current)) + return current + current += 1 + +firstPrimeAfter(10000000) + From f60c63ee8a1734a57f26a969888d5cd747d78216 Mon Sep 17 00:00:00 2001 From: Sameer Shende Date: Tue, 7 Aug 2018 06:04:05 -0700 Subject: [PATCH 58/60] Changed printf to TAU_VERBOSE for WEIRD CRAY line. Former-commit-id: fb9dba4ee80a8d0272a0ff216fb3a877a63020a9 --- src/Profile/TauMetaData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Profile/TauMetaData.cpp b/src/Profile/TauMetaData.cpp index 5998e97d6..65f931a20 100644 --- a/src/Profile/TauMetaData.cpp +++ b/src/Profile/TauMetaData.cpp @@ -814,7 +814,7 @@ extern "C" int writeMetaDataAfterMPI_Init(void) { } line = strtok(NULL, " "); - printf("WEIRD CRAY LINE: %s", line); + TAU_VERBOSE("WEIRD CRAY LINE: %s", line); Tau_metadata_register("CRAY_CORE_ID", line); } From a577feaa40ec42352640f57b55ae57b3c98dabc2 Mon Sep 17 00:00:00 2001 From: Sameer Shende Date: Tue, 7 Aug 2018 06:04:34 -0700 Subject: [PATCH 59/60] Removed printf. Former-commit-id: 4f3e5b609995c4981160137dd34399c0ddfc5b5b --- examples/mm/matmult.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/mm/matmult.c b/examples/mm/matmult.c index cdfef5b0e..ec47ad14a 100644 --- a/examples/mm/matmult.c +++ b/examples/mm/matmult.c @@ -357,9 +357,7 @@ int main (int argc, char *argv[]) #endif /* PTHREADS */ #ifdef TAU_MPI - fprintf(stdout, "mm: call before MPI_Finalize()\n"); MPI_Finalize(); - fprintf(stdout, "mm: call after MPI_Finalize()\n"); #endif /* TAU_MPI */ printf ("Done.\n"); From 045eebe78da458fd677b45435745a5b8c83990c2 Mon Sep 17 00:00:00 2001 From: Sameer Shende Date: Tue, 7 Aug 2018 15:40:00 -0500 Subject: [PATCH 60/60] Added -Werror for const error issue with LLVM underneath gcc on Mac. Former-commit-id: 8eb960d5fd9d5358845c6bae707a5ab44f5e1605 --- configure | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure b/configure index fe5f06f21..def478c66 100755 --- a/configure +++ b/configure @@ -6987,6 +6987,10 @@ if [ "x$mpiinc" != "x" -o "x$mpilib" != "x" -o $mpi = yes ] ; then mpiwarnings="-qhalt=w" fi if [ $c_compiler = "clang" -o $c_compiler = "armclang" ] + then + mpiwarnings="-Werror" + fi + if [ $c_compiler = "gcc" -a $machine = apple ] then mpiwarnings="-Werror" fi