diff --git a/Makefile.meson b/Makefile.meson index 22527586..a0b338eb 100644 --- a/Makefile.meson +++ b/Makefile.meson @@ -26,12 +26,18 @@ ifneq ($(V),0) VERBOSE=--verbose endif + +.PHONY: all +.PHONY: check test test-verbose-if-fail test-valgrind test-helgrind +.PHONY: benchmark coverage +.PHONY: dist install clean distclean +.PHONY: mu4e-doc-html + # MESON_FLAGS, e.g. "-Dreadline=enabled" # examples: # 1. build with clang, and the thread-sanitizer # make clean all MESON_FLAGS="-Db_sanitize=thread" CXX=clang++ CC=clang - all: $(BUILDDIR) $(NINJA) -C $(BUILDDIR) $(VERBOSE) @@ -43,6 +49,19 @@ check: test test: all $(MESON) test $(VERBOSE) -C $(BUILDDIR) + +install: $(BUILDDIR) + @cd $(BUILDDIR); $(MESON) install + +clean: + @rm -rf $(BUILDDIR) $(COVERAGE_BUILDDIR) + + +# +# below targets are just for development/testing/debugging. They may or +# may not work on your system. +# + test-verbose-if-fail: all @cd $(BUILDDIR); $(MESON) test || $(MESON) test --verbose @@ -56,6 +75,9 @@ test-helgrind: $(BUILDDIR) --wrap='valgrind --tool=helgrind --error-exitcode=1' \ --timeout-multiplier 100 +benchmark: $(BUILDDIR) + $(NINJA) -C $(BUILDDIR) benchmark + $(COVERAGE_BUILDDIR): $(MESON) -Db_coverage=true --buildtype=debug $(COVERAGE_BUILDDIR) @@ -63,7 +85,7 @@ covfile:=$(COVERAGE_BUILDDIR)/meson-logs/coverage.info # generate by hand, meson's built-ins are unflexible coverage: $(COVERAGE_BUILDDIR) - ninja -C $(COVERAGE_BUILDDIR) test + $(NINJA) -C $(COVERAGE_BUILDDIR) test lcov --capture --directory . --output-file $(covfile) @lcov --remove $(covfile) '/usr/*' '*guile*' '*thirdparty*' '*/tests/*' '*mime-object*' --output $(covfile) @mkdir -p $(COVERAGE_BUILDDIR)/meson-logs/coverage @@ -72,11 +94,7 @@ coverage: $(COVERAGE_BUILDDIR) dist: $(BUILDDIR) @cd $(BUILDDIR); $(MESON) dist -install: $(BUILDDIR) - @cd $(BUILDDIR); $(MESON) install - -clean: - @test -d $(BUILDDIR) && $(NINJA) -C $(BUILDDIR) clean +distclean: clean HTMLPATH=${BUILDDIR}/mu4e/mu4e mu4e-doc-html: diff --git a/lib/tests/bench-mu-store.cc b/lib/tests/bench-mu-store.cc new file mode 100644 index 00000000..4449663a --- /dev/null +++ b/lib/tests/bench-mu-store.cc @@ -0,0 +1,151 @@ +/* +** Copyright (C) 2022 Dirk-Jan C. Binnema +** +** This program is free software; you can redistribute it and/or modify it +** under the terms of the GNU General Public License as published by the +** Free Software Foundation; either version 3, or (at your option) any +** later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, +** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +** +*/ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "mu-maildir.hh" + +using namespace Mu; + +constexpr auto test_msg = R"(Date: Sat, 21 May 2022 07:55:16 -0700 +From: "Quinn @ID@" +To: test@ID@.example.com +Message-ID: +In-Reply-To: <314151592@ID@@example.com> +References: <2718281828@ID@@example.com> +Subject: Test Message @ID@ +Mime-Version: 1.0 +Content-Type: multipart/alternative; + boundary="--==_mimepart_6288fd545cc61_3421d2c8149243"; + charset=UTF-8 +Content-Transfer-Encoding: 7bit + +----==_mimepart_6288fd545cc61_3421d2c8149243 +Content-Type: text/plain; + charset=UTF-8 +Content-Transfer-Encoding: 7bit + +Just some random text. + +-- +Reply to this email directly or view it on GitHub: +https://github.com/djcb/mu/pull/2262#issuecomment-1133647407 +You are receiving this because you are subscribed to this thread. + +Message ID: +----==_mimepart_6288fd545cc61_3421d2c8149243 +Content-Type: text/html; + charset=UTF-8 +Content-Transfer-Encoding: 7bit + +

