Skip to content
Merged
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
12 changes: 12 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,17 @@ if test -z "$RUBY"; then
AC_CHECK_PROG(RUBY,[ruby],[ruby],[no])
test "$RUBY" == "no" && AC_MSG_ERROR([Required program 'ruby' not found.])
fi
# iprof needs Ruby >= 2.7. It's a runtime dependency, but we assume people use
# the same ruby version at compile and runtime. Will also be used to potentially
# update other parts of the project.
RUBY_MIN_VERSION=2.7.0
AC_SUBST([RUBY_MIN_VERSION])
AC_MSG_CHECKING([for ruby >= $RUBY_MIN_VERSION])
RUBY_VERSION_FOUND=`$RUBY -e 'print RUBY_VERSION'`
AX_COMPARE_VERSION([$RUBY_VERSION_FOUND], [ge], [$RUBY_MIN_VERSION],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_MSG_ERROR([ruby version $RUBY_VERSION_FOUND is too old, need >= $RUBY_MIN_VERSION])])
if test -z "$ERB"; then
AC_CHECK_PROG(ERB,[erb],[erb],[no])
test "$ERB" == "no" && AC_MSG_ERROR([Required program 'erb' not found.])
Expand Down Expand Up @@ -155,6 +166,7 @@ AC_CONFIG_FILES([backends/mpi/tracer_mpi.sh], [chmod +x backends/mpi/tracer_mpi.
AC_CONFIG_FILES([backends/itt/tracer_itt.sh], [chmod +x backends/itt/tracer_itt.sh])
AC_CONFIG_FILES([utils/babeltrace_thapi], [chmod +x utils/babeltrace_thapi])
AC_CONFIG_FILES([xprof/xprof.rb], [chmod +x xprof/xprof.rb])
AC_CONFIG_FILES([xprof/iprof:xprof/xprof_wrapper.rb.in], [chmod +x xprof/iprof])
AC_CONFIG_FILES([thapi.pc])

AC_OUTPUT
34 changes: 34 additions & 0 deletions integration_tests/old_ruby_frontend.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
bats_require_minimum_version 1.5.0

# The `iprof` launcher must stay parseable by an old Ruby (the system default on
# some machines) so that, on a too-old interpreter, it prints a friendly version
# message instead of a raw SyntaxError. All modern-syntax logic lives in the
# required `xprof.rb`, which is only parsed after the version gate passes.

setup() {
# ruby CLI need a path
iprof_path=$(command -v iprof)

# Single source of truth: read the minimal ruby version baked into iprof itself
# (configure.ac may not be present, e.g. CI only ships the install tree). The
# value keeps its quotes, so it drops straight into the ruby below.
min_version=$(awk '/^THAPI_RUBY_MINIMAL_VERSION/ {print $3}' "${iprof_path}")

# The ruby to test against. Defaults to `ruby`; point THAPI_OLD_RUBY at an old
# interpreter to exercise this on a machine whose default ruby is recent.
old_ruby="${THAPI_OLD_RUBY:-ruby}"
if "${old_ruby}" -e "exit(Gem::Version.new(RUBY_VERSION) >= Gem::Version.new(${min_version}))"; then
skip "${old_ruby} is >= ${min_version}; set THAPI_OLD_RUBY to an older ruby to run this test"
fi
}

@test "frontend_parses_under_old_ruby" {
run -0 "${old_ruby}" -c "${iprof_path}"
}

@test "frontend_prints_friendly_message_under_old_ruby" {
run ! "${old_ruby}" "${iprof_path}" --help
[[ "${output}" == *"too old"* ]]
[[ "${output}" != *"SyntaxError"* ]]
[[ "${output}" != *"unexpected"* ]]
}
11 changes: 7 additions & 4 deletions xprof/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@ bin_SCRIPTS = \
iprof \
sync_daemon_fs

# `iprof` is the old-Ruby-safe wrapper, generated from xprof_wrapper.rb.in by
# configure (see configure.ac). It requires xprof.rb (the implementation) from
# DATADIR at runtime, the same place as optparse_thapi.rb and version (see
# utils/Makefile.am).
data_DATA = \
xprof.rb

if FOUND_MPI
bin_SCRIPTS += sync_daemon_mpi
endif

sync_daemon_mpi: $(srcdir)/sync_daemon_mpi.cpp
$(MPICXX) $(CXXFLAGS) $(AM_CXXFLAGS) -I$(top_srcdir)/utils/include $< -o $@

iprof: xprof.rb
cp xprof.rb $@

xprof_utils.hpp: $(top_srcdir)/utils/xprof_utils.hpp
cp $< $@

Expand Down Expand Up @@ -227,7 +231,6 @@ EXTRA_DIST = \
sync_daemon_fs

CLEANFILES = \
iprof \
xprof_utils.hpp \
perfetto_pruned.pb.h \
perfetto_pruned.pb.cc \
Expand Down
10 changes: 5 additions & 5 deletions xprof/sync_daemon_fs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#!/usr/bin/env ruby

# Cannot use require_relative as iprof is not a rb file
# Load MPITopo and related helpers
load(File.join(__dir__, 'iprof'))
# Load MPITopo and related helpers from the implementation (installed in
# ../share), not the iprof wrapper, which would set $thapi_launch and run the
# whole program instead of just defining helpers.
require_relative File.join('..', 'share', 'xprof')

require 'open3'
require 'fileutils'
Expand Down Expand Up @@ -66,12 +67,11 @@ until msg == SyncDaemon::MSG_FINISH
raise 'sync_daemon_fs: parent closed socket without sending FINISH' if msg.empty?

case msg
when SyncDaemon::MSG_INIT then nil
when SyncDaemon::MSG_INIT, SyncDaemon::MSG_FINISH then nil
when SyncDaemon::MSG_LOCAL_BARRIER
local_barrier(local_barrier_count.to_s)
local_barrier_count += 1
when SyncDaemon::MSG_GLOBAL_BARRIER then global_barrier(global_handle)
when SyncDaemon::MSG_FINISH then nil
else
warn("sync_daemon_fs: unknown message '#{msg}'")
exit(1)
Expand Down
12 changes: 4 additions & 8 deletions xprof/xprof.rb.in
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
#!/usr/bin/env ruby

# 2.7 for Lazy in Enumerable. 2.7 was released 25 Dec 2019
THAPI_RUBY_MINIMAL_VERSION = '2.7.0'
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new(THAPI_RUBY_MINIMAL_VERSION)
warn("Your ruby version #{RUBY_VERSION} is too old. #{THAPI_RUBY_MINIMAL_VERSION} or newer required")
exit(1)
end
# This file doesn't do any ruby version check. All the check are done in `iprof`.

# We Cannot use "@ .. @" for libdir, bindir, and datarootdir
# as they will appear as bash "${exec_prefix}/lib"
Expand Down Expand Up @@ -1007,8 +1002,9 @@ def last_trace_saved
Dir[File.join(thapi_trace_home, 'thapi*')].max_by { |f| File.mtime(f) }
end

# Avoid load problem
if __FILE__ == $PROGRAM_NAME
# Run when launched through the `iprof` wrapper (which sets $thapi_launch before
# requiring this file) or when executed directly.
if $thapi_launch || __FILE__ == $PROGRAM_NAME
parser = OptionParserWithDefaultAndValidation.new

parser.banner = "Usage: #{File.basename($PROGRAM_NAME)} [options] [--] [command]"
Expand Down
18 changes: 18 additions & 0 deletions xprof/xprof_wrapper.rb.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env ruby

# User-facing `iprof` launcher. It MUST stay parseable by old Ruby: Ruby parses
# the whole file before running any of it, so modern syntax here (endless ranges,
# pattern matching, ...) would raise a raw SyntaxError before the version check
# below could run. All real logic lives in xprof.rb, required only after the check
# passes, so users on an old Ruby get the friendly message below instead.

# Named constant (not inlined) so bats can grep the minimal version out of iprof.
THAPI_RUBY_MINIMAL_VERSION = '@RUBY_MIN_VERSION@'
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new(THAPI_RUBY_MINIMAL_VERSION)
warn("Your ruby version #{RUBY_VERSION} is too old. #{THAPI_RUBY_MINIMAL_VERSION} or newer required")
exit(1)
end

$LOAD_PATH.unshift(File.join('@prefix@', 'share'))
$thapi_launch = true
require 'xprof'
Loading