blob: bca59df4ff942c3291008a1ef3eb06d9f08a1fab [file] [log] [blame]
/*
* Copyright 2016 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.h"
#include <map>
#include <string>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#if defined(OS_STARBOARD)
#include "nb/analytics/memory_tracker.h"
#include "nb/analytics/memory_tracker_impl.h"
#include "nb/scoped_ptr.h"
#include "nb/simple_thread.h"
#endif
namespace cobalt {
namespace browser {
#if !defined(OS_STARBOARD)
// A dummy implementation.
scoped_ptr<MemoryTrackerTool> CreateMemoryTrackerTool(const std::string&) {
DLOG(INFO)
<< "Memory tracker tool is not enabled on non-starboard builds.";
MemoryTrackerTool* null_ptr = NULL;
return scoped_ptr<MemoryTrackerTool>(null_ptr);
}
#else // defined(OS_STARBOARD)
namespace {
enum SwitchEnum {
kNull,
kStartup,
kContinuousPrinter,
};
struct SwitchVal {
SwitchVal() : help_msg(), enum_value(kNull) {}
SwitchVal(const SwitchVal& other)
: tool_name(other.tool_name), help_msg(other.help_msg),
enum_value(other.enum_value) {}
SwitchVal(const char* name, const char* msg, SwitchEnum val)
: tool_name(name), help_msg(msg), enum_value(val) {}
std::string tool_name;
std::string help_msg;
SwitchEnum enum_value;
};
} // namespace.
class MemoryTrackerThreadImpl : public MemoryTrackerTool {
public:
explicit MemoryTrackerThreadImpl(nb::SimpleThread* ptr)
: thread_ptr_(ptr) {
}
virtual ~MemoryTrackerThreadImpl() OVERRIDE {}
scoped_ptr<nb::SimpleThread> thread_ptr_;
};
scoped_ptr<MemoryTrackerTool> CreateMemoryTrackerTool(
const std::string& command_arg) {
// The command line switch for memory_tracker was used. Look into the args
// and determine the mode that the memory_tracker should be used for.
using nb::analytics::MemoryTrackerPrintThread;
using nb::analytics::MemoryTracker;
// The map is used to
// 1) Resolve the string to an enum.
// 2) Print a useful help method of all known memory_tracker modes.
typedef std::map<std::string, SwitchVal> SwitchMap;
SwitchVal startup_tool(
"startup",
"Records high-frequency memory metrics for the first 60 "
"seconds of program launch and then dumps it out in CSV format "
"to stdout.",
kStartup);
SwitchVal continuous_printer_tool(
"continuous_printer",
"Once every second the memory state is dumped to stdout.",
kContinuousPrinter);
SwitchMap switch_map;
switch_map[startup_tool.tool_name] = startup_tool;
switch_map[continuous_printer_tool.tool_name] = continuous_printer_tool;
// FAST OUT - is a thread type not selected? Then print out a help menu
// and request that the app should shut down.
SwitchMap::const_iterator found_it = switch_map.find(command_arg);
if (found_it == switch_map.end()) {
// Error, tell the user what to do instead and then exit.
std::stringstream ss;
ss << "\nNo memory tracker tool selected so help has been invoked:\n";
ss << "Memory Tracker help:\n";
for (SwitchMap::const_iterator it = switch_map.begin();
it != switch_map.end(); ++it) {
const std::string& name = it->first;
const SwitchVal& val = it->second;
ss << " memory_tracker="
<< name << " " << "\"" << val.help_msg << "\"\n";
}
ss << "\n";
SbLogRaw(ss.str().c_str());
ss.str(""); // Clears the contents of stringstream.
SbLogFlush();
// Try and turn off all logging so that the stdout is less likely to be
// polluted by interleaving output.
logging::SetMinLogLevel(INT_MAX);
// SbThreadSleep wants microseconds. We sleep here so that the user can
// read the help message before the engine starts up again and the
// fills the output with more logging text.
const SbTime four_seconds = 4000 * kSbTimeMillisecond;
SbThreadSleep(four_seconds);
found_it = switch_map.find(continuous_printer_tool.tool_name);
ss << "Defaulting to tool: " << found_it->first << "\n";
SbLogRaw(ss.str().c_str());
SbLogFlush();
// One more help message and 1-second pause. Then continue on with the
// execution as normal.
const SbTime one_second = 1000 * kSbTimeMillisecond;
SbThreadSleep(one_second);
}
// Okay we have been resolved to use a memory tracker in some way.
DLOG(INFO) << "\n\nUsing MemoryTracking=" << found_it->first << "\n";
MemoryTracker* memory_tracker = MemoryTracker::Get();
memory_tracker->InstallGlobalTrackingHooks();
scoped_ptr<nb::SimpleThread> thread_ptr;
const SwitchVal& value = found_it->second;
switch (value.enum_value) {
case kNull: {
SB_NOTREACHED();
break;
}
case kStartup: {
nb::scoped_ptr<nb::analytics::MemoryTrackerPrintCSVThread> ptr =
CreateDebugPrintCSVThread(memory_tracker,
1000, // Sample once a second.
60 * 1000); // Output after 60 seconds.
// Create a thread that will gather memory metrics for startup.
thread_ptr.reset(ptr.release());
break;
}
case kContinuousPrinter: {
nb::scoped_ptr<MemoryTrackerPrintThread> ptr =
CreateDebugPrintThread(memory_tracker);
// Create a thread that will continuously report memory use.
thread_ptr.reset(ptr.release());
break;
}
default: {
SB_NOTREACHED() << "Unhandled case.";
break;
}
}
// Wrap the tool up in MemoryTrackerThreadImpl.
return scoped_ptr<MemoryTrackerTool>(
new MemoryTrackerThreadImpl(thread_ptr.release()));
}
#endif // defined(OS_STARBOARD)
} // namespace browser
} // namespace cobalt