blob: 3a96a341a5c7fc5b740975be0a9305b683145102 [file] [log] [blame]
// Copyright 2017 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef COBALT_BROWSER_MEMORY_TRACKER_TOOL_HISTOGRAM_TABLE_CSV_BASE_H_
#define COBALT_BROWSER_MEMORY_TRACKER_TOOL_HISTOGRAM_TABLE_CSV_BASE_H_
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include "base/logging.h"
#include "cobalt/browser/memory_tracker/tool/util.h"
#include "starboard/types.h"
namespace cobalt {
namespace browser {
namespace memory_tracker {
// This HistogramTableCSV provides most of the functionality for generating a
// csv table from a histogram of data.
//
// Subclasses need to override ValueToString(...) so that the
// data-type can be stringified during the call to ToString().
//
// Example:
// class MyHistogram : public HistogramTableCSV<int64_t>() {...}
// MyHistogram my_histogram;
// my_histogram.set_title("Memory Values");
//
// // Add first row.
// my_histogram.BeginRow(time_delta);
// my_histogram.AddRowValue("ColumnA", 0);
// my_histogram.AddRowValue("ColumnB", 0);
// my_histogram.FinalizeRow();
//
// // Add second row.
// my_histogram.BeginRow(time_delta);
// my_histogram.AddRowValue("ColumnA", 1);
// my_histogram.AddRowValue("ColumnB", 2);
// my_histogram.AddRowValue("ColumnC", 1); // Ok, ColumnC will be autofilled.
// my_histogram.FinalizeRow();
//
// Print(my_histogram.ToString());
template <typename ValueType>
class HistogramTableCSVBase {
public:
typedef std::map<std::string, std::vector<ValueType> > TableData;
// default_value is used to auto-fill values, such as when a new column
// is introduced.
explicit HistogramTableCSVBase(const ValueType& default_value)
: default_value_(default_value) {}
virtual std::string ValueToString(const ValueType& value) const = 0;
void set_title(const std::string& title) { title_ = title; }
void BeginRow(const base::TimeDelta time_value) {
time_values_.push_back(time_value);
}
void AddRowValue(const std::string& column_key, const ValueType& value) {
if (time_values_.empty()) {
NOTREACHED() << "table_data_ was empty.";
time_values_.push_back(base::TimeDelta());
}
const size_t n = time_values_.size();
std::vector<ValueType>& column = table_data_[column_key];
while (column.size() < n - 1) {
column.push_back(default_value_);
}
column.push_back(value);
}
void FinalizeRow() {
const size_t n = time_values_.size();
for (typename TableData::iterator it = table_data_.begin();
it != table_data_.end(); ++it) {
std::vector<ValueType>& column = it->second;
while (column.size() < n) {
column.push_back(default_value_);
}
}
}
std::string ToString() const {
const char kSeparator[] = "//////////////////////////////////////////////";
std::stringstream ss;
ss << kSeparator << kNewLine;
if (title_.size()) {
ss << "// CSV of " << title_ << kNewLine;
}
for (size_t i = 0; i < NumberOfRows(); ++i) {
ss << StringifyRow(i);
}
ss << kSeparator;
return ss.str();
}
// All odd elements are removed. Effectively compressing the table in half.
void RemoveOddElements() {
memory_tracker::RemoveOddElements(&time_values_);
for (typename TableData::iterator it = table_data_.begin();
it != table_data_.end(); ++it) {
memory_tracker::RemoveOddElements(&it->second);
}
}
size_t NumberOfRows() const { return time_values_.size(); }
protected:
static std::string JoinValues(const std::vector<std::string>& row_values) {
std::stringstream ss;
for (size_t i = 0; i < row_values.size(); ++i) {
ss << kQuote << row_values[i] << kQuote << kDelimiter;
}
ss << kNewLine;
return ss.str();
}
static std::string TimeToMinutesString(base::TimeDelta dt) {
double value_minutes = dt.InSecondsF() / 60.;
char buff[128];
SbStringFormatF(buff, sizeof(buff), "%.2f", value_minutes);
return std::string(buff);
}
std::string StringifyRow(size_t index) const {
if (index == 0) {
// Create header row.
std::vector<std::string> column_keys;
column_keys.push_back("Time(min)");
for (typename TableData::const_iterator it = table_data_.begin();
it != table_data_.end(); ++it) {
column_keys.push_back(SanitizeCSVKey(it->first));
}
return JoinValues(column_keys);
} else {
// Create data row.
std::vector<std::string> row_values;
row_values.push_back(TimeToMinutesString(time_values_[index]));
for (typename TableData::const_iterator it = table_data_.begin();
it != table_data_.end(); ++it) {
const std::vector<ValueType>& column = it->second;
const std::string value_str = ValueToString(column[index]);
row_values.push_back(value_str);
}
return JoinValues(row_values);
}
}
std::string title_;
ValueType default_value_;
std::vector<base::TimeDelta> time_values_;
TableData table_data_;
};
// Useful for tracking values in megabytes.
class MemoryBytesHistogramCSV : public HistogramTableCSVBase<int64_t> {
public:
MemoryBytesHistogramCSV() : HistogramTableCSVBase<int64_t>(0) {}
std::string ValueToString(const int64_t& bytes) const override {
return ToMegabyteString(bytes);
}
static std::string ToMegabyteString(int64_t bytes) {
double megabytes = static_cast<double>(bytes) / (1024.0 * 1024.0);
char buff[128];
SbStringFormatF(buff, sizeof(buff), "%.1f", megabytes);
return std::string(buff);
}
};
} // namespace memory_tracker
} // namespace browser
} // namespace cobalt
#endif // COBALT_BROWSER_MEMORY_TRACKER_TOOL_HISTOGRAM_TABLE_CSV_BASE_H_