Skip to content

INFR: Add Timer context manager for modern timing patterns #783

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Aug 16, 2025

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Aug 12, 2025

This PR implements a Timer context manager to modernize timing patterns in QuantEcon.py, addressing the infrastructure need identified in the issue.

Problem

The codebase currently uses manual timing patterns like:

start_time = time()
freq = compute_freq(params, key).block_until_ready()
end_time = time()
print(f"Elapsed time: {(end_time - start_time) * 1000:.6f} ms")

This approach is verbose and error-prone, requiring manual time calculations and formatting.

Solution

Added a Timer context manager that provides clean, modern timing syntax:

# Basic usage
with Timer():
    freq = compute_freq(params, key).block_until_ready()
# Output: 0.05 seconds elapsed

# With custom message and units
with Timer("Computing frequency", unit="milliseconds"):
    freq = compute_freq(params, key).block_until_ready()
# Output: Computing frequency: 50.25 ms elapsed

# Store elapsed time for method comparison
timer = Timer(silent=True)
with timer:
    freq = compute_freq(params, key).block_until_ready()
elapsed_time = timer.elapsed  # Available for comparison

Features

  • Multiple time units: seconds (default), milliseconds, microseconds
  • Customizable precision: Control decimal places in output
  • Silent mode: Store timing without printing for method comparisons
  • Custom messages: Add context to timing output
  • Exception safety: Works correctly even when exceptions occur
  • Stored elapsed time: Access timer.elapsed after context exit for performance comparisons

Implementation Details

  • Added Timer class to existing quantecon/util/timing.py module
  • Exported from both quantecon.Timer and quantecon.util.Timer
  • Maintains full backward compatibility with existing tic/tac/toc functions
  • Comprehensive test coverage with 8 new test methods
  • All existing tests continue to pass

Usage Examples

The Timer supports various usage patterns:

import quantecon as qe

# Replace old patterns
with qe.Timer():
    result = expensive_computation()

# Method comparison (as requested)
timers = []
for method in [method_a, method_b, method_c]:
    timer = qe.Timer(f"{method.__name__}", silent=True)
    with timer:
        method()
    timers.append((method.__name__, timer.elapsed))

fastest = min(timers, key=lambda x: x[1])
print(f"Fastest method: {fastest[0]} ({fastest[1]:.6f}s)")

Fixes #782.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@Copilot Copilot AI assigned Copilot and mmcky Aug 12, 2025
Copy link
Contributor Author

Copilot AI commented Aug 12, 2025

@mmcky 👋 This repository doesn't have Copilot instructions. With Copilot instructions, I can understand the repository better, work faster and produce higher quality PRs.

I can generate a .github/copilot-instructions.md file for you automatically. Click here to open a pre-filled issue and assign it to me. I'll write the instructions, and then tag you for review.

@Copilot Copilot AI changed the title [WIP] INFR: write a Timer context manager INFR: Add Timer context manager for modern timing patterns Aug 12, 2025
@Copilot Copilot AI requested a review from mmcky August 12, 2025 03:13
Copilot finished work on behalf of mmcky August 12, 2025 03:13
@coveralls
Copy link

coveralls commented Aug 12, 2025

Coverage Status

coverage: 92.626% (-0.09%) from 92.72%
when pulling f30fd36 on copilot/fix-782
into 0a4af14 on main.

@mmcky
Copy link
Contributor

mmcky commented Aug 12, 2025

This is an example of use within a lecture from

Screenshot 2025-08-12 at 1 44 03 pm

@jstac I quite like this style and the functionality that copilot has put together.

for comparison here is our existing tic, toc version

Screenshot 2025-08-12 at 1 47 37 pm

@mmcky
Copy link
Contributor

mmcky commented Aug 12, 2025

  • get feedback and comments from @jstac, @HumphreyYang, @oyamad about implementation
  • update QuantEcon.manual with some usage examples

@jstac
Copy link
Contributor

jstac commented Aug 12, 2025

This is really nice @mmcky :-)

I'm happy for you to go ahead. It will be really nice to get these changes propagated...

@mmcky
Copy link
Contributor

mmcky commented Aug 15, 2025

thanks @jstac.

I will double check the code and get this merged.

Note (@jstac): from a style perspective do you prefer this approach for timing code to using Jupyter cell magics %time and %%timeit? -- I find them to be a relatively good approach to getting timing information, but I quite like the context manager as it wraps code that is being timed so doesn't have to be a one-liner function (for example)

As I see it the main downside is %%timeit is that it does multiple runs and finds the average so takes longer and %time can't save results for comparison

Screenshot 2025-08-15 at 11 45 18 am

@oyamad
Copy link
Member

oyamad commented Aug 15, 2025

I have usecases of tic, tac, toc from qe for example here.
It would be nice if how to migrate from those to the new pattern is documented in the deprecating notice.

@mmcky
Copy link
Contributor

mmcky commented Aug 15, 2025

I have usecases of tic, tac, toc from qe for example here. It would be nice if how to migrate from those to the new pattern is documented in the deprecating notice.

Fully agree @oyamad.

We are in no real rush to remove them, but I was thinking about issuing a DeprecationWarning with links to a migration guide -- perhaps in the next major release.

#783 (comment) includes the pattern, but including in the notice is always helpful.

Given we have an open issue (See #786) -- I will check that box off and we can treat that separately.

@oyamad I have updated the QuantEcon manual with some more information https://manual.quantecon.org/styleguide/code.html#performance-timing-patterns

@mmcky mmcky merged commit 6045b51 into main Aug 16, 2025
12 checks passed
@mmcky mmcky deleted the copilot/fix-782 branch August 16, 2025 01:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

INFR: write a Timer context manager
5 participants