From 08bae8d9be6fa7a61589ee3b8f77177e600c4c61 Mon Sep 17 00:00:00 2001 From: Jim Miller Date: Fri, 10 Apr 2026 16:49:17 -0500 Subject: [PATCH] Imperfect, but working perf profiling --- calibre-plugin/fff_plugin.py | 27 ++++----------------------- calibre-plugin/jobs.py | 22 ++++++++++++++++++++++ fanficfare/cli.py | 4 +++- fanficfare/fff_profile.py | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 24 deletions(-) create mode 100644 fanficfare/fff_profile.py diff --git a/calibre-plugin/fff_plugin.py b/calibre-plugin/fff_plugin.py index f7547471..eedeccdf 100644 --- a/calibre-plugin/fff_plugin.py +++ b/calibre-plugin/fff_plugin.py @@ -10,27 +10,6 @@ __docformat__ = 'restructuredtext en' import fanficfare.six as six from fanficfare.six import ensure_text, string_types, text_type as unicode -# from io import StringIO -# import cProfile, pstats -# from pstats import SortKey - -# def do_cprofile(func): -# def profiled_func(*args, **kwargs): -# profile = cProfile.Profile() -# try: -# profile.enable() -# result = func(*args, **kwargs) -# profile.disable() -# return result -# finally: -# # profile.print_stats() -# s = StringIO() -# sortby = SortKey.CUMULATIVE -# ps = pstats.Stats(profile, stream=s).sort_stats(sortby) -# ps.print_stats(20) -# print(s.getvalue()) -# return profiled_func - import logging logger = logging.getLogger(__name__) @@ -91,6 +70,8 @@ from fanficfare.geturls import ( get_urls_from_page, get_urls_from_text,get_urls_from_imap, get_urls_from_mime) +from fanficfare.fff_profile import do_cprofile + from calibre_plugins.fanficfare_plugin.fff_util import ( get_fff_adapter, get_fff_config, get_fff_personalini, get_common_elements) @@ -1304,7 +1285,7 @@ class FanFicFarePlugin(InterfaceAction): # let other exceptions percolate up. return adapter.getStoryMetadataOnly(get_cover=False) - # @do_cprofile + @do_cprofile def prep_download_loop(self,book, options={'fileform':'epub', 'collision':ADDNEW, @@ -1900,7 +1881,7 @@ class FanFicFarePlugin(InterfaceAction): else: return None - # @do_cprofile + @do_cprofile def update_books_loop(self,book,db=None, options={'fileform':'epub', 'collision':ADDNEW, diff --git a/calibre-plugin/jobs.py b/calibre-plugin/jobs.py index 1b1a3955..ee5ea496 100644 --- a/calibre-plugin/jobs.py +++ b/calibre-plugin/jobs.py @@ -24,12 +24,34 @@ try: except NameError: pass # load_translations() added in calibre 1.9 +from io import StringIO +import cProfile, pstats +from pstats import SortKey +def do_cprofile(func): + def profiled_func(*args, **kwargs): + profile = cProfile.Profile() + try: + profile.enable() + result = func(*args, **kwargs) + profile.disable() + return result + finally: + # profile.print_stats() + s = StringIO() + sortby = SortKey.CUMULATIVE + ps = pstats.Stats(profile, stream=s).sort_stats(sortby) + ps.print_stats(20) + print(s.getvalue()) + return profiled_func + + # ------------------------------------------------------------------------------ # # Functions to perform downloads using worker jobs # # ------------------------------------------------------------------------------ +@do_cprofile def do_download_worker_single(site, book_list, options, diff --git a/fanficfare/cli.py b/fanficfare/cli.py index f0d69727..498a6f96 100644 --- a/fanficfare/cli.py +++ b/fanficfare/cli.py @@ -27,7 +27,6 @@ import pprint import string import os, sys, platform - version="4.56.1" os.environ['CURRENT_VERSION_ID']=version @@ -51,6 +50,8 @@ from fanficfare.geturls import get_urls_from_page, get_urls_from_imap from fanficfare.six.moves import configparser from fanficfare.six import text_type as unicode +from fanficfare.fff_profile import do_cprofile + def write_story(config, adapter, writeformat, metaonly=False, nooutput=False, outstream=None): @@ -346,6 +347,7 @@ def main(argv=None, dispatch(options, urls, passed_defaultsini, passed_personalini, warn, fail) # make rest a function and loop on it. +@do_cprofile def do_download(arg, options, passed_defaultsini, diff --git a/fanficfare/fff_profile.py b/fanficfare/fff_profile.py new file mode 100644 index 00000000..6b31c277 --- /dev/null +++ b/fanficfare/fff_profile.py @@ -0,0 +1,35 @@ +# Copyright 2026 FanFicFare team +# +# Licensed under the Apache License, Version 2.0 (the 'License'); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an 'AS IS' BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from io import StringIO +import cProfile, pstats +from pstats import SortKey +def do_cprofile(func): + def profiled_func(*args, **kwargs): + profile = cProfile.Profile() + try: + profile.enable() + result = func(*args, **kwargs) + profile.disable() + return result + finally: + # profile.print_stats() + s = StringIO() + sortby = SortKey.CUMULATIVE + ps = pstats.Stats(profile, stream=s).sort_stats(sortby) + ps.print_stats(20) + print(s.getvalue()) + return profiled_func +