I think ossi has explained the problem clearly, especially in post #7.
The problem is: something wakes up, every now and then, and disables interrupts for some amount of time.
The main question I have is: If you remove the Serial.print() call from the loop() function, does that still happen?
As indicated by Frank B, the systick interrupt, and the USB hardware, will cause interrupts, and especially USB may have some amount of latency involved.
Also, what is causing these interrupts? Are they pin interrupts, or timer interrupts, or some other form of interrupts? Interrupt priority may end up being a factor.
Clearly explained what is observed and demonstrated in the scope image - except for repro code to see what may be behind it.
systick and usb prints noted post #8 - prior to p#10 Frank B.
As far as observations here - without high USB SPEW rate - there is no other interference from any other interrupt.
Speculation involved ... Using own sketch evolving p#8 for other purpose - testing __STREXW for atomic update w/_isr() instead of interrupt Off/On the counts always work ... but no intense USB output that as noted in p#8 is possibly the issue - 'ASSUMING' what code may be running and printing as noted.
> from p#9 code when running - the counts per second in the _isr() are hitting 500K - even with two of then running at 500K - so none are being missed.
> added LEDs to this T_4.1 - and more code to _isr()'s to blink lights and using the __STREXW I can see when an interrupt fires during the retrieval of _isr() count values, but even when that happens both 2 us timers never miss a count
> worst (very rare in steady state 1 second print) case is one interval of a second measured in loop hits 499999 and the next interval then shows 500001.
>> Unless I purposefully put a delay in the loop code with a button press causing more code overhead and conditional LED blinks - but no more USB prints.
>> and those 'off' counts typically return when the button is released?
This shows the two timers mt and mtB hitting 500K, then with 'delay' button the loop code is interrupted and repeats 9 extra times per update on the second - oddly 9 extra counts are triggered on button press and the extras are removed on button release and steady state returns.
mt#=500000 with LoopCount=4059687 mtB#=500000
mt#=500005 with LoopCount=4013582 mtB#=500004 Extra STREX#=9
mt#=500000 with LoopCount=4004097 mtB#=500000 Extra STREX#=9
mt#=500000 with LoopCount=4061802 mtB#=500000 Extra STREX#=9
mt#=499995 with LoopCount=3999810 mtB#=499996
mt#=500000 with LoopCount=4060609 mtB#=500000
>> Even here no counts are missed - just shifted in accounting for them
Also in (re)finding the post #9 'lag' or overhead in T_4 timers - KurtE noted this Pull Request from January ::
github.com/PaulStoffregen/cores/pull/425
> it is possible it might improve the system and remove the signs of the problem ... but it has some merging needed now as written it seems ...
> Not sure how this affect 'evolving sketch' yet either