Timing Time in Bash

As someone who uses bash all the time, I got used to $EPOCHSECONDS as a source of time. As a shell variable, it’s probably the fastest way to get that information. That said, getting down to using date is still something I occassionally do. It’s supported accross the shells and it’s still fast enough.

But, I started wondering - what is the speed difference? As an example I decided to use SECONDS % 60 as it’s not only getting seconds but also processing them a bit. I would say that is a representative usage of the time - not just reading but also adding some light arithmetic operation. So, I prepared a script to execute the following:

echo $EPOCHREALTIME
echo $((EPOCHSECONDS %60))
echo $EPOCHREALTIME
printf '%(%S)T\n'
echo $EPOCHREALTIME
echo $(date +%S)
echo $EPOCHREALTIME

On bash this will run my three equivalent examples of how to get a number of seconds and get their execution time in microseconds. Yes, echo here is bluring results a bit but it’s bluring them for all examples the same. For a quick test, it’s good enough. So, I placed this into a 100x loop and here are the results.

CommandAverageStDevRatio
echo $((EPOCHSECONDS %60))0.0000380.0000141.00
printf '%(%S)T\n'0.0001110.0000362.95
echo $(date +%S)0.0046540.000726123.78

As expected, using $EPOCHSECONDS is the fastest. I am slightly surprised that printf is 3x slower. I guess it makes sense because it is doing additional parsing, but I expected the result to be closer. But both of those are in microseconds on my laptop.

The only test to reach the milliseconds was date. Invoking date was 42x slower than printf and almost 124x slower than using the variable directly. Now, while this looks dreadful in comparison, in reality it’s not that bad as this doesn’t mean CPU was busy for the duration. But I find it still a bit worrying considering how often I used it myself.

But let’s be realistic - you are not echoing date command. You are probably just storing it into variable - what is the effect then?

echo $EPOCHREALTIME
TEST=$((EPOCHSECONDS %60))
echo $EPOCHREALTIME
printf -v TEST '%(%S)T'
echo $EPOCHREALTIME
TEST=$(date +%S)
echo $EPOCHREALTIME

Well, this run resulted in the following table.

CommandAverageStDevRatio
TEST=$((EPOCHSECONDS %60))0.0000180.0000071.00
printf -v TEST '%(%S)T'0.0000930.0000235.17
TEST=$(date +%S)0.0040760.000451226.58

Times did reduce a bit, especially for printf, but the ratios got even worse.

In the end, if you need to deal with a local time zone or you need a POSIX shell, date is still worth it. But, for bash-specific scripts, I will start paying a bit more attention to use EPOCHSECONDS when I can.

Trim on the Framework Expansion Cards

To handle trim on framework expansion cards, you can adjust udev rules:

cat << EOF | sudo tee /etc/udev/rules.d/42-framework-storage.rules
ACTION=="add|change", SUBSYSTEM=="scsi_disk", ATTRS{idVendor}=="13fe", ATTRS{idProduct}=="6500", ATTR{provisioning_mode}="unmap"
ACTION=="add|change", SUBSYSTEM=="scsi_disk", ATTRS{idVendor}=="32ac", ATTRS{idProduct}=="0005", ATTR{provisioning_mode}="unmap"
ACTION=="add|change", SUBSYSTEM=="scsi_disk", ATTRS{idVendor}=="32ac", ATTRS{idProduct}=="0010", ATTR{provisioning_mode}="unmap"
EOF

If you don’t want to restart, follow that with:

sudo udevadm control --reload-rules
sudo udevadm trigger

And that works.

However, under kernel 7.0 I noticed that unplugging and repluggin device would disable trim (as checked with lsblk -D). To be honest, this might have been happening under older kernel too and I just didn’t notice. Regardless, I needed a solution.

To cut a long story short, my solution was to manually trigger udevadm 2 seconds after USB device has been added. Not the most elegant solution, but it does work.

