Concrete types in a function signature also work as assertions, so it's one way to force the compiler's hand this way. In many cases it's better to assert the arguments, rather than the parameters, to keep the method itself generic. The main reason to add types to a method is to allow multiple dispatch to pick that method of the function for values of the specified type.
The slow function I added the types to didn't really make any sense to be really generic. For nearly all the arguments (of which there was like 20), there was only one type that made any sense for each. I don't think keeping it more generic would have bought me much, and adding types worked as an assertion that made things much faster.
But yes, once I started adding types to thing, I did start utilizing multiple dispatch, since I've always been a bit fan of Clojure-style multimethods and this got me something more or less comparable to it.
No they do not, this is not how it works. Functions auto-specialize on the types they see and do a multiple dispatch behind the scenes on these specializations. Type parameters in a function signature thus only define what specializations are allowed. See https://book.sciml.ai/notes/02-Optimizing_Serial_Code/ for details. As such, you don't need to add any types to a function signature to get performance.
I didn't do a control test to figure out exactly why, but I think it was having some issue with a parsed CSV being read as a matrix. I think explicitly putting that requirement into the function signature allowed for a lot of low-level optimizations to be used that it couldn't use before.
I'm not 100% sure though; basically when I was getting some performance bottlenecks I did some preliminary searching and some of the results said "try adding types to your function signatures", and I really couldn't think of a good reason not to add them for most of the variables, and so I did and it worked.