[dm-devel] [PATCH 2/4] dm stats: support precise timestamps
Mike Snitzer
snitzer at redhat.com
Wed Jun 10 17:40:52 UTC 2015
On Wed, Jun 10 2015 at 1:33pm -0400,
Mikulas Patocka <mpatocka at redhat.com> wrote:
>
>
> On Wed, 10 Jun 2015, Mike Snitzer wrote:
>
> > On Tue, Jun 09 2015 at 5:21pm -0400,
> > Mikulas Patocka <mpatocka at redhat.com> wrote:
> >
> > > This patch makes it possible to use precise timestamps with nanosecond
> > > granularity in dm statistics.
> > >
> > > Signed-off-by: Mikulas Patocka <mpatocka at redhat.com>
> > >
> > > ---
> > > Documentation/device-mapper/statistics.txt | 25 ++++-
> > > drivers/md/dm-stats.c | 139 +++++++++++++++++++++--------
> > > drivers/md/dm-stats.h | 4
> > > 3 files changed, 125 insertions(+), 43 deletions(-)
> > >
> > > Index: linux-4.1-rc7/drivers/md/dm-stats.c
> > > ===================================================================
> > > --- linux-4.1-rc7.orig/drivers/md/dm-stats.c 2015-06-08 16:02:27.000000000 +0200
> > > +++ linux-4.1-rc7/drivers/md/dm-stats.c 2015-06-08 16:38:43.000000000 +0200
> > > @@ -33,13 +33,14 @@ struct dm_stat_percpu {
> > >
> > > struct dm_stat_shared {
> > > atomic_t in_flight[2];
> > > - unsigned long stamp;
> > > + unsigned long long stamp;
> > > struct dm_stat_percpu tmp;
> > > };
> > >
> > > struct dm_stat {
> > > struct list_head list_entry;
> > > int id;
> > > + unsigned stat_flags;
> > > size_t n_entries;
> > > sector_t start;
> > > sector_t end;
> > > @@ -53,6 +54,8 @@ struct dm_stat {
> > > struct dm_stat_shared stat_shared[0];
> > > };
> > >
> > > +#define STAT_PRECISE_TIMESTAMPS 1
> > > +
> > > struct dm_stats_last_position {
> > > sector_t last_sector;
> > > unsigned last_rw;
> > > @@ -227,7 +230,8 @@ void dm_stats_cleanup(struct dm_stats *s
> > > }
> > >
> > > static int dm_stats_create(struct dm_stats *stats, sector_t start, sector_t end,
> > > - sector_t step, const char *program_id, const char *aux_data,
> > > + sector_t step, unsigned stat_flags,
> > > + const char *program_id, const char *aux_data,
> > > void (*suspend_callback)(struct mapped_device *),
> > > void (*resume_callback)(struct mapped_device *),
> > > struct mapped_device *md)
> > > @@ -268,6 +272,7 @@ static int dm_stats_create(struct dm_sta
> > > if (!s)
> > > return -ENOMEM;
> > >
> > > + s->stat_flags = stat_flags;
> > > s->n_entries = n_entries;
> > > s->start = start;
> > > s->end = end;
> > > @@ -417,15 +422,22 @@ static int dm_stats_list(struct dm_stats
> > > return 1;
> > > }
> > >
> > > -static void dm_stat_round(struct dm_stat_shared *shared, struct dm_stat_percpu *p)
> > > +static void dm_stat_round(struct dm_stat *s, struct dm_stat_shared *shared,
> > > + struct dm_stat_percpu *p)
> > > {
> > > /*
> > > * This is racy, but so is part_round_stats_single.
> > > */
> > > - unsigned long now = jiffies;
> > > - unsigned in_flight_read;
> > > - unsigned in_flight_write;
> > > - unsigned long difference = now - shared->stamp;
> > > + unsigned long long now, difference;
> > > + unsigned in_flight_read, in_flight_write;
> > > +
> > > + if (likely(!(s->stat_flags & STAT_PRECISE_TIMESTAMPS))) {
> > > + now = jiffies;
> > > + } else {
> > > + now = ktime_to_ns(ktime_get());
> > > + }
> > > +
> > > + difference = now - shared->stamp;
> > >
> > > if (!difference)
> > > return;
> >
> > Here 'difference' is in nanosecond resolution if STAT_PRECISE_TIMESTAMPS
>
> Yes.
>
> > > @@ -646,11 +673,15 @@ static int dm_stats_clear(struct dm_stat
> > > /*
> > > * This is like jiffies_to_msec, but works for 64-bit values.
> > > */
> > > -static unsigned long long dm_jiffies_to_msec64(unsigned long long j)
> > > +static unsigned long long dm_jiffies_to_msec64(struct dm_stat *s, unsigned long long j)
> > > {
> > > - unsigned long long result = 0;
> > > + unsigned long long result;
> > > unsigned mult;
> > >
> > > + if (s->stat_flags & STAT_PRECISE_TIMESTAMPS)
> > > + return j;
> > > +
> > > + result = 0;
> > > if (j)
> > > result = jiffies_to_msecs(j & 0x3fffff);
> > > if (j >= 1 << 22) {
> >
> > Yet here you aren't converting ns to ms...
>
> That function is converting jiffies to ms. When STAT_PRECISE_TIMESTAMPS is
> not set, the internal times are kept in jiffies and they are converted to
> ms when being printed. When STAT_PRECISE_TIMESTAMPS is set, the internal
> times are kept in ns and no conversion is done when they are printed.
>
> > > @@ -712,16 +743,16 @@ static int dm_stats_print(struct dm_stat
> > > shared->tmp.ios[READ],
> > > shared->tmp.merges[READ],
> > > shared->tmp.sectors[READ],
> > > - dm_jiffies_to_msec64(shared->tmp.ticks[READ]),
> > > + dm_jiffies_to_msec64(s, shared->tmp.ticks[READ]),
> > > shared->tmp.ios[WRITE],
> > > shared->tmp.merges[WRITE],
> > > shared->tmp.sectors[WRITE],
> > > - dm_jiffies_to_msec64(shared->tmp.ticks[WRITE]),
> > > + dm_jiffies_to_msec64(s, shared->tmp.ticks[WRITE]),
> > > dm_stat_in_flight(shared),
> > > - dm_jiffies_to_msec64(shared->tmp.io_ticks_total),
> > > - dm_jiffies_to_msec64(shared->tmp.time_in_queue),
> > > - dm_jiffies_to_msec64(shared->tmp.io_ticks[READ]),
> > > - dm_jiffies_to_msec64(shared->tmp.io_ticks[WRITE]));
> > > + dm_jiffies_to_msec64(s, shared->tmp.io_ticks_total),
> > > + dm_jiffies_to_msec64(s, shared->tmp.time_in_queue),
> > > + dm_jiffies_to_msec64(s, shared->tmp.io_ticks[READ]),
> > > + dm_jiffies_to_msec64(s, shared->tmp.io_ticks[WRITE]));
> > >
> > > if (unlikely(sz + 1 >= maxlen))
> > > goto buffer_overflow;
> >
> > So the printed stats won't actually be in msec.
> >
> > Or am I missing something?
>
> If STAT_PRECISE_TIMESTAMPS is not set, the printed values are in ms, if it
> is set, they are in ns.
OK, makes sense. Otherwise we'd be losing the precision (which defeats
the purpose of this exercise). Thanks.
More information about the dm-devel
mailing list