Oberon space
General Category => Общий раздел => Тема начата: valexey_u от Апрель 24, 2013, 04:34:26 pm
-
Коль пошла такая пьянка, предлагаю погонять один и тот же алгоритм блюра на разных ЯП. Ну и попробовать, возмжно, оптимизировать производительность не изменяя самого алгоритма.
Начало темы, тут: http://oberspace.dyndns.org/index.php/topic,480.msg15786.html#msg15786
Рассматриваем только алгоритм Сергея. Краткое описание алгоритма (наивная реализация для одного цветового канала флоатов на C#):
const int N = 13;
for (int n = 0; n < N; n++)
{
for (int y = 1; y < 479; y++)
{
for (int x = 1; x < 639; x++)
{
b[y, x] = 0.25 * (a[y - 1, x] + a[y + 1, x] + a[y, x - 1] + a[y, x + 1]);
}
}
for (int y = 1; y < 479; y++)
{
for (int x = 1; x < 639; x++)
{
a[y, x] = 0.25 * (b[y - 1, x] + b[y + 1, x] + b[y, x - 1] + b[y, x + 1]);
}
}
}
Продублирую и дополню и вычищу то, что содержалось в том сообщении (из дополнительного - появилась реализация на КП/ББ):
Итак, вначале результаты. Напомню, что радиус размытия (N) = 13. Обрабатываются все три канала. Число обрабатываемых кадров = 1000.
C#:
time: 107 seconds
fps : 9.35
С++:
time: 96 seconds
fps : 10.42
BB/CP (2D массивы аналогично наивной реализации на C#):
time: 439 seconds
fps : 2.28
BB/CP (1D массивы, функция вычисления индекса - аналогично C++):
time: 688 seconds
fps : 1.45
Исходники:
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication5
{
class Program
{
static unsafe void Main(string[] args)
{
const int H = 480;
const int W = 640;
byte[] a = new byte[H * W * 3];
byte[] b = new byte[H * W * 3];
System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
const int N = 13;
timer.Reset();
timer.Start();
const int frames = 1000;
for (int nn = 0; nn<frames; nn++)
{
fixed (byte* pa = &a[0])
{
fixed (byte* pb = &b[0])
{
for (int n = 0; n < N; n++)
{
for (int y = 1; y < H - 1; y++)
{
for (int x = 1; x < W - 1; x++)
{
for (int color_shift = 0; color_shift < 3; color_shift++)
{
*(pb + (H * y + x) * 3 + color_shift) = (byte)(0.25 * (*(pa + (H * (y - 1) + x) * 3 + color_shift)
+ *(pa + (H * (y + 1) + x) * 3 + color_shift)
+ *(pa + (H * y + x - 1) * 3 + color_shift)
+ *(pa + (H * y + x + 1) * 3 + color_shift)));
}
}
}
for (int y = 1; y < H - 1; y++)
{
for (int x = 1; x < W - 1; x++)
{
for (int color_shift = 0; color_shift < 3; color_shift++)
{
*(pa + (H * y + x) * 3 + color_shift) = (byte)(0.25 * (*(pb + (H * (y - 1) + x) * 3 + color_shift)
+ *(pb + (H * (y + 1) + x) * 3 + color_shift)
+ *(pb + (H * y + x - 1) * 3 + color_shift)
+ *(pb + (H * y + x + 1) * 3 + color_shift)));
}
}
}
}
}
}
}
timer.Stop();
double dt = timer.Elapsed.TotalSeconds;
System.Console.WriteLine("N = {0} (R = {1}), dt={2} seconds, FPS = {3}",
N, 2 * N, dt, (frames / dt));
System.Console.ReadLine();
}
}
}
C++:
#include <iostream>
#include <ctime>
const int width = 640;
const int height = 480;
const size_t blurRange = 13;
enum Color {
RED = 0,
GREEN,
BLUE
};
int index(int x, int y, Color color) {
return width*y*3+x*3+color;
}
int main()
{
volatile unsigned char* volatile in = new unsigned char[width*height*3];
volatile unsigned char* volatile out = new unsigned char[width*height*3];
time_t begin;
time(&begin);
const int frames = 1000;
for (int nn=0; nn<frames; nn++) {
for (int i=0; i<blurRange; i++) {
for (int y=1; y<height-1; y++)
for (int x=1; x<width-1; x++) {
out[index(x,y,RED)]= 0.25*(
(float)in[index(x,y-1,RED)]+
in[index(x,y+1,RED)]+
in[index(x-1,y,RED)]+
in[index(x+1,y,RED)]);
out[index(x,y,GREEN)]= 0.25*(
(float)in[index(x,y-1,GREEN)]+
in[index(x,y+1,GREEN)]+
in[index(x-1,y,GREEN)]+
in[index(x+1,y,GREEN)]);
out[index(x,y,BLUE)]= 0.25*(
(float)in[index(x,y-1,BLUE)]+
in[index(x,y+1,BLUE)]+
in[index(x-1,y,BLUE)]+
in[index(x+1,y,BLUE)]);
}
for (int y=1; y<height-1; y++)
for (int x=1; x<width-1; x++) {
in[index(x,y,RED)]=0.25*(
(float)out[index(x,y-1,RED)]+
out[index(x,y+1,RED)]+
out[index(x-1,y,RED)]+
out[index(x+1,y,RED)]);
in[index(x,y,GREEN)]=0.25*(
(float)out[index(x,y-1,GREEN)]+
out[index(x,y+1,GREEN)]+
out[index(x-1,y,GREEN)]+
out[index(x+1,y,GREEN)]);
in[index(x,y,BLUE)]=0.25*(
(float)out[index(x,y-1,BLUE)]+
out[index(x,y+1,BLUE)]+
out[index(x-1,y,BLUE)]+
out[index(x+1,y,BLUE)]);
}
}
}
time_t end;
time(&end);
auto seconds = difftime(end, begin);
std::cout << float(frames)/seconds << " " << seconds << std::endl;
}
Тестовый модуль на КП. Две функции:
Blur2DArray - реализация на 2D массивах
Blur1DArray - реализация на одномерных массивах.
MODULE Blur;
IMPORT Kernel, Out:=StdLog;
CONST
W = 640;
H = 480;
N = 13;
Frames = 1000;
TYPE
Plane = ARRAY W*3, H OF BYTE;
Plane1 = ARRAY W*H*3 OF BYTE;
PROCEDURE Blur2DArray*;
VAR
time : LONGINT;
f, n : INTEGER;
x, y : INTEGER;
color : INTEGER;
a, b : POINTER TO Plane;
BEGIN
NEW(a);
NEW(b);
time := Kernel.Time();
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
b[x*3+color,y] := SHORT(SHORT(SHORT(ENTIER(0.25*(a[x*3+color,y+1]+a[x*3+color,y-1]+a[(x-1)*3,y]+a[(x+1)*3,y])))));
END
END
END;
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
a[x*3+color,y] := SHORT(SHORT(SHORT(ENTIER(0.25*(b[x*3+color,y+1]+b[x*3+color,y-1]+b[(x-1)*3,y]+b[(x+1)*3,y])))));
END
END
END
END
END;
Out.Real((Kernel.Time() - time)/1000)
END Blur2DArray;
PROCEDURE Index(x,y,color : INTEGER) : INTEGER;
BEGIN
RETURN ((x+y*W)*3+color)
END Index;
PROCEDURE Blur1DArray*;
VAR
time : LONGINT;
f, n : INTEGER;
x, y : INTEGER;
color : INTEGER;
a, b : POINTER TO Plane1;
BEGIN
NEW(a);
NEW(b);
time := Kernel.Time();
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
b[Index(x,y,color)] := SHORT(SHORT(SHORT(ENTIER(0.25*(a[Index(x,y+1,color)]+a[Index(x,y-1,color)]+a[Index(x-1,y,color)]+a[Index(x+1,y,color)])))));
END
END
END;
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
a[Index(x,y,color)] := SHORT(SHORT(SHORT(ENTIER(0.25*(b[Index(x,y+1,color)]+b[Index(x,y-1,color)]+b[Index(x-1,y,color)]+b[Index(x+1,y,color)])))));
END
END
END;
END
END;
Out.Real((Kernel.Time() - time)/1000)
END Blur1DArray;
BEGIN
END Blur.
-
Чем умножать целочисленную переменную на 0.25, а потом переводить результат в целочисленный же вид, не проще ли сдвиг на два бита использовать?
(int)(0.25 * x) == (x >> 2)
-
Чем умножать целочисленную переменную на 0.25, а потом переводить результат в целочисленный же вид, не проще ли сдвиг на два бита использовать?
(int)(0.25 * x) == (x >> 2)
А ты попробуй - исходники все есть :-)
-
А от моих оптимизаций руками эффекта не было?
-
А от моих оптимизаций руками эффекта не было?
Я еще не пробовал. Народ, попробуйте - я просто не успеваю пробовать все идеи :-)
-
Чем умножать целочисленную переменную на 0.25, а потом переводить результат в целочисленный же вид, не проще ли сдвиг на два бита использовать?
(int)(0.25 * x) == (x >> 2)
Замена на целочисленное деление на 4 в варианте C++ дало прирост в скорости в 1.5 раза:
C++ (умножение на 0.25):
time: 92
fps : 10.87
C++ (деление на 4):
time: 66
fps : 15.15
-
В 2D массивном варианте ББ/КП также при переходе не целочисленку быстродействие поднялось в полтора раза:
BB/CP (2D массивы аналогично наивной реализации на C#, "*0.25"):
time: 439 seconds
fps : 2.28
BB/CP (2D массивы аналогично наивной реализации на C#, "/4"):
time: 303 seconds
fps : 3.3
Исходник функции (модуль тот же):
PROCEDURE Blur2DArray*;
VAR
time : LONGINT;
f, n : INTEGER;
x, y : INTEGER;
color : INTEGER;
a, b : POINTER TO Plane;
BEGIN
NEW(a);
NEW(b);
time := Kernel.Time();
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
b[x*3+color,y] := SHORT(SHORT((a[x*3+color,y+1]+a[x*3+color,y-1]+a[(x-1)*3,y]+a[(x+1)*3,y]) DIV 4));
END
END
END;
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
a[x*3+color,y] := SHORT(SHORT((b[x*3+color,y+1]+b[x*3+color,y-1]+b[(x-1)*3,y]+b[(x+1)*3,y]) DIV 4));
END
END
END
END
END;
Out.Real((Kernel.Time() - time)/1000)
END Blur2DArray;
-
x*3+color
Зачем так много раз вычислять это? Компилер ведь не оптимизирующий.
Да и вообще можно на одном прогоне эти значения в массив загнать.
-
x*3+color
Зачем так много раз вычислять это? Компилер ведь не оптимизирующий.
Да и вообще можно на одном прогоне эти значения в массив загнать.
You are welcome!
В смысле, перепиши ББшную процедуру так, как тебе кажется правильным, кинь сюда, также кинь сравнительный замер того что было и что стало на твоей машине, и я тоже прогоню тест на своей.
-
Типа так:
MODULE Blur;
IMPORT Kernel, Out:=StdLog;
CONST
W = 640; W1 = 640 - 3;
H = 480; H1 = 480 - 3;
N = 13;
Frames = 1000;
TYPE
Plane = ARRAY W*3, H OF BYTE;
Plane1 = ARRAY W*H*3 OF INTEGER;
PROCEDURE Blur2DArray*;
VAR
time : LONGINT;
f, n : INTEGER;
x, y : INTEGER;
color : INTEGER;
a, b : POINTER TO Plane;
c1, c2, c3, c4: POINTER TO Plane1;
i: INTEGER;
BEGIN
NEW(a);
NEW(b);
NEW(c1); NEW(c2); NEW(c3); NEW(c4); i := 0;
time := Kernel.Time();
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
c1[i] := x*3+color;
c2[i] := (x-1)*3;
c3[i] := (x+1)*3;
c4[i] := y;
INC(i);
END
END
END;
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
(*FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
b[x*3+color,y] :=
(a[x*3+color,y+1] +
a[x*3+color,y-1] +
a[(x-1)*3,y] +
a[(x+1)*3,y]) DIV 4;
END
END
END;*)
FOR i := 0 TO W1*H1*3 DO
x := c1[i];
y := c4[i];
b[x, y] := SHORT(SHORT((a[x, y+1] + a[x, y-1] + a[c2[i], y] + a[c3[i], y]) DIV 4));
END;
(*FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
a[x*3+color,y] :=
(b[x*3+color,y+1] +
b[x*3+color,y-1] +
b[(x-1)*3,y] +
b[(x+1)*3,y]) DIV 4;
END
END
END*)
FOR i := 1 TO W1*H1*3 DO
x := c1[i];
y := c4[i];
a[x, y] := SHORT(SHORT((b[x, y+1] + b[x, y-1] + b[c2[i], y] + b[c3[i], y]) DIV 4));
END;
END
END;
Out.Real((Kernel.Time() - time)/1000)
END Blur2DArray;
(*Blur1DArray*)
END Blur.
было ~750 (версия с DIV 4)
стало ~440
Но у меня может быть гон. Ибо антивирус мелкомягкий работает.
-
FOR i := 1 TO W1*H1*3 DO
Косяк :) i := 0 конечно
-
FOR i := 1 TO W1*H1*3 DO
Косяк :) i := 0 конечно
Ну, это не может сказаться значительно ни на производительности, ни на корректности работы :-)
-
Похоже таки гон. Сейчас еще раз прогнал твой код с DIV и получилось тоже ~440
-
Похоже таки гон. Сейчас еще раз прогнал твой код с DIV и получилось тоже ~440
Я прогнал твой вариант. Стало медленнее - было 303 (вариант с DIV), стало 378 секунд.
Что в общем то и следовало ожидать - вместо пересылки из регистра в регистр мы получили пересылку из ОЗУ (пусть даже это кэш первого или второго уровня).
-
Значит оптимизации тут роли особой не играют. Скорее всего поможет только отключение проверок.
-
Значит оптимизации тут роли особой не играют. Скорее всего поможет только отключение проверок.
Возможно имеет смысл вычислять эти оффсеты один раз для всех 4 пикселов. Что-то вроде того, как Валерий предлагал. Надо будет попробовать.
-
Значит оптимизации тут роли особой не играют. Скорее всего поможет только отключение проверок.
Возможно имеет смысл вычислять эти оффсеты один раз для всех 4 пикселов. Что-то вроде того, как Валерий предлагал. Надо будет попробовать.
может лучше мозги не трахать а попробовать вот это http://web.archive.org/web/20060718054020/http://www.acm.uiuc.edu/siggraph/workshops/wjarosz_convolution_2001.pdf (http://web.archive.org/web/20060718054020/http://www.acm.uiuc.edu/siggraph/workshops/wjarosz_convolution_2001.pdf) ;)
-
Значит оптимизации тут роли особой не играют. Скорее всего поможет только отключение проверок.
Возможно имеет смысл вычислять эти оффсеты один раз для всех 4 пикселов. Что-то вроде того, как Валерий предлагал. Надо будет попробовать.
может лучше мозги не трахать а попробовать вот это http://web.archive.org/web/20060718054020/http://www.acm.uiuc.edu/siggraph/workshops/wjarosz_convolution_2001.pdf (http://web.archive.org/web/20060718054020/http://www.acm.uiuc.edu/siggraph/workshops/wjarosz_convolution_2001.pdf) ;)
Спасибо за ссылку конечно, но это офтопик. В данной теме (перечитай первое сообщение) мы сравниваем скорость разных ЯП на одном и том же алгоритме. Это бенчмарк по сути.
А обсуждение алгоритмов для быстрого размытия картинки ведется в теме "мы победили".
Впрочем под это не грех будет и отдельный топик завести.
-
Спасибо за ссылку конечно, но это офтопик. В данной теме (перечитай первое сообщение) мы сравниваем скорость разных ЯП на одном и том же алгоритме. Это бенчмарк по сути.
А обсуждение алгоритмов для быстрого размытия картинки ведется в теме "мы победили".
Впрочем под это не грех будет и отдельный топик завести.
;) Да ну... это было бы оффтопиком если бы не большинство сообщений об усовершенствованиях - в том числе и ваше (на которое я ответил)...
-
Спасибо за ссылку конечно, но это офтопик. В данной теме (перечитай первое сообщение) мы сравниваем скорость разных ЯП на одном и том же алгоритме. Это бенчмарк по сути.
А обсуждение алгоритмов для быстрого размытия картинки ведется в теме "мы победили".
Впрочем под это не грех будет и отдельный топик завести.
;) Да ну... это было бы оффтопиком если бы не большинство сообщений об усовершенствованиях - в том числе и ваше (на которое я ответил)...
Эти усовершенствования алгоритм не меняли, если угодно, это были всего лишь подсказки компилятору.
-
я к чему это... бенчмарктесь на здоровье но на качественной основе...
-
Реаизовал алгоритм на javaScript'e. Поскольку прямо сейчас под рукой той, референсной машины нет, то все гонял на старом ноутбуке (2008 год, 32 бита. виста).
Результаты (js, и, для сравнения, ББ на этой машине):
js:
time: 290 seconds
fps : 3.45
BB/CP (DIV-оптимизация, 2D array):
time: 454 seconds
fps : 2.20
Итого, на числодробильных задачах (ну или по крайней мере на задачах обработки изображений) современный javascript в полтора раза быстрее чем BB. На 64-битной (референсной) системе отрыв, по идее, должен стать еще больше.
Код:
var N = 13;
var W = 640;
var H = 480;
function index(x,y,color) {
return (W*y+x)*3+color;
}
var a = new Uint8Array(W*H*3);
var b = new Uint8Array(W*H*3);
var t1 = Date.now();
var frames = 1000;
for (var nn=0; nn<frames; nn++) {
for (var i=0; i<N; i++) {
for (var y=1; y<H-1; y++) {
for (var x=1; x<W-1; x++) {
for (var c=0; c<3; c++) {
b[index(x,y,c)] = (a[index(x,y+1,c)] + a[index(x,y-1,c)] + a[index(x+1,y,c)] + a[index(x-1,y,c)])/4;
}
}
}
for (var y=1; y<H-1; y++) {
for (var x=1; x<W-1; x++) {
for (var c=0; c<3; c++) {
a[index(x,y,c)] = (b[index(x,y+1,c)] + b[index(x,y-1,c)] + b[index(x+1,y,c)] + b[index(x-1,y,c)])/4;
}
}
}
}
}
var t2 = Date.now();
console.log((t2-t1)/1000);
console.log(frames/((t2-t1)/1000));
-
Сделал цвета однобайтовыми, делаю блюр в трёх каналах, загружаю из картинки.
На i7 2600K уже с учётом трёх каналов:
N=5, R=10, time = 0.0140209 seconds, FPS = 71.3220977255383
N=6, R=12, time = 0.0166911 seconds, FPS = 59.912168760597
N=7, R=14, time = 0.0194411 seconds, FPS = 51.4374186645817
N=8, R=16, time = 0.0224343 seconds, FPS = 44.5746022831111
R - радиус размытия, N - количество фаз (за одну фазу делается два прохода, R = 2*N)
// Note! Need add reference to: WindowsBase, PresentationCore, System.Xaml
namespace Blur
{
class Program
{
private const int W = 640;
private const int H = 480;
private static System.Windows.Media.PixelFormat pixelFormat = System.Windows.Media.PixelFormats.Bgr24;
static void Main (string[] args)
{
byte[] a;
if (Load("input.jpg", out a))
{
const int N = 7;
byte[] b = new byte[a.Length];
System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
timer.Start();
BlurX2(a, b, N);
timer.Stop();
double dt = timer.Elapsed.TotalSeconds;
System.Console.WriteLine("N={0}, R={1}, time = {2} seconds, FPS = {3}", N, 2*N, dt, 1.0/dt);
Save("output-R" + (2*N) + ".jpg", a);
System.Console.WriteLine("Ok");
System.Console.ReadLine();
}
}
public static unsafe void BlurX2 (byte[] A, byte[] B, int N)
{
const int dy = 3*W;
const int dx = 3;
fixed (byte* a = &A[0])
{
fixed (byte* b = &B[0])
{
for (int n = 0; n < N; n++)
{
for (int y = dy; y < dy*(H-1); y+=dy)
{
for (int x = dx; x < dx*(W-1); x+=dx)
{
int offset = y + x;
b[offset+0] = (byte)((a[offset-dy+0] + a[offset+dy+0] + a[offset-dx+0] + a[offset+dx+0]) / 4);
b[offset+1] = (byte)((a[offset-dy+1] + a[offset+dy+1] + a[offset-dx+1] + a[offset+dx+1]) / 4);
b[offset+2] = (byte)((a[offset-dy+2] + a[offset+dy+2] + a[offset-dx+2] + a[offset+dx+2]) / 4);
}
}
for (int y = dy; y < dy*(H-1); y+=dy)
{
for (int x = dx; x < dx*(W-1); x+=dx)
{
int offset = y + x;
a[offset+0] = (byte)((b[offset-dy+0] + b[offset+dy+0] + b[offset-dx+0] + b[offset+dx+0]) / 4);
a[offset+1] = (byte)((b[offset-dy+1] + b[offset+dy+1] + b[offset-dx+1] + b[offset+dx+1]) / 4);
a[offset+2] = (byte)((b[offset-dy+2] + b[offset+dy+2] + b[offset-dx+2] + b[offset+dx+2]) / 4);
}
}
}
}
}
}
public static bool Load (string fileName, out byte[] buffer)
{
buffer = null;
using (System.IO.FileStream s = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read))
{
System.Windows.Media.Imaging.BitmapDecoder d = System.Windows.Media.Imaging.BitmapDecoder.Create(s,
System.Windows.Media.Imaging.BitmapCreateOptions.PreservePixelFormat,
System.Windows.Media.Imaging.BitmapCacheOption.Default);
System.Windows.Media.Imaging.BitmapFrame f = d.Frames[0];
if (f.PixelWidth != W)
{
System.Console.WriteLine("Unexpected width={0}, expected={1}", f.PixelWidth, W);
}
else if (f.PixelHeight != H)
{
System.Console.WriteLine("Unexpected height={0}, expected={1}", f.PixelHeight, H);
}
else if (f.Format != pixelFormat)
{
System.Console.WriteLine("Unexpected pixel format={0}, expected={1}", f.Format, pixelFormat);
}
else
{
buffer = new byte[W * H * 3];
f.CopyPixels(buffer, W * 3, 0);
}
}
return (buffer != null);
}
public static void Save (string fileName, byte[] buffer)
{
System.Windows.Media.Imaging.BitmapSource bm = System.Windows.Media.Imaging.BitmapSource.Create(
W, H, 300, 300, pixelFormat, null, buffer, W * 3);
using (System.IO.FileStream s = new System.IO.FileStream(fileName, System.IO.FileMode.Create))
{
System.Windows.Media.Imaging.JpegBitmapEncoder e = new System.Windows.Media.Imaging.JpegBitmapEncoder();
e.Frames.Add(System.Windows.Media.Imaging.BitmapFrame.Create(bm));
e.Save(s);
}
}
}
}
Прилагаю картинки (в архиве)
-
Windows XP sp3, Pentium DualCore 1.6 GHz
GNAT2012 9.4 fps
TinyC 0.9.24 2.3 fps
VC2010 12.3 fps
Ada GNAT 2012
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
with Ada.Real_Time; use Ada.Real_Time;
procedure BlurGnat is
package Duration_IO is new Ada.Text_IO.Fixed_IO(Duration);
use Duration_IO;
width : constant integer := 640;
height : constant integer := 480;
blurRange : constant integer := 13;
frames : constant integer := 1000;
type Byte is range 0 .. 255; for Byte'Size use 8;
type Frame is array (0 .. (width*height*3-1)) of Byte;
procedure Blur(inar : in Frame; outar : out Frame) is
RED : constant integer := 0;
GREEN : constant integer := 1;
BLUE : constant integer := 2;
function index(x: integer; y: integer; color: integer) return integer is
begin
return width*y*3+x*3+color;
end index;
begin
for y in 1..height-1-1 loop
for x in 1..width-1-1 loop
outar(index(x,y,RED)) := Byte(
(Integer(inar(index(x,y-1,RED))) + Integer(inar(index(x,y+1,RED))) +
Integer(inar(index(x-1,y,RED))) + Integer(inar(index(x+1,y,RED)))) / 4);
outar(index(x,y,GREEN)) := Byte(
(Integer(inar(index(x,y-1,GREEN))) + Integer(inar(index(x,y+1,GREEN))) +
Integer(inar(index(x-1,y,GREEN))) + Integer(inar(index(x+1,y,GREEN)))) / 4);
outar(index(x,y,BLUE)) := Byte(
(Integer(inar(index(x,y-1,BLUE))) + Integer(inar(index(x,y+1,BLUE))) +
Integer(inar(index(x-1,y,BLUE))) + Integer(inar(index(x+1,y,BLUE)))) / 4);
end loop;
end loop;
end Blur;
inarr : Frame;
outarr : Frame;
time_begin : Time;
time_elapsed : Duration;
begin
for i in Frame'Range loop inarr(i) := 127; end loop;
time_begin := Clock;
for nn in 1..frames loop
for i in 1..blurRange loop
Blur(inarr, outarr);
Blur(outarr, inarr);
end loop;
end loop;
time_elapsed := To_Duration(Clock - time_begin);
Put("BlurGNAT: fps = "); Put(Float(frames)/Float(time_elapsed));
Put(" time = "); Put(time_elapsed);
Put_Line(" sec");
end BlurGnat;
TinyC 0.9.24
#include <stdio.h>
#include <time.h>
#define width 640
#define height 480
#define blurRange 13
#define frames 200
void Blur(char* inar, char* outar)
{
#define RED 0
#define GREEN 1
#define BLUE 2
#define index(x,y,color) ((width)*(y)*3+(x)*3+(color))
int x, y;
for (y=1; y<height-1; y++)
for (x=1; x<width-1; x++) {
outar[index(x,y,RED)]=
((int)inar[index(x,y-1,RED)]+
(int)inar[index(x,y+1,RED)]+
(int)inar[index(x-1,y,RED)]+
(int)inar[index(x+1,y,RED)]) >> 2;
outar[index(x,y,GREEN)]=
((int)inar[index(x,y-1,GREEN)]+
(int)inar[index(x,y+1,GREEN)]+
(int)inar[index(x-1,y,GREEN)]+
(int)inar[index(x+1,y,GREEN)]) >> 2;
outar[index(x,y,BLUE)]=
((int)inar[index(x,y-1,BLUE)]+
(int)inar[index(x,y+1,BLUE)]+
(int)inar[index(x-1,y,BLUE)]+
(int)inar[index(x+1,y,BLUE)]) >> 2;
}
}
char in [width*height*3];
char out[width*height*3];
int main(void)
{
int nn, i;
time_t begin, end;
double seconds;
time(&begin);
for (nn=0; nn<frames; nn++)
{
for (i=0; i<blurRange; i++)
{
Blur(in, out);
Blur(out, in);
}
}
time(&end);
seconds = difftime(end, begin);
printf("%f %d", (float)((double)frames)/seconds, (int)(seconds+0.5));
return 0;
}
-
Сделал цвета однобайтовыми, делаю блюр в трёх каналах, загружаю из картинки.
Предлагаю продолжить обсуждение алгоритмов тут: Сравнение blur-алгоритмов. (http://oberspace.dyndns.org/index.php/topic,485.0.html)
-
Windows XP sp3, Pentium DualCore 1.6 GHz
GNAT2012 9.4 fps
TinyC 0.9.24 2.3 fps
VC2010 12.3 fps
Ada GNAT 2012
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Float_Text_IO; use Ada.Float_Text_IO;
with Ada.Real_Time; use Ada.Real_Time;
procedure BlurGnat is
package Duration_IO is new Ada.Text_IO.Fixed_IO(Duration);
use Duration_IO;
width : constant integer := 640;
height : constant integer := 480;
blurRange : constant integer := 13;
frames : constant integer := 1000;
type Byte is range 0 .. 255; for Byte'Size use 8;
type Frame is array (0 .. (width*height*3-1)) of Byte;
procedure Blur(inar : in Frame; outar : out Frame) is
RED : constant integer := 0;
GREEN : constant integer := 1;
BLUE : constant integer := 2;
function index(x: integer; y: integer; color: integer) return integer is
begin
return width*y*3+x*3+color;
end index;
begin
for y in 1..height-1-1 loop
for x in 1..width-1-1 loop
outar(index(x,y,RED)) := Byte(
(Integer(inar(index(x,y-1,RED))) + Integer(inar(index(x,y+1,RED))) +
Integer(inar(index(x-1,y,RED))) + Integer(inar(index(x+1,y,RED)))) / 4);
outar(index(x,y,GREEN)) := Byte(
(Integer(inar(index(x,y-1,GREEN))) + Integer(inar(index(x,y+1,GREEN))) +
Integer(inar(index(x-1,y,GREEN))) + Integer(inar(index(x+1,y,GREEN)))) / 4);
outar(index(x,y,BLUE)) := Byte(
(Integer(inar(index(x,y-1,BLUE))) + Integer(inar(index(x,y+1,BLUE))) +
Integer(inar(index(x-1,y,BLUE))) + Integer(inar(index(x+1,y,BLUE)))) / 4);
end loop;
end loop;
end Blur;
inarr : Frame;
outarr : Frame;
time_begin : Time;
time_elapsed : Duration;
begin
for i in Frame'Range loop inarr(i) := 127; end loop;
time_begin := Clock;
for nn in 1..frames loop
for i in 1..blurRange loop
Blur(inarr, outarr);
Blur(outarr, inarr);
end loop;
end loop;
time_elapsed := To_Duration(Clock - time_begin);
Put("BlurGNAT: fps = "); Put(Float(frames)/Float(time_elapsed));
Put(" time = "); Put(time_elapsed);
Put_Line(" sec");
end BlurGnat;
TinyC 0.9.24
#include <stdio.h>
#include <time.h>
#define width 640
#define height 480
#define blurRange 13
#define frames 200
void Blur(char* inar, char* outar)
{
#define RED 0
#define GREEN 1
#define BLUE 2
#define index(x,y,color) ((width)*(y)*3+(x)*3+(color))
int x, y;
for (y=1; y<height-1; y++)
for (x=1; x<width-1; x++) {
outar[index(x,y,RED)]=
((int)inar[index(x,y-1,RED)]+
(int)inar[index(x,y+1,RED)]+
(int)inar[index(x-1,y,RED)]+
(int)inar[index(x+1,y,RED)]) >> 2;
outar[index(x,y,GREEN)]=
((int)inar[index(x,y-1,GREEN)]+
(int)inar[index(x,y+1,GREEN)]+
(int)inar[index(x-1,y,GREEN)]+
(int)inar[index(x+1,y,GREEN)]) >> 2;
outar[index(x,y,BLUE)]=
((int)inar[index(x,y-1,BLUE)]+
(int)inar[index(x,y+1,BLUE)]+
(int)inar[index(x-1,y,BLUE)]+
(int)inar[index(x+1,y,BLUE)]) >> 2;
}
}
char in [width*height*3];
char out[width*height*3];
int main(void)
{
int nn, i;
time_t begin, end;
double seconds;
time(&begin);
for (nn=0; nn<frames; nn++)
{
for (i=0; i<blurRange; i++)
{
Blur(in, out);
Blur(out, in);
}
}
time(&end);
seconds = difftime(end, begin);
printf("%f %d", (float)((double)frames)/seconds, (int)(seconds+0.5));
return 0;
}
Интересно TinyC умеет inline?
А за реализацию на Аде - отдельное спасибо. Буду тестировать :-)
-
Интересно TinyC умеет inline?
Похоже, что не умеет, потому что когда я вынес алгоритм самого блура в процедуру Blur, время работы выросло почти на 5%...
А за реализацию на Аде - отдельное спасибо. Буду тестировать :-)
Пока делал вариант на Аде -- половину времени потратил на то, что бы вывести результат в stdio -- с выводом чисел и всяких пользовательских там беда...
-
Реаизовал алгоритм на javaScript'e. Поскольку прямо сейчас под рукой той, референсной машины нет, то все гонял на старом ноутбуке (2008 год, 32 бита. виста).
Результаты (js, и, для сравнения, ББ на этой машине):
js:
time: 290 seconds
fps : 3.45
BB/CP (DIV-оптимизация, 2D array):
time: 454 seconds
fps : 2.20
Итого, на числодробильных задачах (ну или по крайней мере на задачах обработки изображений) современный javascript в полтора раза быстрее чем BB. На 64-битной (референсной) системе отрыв, по идее, должен стать еще больше.
Потестировал на референсном ультрабуке:
js (32 bit):
time: 246 seconds
fps : 4.07
BB/CP (DIV-оптимизация, 2D array):
time: 303 seconds
fps : 3.30
js (64 bit):
time: 1125 seconds
fps : 0.89
Как ни странно, 64битная сборка node.js (движок там v8 - тот же что в google chrome) под 64битной же виндой работает в 4-5 раз медленнее на этой задче, чем 32битная.
Ну и js (32bit) и тут быстрее чем BlackBox, хотя разница уже не столь значительна.
Результаты тестов устойчивые, разлет не более чем на 3 секунды от теста к тесту.
-
Windows7 sp1, AMD Phenom 9650 2300MHz
TinyC 0.9.24 2.17 fps (реализация Geniepro)
Delphi-2010 4.32 fps
Delphi-2010 2.88 fps (Range checking)
BBCP 1.83 fps
XDS O2 1.82 fps
O-07M (Rifat) 0.37 fps
O-07/11 (akron1) 0.44 fps
O-07/11 (akron1) 0.55 fps (сдвиг вместо деления)
Везде, кроме TinyC 2D array
-
Windows7 sp1, AMD Phenom 9650 2300MHz
TinyC 0.9.24 2.17 fps (реализация Geniepro)
Delphi-2010 4.32 fps
Delphi-2010 2.88 fps (Range checking)
BBCP 1.83 fps
XDS O2 1.82 fps
O-07M (Rifat) 0.37 fps
O-07/11 (akron1) 0.44 fps
O-07/11 (akron1) 0.55 fps (сдвиг вместо деления)
Везде, кроме TinyC 2D array
Можно исходники для Оберона-2 и Оберона-07/11?
Ну и делфи, до кучи.
-
Oberon-2
<*+ MAIN *>
MODULE Blur;
IMPORT Out;
CONST
W = 640; W1 = 640 - 3;
H = 480; H1 = 480 - 3;
N = 13;
Frames = 100;
TYPE
INTEGER = LONGINT;
Plane = ARRAY W*3, H OF SHORTINT;
VAR
a, b : Plane;
PROCEDURE Blur2DArray*;
VAR
f, n : INTEGER;
x, y : INTEGER;
color : INTEGER;
BEGIN
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
b[x*3+color,y] := (a[x*3+color,y+1]+a[x*3+color,y-1]+a[(x-1)*3,y]+a[(x+1)*3,y]) DIV 4;
END
END
END;
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
a[x*3+color,y] := (b[x*3+color,y+1]+b[x*3+color,y-1]+b[(x-1)*3,y]+b[(x+1)*3,y]) DIV 4;
END
END
END
END
END;
END Blur2DArray;
BEGIN
Blur2DArray;
Out.String("Done");
END Blur.
Oberon-07/11
MODULE Blur;
IMPORT dt := DateTime, In, Out, RTL;
CONST
W = 640; W1 = 640 - 3;
H = 480; H1 = 480 - 3;
N = 13;
Frames = 1;
TYPE
Plane = ARRAY W*3, H OF CHAR;
VAR
a, b: Plane;
time: LONGREAL;
PROCEDURE Blur2DArray*;
VAR
f, n : INTEGER;
x, y : INTEGER;
color : INTEGER;
BEGIN
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
b[x*3+color,y] := CHR((ORD(a[x*3+color,y+1])+ORD(a[x*3+color,y-1])+ORD(a[(x-1)*3,y])+ORD(a[(x+1)*3,y])) DIV 4);
END
END
END;
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
a[x*3+color,y] := CHR((ORD(b[x*3+color,y+1])+ORD(b[x*3+color,y-1])+ORD(b[(x-1)*3,y])+ORD(b[(x+1)*3,y])) DIV 4);
END
END
END
END
END;
END Blur2DArray;
BEGIN
In.Open;
Out.Open;
time := dt.Now();
Blur2DArray;
Out.FixReal(LONG(FLT(Frames))/((dt.Now() - time) * 86400.D0), 20, 5);
In.Ln;
END Blur.
Oberon-07M
MODULE Blur;
IMPORT c := Console;
CONST
W = 640; W1 = 640 - 3;
H = 480; H1 = 480 - 3;
N = 13;
Frames = 10;
TYPE
Plane = ARRAY W*3, H OF CHAR;
VAR
a, b : Plane;
time : INTEGER;
PROCEDURE ["Kernel32.dll", "GetTickCount", 0] GetTickCount(): INTEGER;
PROCEDURE Blur2DArray*;
VAR
f, n : INTEGER;
x, y : INTEGER;
color : INTEGER;
BEGIN
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
b[x*3+color,y] := CHR((ORD(a[x*3+color,y+1])+ORD(a[x*3+color,y-1])+ORD(a[(x-1)*3,y])+ORD(a[(x+1)*3,y])) DIV 4);
END
END
END;
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
a[x*3+color,y] := CHR((ORD(b[x*3+color,y+1])+ORD(b[x*3+color,y-1])+ORD(b[(x-1)*3,y])+ORD(b[(x+1)*3,y])) DIV 4);
END
END
END
END
END;
END Blur2DArray;
BEGIN
time := GetTickCount();
Blur2DArray;
time := GetTickCount() - time;
c.Int(time); c.Ln;
END Blur.
Dephi
program Blur;
{$APPTYPE CONSOLE}
uses
SysUtils,
Windows;
CONST
W = 640; W1 = 640 - 3;
H = 480; H1 = 480 - 3;
NN = 13;
Frames = 10;
TYPE
Plane = ARRAY [0..W*3-1, 0..H-1] OF BYTE;
VAR
a, b : Plane;
PROCEDURE Blur2DArray;
VAR
f, n : INTEGER;
x, y : INTEGER;
color : INTEGER;
i: INTEGER;
BEGIN
FOR f:=1 TO Frames DO BEGIN
FOR n:=1 TO NN DO BEGIN
FOR y:=1 TO H-2 DO BEGIN
FOR x:=1 TO W-2 DO BEGIN
FOR color:=0 TO 2 DO BEGIN
b[x*3+color,y] := (a[x*3+color,y+1]+a[x*3+color,y-1]+a[(x-1)*3,y]+a[(x+1)*3,y]) DIV 4;
END
END
END;
FOR y:=1 TO H-2 DO BEGIN
FOR x:=1 TO W-2 DO BEGIN
FOR color:=0 TO 2 DO BEGIN
a[x*3+color,y] := (b[x*3+color,y+1]+b[x*3+color,y-1]+b[(x-1)*3,y]+b[(x+1)*3,y]) DIV 4;
END
END
END
END
END;
END;
var t: Cardinal;
begin
try
t := GetTickCount;
Blur2DArray;
t := GetTickCount - t;
Write((Frames/t*1000):20:5);
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
-
Oberon-2
...
Oberon-07/11
...
Oberon-07M
...
Delphi
Спасибо, буду гонять (хотя до Delphi скорее всего не доберусь).
-
Ну так как, дала моя ручная оптимизация какой-нибудь результат?
-
Ну так как, дала моя ручная оптимизация какой-нибудь результат?
Не добрался еще, но помню что надо добраться :-)
-
Win7 32 bit, Pentium DualCore 2.6 GHz
GNAT 2012 15.5 fps
TinyCC 3.77 fps
VC2012 20.8 fps
Rust 0.6 10.6 fps
Код на Rust'е -- первый раз на нём пишу, хз что надо тут делать, что бы шустро вычислялось...
extern mod std;
use std::time::precise_time_s;
fn index(x: uint, y: uint, color: uint) -> uint {
(640*y + x)*3 + color
}
fn Blur(inar: &mut [u8], outar: &mut [u8]) {
for uint::range(1, 480-2) |y| {
for uint::range(1, 640-2) |x| {
outar[index(x, y, 0)]= (
((inar[index(x, y-1, 0)] as uint) +
(inar[index(x, y+1, 0)] as uint) +
(inar[index(x-1, y, 0)] as uint) +
(inar[index(x+1, y, 0)] as uint)) >> 2) as u8;
outar[index(x, y, 1)]= (
((inar[index(x, y-1, 1)] as uint) +
(inar[index(x, y+1, 1)] as uint) +
(inar[index(x-1, y, 1)] as uint) +
(inar[index(x+1, y, 1)] as uint)) >> 2) as u8;
outar[index(x, y, 2)]= (
((inar[index(x, y-1, 2)] as uint) +
(inar[index(x, y+1, 2)] as uint) +
(inar[index(x-1, y, 2)] as uint) +
(inar[index(x+1, y, 2)] as uint)) >> 2) as u8;
}
}
}
fn timeit(f: &fn()) -> float {
let start = precise_time_s();
f();
let stop = precise_time_s();
stop - start
}
fn main() {
let blurRange : uint = 13;
let frames : uint = 1000;
let mut inarr = [127u8, ..(640*480*3)];
let mut outarr = [ 0u8, ..(640*480*3)];
let time = do timeit {
for uint::range(1, frames) |_nn| {
for uint::range(1, blurRange) |_i| {
Blur(inarr, outarr);
Blur(outarr, inarr);
}
} };
io::println(fmt!("blur_rust: fps %? time %? sec", ((frames as float)/time), time));
}
-
DIzer, не желаете эйфорию испытать?
-
WinXP sp3 Pentium DualCore 1.6 GHz
C# VS2010 .NET 4.0 3.8 fps
F# VS2010 .NET 4.0 10.9 fps
На этом же ПК до этого у меня были такие результаты:
GNAT2012 9.4 fps
TinyC 0.9.24 2.3 fps
VC2010 12.3 fps
Результаты ваще удивительные:
программа на сишарпе в три раза медленнее, чем на С++ (видимо из-за проверок выхода за границы массивов);
однако программа на F# почти догнала сишную (хотя её стоит лучше проверить -- на реальных фотках, а то хз правильно ли она работает)
C#:
using System;
namespace BlurCS
{
class Program
{
const uint width = 640,
height = 480,
blurRange = 13,
frames = 20;
static Byte[] inarr = new Byte[width*height*3],
outarr = new Byte[width*height*3];
enum Color: uint
{
RED = 0,
GREEN,
BLUE
}
static uint index(uint x, uint y, Color color)
{
return 3*(width*y + x) + (uint)color;
}
static void Blur(ref Byte[] inar, ref Byte[] outar)
{
for (uint y=1; y<height-1; y++)
{
for (uint x=1; x<width-1; x++)
{
outar[index(x, y, Color.RED)]= (Byte)(
((uint)inar[index(x, y-1, Color.RED)]+
(uint)inar[index(x, y+1, Color.RED)]+
(uint)inar[index(x-1, y, Color.RED)]+
(uint)inar[index(x+1, y, Color.RED)]) >> 2);
outar[index(x, y, Color.GREEN)]= (Byte)(
((uint)inar[index(x, y-1, Color.GREEN)]+
(uint)inar[index(x, y+1, Color.GREEN)]+
(uint)inar[index(x-1, y, Color.GREEN)]+
(uint)inar[index(x+1, y, Color.GREEN)]) >> 2);
outar[index(x, y, Color.BLUE)]= (Byte)(
((uint)inar[index(x, y-1, Color.BLUE)]+
(uint)inar[index(x, y+1, Color.BLUE)]+
(uint)inar[index(x-1, y, Color.BLUE)]+
(uint)inar[index(x+1, y, Color.BLUE)]) >> 2);
}
}
}
static void Main(string[] args)
{
System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch();
timer.Reset(); timer.Start();
for (uint nn=0; nn<frames; nn++)
{
for (uint i=0; i<blurRange; i++)
{
Blur(ref inarr, ref outarr);
Blur(ref outarr, ref inarr);
}
}
timer.Stop();
double dt = timer.Elapsed.TotalSeconds;
System.Console.WriteLine("BlurC#: FPS = {0:##.##} time = {1:#.#} sec", (frames / dt), dt);
}
}
}
F#:
let width : int = 640
let height : int = 480
let blurRange: int = 13
let frames : int = 100
let inarr: byte array = Array.create (3*width*height) 127uy
let outarr: byte array = Array.zeroCreate (3*width*height)
let Blur(inar: byte array ref, outar: byte array ref) =
let inline index x y color = 3*(width*y + x) + color
for y = 1 to height-2 do
for x = 1 to width-2 do
Array.set !outar (index x y 0)
(byte(
(int (!inar).[index x (y-1) 0] +
int (!inar).[index x (y+1) 0] +
int (!inar).[index (x-1) y 0] +
int (!inar).[index (x+1) y 0]) / 2))
do let timer = new System.Diagnostics.Stopwatch()
timer.Reset(); timer.Start()
for nn = 1 to frames do
for i = 1 to blurRange do
Blur(ref inarr, ref outarr)
Blur(ref outarr, ref inarr)
timer.Stop()
let dt = timer.Elapsed.TotalSeconds
System.Console.WriteLine("BlurF#: FPS = {0:##.##} time = {1:#.#} sec", (float frames / dt), dt)
-
Результаты ваще удивительные:
программа на сишарпе в три раза медленнее, чем на С++ (видимо из-за проверок выхода за границы массивов);
однако программа на F# почти догнала сишную (хотя её стоит лучше проверить -- на реальных фотках, а то хз правильно ли она работает)
Ларчик просто открывался -- в программе на F# была ошибка -- обрабатывался только 1 цвет )))
WinXP sp3 Pentium DualCore 1.6 GHz
C# VS2010 .NET 4.0 3.8 fps
F# VS2010 .NET 4.0 2.8 fps
На этом же ПК до этого у меня были такие результаты:
GNAT2012 9.4 fps
TinyC 0.9.24 2.3 fps
VC2010 12.3 fps
Исправленный вариант на F#:
let width : int = 640
let height : int = 480
let blurRange: int = 13
let frames : int = 100
let inarr: byte array = Array.create (3*width*height) 127uy
let outarr: byte array = Array.zeroCreate (3*width*height)
let Blur(inar: byte array ref, outar: byte array ref) =
let index x y color = 3*(width*y + x) + color
for y = 1 to height-2 do
for x = 1 to width-2 do
for c = 0 to 2 do
Array.set !outar (index x y c)
(byte((int (!inar).[index x (y-1) c] +
int (!inar).[index x (y+1) c] +
int (!inar).[index (x-1) y c] +
int (!inar).[index (x+1) y c]) / 2))
do let timer = new System.Diagnostics.Stopwatch()
timer.Reset(); timer.Start()
for nn = 1 to frames do
for i = 1 to blurRange do
Blur(ref inarr, ref outarr)
Blur(ref outarr, ref inarr)
timer.Stop()
let dt = timer.Elapsed.TotalSeconds
System.Console.WriteLine("BlurF#: FPS = {0:##.##} time = {1:#.#} sec", (float frames / dt), dt)
-
Какой-то не очень компилятор у F# -- не может развернуть простейший цикл. Развернул вручную -- fps поднялся 22% и составил 3.37 (был 2.8).
Всё же от сишарпа отстаёт на 13%...
F#:let width : int = 640
let height : int = 480
let blurRange: int = 13
let frames : int = 100
let inarr: byte array = Array.create (3*width*height) 127uy
let outarr: byte array = Array.zeroCreate (3*width*height)
let Blur(inar: byte array ref, outar: byte array ref) =
let index x y color = 3*(width*y + x) + color
for y = 1 to height-2 do
for x = 1 to width-2 do
Array.set !outar (index x y 0)
(byte((int (!inar).[index x (y-1) 0] +
int (!inar).[index x (y+1) 0] +
int (!inar).[index (x-1) y 0] +
int (!inar).[index (x+1) y 0]) / 2))
Array.set !outar (index x y 1)
(byte((int (!inar).[index x (y-1) 1] +
int (!inar).[index x (y+1) 1] +
int (!inar).[index (x-1) y 1] +
int (!inar).[index (x+1) y 1]) / 2))
Array.set !outar (index x y 2)
(byte((int (!inar).[index x (y-1) 2] +
int (!inar).[index x (y+1) 2] +
int (!inar).[index (x-1) y 2] +
int (!inar).[index (x+1) y 2]) / 2))
do let timer = new System.Diagnostics.Stopwatch()
timer.Reset(); timer.Start()
for nn = 1 to frames do
for i = 1 to blurRange do
Blur(ref inarr, ref outarr)
Blur(ref outarr, ref inarr)
timer.Stop()
let dt = timer.Elapsed.TotalSeconds
System.Console.WriteLine("BlurF#: FPS = {0:##.##} time = {1:#.#} sec", (float frames / dt), dt)
-
Интересно, у кого есть оптимизирующий компилятор OOC, может ли проверить результат кода на Обероне-2?
-
При замене кода
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
b[x*3+color,y] := SHORT(SHORT((a[x*3+color,y+1]+a[x*3+color,y-1]+a[(x-1)*3,y]+a[(x+1)*3,y]) DIV 4));
END
END
END;
на такой:
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
v := x*3; va := a[v - 3,y] + a[v + 3,y];
b[v,y] := SHORT(SHORT(ASH(
a[v,y+1]+
a[v,y-1]+
va
, -2)));
INC(v);
b[v,y] := SHORT(SHORT(ASH(
a[v,y+1]+
a[v,y-1]+
va
, -2)));
INC(v);
b[v,y] := SHORT(SHORT(ASH(
a[v,y+1]+
a[v,y-1]+
va
, -2)));
END
END;
Получаю дополнительное уменьшение времени выполнения почти на 40%.
Только гарантировать верность вычислений подтвердить не могу: на картинке не проверял.
-
DIzer, не желаете эйфорию испытать?
Не желаю участвовать в коллективном маразме (если состояние эйфории Алексея я еще могу понять, но лично мне моча глаза не застилает).. но это ИМХО , конечно...
-
DIzer, не желаете эйфорию испытать?
Не желаю участвовать в коллективном маразме (если состояние эйфории Алексея я еще могу понять, но лично мне моча глаза не застилает).. но это ИМХО , конечно...
Ну, предложи другой конкретный алгоритм для бенчмарка. Он должен быть просто и короток в реализации.
Конкретный алгоритм - это значит покажи референсную реализацию его на любом императивном языке.
-
Ну, предложи другой конкретный алгоритм для бенчмарка. Он должен быть просто и короток в реализации.
Конкретный алгоритм - это значит покажи референсную реализацию его на любом императивном языке.
да любой другой... хоть решето Эратосфена...,или вычисления знаков числа Пи, Дело ведь не в этом..Я гнусно намекаю на следующее
ну ладно понравилось ЛИЧНО ВАМ слово Блер (с какого перепоя не мне судить). Захотели вы его реализовать... ну вызвался Сергей в качестве реализатора...
вопрос с какого перепоя Блером называется свертка с ядром ({0,1,0},{1,0,1},{0,1,0})/4 а не ({1,1,1},{1,0,1},{1,1,1})/8... с какого будуна апликация сверток (повторение свертки N раз) ведет напрямую к увеличению ее радиуса (по факту ширине окна усреднения). Просто посмотрите на ссылку ( это ведет главным образом к приближению к гауссовскому распределению (радиальной симметричности), и на картинке видно, что больше N=6 - особого смысла выполнять итерации нет)... короче... не охота быть лошарой ми кантарой...
-
DIzer, не желаете эйфорию испытать?
Не желаю участвовать в коллективном маразме (если состояние эйфории Алексея я еще могу понять, но лично мне моча глаза не застилает).. но это ИМХО , конечно...
Не вижу никакого маразма. Лично мне было интересно проверить некоторые моменты сгенерированного машинного кода для одного и того же алгоритма у разных компиляторов интересующих меня языков -- я и проверил. А какой именно там алгоритм -- правильный это блур или не очень -- мне пофигу... :D
-
Не вижу никакого маразма. Лично мне было интересно....
А лично мне эта х..я не интересна... - лично я не вижу никаких преимуществ у нее перед тем же решетом, с одной стороны, а с другой стороны.. доказывать ПОНИМАЮЩЕМУ человеку что это не х..я сложнее.. но это ИМХО
-
У решета Эратосфена есть возможность оптимизации, которая может радикально его ускорить -- использование битовых массивов. Эта реализация может быть невозможной или крайне неэффективной в языках достаточно высокого уровня -- выше Си...
-
У решета Эратосфена есть возможность оптимизации, которая может радикально его ускорить -- использование битовых массивов. Эта реализация может быть невозможной или крайне неэффективной в языках достаточно высокого уровня -- выше Си...
Конгениально , Геннадий (поправьте если ошибаюсь)... то же самое можно сказать и про текущий алгоритм, если в яп нет операции побитового сдвига... ;)
-
Спокойно народ. Этот бенчмарк будет подан под соусом - выбор инструмента в условиях хакатона (то есть в условиях когда времени нет, мозга нет, организм в шоке, зато есть ИДЕЯ, и нужно слепить прототип реализации этой идеи за короткое время).
Решето, вычисление Пи, функция Аккермана - идут лесом. Ибо не профиль.
-
Решето, вычисление Пи, функция Аккермана - идут лесом. Ибо не профиль.
а что профиль.. почему БЛЕР.. а не просто дымчатый фон который генерируется за один проход...
-
Спокойно народ. Этот бенчмарк будет подан под соусом
вот именно это и не нравится.... соус не соответствует блюду... и сделан из некачественных продуктов.. порубленный и смешанных "китайскими лохами"
-
Решето, вычисление Пи, функция Аккермана - идут лесом. Ибо не профиль.
а что профиль.. почему БЛЕР.. а не просто дымчатый фон который генерируется за один проход...
Потому что ИДЕЯ. Фикс :-)
Ты дымчатый фон предполагаешь статичным? Генерацию через какой-нибудь perlin noise?
-
Решето, вычисление Пи, функция Аккермана - идут лесом. Ибо не профиль.
а что профиль.. почему БЛЕР.. а не просто дымчатый фон который генерируется за один проход...
Потому что ИДЕЯ. Фикс :-)
Ты дымчатый фон предполагаешь статичным? Генерацию через какой-нибудь perlin noise?
я вам предлагал... сначала поработать со статикой.. (картинка не меняется от кадра к кадру)... для того что бы можно было либо сделать какие то выводы.. либо наметить путь дальнейших исследований... но касаемо конкретного ответа, на конкретный вопрос... как вам понравится эффект наложения дымчатой текстуры.. с трансформацией ее от кадра к кадру (например, по синусоиде)?
-
Конгениально , Геннадий (поправьте если ошибаюсь)...
Евгений.
то же самое можно сказать и про текущий алгоритм, если в яп нет операции побитового сдвига... ;)
Даже если в языке нет операции побитового сдвига, то стыдно компилятору этого языка не суметь соптимизировать целочисленное умножение/деление на степень двойки в битовый сдвиг. Это тоже может быть показателем качества реализации языка...
-
как вам понравится эффект наложения дымчатой текстуры.. с трансформацией ее от кадра к кадру (например, по синусоиде)?
Я наверно предпочту 3D вариацию perlin noise, либо 3D simplex noise.
-
Спокойно народ. Этот бенчмарк будет подан под соусом - выбор инструмента в условиях хакатона (то есть в условиях когда времени нет, мозга нет, организм в шоке, зато есть ИДЕЯ, и нужно слепить прототип реализации этой идеи за короткое время).
Непонятно, как такой соус может проканать -- ведь решения на других языках тут предлагались вовсе не в условиях хакатоновского стресса.
В таких условиях -- какой инструмент лучше знаешь, на том быстрее и решишь задачу (слепишь прототип)...
Вообще, в чём идея той серии статей про Оберон -- популяризовать его или совсем уже ниже плинтуса опустить? )))
ЗЫ. Да, и пора бы тебе уже привести на этот форум саму Надю! А то чо тут одни мужики собрались???
-
как вам понравится эффект наложения дымчатой текстуры.. с трансформацией ее от кадра к кадру (например, по синусоиде)?
Надеюсь, мои глаза такого гипнотизирующего эффекта никогда не увидят -- болеть начнут на второй секунде )))
-
Plane = ARRAY W*3, H OF SHORTINT;
Видимо, для Оберонов/КП правильный массив должен выглядеть как
Plane = ARRAY H, W*3 OF SHORTINT;
и результат тогда будет несколько другой
-
Спокойно народ. Этот бенчмарк будет подан под соусом - выбор инструмента в условиях хакатона (то есть в условиях когда времени нет, мозга нет, организм в шоке, зато есть ИДЕЯ, и нужно слепить прототип реализации этой идеи за короткое время).
Непонятно, как такой соус может проканать -- ведь решения на других языках тут предлагались вовсе не в условиях хакатоновского стресса.
Это то как раз просто - чем наивней реализация, тем она лучше :-)
Ну и опять таки - любое усовершенствование в реализации алгоритма на конкретном языке обязано быть перенесено во все другия ЯП, и протестировано. У нас не http://benchmarksgame.alioth.debian.org/ , у нас все раализации одинаковы будут. Если какое-то усовершенствование не влияет на производительность скажем кода С++, то оно туда не вносится, а если, при этом, оно влияет на производительность Оберон-кода, то в результате имеем 2 версии Оберон-кода - с наивной реализацией, и с оптимизированной. Тестируются обе версии.
По результатам можно будет сравнить как производительность всех реализаций, так и читабельность (а также вероятность доспутить ошибку в реализации в состоянии цейтнота). И уже на основе этого сделать какие-то выводы.
В таких условиях -- какой инструмент лучше знаешь, на том быстрее и решишь задачу (слепишь прототип)...
Не совсем так. Если ты даже прекрасно знаешь js, то быструю реализацию данного алгоритма ты все равно не напишешь. То есть придется тратить драгоценное время на поиск менее тривиальных методик блюра.
Вообще, в чём идея той серии статей про Оберон -- популяризовать его или совсем уже ниже плинтуса опустить? )))
Для начала донести до народа, что они вообще существуют. И вон, даже их бенчмаркают на ряду со всеми известными ЯП.
ЗЫ. Да, и пора бы тебе уже привести на этот форум саму Надю! А то чо тут одни мужики собрались???
Захочет - сама придет :-)
-
Даже если в языке нет операции побитового сдвига, то стыдно компилятору этого языка не суметь соптимизировать целочисленное умножение/деление на степень двойки в битовый сдвиг. Это тоже может быть показателем качества реализации языка...
не знаю как насчет сдвига.. но в той же эйфории целочисленное деление (вычисление остатка) может применяться ко всем членам последовательности (как целочисленным так и нет) -обобщенка.. ну не факт, что кто то будет оптимизировать это в общем случае...
-
Евгений.
:( Извините.. буду знать.
-
Непонятно, как такой соус может проканать -- ведь решения на других языках тут предлагались вовсе не в условиях хакатоновского стресса.
Вот это и обидно.. если Блероманию.. можно списать хакатоновый стресс.. и идею фикс... , то х..ню от кучи здоровых мужиков у которых есть время разобраться.. - нет.. но это имхо..Впрочем, хотя уровень средний харбровских статей около плинтуса.. лично мне не охота вносить свой СОЗНАТЕЛЬНЫЙ вклад в увеличении энтропии.. Кроме того есть небольшая вероятность что можно напороться на специалиста.. - который скажет - "ну и уроды..."
-
Непонятно, как такой соус может проканать -- ведь решения на других языках тут предлагались вовсе не в условиях хакатоновского стресса.
Вот это и обидно.. если Блероманию.. можно списать хакатоновый стресс.. и идею фикс... , то х..ню от кучи здоровых мужиков у которых есть время разобраться.. - нет.. но это имхо..Впрочем, хотя уровень средний харбровских статей около плинтуса.. лично мне не охота вносить свой СОЗНАТЕЛЬНЫЙ вклад в увеличении энтропии.. Кроме того есть небольшая вероятность что можно напороться на специалиста.. - который скажет - "ну и уроды..."
Еще раз - мы эмулируем разработку и реализацию алгоритма в условиях хакатона. В этой теме (вот конкретно в этой) не ведется дискуссия о качестве самого алгоритма. Мы тут лишь смотрим как разные ЯП себя ведут на наивнейшем и кривейшем алгоритме размытия. Всё.
Если говорить о алгоритме, то в общем то Надя еще в начале недели нашла алгоритм (но не реализацию) который реализует размытие любой силы за O(W*H) (то есть от силы размытия не зависит, зависит только от размеров картинки). И я теперь себя чувствую дебилом, ибо я же ЗНАЮ эти методики, и там в общем то ничего нового для меня по сути нет. По идее, мог бы и прямо на хакатоне додуматься до такого. Так что свое ускорение в 10 раз мы скорее всего уже получили :-)
-
Еще раз - мы эмулируем разработку и реализацию алгоритма в условиях хакатона.
Делайте что хотите... только уж определитесь.. бенчмарки вы собираетеь отсылать или что еще.. и непонятно.. нафиг условиях хакотона моделировать бенчмарки... ;) - короче,
я не ПРОТИВ , я за то что бы усе было достойно и непротиворечиво...
-
вопрос с какого перепоя Блером называется свертка с ядром ({0,1,0},{1,0,1},{0,1,0})/4 а не ({1,1,1},{1,0,1},{1,1,1})/8... с какого будуна апликация сверток (повторение свертки N раз) ведет напрямую к увеличению ее радиуса (по факту ширине окна усреднения).
Почему я беру именно ({0,1,0},{1,0,1},{0,1,0})/4 объясняется очень просто.
Изображение можно "разгладить" до
0) среднего значения;
1) линейного градиента;
2) полинома второй степени по x и y;
3) третей степени;
и т. д.
Случай (0) не очень интересен. Минимальное нетривиальное "разглаживание" есть разглаживание до линейного градиента, то есть зануление вторых и более высоких производных. Двумерный разностный лапласиан:
Lf[y, x] = f[y-1, x] + f[y+1, x] + f[y, x-1] + f[y, x+1] - 4*f[y, x];
Зануляем Lf[y, x] = 0, получаем итерационную схему
f -> h:
h[y, x] = (f[y-1, x] + f[y+1, x] + f[y, x-1] + f[y, x+1]) / 4;
Если эту схему гонять много раз, то картинка будет превращаться в линейный градиент.
Можно взять квадрат оператора лапласа:
LLf[y, x] = f[-2 + y, x] + 2 f[-1 + y, -1 + x] - 8 f[-1 + y, x] + 2 f[-1 + y, 1 + x] + f[y, -2 + x] - 8 f[y, -1 + x] + 20 f[y, x] - 8 f[y, 1 + x] + f[y, 2 + x] + 2 f[1 + y, -1 + x] - 8 f[1 + y, x] + 2 f[1 + y, 1 + x] + f[2 + y, x];
занулив его
LLf[y, x] = 0
получить другую итерационную схему:
h[y, x] = (-f[-2 + y, x] - 2 f[-1 + y, -1 + x] + 8 f[-1 + y, x] - 2 f[-1 + y, 1 + x] - f[y, -2 + x] + 8 f[y, -1 + x] + 8 f[y, 1 + x] - f[y, 2 + x] - 2 f[1 + y, -1 + x] + 8 f[1 + y, x] - 2 f[1 + y, 1 + x] - f[2 + y, x]) / 20;
Если эту схему гонять много раз, то картинка будет превращаться в "кубический градиент".
Как-то так...
-
Почему я беру именно ({0,1,0},{1,0,1},{0,1,0})/4 объясняется очень просто.
Если эту схему гонять много раз, то картинка будет превращаться в "кубический градиент".
Как-то так...
почему не вариант Б - с 8 единицами как более аккуратное прилближение... кстати , если посмотрите на ссылку.. то там на картинке видно, что при N=6 (для нормального ядра УЖЕ получается практически гауссово размытие.. т.е. больше 6 раз прогонять свертку на ядре 3x3 - смысла нет)
-
это если на передний план смотреть...
-
это если на передний план смотреть...
а зачем нам туда смотреть.. мы должны смотреть(искажать) назад(задний план)... то что попало в фокус камеры (передний план) должно передаваться без искажений (или с минимальными)...
-
Вот моя версия КП/ББ. На моём компе на N=13 работает две минуты.
MODULE WorkBlur;
IMPORT Log, Kernel, SYSTEM;
CONST W = 640; H = 480; (* размер кадра в пикселях *)
w = (W - 1) * 3; h = H -1; (* размер области кадра на обработке *)
F = 1000; (* кол-во кадров *)
PROCEDURE Do*(N : INTEGER);
VAR a1, a2 : POINTER TO ARRAY OF BYTE;
len : INTEGER;
f, n, x, y : INTEGER;
m, t, l, r, b : INTEGER;
time : LONGINT;
BEGIN
time := Kernel.Time();
len := W * H * 3;
NEW( a1, len );
NEW( a2, len );
f := 0;
WHILE f < F DO
n := 0;
WHILE n < N DO (* x, y *)
t := 3; (* 1, 0 *)
l := w - 3; m := l + 3; r := l + 6; (* 0, 1 ; 1, 1 ; 2, 1 *)
b := r + w; (* 1, 2 *)
y := 1;
WHILE y < h DO
x := 3;
WHILE x < w DO
a2[m] := SHORT(SHORT(SYSTEM.LSH((a1[t] + a1[b] + a1[l] + a1[r]), -2)));
t := t + 1; l := l + 1; m := m + 1; r := r + 1; b := b + 1;
x := x + 1
(*INC(t); INC(l); INC(m); INC(r); INC(b);
INC(x)*)
END;
t := t + 6; l := l + 6; m := m + 6; r := r + 6; b := b + 6;
y := y + 1
(*INC(y)*)
END;
(*<-->*)
t := 3;
l := w - 3; m := l + 3; r := l + 6;
b := r + w;
y := 1;
WHILE y < h DO
x := 3;
WHILE x < w DO
a1[m] := SHORT(SHORT(SYSTEM.LSH((a2[t] + a2[b] + a2[l] + a2[r]), -2)));
t := t + 1; l := l + 1; m := m + 1; r := r + 1; b := b + 1;
x := x + 1
END;
t := t + 6; l := l + 6; m := m + 6; r := r + 6; b := b + 6;
y := y + 1
END;
n := n + 1
END;
f := f + 1
END;
Log.Int(SHORT(Kernel.Time() - time))
END Do;
END WorkBlur.
-
Пока писал версию для двумерного массива, понял, что неправильно соптимизировал версию для одномерного.
Второй заход:
для N=13
одномерный массив - больше 1.5 минуты
двумерный - больше 3 минут
MODULE WorkBlur;
IMPORT Log, Kernel, SYSTEM;
CONST W = 640; H = 480; (* размер кадра в пикселях *)
ln = 1;
clr = 3;
w = (W - 1) * clr; h = H -1; (* размер области кадра на обработке *)
w2 = W * clr;
shift = -2;
F = 1000; (* кол-во кадров *)
PROCEDURE Do*(N : INTEGER);
VAR a1, a2 : POINTER TO ARRAY OF BYTE;
len : INTEGER;
f, n, x, y : INTEGER;
m : INTEGER;
time : LONGINT;
BEGIN
time := Kernel.Time();
len := W * H * clr;
NEW( a1, len );
NEW( a2, len );
f := 0;
WHILE f < F DO
n := 0;
WHILE n < N DO
m := w + 6;
y := 1;
WHILE y < h DO
x := 3;
WHILE x < w DO
a2[m] := SHORT(SHORT(SYSTEM.LSH(a1[m - w2] + a1[m - clr] + a1[m + clr] + a1[m + w2], shift)));
m := m + 1;
x := x + 1
END;
m := m + 6;
y := y + 1
END;
(*<-->*)
m := w + 6;
y := 1;
WHILE y < h DO
x := 3;
WHILE x < w DO
a1[m] := SHORT(SHORT(SYSTEM.LSH(a2[m - w2] + a2[m - clr] + a2[m + clr] + a2[m + w2], shift)));
m := m + 1;
x := x + 1
END;
m := m + 6;
y := y + 1
END;
n := n + 1
END;
f := f + 1
END;
Log.Int(SHORT(Kernel.Time() - time))
END Do;
PROCEDURE Do2*(N : INTEGER);
VAR a1, a2 : POINTER TO ARRAY OF ARRAY OF BYTE;
len : INTEGER;
f, n, x, y : INTEGER;
time : LONGINT;
BEGIN
time := Kernel.Time();
NEW( a1, H, W * 3 );
NEW( a2, H, W * 3 );
f := 0;
WHILE f < F DO
n := 0;
WHILE n < N DO
y := 1;
WHILE y < h DO
x := 3;
WHILE x < w DO
a2[y, x] := SHORT(SHORT(SYSTEM.LSH(a1[y - ln, x] + a1[y, x - clr] + a1[y, x + clr] + a1[y + ln, x], shift)));
x := x + 1
END;
y := y + 1
END;
y := 1;
WHILE y < h DO
x := 3;
WHILE x < w DO
a1[y, x] := SHORT(SHORT(SYSTEM.LSH(a2[y - ln, x] + a2[y, x - clr] + a2[y, x + clr] + a2[y + ln, x], shift)));
x := x + 1
END;
y := y + 1
END;
n := n + 1
END;
f := f + 1
END;
Log.Int(SHORT(Kernel.Time() - time))
END Do2;
END WorkBlur.
-
Пока писал версию для двумерного массива, понял, что неправильно соптимизировал версию для одномерного.
Второй заход:
для N=13
одномерный массив - больше 1.5 минуты
двумерный - больше 3 минут
Круто! А какие характеристики ноута?
-
я это на большом компе запускал.
Проц. i3 3220. Остальное значение не имеет, мне кажется.
-
я это на большом компе запускал.
Проц. i3 3220. Остальное значение не имеет, мне кажется.
Всё равно круто :-) (вообще говоря, тут еще шустрость памяти играет роль)
Доберусь до того ультрабука - затестю.
PS. И надо будет таки научиться работать с картинками в ББ (прочитать с диска, отобразить, записать на диск)
-
Про память я уже подзабыл.
Помню, что Кингстон, тайминги 11.
Частота, возможно 1600
-
нетбук асус 1215b.
Проц. AMD® APU E450 1.65GHz (dual core)
Память DDR3, одноканальная.
Провёл несколько тестов на одномерных массивах. Постепенно "отпускал" комп. от режима энергопотребления к максимальной производительности.
658 - 783 - 385 - 385 (секунды)
-
Реаизовал алгоритм на javaScript'e. Поскольку прямо сейчас под рукой той, референсной машины нет, то все гонял на старом ноутбуке (2008 год, 32 бита. виста).
Результаты (js, и, для сравнения, ББ на этой машине):
js:
time: 290 seconds
fps : 3.45
BB/CP (DIV-оптимизация, 2D array):
time: 454 seconds
fps : 2.20
BB/CP (DIV-оптимизация, 2D array): ~428 s
LuaJit 2.0.1 (x86): ~197 s
local ffi = require 'ffi'
local W, H = 640, 480
local N, F = 13, 1000
local plane = ffi.typeof("uint8_t[?]")
local a, b = plane(W*H*3), plane(W*H*3)
local function index(x, y, c)
return (x+y*W)*3 + c
end
local t1 = os.clock()
for f = 1, F do
for n = 1, N do
for y = 1, H-2 do
for x = 1, W-2 do
for c = 0, 2 do
b[index(x, y, c)] = bit.lshift(
a[index(x, y+1, c)]+
a[index(x, y-1, c)]+
a[index(x-1, y, c)]+
a[index(x+1, y, c)], 2)
end
end
end
for y = 1, H-2 do
for x = 1, W-2 do
for c = 0, 2 do
a[index(x, y, c)] = bit.lshift(
b[index(x, y+1, c)]+
b[index(x, y-1, c)]+
b[index(x-1, y, c)]+
b[index(x+1, y, c)], 2)
end
end
end
end
end
print(os.clock() - t1)
Core i3 M380 2.53GHz
Windows 7 64
-
Версия на Fortran
program blur_bench
implicit none
integer, parameter :: width = 640, height = 480
integer, parameter :: frames = 20, r = 13
type pixel
byte :: r, g, b
end type
integer :: i, j, f, n
real :: t1, t2
type(pixel), dimension(width,height) :: in, out
call cpu_time(t1)
do f = 1,frames
do n = 1,r
do j = 2,height-1
do i = 2,width-1
out(i,j)%r = (in(i-1,j)%r + in(i+1,j)%r + in(i,j-1)%r + in(i,j+1)%r) / 4
out(i,j)%g = (in(i-1,j)%g + in(i+1,j)%g + in(i,j-1)%g + in(i,j+1)%g) / 4
out(i,j)%b = (in(i-1,j)%b + in(i+1,j)%b + in(i,j-1)%b + in(i,j+1)%b) / 4
end do
end do
do j = 2,height-1
do i = 2,width-1
in(i,j)%r = (out(i-1,j)%r + out(i+1,j)%r + out(i,j-1)%r + out(i,j+1)%r) / 4
in(i,j)%g = (out(i-1,j)%g + out(i+1,j)%g + out(i,j-1)%g + out(i,j+1)%g) / 4
in(i,j)%b = (out(i-1,j)%b + out(i+1,j)%b + out(i,j-1)%b + out(i,j+1)%b) / 4
end do
end do
end do
end do
call cpu_time(t2)
write (*,*) 'Time: ', t2-t1
write (*,*) 'FPS: ', frames/(t2-t1)
end program
-
Варианта на жабе не было?
через for-ы где-то на полсекунды быстрее работает, чем через while. Но всё равно где-то на 10 сек. медленнее ББ.
Проверял на десктопе, из IDE, без каких-либо ключей. жаба 7.
import java.io.IOException;
import java.io.InputStream;
public class TestBlur {
private static int W = 640;
private static int H = 480;
private static int line = 1;
private static int colour = 3;
private static int w = (W - 1) * colour;
private static int h = H - 1;
private static int w2 = W + colour;
private static int shift = 2;
private static int F = 1000;
private static void Do(int N) {
long time = System.currentTimeMillis();
int len = W * H * colour;
byte a1[] = new byte[len];
byte a2[] = new byte[len];
int m;
for (int f = 0; f < F; f++) {
for (int n = 0; n < N; n++) {
m = w + 6;
for (int y = 1; y < h; y++) {
for (int x = 3; x < w; x++) {
a2[m] = (byte) ((a1[m - w2] + a1[m - colour] + a1[m + colour] + a1[m + w2] ) >> shift);
m++;
}
m = m + 6;
}
m = w + 6;
for (int y = 1; y < h; y++) {
for (int x = 3; x < w; x++) {
a1[m] = (byte) ((a2[m - w2] + a2[m - colour] + a2[m + colour] + a2[m + w2] ) >> shift);
m++;
}
m = m + 6;
}
}
}
System.out.println(System.currentTimeMillis() - time);
}
private static void Do2(int N) {
long time = System.currentTimeMillis();
int len = W * H * colour;
byte a1[] = new byte[len];
byte a2[] = new byte[len];
int m;
int f, n;
int x, y;
f = 0;
while (f < F) {
n = 0;
while (n < N) {
m = w + 6;
y = 1;
while (y < h) {
x = 3;
while (x < w) {
a2[m] = (byte) ((a1[m - w2] + a1[m - colour] + a1[m + colour] + a1[m + w2] ) >> shift);
m++;
x++;
}
m = m + 6;
y++;
}
m = w + 6;
y = 1;
while (y < h) {
x = 3;
while (x < w) {
a1[m] = (byte) ((a2[m - w2] + a2[m - colour] + a2[m + colour] + a2[m + w2] ) >> shift);
m++;
x++;
}
m = m + 6;
y++;
}
n++;
}
f++;
}
System.out.println(System.currentTimeMillis() - time);
}
public static void main(String argv[]) {
char ch = 'd';
InputStream is = System.in;
while (ch != 'q' || ch == 'Q') {
System.out.print("Start test [1,2], [Q]uit > ");
try {
ch = (char) is.read();
if (ch == '1') {
Do(13);
} else if (ch == '2') {
Do2(13);
}
} catch (IOException e) {
System.err.println("error: " + e.getMessage());
}
}
}
}
-
...
Блин, перепутал.
rshift должен быть
-
Сделал версию на Лимбе, но что-то оно медленно работает...
То ли там особый подход нужен, то ли эмулятор там слабенький.
Для N=13 работало дольше 1:20. Правда, через полчаса после запуска меня заколебало, и я начал просмотр фильма. Возможно, это в некоторой степени повлияло на результат.
-
В Блэкбоксе же ASH есть нормально работающий
-
Глянул исходники компилятора Блэкбокса - DIV в нужных местах заменяется на математические сдвиги
-
то бишь на арифметические
-
Байт бывает отрицательным.
Глянул исходники компилятора Блэкбокса
А в каком именно модуле ББ это находится?
-
Байт бывает отрицательным.
Глянул исходники компилятора Блэкбокса
А в каком именно модуле ББ это находится?
CPB
-
Да, спасибо. Я уже тоже нашёл.
-
Так какие же результаты запусков программ на эталонной машине?
-
Oberon-07/11
Кстати, к вопросу о совместимости разных реализаций. Приведенный пример не соответствует репорту языка синтаксически - пресловутые "лишние" точки с запятой. Могу долго рассказывать, что я об этом думаю... но не буду. Просто замечу.
-
Oberon-07/11
Кстати, к вопросу о совместимости разных реализаций. Приведенный пример не соответствует репорту языка синтаксически - пресловутые "лишние" точки с запятой. Могу долго рассказывать, что я об этом думаю... но не буду. Просто замечу.
Цитата из репорта:
statement = [assignment | ProcedureCall | IfStatement | CaseStatement |
WhileStatement | RepeatStatement | ForStatement].
...
StatementSequence = statement {";" statement}.
Из этого следует, что statement может быть пустым, значит лишние ";" не являются ошибкой, они просто необязательны.
-
Могу долго рассказывать, что я об этом думаю... но не буду.
Если не затруднит, поясните пожалуйста, какой смысл иметь возможность использовать пустой оператор?
-
Например:
WHILE func() DO
(* пустой оператор *)
END
Где func -- функция с побочным эффектом, например читает данные из файла, выполняет их обработку и возвращает FALSE, если достигнут конец файла.
-
Такие вещи можно и в одну строку оформлять на мой взгляд.
WHILE ProcessNextFile() DO END; (* Обработали файлы *)
В руководстве от Гугла по С++, если не ошибаюсь, разрешают и так:
while (ProcessNextFile()) {}
-
statement = [assignment | ProcedureCall | IfStatement | CaseStatement |
WhileStatement | RepeatStatement | ForStatement].
...
StatementSequence = statement {";" statement}.
Из этого следует, что statement может быть пустым, значит лишние ";" не являются ошибкой, они просто необязательны.
Не, не вижу - где может быть пустой statement?
-
Не, не вижу - где может быть пустой statement?
statement = [assignment | ProcedureCall | IfStatement | CaseStatement |
WhileStatement | RepeatStatement | ForStatement].
Квадратные скобки видишь?))
-
Квадратные скобки видишь?))
Спасибо! :)
-
Если не затруднит, поясните пожалуйста, какой смысл иметь возможность использовать пустой оператор?
У меня была претензия не к пустому оператору, а к отсутствию (обязательному) точки с запятой перед END. akron1 указал на возможность пустого statement в грамматике (я этот момент упустил), так что опциональная точка с запятой допустима. Претензия снята, был не прав.
-
Поигрался в оптимизацию на BB.
Исходный вариант с Blur2DArray: 0.77 fps.
Переход к 3D (ARRAY W, H, 3 OF BYTE): 0.73 fps, зато обнаружились ошибки (пропущено +color).
DIV 4 вместо *0.25 : 1.4 fps.
Раскрутка цикла по color : 2.09 fps. (по идее здесь устраняются и проверки последнего индекса)
Выравнивание данных (ARRAY W, H, 4 OF BYTE): 2.48 fps.
Статический массив вместо динамического: 2.65 fps.
Отключение проверок: 2.73 fps.
Здесь фантазия иссякла.
Без выравнивания, но с отключеными проверками дает 2.54 fps, что чуть лучше, чем tcc (2.22 fps).
-
Поигрался в оптимизацию на BB.
Исходный вариант с Blur2DArray: 0.77 fps.
Переход к 3D (ARRAY W, H, 3 OF BYTE): 0.73 fps, зато обнаружились ошибки (пропущено +color).
DIV 4 вместо *0.25 : 1.4 fps.
Раскрутка цикла по color : 2.09 fps. (по идее здесь устраняются и проверки последнего индекса)
Выравнивание данных (ARRAY W, H, 4 OF BYTE): 2.48 fps.
Статический массив вместо динамического: 2.65 fps.
Отключение проверок: 2.73 fps.
Здесь фантазия иссякла.
Без выравнивания, но с отключеными проверками дает 2.54 fps, что чуть лучше, чем tcc (2.22 fps).
Исходники от экспериментов остались? Было бы полезно из выложить - чтобы другим велосипед не изобретать.
-
Здесь фантазия иссякла.
Семен Семеныч! Там же индексы в "неправильном" порядке!
Итого 3.5 fps или 4.7 fps с отключенными проверками.
MODULE TestBlur;
IMPORT Kernel, Out:=StdLog;
CONST
W = 640;
H = 480;
N = 13;
Frames = 100;
RED = 0; GREEN=1; BLUE=2;
TYPE
Plane = ARRAY H, W, 4 OF BYTE;
VAR
a, b : Plane;
PROCEDURE Blur*;
VAR
time1,time2 : LONGINT; fps:REAL;
f, n : INTEGER;
x, y : INTEGER;
color : INTEGER;
BEGIN
time1 := Kernel.Time();
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
FOR y:= 1 TO H-2 DO
FOR x:= 1 TO W-2 DO
b[y,x][RED] := SHORT(SHORT((a[y,x + 1][RED] + a[y,x - 1][RED] + a[y - 1, x][RED] + a[y + 1, x][RED]) DIV 4));
b[y,x][GREEN] := SHORT(SHORT((a[y,x + 1][GREEN] + a[y,x - 1][GREEN] + a[y - 1, x][GREEN] + a[y + 1, x][GREEN]) DIV 4));
b[y,x][BLUE] := SHORT(SHORT((a[y,x + 1][BLUE] + a[y,x - 1][BLUE] + a[y - 1, x][BLUE] + a[y + 1, x][BLUE]) DIV 4));
END
END;
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
a[y,x][RED] := SHORT(SHORT((b[y,x + 1][RED] + b[y,x - 1][RED] + b[y - 1, x][RED] + b[y + 1, x][RED]) DIV 4));
a[y,x][GREEN] := SHORT(SHORT((b[y,x + 1][GREEN] + b[y,x - 1][GREEN] + b[y - 1, x][GREEN] + b[y + 1, x][GREEN]) DIV 4));
a[y,x][BLUE] := SHORT(SHORT((b[y,x + 1][BLUE] + b[y,x - 1][BLUE] + b[y - 1, x][BLUE] + b[y + 1, x][BLUE]) DIV 4));
END
END
END
END;
time2 := Kernel.Time();
fps:=Frames*1000/(time2 - time1);
Out.String("t="); Out.Real((time2 - time1)/1000);
Out.String(" fps="); Out.Real(fps);
Out.Ln;
END Blur;
END TestBlur.
DevCompiler.CompileThis TestBlur!!
TestBlur.Blur
-
Здесь фантазия иссякла.
Семен Семеныч! Там же индексы в "неправильном" порядке!
Итого 3.5 fps или 4.7 fps с отключенными проверками.
MODULE TestBlur;
IMPORT Kernel, Out:=StdLog;
CONST
W = 640;
H = 480;
N = 13;
Frames = 100;
RED = 0; GREEN=1; BLUE=2;
TYPE
Plane = ARRAY H, W, 4 OF BYTE;
VAR
a, b : Plane;
PROCEDURE Blur*;
VAR
time1,time2 : LONGINT; fps:REAL;
f, n : INTEGER;
x, y : INTEGER;
color : INTEGER;
BEGIN
time1 := Kernel.Time();
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
FOR y:= 1 TO H-2 DO
FOR x:= 1 TO W-2 DO
b[y,x][RED] := SHORT(SHORT((a[y,x + 1][RED] + a[y,x - 1][RED] + a[y - 1, x][RED] + a[y + 1, x][RED]) DIV 4));
b[y,x][GREEN] := SHORT(SHORT((a[y,x + 1][GREEN] + a[y,x - 1][GREEN] + a[y - 1, x][GREEN] + a[y + 1, x][GREEN]) DIV 4));
b[y,x][BLUE] := SHORT(SHORT((a[y,x + 1][BLUE] + a[y,x - 1][BLUE] + a[y - 1, x][BLUE] + a[y + 1, x][BLUE]) DIV 4));
END
END;
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
a[y,x][RED] := SHORT(SHORT((b[y,x + 1][RED] + b[y,x - 1][RED] + b[y - 1, x][RED] + b[y + 1, x][RED]) DIV 4));
a[y,x][GREEN] := SHORT(SHORT((b[y,x + 1][GREEN] + b[y,x - 1][GREEN] + b[y - 1, x][GREEN] + b[y + 1, x][GREEN]) DIV 4));
a[y,x][BLUE] := SHORT(SHORT((b[y,x + 1][BLUE] + b[y,x - 1][BLUE] + b[y - 1, x][BLUE] + b[y + 1, x][BLUE]) DIV 4));
END
END
END
END;
time2 := Kernel.Time();
fps:=Frames*1000/(time2 - time1);
Out.String("t="); Out.Real((time2 - time1)/1000);
Out.String(" fps="); Out.Real(fps);
Out.Ln;
END Blur;
END TestBlur.
DevCompiler.CompileThis TestBlur!!
TestBlur.Blur
Прогнал этот вариант на оном референсном ультрабуке (компилировал обычным образом, то есть видимо проверка индексов есть):
BB/CB (trurl):
time: t= 261
fps : 3.83
BB/CB (DIV-оптимизация, 2D array - предыдущий вариант):
time: 303 seconds
fps : 3.30
Ну, то есть быстрее, но не значительно.
А как отключить проверку индексов?
-
Догнал до 7 fps.
MODULE TestBlur2;
IMPORT Kernel, Out:=StdLog;
CONST
W = 640;
H = 480;
N = 13;
Frames = 100;
RED = 0; GREEN = 1; BLUE = 2;
TYPE
Plane = ARRAY H*W, 4 OF BYTE;
VAR
a, b : Plane;
PROCEDURE Blur*;
VAR
f, n : INTEGER;
x, y, z : INTEGER;
time1, time2 : LONGINT;
fps:REAL;
BEGIN
time1 := Kernel.Time();
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
FOR y:= 1 TO H-2 DO
FOR x:= 1 TO W-2 DO
z:= y*W+x;
b[z][RED] := SHORT(SHORT((a[z + 1][RED] + a[z - 1][RED] + a[z - W][RED] + a[z + W][RED]) DIV 4));
b[z][GREEN] := SHORT(SHORT((a[z + 1][GREEN] + a[z - 1][GREEN] + a[z - W][GREEN] + a[z + W][GREEN]) DIV 4));
b[z][BLUE] := SHORT(SHORT((a[z + 1][BLUE] + a[z - 1][BLUE] + a[z - W][BLUE] + a[z + W][BLUE]) DIV 4));
END
END;
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
z:= y*W+x;
a[z][RED] := SHORT(SHORT((b[z + 1][RED] + b[z - 1][RED] + b[z - W][RED] + b[z + W][RED]) DIV 4));
a[z][GREEN] := SHORT(SHORT((b[z + 1][GREEN] + b[z - 1][GREEN] + b[z - W][GREEN] + b[z + W][GREEN]) DIV 4));
a[z][BLUE] := SHORT(SHORT((b[z + 1][BLUE] + b[z - 1][BLUE] + b[z - W][BLUE] + b[z + W][BLUE]) DIV 4));
END
END
END
END;
time2 := Kernel.Time();
fps:=Frames*1000/(time2 - time1);
Out.String("t="); Out.Real((time2 - time1)/1000);
Out.String(" fps="); Out.Real(fps);
Out.Ln;
END Blur;
END TestBlur2.
-
А как отключить проверку индексов?
Там команда для компиляции: (!) DevCompiler.CompileThis TestBlur!!
-
А как отключить проверку индексов?
Там команда для компиляции: (!) DevCompiler.CompileThis TestBlur!!
Вау! Та же самая версия (не твоя новая 7 fps'ная) собранная вот так, дает такие результаты:
BB/CB (trurl с проверкой индексов):
time: 261 seconds
fps : 3.83
BB/CB (trurl без проверки индексов):
time: 113 seconds
fps : 8.87
Прирост в 2.5 раза!
Вот она, цена проверки выхода за границы! ;-)
-
Догнал до 7 fps.
MODULE TestBlur2;
IMPORT Kernel, Out:=StdLog;
CONST
W = 640;
H = 480;
N = 13;
Frames = 100;
RED = 0; GREEN = 1; BLUE = 2;
TYPE
Plane = ARRAY H*W, 4 OF BYTE;
VAR
a, b : Plane;
PROCEDURE Blur*;
VAR
f, n : INTEGER;
x, y, z : INTEGER;
time1, time2 : LONGINT;
fps:REAL;
BEGIN
time1 := Kernel.Time();
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
FOR y:= 1 TO H-2 DO
FOR x:= 1 TO W-2 DO
z:= y*W+x;
b[z][RED] := SHORT(SHORT((a[z + 1][RED] + a[z - 1][RED] + a[z - W][RED] + a[z + W][RED]) DIV 4));
b[z][GREEN] := SHORT(SHORT((a[z + 1][GREEN] + a[z - 1][GREEN] + a[z - W][GREEN] + a[z + W][GREEN]) DIV 4));
b[z][BLUE] := SHORT(SHORT((a[z + 1][BLUE] + a[z - 1][BLUE] + a[z - W][BLUE] + a[z + W][BLUE]) DIV 4));
END
END;
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
z:= y*W+x;
a[z][RED] := SHORT(SHORT((b[z + 1][RED] + b[z - 1][RED] + b[z - W][RED] + b[z + W][RED]) DIV 4));
a[z][GREEN] := SHORT(SHORT((b[z + 1][GREEN] + b[z - 1][GREEN] + b[z - W][GREEN] + b[z + W][GREEN]) DIV 4));
a[z][BLUE] := SHORT(SHORT((b[z + 1][BLUE] + b[z - 1][BLUE] + b[z - W][BLUE] + b[z + W][BLUE]) DIV 4));
END
END
END
END;
time2 := Kernel.Time();
fps:=Frames*1000/(time2 - time1);
Out.String("t="); Out.Real((time2 - time1)/1000);
Out.String(" fps="); Out.Real(fps);
Out.Ln;
END Blur;
END TestBlur2.
Эта версия, если отключить проверку индексов, выдает такие результаты (для сравнения, рядом результаты C++ версии):
BB/CP (trurl "7 fps" version, range check off):
time: 88 seconds
fps : 11.38
C++:
time: 66
fps : 15.15
-
Так а сколько мой вариант на одномерном массиве выдаёт fps? http://oberspace.dyndns.org/index.php/topic,484.msg15894.html#msg15894
-
Прирост в 2.5 раза!
Ух ты! У меня прирост от непроверки далеко не такой.
Еще один страшный вариант.
MODULE TestBlur3;
IMPORT Kernel,SYSTEM, Out:=StdLog;
CONST
W = 640;
H = 480;
N = 13;
Frames = 1000;
TYPE
Pixel = ARRAY 4 OF BYTE;
Plane = ARRAY H*W OF Pixel;
VAR
a, b : Plane;
PROCEDURE Blur*;
VAR
f, n : INTEGER;
x, y, z : INTEGER;
q1, q2, q3, q4: SET;
time1, time2 : LONGINT;
fps:REAL;
CONST
MaskRB = {0..7,16..23};
BEGIN
time1 := Kernel.Time();
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
z:= W+1;
FOR y:= 1 TO H-2 DO
FOR x:= 1 TO W-2 DO
q1:=SYSTEM.VAL(SET, a[z + 1]);
q2:=SYSTEM.VAL(SET, a[z - 1]);
q3:=SYSTEM.VAL(SET, a[z + W]);
q4:=SYSTEM.VAL(SET, a[z - W]);
SYSTEM.PUT(SYSTEM.ADR(b[z]),
BITS( (ORD(q1*MaskRB) + ORD(q2*MaskRB) + ORD(q3*MaskRB) + ORD(q4*MaskRB)) DIV 4)
+ BITS( (ORD(q1-MaskRB) + ORD(q2-MaskRB) + ORD(q3-MaskRB) + ORD(q4-MaskRB)) DIV 4));
INC(z);
END;
INC(z,2);
END;
z:= W+1;
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
z:= y*W+x;
q1:=SYSTEM.VAL(SET, b[z + 1]);
q2:=SYSTEM.VAL(SET, b[z - 1]);
q3:=SYSTEM.VAL(SET, b[z + W]);
q4:=SYSTEM.VAL(SET, b[z - W]);
SYSTEM.PUT(SYSTEM.ADR(a[z]),
BITS( (ORD(q1*MaskRB) + ORD(q2*MaskRB) + ORD(q3*MaskRB) + ORD(q4*MaskRB)) DIV 4)
+ BITS( (ORD(q1-MaskRB) + ORD(q2-MaskRB) + ORD(q3-MaskRB) + ORD(q4-MaskRB)) DIV 4));
INC(z);
END;
INC(z,2);
END;
END
END;
time2 := Kernel.Time();
fps:=Frames*1000/(time2 - time1);
Out.String("t="); Out.Real((time2 - time1)/1000);
Out.String(" fps="); Out.Real(fps);
Out.Ln;
END Blur;
END TestBlur3.
DevCompiler.CompileThis TestBlur3!!
TestBlur3.Blur
-
тык какой результат то ?
-
Пока писал версию для двумерного массива, понял, что неправильно соптимизировал версию для одномерного.
Второй заход:
для N=13
одномерный массив - больше 1.5 минуты
двумерный - больше 3 минут
MODULE WorkBlur;
IMPORT Log, Kernel, SYSTEM;
CONST W = 640; H = 480; (* размер кадра в пикселях *)
ln = 1;
clr = 3;
w = (W - 1) * clr; h = H -1; (* размер области кадра на обработке *)
w2 = W * clr;
shift = -2;
F = 1000; (* кол-во кадров *)
PROCEDURE Do*(N : INTEGER);
VAR a1, a2 : POINTER TO ARRAY OF BYTE;
len : INTEGER;
f, n, x, y : INTEGER;
m : INTEGER;
time : LONGINT;
BEGIN
time := Kernel.Time();
len := W * H * clr;
NEW( a1, len );
NEW( a2, len );
f := 0;
WHILE f < F DO
n := 0;
WHILE n < N DO
m := w + 6;
y := 1;
WHILE y < h DO
x := 3;
WHILE x < w DO
a2[m] := SHORT(SHORT(SYSTEM.LSH(a1[m - w2] + a1[m - clr] + a1[m + clr] + a1[m + w2], shift)));
m := m + 1;
x := x + 1
END;
m := m + 6;
y := y + 1
END;
(*<-->*)
m := w + 6;
y := 1;
WHILE y < h DO
x := 3;
WHILE x < w DO
a1[m] := SHORT(SHORT(SYSTEM.LSH(a2[m - w2] + a2[m - clr] + a2[m + clr] + a2[m + w2], shift)));
m := m + 1;
x := x + 1
END;
m := m + 6;
y := y + 1
END;
n := n + 1
END;
f := f + 1
END;
Log.Int(SHORT(Kernel.Time() - time))
END Do;
PROCEDURE Do2*(N : INTEGER);
VAR a1, a2 : POINTER TO ARRAY OF ARRAY OF BYTE;
len : INTEGER;
f, n, x, y : INTEGER;
time : LONGINT;
BEGIN
time := Kernel.Time();
NEW( a1, H, W * 3 );
NEW( a2, H, W * 3 );
f := 0;
WHILE f < F DO
n := 0;
WHILE n < N DO
y := 1;
WHILE y < h DO
x := 3;
WHILE x < w DO
a2[y, x] := SHORT(SHORT(SYSTEM.LSH(a1[y - ln, x] + a1[y, x - clr] + a1[y, x + clr] + a1[y + ln, x], shift)));
x := x + 1
END;
y := y + 1
END;
y := 1;
WHILE y < h DO
x := 3;
WHILE x < w DO
a1[y, x] := SHORT(SHORT(SYSTEM.LSH(a2[y - ln, x] + a2[y, x - clr] + a2[y, x + clr] + a2[y + ln, x], shift)));
x := x + 1
END;
y := y + 1
END;
n := n + 1
END;
f := f + 1
END;
Log.Int(SHORT(Kernel.Time() - time))
END Do2;
END WorkBlur.
Прогнал.
== With array bound checks ===
BB/CB (Valery Solovey 1D):
time: 131 seconds
fps : 7.6
BB/CB (Valery Solovey 2D):
time: 261 seconds
fps : 3.8
== Without array bound checks ===
BB/CB (Valery Solovey 1D):
time: 103 seconds
fps : 9.7 fps
BB/CB (Valery Solovey 2D):
time: 158 seconds
fps : 6.3
-
Прирост в 2.5 раза!
Ух ты! У меня прирост от непроверки далеко не такой.
А процессор какой? У меня мобильный i5. Подозреваю что у разных процессоров алгоритм предсказания немного разный. А ветвления (любые) сильно мешают алгоритму предсказания и увеличивают промахи кеша.
Еще один страшный вариант.
MODULE TestBlur3;
IMPORT Kernel,SYSTEM, Out:=StdLog;
CONST
W = 640;
H = 480;
N = 13;
Frames = 1000;
TYPE
Pixel = ARRAY 4 OF BYTE;
Plane = ARRAY H*W OF Pixel;
VAR
a, b : Plane;
PROCEDURE Blur*;
VAR
f, n : INTEGER;
x, y, z : INTEGER;
q1, q2, q3, q4: SET;
time1, time2 : LONGINT;
fps:REAL;
CONST
MaskRB = {0..7,16..23};
BEGIN
time1 := Kernel.Time();
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
z:= W+1;
FOR y:= 1 TO H-2 DO
FOR x:= 1 TO W-2 DO
q1:=SYSTEM.VAL(SET, a[z + 1]);
q2:=SYSTEM.VAL(SET, a[z - 1]);
q3:=SYSTEM.VAL(SET, a[z + W]);
q4:=SYSTEM.VAL(SET, a[z - W]);
SYSTEM.PUT(SYSTEM.ADR(b[z]),
BITS( (ORD(q1*MaskRB) + ORD(q2*MaskRB) + ORD(q3*MaskRB) + ORD(q4*MaskRB)) DIV 4)
+ BITS( (ORD(q1-MaskRB) + ORD(q2-MaskRB) + ORD(q3-MaskRB) + ORD(q4-MaskRB)) DIV 4));
INC(z);
END;
INC(z,2);
END;
z:= W+1;
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
z:= y*W+x;
q1:=SYSTEM.VAL(SET, b[z + 1]);
q2:=SYSTEM.VAL(SET, b[z - 1]);
q3:=SYSTEM.VAL(SET, b[z + W]);
q4:=SYSTEM.VAL(SET, b[z - W]);
SYSTEM.PUT(SYSTEM.ADR(a[z]),
BITS( (ORD(q1*MaskRB) + ORD(q2*MaskRB) + ORD(q3*MaskRB) + ORD(q4*MaskRB)) DIV 4)
+ BITS( (ORD(q1-MaskRB) + ORD(q2-MaskRB) + ORD(q3-MaskRB) + ORD(q4-MaskRB)) DIV 4));
INC(z);
END;
INC(z,2);
END;
END
END;
time2 := Kernel.Time();
fps:=Frames*1000/(time2 - time1);
Out.String("t="); Out.Real((time2 - time1)/1000);
Out.String(" fps="); Out.Real(fps);
Out.Ln;
END Blur;
END TestBlur3.
DevCompiler.CompileThis TestBlur3!!
TestBlur3.Blur
Результаты прогонов страшного варианта:
BB/CB (trurl/SYSTEM with array bound checks)
time: 81 seconds
fps : 12.2
BB/CB (trurl/SYSTEM without array bound checks)
time: 77 seconds
fps : 13.0
-
Кстати, о корректности: в исходных данных картинки мы имеем набор unsigned char'ов, то есть беззнаковых целых в диапазоне от 0 до 255. Насколько я понимаю, в КП у нас таки тип BYTE знаковый, соответственно нужно как-то конвертировать наверное...
Вообще, как корректно биндинг строится к функции вида:
bool __stdcall PXCUPipeline_QueryRGB(PXCUPipeline_Instance instance, unsigned char *data);
?
-
Кстати, о корректности: в исходных данных картинки мы имеем набор unsigned char'ов, то есть беззнаковых целых в диапазоне от 0 до 255. Насколько я понимаю, в КП у нас таки тип BYTE знаковый, соответственно нужно как-то конвертировать наверное...
Вообще, как корректно биндинг строится к функции вида:
bool __stdcall PXCUPipeline_QueryRGB(PXCUPipeline_Instance instance, unsigned char *data);
?
Если посмотреть на жабу, то там unsigned char отображают тупо в int. То есть был массив байт, стал массив 4байтных целых. Причем так, что один пиксель == одно целое 4 байтное число, RGBA.
Ну и соответственно, чтобы как-то с этим жить, там есть замечательные функции вида:
public final float green(int rgb)
Extracts the green value from a color, scaled to match current colorMode(). This value is always returned as a float so be careful not to assign it to an int value.
The green() function is easy to use and undestand, but is slower than another technique. To achieve the same results when working in colorMode(RGB, 255), but with greater speed, use the >> (right shift) operator with a bit mask. For example, the following two lines of code are equivalent:
float r1 = green(myColor);
float r2 =
myColor >> 8 & 0xFF;
Parameters:
rgb - any value of the color datatype
Ну и конечно функция для создания данных для одного пикселя:
public final int color(int v1,
int v2,
int v3,
int a)
-
Мне кажется что не нужно конвертить. Должно так работать.
-
Кстати, о корректности: в исходных данных картинки мы имеем набор unsigned char'ов, то есть беззнаковых целых в диапазоне от 0 до 255. Насколько я понимаю, в КП у нас таки тип BYTE знаковый, соответственно нужно как-то конвертировать наверное...
Да, надо. Либо MOD 256 добавлять, либо вместо BYTE использовать SHORTCHAR.
-
Oberon-07/11
Теперь этот вариант можно скомпилить и запустить прямо в браузере - см. шапку форума ;) Компилятор сырой, но подрихтованный вариант akron1 он компилит (я закомментировал импорты)
MODULE Blur;
(*IMPORT dt := DateTime, In, Out, RTL;*)
CONST
W = 640; W1 = 640 - 3;
H = 480; H1 = 480 - 3;
N = 13;
Frames = 1;
TYPE
Plane = ARRAY W*3, H OF CHAR;
VAR
a, b: Plane;
time: LONGREAL;
PROCEDURE Blur2DArray*;
VAR
f, n : INTEGER;
x, y : INTEGER;
color : INTEGER;
BEGIN
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
b[x*3+color,y] := CHR((ORD(a[x*3+color,y+1])+ORD(a[x*3+color,y-1])+ORD(a[(x-1)*3,y])+ORD(a[(x+1)*3,y])) DIV 4);
END
END
END;
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
a[x*3+color,y] := CHR((ORD(b[x*3+color,y+1])+ORD(b[x*3+color,y-1])+ORD(b[(x-1)*3,y])+ORD(b[(x+1)*3,y])) DIV 4);
END
END
END
END
END;
END Blur2DArray;
BEGIN
(*In.Open;
Out.Open;
time := dt.Now();*)
Blur2DArray;
(*Out.FixReal(LONG(FLT(Frames))/((dt.Now() - time) * 86400.D0), 20, 5);
In.Ln;*)
END Blur.
-
Oberon-07/11
Теперь этот вариант можно скомпилить и запустить прямо в браузере - см. шапку форума ;) Компилятор сырой, но подрихтованный вариант akron1 он компилит (я закомментировал импорты)
MODULE Blur;
(*IMPORT dt := DateTime, In, Out, RTL;*)
CONST
W = 640; W1 = 640 - 3;
H = 480; H1 = 480 - 3;
N = 13;
Frames = 1;
TYPE
Plane = ARRAY W*3, H OF CHAR;
VAR
a, b: Plane;
time: LONGREAL;
PROCEDURE Blur2DArray*;
VAR
f, n : INTEGER;
x, y : INTEGER;
color : INTEGER;
BEGIN
FOR f:=1 TO Frames DO
FOR n:=1 TO N DO
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
b[x*3+color,y] := CHR((ORD(a[x*3+color,y+1])+ORD(a[x*3+color,y-1])+ORD(a[(x-1)*3,y])+ORD(a[(x+1)*3,y])) DIV 4);
END
END
END;
FOR y:=1 TO H-2 DO
FOR x:=1 TO W-2 DO
FOR color:=0 TO 2 DO
a[x*3+color,y] := CHR((ORD(b[x*3+color,y+1])+ORD(b[x*3+color,y-1])+ORD(b[(x-1)*3,y])+ORD(b[(x+1)*3,y])) DIV 4);
END
END
END
END
END;
END Blur2DArray;
BEGIN
(*In.Open;
Out.Open;
time := dt.Now();*)
Blur2DArray;
(*Out.FixReal(LONG(FLT(Frames))/((dt.Now() - time) * 86400.D0), 20, 5);
In.Ln;*)
END Blur.
Нюанс - в этом исходнике обрабатывается ОДИН кадр (Frames = 1). Так что не удивляйтесь быстрому завершению работы алгоритма. :-)
-
Обнаружил ошибку в сравнении целых
MODULE test;
IMPORT JS;
VAR x: INTEGER;
BEGIN
x := 10;
IF x >= 0 THEN
JS.alert("TRUE")
ELSE
JS.alert("FALSE")
END
END test.
строка
IF x >= 0 THEN
транслируется так
if (RTL$.setInclR(x, 0))
и естественно не работает как надо, похоже, что компилятор применяет операцию ">=" перегруженную для множеств.
Операции ">" и "<" для целых не работают вообще, пишет: TypeError: Cannot call method 'replace' of undefined.
Кстати операции ">=" и "<=" для множеств тоже работают неправильно:
MODULE test;
IMPORT JS;
VAR s1, s2: SET;
BEGIN
s1 := {0..5};
s2 := {0..8};
IF s1 <= s2 THEN
JS.alert("TRUE")
ELSE
JS.alert("FALSE")
END
END test.
Программа пишет "FALSE" (должно быть "TRUE")
-
Обнаружил ошибку в сравнении целых
Спасибо! Буду фиксить :)
-
Начал проверку на корректность алгоритмов. Пока проверил код генерируемый компилятором vlad'a - он выдает корректный результат (то есть это Oberon-07/11). И проверил js-реализацию.
Планирую как минимум проверить следующие реализации: C#, C++, CB/BB (несколько), Oberon-07 (две под винду), возможно Lua-jit.
Oberon-2, F#, Ada, Delphi, Java, Fortran скорее всего окажутся пока за бортом - у меня просто на них времени и сил не хватит.
-
GPCP for .NET. Наивная реализация алгоритма. Ключи компиляции: /nodebug /nocheck (/nocheck убирает проверку целочисленного переполнение - это дает выигрыш в два раза, суммарно эти две опции дают выигрыш примерно в 10 раз).
Время работы: 171 секунда.
Для сравнения, примерно то же самое в ББ работает порядка 560 секунд.
Наивная реализация:
MODULE Blur;
IMPORT CPmain;
CONST
width = 640;
height = 480;
N = 13;
frames = 1000;
red = 0;
green = 1;
blue = 2;
TYPE
Frame = ARRAY width*height*(blue+1) OF SHORTCHAR;
PROCEDURE Index(x,y,color : INTEGER) : INTEGER;
BEGIN
RETURN ((x+y*width)*3+color)
END Index;
PROCEDURE Blur(IN in : Frame; OUT out : Frame);
VAR
x,y,c : INTEGER;
BEGIN
FOR y:=1 TO height-2 DO
FOR x:=1 TO width-2 DO
FOR c:=red TO blue DO
out[Index(x,y,c)] := SHORT(CHR( ( ORD(in[Index(x,y-1,c)]) + ORD(in[Index(x,y+1,c)]) +
ORD(in[Index(x-1,y,c)]) + ORD(in[Index(x+1,y,c)]) ) DIV 4 ));
END;
END;
END;
END Blur;
PROCEDURE Do*;
VAR
time : LONGINT;
f, n : INTEGER;
a1, a2 : POINTER TO Frame;
BEGIN
NEW(a1);
NEW(a2);
FOR f:=1 TO frames DO
FOR n:=1 TO N DO
Blur(a1,a2);
Blur(a2,a1)
END
END;
END Do;
BEGIN
Do;
END Blur.
-
В компиляторе vlad'а не реализованы встроенные процедуры-функции вроде ROR, ASR и так далее. Зарепортил: https://github.com/vladfolts/oberonjs/issues/4
-
Реализовал вариант на Джулии (http://julialang.org):
module Blur
export blur
const width = 640
const height = 480
const blur_range = 13
const RED = 0
const GREEN = 1
const BLUE = 2
function index(x::Int64,y::Int64, color::Int64)
return width*y*3 + x*3 + color + 1
end
function blur!(inp::Array{Uint8,1}, out::Array{Uint8,1})
for y = 1:height-2
for x = 1:width-2
@inbounds out[index(x,y,RED)] = (
inp[index(x,y-1,RED)] +
inp[index(x,y+1,RED)] +
inp[index(x-1,y,RED)] +
inp[index(x+1,y,RED)]) >> 2
@inbounds out[index(x,y,GREEN)] = (
inp[index(x,y-1,GREEN)] +
inp[index(x,y+1,GREEN)] +
inp[index(x-1,y,GREEN)] +
inp[index(x+1,y,GREEN)]) >> 2
@inbounds out[index(x,y,BLUE)] = (
inp[index(x,y-1,BLUE)] +
inp[index(x,y+1,BLUE)] +
inp[index(x-1,y,BLUE)] +
inp[index(x+1,y,BLUE)]) >> 2
end
end
end
function blur()
const frames = 1000
input = Array(Uint8, height*width*3)
output = Array(Uint8, height*width*3)
const blur_range = 13
for f = 1:frames
for i = 1:blur_range
blur!(input, output)
blur!(output, input)
end
end
end
end
Обратите внимание на макрос @inbounds - этот макрос отключает проверку выхода за краницы массива в данном конкретном statement'e. То есть в отличие от того же ББ, в котором можно отключить проверку границ только для всего модуля целиком, тут можно отключить только в одном, проверенном, выражении.
Результаты:
== With array bound checks ===
Julia:
time: 77 sec
fps : 13
== Without array bound checks ===
Julia:
time: 32 sec
fps : 31
А вообще, рекорд скорости у С++ и Ada приложений, если использовать свежий gcc - там используются simd-инструкции, и отрабатывает оно примерно за 17 секунд (а код С++ собранный MSVS 2012 отрабатывает за 60 секунд).
В Julia в принципе тоже есть экспериментальная поддержка SIMD, можно попробовать поиграться.
В общем и в целом скоростью и удобством Julia я удовлетворен.
PS. Напомню, что рекорд BB - это 77 секунд, с использованием SYSTEM и отключением проверки границ массивов.