Skip to content

Commit

Permalink
Merge pull request #8223 from ckan/profile-profile
Browse files Browse the repository at this point in the history
cli profile improvements
  • Loading branch information
amercader committed May 23, 2024
2 parents 73dfa66 + b8b99b3 commit f8e9b1f
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 24 deletions.
5 changes: 5 additions & 0 deletions changes/8223.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fix profile cli, add --cold and --best-of options.

By default cli profile will now run the request once (cold), then give the
best of the next 3 (hot) runs. Use --cold --best-of=1 for the old cli profile
behavior.
50 changes: 26 additions & 24 deletions ckan/cli/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
from . import error_shout


@click.group(
short_help=u"Code speed profiler.", invoke_without_command=True,
)
@click.pass_context
def profile(ctx: click.Context):
@click.command(short_help="Code speed profiler.")
@click.argument("url")
@click.argument("user", required=False, default="visitor")
@click.option('--cold', is_flag=True, default=False, help='measure first call')
@click.option('-b', '--best-of', type=int, default=3, help='best of N calls')
def profile(url: str, user: str, cold: bool, best_of: int):
"""Provide a ckan url and it will make the request and record how
long each function call took in a file that can be read by
pstats.Stats (command-line) or runsnakerun (gui).
pstats.Stats (command-line) or SnakeViz (web).
Usage:
profile URL [username]
Expand All @@ -28,36 +29,37 @@ def profile(ctx: click.Context):
You may need to install python module: cProfile
"""
if ctx.invoked_subcommand is None:
ctx.invoke(main)


@profile.command('profile', short_help=u"Code speed profiler.",)
@click.argument(u"url")
@click.argument(u"user", required=False, default=u"visitor")
def main(url: str, user: str):
import cProfile
from cProfile import Profile
from ckan.tests.helpers import _get_test_app

app = _get_test_app()

def profile_url(url: str): # type: ignore # noqa
def profile_url(url: str):
try:
app.get(
url, status=[200], environ_overrides={"REMOTE_USER": str(user)}
url, status=200, environ_overrides={"REMOTE_USER": str(user)}
)
except KeyboardInterrupt:
raise
except Exception:
error_shout(traceback.format_exc())

output_filename = u"ckan%s.profile" % re.sub(
u"[/?]", u".", url.replace(u"/", u".")
)
profile_command = u"profile_url('%s')" % url
cProfile.runctx(
profile_command, globals(), locals(), filename=output_filename
)
if not cold:
profile_url(url)

best = None
for _n in range(best_of):
with Profile() as pr:
profile_url(url)
if best is None or (best.getstats()[0].totaltime # type: ignore
> pr.getstats()[0].totaltime): # type: ignore
best = pr

if best is None:
return

output_filename = "ckan%s.profile" % re.sub(r"[\W]", ".", url)
best.dump_stats(output_filename)
import pstats

stats = pstats.Stats(output_filename)
Expand Down

0 comments on commit f8e9b1f

Please sign in to comment.