I like your program, but is there any way to improve the performance? When I input large files, for example, a file with 5,000 lines of emojis, the program 'thinks' for about a second, while other similar programs work instantly
I think there is definitely room for improving wmenu's performance. Does loading the search results of wmenu take a long time as well, or is it just the initial load that takes a long time?
Each loading takes a long time, not just the first one. I also conducted a few more tests: for example, I created 100 copies of a file with emojis and entered the command cat emoji.txt* | wmenu, and the menu appeared only after 13 seconds, while dmenu and other similar programs appear instantly. However, wmenu is heavily dependent on the number of lines in a file; it works acceptably only if there are no more than 500 lines in a file, but other similar programs are indifferent to the number of lines and work instantly
I probably misunderstood you - the initial loading takes a long time, but the search results happens quickly
i use it with rofimoji. it opens instantly for me
@treeshateorcs wrote in #27 (comment):
i use it with rofimoji. it opens instantly for me
I ran cat /usr/lib/python3.13/site-packages/picker/data/emojis_* | wc -l, and it returned 1910. This doesn't appear instantly but with a slight delay corresponding to the number of lines
I ran cat /usr/lib/python3.13/site-packages/picker/data/emojis_* | wc -l, and it returned 1910. This doesn't appear instantly but with a slight delay corresponding to the number of lines
same result here (1910), but it runs instantly, right after i press enter. maybe it depends on hardware
@treeshateorcs wrote in #27 (comment):
I ran cat /usr/lib/python3.13/site-packages/picker/data/emojis_* | wc -l, and it returned 1910. This doesn't appear instantly but with a slight delay corresponding to the number of lines
same result here (1910), but it runs instantly, right after i press enter. maybe it depends on hardware
Well, that's about 0.2 seconds, but it's not instant; try piping a large file with 10,000 lines or more, and you'll see that the delay increases with the size of the file
it took 0.2 seconds to move my finger from up arrow to enter. i just did this with a 100k line long file (100k letters "a" each on its own line) and it's still instant
@treeshateorcs wrote in #27 (comment):
it took 0.2 seconds to move my finger from up arrow to enter. i just did this with a 100k line long file (100k letters "a" each on its own line) and it's still instant
Try this
@treeshateorcs wrote in #27 (comment):
still instant
Can you show a video of executing the command cat large.txt | wmenu?
no, i can't. because the command does nothing for me
oh wait no, it takes about 3-4 seconds
@treeshateorcs wrote in #27 (comment):
oh wait no, it takes about 3-4 seconds
Other similar programs do this in 0 seconds
I took some time to benchmark wmenu on a large input (doing wmenu < words.txt, an English dictionary with 466550 lines and almost 5 MB) to find out exactly where the slow parts of the program are. This is admittedly a large input, but it should show where some of the the bottlenecks are.
Startup
Measuring just the time to start the program, display the first frame, and exit, the total time is about 3 seconds, and the majority (97%) of the CPU time to spent (according to perf record --call-graph dwarf .../perf report), inside menu_run() > menu_render_items() > calc_widths() > text_width() > get_text_size(), measuring the display sizes of individual entries of the input. The maximum of these sizes determines the input area width menu->inputw.
Using a fixed input area width (e.g. calculated with a formula like min(max(20 em, 1/5 screen width), 1/2 screen width)), like I believe dmenu does, would make it possible to avoid this specific calculation.
The display sizes of input entries are also used to determine how to page all the searched items (see page_items() in menu.c) but in theory the pages could be done on demand, since (unless one jumps to the end of the page list) only the layout of the first page is immediately needed.
Text width calculation may be slower in particular for emojis than for alphabetical text because it may require much more font/character loading work. Depending on how many and which fonts you have and use it could vary a lot.
Searching for words:
After starting wmenu < words.txt, I measured the time to repeatedly search for t, te, t, te, t etc. (by typing a letter and backspacing). Each search took about 25ms (leading to a noticeable >1 frame delay). According to perf record --call-graph dwarf -p `pidof wmenu` , 95% of the time is spent in match_items(), and about 75% of that in fstrstr(). I can think of several directions to optimize this:
fstrstr()takes O(w k) time for query length k and entry length w. There are asymptotically faster algorithms; for example, with Knuth-Morris-Pratt is a rather practical O(w + k) time algorithm, which uses a lightweight O(k) time preprocessing of the query string that can be reused for each entry. Case insensitive comparison should be doable by storing a case folded + normalized version of the query string and entry strings (see e.g. https://www.w3.org/TR/charmod-norm/#definitionCaseFolding ; https://unicode-org.github.io/icu/userguide/transforms/casemappings.html#case-folding)- Exact and prefix matches are put first in the results list; on inputs where you have enough of these, you can avoid doing substring searches until the user advances to a page that needs them. Building an index (e.g. a sorted list of all entries) should make it possible to very quickly find exact and prefix matches using binary search; however, it could slow down startup.
- When a letter is added, the new result list will be a subset of the previous result list, so you can search within the old list
I'd be open to updating wmenu's input area size calculation to match dmenu's, especially if it improves performance. However, the width of each input item is also used to paginate menu items ahead of time. I believe dmenu does the width calculations on demand as you page through the items, but I could be wrong. wmenu originally used to do it that way as well, but I eventually resorted to paginating items ahead of time to fix bugs with the old approach.
One consequence of this approach is that pagination works slightly differently than in dmenu. In dmenu, paging from the beginning and paging from the end results in different pages due to the dynamic page calculations, whereas wmenu's pages are consistent in both directions since they are computed ahead of time.
In order to fix the performance issue, we'd likely need to revert to dmenu's method of calculating pages. This could potentially reduce memory usage as well.
No due date set.
No dependencies set.
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?