Skip to content
Open
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
39 changes: 37 additions & 2 deletions pretext/lib/pretext.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@
# contextmanager tools
import contextlib

import time

# cleanup multiline strings used as source code
import textwrap

Expand Down Expand Up @@ -4856,6 +4858,9 @@ def html(xml, pub_file, stringparams, xmlid_root, file_format, extra_xsl, out_fi
# to ensure provided stringparams aren't mutated unintentionally
stringparams = stringparams.copy()

log_time_info = stringparams.get("profile.py", False) == "yes"
time_logger = Stopwatch("html()", log_time_info)

# Consult publisher file for locations of images
generated_abs, external_abs = get_managed_directories(xml, pub_file)
# Consult source for additional files
Expand All @@ -4866,6 +4871,7 @@ def html(xml, pub_file, stringparams, xmlid_root, file_format, extra_xsl, out_fi

pub_vars = get_publisher_variable_report(xml, pub_file, stringparams)
include_static_files = get_publisher_variable(pub_vars, 'portable-html') != "yes"
time_logger.log("pubvars loaded")

if include_static_files:
# interrogate Runestone server (or debugging switches) and populate
Expand All @@ -4875,6 +4881,7 @@ def html(xml, pub_file, stringparams, xmlid_root, file_format, extra_xsl, out_fi
# even if we don't need static files, we need to set stringparams for
# Runestone Services information.
_cdn_runestone_services(stringparams, ext_rs_methods)
time_logger.log("runestone placed")

# support publisher file, and subtree argument
if pub_file:
Expand All @@ -4893,18 +4900,19 @@ def html(xml, pub_file, stringparams, xmlid_root, file_format, extra_xsl, out_fi
# place managed directories - some of these (Asymptote HTML) are
# consulted during the XSL run and so need to be placed beforehand
copy_managed_directories(tmp_dir, external_abs=external_abs, generated_abs=generated_abs, data_abs=data_dir)
time_logger.log("managed directories copied")

if include_static_files:
# Copy js and css, but only if not building portable html
# place JS in scratch directory
copy_html_js(tmp_dir)

# build or copy theme
build_or_copy_theme(xml, pub_vars, tmp_dir)
time_logger.log("css/js copied")

# Write output into temporary directory
log.info("converting {} to HTML in {}".format(xml, tmp_dir))
xsltproc(extraction_xslt, xml, None, tmp_dir, stringparams)
time_logger.log("xsltproc complete")

if not(include_static_files):
# remove latex-image generated directories for portable builds
Expand Down Expand Up @@ -4940,6 +4948,8 @@ def html(xml, pub_file, stringparams, xmlid_root, file_format, extra_xsl, out_fi
else:
raise ValueError("PTX:BUG: HTML file format not recognized")

time_logger.log("build completed")


def revealjs(
xml, pub_file, stringparams, xmlid_root, file_format, extra_xsl, out_file, dest_dir
Expand Down Expand Up @@ -6259,6 +6269,31 @@ def place_latex_package_files(dest_dir, journal_name, cache_dir):
shutil.copy2(file_path, dest_dir)


class Stopwatch:
"""A simple stopwatch class for measuring elapsed time.

print_log controls whether log messages are printed when the log() is called
"""

def __init__(self, name:str="", print_log:bool=True):
self.name = name
self.print_log = print_log
self.start_time = time.time()
self.last_log_time = self.start_time

def reset(self):
"""Reset the log timer to the current time."""
self.last_log_time = time.time()

def log(self, timepoint_description:str=""):
"""Print a log message with the elapsed time since the last log event."""
if self.print_log:
cur_time = time.time()
elapsed_time = cur_time - self.start_time
since_last_log_time = cur_time - self.last_log_time
self.reset()
log.info(f"** Timing report from {self.name}: {timepoint_description}, {since_last_log_time:.2f}s since last watch reset. {elapsed_time:.2f}s total elapsed time.")


###########################
#
Expand Down