cat << EOF | sudo tee /etc/udev/rules.d/42-framework-storage.rules
ACTION=="add|change", SUBSYSTEM=="scsi_disk", ATTRS{idVendor}=="13fe", ATTRS{idProduct}=="6500", ATTR{provisioning_mode}="unmap"
ACTION=="add|change", SUBSYSTEM=="scsi_disk", ATTRS{idVendor}=="32ac", ATTRS{idProduct}=="0005", ATTR{provisioning_mode}="unmap"
ACTION=="add|change", SUBSYSTEM=="scsi_disk", ATTRS{idVendor}=="32ac", ATTRS{idProduct}=="0010", ATTR{provisioning_mode}="unmap"
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="32ac", ATTR{idProduct}=="0005", RUN+="/bin/sh -c 'sleep 2; udevadm trigger'"
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="32ac", ATTR{idProduct}=="0010", RUN+="/bin/sh -c 'sleep 2; udevadm trigger'"
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="13fe", ATTR{idProduct}=="6500", RUN+="/bin/sh -c 'sleep 2; udevadm trigger'"
EOF

DaVinci Resolve 18 on Ubuntu 23.10 with Intel GPU

While I am not really a video editing guy I do occassionally play with DaVinci Resolve. Unfortunately, installation was not really straightforward under Ubuntu. Even worse, as I switched to AMD laptop with internal GPU, Resolve didn’t work at all.

As one of those video editing opportunities arose, I decided to try my luck on Kubuntu 26.04. Since this OS is quite newer than my current DaVinci resolve machine (Ubuntu 24.04), I decided to scratch previous procedure and try installation from scratch. Once basic install is done, I can figure which libraries are missing and need adjustment.

So, I downloaded DaVinci Resolve 23.0.1 and executed the following commands:

cd ~/Downloads
unzip DaVinci_Resolve_21.0.3_Linux.zip
chmod +x DaVinci_Resolve_21.0.3_Linux.run
sudo SKIP_PACKAGE_CHECK=1 ./DaVinci_Resolve_21.0.3_Linux.zip

Once install was done, I started the application expecting errors but everything worked just fine. Yes, even on AMD internal GPU.

Now, free version still doesn’t deal with MP4 files and AAC under Linux - darn licenses. Regardless, I am happy to do some pre-conversion before editing rather then dealing with Windows.

Not All Rotates Are Made Equal

If you are dealing with encryption algorithms at all, you will notice bitwise rotate operation is used with regularity. While most processors have it available, not all languages do. For example, C# will force you to use shifting and or alternative, something like this:

(value >> count) | (value << (64 - count))

What might come as a surprise is that this incurs no performance penalty as compared to the native rotate operation. How come?

Well, a couple of years ago issue 4519 dealt with this exact problem. While it was deemed to disruptive to introduce rotate operation to the whole .NET system, it was possible to make JIT smarter. Whenever JIT notices operation pattern above, it will call upon native rotate operation, thus drastically improving performance.

However, since we’re talking about pattern recognition, you need to be careful how you write it. While we can write rotate operation in multitude of ways, not all of them will result in performance improvement. If you want rotate, better stick with the “official” pattern.

Avalonia ShowDialog and a Minimize Button

If you use ShowDialog in Avalonia, you will notice that under KDE/Wayland, window will retain minimize button. Even worse, minimize will hide the window, leaving its owner visible but not clickable. Slightly annoying and user might not even understand immediatelly why clicks on the main window are not working until they restore minimized dialog.

And, try as I might, I found no way to remove minimize box without removing the whole title. Since I was not in the mood to handle titleless windows, the next best thing was to close dialog window on minimize. Of course, detecting when window gets minimized is not really straightforward.

In the end, this is the code I ended up using:

PropertyChanged += (sender, e) => {
  if (e.Property == Window.WindowStateProperty && WindowState == WindowState.Minimized) {
    Dispatcher.UIThread.InvokeAsync(() => {
      WindowState = WindowState.Normal;
      Close();
    });
  }
};

We inject our check into the general PropertyChanged event handling. However, we cannot directly close window here as it will not revert focus to the owner. What we need is to ask dispatcher to invoke our code once UI thread has a spare moment. Then we restore the freshly minimized window, followed by close.

Not great, but not terrible either.