Jot Evaluation

Text-editor evaluation and comparison

This note compares jot to several popular text editors. See also

and

The editors included in this comparison were:

In windowsland

For Raspberry pi these editors were tried:

Method

The tasks can in general be describes as "time loading some stonking-great text file, doing something then exiting without writing". One might reasonably ask "so who's interested in knowing how long it takes to do something with a file several orders of magnitude bigger than I shall ever be dealing with?" The answer is: when our editors are performing some complicated series of programmed operations, the raw performance determines how long we have to sit and stare at a static screen. It also, perhaps, places our editors under stress so we can detect any memory-stress related crashyness.

The run-time comparison used the time_trial.jot script, this launches the editors and calculates elapsed times. This script only reports elapsed times but was used in preference to the linux "time" command as it works equally well in windowsland.

Tests were run using reasonably large files for two reasons:

Both vi and emacs are, by default, case sensitive whereas jot and ecce are not. Case sensitive searches are simpler and one would expect them to run searches a bit faster. All jot runs include a command to make searches case sensitive - this version of ecce appears to be lacking such a command.

The values in the text density section were obtained from the RSS reported by the linux time command, while the editor was processing the big file. e.g:

$ /usr/bin/time -f "  %E elapsed, %U user, %S system, %P CPU, (%F major + %R minor) faults, %I io, %M rss" jot big_file.txt -in=%a

In all cases the session was abandoned without writing back to the filing system.

The linux-PC tests were run on a Fedora 34 desktop system with (according to lscpu and lsmem):

The Windows tests were run on the same system under wine and genuine windows 10. Under wine, the headless emacs tasks all failed - complaining it was not connected to a genuine terminal.

The Raspberry pi was:

The test files

A sample file of about 500Mb was created by jot using these commands:

$ rm big_file.txt
$ jot -in="%eq=ls -RF /usr/lib; %r=ls2list; \

%da= 00 aaa This is the start of the big file; za %o= -append big_file.txt; \ ol100000000 z. m-0((%i.= -binary=32 'q; i'qbr0b %o= -append big_file.txt;, ) %q$=file big_file.txt; f/ size = /-oid o> zqm)0 \ %d$= 00 zzz This is the end of the big file; %o= -append big_file.txt; %a;"

A similar file but with very long lines, was created thusly:

$ rm fat_file.txt
$ jot -in="%eq=ls -RF /usr/lib; %r=ls2list; \

%da= 00 aaa This is the start of the fat file; za %o= -append fat_file.txt; \ ol100000000 m-0((%i.= -binary=64 'q; (m-0(jm)0m-)0 r-0i'qbr0b %o= -append fat_file.txt;, ) %q$=file fat_file.txt; f/ size = /-oid o> zqm)0 \ %d$= 00 zzz This is the end of the fat file; %o= -append fat_file.txt; %a;"

Image Size

The total installed size of some of these editors is not immediately obvious - applying du -b to /usr/share/<name>, in the case of jot the size given is that of the unpacked tarball, this includes includes two statically-linked linux executables and the windows executable:

Text density

The big file is loaded up and the session exits without any other editing activity while the process is being monitored by the linux time command. And the The RSS result is recorded - this shows the peak memory used. For a big file this should give a reasonable indication of the text packing density.

First the big file:

In summary: rss

But nano's memory usage goes through the roof when handling the fat file - see postscript

Image activation time

The elapsed time is not particularly reliable in the case of emacs and nano, since these do not seem to offer any options to enter editor commands from the command line. For nano and emacs the session was quickly closed using interactive commands.

