Just so you know, the entire UnityEngine.UI system is available in source control from the package manager (and from github) and you can look at it and probably see there isn’t going to be a lot of fat.
If there are some particular specific widgets you use in there that are too slow because of the use-generalization assumptions made, you might be able to get some benefit by tweaking them, but since so much of mobile performance bumps against pixel fill bounds, it’s unlikely to get you much benefit.
Instead, if you have a massively-complex UI, the time-honored way of breaking it into the static and the dynamic parts and placing those in different hierarchies is likely to give you the best improvements, at least based on the number of times I have optimized UI this way.
Look to optimize drawcalls this way too, as well as reducing transform updates. Use the Frame Debugger to see what all gets drawn each call, and that can give you some great insight into how to batch big chunks of identical draws into a single pass. Obviously good sprite packing helps a lot here too. In my experience the general Unity sprite packer can get you about 80-90% of the way, and for any more you need to hand-pack your sprites, probably using a third-party tool.
And of course, get your pixel overdraw down down down. Use the overdraw view in the Scene to see what your major offenders are. Often with a big UI you’ll have several near-full-screen pieces that can either go away or get baked down into a pre-made background for huge wins.
Here is a starting point: