Pretty much all the standard performance advice from other languages like C/C++/Rust applies. The concepts driving "data oriented design" will get you a long way. The biggest difference is learning how to play nice with the GC- avoiding allocations where necessary, keeping the heap simple so that collections are cheap, or just setting things up so the GC never has to run.
Some of the implementation details (like the operator codegen) are surprisingly outdated now given the speed at which the runtime has moved (and the library is now ~4x faster or something silly like that), but the fundamentals are still there.
Since I wrote that, codegen has improved a lot, the hardware intrinsic vector APIs have offered a way to optimize critical codepaths further, additional cross platform vectorization helpers have made it even easier, NativeAOT is getting close, and all sorts of other stuff. The C# discord #allow-unsafe-blocks channel contains a variety of denizens who might be able to offer more resources.
Thanks! That link especially contains some really helpful write-ups.
I never really needed to think much about performance, as my C# usage always was constrained to simple CRUD stuff in server backends, which is a shame really, as it is such a nice language.