Peter Zhu c2473016ed Set STR_DUPLICATE_MAX_EMBED_LEN to 256
I benchmarked various values of STR_DUPLICATE_MAX_EMBED_LEN and the
performance impacts. For String#dup, creating a view is faster until it
is below 256 bytes. Unsurprisingly, if we add modification to the string,
then it is faster to eagerly create a copy than use a view. Surprisingly,
if we append to the string, it's still faster to go from embedded -> extended
than shared -> extended. However, both of these cases will incur a memory
penalty as the remainder of the slot is wasted memory.

Benchmark:

    require "benchmark"

    TIMES = 10_000_000

    Benchmark.bm do |x|
      [64, 128, 256, 512, 1024].each do |len|
        len -= 25 # Subtract header length

        x.report("String#dup for #{len.to_s}") do
          pid = fork do
            str = ("a" * len).freeze

            i = 0
            while i < TIMES
              str.dup
              i += 1
            end
          end
          Process.wait(pid)
        end

        x.report("String#dup + String#[]= for #{len.to_s}") do
          pid = fork do
            str = ("a" * len).freeze

            i = 0
            while i < TIMES
              dup = str.dup
              dup[0] = "1"
              i += 1
            end
          end
          Process.wait(pid)
        end

        x.report("String#dup + String#<< for #{len.to_s}") do
          pid = fork do
            str = ("a" * len).freeze

            i = 0
            while i < TIMES
              dup = str.dup
              dup << "1"
              i += 1
            end
          end
          Process.wait(pid)
        end
      end
    end

Result:

    1024

                                            user     system      total        real
        String#dup for 39                0.000085   0.000646   0.207714 (  0.208041)
        String#dup + String#[]= for 39   0.000067   0.000379   0.499957 (  0.500514)
        String#dup + String#<< for 39    0.000069   0.000413   0.600205 (  0.600984)
        String#dup for 103               0.000068   0.000374   0.236938 (  0.237424)
        String#dup + String#[]= for 103  0.000063   0.000401   0.501791 (  0.502506)
        String#dup + String#<< for 103   0.000066   0.000395   0.600041 (  0.600870)
        String#dup for 231               0.000066   0.000370   0.281924 (  0.282409)
        String#dup + String#[]= for 231  0.000064   0.000355   0.574779 (  0.575599)
        String#dup + String#<< for 231   0.000070   0.000395   0.691011 (  0.691972)
        String#dup for 487               0.000070   0.000366   0.355631 (  0.356230)
        String#dup + String#[]= for 487  0.000067   0.000391   0.653774 (  0.654509)
        String#dup + String#<< for 487   0.000066   0.000359   0.891413 (  0.892607)
        String#dup for 999               0.000068   0.000394   0.527350 (  0.528033)
        String#dup + String#[]= for 999  0.000067   0.000378   0.786794 (  0.787682)
        String#dup + String#<< for 999   0.000063   0.000363   1.070604 (  1.071885)

    512

                                            user     system      total        real
        String#dup for 39                0.000083   0.000639   0.207305 (  0.207687)
        String#dup + String#[]= for 39   0.000067   0.000398   0.501968 (  0.502645)
        String#dup + String#<< for 39    0.000071   0.000414   0.586533 (  0.587365)
        String#dup for 103               0.000064   0.000397   0.222104 (  0.222600)
        String#dup + String#[]= for 103  0.000069   0.000389   0.483612 (  0.484240)
        String#dup + String#<< for 103   0.000069   0.000380   0.606659 (  0.607510)
        String#dup for 231               0.000067   0.000388   0.292563 (  0.293070)
        String#dup + String#[]= for 231  0.000064   0.000389   0.573774 (  0.574479)
        String#dup + String#<< for 231   0.000069   0.000413   0.739569 (  0.740614)
        String#dup for 487               0.000067   0.000419   0.370516 (  0.371072)
        String#dup + String#[]= for 487  0.000060   0.000337   0.676507 (  0.677282)
        String#dup + String#<< for 487   0.000074   0.000410   0.911670 (  0.916480)
        String#dup for 999               0.000069   0.000397   0.239633 (  0.240049)
        String#dup + String#[]= for 999  0.000066   0.000370   1.196397 (  1.198272)
        String#dup + String#<< for 999   0.000072   0.000396   1.683562 (  1.686244)

    256

                                            user     system      total        real
        String#dup for 39                0.000073   0.000588   0.198103 (  0.198485)
        String#dup + String#[]= for 39   0.000067   0.000397   0.475345 (  0.476011)
        String#dup + String#<< for 39    0.000074   0.000408   0.589001 (  0.589778)
        String#dup for 103               0.000073   0.000420   0.244381 (  0.244818)
        String#dup + String#[]= for 103  0.000065   0.000421   0.480720 (  0.481569)
        String#dup + String#<< for 103   0.000070   0.000414   0.589164 (  0.590123)
        String#dup for 231               0.000077   0.000447   0.272169 (  0.272640)
        String#dup + String#[]= for 231  0.000067   0.000425   0.517280 (  0.518037)
        String#dup + String#<< for 231   0.000064   0.000409   0.681593 (  0.682572)
        String#dup for 487               0.000065   0.000390   0.229708 (  0.230153)
        String#dup + String#[]= for 487  0.000067   0.000395   0.872966 (  0.874233)
        String#dup + String#<< for 487   0.000071   0.000411   1.317758 (  1.320085)
        String#dup for 999               0.000070   0.000397   0.255197 (  0.255609)
        String#dup + String#[]= for 999  0.000068   0.000380   1.174781 (  1.176700)
        String#dup + String#<< for 999   0.000067   0.000389   1.729608 (  1.738797)

    128

                                            user     system      total        real
        String#dup for 39                0.000105   0.000950   0.205384 (  0.206565)
        String#dup + String#[]= for 39   0.000066   0.000406   0.483924 (  0.485308)
        String#dup + String#<< for 39    0.000075   0.000433   0.590150 (  0.591641)
        String#dup for 103               0.000076   0.000414   0.225900 (  0.227975)
        String#dup + String#[]= for 103  0.000098   0.000604   0.499234 (  0.503926)
        String#dup + String#<< for 103   0.000070   0.000400   0.619562 (  0.627411)
        String#dup for 231               0.000073   0.000445   0.241433 (  0.243606)
        String#dup + String#[]= for 231  0.000067   0.000402   0.843665 (  0.853293)
        String#dup + String#<< for 231   0.000071   0.000392   0.990903 (  0.994555)
        String#dup for 487               0.000073   0.000403   0.234920 (  0.236132)
        String#dup + String#[]= for 487  0.000077   0.000445   0.944582 (  0.956001)
        String#dup + String#<< for 487   0.000069   0.000410   1.337099 (  1.341250)
        String#dup for 999               0.000072   0.000420   0.233520 (  0.234182)
        String#dup + String#[]= for 999  0.000072   0.000419   1.186288 (  1.188972)
        String#dup + String#<< for 999   0.000069   0.000436   1.685112 (  1.689536)
2026-07-28 10:57:57 -04:00
..