Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 55 additions & 5 deletions packages/taucmdr/cf/software/tau_installation.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
'pprof',
'slog2print',
'tau2slog2',
'tau_trace2json',
'taudb_configure',
'taudb_install_cert',
'taudb_keygen',
Expand Down Expand Up @@ -147,7 +148,14 @@

PROFILE_ANALYSIS_TOOLS = 'paraprof', 'pprof'

TRACE_ANALYSIS_TOOLS = 'jumpshot', 'vampir'
TRACE_ANALYSIS_TOOLS = 'jumpshot', 'vampir', 'google_chrome'

TOOL_FOR_FORMAT = {
'json':['google_chrome'],
'slog2':['jumpshot'],
'otf2':['vampir'],
'tau':['pprof','paraprof'],
}

PROGRAM_LAUNCHERS = {'mpirun': ['-app', '--app', '-configfile'],
'mpiexec': ['-app', '--app', '-configfile'],
Expand Down Expand Up @@ -321,7 +329,7 @@ def __init__(self, sources, target_arch, target_os, compilers,
assert isinstance(select_file, basestring) or select_file is None
assert baseline in (True, False)
assert profile in ("tau", "merged", "cubex", "none")
assert trace in ("slog2", "otf2", "none")
assert trace in ("slog2", "otf2", "json", "none")
assert sample in (True, False)
assert isinstance(metrics, list) or metrics is None
assert measure_io in (True, False)
Expand Down Expand Up @@ -1273,7 +1281,7 @@ def runtime_config(self, opts=None, env=None):
else:
env['TAU_PROFILE'] = '0'
env['SCOREP_ENABLE_PROFILING'] = 'false'
if self.trace == 'slog2':
if self.trace == 'slog2' or self.trace == 'json':
env['TAU_TRACE'] = '1'
elif self.trace == 'otf2':
env['TAU_TRACE'] = '1'
Expand Down Expand Up @@ -1580,6 +1588,10 @@ def get_data_format(self, path):
return 'slog2'
elif ext == '.otf2':
return 'otf2'
elif ext == '.json':
return 'json'
elif ext == '.json':
return 'json'
elif ext == '.gz':
root, ext = os.path.splitext(root)
if ext == '.xml':
Expand All @@ -1592,7 +1604,7 @@ def is_profile_format(self, fmt):

def is_trace_format(self, fmt):
"""Return True if ``fmt`` is a string indicating a trace data format."""
return fmt in ('slog2', 'otf2')
return fmt in ('slog2', 'otf2', 'json')

def _show_unknown(self, tool):
def launcher(_, paths, env):
Expand Down Expand Up @@ -1673,6 +1685,23 @@ def _show_vampir(self, fmt, paths, env):
retval += util.create_subprocess(['vampir', path], cwd=cwd, env=env)
return retval

def _show_google_chrome(self, fmt, paths, env):
if fmt != 'json':
raise ConfigurationError("Chrome cannot open traces in '%s' format" % fmt)
self._check_X11()
retval = 0
for path in paths:
if not os.path.exists(path):
raise ConfigurationError("Trace file '%s' does not exist" % path)
path = os.path.abspath(path)
cwd = os.path.dirname(path)

LOGGER.info("\nTo see the profile, go to chrome://tracing in your browser and load the tau.json file at this path")
LOGGER.info(path)
retval += util.create_subprocess(['google-chrome', ''],
cwd=cwd, env=env, stdout=False)
return retval

def _prep_data_analysis_tools(self):
"""Checks that data analysis tools are installed, or installs them if needed."""
if not glob.glob(os.path.join(self.lib_path, 'Makefile.tau*')):
Expand Down Expand Up @@ -1704,7 +1733,11 @@ def show_data_files(self, dataset, profile_tools=None, trace_tools=None):
tools = trace_tools if trace_tools is not None else TRACE_ANALYSIS_TOOLS
else:
raise InternalError("Unhandled data format '%s'" % fmt)
for tool in tools:
try:
available_tools = TOOL_FOR_FORMAT[fmt]
except KeyError:
raise InternalError("'%s'is an unrecognized file type" % fmt)
for tool in available_tools:
try:
launcher = getattr(self, '_show_'+tool)
except AttributeError:
Expand Down Expand Up @@ -1785,6 +1818,23 @@ def tau_trace_to_slog2(self, trc, edf, slog2):
if not os.path.exists(slog2):
raise InternalError("Failed to convert TAU trace data: no slog2 files exist after calling 'tau2slog2'")

def tau_trace_to_json(self, trc, edf, json):
"""Convert a TAU trace file to JSON format.

Args:
trc (str): Path to the trc file.
edf (str): Path to the edf file.
json (str): Path to the json file to create.
"""
self._prep_data_analysis_tools()
LOGGER.info("Converting TAU trace files to json format...")
cmd = [os.path.join(self.bin_path, 'tau_trace2json'), trc, edf, '-chrome', '-ignoreatomic', '-o', json]
if util.create_subprocess(cmd, stdout=False, log=True, show_progress=True):
os.remove(json)
raise InternalError("Nonzero return code from tau_trace2json")
if not os.path.exists(json):
raise InternalError("Failed to convert TAU trace data: no json files exist after calling 'tau_trace2json'")

def tau_metrics(self):
"""List TAU metrics available on this target.

Expand Down
11 changes: 11 additions & 0 deletions packages/taucmdr/cli/commands/application/tests/test_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

from taucmdr import tests
from taucmdr.cli.commands.application.create import COMMAND as create_cmd
from taucmdr.model.application import Application
from taucmdr.cf.storage.levels import PROJECT_STORAGE

class CreateTest(tests.TestCase):
"""Tests for :any:`application.create`."""
Expand All @@ -43,6 +45,15 @@ def test_create(self):
self.assertIn('Added application \'test01\' to project configuration', stdout)
self.assertFalse(stderr)

def test_python(self):
self.reset_project_storage()
name = 'python_app'
stdout, stderr = self.assertCommandReturnValue(0, create_cmd, [name,'--python'])
app = Application.controller(PROJECT_STORAGE).one({'name': name})
self.assertIsInstance(app, Application)
self.assertEqual(app['python'], True)
self.assertFalse(stderr)

def test_duplicatename(self):
self.reset_project_storage()
_, stderr = self.assertNotCommandReturnValue(0, create_cmd, ['app1'])
Expand Down
10 changes: 10 additions & 0 deletions packages/taucmdr/cli/commands/measurement/tests/test_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ def test_trace_callpath(self):
self.assertIsInstance(meas, Measurement)
self.assertEqual(meas['callpath'], 0)

def test_trace_json(self):
self.reset_project_storage()
name = 'trace_json'
stdout, stderr = self.assertCommandReturnValue(0, create_cmd, [name, '--trace','json'])
self.assertFalse(stderr)
self.assertIn("Added measurement '%s' to project" % name, stdout)
self.assertNotIn("WARNING", stdout)
meas = Measurement.controller(PROJECT_STORAGE).one({'name': name})
self.assertEqual(meas['trace'],'json')

def test_trace_callpath_0(self):
self.reset_project_storage()
name = 'test_trace_callpath_0'
Expand Down
13 changes: 13 additions & 0 deletions packages/taucmdr/cli/commands/trial/tests/test_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,16 @@ def test_export_otf2(self):
self.assertCommandReturnValue(EXIT_SUCCESS, trial_export_cmd, [])
export_file = expr['name'] + '.trial0.tgz'
self.assertTrue(os.path.exists(export_file))

def test_export_json(self):
self.reset_project_storage(['--trace', 'json', '--profile', 'none'])
expr = Project.selected().experiment()
meas = expr.populate('measurement')
self.assertEqual(meas['trace'], 'json')
self.assertEqual(meas['profile'], 'none')
self.assertManagedBuild(0, CC, [], 'hello.c')
self.assertCommandReturnValue(EXIT_SUCCESS, trial_create_cmd, ['./a.out'])
self.assertCommandReturnValue(EXIT_SUCCESS, trial_export_cmd, [])
export_file = expr['name'] + '.trial0.json'
self.assertTrue(os.path.exists(export_file))

6 changes: 6 additions & 0 deletions packages/taucmdr/model/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ def _encourage_except_baseline(lhs, lhs_attr, lhs_value, rhs):
'const': 25},
'rebuild_required': True
},
'python': {
'type': 'boolean',
'description': 'application uses python',
'argparse': {'flags': ('--python',)},
'rebuild_required': True
},
'linkage': {
'type': 'string',
'default': 'static' if HOST_OS is CRAY_CNL else 'dynamic',
Expand Down
2 changes: 1 addition & 1 deletion packages/taucmdr/model/measurement.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ def _ensure_instrumented(lhs, lhs_attr, lhs_value, rhs):
'group': 'output format',
'metavar': '<format>',
'nargs': '?',
'choices':('slog2', 'otf2', 'none'),
'choices':('slog2', 'otf2', 'json', 'none'),
'const': 'otf2'},
'compat': {'otf2': Target.exclude('libotf2_source', None),
lambda x: x != 'none': _discourage_callpath},
Expand Down
29 changes: 29 additions & 0 deletions packages/taucmdr/model/trial.py
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,27 @@ def _postprocess_slog2(self):
count += 1
progress_bar.update(count)

def _postprocess_json(self):
json = os.path.join(self.prefix, 'tau.json')
if os.path.exists(json):
return
tau = TauInstallation.get_minimal()
merged_trc = os.path.join(self.prefix, 'tau.trc')
merged_edf = os.path.join(self.prefix, 'tau.edf')
if not os.path.exists(merged_trc) or not os.path.exists(merged_edf):
tau.merge_tau_trace_files(self.prefix)
tau.tau_trace_to_json(merged_trc, merged_edf, json)
trc_files = glob.glob(os.path.join(self.prefix, '*.trc'))
edf_files = glob.glob(os.path.join(self.prefix, '*.edf'))
count_trc_edf = len(trc_files) + len(edf_files)
LOGGER.info('Cleaning up TAU trace files...')
with ProgressIndicator("", total_size=count_trc_edf) as progress_bar:
count = 0
for path in trc_files + edf_files:
os.remove(path)
count += 1
progress_bar.update(count)

def get_data_files(self):
"""Return paths to the trial's data files or directories mapped by data type.

Expand All @@ -474,6 +495,8 @@ def get_data_files(self):
trace_fmt = meas.get('trace', 'none')
if trace_fmt == 'slog2':
self._postprocess_slog2()
elif trace_fmt == 'json':
self._postprocess_json()
data = {}
if profile_fmt == 'tau':
data[profile_fmt] = self.prefix
Expand All @@ -488,6 +511,8 @@ def get_data_files(self):
data[trace_fmt] = os.path.join(self.prefix, 'tau.slog2')
elif trace_fmt == 'otf2':
data[trace_fmt] = os.path.join(self.prefix, 'traces.otf2')
elif trace_fmt == 'json':
data[trace_fmt] = os.path.join(self.prefix, 'tau.json')
elif trace_fmt != 'none':
raise InternalError("Unhandled trace format '%s'" % trace_fmt)
return data
Expand Down Expand Up @@ -640,5 +665,9 @@ def export(self, dest):
expr_dir, trial_dir = os.path.split(os.path.dirname(path))
items = [os.path.join(trial_dir, item) for item in 'traces', 'traces.def', 'traces.otf2']
util.create_archive('tgz', export_file, items, expr_dir)
elif fmt == 'json':
export_file = os.path.join(dest, stem+'.json')
LOGGER.info("Writing '%s'...", export_file)
util.copy_file(path, export_file)
elif fmt != 'none':
raise InternalError("Unhandled data file format '%s'" % fmt)