tick-sched: Set last_tick correctly so that timer interrupts happen less

TODO: make this only if the tick_nohz_handler() arrived late, not early.
Some broken hardware may make it arrive earlier.

If there are delays in timer interrupts, or other reasons, we can have
tick_nohz_handler() called in quick succession. This seems useless for
low res, and can momentarily make things appear to be high res.

When the tick is active, a delay in a timer interrupt does not mean the
next tick will also be similarly delayed. This seems counter-intuitive
when we are low res. We want the ticks to be spaced out by at least
TICK_NSEC, not less. So fix that.

Also for stop code,  consider the following scenario in low res mode:

1. Assume ts->last_tick is 8.5ms.

2. The CPU exits from idle for some reason, and the tick is restarted.
   During this restart, it is determined in tick_nohz_restart() that the
   next tick should happen at 9.5ms (HZ=1000). This is programmed to the
   clock event (and also recorded into the hrtimer).

3. Just after step 2, the CPU tries to stop the tick while entering idle.
   During this, there is a call to tick_nohz_next_event() which sets
   ts->timer_expires to 10ms due to rounding to TICK_NSEC.

4. Just after this, tick_nohz_stop_tick() is called which sets
   ts->last_tick to 9.5ms (the value recorded in #2 into the hrtimer)
   and the clock event device is set to the 10ms due to ts->timer_expires.

5. Now the timer interrupt goes off at 10ms, tick_nohz_restart() is
   called again, and it programs the clock event to go off at the
   ts->last_tick + TICKNSEC which is 10.5ms.

6. Now the timer interrupt goes off at 10.5ms.

The end result is, we have 2 timer interrupts that went off at a
granularity of less than 1ms which causes timer wheel and hrtimers to
have higher res than they otherwise would.

Fix by setting ts->last_tick in #5 to now, which is really when the last
tick happened. This correct makes tick_nohz_restart() consider the most
recent time that the tick timer fired.

I see a similar issue where tick_nohz_handler() could also program the
next timer event too quickly. For this reason, also set the tick-sched
hrtimer in tick_nohz_handler() to now.

With this, I don't see tick_nohz_handler() firing in quick succession.

Signed-off-by: Joel Fernandes (Google) <joel@joelfernandes.org>
1 file changed