Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Vectorize addition in map #4641

Merged
merged 21 commits into from
Apr 22, 2022
Merged

feat: Vectorize addition in map #4641

merged 21 commits into from
Apr 22, 2022

Conversation

Marwes
Copy link
Contributor

@Marwes Marwes commented Apr 5, 2022

Closes #4585

Based on #4636

@Marwes Marwes changed the title feat: Get vector addition working for integers feat: Get vector addition working Apr 5, 2022
@Marwes Marwes changed the title feat: Get vector addition working feat: Vectorize addition in map Apr 5, 2022
@Marwes Marwes force-pushed the refactor_vectorize_2 branch 3 times, most recently from c849921 to 9dba533 Compare April 6, 2022 15:07
@Marwes Marwes marked this pull request as ready for review April 6, 2022 15:48
@Marwes Marwes requested a review from a team as a code owner April 6, 2022 15:48
@Marwes Marwes requested review from rockstar and removed request for a team April 6, 2022 15:48
@Marwes Marwes marked this pull request as draft April 6, 2022 15:49
@Marwes Marwes removed the request for review from rockstar April 6, 2022 15:50
@Marwes Marwes marked this pull request as ready for review April 7, 2022 10:22
@Marwes Marwes requested a review from a team as a code owner April 7, 2022 10:22
@Marwes Marwes requested review from jstirnaman, a team and jsternberg and removed request for a team April 7, 2022 10:22
@Marwes Marwes force-pushed the refactor_vectorize_2 branch 4 times, most recently from 9bbe79d to 425ff1b Compare April 8, 2022 12:52
Copy link
Contributor

@jsternberg jsternberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some comments about how the memory allocator is passed through the compiler. I'd like to understand more the challenges around passing it through as I share the same concern that passing it through the context is non-ideal. After learning a bit more, I'll likely just change to approve if we can't determine a better way.

array/binary.gen.go Outdated Show resolved Hide resolved
array/binary.gen.go Outdated Show resolved Hide resolved

const runtimeDependenciesKey key = iota

type RuntimeDependencies struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is what you were mentioning but I can't remember what you said. Do you think we can change the compiler to take an extra parameter for the memory allocator? I'd generally prefer to change the function signature than to inject the memory allocator through the context.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd agree and I tried that, but that would force me to change every call into the evaluator to take that extra parameter (or rather, a new EvaluatorState struct which would make it easier to add new parameters/state later on). However even the interpreter ends up calling into the evaluator through some builtins so there are just far to much code that would be affected by such a change as part of this PR.

type EvaluatorState struct {
    ctx context.Context
   scope Scope
   mem memory.Allocator
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured you could have the compiler initialize it as an attribute. So binaryVectorEvaluator would be like:

type binaryVectorEvaluator struct {
    // other attributes
    mem memory.Allocator
}

It would then use that during evaluation. The compiler would initialize the evaluator with the memory allocator.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried that, but it doesn't really change anything as then the evaluator compiler needs access to the allocator and the only way to provide that is by storing it in the Context.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can do one of these two things:

  1. Add an extra parameter to the compile function to take in the allocator. Then change the call sites to include it. It looks like the JetBrains IDE can automate most of this.
  2. Change the compile function to be a method on a type and have that type include a reference to the memory allocator such as this:
type compiler struct {
    mem memory.Allocator
}

func (c *compiler) compile(...) (...) {
    c.mem.Allocate(...)
}

I think either of these two would be better than the context. The context is very error prone for this type of thing.

Copy link
Contributor Author

@Marwes Marwes Apr 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, and I have tried that but then I ran into callsites like this

f, err := compiler.Compile(compiler.ToScope(fn.Scope), fn.Fn, inputType)
where the only way to pass in the allocator is via the context again
func(ctx context.Context, args values.Object) (values.Value, error) {
.

So it doesn't fundamentally change anything, we still need to store the allocator in the context.

I do think we should refactor this such that we can pass the allocator (and any other state we might need) in a type safe way, however it would force changes throughout almost the entire go project since most functions that take a Context needs to be altered to pass a bespoke struct instead (though that struct would have a field holding the Context).

If we do want that refactor I can do that before or after this PR depending on what seems best.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I didn't realize that some functions needed access. Let me take a quick look again and then I can hit approve.

Copy link
Contributor

@jsternberg jsternberg Apr 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a look and if we're going to inject this into the context I think this isn't the proper location.

First, the dependency interface isn't really meant for this. It's much more straightforward to use the context directly and not with a struct and a name like RuntimeDependencies.

Second, we'll need to add this to the context in lang.Program probably. We need to make sure that the allocator is available in the context for both the interpreter and the compiler. The compiler generally gets run inside of the execution context inside of the executor, but the interpreter runs outside of that. Fortunately for us, they're close enough that they seem to use the same allocator.

func (p *AstProgram) Start(ctx context.Context, alloc *memory.Allocator) (flux.Query, error) {

It seems to me like we should add the logic inside of the memory package instead so that the interpreter, the compiler, and any functions that use it have easy access.

Generally, the Go standard for using context is like this:

type key int

const allocatorKey key = iota

func WithAllocator(ctx context.Context, mem Allocator) context.Context {
    return context.WithValue(ctx, allocatorKey, mem)
}

func GetAllocator(ctx context.Context) Allocator {
    mem, ok := ctx.Value(allocatorKey).(Allocator)
    if !ok {
        return DefaultAllocator
    }
    return mem
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I was sure I had added the allocator in Start but apparently I hadn't or I removed it for some reason...

/// Enables vectorization of addition expressions
VectorizeAddition,
/// Enables vectorization
VectorizedMap,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this just be named "Vectorize"? Since the rust code is agnostic for where it's vectorized.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, but the actual feature is called vectorizedMap so I felt it was better to be consistent with that.

@jstirnaman jstirnaman requested review from sanderson and removed request for jstirnaman April 12, 2022 14:36
Copy link
Contributor

@sanderson sanderson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good from the docs side 👍🏻

Markus Westerlind added 2 commits April 22, 2022 15:32
Not sure why this only occurred after I rebased :S
@Marwes Marwes merged commit 046acc1 into master Apr 22, 2022
@Marwes Marwes deleted the refactor_vectorize_2 branch April 22, 2022 19:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Pilot: vectorize one arithmetic operator
3 participants