diff options
| author | Tomas Janousek <tomi@nomi.cz> | 2020-11-12 10:02:44 +0000 | 
|---|---|---|
| committer | jao <jao@gnu.org> | 2020-11-13 02:10:31 +0000 | 
| commit | 17b0dac481c01425651326e8814b45058cd40f06 (patch) | |
| tree | cabb9394e29880b7460ae3cfbc449c53bd416722 /src | |
| parent | e47cb0222eb5b152f69a18f4685726a5460f4b90 (diff) | |
| download | xmobar-17b0dac481c01425651326e8814b45058cd40f06.tar.gz xmobar-17b0dac481c01425651326e8814b45058cd40f06.tar.bz2 | |
Optimize Date plugin again (refresh timezone only once a minute)
This makes the Date plugin approximately twice as fast, and makes xmobar
up to about 5–10 % faster if Date is the only active plugin. (If more
expensive plugins like Network or MultiCpu are used, it doesn't make any
measurable difference.)
Micro-benchmark results on my HW:
    Date Benchmarks/Date                     mean 2.833 μs  ( +- 16.08 ns  )
    Date Benchmarks/DateZonedTime            mean 5.020 μs  ( +- 32.91 ns  )
    Date Benchmarks/DateWithTimeZone         mean 2.827 μs  ( +- 20.52 ns  )
(DateZonedTime is the original implementation and DateWithTimeZone is
the implementation we had since 0.34 which never refreshes timezone.)
Real-life measurements (done overnight on an idle laptop, with all
measured xmobars running in parallel to ensure comparable conditions;
xmobars configured to only display date and with rate 10 — once per
second):
    $ time timeout 6h xmobar .xmobarrc-DateZonedTime
    real    360m0,010s
    user    0m9,867s
    sys     0m4,644s
    (9.867 + 4.644) / (360 * 60) = 0.000672
    $ time timeout 6h xmobar .xmobarrc-Date
    real    360m0,008s
    user    0m9,535s
    sys     0m4,327s
    (9.535 + 4.327) / (360 * 60) = 0.000642
    $ time timeout 6h xmobar .xmobarrc-Date-10m
    real    360m0,010s
    user    0m9,780s
    sys     0m4,215s
    (9.780 + 4.215) / (360 * 60) = 0.000648
    $ time timeout 6h xmobar .xmobarrc-DateWithTimeZone
    real    360m0,006s
    user    0m9,658s
    sys     0m4,166s
    (9.658 + 4.166) / (360 * 60) = 0.000640
(.xmobarrc-Date-10m is the proposed implementation, but with timezone
refresh every 10 minutes instead of every 1 minute)
Interpretation of these results:
 * refreshing xmobar with just date takes around 650 μs
 * that is xmobar with just date uses around 0.065 % of CPU time
 * refreshing timezone takes additional cca 30 μs
When we only refresh timezone once a minute, these 30 μs become 0.5 μs
amortized, and that should be acceptable to even the most dedicated
perfectionist :-)
Fixes: a58e32f7c8af ("Revert "Optimize date plugin"")
Fixes: 878db3908060 ("Optimize date plugin")
Co-authored-by: Sibi Prabakaran <sibi@psibi.in>
Diffstat (limited to 'src')
| -rw-r--r-- | src/Xmobar/Plugins/Date.hs | 21 | 
1 files changed, 17 insertions, 4 deletions
| diff --git a/src/Xmobar/Plugins/Date.hs b/src/Xmobar/Plugins/Date.hs index 1cb0596..d7de2e9 100644 --- a/src/Xmobar/Plugins/Date.hs +++ b/src/Xmobar/Plugins/Date.hs @@ -17,22 +17,35 @@  --  ----------------------------------------------------------------------------- -module Xmobar.Plugins.Date (Date(..)) where +module Xmobar.Plugins.Date (Date(..), date) where  import Xmobar.Run.Exec  #if ! MIN_VERSION_time(1,5,0)  import System.Locale  #endif +import Data.IORef  import Data.Time +import Control.Concurrent.Async (concurrently_)  data Date = Date String String Int      deriving (Read, Show)  instance Exec Date where      alias (Date _ a _) = a -    run   (Date f _ _) = date f      rate  (Date _ _ r) = r +    start (Date f _ r) cb = +        -- refresh time zone once a minute to avoid wasting CPU cycles +        withRefreshingZone 600 $ \zone -> +            doEveryTenthSeconds r $ date zone f >>= cb -date :: String -> IO String -date format = fmap (formatTime defaultTimeLocale format) getZonedTime +date :: IORef TimeZone -> String -> IO String +date zoneRef format = do +    zone <- readIORef zoneRef +    fmap (formatTime defaultTimeLocale format . utcToZonedTime zone) getCurrentTime + +withRefreshingZone :: Int -> (IORef TimeZone -> IO ()) -> IO () +withRefreshingZone r action = do +    zone <- newIORef =<< getCurrentTimeZone +    let refresh = atomicWriteIORef zone =<< getCurrentTimeZone +    concurrently_ (doEveryTenthSeconds r refresh) (action zone) | 
