/* * This file is a part of Winix * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2008-2018, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include "loadavg.h" #include "misc.h" namespace Winix { LoadAvg::LoadAvg() { current1.Clear(); current5.Clear(); current15.Clear(); cache_load1 = 0.0; cache_load5 = 0.0; cache_load15 = 0.0; cache_req_per_sec1 = 0.0; cache_req_per_sec5 = 0.0; cache_req_per_sec15 = 0.0; timespec_old_req_stop.tv_sec = 0; timespec_old_req_stop.tv_nsec = 0; CreateTable(); } LoadAvg & LoadAvg::operator=(const LoadAvg & l) { current1 = l.current1; current5 = l.current5; current15 = l.current15; cache_load1 = l.cache_load1; cache_load5 = l.cache_load5; cache_load15 = l.cache_load15; cache_req_per_sec1 = l.cache_req_per_sec1; cache_req_per_sec5 = l.cache_req_per_sec5; cache_req_per_sec15 = l.cache_req_per_sec15; timespec_old_req_stop.tv_sec = l.timespec_old_req_stop.tv_sec; timespec_old_req_stop.tv_nsec = l.timespec_old_req_stop.tv_nsec; CreateTable(); return *this; } LoadAvg::LoadAvg(const LoadAvg & l) { operator=(l); } LoadAvg::~LoadAvg() { delete [] tab1; delete [] tab5; delete [] tab15; } void LoadAvg::CreateTable(size_t seconds, size_t granularity, Times* & tab, size_t & len) { len = (seconds / granularity) + 1; // rounding up (len mininum is 1) tab = new Times[len]; for(size_t i=0 ; i 1 ) { for(size_t i=0 ; i (double)WINIX_LOADAVG_GRANULARITY1 ) UpdateTimer1(); if( current5.dr + current5.dp > (double)WINIX_LOADAVG_GRANULARITY5 ) UpdateTimer5(); if( current15.dr + current15.dp > (double)WINIX_LOADAVG_GRANULARITY15 ) UpdateTimer15(); } void LoadAvg::StartRequest(Request * req) { if( timespec_old_req_stop.tv_sec != 0 ) { // we got at least one request in the past timespec diff; calculate_timespec_diff(timespec_old_req_stop, req->timespec_req_start, diff); double dp = timespec_to_double(diff); current1.dp += dp; current5.dp += dp; current15.dp += dp; CheckTimers(); } } void LoadAvg::StopRequest(Request * req) { double dr = timespec_to_double(req->timespec_req_diff); current1.dr += dr; current5.dr += dr; current15.dr += dr; current1.req += 1; current5.req += 1; current15.req += 1; timespec_old_req_stop = req->timespec_req_stop; } void LoadAvg::SumTab(Times * tab, size_t len, double expected, Times & t) { size_t i = len; while( i-- > 0 && t.dr+t.dp < expected ) { t.dr += tab[i].dr; t.dp += tab[i].dp; t.req += tab[i].req; } } void LoadAvg::Calculate1() { Times t = current1; SumTab(tab1, len1, 60.0, t); if( t.dr+t.dp == 0.0 ) { cache_load1 = 0.0; cache_req_per_sec1 = 0.0; } else { cache_load1 = t.dr / (t.dr+t.dp); cache_req_per_sec1 = t.req / (t.dr+t.dp); } } void LoadAvg::Calculate5() { Times t = current5; SumTab(tab5, len5, 60.0 * 5, t); if( t.dr+t.dp == 0.0 ) { cache_load5 = 0.0; cache_req_per_sec5 = 0.0; } else { cache_load5 = t.dr / (t.dr+t.dp); cache_req_per_sec5 = t.req / (t.dr+t.dp); } } void LoadAvg::Calculate15() { Times t = current15; SumTab(tab15, len15, 60.0 * 15, t); if( t.dr+t.dp == 0.0 ) { cache_load15 = 0.0; cache_req_per_sec15 = 0.0; } else { cache_load15 = t.dr / (t.dr+t.dp); cache_req_per_sec15 = t.req / (t.dr+t.dp); } } double LoadAvg::LoadAvgNow() { double load = 0.0; double dr = current1.dr; double dp = current1.dp; if( tab1[len1-1].dr + tab1[len1-1].dp < WINIX_LOADAVG_GRANULARITY1 * 2 ) { dr += tab1[len1-1].dr; dp += tab1[len1-1].dp; } if( dr + dp != 0.0 ) load = dr / (dr + dp); return load; } double LoadAvg::LoadAvg1() { if( cache_load1 != 0.0 ) return cache_load1; Calculate1(); return cache_load1; } double LoadAvg::LoadAvg5() { if( cache_load5 != 0.0 ) return cache_load5; Calculate5(); return cache_load5; } double LoadAvg::LoadAvg15() { if( cache_load15 != 0.0 ) return cache_load15; Calculate15(); return cache_load15; } double LoadAvg::ReqPerSecNow() { double req_per_sec = 0.0; double dr = current1.dr; double dp = current1.dp; double req = current1.req; if( tab1[len1-1].dr + tab1[len1-1].dp < WINIX_LOADAVG_GRANULARITY1 * 2 ) { dr += tab1[len1-1].dr; dp += tab1[len1-1].dp; req += tab1[len1-1].req; } if( dr + dp != 0.0 ) req_per_sec = req / (dr + dp); return req_per_sec; } double LoadAvg::ReqPerSec1() { if( cache_req_per_sec1 != 0.0 ) return cache_req_per_sec1; Calculate1(); return cache_req_per_sec1; } double LoadAvg::ReqPerSec5() { if( cache_req_per_sec5 != 0.0 ) return cache_req_per_sec5; Calculate5(); return cache_req_per_sec5; } double LoadAvg::ReqPerSec15() { if( cache_req_per_sec15 != 0.0 ) return cache_req_per_sec15; Calculate15(); return cache_req_per_sec15; } } // namespace Winix