blob: e86567040ca1065a3ba1edba3a7efa9a36238927 [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.
#include "cobalt/browser/memory_tracker/tool/util.h"
#include <algorithm>
#include <iterator>
#include <string>
#include <vector>
#include "base/time/time.h"
#include "nb/bit_cast.h"
#include "starboard/common/string.h"
namespace cobalt {
namespace browser {
namespace memory_tracker {
const char kQuote[] = "\"";
const char kDelimiter[] = ",";
const char kNewLine[] = "\n";
std::string RemoveString(const std::string& haystack, const char* needle) {
const size_t kNotFound = std::string::npos;
// Base case. No modification needed.
size_t pos = haystack.find(needle);
if (pos == kNotFound) {
return haystack;
}
const size_t n = strlen(needle);
std::string output;
output.reserve(haystack.size());
// Copy string, omitting the portion containing the "needle".
std::copy(haystack.begin(), haystack.begin() + pos,
std::back_inserter(output));
std::copy(haystack.begin() + pos + n, haystack.end(),
std::back_inserter(output));
// Recursively remove same needle in haystack.
return RemoveString(output, needle);
}
std::string SanitizeCSVKey(std::string key) {
key = RemoveString(key, kQuote);
key = RemoveString(key, kDelimiter);
key = RemoveString(key, kNewLine);
return key;
}
std::string InsertCommasIntoNumberString(const std::string& input) {
typedef std::vector<char> CharVector;
typedef CharVector::iterator CharIt;
CharVector chars(input.begin(), input.end());
std::reverse(chars.begin(), chars.end());
CharIt curr_it = chars.begin();
CharIt mid = std::find(chars.begin(), chars.end(), '.');
if (mid == chars.end()) {
mid = curr_it;
}
CharVector out(curr_it, mid);
int counter = 0;
for (CharIt it = mid; it != chars.end(); ++it) {
if (counter != 0 && (counter % 3 == 0)) {
out.push_back(',');
}
if (*it != '.') {
counter++;
}
out.push_back(*it);
}
std::reverse(out.begin(), out.end());
std::stringstream ss;
for (size_t i = 0; i < out.size(); ++i) {
ss << out[i];
}
return ss.str();
}
Timer::Timer(base::TimeDelta delta_time) {
start_time_ = Now();
time_before_expiration_ = delta_time;
}
Timer::Timer(base::TimeDelta delta_time, Timer::TimeFunctor time_functor) {
time_function_override_ = time_functor;
start_time_ = Now();
time_before_expiration_ = delta_time;
}
void Timer::Restart() { start_time_ = Now(); }
bool Timer::UpdateAndIsExpired() {
base::TimeTicks now_time = Now();
base::TimeDelta delta_time = now_time - start_time_;
if (delta_time >= time_before_expiration_) {
start_time_ = now_time;
return true;
} else {
return false;
}
}
base::TimeTicks Timer::Now() {
if (time_function_override_.is_null()) {
return base::TimeTicks::Now();
} else {
return time_function_override_.Run();
}
}
void Timer::ScaleTriggerTime(double scale) {
int64_t old_dt = time_before_expiration_.InMicroseconds();
int64_t new_dt = static_cast<int64_t>(static_cast<double>(old_dt) * scale);
time_before_expiration_ = base::TimeDelta::FromMicroseconds(new_dt);
}
Segment::Segment(const std::string* name, const char* start_address,
const char* end_address)
: name_(name), begin_(start_address), end_(end_address) {}
void Segment::SplitAcrossPageBoundaries(size_t page_size,
std::vector<Segment>* segments) const {
if (size() == 0) {
segments->push_back(*this);
return;
}
uintptr_t page_start = nb::bit_cast<uintptr_t>(begin_) / page_size;
uintptr_t page_end = nb::bit_cast<uintptr_t>(end_ - 1) / page_size;
if (page_start == page_end) {
segments->push_back(*this);
return;
}
for (uintptr_t p = page_start; p <= page_end; ++p) {
uintptr_t start_addr;
if (p == page_start) {
start_addr = nb::bit_cast<uintptr_t>(begin_);
} else {
start_addr = p * page_size;
}
uintptr_t end_addr;
if (p == page_end) {
end_addr = nb::bit_cast<uintptr_t>(end_);
} else {
end_addr = (p + 1) * page_size;
}
const char* start = nb::bit_cast<const char*>(start_addr);
const char* end = nb::bit_cast<const char*>(end_addr);
segments->push_back(Segment(name_, start, end));
}
}
bool Segment::Intersects(const Segment& other) const {
size_t total_span = std::distance(std::min(begin_, other.begin()),
std::max(end_, other.end()));
bool intersects = (size() + other.size()) > total_span;
return intersects;
}
bool Segment::operator<(const Segment& other) const {
return begin_ < other.begin();
}
bool Segment::operator==(const Segment& other) const {
if (begin_ == other.begin() && end_ == other.end()) {
DCHECK(name_ == other.name_);
return true;
}
return false;
}
size_t Segment::size() const { return std::distance(begin_, end_); }
const char* BaseNameFast(const char* file_name) {
// Case: Linux.
const char* end_pos = file_name + strlen(file_name);
const char* last_forward_slash = strrchr(file_name, '/');
if (last_forward_slash) {
if (end_pos != last_forward_slash) {
++last_forward_slash;
}
return last_forward_slash;
}
// Case: Windows.
const char* last_backward_slash = strrchr(file_name, '\\');
if (last_backward_slash) {
if (end_pos != last_backward_slash) {
++last_backward_slash;
}
return last_backward_slash;
}
return file_name;
}
} // namespace memory_tracker
} // namespace browser
} // namespace cobalt