Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Upvote just for teaching me about the existence of `hyperfine`.

    $ hyperfine 'alacritty -e true'
    Benchmark 1: alacritty -e true
      Time (mean ± σ):      84.1 ms ±   4.9 ms    [User: 40.1 ms, System: 30.8 ms]
      Range (min … max):    80.5 ms … 104.4 ms    32 runs
    
    $ hyperfine 'xterm -e true'
    Benchmark 1: xterm -e true
      Time (mean ± σ):      81.9 ms ±   2.6 ms    [User: 21.7 ms, System: 7.9 ms]
      Range (min … max):    74.9 ms …  87.1 ms    37 runs
    
    $ hyperfine 'wezterm -e true'
    Benchmark 1: wezterm -e true
      Time (mean ± σ):     211.7 ms ±  13.4 ms    [User: 41.4 ms, System: 60.0 ms]
      Range (min … max):   190.5 ms … 240.5 ms    15 runs


If we're handing out tips, then as noted in a few examples from the article hyperfine is even more useful when called with multiple commands directly. It presents a concise epilogue with the information you're probably trying to gleam from a run such as yours:

    $ hyperfine -L arg '1,2,3' 'sleep {arg}'
    …
    Summary
      sleep 1 ran
        2.00 ± 0.00 times faster than sleep 2
        3.00 ± 0.00 times faster than sleep 3
If your commands don't share enough in common for that approach then you can declare them individually, as in "hyperfine 'blib 1' 'blob x y' 'blub --arg'", and still get the summary.


i once used hyperfine to micro-bench elisp functions. i se $SHELL to a script that evaluated it's arguments in emacs by talking to a long-running session over a named pipe. Hyperfine runs a few no-ops with $SHELL and factored out the overhead, though it was still helpful to run a nested loop in elisp for finer results.


Besides learning about `hyperfine`, the combination of `xargs` to keep N warm processes ready, `LD_PRELOAD` to trick them into waiting to map their windows, and `pkill --oldest ...` to get one of those to go is quite neat.

But I have a very different solution to this problem: have just one terminal window and use and abuse `tmux`. I only use new windows (or tabs, if the terminal app has those) to run `ssh` to targets where I use `tmux`. I even nest `tmux` sessions, so essentially I've two levels of `tmux` sessions, and I title each window in the top-level session to match the name of the session running in that window -- this helps me find things very quickly. I also title windows running `vi` after the `basename` of the file being edited. Add in a simple PID-to-tmux window resolver script, scripts for utilities like `cscope` to open new windows, and this gets very comfortable, and it's fast. I even have a script that launches this whole setup should I need to reboot. Opening a new `tmux` window is very snappy!



I also didn't know about `hyperfine`, very nice!

Even 80ms seems unnecessarily slow to me. 300ms would drive me nuts ...

I'm using a tiling window manager (dwm) and interestingly the spawning time varies depending on the position that the terminal window has to be rendered to.

The fastest startup time I get on the fullscreen tiling mode.

   hyperfine 'st -e true'
   Benchmark 1: st -e true
     Time (mean ± σ):      35.7 ms ±  10.0 ms    [User: 15.4 ms, System: 4.8 ms]
     Range (min … max):    17.2 ms …  78.7 ms    123 runs
The non-fullscreen one ends up at about 60ms which still seems reasonable.


You could maybe find out where the delay is by using st's Xembed support? Create a window with tabbed¹ in a tiling layout, open st in to it with "st -w <xid> -e true". If it is close to the monocle time, it is probably the other windows handling the resize event that is causing the slowdown not the layout choice.

To prove it to myself: I'm using river² and I can see a doubling-ish of startup time with foot³, iff I allow windows from heavier apps to handle the resize event immediately. If the time was a little longer(or more common) I'd be tempted to wrap the spawn along the lines of "kill -STOP <other_clients_in_tag>; <spawn & hold for map>; kill -CONT <other_clients_in_tag>" to delay the resize events until my new window was ready. That way the frames still resize, but their content resize is delayed.

¹ https://tools.suckless.org/tabbed/

² https://codeberg.org/river/river

³ https://codeberg.org/dnkl/foot


The result of running the same on st for me:

    Benchmark 1: st -e true
      Time (mean ± σ):      35.4 ms ±   6.9 ms    [User: 15.1 ms, System: 3.8 ms]
      Range (min … max):    24.2 ms …  65.2 ms    114 runs
This is on awesome-wm with the window opening as the 3rd tiled window on a monitor, which means it has to redraw at least the other two windows. I'm also running xfs on top of luks/dm-crypt for my filesystem, which shouldn't matter too much on this benchmark thanks to the page cache, but is a relatively common source of performance woes on this particular system. I really ought to migrate back to unencrypted ext4 and use my SSD's encryption but I haven't wanted to muck with it.


To get an idea of the cost of tiling (with bspwm, quarter screen tile and 2560x1440@60Hz screen):

  hyperfine -L args '','-c floating' 'st {args} -e true'
  Benchmark 1: st  -e true
    Time (mean ± σ):      25.0 ms ±   2.7 ms    [User: 10.5 ms, System: 3.7 ms]
    Range (min … max):    14.8 ms …  44.1 ms    197 runs

  Benchmark 2: st -c floating -e true
    Time (mean ± σ):      22.7 ms ±   2.6 ms    [User: 10.3 ms, System: 3.9 ms]
    Range (min … max):    20.7 ms …  35.4 ms    123 runs

  Summary
    'st -c floating -e true' ran
      1.10 ± 0.17 times faster than 'st  -e true'
Flexing my system too, heh.


Does it parse commands and call exec*() or spawn a new shell for every run of every command?


You can choose the behaviour with the --shell option¹. The default behaviour is nice because it allows you to benchmark pipelines easily, but if you want to change it you can.

¹ https://github.com/sharkdp/hyperfine#intermediate-shell




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: