input buffer of type Halide::Runtime::Buffer gets modified by generator - halide

I have a generator that has input and output:
Input<Buffer<uint8_t>> input{"input", 2};
Output<Buffer<uint8_t>> output{"output", 2};
In generate method I defined following algorithm:
output(c,x) = Halide::cast<uint8_t> (input(mux(c, {1,0,2,3,0,2}), x));
The problem is that when I pass input and output buffer from main program I get the desired output but input buffer gets also modified which I would like to avoid. I tried to make function and then apply algorithm but I have same effect:
Func decode;
Func in;
in(c,x) = input(c,x);
decode(c,x) = Halide::cast<uint8_t> (in(mux(c, {1,0,2,3,0,2}), x));
output(c,x) = decode(c,x);
...
I also tried to create copy of input buffer from Input<Buffer<uint8_t>> input{"input", 2} like:
in(c,x) = input(c,x);
Halide::Buffer<uint8_t> in_copy = in.realize({Halide::Internal::as_const_int(input.dim(0).extent()), Halide::Internal::as_const_int(input.dim(1).extent())});
but this results in Unhandled exception: Error: Buffer argument input is nullptr which is understandable. Do You have any suggestion how to avoid input buffer mutation?
#Alex asked to post compile-able generator so here is a version with using the functions
#include "Halide.h"
using namespace Halide;
class Yuv422Decoder : public Halide::Generator<Yuv422Decoder> {
public:
Input<Buffer<uint8_t>> input{"input", 2};
Output<Buffer<uint8_t>> output{"output", 2};
Var c,x,xo,xi,co,ci;
void generate() {
Func decode;
Func in;
in(c,x) = input(c,x);
// define algorithm
decode(c,x) = Halide::cast<uint8_t> (in(mux(c, {1,0,2,3,0,2}), x));
output(c,x) = decode(c,x);
}
void schedule() {
output.bound_extent(c,6);
output.split(x, xo, xi, input.dim(1).extent()/8);
output.parallel(xo,2);
output.parallel(xi,2);
output.unroll(c);
output.vectorize(xi,128);
}
};
// Use this macro to create function that you can call in your program
HALIDE_REGISTER_GENERATOR(Yuv422Decoder, yuv422decoder);

Problem was in size of the output buffer. I doubled it and now I don't have mutation of input buffer. I am not sure how exactly this happens when size of the output buffer is too small but anyhow it was programming mistake in the end.
uint8_t* buffer_out = new uint8_t [2*size];
Runtime::Buffer<uint8_t> out(buffer_out, {{0,6,1}, {0,size/4,6}});

Related

Invalid use of int and no static main entry

It says there is no suitable entry point for the program as well as invalid expression of int when attempting to use the printMenu method. My instructions specify that I need to initialize the array and menu in the main and utilize the 5 methods in a switch statement but I am tripping over the Main method. I am unable to understand how to reference an (int[] args) with a string. I was able to do it just fine with a switch statement but since moving onto methods I have struggled understanding how to reference properly and would appreciate any tops or fixes on how to adjust.
public static void Main(string[] args)
{
int[] initArray = new int[10];
Console.Write("Would you like to: \n1) Enter a number\n2)Print the array \n3)find the sum of the array\n4)Reset the array\n5)Quit\n");
int input = Convert.ToInt32(Console.ReadLine());
printMenu(int[input]);
}
public void printMenu(int[] args)
{
Console.Write("Would you like to: \n1) Enter a number\n2)Print the array \n3)find the sum of the array\n4)Reset the array\n5)Quit\n");
int input = Convert.ToInt32(Console.ReadLine());
do
{
switch (input)
{
case 1:
enterNum(args);
break;
}
} while (input < 5);
}
You can call the printMenu method like this:
printMenu(new int[]{ input });
If you have a second input you would do:
printMenu(new int[]{ input, input2 });
Using an array of integers is only logical when you want to pass in multiple integers. When you are never going to pass in more than 1 ints I suggest changing the signature of printMenu to ask for just one integer: printMenu(int arg) and just pass in the one input.
printMenu(input);

append's return value in Go

