Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754351AbbLaLqA (ORCPT ); Thu, 31 Dec 2015 06:46:00 -0500 Received: from mo4-p00-ob.smtp.rzone.de ([81.169.146.220]:52624 "EHLO mo4-p00-ob.smtp.rzone.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753657AbbLaLnL (ORCPT ); Thu, 31 Dec 2015 06:43:11 -0500 X-RZG-AUTH: :OH8QVVOrc/CP6za/qRmbF3BWedPGA1vjs2ejZCzW8NRdwTYefHi0LhjeQF0sTFwGWOFPJQ== X-RZG-CLASS-ID: mo00 From: Thomas Schoebel-Theuer To: linux-kernel@vger.kernel.org, tst@schoebel-theuer.de Subject: [RFC 11/31] mars: add new module lib_timing Date: Thu, 31 Dec 2015 12:36:06 +0100 Message-Id: X-Mailer: git-send-email 2.6.4 In-Reply-To: References: In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7356 Lines: 280 Signed-off-by: Thomas Schoebel-Theuer --- drivers/staging/mars/lib/lib_timing.c | 71 +++++++++++++ include/linux/brick/lib_timing.h | 181 ++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 drivers/staging/mars/lib/lib_timing.c create mode 100644 include/linux/brick/lib_timing.h diff --git a/drivers/staging/mars/lib/lib_timing.c b/drivers/staging/mars/lib/lib_timing.c new file mode 100644 index 0000000..7421dc4 --- /dev/null +++ b/drivers/staging/mars/lib/lib_timing.c @@ -0,0 +1,71 @@ +/* + * MARS Long Distance Replication Software + * + * Copyright (C) 2010-2014 Thomas Schoebel-Theuer + * Copyright (C) 2011-2014 1&1 Internet AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include +#include + +#ifdef CONFIG_DEBUG_KERNEL + +int report_timing(struct timing_stats *tim, char *str, int maxlen) +{ + int len = 0; + int time = 1; + int resol = 1; + + static const char * const units[] = { + "us", + "ms", + "s", + "ERROR" + }; + const char *unit = units[0]; + int unit_index = 0; + int i; + + for (i = 0; i < TIMING_MAX; i++) { + int this_len = scnprintf(str, + + maxlen, + "<%d%s = %d (%lld) ", + resol, + unit, + tim->tim_count[i], + (long long)tim->tim_count[i] * time); + str += this_len; + len += this_len; + maxlen -= this_len; + if (maxlen <= 1) + break; + resol <<= 1; + time <<= 1; + if (resol >= 1000) { + resol = 1; + unit = units[++unit_index]; + } + } + return len; +} + +#endif /* CONFIG_DEBUG_KERNEL */ + +struct threshold global_io_threshold = { + .thr_limit = 30 * 1000000, /* 30 seconds */ + .thr_factor = 100, + .thr_plus = 0, +}; diff --git a/include/linux/brick/lib_timing.h b/include/linux/brick/lib_timing.h new file mode 100644 index 0000000..8a7a1e9 --- /dev/null +++ b/include/linux/brick/lib_timing.h @@ -0,0 +1,181 @@ +/* + * MARS Long Distance Replication Software + * + * Copyright (C) 2010-2014 Thomas Schoebel-Theuer + * Copyright (C) 2011-2014 1&1 Internet AG + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef LIB_TIMING_H +#define LIB_TIMING_H + +#include + +/* Simple infrastructure for timing of arbitrary operations and creation + * of some simple histogram statistics. + */ + +#define TIMING_MAX 24 + +struct timing_stats { +#ifdef CONFIG_DEBUG_KERNEL + int tim_count[TIMING_MAX]; + +#endif +}; + +#define _TIME_THIS(_stamp1, _stamp2, _CODE) \ + ({ \ + (_stamp1) = cpu_clock(raw_smp_processor_id()); \ + \ + _CODE; \ + \ + (_stamp2) = cpu_clock(raw_smp_processor_id()); \ + (_stamp2) - (_stamp1); \ + }) + +#define TIME_THIS(_CODE) \ + ({ \ + unsigned long long _stamp1; \ + unsigned long long _stamp2; \ + _TIME_THIS(_stamp1, _stamp2, _CODE); \ + }) + +#ifdef CONFIG_DEBUG_KERNEL + +#define _TIME_STATS(_timing, _stamp1, _stamp2, _CODE) \ + ({ \ + unsigned long long _time; \ + unsigned long _tmp; \ + int _i; \ + \ + _time = _TIME_THIS(_stamp1, _stamp2, _CODE); \ + \ + _tmp = _time / 1000; /* convert to us */ \ + _i = 0; \ + while (_tmp > 0 && _i < TIMING_MAX - 1) { \ + _tmp >>= 1; \ + _i++; \ + } \ + (_timing)->tim_count[_i]++; \ + _time; \ + }) + +#define TIME_STATS(_timing, _CODE) \ + ({ \ + unsigned long long _stamp1; \ + unsigned long long _stamp2; \ + _TIME_STATS(_timing, _stamp1, _stamp2, _CODE); \ + }) + +extern int report_timing(struct timing_stats *tim, char *str, int maxlen); + +#else /* CONFIG_DEBUG_KERNEL */ + +#define _TIME_STATS(_timing, _stamp1, _stamp2, _CODE) \ + ((void)_timing, (_stamp1) = (_stamp2) = cpu_clock(raw_smp_processor_id()), _CODE, 0) + +#define TIME_STATS(_timing, _CODE) \ + ((void)_timing, _CODE, 0) + +#define report_timing(tim, str, maxlen) ((void)tim, 0) + +#endif /* CONFIG_DEBUG_KERNEL */ + +/* A banning represents some overloaded resource. + * + * Whenever overload is detected, you should call banning_hit() + * telling that the overload is assumed / estimated to continue + * for some duration in time. + * + * ATTENTION! These operations are deliberately raceful. + * They are meant to deliver _hints_ (e.g. for IO scheduling + * decisions etc), not hard facts! + * + * If you need locking, just surround these operations + * with locking by yourself. + */ +struct banning { + long long ban_last_hit; + + /* statistical */ + int ban_renew_count; + int ban_count; +}; + +extern inline +bool banning_hit(struct banning *ban, long long duration) +{ + long long now = cpu_clock(raw_smp_processor_id()); + bool hit = ban->ban_last_hit >= now; + long long new_hit = now + duration; + + ban->ban_renew_count++; + if (!ban->ban_last_hit || ban->ban_last_hit < new_hit) { + ban->ban_last_hit = new_hit; + ban->ban_count++; + } + return hit; +} + +extern inline +bool banning_is_hit(struct banning *ban) +{ + long long now = cpu_clock(raw_smp_processor_id()); + + return (ban->ban_last_hit && ban->ban_last_hit >= now); +} + +extern inline +void banning_reset(struct banning *ban) +{ + ban->ban_last_hit = 0; +} + +/* Threshold: trigger a banning whenever some latency threshold + * is exceeded. + */ +struct threshold { + struct banning *thr_ban; + + struct threshold *thr_parent; /* support hierarchies */ + /* tunables */ + int thr_limit; /* in us */ + int thr_factor; /* in % */ + int thr_plus; /* in us */ + /* statistical */ + int thr_max; /* in ms */ + int thr_triggered; + int thr_true_hit; +}; + +extern inline +void threshold_check(struct threshold *thr, long long latency) +{ + int ms = latency >> 6; /* ignore small rounding error */ + while (thr) { + if (ms > thr->thr_max) + thr->thr_max = ms; + if (thr->thr_limit && + latency > (long long)thr->thr_limit * 1000) { + thr->thr_triggered++; + if (thr->thr_ban && + !banning_hit(thr->thr_ban, latency * thr->thr_factor / 100 + thr->thr_plus * 1000)) + thr->thr_true_hit++; + } + thr = thr->thr_parent; + } +} + +extern struct threshold global_io_threshold; + +#endif -- 2.6.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/