2015-10-24 2 views
3

Я в основном очень программист на высоком уровне, поэтому думать о вещах, таких как местность процессора, для меня очень нова.Почему мое исполнение плохое? (Noob scheduling)

Я работаю над базовой билинейной демографией (для данных датчика RGGB), и у меня есть алгоритм справа (судя по результатам), но он не работает так же хорошо, как я надеялся (~ 210Mpix/s) ,

Вот мой код (вход является 4640x3472 изображение с одного канала RGGB):

def get_bilinear_debayer(input_raw, print_nest=False): 
    x, y, c = Var(), Var(), Var() 

    # Clamp and move to 32 bit for lots of space for averaging. 
    input = Func() 
    input[x,y] = cast(
     UInt(32), 
     input_raw[ 
      clamp(x,0,input_raw.width()-1), 
      clamp(y,0,input_raw.height()-1)] 
    ) 

    # Interpolate vertically 
    vertical = Func() 
    vertical[x,y] = (input[x,y-1] + input[x,y+1])/2 

    # Interpolate horizontally 
    horizontal = Func() 
    horizontal[x,y] = (input[x-1,y] + input[x+1,y])/2 

    # Interpolate on diagonals 
    diagonal_average = Func() 
    diagonal_average[x, y] = (
     input[x+1,y-1] + 
     input[x+1,y+1] + 
     input[x-1,y-1] + 
     input[x-1,y+1])/4 

    # Interpolate on adjacents 
    adjacent_average = Func() 
    adjacent_average[x, y] = (horizontal[x,y] + vertical[x,y])/2 

    red, green, blue = Func(), Func(), Func() 

    # Calculate the red channel 
    red[x, y, c] = select(
     # Red photosite 
     c == 0, input[x, y], 
     # Green photosite 
     c == 1, select(x%2 == 0, vertical[x,y], 
           horizontal[x,y]), 
     # Blue photosite 
     diagonal_average[x,y] 
    ) 

    # Calculate the blue channel 
    blue[x, y, c] = select(
     # Blue photosite 
     c == 2, input[x, y], 
     # Green photosite 
     c == 1, select(x%2 == 1, vertical[x,y], 
           horizontal[x,y]), 
     # Red photosite 
     diagonal_average[x,y] 
    ) 

    # Calculate the green channel 
    green[x, y, c] = select(
     # Green photosite 
     c == 1, input[x,y], 
     # Red/Blue photosite 
     adjacent_average[x,y] 
    ) 

    # Switch color interpolator based on requested color. 
    # Specify photosite as third argument, calculated as [x, y, z] = (0, 0, 0), (0, 1, 1), (1, 0, 1), (1, 1, 2) 
    # Happily works out to a sum of x mod 2 and y mod 2. 
    debayer = Func() 
    debayer[x, y, c] = select(c == 0, red[x, y, x%2 + y%2], 
           c == 1, green[x, y, x%2 + y%2], 
             blue[x, y, x%2 + y%2]) 


    # Scheduling 
    x_outer, y_outer, x_inner, y_inner, tile_index = Var(), Var(), Var(), Var(), Var() 

    bits = input_raw.get().type().bits 

    output = Func() 
    # Cast back to the original colour space 
    output[x,y,c] = cast(UInt(bits), debayer[x,y,c]) 
    # Reorder so that colours are calculated in order (red runs, then green, then blue) 

    output.reorder_storage(c, x, y) 
    # Tile in 128x128 squares 
    output.tile(x, y, x_outer, y_outer, x_inner, y_inner, 128, 128) 
    # Vectorize based on colour 
    output.bound(c, 0, 3) 
    output.vectorize(c) 
    # Fuse and parallelize 
    output.fuse(x_outer, y_outer, tile_index) 
    output.parallel(tile_index) 

    # Debugging 
    if print_nest: 
     output.print_loop_nest() 
     debayer.print_loop_nest() 
     red.print_loop_nest() 
     green.print_loop_nest() 
     blue.print_loop_nest() 

    return output 

Честно говоря, я никогда не знаю, что я делаю здесь, и я тоже новичок в этом, чтобы иметь любой ключ, где или на что смотреть.

Any Полезно знать, как улучшить планирование. Я все еще участвую, но обратной связи трудно найти.

График, который у меня есть, - это лучшее, что я смог сделать, но это почти полностью проб и ошибок.

EDIT: Я добавил дополнительные 30Mpix/s, выполнив все смежное среднее суммирование в функции напрямую и векторизовать на x_inner вместо цвета.

