Юлия: Структура с постоянным полем для оптимизации производительности - PullRequest
2 голосов
/ 24 марта 2020

foo - это вызываемая примерная структура, которая позже будет иметь дополнительные поля. Поскольку некоторые из этих полей содержат массивы с изменяющимися значениями, нельзя сделать экземпляр const G. Однако логическое значение b остается постоянным. Есть ли способ сообщить компилятору, что это поле никогда не изменится, чтобы включить оптимизацию? В этом примере я бы хотел, чтобы F был таким же быстрым, как G и H.

using BenchmarkTools

struct foo
  b::Bool
end

function (f::foo)(x)
  if f.b
    x+1
  end
end

F = foo(true)

const G = foo(true)

H(x) = x+1


@btime F(1) # 12.078 ns (0 allocations: 0 bytes)

@btime G(1) # 0.023 ns (0 allocations: 0 bytes)

@btime H(1) # 0.024 ns (0 allocations: 0 bytes)

1 Ответ

2 голосов
/ 24 марта 2020

Вы неправильно оцениваете F. Вот способ сделать это:

julia> @btime $F(1)
  0.026 ns (0 allocations: 0 bytes)
2

Проблема не в том, что F является глобальной непостоянной переменной, в то время как G является константой, поэтому при доступе к F ее значение не стабильный в @btime.

Добавление $ перед вызовом делает F локальной переменной во время теста, и вы можете видеть, что она одинаково быстра.

Также в таких случаях, вероятно, лучше сравнить некоторые более крупные функции. Вот краткий пример:

julia> function test(x)
       s = 0
       for i in 1:10^6
           s += x(1)
       end
       s
       end
test (generic function with 1 method)

julia> @btime test($F)
  35.830 μs (0 allocations: 0 bytes)
2000000

julia> @btime test($G)
  35.839 μs (0 allocations: 0 bytes)
2000000

Также вы можете проверить с помощью @code_native, что F и G заканчиваются идентичным собственным кодом:

julia> @code_native F(1)
    .text
; ┌ @ REPL[10]:2 within `foo'
    cmpb    $0, (%rsi)
    je  L17
; │ @ REPL[10]:3 within `foo'
; │┌ @ int.jl:53 within `+'
    addq    $1, %rdx
; │└
    movq    %rdx, (%rdi)
    movb    $2, %dl
    xorl    %eax, %eax
    retq
L17:
    movb    $1, %dl
    xorl    %eax, %eax
; │ @ REPL[10]:3 within `foo'
    retq
    nopw    %cs:(%rax,%rax)
; └

julia> @code_native G(1)
    .text
; ┌ @ REPL[10]:2 within `foo'
    cmpb    $0, (%rsi)
    je  L17
; │ @ REPL[10]:3 within `foo'
; │┌ @ int.jl:53 within `+'
    addq    $1, %rdx
; │└
    movq    %rdx, (%rdi)
    movb    $2, %dl
    xorl    %eax, %eax
    retq
L17:
    movb    $1, %dl
    xorl    %eax, %eax
; │ @ REPL[10]:3 within `foo'
    retq
    nopw    %cs:(%rax,%rax)
; └
...