+Some random text as html +----==_mimepart_6288fd545cc61_3421d2c8149243-- +)"; + + +static std::string +message(const std::regex& rx, size_t id) +{ + char buf[16]; + ::snprintf(buf, sizeof(buf), "%zu", id); + return std::regex_replace(test_msg, rx, buf); +} + + +static void +setup(size_t num_maildirs, size_t num_messages) +{ + /* create toplevel */ + auto top_maildir = std::string{BENCH_MAILDIRS}; + int res = g_mkdir_with_parents(top_maildir.c_str(), 0700); + g_assert_cmpuint(res,==, 0); + + /* create maildirs */ + for (size_t i = 0; i != num_maildirs; ++i) { + const auto mdir = format("%s/maildir-%zu", top_maildir.c_str(), i); + auto res = maildir_mkdir(mdir); + g_assert(!!res); + } + const auto rx = std::regex("@ID@"); + /* create messages */ + for (size_t n = 0; n != num_messages; ++n) { + auto mpath = format("%s/maildir-%zu/cur/msg-%zu:2,S", + top_maildir.c_str(), + n % num_maildirs, + n); + std::ofstream stream(mpath); + auto msg = message(rx, n); + stream.write(msg.c_str(), msg.size()); + g_assert_true(stream.good()); + } +} + +static void +tear_down() +{ + /* ugly */ + GError *err{}; + const auto cmd{format("/bin/rm -rf '%s' '%s'", BENCH_MAILDIRS, BENCH_STORE)}; + if (!g_spawn_command_line_sync(cmd.c_str(), NULL, NULL, NULL, &err)) { + g_warning("error: %s\n", err ? err->message : "?"); + g_clear_error(&err); + } +} + +int +main(int argc, char *argv[]) +{ + using namespace std::chrono_literals; + using Clock = std::chrono::steady_clock; + + constexpr size_t NumMaildirs=20; + constexpr size_t NumMessages=5000; + + setup(NumMaildirs, NumMessages); + + auto start = Clock::now(); + + { + auto store{Store::make_new(BENCH_STORE, BENCH_MAILDIRS, {}, {})}; + g_assert_true(!!store); + auto res = store->indexer().start({}); + g_assert_true(res); + while(store->indexer().is_running()) { + std::this_thread::sleep_for(100ms); + } + g_assert_cmpuint(store->size(),==,NumMessages); + } + const auto elapsed = Clock::now() - start; + std::cout << "indexed " << NumMessages << " messages in " + << NumMaildirs << " maildirs in " + << to_ms(elapsed) << "ms; " + << to_us(elapsed) / NumMessages << "us/msg\n"; + + tear_down(); + + return 0; +} diff --git a/lib/tests/meson.build b/lib/tests/meson.build index 42508a6e..2438f936 100644 --- a/lib/tests/meson.build +++ b/lib/tests/meson.build @@ -61,3 +61,16 @@ test('test-parser', 'test-parser.cc', install: false, dependencies: [glib_dep, gmime_dep, lib_mu_dep, lib_test_mu_common_dep])) +# +# benchmarks +# +bench_maildirs=join_paths(meson.current_build_dir(), 'maildirs') +bench_store=join_paths(meson.current_build_dir(), 'store') +benchmark('bench-store', + executable('bench-store', + 'bench-mu-store.cc', + install:false, + cpp_args:['-DBENCH_MAILDIRS="' + bench_maildirs + '"', + '-DBENCH_STORE="' + bench_store + '"', + ], + dependencies: [lib_mu_dep, glib_dep]))