5 comments

  • bormaj 1 hour ago
    Great explanation of why a branchless approach results in such a speed up. I've never really had to deal with performance optimization at this level. Generally it's probably best not to get too involved letting the CPU black box do its thing.

    I do wonder, would the performance characteristics of branchless vs branching be consistent across different CPUs/architectures? If you had a CPU that wasn't trying to be fancy with branch prediction, would the regular algo be faster?

    • throwaway_95283 24 minutes ago
      CPUs aren't black boxes. They are actually much better documented than almost all the software that runs on them.

      If you want to treat the CPU as a black box, trust me you do not want to use a CPU with out a branch predictor, your slow code will run like molasses frozen in antarctica.

      The regular algo will be lightyears slower on any CPU that does not have a branch predictor.

    • nvme0n1p1 44 minutes ago
      Virtually every CPU has branch prediction, going back to at least the original Pentium (1993), maybe earlier.

      If you're running on a very old CPU, yes, the regular algo should be faster.

    • Brian_K_White 6 minutes ago
      Another recent story from github about case folding as part of code search, the simple version of the code had a couple of ifs, and the branchless version was actually slower.

      They have a stupendously fast version and it is also branchless, but it just required more than branchless alone.

      I'm fuzzy on the details but I think one of the ifs was an early exit, and without that the loop does a memory assignment on every byte instead of skipping most.

      The really fast version was also vectorized. The branchless makes it possible to vectorize, but it was the vectorization that actually made it fast.

  • veqq 42 minutes ago
    I've been doing leetcode in Janet in a (sometimes) tacit (variabless), branchless way:

        (def find-shared-gcd
          (comp
           (fn [e] (max ;(map (fn [d] (* d ;(map |(- 1 (min 1 (mod $ d))) e)))
                             (range 1 (+ 1 (min ;e))))))
           |((juxt* max min) ;$)))
    
       
        (defn max-diff `where elements increase` [& numbs]
          (reduce max
                  -1 (filter |(< 0 $) # strip 0s and add -1 in case (= true (apply > numbs))
                                 (map - numbs (accumulate2 min numbs)))))
  • Retro_Dev 13 minutes ago
    This article is 100% AI written. The data was interesting, the commentary overly verbose and hard to gain useful insights from.
  • codetiger 1 hour ago
    Thanks for sharing, optimisations like these are what keeps the fun in programming. I have been optimising my JSONLogic evaluator in rust and used arena allocator and preallocation tricks that gave me good jump in tuning. Let me see if branchless programming techniques can get any further in my case
  • crazysim 57 minutes ago
    Would PGO figure this out?
    • j16sdiz 37 minutes ago
      They could.

      but.... running PGO is just too much pain.

      We can't do it "incrementally", can we? How about combining with LTO?

      edit: I was thinking profiling individual module on a test driver and link them after PGO