blob: f896f2f9f30834a1cf71bc07ace65786c91e53f6 [file] [log] [blame]
// Copyright 2017 Google Inc. 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.
#include "cobalt/browser/memory_tracker/tool/print_tool.h"
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/threading/platform_thread.h"
#include "cobalt/base/c_val.h"
#include "cobalt/browser/memory_tracker/tool/util.h"
#include "nb/analytics/memory_tracker.h"
#include "nb/analytics/memory_tracker_helpers.h"
#include "starboard/log.h"
#include "starboard/types.h"
namespace cobalt {
namespace browser {
namespace memory_tracker {
using nb::analytics::AllocationGroup;
class PrintTool::CvalsMap {
public:
typedef base::CVal<base::cval::SizeInBytes> CValType;
~CvalsMap() {
while (!map_.empty()) {
MapCvals::iterator it = map_.begin();
delete it->second;
map_.erase(it);
}
}
void Update(const std::string& name, size_t value) {
std::string cval_name = GetCvalName(name);
CValType*& val = map_[cval_name];
if (!val) {
// Create if not found.
val = new CValType(cval_name, 0,
"Automatically generated by the "
"browser::memory_tracker system.");
}
(*val) = value;
}
static std::string GetCvalName(const std::string& name) {
std::stringstream ss;
ss << "Memory.Scope." << name;
return ss.str();
}
private:
typedef std::map<std::string, CValType*> MapCvals;
MapCvals map_;
};
PrintTool::PrintTool() : cvals_map_(new CvalsMap) {}
PrintTool::~PrintTool() {}
void PrintTool::Run(Params* params) {
const std::string kSeperator =
"--------------------------------------------------";
while (!params->finished()) {
std::vector<const AllocationGroup*> vector_output;
params->memory_tracker()->GetAllocationGroups(&vector_output);
typedef std::map<std::string, const AllocationGroup*> Map;
typedef Map::const_iterator MapIt;
Map output;
for (size_t i = 0; i < vector_output.size(); ++i) {
const AllocationGroup* group = vector_output[i];
output[group->name()] = group;
}
int32 num_allocs = 0;
int64 total_bytes = 0;
struct F {
static void PrintRow(std::stringstream* ss, const std::string& v1,
const std::string& v2, const std::string& v3) {
ss->width(25);
*ss << std::left << v1;
ss->width(13);
*ss << std::right << v2 << " ";
ss->width(10);
*ss << std::right << v3 << "\n";
}
};
if (params->memory_tracker()->IsMemoryTrackingEnabled()) {
// If this isn't true then it would cause an infinite loop. The
// following will likely crash.
SB_DCHECK(false) << "Unexpected, memory tracking should be disabled.";
}
std::stringstream ss;
ss << kNewLine;
ss << "TimeNow " << params->TimeInMinutesString()
<< " (minutes):" << kNewLine << kNewLine;
ss << kSeperator << kNewLine;
nb::analytics::MemoryStats memstats =
nb::analytics::GetProcessMemoryStats();
F::PrintRow(&ss, "MALLOC STAT", "IN USE BYTES", "");
ss << kSeperator << kNewLine;
F::PrintRow(&ss, "Total CPU Reserved",
NumberFormatWithCommas(memstats.total_cpu_memory), "");
F::PrintRow(&ss, "Total CPU Used",
NumberFormatWithCommas(memstats.used_cpu_memory), "");
F::PrintRow(&ss, "Total GPU Reserved",
NumberFormatWithCommas(memstats.total_gpu_memory), "");
F::PrintRow(&ss, "Total GPU Used",
NumberFormatWithCommas(memstats.used_gpu_memory), "");
ss << kSeperator << kNewLine << kNewLine;
ss << kSeperator << kNewLine;
F::PrintRow(&ss, "MEMORY REGION", "IN USE BYTES", "NUM ALLOCS");
ss << kSeperator << kNewLine;
for (MapIt it = output.begin(); it != output.end(); ++it) {
const AllocationGroup* group = it->second;
if (!group) {
continue;
}
int32 num_group_allocs = -1;
int64 total_group_bytes = -1;
group->GetAggregateStats(&num_group_allocs, &total_group_bytes);
SB_DCHECK(-1 != num_group_allocs);
SB_DCHECK(-1 != total_group_bytes);
cvals_map_->Update(group->name(), static_cast<size_t>(total_group_bytes));
num_allocs += num_group_allocs;
total_bytes += total_group_bytes;
F::PrintRow(&ss, it->first, NumberFormatWithCommas(total_group_bytes),
NumberFormatWithCommas(num_group_allocs));
}
cvals_map_->Update("Total", static_cast<size_t>(total_bytes));
ss << kNewLine;
F::PrintRow(&ss, "Total (in groups above)",
NumberFormatWithCommas(total_bytes),
NumberFormatWithCommas(num_allocs));
ss << kSeperator << kNewLine;
ss << kNewLine << kNewLine;
params->logger()->Output(ss.str().c_str());
// Output once every 5 seconds.
base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(5));
}
}
std::string PrintTool::tool_name() const {
return "MemoryTrackerPrintThread";
}
} // namespace memory_tracker
} // namespace browser
} // namespace cobalt