NeoMutt  2025-12-11-694-ga89709
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
benchmark.c File Reference

Standalone benchmark for libfuzzy. More...

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "lib.h"
+ Include dependency graph for benchmark.c:

Go to the source code of this file.

Functions

static double get_time_ms (void)
 Get current time in milliseconds.
 
static void benchmark_basic (const char *pattern, const char *candidate, int iterations, const char *description)
 Basic pattern matching benchmark.
 
static void benchmark_mailbox_list (const char *pattern, int iterations)
 Benchmark searching through mailbox list.
 
static void benchmark_options (const char *pattern, const char *candidate, int iterations)
 Benchmark with different options.
 
int main (int argc, char *argv[])
 Entry point for fuzzy benchmark.
 

Variables

static const char * mailbox_paths []
 
static const int NUM_MAILBOXES = sizeof(mailbox_paths) / sizeof(mailbox_paths[0])
 

Detailed Description

Standalone benchmark for libfuzzy.

Authors
  • Richard Russon

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, see http://www.gnu.org/licenses/.

Definition in file benchmark.c.

Function Documentation

◆ get_time_ms()

static double get_time_ms ( void )
static

Get current time in milliseconds.

Return values
numCurrent time in milliseconds

Definition at line 86 of file benchmark.c.

87{
88#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0
89 struct timespec ts;
90 clock_gettime(CLOCK_MONOTONIC, &ts);
91 return (ts.tv_sec * 1000.0) + (ts.tv_nsec / 1000000.0);
92#else
93 // Fallback to less accurate clock()
94 return (double) clock() / CLOCKS_PER_SEC * 1000.0;
95#endif
96}
+ Here is the caller graph for this function:

◆ benchmark_basic()

static void benchmark_basic ( const char * pattern,
const char * candidate,
int iterations,
const char * description )
static

Basic pattern matching benchmark.

Parameters
patternPattern to match
candidateCandidate string
iterationsNumber of iterations
descriptionTest description

Definition at line 105 of file benchmark.c.

107{
108 struct FuzzyOptions opts = { 0 };
109 struct FuzzyResult result = { 0 };
110
111 double start = get_time_ms();
112
113 int matches = 0;
114 for (int i = 0; i < iterations; i++)
115 {
116 int score = fuzzy_match(pattern, candidate, FUZZY_ALGO_SUBSEQ, &opts, &result);
117 if (score >= 0)
118 matches++;
119 }
120
121 double end = get_time_ms();
122 double elapsed = end - start;
123 double per_match = elapsed / iterations;
124 double throughput = iterations / (elapsed / 1000.0);
125
126 printf("%-50s ", description);
127 printf("%8.2f ms ", elapsed);
128 printf("%8.3f µs/op ", per_match * 1000.0);
129 printf("%10.0f ops/sec ", throughput);
130 printf("(%d/%d matches)\n", matches, iterations);
131}
static double get_time_ms(void)
Get current time in milliseconds.
Definition benchmark.c:86
bool candidate(struct CompletionData *cd, char *user, const char *src, char *dest, size_t dlen)
Helper function for completion.
Definition helpers.c:79
@ FUZZY_ALGO_SUBSEQ
Subsequence matching algorithm.
Definition lib.h:77
int fuzzy_match(const char *pattern, const char *candidate, enum FuzzyAlgo algo, const struct FuzzyOptions *opts, struct FuzzyResult *out)
Perform fuzzy matching.
Definition fuzzy.c:58
Options for fuzzy matching.
Definition lib.h:87
Result of a fuzzy match.
Definition lib.h:98
int score
Score (<0 = no match)
Definition lib.h:99
int start
First match position.
Definition lib.h:101
int end
Last match position.
Definition lib.h:102
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ benchmark_mailbox_list()

static void benchmark_mailbox_list ( const char * pattern,
int iterations )
static

Benchmark searching through mailbox list.

Parameters
patternPattern to search for
iterationsNumber of times to search through all mailboxes

Definition at line 138 of file benchmark.c.

