A macro that checks code vectorization with potential false positives and negatives - ready for PR

I made a macro that checks if some code is vectorized or not, by getting the LLVM code and checking if “vector.body” is there or not, and then it actually runs the code. Here it is:

macro vec_check(expr)
	f = gensym()
	llvm = gensym()
	io = gensym()
	vec = gensym()

	return esc(quote
		function $f()
			$expr
		end
		$io = IOBuffer()
		code_llvm($io, $f, ())
		$llvm = String(take!($io))
		$vec = all(contains.($llvm, ("\nvector.body:", "\nvector.ph:")))
		if $vec
			println("Vectorized")
		else
			println("Not vectorized")
		end
		$expr
	end) 
end

This is useful when you have a big algorithm and you want to check if each loop which you are trying to vectorize is really vectorized or not. Example:

julia> @vec_check begin
           n = 100000; a = rand(n); @inbounds @simd for i in 1:n
               a[i] = 1
           end
           a;
       end;
Vectorized

julia> @vec_check begin
           n = 100000; a = rand(n); @simd for i in 1:n
               a[i] = 1
           end
           a;
       end;
Not vectorized

Is this a welcome PR, and if so to which package, Base?

This may be useful, but it is not transparent in this form because it prints something. Instead of a macro, it could be formulated as an inspection tool, eg like @code_warntype: not something I would build into code, but a tool I would call on code for inspection and analysis.

Hmm, it is for inspection yes. By transparent I meant that I can run the same testing code with the macro there or without it, because it is still running the actual code. This is different from @code_warntype for example which does not run the code, it only inspects it so I have to copy the code over or something if I want to use a global test case for inspecting a small function inside the code. Printing is the only way I can “return” some useful information to the inspector without disrupting the flow or structure of the rest of the code. Do you think this can be done better in any other way?

I am currently using it to vectorize MMA.jl which has many loops inside that can be vectorized, but it is hard to check each one individually without this macro.

This sounds useful to me, to understand what’s going on (alongside benchmarking).

But when I paste these examples into Julia I get Not vectorized for both.

This is not transparent at all. It changes the scope of the code and greately affect what optimization is possible on the code so it won’t tell you the real answer. Looking for vector.body is also pretty unreliable but that’s another issue…

You can just add the @code_llvm in the code you run.

Weird, which version of Julia is yours, I tested it in v0.6.2 in Windows and Linux.

Hmm, if I understand correctly, are you saying that the code could be really vectorized inline but when I wrap it in a function and call code_llvm it changes the scope and may therefore tell me it is not vectorized when it is, i.e. false negative? But then at least if I get the “vector.body” pieces in the LLVM code then the code is definitely vectorized? That is the probability of a false positive result is pretty slim, but non-zero because the string “\nvector.body:” could be sitting in the code for some other reason which for my use cases is very unlikely.

I can’t, because it expects a function, it won’t just wrap a loop and it doesn’t run the code so I have to have the code inside the function and then outside which is what the macro above is doing. Am I missing something?

No, it can go either way.

No.

It’s not at all the issue. vector.body label could be there without vectorization.

Yes. If the code is not in a function, you are doing something wrong to begin with. If it is in a function, then just check on that function instead.

Interesting, is there a better way to check if the code in a function is vectorized or not though?

The code is obviously in a function but the function is big and has a few loops following each other doing their own things, and separating them into sub-functions just doesn’t make much sense in my use cases, so I was looking for a quick and dirty way to analyze individual loops in a big function without having to put each loop in its own function in the original code.

I usually check for vector instructions that I expect in a loop. I don’t think that’s something you can easily compute from the texture form.

Well, as a fact, your macro will affect what the optimizer can actually do so you shouldn’t call it “transparent”. If you really don’t want to split up your huge function, which I usually find to be a much better solution, you can certainly use this while keeping in mind that you can have both false positives and negatives.

1 Like

Changed the title accordingly.