Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28441 Discussions

Why is even a simple SELECT CASE always apparently slow?

New Contributor II

Even simple uses of SELECT CASE appear to be slow. Using "ifx -O3" or "ifort -O3" on a simple Linux setup  I get very different times for the different inner operations that with three other compilers all reduce to the same time or have the SELECT CASE the fastest.  Is there an additional

option required to optimize SELECT CASE?

The example is rather unnatural to prevent the loops from being eliminated and to compare the simple code differences in the inner code "DO I=1,SZ" loops, but it simple repeatedly converts an ASCII string to uppercase just as a sample, as it shows that SELECT CASE with CHARACTER cases seem to be particularly slow.  I have tried a variety of options in addition to -O and so far some of these are horribly slow.

program main
   implicit none
   integer, parameter         :: ade_a = iachar('a'), ade_z = iachar('z'), diff = iachar('A') - iachar('a')
   character(len=*), parameter :: in = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789?/,./!@#$%^&'
   integer, parameter          :: sz = len(in), calls = 1000000
   character(len=sz)          :: string, str, keep
   integer                    :: i, j, k, ch, ii
   real                       :: rr
   doubleprecision            :: time_start, time_finish

   do k=0,3
      call setup() ! get a baseline time with a basic assign, assuming loop not optimized away
      do j = 1, calls
            select case(k)
               ! just an assign for a baseline, assuming loop is not optimized away
               string = str
               do i=1,sz
                  ch = iachar(str(i:i))
                  if (ch >= ade_a .and. ch <= ade_z) ch = ch + diff
                  string(i:i) = achar(ch)
               do i=1,sz
                  select case (str(i:i))
                  case ('a':'z'); string(i:i) = achar(iachar(str(i:i)) + diff)
                  case default; string(i:i) = str(i:i)
                  end select
               do i=1,sz
                  ch = iachar(str(i:i))
                  select case (ch)
                  case (ade_a:ade_z); string(i:i) = achar(ch + diff)
                  case default; string(i:i) = str(i:i)
                  end select
            case default
               stop '<ERROR>'
            end select
            if (j .eq. ii) keep = string
      end do
      call finish()
   end do


   subroutine setup()
   real     :: rr
      str = random_string(in, len(in)) ! do some random stuff to keep loops from being optimzed away
      call random_number(rr)
      ii = max(1, int(rr*calls))
      keep = ''
      call cpu_time(time_start)
   end subroutine setup

   subroutine finish()
      call cpu_time(time_finish)
      print '(i10,1x,*(g0,1x))', int(100000*(time_finish - time_start)), ' ', keep, (time_finish - time_start)
   end subroutine finish

   function random_string(chars, length) result(out)
      character(len=*), intent(in)     :: chars
      integer, intent(in)              :: length
      character(len=:), allocatable    :: out
      real                         :: x
      integer                      :: ilen, which, i
      ilen = len(chars)
      out = ''
      if (ilen .gt. 0) then
         do i = 1, length
            call random_number(x)
            which = nint(real(ilen - 1)*x) + 1
            out = out//chars(which:which)
         end do
      end if
   end function random_string

end program main
       655   acAX$9y!69z,h.Z2we/hdgP@g!hV?j&5bm&3qWNJ9c^R4G06Gp1X1pxt3OUUKIjNo%RbxOXbtI .6553999999999999E-02
      2254   RUDM7Y.Z2TXW@%LFXSM@NNPBKOSVJ3W%.5%VWRV#QXOTN?/HSUOH0TWCL/$OXP$S2!A%4QNU7L .2254600000000000E-01
    184174   WC8O^@7EPUIMMPUFB7O#1N5DSTAQ!P$/ZRC/CO1/YL9T6E2S#P.JZ,VLTPX,PKTYS?XMZTE6DO 1.841741000000000
      2861   4P4NHP3VPUY4FFY%7MPG.6@DRIWEQ,.ZWMQIURVAP4XAF%F2ZF9EE/WJD#ES2%RBW$JEP.E?YZ .2861899999999995E-01


0 Kudos
1 Reply

No there is no option to help with SELECT CASE.  if the data was not random you could try PGO with -prof-gen and -prof-use.  but with random data this won't help.   Select case will not vectorize.


Character intrinsics are not vectorized and are not particularly speedy.  CASE statements do not create masked vector operations available in AVX2 and above.  Branchy code, lots of intrinsics calls for character functions.  Not much the compiler can do here. 

0 Kudos