调度有问题
Having problems with scheduling
我试图降低侵蚀函数的执行时间,但当我尝试使用平铺划分问题时执行速度实际上更慢,如图所示:
我没有任何调度的代码是:
Halide::Image<uint8_t> erode(Halide::Image<uint8_t> input, int dimension) {
Halide::Var x("x"), y("y");
Halide::Image<uint8_t> output;
Halide::Func limit("limit"), e("e");
limit = Halide::BoundaryConditions::repeat_edge(input);
Halide::RDom r(dimension*-1 / 2, dimension, dimension*-1 / 2, dimension);
e(x, y) = limit(x, y);
e(x, y) = Halide::min(limit(x + r.x, y + r.y), e(x, y));
output = e.realize(input.width(), input.height());
return output;
}
我的代码进行了平铺尝试(我尝试使用教程中显示的示例):
Halide::Image<uint8_t> erodeTiling(Halide::Image<uint8_t> input, int dimension) {
Halide::Var x("x"), y("y"), x_outer, x_inner, y_outer, y_inner, tile_index;
Halide::Image<uint8_t> output;
Halide::Func limit("limit"), e("e");
limit = Halide::BoundaryConditions::repeat_edge(input);
Halide::RDom r(dimension*-1 / 2, dimension, dimension*-1 / 2, dimension);
e(x, y) = limit(x, y);
e(x, y) = Halide::min(limit(x + r.x, y + r.y), e(x, y));
e.tile(x, y, x_outer, y_outer, x_inner, y_inner, 64,64).fuse(x_outer, y_outer, tile_index).parallel(tile_index);
output = e.realize(input.width(), input.height());
return output;
}
任何关于如何正确安排时间的提示都将不胜感激,因为我对此还很陌生。
编辑:用于获取时间的代码:
__int64 ctr1 = 0, ctr2 = 0, freq = 0;
output = erode(input, dimension);
if (QueryPerformanceCounter((LARGE_INTEGER *)&ctr1) != 0) {
// Activity to be timed
output = erode(input, dimension);
QueryPerformanceCounter((LARGE_INTEGER *)&ctr2);
QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
}
std::cout << "\nerosion " << dimension << "x" << dimension << ":" << ((ctr2 - ctr1) *1.0 / freq) << "...";
ctr1 = 0, ctr2 = 0, freq = 0;
这里的一个大问题是每次要腐蚀图像时都需要重新编译成像管道。如果你使用一个ImageParam作为输入,一个Param作为维度,你可以只编译一次然后在不同的图像上多次实现它。
撇开这一点,调度是在 Func 的每个阶段独立完成的。您的 Func 有两个阶段(以 "e(x, y) =" 开头的每一行都是一个阶段),并且您只安排第一个(便宜的)阶段。尝试这样的事情以相同的方式安排初始化和更新:
e.tile(x, y, x_outer, y_outer, x_inner, y_inner, 64,64).fuse(x_outer, y_outer, tile_index).parallel(tile_index);
e.update(0).tile(x, y, x_outer, y_outer, x_inner, y_inner, 64,64).fuse(x_outer, y_outer, tile_index).parallel(tile_index);
如果维度 > 3,您可能需要一个可分离的最小过滤器。我会这样写:
Func minx, miny;
miny(x, y) = minimum(limit(x, y+r));
minx(x, y) = minimum(miny(x+r, y));
minx.parallel(y, 4).vectorize(x, 32);
miny.compute_at(minx, y).vectorize(x, 32);
我试图降低侵蚀函数的执行时间,但当我尝试使用平铺划分问题时执行速度实际上更慢,如图所示:
我没有任何调度的代码是:
Halide::Image<uint8_t> erode(Halide::Image<uint8_t> input, int dimension) {
Halide::Var x("x"), y("y");
Halide::Image<uint8_t> output;
Halide::Func limit("limit"), e("e");
limit = Halide::BoundaryConditions::repeat_edge(input);
Halide::RDom r(dimension*-1 / 2, dimension, dimension*-1 / 2, dimension);
e(x, y) = limit(x, y);
e(x, y) = Halide::min(limit(x + r.x, y + r.y), e(x, y));
output = e.realize(input.width(), input.height());
return output;
}
我的代码进行了平铺尝试(我尝试使用教程中显示的示例):
Halide::Image<uint8_t> erodeTiling(Halide::Image<uint8_t> input, int dimension) {
Halide::Var x("x"), y("y"), x_outer, x_inner, y_outer, y_inner, tile_index;
Halide::Image<uint8_t> output;
Halide::Func limit("limit"), e("e");
limit = Halide::BoundaryConditions::repeat_edge(input);
Halide::RDom r(dimension*-1 / 2, dimension, dimension*-1 / 2, dimension);
e(x, y) = limit(x, y);
e(x, y) = Halide::min(limit(x + r.x, y + r.y), e(x, y));
e.tile(x, y, x_outer, y_outer, x_inner, y_inner, 64,64).fuse(x_outer, y_outer, tile_index).parallel(tile_index);
output = e.realize(input.width(), input.height());
return output;
}
任何关于如何正确安排时间的提示都将不胜感激,因为我对此还很陌生。
编辑:用于获取时间的代码:
__int64 ctr1 = 0, ctr2 = 0, freq = 0;
output = erode(input, dimension);
if (QueryPerformanceCounter((LARGE_INTEGER *)&ctr1) != 0) {
// Activity to be timed
output = erode(input, dimension);
QueryPerformanceCounter((LARGE_INTEGER *)&ctr2);
QueryPerformanceFrequency((LARGE_INTEGER *)&freq);
}
std::cout << "\nerosion " << dimension << "x" << dimension << ":" << ((ctr2 - ctr1) *1.0 / freq) << "...";
ctr1 = 0, ctr2 = 0, freq = 0;
这里的一个大问题是每次要腐蚀图像时都需要重新编译成像管道。如果你使用一个ImageParam作为输入,一个Param作为维度,你可以只编译一次然后在不同的图像上多次实现它。
撇开这一点,调度是在 Func 的每个阶段独立完成的。您的 Func 有两个阶段(以 "e(x, y) =" 开头的每一行都是一个阶段),并且您只安排第一个(便宜的)阶段。尝试这样的事情以相同的方式安排初始化和更新:
e.tile(x, y, x_outer, y_outer, x_inner, y_inner, 64,64).fuse(x_outer, y_outer, tile_index).parallel(tile_index);
e.update(0).tile(x, y, x_outer, y_outer, x_inner, y_inner, 64,64).fuse(x_outer, y_outer, tile_index).parallel(tile_index);
如果维度 > 3,您可能需要一个可分离的最小过滤器。我会这样写:
Func minx, miny;
miny(x, y) = minimum(limit(x, y+r));
minx(x, y) = minimum(miny(x+r, y));
minx.parallel(y, 4).vectorize(x, 32);
miny.compute_at(minx, y).vectorize(x, 32);