PC-linux:

  • vim

  • $ time_trial vim t.t -c:q
      0:00.02 elapsed, 0.01 user, 0.00 system, 100% CPU, (0 major + 988 minor) faults, 0 io, 9372 rss
    

    Loading a big file

    A sample file of about 500Mb was created by jot using these commands:

    $ rm big_file.txt
    $ jot -in="%eq=ls -RF /usr/lib; %r=ls2list; \
    

    %da= 00 aaa This is the start of the big file; za %o= -append big_file.txt; \ ol500000000 z. m-0((%i.= -binary=32 'q; i'qbr0b %o= -append big_file.txt;, ) %q$=file big_file.txt; f/ size = /-oid o> zqm)0 \ %d$= 00 zzz This is the end of the big file; %o= -append big_file.txt; %a;"

    The resultant file was, unfortunately too big for the emacs buffer so it was reduced to 445495954B bu editing.

    PC-linux:

    {Ctrl+x} - to exit.

      0:04.23 elapsed, 3.11 user, 0.55 system, 86% CPU, (4 major + 197674 minor) faults, 896 io, 793484 rss
    

    PC-windows:

    {Ctrl+x} - to exit.

      
    

    Pi-linux:

    {Ctrl+x} - to exit.

      0m45.516s
    

    The results are all pretty much the same - jot and vim were a bit faster but all were within acceptable limits.

    Loading a big file and searching forwards

    The big_file.txt is loaded again and this time each editor is set to search the entire file for a string that only occurs at the end of the file.

    PC-linux:

    PC-Windows:

    {Ctrl+x} - to exit.

      
    

    Pi-linux:

    {Ctrl+x} - to exit.

      0m45.516s
    

    Pi-linux:

  • vi

  • $ time vi big_file.txt -c/zzz/ +:q
      1m38.429s
    

    Loading a file and moving to the end

    The only reason for doing this is to obtain a slightly more accurate estimate of the reverse-search time (in the following section).

    PC-Linux:

    {Ctrl+_}{Ctrl+v}{Ctrl+x}

      0:09.67 elapsed, 3.24 user, 0.63 system, 40% CPU, (0 major + 197676 minor) faults, 0 io, 793488 rss
    

    PC-Windows:

    {Ctrl+_}{Ctrl+v}{Ctrl+x}

      
    

    Pi-Linux:

    {Ctrl+_}{Ctrl+v}{Ctrl+x}

      1m0.387s
    

    Loading a file, moving to the end then searching back

    In this test we ask our editors to go right to the end of a big file and then find a string that appears only at the very beginning of the file.

    PC-Linux:

    PC-Windows:

  • emacs (.el-lisp script)

  • $ cat - > x.el << end-of-lisp
    (insert-file-contents "big_file.txt")
    (goto-char (point-max))
    (search-backward "aaa")
    end-of-lisp
    $ time emacs --script x.el
      0m38.495s
    

    Loading a big file and doing a global search and replace - 1

    In this case the replacement string is the same length as the original. Originally this was tried with the search string "00", and both jot and vim acquitted themselves quite well but emacs failed miserably and had to be killed after 30 minutes. This failure appears to be something to do with the undo journal it maintains.

    So, for this test we use the much less commonly-occurring search string "99".

    PC-Windows:

    Pi-linux:

  • {Ctrl+\}99{Return}zz{Return}a{Return}

  • Loading a big file and doing a global search and replace - 2

    In this case the replacement string is the longer than the original. This is an important difference since our editors must somehow shuffle the text and allocate more memory for the extended lines.

    PC-Windows:

    Pi-linux:

  • {Ctrl+\}99{Return}abcdefghi{Return}a{Return}

  • Loading a big file and doing a global search and replace - 3

    In this case the replacement string is the shorter than the original. This is an important difference since our editors must shuffle the text.

    PC-Linux:

    PC-Windows:

    PI-linux:

    Loading a big file and doing a global regex-search and replace

    PC-Linux:

  • {Ctrl+\}{Alt+r}[^a-zA-Z0-9]99[^a-zA-Z0-9]{Return} zz {Return}a{Return}

  • PC-Windows:

  • {Ctrl+\}{Alt+r}[^a-zA-Z0-9]99[^a-zA-Z0-9]{Return} zz {Return}a{Return}

  • Pi-Linux:

  • {Ctrl+\}{Alt+r}[^a-zA-Z0-9]99[^a-zA-Z0-9]{Return} zz {Return}a{Return}

  • Loading, cutting and pasting and pasting all of a big file

    PC-Linux:

  • {Ctrl+^} - to set a mark.

  • PC-Windows:

  • {Alt+a} - to set a mark.

  • Pi-Linux:

  • {Ctrl+^} - to set a mark.

  • Loading a file with very long lines - a fat file

    A file of just under 300Mb was created with these commands, it has 547 lines of varying length, some over 20Mb, most are several hundred Kb long. There are 18356191 instances of the string "00" and 50192 instances of the string "99".

    This series of tests is intended to compare performance for handling files with long lines.

    PC-Linux:

    PC-Windows:

    pi-Linux:

    Loading a fat file and searching

    This test is intended to compare performance for reading and searching files with long lines. The string is right at the end of the file so our editors must go through the whole file.

    PC-linux:

    PC-Windows:

    pi-linux:

    Loading a fat file and and doing a global search and replace - 1

    This test compares the performance for searching and replacing with a new string of the same size. We're searching for "99" because there so too many instances of "00" all but one of the editors crashed or exceeded the 30 minute limit. That editor was, of course, jot which, if you're interested, did the lot in under 3 seconds.

    Substituting a string of the same size as the original should be the simplest search-and-replace situation since no new memory or byte shifting is required. Later sections will repeat these tests but for both longer and shorter substitutions.

    PC-linux:

    Loading a fat file and and doing a global search and replace - 2

    This time the substitute string is a bit longer than the original.

    PC-linux:

    Loading a fat file and and doing a global search and replace - 3

    This time the substitute string is shorter than the original.

    PC-linux:

    Loading the fat file, moving to the end then searching back

    PC-Linux:

    MS-Windows editors

    Analysis of performance comparison.

    Command structure

    More

    Conclusions

    Postscript

    There were persistent problems with editors crashing on tasks they usually have no trouble performing. Also nano seemed to be particularly crashy when attempting the long-line file tasks. It was experimentally determined that nano, even if it did not crash itself, was somehow cause subsequent programmes to crash some time after nano had, apparently successfully, finished it's task and exited - maybe a memory leak?

    The editors were run manually with the time utility monitoring a few system parameters while they did a global search and replace in the same file with very long lines. The test_file.txt used was a shortened version of fat_file.txt just under 8Mb with lines of up to 3mb long. The editors task was a global substitution - changing the 603 instances of "99" to "abcdefghi",

    /usr/bin/time -f "  %E elapsed, %U user, %S system, %P CPU, (%F major + %R minor) faults, %I io, %M rss" jot test_file.txt -quiet -in="%f= -global_substitute=abcdefghi 99; %a0;"
    

    0:00.12 elapsed, 0.08 user, 0.03 system, 99% CPU, (0 major + 4793 minor) faults, 0 io, 16764 rss

    /usr/bin/time -f "  %E elapsed, %U user, %S system, %P CPU, (%F major + %R minor) faults, %I io, %M rss" vim test_file.txt -c:%s/99/abcdefghi/g +:q!
    

    0:00.74 elapsed, 0.69 user, 0.04 system, 99% CPU, (0 major + 14512 minor) faults, 0 io, 38760 rss

    /usr/bin/time -f "  %E elapsed, %U user, %S system, %P CPU, (%F major + %R minor) faults, %I io, %M rss" emacs -execute '(insert-file-contents "test_file.txt")' -execute '(replace-string "99" "abcdefghi")' -kill
    

    0:00.83 elapsed, 0.60 user, 0.09 system, 83% CPU, (20 major + 10360 minor) faults, 0 io, 99372 rss

    /usr/bin/time -f "  %E elapsed, %U user, %S system, %P CPU, (%F major + %R minor) faults, %I io, %M rss" ecce test_file.txt -command "(f/99/s/a/)0" -command "%a"
    

    ... 0:00.14 elapsed, 0.12 user, 0.01 system, 98% CPU, (0 major + 3914 minor) faults, 0 io, 16720 rss

    /usr/bin/time -f "  %E elapsed, %U user, %S system, %P CPU, (%F major + %R minor) faults, %I io, %M rss" nano test_file.txt 
    

    3:35.64 elapsed, 195.80 user, 1.00 system, 91% CPU, (0 major + 488202 minor) faults, 0 io, 1937276 rss

    In summary

    Name    Elapsed     User System  CPU  Major  Minor      IO      RSS
    

    jot 0

    00.12 0.08 0.03 99% 0 4793 0 16764

    vim 0

    00.74 0.69 0.04 99% 0 14512 0 38760

    emacs 0

    00.83 0.60 0.09 83% 20 10360 0 99372

    ecce 0

    00.14 0.12 0.01 98% 0 3914 0 16720

    nano 3

    35.64 195.80 1.00 91% 0 488202 0 1937276

    Phew!!!! nano's main claim my be that it's small, friendly and lightweight but, an RSS of 1937276 for a 8Mb file, that's neither small or lightweight and definitely unfriendly - one might easily mistake it for a memory-gobbling monster.