On x64, does each PUSH instruction push a multiple of 8 bytes? If not, how much does it push?
Also, how much stack space does each function parameter consume?
No, but in practice, one always pushes an 8 byte value onto the stack.
Function parameters consuming varying amounts of stack space depending on the size of the function parameter and whether it is passed in the stack, in the registers, or passed by reference.
If one passes a function parameter in the stack by pushing, then the fact that there are convenient push instructions that pushes 8 bytes strongly suggests that you pass the parameter as an 8 byte value. For pointers, int64 and plain doubles, this is obviously easy. For char, bool, short, and other types whose memory size is smaller, what most compilers do is push the value in an 8 byte chunk. Types that take 16 or 32 bytes might be pushed by the compiler with several push instructions. Bigger values tend not to get passed by pushing; often a compiler tries to pass a pointer to a bigger value rather than pass the value itself. {I've built a compiler that can pass arbitrarily big values, but it does so by making space in the stack, and then executing a block move instruction]. Details vary from compiler to compiler, and according to the language semantics of the program being compiled.
A really clever compiler might notice that several arguments are small and can be packed into an 8 byte quantity that only requires a single push. I've not seen one actually do that, probably because it takes work to pack such values together into a register, and push instructions are already pretty fast by design and by cache.
It is possible to push smaller values onto the stack. This is legal according to the architecture, but is likely to cause a mis-aligned access performance hit if the set of small values pushed isn't a multiple of 8 bytes. And then one must be careful to pop off the non-multiple correctly to restore stack alignment. Not useful in my experience (see code golf comment by Peter Cordes).
If you pass the value in a register, nothing gets pushed :-}
One might arrange to store parameter values in a well known locations in the stack. Then there isn't any push :-}