I've knocked up a bit of a debug version here: https://github.com/leehuk/misc/raw/main/TrainNetworkForPlayers_0.12.99.zip . It uses the inbuilt profiler to spam factorio-current.log with profiling timings for each of the events that gets fired. Its not something you'd want to run for very long, but I'd be interested to see the numbers if you get chance for some brief testing. I can work without it like, its just whether there's something SE specific going on.
Looking at the numbers from my SP K2 save its fine ups-wise dealing with "background" events, its the train dispatching (~54ms) and the stationselect gui drawing (~125ms) that hurt. I suspect the lag you're seeing is around that stationselect gui, though I'm not exactly sure how guis work in MP.
Easiest way to test it is to walk to a tnfp train waiting at its normal station, board it and then hit the tnfp request button -- it'll shortcut straight into the gui without going through any dispatching logic and should in theory trigger the worst of the lag spikes. If it does and you wait for the lag to clear and then select a destination, it should be pretty stable for the journey.
Fixing the stationselect code could be an interesting challenge though, this K2 save spends 67ms waiting for player.surface.find_entities_filtered({type = "train-stop"}) to get a list of train stops and that part is sort of unavoidable, but well over the 16ms for everything per-tick. There's another ~56ms drawing the station buttons within the three tabs, but I can drop that to ~2ms by hacking out the 'All' tab and it might be possible to do proper lazyloading there.
Certainly some things to go at.. none of them as easy as the circuit fix though, so I'll have to see when I get some more time.