EDIT: Новый график:

# Set input bounds. 
output.bound(x, 0, (input_raw.width()/2)*2) 
output.bound(y, 0, (input_raw.height()/2)*2) 
output.bound(c, 0, 3) 

# Reorder so that colours are calculated in order (red runs, then green, then blue) 
output.reorder_storage(c, x, y) 
output.reorder(c, x, y) 

# Tile in 128x128 squares 
output.tile(x, y, x_outer, y_outer, x_inner, y_inner, 128, 128) 
output.unroll(x_inner, 2).unroll(y_inner,2) 

# Vectorize based on colour 
output.unroll(c) 
output.vectorize(c) 

# Fuse and parallelize 
output.fuse(x_outer, y_outer, tile_index) 
output.parallel(tile_index) 

EDIT: Окончательный график, который сейчас бьется (640MP/с) в Intel Performance Primitive benchmark, который был запущен на процессоре twice as powerful as mine:

output = Func() 

# Cast back to the original colour space 
output[x,y,c] = cast(UInt(bits), debayer[x,y,c]) 

# Set input bounds. 
output.bound(x, 0, (input_raw.width()/2)*2) 
output.bound(y, 0, (input_raw.height()/2)*2) 
output.bound(c, 0, 3) 

# Tile in 128x128 squares 
output.tile(x, y, x_outer, y_outer, x_inner, y_inner, 128, 128) 
output.unroll(x_inner, 2).unroll(y_inner, 2) 

# Vectorize based on colour 
output.vectorize(x_inner, 16) 

# Fuse and parallelize 
output.fuse(x_outer, y_outer, tile_index) 
output.parallel(tile_index) 

target = Target() 
target.arch = X86 
target.os = OSX 
target.bits = 64 
target.set_feature(AVX) 
target.set_feature(AVX2) 
target.set_feature(SSE41) 

output.compile_jit(target) 

ответ

3

Убедитесь, что вы используя unroll (c), чтобы оптимизировать логику выбора каждого канала. Развернув на 2 х и у также поможет:

output.unroll(x, 2).unroll(y,2) 

Цель есть оптимизировать вне выбора логики между четными/нечетными строками и столбцами. Для того, чтобы в полной мере воспользоваться этим, вы, вероятно, также необходимо сказать, что галогенид мин и степени кратны 2:

output.output_buffer().set_bounds(0, 
            (f.output_buffer().min(0)/2) * 2, 
            (output.output_buffer().extent(0)/2) * 2) 
output.output_buffer().set_bounds(1, 
            (f.output_buffer().min(1)/2) * 2, 
            (output.output_buffer().extent(1)/2) * 2) 

Хотя это может быть стоит о том, даже более жесткие ограничения, такие как использование 128 вместо 2, чтобы утверждать кратные размеры плитки или просто устанавливать минимальную и протяженность, чтобы отражать фактические параметры датчика, если вы поддерживаете только одну камеру.

+0

Я обновил свой пост с новым расписанием, скорректированным с вашими комментариями. Таким образом, он достигает 360MPix/s, что довольно хорошо. Я знаю, что у Intel есть алгоритм debayer, который получает до 630, хотя: http://www.fastcompression.com/products/debayer/benchmarks.htm – user478250

+0

Векторизация на c ограничена, поскольку есть только три элемента. Иногда вы можете развернуть больший коэффициент, чтобы получить согласованное отображение полосы и обработать сразу несколько векторов информации о цветовых каналах. (Например, Unrolling by 4 дает 3 32x4 вектора одновременно. Вероятно, здесь он работает, так как сырая обработка обычно имеет достаточно большое минимальное ограничение выравнивания - изображения кратно 16 или 32 и т. Д.) Однако лучше было бы vectorize на x, что позволяет увеличить ширину векторизации. В этот момент есть фактор 2, который должен быть выполнен, чтобы вычисление соответствовало 16-битным целым числам. –

+0

Хорошо, поэтому я перепутал вещи в 16-битные целые числа и векторизовал на x_inner, и получил до 480MP/с. Самая большая победа, хотя была вручную указана цель сборки. Когда я вручную попросил 64-битную OSX с AVX, AVX2 и SSE4.1, я получил 640 Мп/с, что превосходит базовый бенчмарк Intel Performance Primitive, несмотря на то, что он работает на процессоре, который наполовину такой же мощный, как тот, на котором тестировался эталон. – user478250

Смежные вопросы