After reading this article, I have some question in mind.
Basically, why we need to store the return value of append() in Go? How is the function actually implemented?
I have tried to replicate (sort of) the mechanism of append in C (which is the first language used to implements the Go language, if I'm not mistaken). I used malloc(), instead of an array as it will not deallocate the slice after the function returns.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
typedef struct SliceHeader {
int length;
int capacity;
int *zerothElement;
} SliceHeader;
void append(SliceHeader *sh, int element)
{
if (sh->length == sh->capacity) {
// grow capacity size
sh->capacity += 10;
realloc(sh->zerothElement, sh->capacity);
}
sh->zerothElement[sh->length] = element;
sh->length++;
}
SliceHeader * make(int capacity)
{
SliceHeader *sh = (SliceHeader *) malloc(sizeof(sh));
sh->length = 0;
sh->capacity = capacity;
sh->zerothElement = (int *) malloc(capacity * sizeof(int));
return sh;
}
int main()
{
SliceHeader *sh = make(3);
append(sh, 5);
append(sh, 10);
append(sh, 15);
append(sh, 20); // exceed the original capacity, should reallocate
for (int i = 0; i < sh->length; i++) {
printf("%d\n", *((sh->zerothElement)+i) );
}
free(sh->zerothElement);
free(sh);
return 0;
}
(I omit NULLs checking to show only the relevant part to the main question).
If I'm using this code, I can use append() without the need to store its return value and no needs to create a new slice header.
So how is the implementation of append() function in Golang that makes it needs to store a new slice header? Even if the zerothElement uses an array, doesn't it means that it will need to change the array only instead of the whole slice header?
What am I missing here?
Thanks :)
Basically, why we need to store the return value of append() in Go?
You only need to store this value if you intend to use the slice with the appended value.
How is the function actually implemented?
Go is open source, just consult the source code. (Btw: This is uninteresting.)

How do I Read and Write to an image with uint format?

I want to read and write from an image that stores unsigned integers. How can I read and write? The standard way to read and write to an image is using imageLoad/imageStore, but when using the format qualifier r32ui, the compiler errors with no matching overloaded function found.
This fails to compile:
#version 450
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(set = 0, binding = 0, r32ui) uniform writeonly uimage3D img;
void main() {
imageStore(img, ivec3(1,2,3), uint(4));
}
This compiles fine:
#version 450
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
layout(set = 0, binding = 0, rgba8ui) uniform writeonly uimage3D img;
void main() {
imageStore(img, ivec3(1,2,3), uvec4(4,5,6,7));
}
I have tried using uvec3 for coordinates instead of ivec3, and uvec4 for the data to write in case I am misunderstanding what the format is storing. Using 2 dimensional images also made no difference.
The error message you get is correct, there simply is no overloaded version of imageStore that takes a single unsigned integer (see specs).
So when using the r32ui qualifier, you still need to pass a 4-component unsigned vector just like in your second example, but instead construct it from a single value:
void main()
{
imageStore(img, ivec3(1,2,3), uvec4(4));
}

replace existing object on the stack with default constructed one

I would like to know the best/correct way to get back to the initial values of an object without playing with delete and new (everything must stay on the stack)
With this 2 classes:
static const int defaultValue{15};
class Foo
{
private:
int val1{defaultValue};
short val2{4};
}
class LongStandingObject
{
public:
void resetFoo(int index);
private:
Foo foos[100];
}
If I need to reset some foos to their default values, what is the best way?
Create reset method in Foo
void Foo::reset()
{
val1 = defaultValue;
val2 = 4;
}
I don't really like the idea to have the values coming from 2 differents places and I do like to have the defaults values in the header next to the variable declaration.
Replace by a locally created Foo
void LongStandingObject::resetFoo(int index)
{
foos[index] = Foo();
}
Am I heading to trouble when the local variable is destroyed?
Use memcpy
void LongStandingObject::resetFoo(int index)
{
Foo foo;
memcpy(foos[index], &foo, sizeof(Foo));
}
Maybe less readable...
Any other method?
Your #2 is just fine, and probably the most legible.
void LongStandingObject::resetFoo(int index)
{
foos[index] = Foo();
}
There are no object lifetime issues here: the assignment operator is called on foos[index] to change its values to match the temporary object materialized from Foo(). That is, the code is exactly equivalent to
{
Foo tmp;
foos[index].val1 = tmp.val1;
foos[index].val2 = tmp.val2;
}
And if optimizations are enabled, almost any compiler will be able to just modify foos[index] directly without actually creating the temporary Foo.
If you do want a Foo::reset() function as well, you can use the same idea for it:
void Foo::reset()
{
*this = Foo();
}
I would avoid using memcpy, since the program would become incorrect if you ever make changes to Foo that make it no longer trivially copyable.
What you can do is to use std::pair on each variable. Initialized with with variable.first = variable.second = value. After, every time you want to update the variable you set: variable.second = new_value. When you want to restore to the original, you set: variable.second = variable.first. You can improve it by writing a macro RestoreDefault(var) to make the code more readable.
For example:
#define RestoreDefault(var) ((var).second = (var).first)
// int val1{180}; // Instead of this line
std::pair<int,int> val1{ 180,180}; // <- this line
val1.second = 456;
RestoreDefault(val1);
If you want to hardcoded block any possibility to re-set later the default value, write:
std::pair<const int,int> val1{ 180,180}; // <- this line
-
Addition: Same principle for array:
class Foo
{
public:
int x = 100;
int y = 200;
};
#define RestoreArrDefault(var) ((var).second.fill((var).first))
// Use:
std::pair<Foo, std::array<Foo, 100>> FooAr, FooAr2;
// You can define different arrays with different defaults:
FooAr.first = { 180,360 }; // <- Customize FooAr defaults
// In that point FooAr default is 180,360 and FooAr2 default is 100,200
FooAr.second[3] = { 2,10 }; // <- Edit FooAr index-3 item
RestoreArrDefault(FooAr); // <- Restore Default

