Introduce timing interval measurement facility in timing framework
Этот коммит содержится в:
родитель
d6d69e2b13
Коммит
8ffad75a0a
@ -89,6 +89,7 @@
|
|||||||
#include "ompi/runtime/ompi_cr.h"
|
#include "ompi/runtime/ompi_cr.h"
|
||||||
|
|
||||||
extern bool ompi_enable_timing;
|
extern bool ompi_enable_timing;
|
||||||
|
extern bool ompi_enable_timing_ext;
|
||||||
|
|
||||||
int ompi_mpi_finalize(void)
|
int ompi_mpi_finalize(void)
|
||||||
{
|
{
|
||||||
@ -151,7 +152,7 @@ int ompi_mpi_finalize(void)
|
|||||||
opal_progress_event_users_increment();
|
opal_progress_event_users_increment();
|
||||||
|
|
||||||
/* check to see if we want timing information */
|
/* check to see if we want timing information */
|
||||||
OPAL_TIMING_EVENT((&tm,"Start barrier"));
|
OPAL_TIMING_MSTART((&tm,"time to execute finalize barrier"));
|
||||||
|
|
||||||
/* NOTE: MPI-2.1 requires that MPI_FINALIZE is "collective" across
|
/* NOTE: MPI-2.1 requires that MPI_FINALIZE is "collective" across
|
||||||
*all* connected processes. This only means that all processes
|
*all* connected processes. This only means that all processes
|
||||||
@ -232,8 +233,9 @@ int ompi_mpi_finalize(void)
|
|||||||
|
|
||||||
/* check for timing request - get stop time and report elapsed
|
/* check for timing request - get stop time and report elapsed
|
||||||
time if so */
|
time if so */
|
||||||
OPAL_TIMING_EVENT((&tm,"Finish barrier"));
|
OPAL_TIMING_MSTOP(&tm);
|
||||||
OPAL_TIMING_REPORT(ompi_enable_timing, &tm, "MPI_Finish");
|
OPAL_TIMING_DELTAS(ompi_enable_timing, &tm);
|
||||||
|
OPAL_TIMING_REPORT(ompi_enable_timing_ext, &tm);
|
||||||
OPAL_TIMING_RELEASE(&tm);
|
OPAL_TIMING_RELEASE(&tm);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -297,7 +297,7 @@ opal_hash_table_t ompi_mpi_f90_complex_hashtable;
|
|||||||
*/
|
*/
|
||||||
opal_list_t ompi_registered_datareps;
|
opal_list_t ompi_registered_datareps;
|
||||||
|
|
||||||
bool ompi_enable_timing;
|
bool ompi_enable_timing, ompi_enable_timing_ext;
|
||||||
extern bool ompi_mpi_yield_when_idle;
|
extern bool ompi_mpi_yield_when_idle;
|
||||||
extern int ompi_mpi_event_tick_rate;
|
extern int ompi_mpi_event_tick_rate;
|
||||||
|
|
||||||
@ -366,6 +366,13 @@ static int ompi_register_mca_variables(void)
|
|||||||
MCA_BASE_VAR_SCOPE_READONLY,
|
MCA_BASE_VAR_SCOPE_READONLY,
|
||||||
&ompi_enable_timing);
|
&ompi_enable_timing);
|
||||||
|
|
||||||
|
ompi_enable_timing_ext = false;
|
||||||
|
(void) mca_base_var_register("ompi", "ompi", NULL, "timing_ext",
|
||||||
|
"Request that critical timing loops be measured",
|
||||||
|
MCA_BASE_VAR_TYPE_BOOL, NULL, 0, 0,
|
||||||
|
OPAL_INFO_LVL_9,
|
||||||
|
MCA_BASE_VAR_SCOPE_READONLY,
|
||||||
|
&ompi_enable_timing_ext);
|
||||||
return OMPI_SUCCESS;
|
return OMPI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,7 +443,7 @@ int ompi_mpi_init(int argc, char **argv, int requested, int *provided)
|
|||||||
mca_base_var_set_value(ret, allvalue, 4, MCA_BASE_VAR_SOURCE_DEFAULT, NULL);
|
mca_base_var_set_value(ret, allvalue, 4, MCA_BASE_VAR_SOURCE_DEFAULT, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
OPAL_TIMING_EVENT((&tm,"Start"));
|
OPAL_TIMING_MSTART((&tm,"time from start to completion of rte_init"));
|
||||||
|
|
||||||
/* if we were not externally started, then we need to setup
|
/* if we were not externally started, then we need to setup
|
||||||
* some envars so the MPI_INFO_ENV can get the cmd name
|
* some envars so the MPI_INFO_ENV can get the cmd name
|
||||||
@ -470,7 +477,7 @@ int ompi_mpi_init(int argc, char **argv, int requested, int *provided)
|
|||||||
ompi_rte_initialized = true;
|
ompi_rte_initialized = true;
|
||||||
|
|
||||||
/* check for timing request - get stop time and report elapsed time if so */
|
/* check for timing request - get stop time and report elapsed time if so */
|
||||||
OPAL_TIMING_EVENT((&tm,"rte_init complete"));
|
OPAL_TIMING_MNEXT((&tm,"time from completion of rte_init to modex"));
|
||||||
|
|
||||||
#if OPAL_HAVE_HWLOC
|
#if OPAL_HAVE_HWLOC
|
||||||
/* if hwloc is available but didn't get setup for some
|
/* if hwloc is available but didn't get setup for some
|
||||||
@ -608,7 +615,7 @@ int ompi_mpi_init(int argc, char **argv, int requested, int *provided)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* check for timing request - get stop time and report elapsed time if so */
|
/* check for timing request - get stop time and report elapsed time if so */
|
||||||
OPAL_TIMING_EVENT((&tm,"Start modex"));
|
OPAL_TIMING_MNEXT((&tm,"time to execute modex"));
|
||||||
|
|
||||||
/* exchange connection info - this function may also act as a barrier
|
/* exchange connection info - this function may also act as a barrier
|
||||||
* if data exchange is required. The modex occurs solely across procs
|
* if data exchange is required. The modex occurs solely across procs
|
||||||
@ -617,7 +624,7 @@ int ompi_mpi_init(int argc, char **argv, int requested, int *provided)
|
|||||||
*/
|
*/
|
||||||
OPAL_FENCE(NULL, 0, NULL, NULL);
|
OPAL_FENCE(NULL, 0, NULL, NULL);
|
||||||
|
|
||||||
OPAL_TIMING_EVENT((&tm,"End modex"));
|
OPAL_TIMING_MNEXT((&tm,"time from modex to first barrier"));
|
||||||
|
|
||||||
/* select buffered send allocator component to be used */
|
/* select buffered send allocator component to be used */
|
||||||
if( OMPI_SUCCESS !=
|
if( OMPI_SUCCESS !=
|
||||||
@ -773,9 +780,8 @@ int ompi_mpi_init(int argc, char **argv, int requested, int *provided)
|
|||||||
/* Do we need to wait for a debugger? */
|
/* Do we need to wait for a debugger? */
|
||||||
ompi_rte_wait_for_debugger();
|
ompi_rte_wait_for_debugger();
|
||||||
|
|
||||||
/* check for timing request - get stop time and report elapsed
|
/* Next timing measurement */
|
||||||
time if so, then start the clock again */
|
OPAL_TIMING_MNEXT((&tm,"time to execute barrier"));
|
||||||
OPAL_TIMING_EVENT((&tm,"Start barrier"));
|
|
||||||
|
|
||||||
/* wait for everyone to reach this point - this is a hard
|
/* wait for everyone to reach this point - this is a hard
|
||||||
* barrier requirement at this time, though we hope to relax
|
* barrier requirement at this time, though we hope to relax
|
||||||
@ -784,7 +790,7 @@ int ompi_mpi_init(int argc, char **argv, int requested, int *provided)
|
|||||||
|
|
||||||
/* check for timing request - get stop time and report elapsed
|
/* check for timing request - get stop time and report elapsed
|
||||||
time if so, then start the clock again */
|
time if so, then start the clock again */
|
||||||
OPAL_TIMING_EVENT((&tm,"End barrier"));
|
OPAL_TIMING_MNEXT((&tm,"time from barrier to complete mpi_init"));
|
||||||
|
|
||||||
#if OPAL_ENABLE_PROGRESS_THREADS == 0
|
#if OPAL_ENABLE_PROGRESS_THREADS == 0
|
||||||
/* Start setting up the event engine for MPI operations. Don't
|
/* Start setting up the event engine for MPI operations. Don't
|
||||||
@ -853,8 +859,6 @@ int ompi_mpi_init(int argc, char **argv, int requested, int *provided)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Check whether we have been spawned or not. We introduce that
|
/* Check whether we have been spawned or not. We introduce that
|
||||||
at the very end, since we need collectives, datatypes, ptls
|
at the very end, since we need collectives, datatypes, ptls
|
||||||
etc. up and running here.... */
|
etc. up and running here.... */
|
||||||
@ -930,9 +934,11 @@ int ompi_mpi_init(int argc, char **argv, int requested, int *provided)
|
|||||||
|
|
||||||
ompi_mpi_initialized = true;
|
ompi_mpi_initialized = true;
|
||||||
|
|
||||||
/* check for timing request - get stop time and report elapsed time if so */
|
/* Finish last measurement, output results
|
||||||
OPAL_TIMING_EVENT((&tm,"Finish"));
|
* and clear timing structure */
|
||||||
OPAL_TIMING_REPORT(ompi_enable_timing, &tm,"MPI Init");
|
OPAL_TIMING_MSTOP(&tm);
|
||||||
|
OPAL_TIMING_DELTAS(ompi_enable_timing, &tm);
|
||||||
|
OPAL_TIMING_REPORT(ompi_enable_timing_ext, &tm);
|
||||||
OPAL_TIMING_RELEASE(&tm);
|
OPAL_TIMING_RELEASE(&tm);
|
||||||
|
|
||||||
return MPI_SUCCESS;
|
return MPI_SUCCESS;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
#!/bin/sh
|
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#
|
#
|
||||||
# Copyright (c) 2014 Artem Polyakov <artpol84@gmail.com>
|
# Copyright (c) 2014 Artem Polyakov <artpol84@gmail.com>
|
||||||
@ -54,8 +53,8 @@ syncfile=`pwd`"/ompi_clock_sync_data.$jobid"
|
|||||||
tmp_timings=`pwd`"/ompi_timing_temp_file.$jobid"
|
tmp_timings=`pwd`"/ompi_timing_temp_file.$jobid"
|
||||||
tmp_out=`pwd`"/ompi_mpirun_prof.$jobid"
|
tmp_out=`pwd`"/ompi_mpirun_prof.$jobid"
|
||||||
|
|
||||||
timing_bkp=$OMPI_MCA_opal_timing_file
|
timing_bkp=$OMPI_MCA_opal_timing_output
|
||||||
export OMPI_MCA_opal_timing_file=$tmp_timings
|
export OMPI_MCA_opal_timing_output=$tmp_timings
|
||||||
|
|
||||||
opts=`extract_nodeset_opts $@`
|
opts=`extract_nodeset_opts $@`
|
||||||
${ompi_instdir}/mpirun --npernode 1 $opts ${ompi_instdir}/mpisync -o $syncfile >$tmp_out 2>&1
|
${ompi_instdir}/mpirun --npernode 1 $opts ${ompi_instdir}/mpisync -o $syncfile >$tmp_out 2>&1
|
||||||
|
@ -10,45 +10,49 @@
|
|||||||
#####################################################################
|
#####################################################################
|
||||||
# Evaluate a floating point number expression.
|
# Evaluate a floating point number expression.
|
||||||
|
|
||||||
function float_eval(){
|
|
||||||
float_scale=9
|
|
||||||
local stat=0
|
|
||||||
local result=0.0
|
|
||||||
if [[ $# -gt 0 ]]; then
|
|
||||||
result=$(echo "scale=$float_scale; $*" | bc -q 2>/dev/null)
|
|
||||||
stat=$?
|
|
||||||
if [[ $stat -eq 0 && -z "$result" ]]; then
|
|
||||||
stat=1;
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo $result
|
|
||||||
return $stat
|
|
||||||
}
|
|
||||||
|
|
||||||
if [ -z "$1" ] || [ -z "$2" ]; then
|
if [ -z "$1" ] || [ -z "$2" ]; then
|
||||||
echo "Need the name of a timing file and the output file"
|
echo "Need the name of a timing file and the output file"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
thefile=$1
|
initfile=$1
|
||||||
postfile=$2
|
postfile=$2
|
||||||
sed '/^$/d' $thefile > ${thefile}_tmp
|
|
||||||
sort ${thefile}_tmp > ${postfile}
|
|
||||||
|
|
||||||
read line < ${postfile}
|
# 1. Filter OPAL_TRACE entrieas only
|
||||||
first_ts=`echo $line | awk '{ print $1 }' | sed -e 's/s//'`
|
# and put the timestamp to the first place
|
||||||
prev_ts=$first_ts
|
#.2. Sort considering that we dealing with
|
||||||
echo $first_ts
|
# floating point numbers
|
||||||
|
# 3. Return to initial field order and count relative fields
|
||||||
|
cat $initfile | \
|
||||||
|
awk 'BEGIN { FPAT = "([^ ]+)|(\"[^\"]+\")" }
|
||||||
|
{
|
||||||
|
if( $0 ~ /\[OPAL_TRACE\]/ ){
|
||||||
|
x = $NF
|
||||||
|
$NF = $1
|
||||||
|
$1 = x
|
||||||
|
print $0
|
||||||
|
}
|
||||||
|
}' | sort --general-numeric-sort | \
|
||||||
|
awk 'BEGIN {
|
||||||
|
FPAT = "([^ ]+)|(\"[^\"]+\")"
|
||||||
|
first = 0
|
||||||
|
prev = 0
|
||||||
|
}
|
||||||
|
{
|
||||||
|
if( first == 0 ){
|
||||||
|
first = $1
|
||||||
|
prev = $1
|
||||||
|
}
|
||||||
|
x = $1
|
||||||
|
$1 = $NF
|
||||||
|
$NF = x
|
||||||
|
rel_to_first = x - first
|
||||||
|
rel_to_prev = x - prev
|
||||||
|
prev = x
|
||||||
|
print $0, " ", rel_to_prev, " ", rel_to_first
|
||||||
|
}' > $postfile
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
while read line ; do
|
|
||||||
cur_ts=`echo $line | awk '{ print $1 }' | sed -e 's/s//'`
|
|
||||||
dif1=`float_eval "$cur_ts - $first_ts"`
|
|
||||||
dif2=`float_eval "$cur_ts - $prev_ts"`
|
|
||||||
newline=`echo $line | sed -e "s/$cur_ts/$dif1:$dif2/"`
|
|
||||||
prev_ts=$cur_ts
|
|
||||||
echo $newline
|
|
||||||
done < ${postfile} > ${thefile}_tmp
|
|
||||||
|
|
||||||
cat ${thefile}_tmp > ${postfile}
|
|
||||||
|
|
||||||
rm -f ${thefile}_tmp
|
|
||||||
|
@ -38,21 +38,31 @@
|
|||||||
#include "opal/class/opal_list.h"
|
#include "opal/class/opal_list.h"
|
||||||
#include "opal/util/timings.h"
|
#include "opal/util/timings.h"
|
||||||
#include "opal/util/output.h"
|
#include "opal/util/output.h"
|
||||||
|
#include "opal/util/basename.h"
|
||||||
|
#include "opal/mca/timer/timer.h"
|
||||||
|
|
||||||
|
#include MCA_timer_IMPLEMENTATION_HEADER
|
||||||
|
|
||||||
|
#define DELTAS_SANE_LIMIT (10*1024*1024)
|
||||||
|
|
||||||
|
/*
|
||||||
static void debug_hang(int i)
|
static void debug_hang(int i)
|
||||||
{
|
{
|
||||||
while( i ){
|
while( i ){
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct interval_descr{
|
||||||
|
opal_timing_event_t *descr_ev, *begin_ev;
|
||||||
|
double interval, overhead;
|
||||||
|
};
|
||||||
|
|
||||||
double opal_timing_get_ts(void);
|
|
||||||
opal_timing_event_t *opal_timing_event_alloc(opal_timing_t *t);
|
opal_timing_event_t *opal_timing_event_alloc(opal_timing_t *t);
|
||||||
void opal_timing_init(opal_timing_t *t);
|
void opal_timing_init(opal_timing_t *t);
|
||||||
opal_timing_prep_t opal_timing_prep_ev(opal_timing_t *t, const char *fmt, ...);
|
opal_timing_prep_t opal_timing_prep_ev(opal_timing_t *t, const char *fmt, ...);
|
||||||
|
|
||||||
void opal_timing_release(opal_timing_t *t);
|
|
||||||
|
|
||||||
static OBJ_CLASS_INSTANCE(opal_timing_event_t, opal_list_item_t, NULL, NULL);
|
static OBJ_CLASS_INSTANCE(opal_timing_event_t, opal_list_item_t, NULL, NULL);
|
||||||
|
|
||||||
|
|
||||||
@ -71,12 +81,13 @@ int opal_timing_clocksync_read(char *fname)
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
char *ptr = NULL;
|
char *ptr = NULL;
|
||||||
|
|
||||||
char hname[1024];
|
char hname[1024] = "NA";
|
||||||
if( gethostname(hname, 1024) ){
|
if( gethostname(hname, 1024) ){
|
||||||
opal_output(0, "opal_timing_clocksync_read(%s): Cannot gethostname\n",fname);
|
opal_output(0, "opal_timing_clocksync_read(%s): Cannot gethostname",
|
||||||
return OPAL_ERROR;
|
fname);
|
||||||
}
|
}
|
||||||
nodename = strdup(hname);
|
nodename = strdup(hname);
|
||||||
|
// Strip domain name
|
||||||
ptr = strchr(nodename,'.');
|
ptr = strchr(nodename,'.');
|
||||||
if( ptr != NULL ){
|
if( ptr != NULL ){
|
||||||
*ptr = '\0';
|
*ptr = '\0';
|
||||||
@ -88,7 +99,7 @@ int opal_timing_clocksync_read(char *fname)
|
|||||||
|
|
||||||
fp = fopen(fname,"r");
|
fp = fopen(fname,"r");
|
||||||
if( fp == NULL ){
|
if( fp == NULL ){
|
||||||
opal_output(0, "opal_timing_clocksync_read(%s): Cannot open the file\n",fname);
|
opal_output(0, "opal_timing_clocksync_read(%s): Cannot open the file",fname);
|
||||||
return OPAL_ERROR;
|
return OPAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +122,7 @@ int opal_timing_clocksync_read(char *fname)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( !found ){
|
if( !found ){
|
||||||
opal_output(0,"opal_timing_clocksync_read: Can't find my host %s in %s\n", hname, fname);
|
opal_output(0,"opal_timing_clocksync_read: Can't find my host %s in %s", hname, fname);
|
||||||
rc = OPAL_ERROR;
|
rc = OPAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,28 +147,58 @@ int opal_timing_set_jobid(char *jid)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get current timestamp */
|
/* Get current timestamp. Derived from MPI_Wtime */
|
||||||
double opal_timing_get_ts(void){
|
|
||||||
|
static double get_ts_gettimeofday(void)
|
||||||
|
{
|
||||||
|
double ret;
|
||||||
|
/* Use gettimeofday() if we opal wasn't initialized */
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
double ret = tv.tv_sec + tv.tv_usec*1E-6;
|
ret = tv.tv_sec;
|
||||||
|
ret += (double)tv.tv_usec / 1000000.0;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OPAL_TIMER_CYCLE_NATIVE
|
||||||
|
static double get_ts_cycle(void)
|
||||||
|
{
|
||||||
|
return ((double) opal_timer_base_get_cycles()) / opal_timer_base_get_freq();
|
||||||
|
}
|
||||||
|
#elif OPAL_TIMER_USEC_NATIVE
|
||||||
|
static double get_ts_usec(void)
|
||||||
|
{
|
||||||
|
return ((double) opal_timer_base_get_usec()) / 1000000.0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static get_ts_t _init_timestamping(void)
|
||||||
|
{
|
||||||
|
if( !opal_initialized ){
|
||||||
|
return get_ts_gettimeofday;
|
||||||
|
}
|
||||||
|
#if OPAL_TIMER_CYCLE_NATIVE
|
||||||
|
return get_ts_cycle;
|
||||||
|
#elif OPAL_TIMER_USEC_NATIVE
|
||||||
|
return get_ts_usec;
|
||||||
|
#endif
|
||||||
|
return get_ts_gettimeofday;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
opal_timing_event_t *opal_timing_event_alloc(opal_timing_t *t)
|
opal_timing_event_t *opal_timing_event_alloc(opal_timing_t *t)
|
||||||
{
|
{
|
||||||
if( t->buffer_offset >= t->buffer_size ){
|
if( t->buffer_offset >= t->buffer_size ){
|
||||||
// notch timings overhead
|
// notch timings overhead
|
||||||
double alloc_begin = opal_timing_get_ts();
|
double alloc_begin = t->get_ts();
|
||||||
|
|
||||||
t->buffer = malloc(sizeof(opal_timing_event_t)*t->buffer_size);
|
t->buffer = malloc(sizeof(opal_timing_event_t)*t->buffer_size);
|
||||||
if( t->buffer == NULL ){
|
if( t->buffer == NULL ){
|
||||||
opal_output(0, "opal_timing_event_alloc: Out of memory!\n");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset(t->buffer, 0, sizeof(opal_timing_event_t)*t->buffer_size);
|
memset(t->buffer, 0, sizeof(opal_timing_event_t)*t->buffer_size);
|
||||||
|
|
||||||
double alloc_end = opal_timing_get_ts();
|
double alloc_end = t->get_ts();
|
||||||
|
|
||||||
t->buffer_offset = 0;
|
t->buffer_offset = 0;
|
||||||
t->buffer[0].fib = 1;
|
t->buffer[0].fib = 1;
|
||||||
@ -172,16 +213,18 @@ void opal_timing_init(opal_timing_t *t)
|
|||||||
{
|
{
|
||||||
memset(t,0,sizeof(*t));
|
memset(t,0,sizeof(*t));
|
||||||
|
|
||||||
t->cur_id = 0;
|
t->next_id_cntr = 0;
|
||||||
// initialize events list
|
t->current_id = -1;
|
||||||
|
/* initialize events list */
|
||||||
t->events = OBJ_NEW(opal_list_t);
|
t->events = OBJ_NEW(opal_list_t);
|
||||||
// Set buffer size
|
/* Set buffer size */
|
||||||
t->buffer_size = OPAL_TIMING_BUFSIZE;
|
t->buffer_size = OPAL_TIMING_BUFSIZE;
|
||||||
// Set buffer_offset = buffer_size so new buffer
|
/* Set buffer_offset = buffer_size so new buffer
|
||||||
// will be allocated at first event report
|
* will be allocated at first event report */
|
||||||
t->buffer_offset = t->buffer_size;
|
t->buffer_offset = t->buffer_size;
|
||||||
|
/* initialize gettime function */
|
||||||
|
t->get_ts = _init_timestamping();
|
||||||
|
|
||||||
OPAL_TIMING_EVENT((t,"%p: Created, events = %p, buffer: ptr = %p, offs = %d", t, t->events, t->buffer, t->buffer_size));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
opal_timing_prep_t opal_timing_prep_ev(opal_timing_t *t, const char *fmt, ...)
|
opal_timing_prep_t opal_timing_prep_ev(opal_timing_t *t, const char *fmt, ...)
|
||||||
@ -192,7 +235,7 @@ opal_timing_prep_t opal_timing_prep_ev(opal_timing_t *t, const char *fmt, ...)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
OBJ_CONSTRUCT(ev, opal_timing_event_t);
|
OBJ_CONSTRUCT(ev, opal_timing_event_t);
|
||||||
ev->ts = opal_timing_get_ts();
|
ev->ts = t->get_ts();
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start( args, fmt );
|
va_start( args, fmt );
|
||||||
vsnprintf(ev->descr, OPAL_TIMING_DESCR_MAX - 1, fmt, args);
|
vsnprintf(ev->descr, OPAL_TIMING_DESCR_MAX - 1, fmt, args);
|
||||||
@ -202,6 +245,23 @@ opal_timing_prep_t opal_timing_prep_ev(opal_timing_t *t, const char *fmt, ...)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opal_timing_prep_t opal_timing_prep_ev_end(opal_timing_t *t, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
opal_timing_prep_t p = { t, NULL, 0 };
|
||||||
|
|
||||||
|
if( t->current_id >= 0 ){
|
||||||
|
opal_timing_event_t *ev = opal_timing_event_alloc(t);
|
||||||
|
if( ev == NULL ){
|
||||||
|
opal_timing_prep_t p = { t, NULL, OPAL_ERR_OUT_OF_RESOURCE };
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
OBJ_CONSTRUCT(ev, opal_timing_event_t);
|
||||||
|
ev->ts = t->get_ts();
|
||||||
|
p.ev = ev;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
void opal_timing_add_step(opal_timing_prep_t p,
|
void opal_timing_add_step(opal_timing_prep_t p,
|
||||||
const char *func, const char *file, int line)
|
const char *func, const char *file, int line)
|
||||||
{
|
{
|
||||||
@ -209,35 +269,184 @@ void opal_timing_add_step(opal_timing_prep_t p,
|
|||||||
p.ev->func = func;
|
p.ev->func = func;
|
||||||
p.ev->file = file;
|
p.ev->file = file;
|
||||||
p.ev->line = line;
|
p.ev->line = line;
|
||||||
p.ev->type = TEVENT;
|
p.ev->type = OPAL_TIMING_TRACE;
|
||||||
opal_list_append(p.t->events, (opal_list_item_t*)p.ev);
|
opal_list_append(p.t->events, (opal_list_item_t*)p.ev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int opal_timing_report(opal_timing_t *t, bool account_overhead, const char *prefix, char *fname)
|
/* Add description of the interval */
|
||||||
|
int opal_timing_descr(opal_timing_prep_t p,
|
||||||
|
const char *func, const char *file, int line)
|
||||||
|
{
|
||||||
|
if( !p.errcode ){
|
||||||
|
p.ev->func = func;
|
||||||
|
p.ev->file = file;
|
||||||
|
p.ev->line = line;
|
||||||
|
p.ev->type = OPAL_TIMING_INTDESCR;
|
||||||
|
p.ev->id = p.t->next_id_cntr;
|
||||||
|
(p.t->next_id_cntr)++;
|
||||||
|
opal_list_append(p.t->events, (opal_list_item_t*)p.ev);
|
||||||
|
return p.ev->id;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void opal_timing_start_id(opal_timing_t *t, int id, const char *func, const char *file, int line)
|
||||||
|
{
|
||||||
|
/* No description is needed. If everything is OK
|
||||||
|
* it'll be included in opal_timing_start_init */
|
||||||
|
opal_timing_event_t *ev = opal_timing_event_alloc(t);
|
||||||
|
if( ev == NULL ){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OBJ_CONSTRUCT(ev, opal_timing_event_t);
|
||||||
|
|
||||||
|
t->current_id = id;
|
||||||
|
ev->ts = t->get_ts();
|
||||||
|
ev->func = func;
|
||||||
|
ev->file = file;
|
||||||
|
ev->line = line;
|
||||||
|
ev->type = OPAL_TIMING_INTBEGIN;
|
||||||
|
ev->id = id;
|
||||||
|
opal_list_append(t->events, (opal_list_item_t*)ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void opal_timing_end(opal_timing_t *t, int id, const char *func, const char *file, int line )
|
||||||
|
{
|
||||||
|
/* No description is needed. If everything is OK
|
||||||
|
* it'll be included in opal_timing_start_init */
|
||||||
|
opal_timing_event_t *ev = opal_timing_event_alloc(t);
|
||||||
|
if( ev == NULL ){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OBJ_CONSTRUCT(ev, opal_timing_event_t);
|
||||||
|
|
||||||
|
if( id < 0 ){
|
||||||
|
ev->id = t->current_id;
|
||||||
|
t->current_id = -1;
|
||||||
|
} else {
|
||||||
|
if( t->current_id == id ){
|
||||||
|
t->current_id = -1;
|
||||||
|
}
|
||||||
|
ev->id = id;
|
||||||
|
}
|
||||||
|
ev->ts = t->get_ts();
|
||||||
|
ev->func = func;
|
||||||
|
ev->file = file;
|
||||||
|
ev->line = line;
|
||||||
|
ev->type = OPAL_TIMING_INTEND;
|
||||||
|
opal_list_append(t->events, (opal_list_item_t*)ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void opal_timing_end_prep(opal_timing_prep_t p,
|
||||||
|
const char *func, const char *file, int line)
|
||||||
|
{
|
||||||
|
opal_timing_event_t *ev = p.ev;
|
||||||
|
|
||||||
|
if( !p.errcode && ( NULL != ev ) ){
|
||||||
|
assert( p.t->current_id >=0 );
|
||||||
|
ev->id = p.t->current_id;
|
||||||
|
p.t->current_id = -1;
|
||||||
|
ev->func = func;
|
||||||
|
ev->file = file;
|
||||||
|
ev->line = line;
|
||||||
|
ev->type = OPAL_TIMING_INTEND;
|
||||||
|
opal_list_append(p.t->events, (opal_list_item_t*)ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _prepare_descriptions(opal_timing_t *t, struct interval_descr **__descr)
|
||||||
|
{
|
||||||
|
struct interval_descr *descr;
|
||||||
|
opal_timing_event_t *ev, *next;
|
||||||
|
|
||||||
|
if( t->next_id_cntr == 0 ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*__descr = malloc(sizeof(struct interval_descr) * t->next_id_cntr);
|
||||||
|
descr = *__descr;
|
||||||
|
memset(descr, 0, sizeof(struct interval_descr) * t->next_id_cntr);
|
||||||
|
|
||||||
|
OPAL_LIST_FOREACH_SAFE(ev, next, t->events, opal_timing_event_t){
|
||||||
|
|
||||||
|
/* opal_output(0,"EVENT: type = %d, id=%d, ts = %.12le, ovh = %.12le %s",
|
||||||
|
ev->type, ev->id, ev->ts, ev->ts_ovh,
|
||||||
|
ev->descr );
|
||||||
|
*/
|
||||||
|
switch(ev->type){
|
||||||
|
case OPAL_TIMING_INTDESCR:{
|
||||||
|
if( ev->id >= t->next_id_cntr){
|
||||||
|
char *file = opal_basename(ev->file);
|
||||||
|
opal_output(0,"opal_timing: bad event id at %s:%d:%s, ignore and remove",
|
||||||
|
file, ev->line, ev->func);
|
||||||
|
free(file);
|
||||||
|
opal_list_remove_item(t->events, (opal_list_item_t *)ev);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if( NULL != descr[ev->id].descr_ev ){
|
||||||
|
opal_timing_event_t *prev = descr[ev->id].descr_ev;
|
||||||
|
char *file = opal_basename(ev->file);
|
||||||
|
char *file_prev = opal_basename(prev->file);
|
||||||
|
opal_output(0,"opal_timing: duplicated description at %s:%d:%s, "
|
||||||
|
"previous: %s:%d:%s, ignore and remove", file, ev->line, ev->func,
|
||||||
|
file_prev, prev->line, prev->func);
|
||||||
|
free(file);
|
||||||
|
free(file_prev);
|
||||||
|
opal_list_remove_item(t->events, (opal_list_item_t *)ev);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
descr[ev->id].descr_ev = ev;
|
||||||
|
descr[ev->id].begin_ev = NULL;
|
||||||
|
descr[ev->id].interval = 0;
|
||||||
|
descr[ev->id].overhead = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OPAL_TIMING_INTBEGIN:
|
||||||
|
case OPAL_TIMING_INTEND:{
|
||||||
|
if( ev->id >= t->next_id_cntr || (NULL == descr[ev->id].descr_ev ) ){
|
||||||
|
char *file = opal_basename(ev->file);
|
||||||
|
opal_output(0,"opal_timing: bad event id at %s:%d:%s, ignore and remove",
|
||||||
|
file, ev->line, ev->func);
|
||||||
|
free(file);
|
||||||
|
opal_list_remove_item(t->events, (opal_list_item_t *)ev);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OPAL_TIMING_TRACE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t->next_id_cntr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output lines in portions that doesn't
|
||||||
|
* exceed OPAL_TIMING_OUTBUF_SIZE for later automatic processing */
|
||||||
|
int opal_timing_report(opal_timing_t *t, char *fname)
|
||||||
{
|
{
|
||||||
opal_timing_event_t *ev;
|
opal_timing_event_t *ev;
|
||||||
int count = 0;
|
|
||||||
FILE *fp = NULL;
|
FILE *fp = NULL;
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
int buf_size = 0;
|
int buf_size = 0;
|
||||||
|
struct interval_descr *descr = NULL;
|
||||||
int rc = OPAL_SUCCESS;
|
int rc = OPAL_SUCCESS;
|
||||||
|
|
||||||
debug_hang(0);
|
|
||||||
|
|
||||||
if( fname != NULL ){
|
if( fname != NULL ){
|
||||||
fp = fopen(fname,"a");
|
fp = fopen(fname,"a");
|
||||||
if( fp == NULL ){
|
if( fp == NULL ){
|
||||||
opal_output(0, "opal_timing_report: Cannot open %s file for writing timing information!\n",fname);
|
opal_output(0, "opal_timing_report: Cannot open %s file"
|
||||||
|
" for writing timing information!",fname);
|
||||||
rc = OPAL_ERROR;
|
rc = OPAL_ERROR;
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
prefix=NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_prepare_descriptions(t, &descr);
|
||||||
|
|
||||||
buf = malloc(OPAL_TIMING_OUTBUF_SIZE+1);
|
buf = malloc(OPAL_TIMING_OUTBUF_SIZE+1);
|
||||||
if( buf == NULL ){
|
if( buf == NULL ){
|
||||||
opal_output(0, "opal_timing_report: Out of memory!\n");
|
|
||||||
rc = OPAL_ERR_OUT_OF_RESOURCE;
|
rc = OPAL_ERR_OUT_OF_RESOURCE;
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
@ -245,42 +454,45 @@ int opal_timing_report(opal_timing_t *t, bool account_overhead, const char *pref
|
|||||||
|
|
||||||
double overhead = 0;
|
double overhead = 0;
|
||||||
OPAL_LIST_FOREACH(ev, t->events, opal_timing_event_t){
|
OPAL_LIST_FOREACH(ev, t->events, opal_timing_event_t){
|
||||||
count++;
|
char *line, *file;
|
||||||
if( ev->fib && account_overhead ){
|
if( ev->fib && opal_timing_overhead ){
|
||||||
overhead += ev->ts_ovh;
|
overhead += ev->ts_ovh;
|
||||||
}
|
}
|
||||||
|
file = opal_basename(ev->file);
|
||||||
|
switch( ev->type ){
|
||||||
|
case OPAL_TIMING_INTDESCR:
|
||||||
|
// Service event, skip it.
|
||||||
|
continue;
|
||||||
|
case OPAL_TIMING_TRACE:
|
||||||
|
rc = asprintf(&line,"[%s:%d] %s \"%s\" [OPAL_TRACE] %s:%d %.10lf\n",
|
||||||
|
nodename, getpid(), jobid, ev->descr, file, ev->line,
|
||||||
|
ev->ts + hnp_offs + overhead);
|
||||||
|
break;
|
||||||
|
case OPAL_TIMING_INTBEGIN:
|
||||||
|
rc = asprintf(&line,"[%s:%d] %s \"%s [start]\" [OPAL_TRACE] %s:%d %.10lf\n",
|
||||||
|
nodename, getpid(), jobid, descr[ev->id].descr_ev->descr,
|
||||||
|
file, ev->line, ev->ts + hnp_offs + overhead);
|
||||||
|
break;
|
||||||
|
case OPAL_TIMING_INTEND:
|
||||||
|
rc = asprintf(&line,"[%s:%d] %s \"%s [stop]\" [OPAL_TRACE] %s:%d %.10lf\n",
|
||||||
|
nodename, getpid(), jobid, descr[ev->id].descr_ev->descr,
|
||||||
|
file, ev->line, ev->ts + hnp_offs + overhead);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(file);
|
||||||
|
|
||||||
if( count > 1){
|
|
||||||
char *line;
|
|
||||||
const char *file_name = ev->file;
|
|
||||||
const char *ptr = file_name;
|
|
||||||
for( ; *ptr != '\0' ; ptr++ ){
|
|
||||||
if( *ptr == '/'){
|
|
||||||
file_name = ptr+1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( prefix != NULL ){
|
|
||||||
rc = asprintf(&line,"%s:\t%lfs\t\"%s\"\t|\t%s\t%s\t%s\t%s:%d\n",
|
|
||||||
prefix,ev->ts + hnp_offs + overhead,
|
|
||||||
ev->descr, nodename, jobid, ev->func, file_name, ev->line);
|
|
||||||
} else {
|
|
||||||
rc = asprintf(&line,"%lfs\t\"%s\"\t|\t%s\t%s\t%s\t%s:%d\n",
|
|
||||||
ev->ts + hnp_offs + overhead,
|
|
||||||
ev->descr, nodename, jobid, ev->func, file_name, ev->line);
|
|
||||||
}
|
|
||||||
if( rc < 0 ){
|
if( rc < 0 ){
|
||||||
opal_output(0, "opal_timing_report: Cannot asprintf!\n");
|
|
||||||
rc = OPAL_ERR_OUT_OF_RESOURCE;
|
rc = OPAL_ERR_OUT_OF_RESOURCE;
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
rc = 0;
|
rc = 0;
|
||||||
|
|
||||||
if( strlen(line) > OPAL_TIMING_OUTBUF_SIZE ){
|
/* Sanity check: this shouldn't happen since description
|
||||||
opal_output(0, "opal_timing_report: timing output buffer overflow!\n");
|
* is event only 1KB long and other fields should never
|
||||||
free(line);
|
* exceed 9KB */
|
||||||
rc = OPAL_ERR_OUT_OF_RESOURCE;
|
assert( strlen(line) <= OPAL_TIMING_OUTBUF_SIZE );
|
||||||
goto err_exit;
|
|
||||||
}
|
|
||||||
if( buf_size + strlen(line) > OPAL_TIMING_OUTBUF_SIZE ){
|
if( buf_size + strlen(line) > OPAL_TIMING_OUTBUF_SIZE ){
|
||||||
// flush buffer to the file
|
// flush buffer to the file
|
||||||
if( fp != NULL ){
|
if( fp != NULL ){
|
||||||
@ -296,7 +508,6 @@ int opal_timing_report(opal_timing_t *t, bool account_overhead, const char *pref
|
|||||||
buf_size += strlen(line);
|
buf_size += strlen(line);
|
||||||
free(line);
|
free(line);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if( buf_size > 0 ){
|
if( buf_size > 0 ){
|
||||||
// flush buffer to the file
|
// flush buffer to the file
|
||||||
@ -311,6 +522,9 @@ int opal_timing_report(opal_timing_t *t, bool account_overhead, const char *pref
|
|||||||
}
|
}
|
||||||
|
|
||||||
err_exit:
|
err_exit:
|
||||||
|
if( NULL != descr ){
|
||||||
|
free(descr);
|
||||||
|
}
|
||||||
if( buf != NULL ){
|
if( buf != NULL ){
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
@ -321,6 +535,186 @@ err_exit:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Output events as one buffer so the data won't be mixed
|
||||||
|
* with other output. This function is supposed to be human readable.
|
||||||
|
* The output goes only to stdout. */
|
||||||
|
int opal_timing_deltas(opal_timing_t *t, char *fname)
|
||||||
|
{
|
||||||
|
opal_timing_event_t *ev;
|
||||||
|
FILE *fp = NULL;
|
||||||
|
char *buf = NULL;
|
||||||
|
struct interval_descr *descr = NULL;
|
||||||
|
int i, rc = OPAL_SUCCESS;
|
||||||
|
size_t buf_size = 0, buf_used = 0;
|
||||||
|
|
||||||
|
if( fname != NULL ){
|
||||||
|
fp = fopen(fname,"a");
|
||||||
|
if( fp == NULL ){
|
||||||
|
opal_output(0, "opal_timing_report: Cannot open %s file"
|
||||||
|
" for writing timing information!",fname);
|
||||||
|
rc = OPAL_ERROR;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_prepare_descriptions(t, &descr);
|
||||||
|
|
||||||
|
OPAL_LIST_FOREACH(ev, t->events, opal_timing_event_t){
|
||||||
|
int id;
|
||||||
|
if( ev->fib ){
|
||||||
|
/* this event caused buffered memory allocation
|
||||||
|
* for events. Account the overhead for all active
|
||||||
|
* intervals. */
|
||||||
|
int i;
|
||||||
|
for( i = 0; i < t->next_id_cntr; i++){
|
||||||
|
if( (NULL != descr[i].descr_ev) && (NULL != descr[i].begin_ev) ){
|
||||||
|
if( opal_timing_overhead ){
|
||||||
|
descr[i].overhead += ev->ts_ovh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we already process all OPAL_TIMING_DESCR events
|
||||||
|
* and we ignore OPAL_TIMING_EVENT */
|
||||||
|
if( ev->type == OPAL_TIMING_INTDESCR ||
|
||||||
|
ev->type == OPAL_TIMING_TRACE){
|
||||||
|
/* skip */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = ev->id;
|
||||||
|
if( id < 0 || id >= t->next_id_cntr ){
|
||||||
|
char *file = opal_basename(ev->file);
|
||||||
|
opal_output(0,"opal_timing_deltas: bad interval event id: %d at %s:%d:%s (maxid=%d)",
|
||||||
|
id, file, ev->line, ev->func, t->next_id_cntr - 1 );
|
||||||
|
free(file);
|
||||||
|
/* skip */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* id's assigned auomatically. Ther shouldn't be any gaps in descr[] */
|
||||||
|
assert( NULL != descr[id].descr_ev);
|
||||||
|
|
||||||
|
if( ev->type == OPAL_TIMING_INTBEGIN ){
|
||||||
|
if( NULL != descr[id].begin_ev ){
|
||||||
|
/* the measurement on this interval was already
|
||||||
|
* started! */
|
||||||
|
opal_timing_event_t *prev = descr[ev->id].begin_ev;
|
||||||
|
char *file = opal_basename(ev->file);
|
||||||
|
char *file_prev = opal_basename(prev->file);
|
||||||
|
opal_output(0,"opal_timing_deltas: duplicated start statement at %s:%d:%s, "
|
||||||
|
"previous: %s:%d:%s", file, ev->line, ev->func,
|
||||||
|
file_prev, prev->line, prev->func);
|
||||||
|
free(file);
|
||||||
|
free(file_prev);
|
||||||
|
} else {
|
||||||
|
/* save pointer to the start of measurement event */
|
||||||
|
descr[id].begin_ev = ev;
|
||||||
|
}
|
||||||
|
/* done, go to the next event */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ev->type == OPAL_TIMING_INTEND ){
|
||||||
|
if( NULL == descr[id].begin_ev ){
|
||||||
|
/* the measurement on this interval wasn't started! */
|
||||||
|
char *file = opal_basename(ev->file);
|
||||||
|
opal_output(0,"opal_timing_deltas: inteval end without start at %s:%d:%s",
|
||||||
|
file, ev->line, ev->func );
|
||||||
|
free(file);
|
||||||
|
} else {
|
||||||
|
descr[id].interval += ev->ts - descr[id].begin_ev->ts;
|
||||||
|
descr[id].begin_ev = NULL;
|
||||||
|
if( ev->fib ){
|
||||||
|
descr[id].overhead += ev->ts_ovh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* shouldn't ever get here: bad ev->type */
|
||||||
|
opal_output(0, "opal_timing_deltas: bad event type %d", ev->type);
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = malloc(OPAL_TIMING_OUTBUF_SIZE + 1);
|
||||||
|
if( buf == NULL ){
|
||||||
|
rc = OPAL_ERR_OUT_OF_RESOURCE;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
buf[0] = '\0';
|
||||||
|
buf_size = OPAL_TIMING_OUTBUF_SIZE + 1;
|
||||||
|
buf_used = 0;
|
||||||
|
for(i = 0; i < t->next_id_cntr; i++){
|
||||||
|
char *line = NULL;
|
||||||
|
size_t line_size;
|
||||||
|
rc = asprintf(&line,"[%s:%d] %s \"%s\" [OPAL_OVHD] %le\n",
|
||||||
|
nodename, getpid(), jobid, descr[i].descr_ev->descr,
|
||||||
|
descr[i].interval - descr[i].overhead);
|
||||||
|
if( rc < 0 ){
|
||||||
|
rc = OPAL_ERR_OUT_OF_RESOURCE;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
rc = 0;
|
||||||
|
line_size = strlen(line);
|
||||||
|
|
||||||
|
/* Sanity check: this shouldn't happen since description
|
||||||
|
* is event only 1KB long and other fields should never
|
||||||
|
* exceed 9KB */
|
||||||
|
assert( line_size <= OPAL_TIMING_OUTBUF_SIZE );
|
||||||
|
|
||||||
|
if( buf_used + strlen(line) > buf_size ){
|
||||||
|
// Increase output buffer
|
||||||
|
while( buf_used + line_size > buf_size && buf_size < DELTAS_SANE_LIMIT){
|
||||||
|
buf_size += OPAL_TIMING_OUTBUF_SIZE + 1;
|
||||||
|
}
|
||||||
|
if( buf_size > DELTAS_SANE_LIMIT ){
|
||||||
|
opal_output(0, "opal_timing_report: delta sane limit overflow (%u > %u)!\n",
|
||||||
|
(unsigned int)buf_size, DELTAS_SANE_LIMIT);
|
||||||
|
free(line);
|
||||||
|
rc = OPAL_ERR_OUT_OF_RESOURCE;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
buf = realloc(buf, buf_size);
|
||||||
|
if( buf == NULL ){
|
||||||
|
opal_output(0, "opal_timing_deltas: Out of memory!\n");
|
||||||
|
rc = OPAL_ERR_OUT_OF_RESOURCE;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sprintf(buf,"%s%s", buf, line);
|
||||||
|
buf_used += line_size;
|
||||||
|
free(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if( buf_used > 0 ){
|
||||||
|
// flush buffer to the file
|
||||||
|
if( fp != NULL ){
|
||||||
|
fprintf(fp,"%s", buf);
|
||||||
|
fprintf(fp,"\n");
|
||||||
|
} else {
|
||||||
|
opal_output(0,"\n%s", buf);
|
||||||
|
}
|
||||||
|
buf[0] = '\0';
|
||||||
|
buf_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_exit:
|
||||||
|
if( NULL != descr ){
|
||||||
|
free(descr);
|
||||||
|
}
|
||||||
|
if( NULL != buf ){
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
if( fp != NULL ){
|
||||||
|
fflush(fp);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
void opal_timing_release(opal_timing_t *t)
|
void opal_timing_release(opal_timing_t *t)
|
||||||
{
|
{
|
||||||
int cnt = opal_list_get_size(t->events);
|
int cnt = opal_list_get_size(t->events);
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#ifndef OPAL_UTIL_TIMING_H
|
#ifndef OPAL_UTIL_TIMING_H
|
||||||
#define OPAL_UTIL_TIMING_H
|
#define OPAL_UTIL_TIMING_H
|
||||||
|
|
||||||
|
#include "opal_config.h"
|
||||||
|
|
||||||
#include "opal/class/opal_list.h"
|
#include "opal/class/opal_list.h"
|
||||||
#include "opal/runtime/opal_params.h"
|
#include "opal/runtime/opal_params.h"
|
||||||
|
|
||||||
@ -20,8 +22,12 @@
|
|||||||
#define OPAL_TIMING_BUFSIZE 32
|
#define OPAL_TIMING_BUFSIZE 32
|
||||||
#define OPAL_TIMING_OUTBUF_SIZE (10*1024)
|
#define OPAL_TIMING_OUTBUF_SIZE (10*1024)
|
||||||
|
|
||||||
typedef enum { TEVENT, TBEGIN, TEND } opal_event_type_t;
|
typedef enum {
|
||||||
|
OPAL_TIMING_TRACE,
|
||||||
|
OPAL_TIMING_INTDESCR,
|
||||||
|
OPAL_TIMING_INTBEGIN,
|
||||||
|
OPAL_TIMING_INTEND
|
||||||
|
} opal_event_type_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
opal_list_item_t super;
|
opal_list_item_t super;
|
||||||
@ -35,12 +41,20 @@ typedef struct {
|
|||||||
int id;
|
int id;
|
||||||
} opal_timing_event_t;
|
} opal_timing_event_t;
|
||||||
|
|
||||||
|
typedef double (*get_ts_t)(void);
|
||||||
|
|
||||||
typedef struct opal_timing_t
|
typedef struct opal_timing_t
|
||||||
{
|
{
|
||||||
int cur_id;
|
int next_id_cntr;
|
||||||
|
// not thread safe!
|
||||||
|
// The whole implementation is not thread safe now
|
||||||
|
// since it is supposed to be used in orte service
|
||||||
|
// thread only. Fix in the future or now?
|
||||||
|
int current_id;
|
||||||
opal_list_t *events;
|
opal_list_t *events;
|
||||||
opal_timing_event_t *buffer;
|
opal_timing_event_t *buffer;
|
||||||
size_t buffer_offset, buffer_size;
|
size_t buffer_offset, buffer_size;
|
||||||
|
get_ts_t get_ts;
|
||||||
} opal_timing_t;
|
} opal_timing_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -84,7 +98,7 @@ void opal_timing_init(opal_timing_t *t);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare timing event, do all printf-like processing.
|
* Prepare timing event, do all printf-like processing.
|
||||||
* Should not be directly used, for service purposes.
|
* Should not be directly used - for service purposes only.
|
||||||
*
|
*
|
||||||
* @param t pointer to the timing handler structure
|
* @param t pointer to the timing handler structure
|
||||||
* @param fmt printf-like format
|
* @param fmt printf-like format
|
||||||
@ -94,6 +108,18 @@ void opal_timing_init(opal_timing_t *t);
|
|||||||
*/
|
*/
|
||||||
opal_timing_prep_t opal_timing_prep_ev(opal_timing_t *t, const char *fmt, ...);
|
opal_timing_prep_t opal_timing_prep_ev(opal_timing_t *t, const char *fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare timing event, ignore printf-like processing.
|
||||||
|
* Should not be directly used - for service purposes only.
|
||||||
|
*
|
||||||
|
* @param t pointer to the timing handler structure
|
||||||
|
* @param fmt printf-like format
|
||||||
|
* @param ... other parameters that should be converted to string representation
|
||||||
|
*
|
||||||
|
* @retval partly filled opal_timing_prep_t structure
|
||||||
|
*/
|
||||||
|
opal_timing_prep_t opal_timing_prep_ev_end(opal_timing_t *t, const char *fmt, ...);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enqueue timing event into the list of events in handler 't'.
|
* Enqueue timing event into the list of events in handler 't'.
|
||||||
*
|
*
|
||||||
@ -104,7 +130,85 @@ opal_timing_prep_t opal_timing_prep_ev(opal_timing_t *t, const char *fmt, ...);
|
|||||||
*
|
*
|
||||||
* @retval
|
* @retval
|
||||||
*/
|
*/
|
||||||
void opal_timing_add_step(opal_timing_prep_t p,
|
void opal_timing_add_step(opal_timing_prep_t p, const char *func,
|
||||||
|
const char *file, int line);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue the description of the interval into a list of events
|
||||||
|
* in handler 't'.
|
||||||
|
*
|
||||||
|
* @param p result of opal_timing_prep_ev
|
||||||
|
* @param func function name where event occurs
|
||||||
|
* @param file file name where event occurs
|
||||||
|
* @param line line number in the file
|
||||||
|
*
|
||||||
|
* @retval id of event interval
|
||||||
|
*/
|
||||||
|
int opal_timing_descr(opal_timing_prep_t p, const char *func,
|
||||||
|
const char *file, int line);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue the beginning of timing interval that already has the
|
||||||
|
* description and assigned id into the list of events
|
||||||
|
* in handler 't'.
|
||||||
|
*
|
||||||
|
* @param p result of opal_timing_prep_ev
|
||||||
|
* @param func function name where event occurs
|
||||||
|
* @param file file name where event occurs
|
||||||
|
* @param line line number in the file
|
||||||
|
*
|
||||||
|
* @retval
|
||||||
|
*/
|
||||||
|
void opal_timing_start_id(opal_timing_t *t, int id, const char *func,
|
||||||
|
const char *file, int line);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue the end of timing interval that already has
|
||||||
|
* description and assigned id into the list of events
|
||||||
|
* in handler 't'.
|
||||||
|
*
|
||||||
|
* @param p result of opal_timing_prep_ev
|
||||||
|
* @param func function name where event occurs
|
||||||
|
* @param file file name where event occurs
|
||||||
|
* @param line line number in the file
|
||||||
|
*
|
||||||
|
* @retval
|
||||||
|
*/
|
||||||
|
void opal_timing_end(opal_timing_t *t, int id, const char *func,
|
||||||
|
const char *file, int line );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueue both description and start of timing interval
|
||||||
|
* into the list of events and assign its id.
|
||||||
|
*
|
||||||
|
* @param p result of opal_timing_prep_ev
|
||||||
|
* @param func function name where event occurs
|
||||||
|
* @param file file name where event occurs
|
||||||
|
* @param line line number in the file
|
||||||
|
*
|
||||||
|
* @retval interval id
|
||||||
|
*/
|
||||||
|
static inline int opal_timing_start_init(opal_timing_prep_t p,
|
||||||
|
const char *func, const char *file, int line)
|
||||||
|
{
|
||||||
|
int id = opal_timing_descr(p, func, file, line);
|
||||||
|
if( id < 0 )
|
||||||
|
return id;
|
||||||
|
opal_timing_start_id(p.t, id, func, file, line);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The wrapper that is used to stop last measurement in OPAL_TIMING_MNEXT.
|
||||||
|
*
|
||||||
|
* @param p result of opal_timing_prep_ev
|
||||||
|
* @param func function name where event occurs
|
||||||
|
* @param file file name where event occurs
|
||||||
|
* @param line line number in the file
|
||||||
|
*
|
||||||
|
* @retval interval id
|
||||||
|
*/
|
||||||
|
void opal_timing_end_prep(opal_timing_prep_t p,
|
||||||
const char *func, const char *file, int line);
|
const char *func, const char *file, int line);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -116,14 +220,31 @@ void opal_timing_add_step(opal_timing_prep_t p,
|
|||||||
* disappear.
|
* disappear.
|
||||||
*
|
*
|
||||||
* @param t timing handler
|
* @param t timing handler
|
||||||
* @param accovh consider malloc overhead introduced by timing code
|
* @param account_overhead consider malloc overhead introduced by timing code
|
||||||
* @param prefix prefix to use when no fname was specifyed to ease grep'ing
|
* @param prefix prefix to use when no fname was specifyed to ease grep'ing
|
||||||
* @param fname name of the output file (may be NULL)
|
* @param fname name of the output file (may be NULL)
|
||||||
*
|
*
|
||||||
* @retval OPAL_SUCCESS On success
|
* @retval OPAL_SUCCESS On success
|
||||||
* @retval OPAL_ERROR or OPAL_ERR_OUT_OF_RESOURCE On failure
|
* @retval OPAL_ERROR or OPAL_ERR_OUT_OF_RESOURCE On failure
|
||||||
*/
|
*/
|
||||||
int opal_timing_report(opal_timing_t *t, bool accovh, const char *prefix, char *fname);
|
int opal_timing_report(opal_timing_t *t, char *fname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report all intervals that were enqueued in the timing handler 't'.
|
||||||
|
* - if fname == NULL the output will be done using opal_output and
|
||||||
|
* each line will be prefixed with "prefix" to ease grep'ing.
|
||||||
|
* - otherwise the corresponding file will be used for output in "append" mode
|
||||||
|
* WARRNING: not all filesystems provide enough support for that feature, some records may
|
||||||
|
* disappear.
|
||||||
|
*
|
||||||
|
* @param t timing handler
|
||||||
|
* @param account_overhead consider malloc overhead introduced by timing code
|
||||||
|
* @param fname name of the output file (may be NULL)
|
||||||
|
*
|
||||||
|
* @retval OPAL_SUCCESS On success
|
||||||
|
* @retval OPAL_ERROR or OPAL_ERR_OUT_OF_RESOURCE On failure
|
||||||
|
*/
|
||||||
|
int opal_timing_deltas(opal_timing_t *t, char *fname);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release all memory allocated for the timing handler 't'.
|
* Release all memory allocated for the timing handler 't'.
|
||||||
@ -140,7 +261,7 @@ void opal_timing_release(opal_timing_t *t);
|
|||||||
* --enable-timing.
|
* --enable-timing.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#define OPAL_TIMING_DECLARE(t) opal_timing_t t; // must have the semicolon here to avoid warnings when not enabled
|
#define OPAL_TIMING_DECLARE(t) opal_timing_t t; /* need semicolon here to avoid warnings when not enabled */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main macro for use in declaring external opal timing handler;
|
* Main macro for use in declaring external opal timing handler;
|
||||||
@ -148,7 +269,7 @@ void opal_timing_release(opal_timing_t *t);
|
|||||||
* --enable-timing.
|
* --enable-timing.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#define OPAL_TIMING_DECLARE_EXT(x, t) x extern opal_timing_t t; // must have the semicolon here to avoid warnings when not enabled
|
#define OPAL_TIMING_DECLARE_EXT(x, t) x extern opal_timing_t t; /* need semicolon here to avoid warnings when not enabled */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main macro for use in initializing opal timing handler;
|
* Main macro for use in initializing opal timing handler;
|
||||||
@ -160,7 +281,8 @@ void opal_timing_release(opal_timing_t *t);
|
|||||||
#define OPAL_TIMING_INIT(t) opal_timing_init(t)
|
#define OPAL_TIMING_INIT(t) opal_timing_init(t)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main macro for use in adding new timing event for the specifyed timing handler;
|
* Macro that enqueues event with its description to the specified
|
||||||
|
* timing handler;
|
||||||
* will be "compiled out" when OPAL is configured without
|
* will be "compiled out" when OPAL is configured without
|
||||||
* --enable-timing.
|
* --enable-timing.
|
||||||
*
|
*
|
||||||
@ -169,16 +291,103 @@ void opal_timing_release(opal_timing_t *t);
|
|||||||
#define OPAL_TIMING_EVENT(x) opal_timing_add_step( opal_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__)
|
#define OPAL_TIMING_EVENT(x) opal_timing_add_step( opal_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main macro for use in reporting collected events;
|
* MDESCR: Measurement DESCRiption
|
||||||
|
* Introduce new timing measurement with string description for the specified
|
||||||
|
* timing handler;
|
||||||
|
* will be "compiled out" when OPAL is configured without
|
||||||
|
* --enable-timing.
|
||||||
|
*
|
||||||
|
* @see opal_timing_descr()
|
||||||
|
*/
|
||||||
|
#define OPAL_TIMING_MDESCR(x) opal_timing_descr( opal_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MSTART_ID: Measurement START by ID.
|
||||||
|
* Marks the beginning of the measurement with ID=id on the
|
||||||
|
* specified timing handler;
|
||||||
|
* will be "compiled out" when OPAL is configured without
|
||||||
|
* --enable-timing.
|
||||||
|
*
|
||||||
|
* @see opal_timing_start_id()
|
||||||
|
*/
|
||||||
|
#define OPAL_TIMING_MSTART_ID(t, id) opal_timing_start_id(t, id, __FUNCTION__, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MSTART: Measurement START
|
||||||
|
* Introduce new timing measurement conjuncted with its start
|
||||||
|
* on the specifyed timing handler;
|
||||||
|
* will be "compiled out" when OPAL is configured without
|
||||||
|
* --enable-timing.
|
||||||
|
*
|
||||||
|
* @see opal_timing_start_init()
|
||||||
|
*/
|
||||||
|
#define OPAL_TIMING_MSTART(x) opal_timing_start_init( opal_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MSTOP: STOP Measurement
|
||||||
|
* Finishes the most recent measurement on the specifyed timing handler;
|
||||||
|
* will be "compiled out" when OPAL is configured without
|
||||||
|
* --enable-timing.
|
||||||
|
*
|
||||||
|
* @see opal_timing_end()
|
||||||
|
*/
|
||||||
|
#define OPAL_TIMING_MSTOP(t) opal_timing_end(t, -1, __FUNCTION__, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MSTOP_ID: STOP Measurement with ID=id.
|
||||||
|
* Finishes the measurement with give ID on the specifyed timing handler;
|
||||||
|
* will be "compiled out" when OPAL is configured without
|
||||||
|
* --enable-timing.
|
||||||
|
*
|
||||||
|
* @see opal_timing_end()
|
||||||
|
*/
|
||||||
|
#define OPAL_TIMING_MSTOP_ID(t, id) opal_timing_end(t, id, __FUNCTION__, __FILE__, __LINE__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MNEXT: start NEXT Measurement
|
||||||
|
* Convinient macro, may be implemented with the sequence of three previously
|
||||||
|
* defined macroses:
|
||||||
|
* - finish current measurement (OPAL_TIMING_MSTOP);
|
||||||
|
* - introduce new timing measurement (OPAL_TIMING_MDESCR);
|
||||||
|
* - starts next measurement (OPAL_TIMING_MSTART_ID)
|
||||||
|
* on the specifyed timing handler;
|
||||||
|
* will be "compiled out" when OPAL is configured without
|
||||||
|
* --enable-timing.
|
||||||
|
*
|
||||||
|
* @see opal_timing_start_init()
|
||||||
|
*/
|
||||||
|
#define OPAL_TIMING_MNEXT(x) ( \
|
||||||
|
opal_timing_end_prep(opal_timing_prep_ev_end x, \
|
||||||
|
__FUNCTION__, __FILE__, __LINE__ ), \
|
||||||
|
opal_timing_start_init( opal_timing_prep_ev x, \
|
||||||
|
__FUNCTION__, __FILE__, __LINE__) \
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The macro for use in reporting collected events with absolute values;
|
||||||
* will be "compiled out" when OPAL is configured without
|
* will be "compiled out" when OPAL is configured without
|
||||||
* --enable-timing.
|
* --enable-timing.
|
||||||
*
|
*
|
||||||
* @param enable flag that enables/disables reporting. Used for fine-grained timing.
|
* @param enable flag that enables/disables reporting. Used for fine-grained timing.
|
||||||
* @see opal_timing_report()
|
* @see opal_timing_report()
|
||||||
*/
|
*/
|
||||||
#define OPAL_TIMING_REPORT(enable, t, prefix) { \
|
#define OPAL_TIMING_REPORT(enable, t) { \
|
||||||
if( enable ) { \
|
if( enable ) { \
|
||||||
opal_timing_report(t, opal_timing_overhead, prefix, opal_timing_output); \
|
opal_timing_report(t, opal_timing_output); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The macro for use in reporting collected events with relative times;
|
||||||
|
* will be "compiled out" when OPAL is configured without
|
||||||
|
* --enable-timing.
|
||||||
|
*
|
||||||
|
* @param enable flag that enables/disables reporting. Used for fine-grained timing.
|
||||||
|
* @see opal_timing_deltas()
|
||||||
|
*/
|
||||||
|
#define OPAL_TIMING_DELTAS(enable, t) { \
|
||||||
|
if( enable ) { \
|
||||||
|
opal_timing_deltas(t, opal_timing_output); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +410,21 @@ void opal_timing_release(opal_timing_t *t);
|
|||||||
|
|
||||||
#define OPAL_TIMING_EVENT(x)
|
#define OPAL_TIMING_EVENT(x)
|
||||||
|
|
||||||
#define OPAL_TIMING_REPORT(enable, t, prefix)
|
#define OPAL_TIMING_MDESCR(x)
|
||||||
|
|
||||||
|
#define OPAL_TIMING_MSTART_ID(t, id)
|
||||||
|
|
||||||
|
#define OPAL_TIMING_MSTART(x)
|
||||||
|
|
||||||
|
#define OPAL_TIMING_MSTOP(t)
|
||||||
|
|
||||||
|
#define OPAL_TIMING_MSTOP_ID(t, id)
|
||||||
|
|
||||||
|
#define OPAL_TIMING_MNEXT(x)
|
||||||
|
|
||||||
|
#define OPAL_TIMING_REPORT(enable, t)
|
||||||
|
|
||||||
|
#define OPAL_TIMING_DELTAS(enable, t)
|
||||||
|
|
||||||
#define OPAL_TIMING_RELEASE(t)
|
#define OPAL_TIMING_RELEASE(t)
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ static int orte_oob_base_close(void)
|
|||||||
|
|
||||||
|
|
||||||
OPAL_TIMING_EVENT((&tm_oob, "Finish"));
|
OPAL_TIMING_EVENT((&tm_oob, "Finish"));
|
||||||
OPAL_TIMING_REPORT(orte_oob_base.timing, &tm_oob, "COMM");
|
OPAL_TIMING_REPORT(orte_oob_base.timing, &tm_oob);
|
||||||
|
|
||||||
return mca_base_framework_components_close(&orte_oob_base_framework, NULL);
|
return mca_base_framework_components_close(&orte_oob_base_framework, NULL);
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ static int orte_rml_base_close(void)
|
|||||||
}
|
}
|
||||||
OBJ_DESTRUCT(&orte_rml_base.posted_recvs);
|
OBJ_DESTRUCT(&orte_rml_base.posted_recvs);
|
||||||
|
|
||||||
OPAL_TIMING_REPORT(orte_rml_base.timing, &tm_rml, "RML");
|
OPAL_TIMING_REPORT(orte_rml_base.timing, &tm_rml);
|
||||||
|
|
||||||
return mca_base_framework_components_close(&orte_rml_base_framework, NULL);
|
return mca_base_framework_components_close(&orte_rml_base_framework, NULL);
|
||||||
}
|
}
|
||||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user