139{
140 struct FuzzyOptions opts = { .smart_case = true };
141 struct FuzzyResult result = { 0 };
142
143 double start = get_time_ms();
144
145 int total_matches = 0;
146 for (int i = 0; i < iterations; i++)
147 {
148 for (int j = 0; j < NUM_MAILBOXES; j++)
149 {
150 int score = fuzzy_match(pattern, mailbox_paths[j], FUZZY_ALGO_SUBSEQ, &opts, &result);
151 if (score >= 0)
152 total_matches++;
153 }
154 }
155
156 double end = get_time_ms();
157 double elapsed = end - start;
158 int total_ops = iterations * NUM_MAILBOXES;
159 double per_match = elapsed / total_ops;
160 double throughput = total_ops / (elapsed / 1000.0);
161
162 printf("%-50s ", "Mailbox list search");
163 printf("%8.2f ms ", elapsed);
164 printf("%8.3f µs/op ", per_match * 1000.0);
165 printf("%10.0f ops/sec ", throughput);
166 printf("(%d matches in %d ops)\n", total_matches, total_ops);
167}
static const char * mailbox_paths[]
Definition benchmark.c:53
static const int NUM_MAILBOXES
Definition benchmark.c:80
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ benchmark_options()

static void benchmark_options ( const char * pattern,
const char * candidate,
int iterations )
static

Benchmark with different options.

Parameters
patternPattern to match
candidateCandidate string
iterationsNumber of iterations

Definition at line 175 of file benchmark.c.

176{
177 struct FuzzyResult result = { 0 };
178
179 // Case insensitive
180 {
181 struct FuzzyOptions opts = { .case_sensitive = false };
182 double start = get_time_ms();
183
184 for (int i = 0; i < iterations; i++)
185 fuzzy_match(pattern, candidate, FUZZY_ALGO_SUBSEQ, &opts, &result);
186
187 double elapsed = get_time_ms() - start;
188 printf("%-50s %8.2f ms %8.3f µs/op\n", " Case-insensitive", elapsed,
189 elapsed / iterations * 1000.0);
190 }
191
192 // Case sensitive
193 {
194 struct FuzzyOptions opts = { .case_sensitive = true };
195 double start = get_time_ms();
196
197 for (int i = 0; i < iterations; i++)
198 fuzzy_match(pattern, candidate, FUZZY_ALGO_SUBSEQ, &opts, &result);
199
200 double elapsed = get_time_ms() - start;
201 printf("%-50s %8.2f ms %8.3f µs/op\n", " Case-sensitive", elapsed,
202 elapsed / iterations * 1000.0);
203 }
204
205 // Smart case
206 {
207 struct FuzzyOptions opts = { .smart_case = true };
208 double start = get_time_ms();
209
210 for (int i = 0; i < iterations; i++)
211 fuzzy_match(pattern, candidate, FUZZY_ALGO_SUBSEQ, &opts, &result);
212
213 double elapsed = get_time_ms() - start;
214 printf("%-50s %8.2f ms %8.3f µs/op\n", " Smart case", elapsed,
215 elapsed / iterations * 1000.0);
216 }
217
218 // With prefix preference
219 {
220 struct FuzzyOptions opts = { .prefer_prefix = true };
221 double start = get_time_ms();
222
223 for (int i = 0; i < iterations; i++)
224 fuzzy_match(pattern, candidate, FUZZY_ALGO_SUBSEQ, &opts, &result);
225
226 double elapsed = get_time_ms() - start;
227 printf("%-50s %8.2f ms %8.3f µs/op\n", " Prefer prefix", elapsed,
228 elapsed / iterations * 1000.0);
229 }
230}
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ main()

int main ( int argc,
char * argv[] )

Entry point for fuzzy benchmark.

Parameters
argcNumber of arguments
argvArgument vector
Return values
0Success

Definition at line 238 of file benchmark.c.

