/** * Copyright (c) 2007-2012, Timothy Stack * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 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. * * Neither the name of Timothy Stack nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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 "hist_source.hh" #include "base/math_util.hh" #include "config.h" #include "fmt/chrono.h" nonstd::optional hist_source2::row_for_time(struct timeval tv_bucket) { std::map::iterator iter; int retval = 0; time_t time_bucket = rounddown(tv_bucket.tv_sec, this->hs_time_slice); for (iter = this->hs_blocks.begin(); iter != this->hs_blocks.end(); ++iter) { struct bucket_block& bb = iter->second; if (time_bucket < bb.bb_buckets[0].b_time) { break; } if (time_bucket > bb.bb_buckets[bb.bb_used].b_time) { retval += bb.bb_used + 1; continue; } for (unsigned int lpc = 0; lpc <= bb.bb_used; lpc++, retval++) { if (time_bucket <= bb.bb_buckets[lpc].b_time) { return vis_line_t(retval); } } } return vis_line_t(retval); } void hist_source2::text_value_for_line(textview_curses& tc, int row, std::string& value_out, text_sub_source::line_flags_t flags) { bucket_t& bucket = this->find_bucket(row); struct tm bucket_tm; value_out.clear(); if (gmtime_r(&bucket.b_time, &bucket_tm) != nullptr) { fmt::format_to(std::back_inserter(value_out), FMT_STRING(" {:%a %b %d %H:%M:%S} "), bucket_tm); } else { log_error("no time?"); } fmt::format_to( std::back_inserter(value_out), FMT_STRING(" {:8L} normal {:8L} errors {:8L} warnings {:8L} marks"), rint(bucket.b_values[HT_NORMAL].hv_value), rint(bucket.b_values[HT_ERROR].hv_value), rint(bucket.b_values[HT_WARNING].hv_value), rint(bucket.b_values[HT_MARK].hv_value)); } void hist_source2::text_attrs_for_line(textview_curses& tc, int row, string_attrs_t& value_out) { bucket_t& bucket = this->find_bucket(row); int left = 0; for (int lpc = 0; lpc < HT__MAX; lpc++) { this->hs_chart.chart_attrs_for_value(tc, left, (const hist_type_t) lpc, bucket.b_values[lpc].hv_value, value_out); } } void hist_source2::add_value(time_t row, hist_source2::hist_type_t htype, double value) { if (row < this->hs_last_row) { log_error("time mismatch %ld %ld", row, this->hs_last_row); } require(row >= this->hs_last_row); row = rounddown(row, this->hs_time_slice); if (row != this->hs_last_row) { this->end_of_row(); this->hs_last_bucket += 1; this->hs_last_row = row; } auto& bucket = this->find_bucket(this->hs_last_bucket); bucket.b_time = row; bucket.b_values[htype].hv_value += value; } void hist_source2::init() { view_colors& vc = view_colors::singleton(); this->hs_chart .with_attrs_for_ident(HT_NORMAL, vc.attrs_for_role(role_t::VCR_TEXT)) .with_attrs_for_ident(HT_WARNING, vc.attrs_for_role(role_t::VCR_WARNING)) .with_attrs_for_ident(HT_ERROR, vc.attrs_for_role(role_t::VCR_ERROR)) .with_attrs_for_ident(HT_MARK, vc.attrs_for_role(role_t::VCR_COMMENT)); } void hist_source2::clear() { this->hs_line_count = 0; this->hs_last_bucket = -1; this->hs_last_row = -1; this->hs_blocks.clear(); this->hs_chart.clear(); this->init(); } void hist_source2::end_of_row() { if (this->hs_last_bucket >= 0) { bucket_t& last_bucket = this->find_bucket(this->hs_last_bucket); for (int lpc = 0; lpc < HT__MAX; lpc++) { this->hs_chart.add_value((const hist_type_t) lpc, last_bucket.b_values[lpc].hv_value); } } } nonstd::optional hist_source2::time_for_row(vis_line_t row) { if (row < 0 || row > this->hs_line_count) { return nonstd::nullopt; } bucket_t& bucket = this->find_bucket(row); return timeval{bucket.b_time, 0}; } hist_source2::bucket_t& hist_source2::find_bucket(int64_t index) { struct bucket_block& bb = this->hs_blocks[index / BLOCK_SIZE]; unsigned int intra_block_index = index % BLOCK_SIZE; bb.bb_used = std::max(intra_block_index, bb.bb_used); this->hs_line_count = std::max(this->hs_line_count, index + 1); return bb.bb_buckets[intra_block_index]; }