OEMCrypto Profiler
This CL is a merge from the widevine repo of: http://go/wvgerrit/16491 Circular Buffer http://go/wvgerrit/16512 Circular Buffer Tests http://go/wvgerrit/16493 Entry Writer http://go/wvgerrit/16495 Profiled Scope http://go/wvgerrit/16500 Stats Collection http://go/wvgerrit/16543 Disallow Stats Copy or Assign http://go/wvgerrit/16514 Moving OEM Function Enum http://go/wvgerrit/16501 Defining Session Interface http://go/wvgerrit/16502 Session Definitions http://go/wvgerrit/16573 Remove code to num bytes table http://go/wvgerrit/16556 Connecting Profiler to Profiled Scope http://go/wvgerrit/16557 Android Reading Profiler History http://go/wvgerrit/16574 Adding Get Stats Method http://go/wvgerrit/16606 Seperating Session Parsing http://go/wvgerrit/16607 Adding get stats method to DRMPlugin http://go/wvgerrit/16608 Fixing Linux Build Failure http://go/wvgerrit/16612 Stop Clearing History http://go/wvgerrit/16613 Accessing profiler information using session id http://go/wvgerrit/16614 Making All Session Subsets of Global Session BUG: 25123303 BUG: 26027857 Change-Id: Ie2422e644aa631871852ea0e461695aeb7060f88
This commit is contained in:
92
libwvdrmengine/cdm/profiler/src/circular_buffer.cpp
Normal file
92
libwvdrmengine/cdm/profiler/src/circular_buffer.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "circular_buffer.h"
|
||||
|
||||
#include "log.h"
|
||||
|
||||
namespace wvcdm {
|
||||
namespace oemprofiler {
|
||||
|
||||
CircularBuffer::CircularBuffer(size_t memory_budget) :
|
||||
buffer_(memory_budget) {
|
||||
|
||||
buffer_.resize(memory_budget, 0x00);
|
||||
fill_ = head_ = tail_ = 0;
|
||||
}
|
||||
|
||||
size_t CircularBuffer::GetFreeSpace() const {
|
||||
return buffer_.size() - fill_;
|
||||
}
|
||||
|
||||
size_t CircularBuffer::GetUsedSpace() const {
|
||||
return fill_;
|
||||
}
|
||||
|
||||
bool CircularBuffer::AddU8(uint8_t value) {
|
||||
return AddU8s(&value, 1);
|
||||
}
|
||||
|
||||
bool CircularBuffer::AddU8s(const uint8_t* values, size_t values_length) {
|
||||
if (GetFreeSpace() < values_length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < values_length; i++) {
|
||||
buffer_[head_] = values[i];
|
||||
head_ = (head_ + 1) % buffer_.size();
|
||||
}
|
||||
|
||||
fill_ += values_length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CircularBuffer::PeekU8s(
|
||||
size_t offset,
|
||||
uint8_t* out,
|
||||
size_t read_length) const {
|
||||
|
||||
if (out == NULL) {
|
||||
LOGE("Cannot read to null output");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offset >= GetUsedSpace()) {
|
||||
LOGE("Cannot read past end of data - %zu >= %zu",
|
||||
offset, GetUsedSpace());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (read_length > GetUsedSpace() - offset) {
|
||||
LOGE("Cannot read when there is not enough data - %zu >= %zu",
|
||||
GetUsedSpace() - offset, sizeof(uint8_t));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < read_length; i++) {
|
||||
const size_t safe_index = (tail_ + offset + i) % buffer_.size();
|
||||
out[i] = buffer_[safe_index];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CircularBuffer::PeekU8(size_t offset, uint8_t* out) const {
|
||||
return PeekU8s(offset, out, 1);
|
||||
}
|
||||
|
||||
bool CircularBuffer::Remove(size_t count) {
|
||||
if (count > GetUsedSpace()) {
|
||||
// can't remove more than there is
|
||||
return false;
|
||||
}
|
||||
|
||||
fill_ -= count;
|
||||
tail_ = (tail_ + count) % buffer_.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace oemprofiler
|
||||
} // namespace wvcdm
|
||||
109
libwvdrmengine/cdm/profiler/src/entry_writer.cpp
Normal file
109
libwvdrmengine/cdm/profiler/src/entry_writer.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "entry_writer.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace wvcdm {
|
||||
namespace oemprofiler {
|
||||
|
||||
static const uint64_t MAX_VALUES_FOR_BYTES[8] = {
|
||||
0x000000000000001F,
|
||||
0x0000000000001FFF,
|
||||
0x00000000001FFFFF,
|
||||
0x000000001FFFFFFF,
|
||||
0x0000001FFFFFFFFF,
|
||||
0x00001FFFFFFFFFFF,
|
||||
0x001FFFFFFFFFFFFF,
|
||||
0x1FFFFFFFFFFFFFFF
|
||||
};
|
||||
|
||||
static const uint64_t CODE_FOR_BYTES[8] = {
|
||||
0x0000000000000000,
|
||||
0x0000000000002000,
|
||||
0x0000000000400000,
|
||||
0x0000000060000000,
|
||||
0x0000008000000000,
|
||||
0x0000A00000000000,
|
||||
0x00C0000000000000,
|
||||
0xE000000000000000
|
||||
};
|
||||
|
||||
EntryWriter::EntryWriter() : write_head_(0){ }
|
||||
|
||||
const uint8_t* EntryWriter::GetData() const { return bytes_; }
|
||||
|
||||
size_t EntryWriter::GetSize() const { return write_head_; }
|
||||
|
||||
int EntryWriter::WriteU8(uint8_t value) { return Write(value); }
|
||||
|
||||
int EntryWriter::WriteU16(uint16_t value) { return Write(value); }
|
||||
|
||||
int EntryWriter::WriteU32(uint32_t value) { return Write(value); }
|
||||
|
||||
int EntryWriter::WriteU64(uint64_t value) { return Write(value); }
|
||||
|
||||
int EntryWriter::WriteVLV(uint64_t value) {
|
||||
for (size_t i = 0; i < sizeof(uint64_t); i++) {
|
||||
if (value <= MAX_VALUES_FOR_BYTES[i]) {
|
||||
return Write(value | CODE_FOR_BYTES[i], i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
LOGE("writeVariableLengthValue - value too large for variable length value");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int EntryWriter::Write(uint64_t v, size_t num_bytes) {
|
||||
if (num_bytes > sizeof(uint64_t)) {
|
||||
LOGE("read - cannot read %zu bytes when 8 bytes are the max", num_bytes);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (GetFreeSpace() < num_bytes) {
|
||||
LOGE("write - cannot write %zu when there are only %zu bytes remaining",
|
||||
num_bytes, GetFreeSpace());
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = num_bytes; i > 0; i--) {
|
||||
bytes_[write_head_] = GetByte(v, i - 1);
|
||||
write_head_++;
|
||||
}
|
||||
|
||||
return static_cast<int>(num_bytes);
|
||||
}
|
||||
|
||||
void EntryWriter::Clear() {
|
||||
write_head_ = 0;
|
||||
}
|
||||
|
||||
size_t EntryWriter::GetFreeSpace() const {
|
||||
return kBufferSize - write_head_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int EntryWriter::Write(T v) {
|
||||
// start the values at index 1 so that the number of bytes
|
||||
// line up with the shift value
|
||||
static const size_t shifts[8] = { 0, 8, 16, 24, 32, 40, 48, 56 };
|
||||
|
||||
if (GetFreeSpace() < sizeof(T)) {
|
||||
LOGE("write - cannot write %zu when there are only %zu bytes remaining",
|
||||
sizeof(T), GetFreeSpace());
|
||||
return -1; // there is not enough room
|
||||
}
|
||||
|
||||
for (int i = sizeof(T) - 1; i >= 0; i--) {
|
||||
bytes_[write_head_] = (uint8_t)((v >> shifts[i]) & 0xFF);
|
||||
write_head_++;
|
||||
}
|
||||
|
||||
return (int)sizeof(T);
|
||||
}
|
||||
|
||||
uint8_t EntryWriter::GetByte(uint64_t value, size_t byte_index) {
|
||||
return static_cast<uint8_t>(0xFF & (value >> (byte_index * 8)));
|
||||
}
|
||||
|
||||
} // oem profiler
|
||||
} // wvcdm
|
||||
66
libwvdrmengine/cdm/profiler/src/profiled_scope.cpp
Normal file
66
libwvdrmengine/cdm/profiler/src/profiled_scope.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved
|
||||
|
||||
#include "profiled_scope.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "profiler_session.h"
|
||||
|
||||
namespace wvcdm {
|
||||
namespace oemprofiler {
|
||||
|
||||
ProfiledScope::ProfiledScope(OEM_FUNCTION fid) :
|
||||
meta_data_(),
|
||||
sid_(kGlobalSID),
|
||||
fid_(fid),
|
||||
start_time_(GetNowUS()) {
|
||||
|
||||
}
|
||||
|
||||
// Only allow a user provided sid to be a positive integer
|
||||
// to prevent a user provided sid from conflicting with the
|
||||
// global sid
|
||||
ProfiledScope::ProfiledScope(uint32_t sid, OEM_FUNCTION fid) :
|
||||
meta_data_(),
|
||||
sid_(static_cast<int64_t>(sid)),
|
||||
fid_(fid),
|
||||
start_time_(GetNowUS()) {
|
||||
|
||||
}
|
||||
|
||||
ProfiledScope::~ProfiledScope() {
|
||||
const uint64_t end_time = GetNowUS();
|
||||
|
||||
if (sid_ != kGlobalSID) {
|
||||
Submit(sid_, end_time);
|
||||
}
|
||||
|
||||
// Always save a copy to the global session so that all other sessions
|
||||
// are subsets of the global session
|
||||
Submit(kGlobalSID, end_time);
|
||||
}
|
||||
|
||||
void ProfiledScope::Submit(int64_t sid, uint64_t end_time) const {
|
||||
ProfilerSession* const session = ProfilerSession::Find(sid);
|
||||
|
||||
if (session != NULL) {
|
||||
session->Submit(
|
||||
fid_,
|
||||
start_time_,
|
||||
end_time,
|
||||
meta_data_.GetData(),
|
||||
meta_data_.GetSize());
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ProfiledScope::GetNowUS() const {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
const uint64_t kSecondsToUSeconds = 1000000;
|
||||
return static_cast<uint64_t>(tv.tv_sec) * kSecondsToUSeconds +
|
||||
static_cast<uint64_t>(tv.tv_usec);
|
||||
}
|
||||
|
||||
} // namespace oemprofiler
|
||||
} // namespace wvcdm
|
||||
229
libwvdrmengine/cdm/profiler/src/profiler_session.cpp
Normal file
229
libwvdrmengine/cdm/profiler/src/profiler_session.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "profiler_session.h"
|
||||
|
||||
#include <log.h>
|
||||
|
||||
namespace wvcdm {
|
||||
namespace oemprofiler {
|
||||
|
||||
namespace {
|
||||
const size_t kProfilingMemoryBudget = 1024; // 1 KB
|
||||
}
|
||||
|
||||
std::map<int64_t, ProfilerSession*> ProfilerSession::sessions_;
|
||||
|
||||
ProfilerSession::ProfilerSession() :
|
||||
buffer_(kProfilingMemoryBudget),
|
||||
time_at_head_(0),
|
||||
time_at_tail_(0) {
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
void ProfilerSession::Submit(
|
||||
OEM_FUNCTION fid,
|
||||
uint64_t start_time,
|
||||
uint64_t end_time,
|
||||
const uint8_t* meta_data,
|
||||
size_t meta_data_length) {
|
||||
|
||||
EntryWriter header;
|
||||
header.WriteU8(fid);
|
||||
header.WriteVLV(start_time - time_at_tail_);
|
||||
header.WriteVLV(end_time - start_time);
|
||||
|
||||
const size_t total_packet_size = header.GetSize() + meta_data_length;
|
||||
|
||||
// The max size for a VLV is 8 bytes and the max size for a entry
|
||||
// writer is 32 bytes. Normally the meta data will be packed using
|
||||
// an entry writer so the max packet size will be 64 bytes. Since the
|
||||
// packet size is encoded with a single byte, the packet must first
|
||||
// be checked to ensure it is not too large for the cast.
|
||||
if (total_packet_size <= 255 && RequestSpace(total_packet_size + 1)) {
|
||||
buffer_.AddU8(static_cast<uint8_t>(total_packet_size));
|
||||
buffer_.AddU8s(header.GetData(), header.GetSize());
|
||||
buffer_.AddU8s(meta_data, meta_data_length);
|
||||
|
||||
time_at_tail_ = end_time;
|
||||
}
|
||||
|
||||
stats_[fid].Update(end_time - start_time);
|
||||
}
|
||||
|
||||
void ProfilerSession::Clear(){
|
||||
buffer_.Remove(buffer_.GetUsedSpace());
|
||||
|
||||
// the buffer is cleared so we reseting these values is clean and safe
|
||||
time_at_tail_ = time_at_head_ = 0;
|
||||
|
||||
for (size_t i = 0; i < OEM_FUNCTION_COUNT; i++) {
|
||||
stats_[i].Reset();
|
||||
}
|
||||
}
|
||||
|
||||
void ProfilerSession::ReadHistory(std::vector<uint8_t>& output) const {
|
||||
// write the tail time
|
||||
for (size_t i = 1; i <= sizeof(time_at_head_); i++) {
|
||||
output.push_back(GetByte(time_at_head_, sizeof(time_at_head_) - i));
|
||||
}
|
||||
|
||||
// write the whole circular buffer into the output buffer
|
||||
const size_t num_bytes = buffer_.GetUsedSpace();
|
||||
for (size_t i = 0; i < num_bytes; i++) {
|
||||
uint8_t b;
|
||||
if (buffer_.PeekU8(i, &b)) {
|
||||
output.push_back(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProfilerSession::ReadAllStats(std::vector<uint8_t>& output) const {
|
||||
|
||||
uint64_t values_to_write[7];
|
||||
EntryWriter writer;
|
||||
|
||||
const size_t num_values_to_write =
|
||||
sizeof(values_to_write) / sizeof(values_to_write[0]);
|
||||
|
||||
// make sure there is enough room
|
||||
output.reserve(
|
||||
output.size() + OEM_FUNCTION_COUNT * sizeof(values_to_write));
|
||||
|
||||
for(size_t fid = 0; fid < OEM_FUNCTION_COUNT; fid++) {
|
||||
const Stat& stat = stats_[fid];
|
||||
|
||||
values_to_write[0] = stat.GetSampleSize();
|
||||
values_to_write[1] = stat.GetMin();
|
||||
values_to_write[2] = stat.GetMax();
|
||||
values_to_write[3] = static_cast<uint64_t>(stat.GetMean());
|
||||
values_to_write[4] = static_cast<uint64_t>(stat.GetMean() * 100) % 100;
|
||||
values_to_write[5] = static_cast<uint64_t>(stat.GetVariance());
|
||||
values_to_write[6] = static_cast<uint64_t>(stat.GetVariance() * 100) % 100;
|
||||
|
||||
for (size_t i = 0; i < num_values_to_write; i++) {
|
||||
writer.Clear();
|
||||
writer.WriteU64(values_to_write[i]);
|
||||
|
||||
for (size_t w_index = 0; w_index < writer.GetSize(); w_index++) {
|
||||
output.push_back(writer.GetData()[w_index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Stat& ProfilerSession::ReadStat(OEM_FUNCTION fid) const {
|
||||
return stats_[fid];
|
||||
}
|
||||
|
||||
bool ProfilerSession::RequestSpace(uint8_t num_bytes) {
|
||||
// check if it is possible to make enough room
|
||||
const size_t buffer_size = buffer_.GetFreeSpace() +
|
||||
buffer_.GetUsedSpace();
|
||||
|
||||
if (num_bytes > buffer_size) {
|
||||
LOGE("Requesting more space than possible (requested = %u, max = %zu)",
|
||||
num_bytes, buffer_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
// drop entries until we have enough space
|
||||
while (num_bytes > buffer_.GetFreeSpace() && DropLastEntry());
|
||||
|
||||
return num_bytes <= buffer_.GetFreeSpace();
|
||||
}
|
||||
|
||||
bool ProfilerSession::ReadNextEntryRealEndTime(uint64_t* output) {
|
||||
if (output == NULL) {
|
||||
LOGE("Cannout output to null pointer");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t initial_time_start_index = 2;
|
||||
|
||||
uint64_t initial_time;
|
||||
const int initial_time_length =
|
||||
ReadVLV(initial_time_start_index, &initial_time);
|
||||
|
||||
if (initial_time_length == -1) {
|
||||
LOGE("Failed to read the start time for head entry");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t delta_time;
|
||||
const int delta_time_length = ReadVLV(
|
||||
initial_time_start_index + initial_time_length, &delta_time);
|
||||
|
||||
if (delta_time_length == -1) {
|
||||
LOGE("Failed to read the delta time for head entry");
|
||||
return false;
|
||||
}
|
||||
|
||||
*output = time_at_head_ + initial_time + delta_time;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProfilerSession::DropLastEntry() {
|
||||
uint8_t entry_size;
|
||||
uint64_t end_time;
|
||||
|
||||
if(buffer_.PeekU8(0, &entry_size) && ReadNextEntryRealEndTime(&end_time)) {
|
||||
// + 1 because the entry size byte needs to be removed too
|
||||
if (buffer_.Remove(entry_size + 1)) {
|
||||
time_at_head_ = end_time;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int ProfilerSession::ReadVLV(size_t offset, uint64_t* output) const {
|
||||
uint8_t first_byte;
|
||||
if (buffer_.PeekU8(offset, &first_byte)) {
|
||||
const size_t num_bytes = (first_byte >> 5) + 1;
|
||||
|
||||
uint64_t value = first_byte & 0x1F;
|
||||
for (size_t i = 1; i < num_bytes; i++) {
|
||||
uint8_t next_byte;
|
||||
if (buffer_.PeekU8(offset + i, &next_byte)) {
|
||||
value = value << 8 | next_byte;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
*output = value;
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t ProfilerSession::GetByte(uint64_t value, size_t byte_index) {
|
||||
return (uint8_t)(0xFF & (value >> (byte_index * 8)));
|
||||
}
|
||||
|
||||
void ProfilerSession::Open(int64_t sid) {
|
||||
if (sessions_.count(sid) == 0) {
|
||||
sessions_.insert(
|
||||
std::pair<int64_t, ProfilerSession*>(sid, new ProfilerSession()));
|
||||
}
|
||||
}
|
||||
|
||||
void ProfilerSession::Close(int64_t sid) {
|
||||
if(sessions_.count(sid) > 0) {
|
||||
ProfilerSession* session = sessions_.at(sid);
|
||||
sessions_.erase(sid);
|
||||
|
||||
delete session;
|
||||
}
|
||||
}
|
||||
|
||||
ProfilerSession* ProfilerSession::Find(int64_t sid) {
|
||||
return sessions_.count(sid) > 0 ? sessions_.at(sid) : NULL;
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
} // namespace oemprofiler
|
||||
|
||||
50
libwvdrmengine/cdm/profiler/src/stats.cpp
Normal file
50
libwvdrmengine/cdm/profiler/src/stats.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "stats.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
namespace wvcdm {
|
||||
namespace oemprofiler {
|
||||
|
||||
Stat::Stat() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Stat::Update(uint64_t sample) {
|
||||
min_ = std::min(min_, sample);
|
||||
max_ = std::max(max_, sample);
|
||||
|
||||
mean_ = ((mean_ * count_) + sample) / (count_ + 1.0);
|
||||
count_ += 1;
|
||||
|
||||
// Welford's method for standard deviation / variance
|
||||
const double old_sdev_m = sdev_m_;
|
||||
const double old_sdev_s = sdev_s_;
|
||||
|
||||
sdev_m_ = old_sdev_m + (sample - old_sdev_m) / count_;
|
||||
sdev_s_ = old_sdev_s + (sample - sdev_m_) * (sample - old_sdev_m);
|
||||
}
|
||||
|
||||
void Stat::Reset() {
|
||||
min_ = std::numeric_limits<uint64_t>::max();
|
||||
max_ = count_ = 0;
|
||||
|
||||
mean_ = sdev_m_ = sdev_s_ = 0.0;
|
||||
}
|
||||
|
||||
uint64_t Stat::GetMin() const { return min_; }
|
||||
|
||||
uint64_t Stat::GetMax() const { return max_; }
|
||||
|
||||
uint64_t Stat::GetSampleSize() const { return count_; }
|
||||
|
||||
double Stat::GetMean() const { return mean_; }
|
||||
|
||||
double Stat::GetVariance() const {
|
||||
return count_ > 1 ? sdev_s_ / (count_ - 1) : 0;
|
||||
}
|
||||
|
||||
} // namespace oemprofiler
|
||||
} // namespace wvcdm
|
||||
Reference in New Issue
Block a user