239{
240 int iterations = 100000;
241
242 if (argc > 1)
243 {
244 iterations = atoi(argv[1]);
245 if (iterations <= 0)
246 iterations = 100000;
247 }
248
249 if (iterations < 100)
250 iterations = 100;
251
252 printf("=================================================================\n");
253 printf("libfuzzy Benchmark - %d iterations per test\n", iterations);
254 printf("=================================================================\n\n");
255
256 printf("Test Time Per Op Throughput Results\n");
257 printf("------------------------------------------------------------------------------------------------------------------------------\n");
258
259 // Short pattern, short candidate
260 benchmark_basic("box", "mailbox", iterations, "Short pattern + short candidate");
261
262 // Short pattern, medium candidate
263 benchmark_basic("mlnd", "mailinglists/neomutt-dev", iterations,
264 "Short pattern + medium candidate");
265
266 // Short pattern, long candidate
267 benchmark_basic("arch", "Archive/2024/January/Projects/NeoMutt", iterations,
268 "Short pattern + long candidate");
269
270 // Medium pattern, long candidate
271 benchmark_basic("archjan", "Archive/2024/January/Projects/NeoMutt",
272 iterations, "Medium pattern + long candidate");
273
274 // No match
275 benchmark_basic("xyz", "mailbox", iterations, "No match");
276
277 // Prefix match
278 benchmark_basic("mail", "mailbox", iterations, "Prefix match");
279
280 // Scattered match
281 benchmark_basic("mlnd", "mailing_list_node_database", iterations, "Scattered match");
282
283 // Full match
284 benchmark_basic("inbox", "inbox", iterations, "Full match");
285
286 printf("\n");
287
288 // Mailbox list benchmark
289 printf("Realistic Scenario - Searching mailbox list (%d mailboxes)\n", NUM_MAILBOXES);
290 printf("------------------------------------------------------------------------------------------------------------------------------\n");
291 benchmark_mailbox_list("inbox", iterations / 100);
292 benchmark_mailbox_list("mlnd", iterations / 100);
293 benchmark_mailbox_list("arch", iterations / 100);
294 benchmark_mailbox_list("work", iterations / 100);
295
296 printf("\n");
297
298 // Options comparison
299 printf("Options Comparison\n");
300 printf("------------------------------------------------------------------------------------------------------------------------------\n");
301 benchmark_options("inbox", "INBOX", iterations);
302
303 printf("\n");
304
305 printf("=================================================================\n");
306 printf("Benchmark Complete\n");
307 printf("=================================================================\n");
308
309 return 0;
310}
static void benchmark_mailbox_list(const char *pattern, int iterations)
Benchmark searching through mailbox list.
Definition benchmark.c:138
static void benchmark_basic(const char *pattern, const char *candidate, int iterations, const char *description)
Basic pattern matching benchmark.
Definition benchmark.c:105
static void benchmark_options(const char *pattern, const char *candidate, int iterations)
Benchmark with different options.
Definition benchmark.c:175
+ Here is the call graph for this function:

Variable Documentation

◆ mailbox_paths

const char* mailbox_paths[]
static
Initial value:
= {
"INBOX",
"Archive/2023",
"Archive/2024/January",
"Archive/2024/February",
"Sent",
"Drafts",
"Trash",
"mailinglists/neomutt-dev",
"mailinglists/neomutt-users",
"mailinglists/linux-kernel",
"mailinglists/debian-devel",
"work/projects/libfuzzy",
"work/projects/neomutt",
"work/reports/weekly",
"work/reports/monthly",
"personal/family",
"personal/friends",
"personal/receipts",
"notifications/github",
"notifications/gitlab",
"shopping/amazon",
"shopping/ebay",
"travel/bookings",
"travel/confirmations",
}

Definition at line 53 of file benchmark.c.

53 {
54 "INBOX",
55 "Archive/2023",
56 "Archive/2024/January",
57 "Archive/2024/February",
58 "Sent",
59 "Drafts",
60 "Trash",
61 "mailinglists/neomutt-dev",
62 "mailinglists/neomutt-users",
63 "mailinglists/linux-kernel",
64 "mailinglists/debian-devel",
65 "work/projects/libfuzzy",
66 "work/projects/neomutt",
67 "work/reports/weekly",
68 "work/reports/monthly",
69 "personal/family",
70 "personal/friends",
71 "personal/receipts",
72 "notifications/github",
73 "notifications/gitlab",
74 "shopping/amazon",
75 "shopping/ebay",
76 "travel/bookings",
77 "travel/confirmations",
78};

◆ NUM_MAILBOXES

const int NUM_MAILBOXES = sizeof(mailbox_paths) / sizeof(mailbox_paths[0])
static

Definition at line 80 of file benchmark.c.