Can generators be used for JIT during development?

What is the best strategy for development in HALIDE?
The end usage will be Ahead of time compiled using generators.
Is there a way to invoke the functions defined in generator for JIT?
Thanks
Yes, Generators work just fine with JIT code.
In general, Generators are the preferred way to encapsulate individual chunk of Halide for reuse. Until recently, they were a bit awkward to use in JIT mode, but recent changes that added machine-generated Stubs greatly simplify that and make using Generators in either JIT or AOT pretty simple.
Unforunately, Generator Stubs are new enough that they aren't represented in the Tutorial yet; your best bet is to look at the self-tests in tests/generator for examples (specifically, example_jittest.cpp and stubtest_jittest.cpp).
As an overview: The basic idea of a Generator Stub is that it's a machine-generated C++ class that is created based on the Generator's public description. It doesn't do anything that you couldn't do yourself directly, but it does make Generator usage much terser, simpler, and less error-prone.
To produce a a Generator stub, just modify you your Makefile to add cpp_stub to the Generator's -e commandline flag , e.g.
./example.generator -n Example -o ./bin -e cpp_stub
This will emit a C++ source file file named example.stub.h; inside this file you'll find a C++ class that looks something like this:
class Example : public Halide::Internal::GeneratorStub {
public:
struct Inputs {
// One field per input to the Generator;
// Buffer inputs will be Halide::Funcs,
// all other (scalar) inputs will be HalideExprs
};
struct GeneratorParams {
// One field per GeneratorParam in the Generator
};
struct ScheduleParams {
// One field per GeneratorParam in the Generator
};
Example();
Example(
const GeneratorContext* context,
const Inputs& inputs,
const GeneratorParams& params = GeneratorParams()
);
void schedule(const ScheduleParams& params = ScheduleParams());
// Output(s)
Func output;
// If the Generator has multiple Outputs, they will be here too
};
You can use this Stub inside JIT code as though it were a helper function (well, mostly):
#include "example.stub.h"
Example::Inputs inputs = { ... };
auto gen = Example(context, inputs);
gen.schedule();
Halide::Buffer<int32_t> img = gen.realize(kSize, kSize, 3);
Under the hood, the Stub is constructing an instance of your Generator, filling in the Input parameters (based on the Inputs struct you give it), calling the generate() method to produce the Output Funcs, and returning them to you.
Stub usage is woefully underdocumented as I type this; I've just opened an issue to gather up the documentation and examples we have into something that is more helpful to general Halide users.
Define your Halide code in an isolated function that takes Expr and Func parameters and returns a Func. Alternatively, you can pass an output Func parameter:
In thing.h
Func thing1( Func input, Expr param1, Expr param2 );
void thing2( Func input, Expr param1, Expr param2, Func output );
In thing.cpp
Func thing1( Func input, Expr param1, Expr param2 )
{
Var x("x"), y("y");
Func output("output");
output( x, y ) = input( x, y ) * param1 + param2;
return output;
}
void thing2( Func input, Expr param1, Expr param2, Func output )
{
Var x("x"), y("y");
output( x, y ) = input( x, y ) * param1 + param2;
}
Now you can include thing.h from both your AOT generator and JIT test.

Resources