NeoMutt
2025-12-11-1040-g5187ba
Teaching an old dog new tricks
DOXYGEN
Toggle main menu visibility
Loading...
Searching...
No Matches
benchmark.c
Go to the documentation of this file.
1
22
45
46
#include <stdbool.h>
47
#include <stdio.h>
48
#include <stdlib.h>
49
#include <time.h>
50
#include "
lib.h
"
51
52
// Sample mailbox paths for realistic testing
53
static
const
char
*
mailbox_paths
[] = {
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
};
79
80
static
const
int
NUM_MAILBOXES
=
sizeof
(
mailbox_paths
) /
sizeof
(
mailbox_paths
[0]);
81
86
static
double
get_time_ms
(
void
)
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
}
97
105
static
void
benchmark_basic
(
const
char
*pattern,
const
char
*
candidate
,
106
int
iterations,
const
char
*description)
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
}
132
138
static
void
benchmark_mailbox_list
(
const
char
*pattern,
int
iterations)
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
}
168
175
static
void
benchmark_options
(
const
char
*pattern,
const
char
*
candidate
,
int
iterations)
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
}
231
238
int
main
(
int
argc,
char
*argv[])
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
}
main
int main(int argc, char *argv[])
Entry point for fuzzy benchmark.
Definition
benchmark.c:238
mailbox_paths
static const char * mailbox_paths[]
Definition
benchmark.c:53
benchmark_mailbox_list
static void benchmark_mailbox_list(const char *pattern, int iterations)
Benchmark searching through mailbox list.
Definition
benchmark.c:138
benchmark_basic
static void benchmark_basic(const char *pattern, const char *candidate, int iterations, const char *description)
Basic pattern matching benchmark.
Definition
benchmark.c:105
benchmark_options
static void benchmark_options(const char *pattern, const char *candidate, int iterations)
Benchmark with different options.
Definition
benchmark.c:175
NUM_MAILBOXES
static const int NUM_MAILBOXES
Definition
benchmark.c:80
get_time_ms
static double get_time_ms(void)
Get current time in milliseconds.
Definition
benchmark.c:86
candidate
bool candidate(struct CompletionData *cd, char *user, const char *src, char *dest, size_t dlen)
Helper function for completion.
Definition
helpers.c:79
lib.h
Fuzzy matching library.
FUZZY_ALGO_SUBSEQ
@ FUZZY_ALGO_SUBSEQ
Subsequence matching algorithm.
Definition
lib.h:82
fuzzy_match
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
FuzzyOptions
Options for fuzzy matching.
Definition
lib.h:92
FuzzyResult
Result of a fuzzy match.
Definition
lib.h:103
FuzzyResult::score
int score
Score (<0 = no match).
Definition
lib.h:104
FuzzyResult::start
int start
First match position.
Definition
lib.h:106
FuzzyResult::end
int end
Last match position.
Definition
lib.h:107