Merge pull request #380 from microsoft/maharrim/vector

Avoid reallocate-and-copy in TPM
This commit is contained in:
larvacea 2020-05-15 11:31:28 -07:00 коммит произвёл GitHub
Родитель 6b5062859f 15e68217c5
Коммит 64c5f633b8
5 изменённых файлов: 126 добавлений и 118 удалений

Просмотреть файл

@ -6,11 +6,13 @@
#include "Enums.hpp"
#include <cstdint>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
#include <array>
#include <atomic>
#include <cstdint>
#include <map>
#include <string>
#include <vector>
/// @cond INTERNAL_DOCS
@ -33,6 +35,11 @@ namespace ARIASDK_NS_BEGIN
/// </summary>
static const size_t MAX_TIMERS_SIZE = 3;
/// <summary>
/// Type alias for the array of timer values set by getTimers()
/// </summary>
using TimerArray = std::array<int, 2>;
/// <summary>
/// The TransmitProfileRule structure contains transmission timer values in particular device states (net+power).
/// </summary>
@ -128,7 +135,7 @@ namespace ARIASDK_NS_BEGIN
/// <summary>
/// A boolean value that indicates whether the timer was updated.
/// </summary>
static bool isTimerUpdated;
static std::atomic<bool> isTimerUpdated;
static void UpdateProfiles(const std::vector<TransmitProfileRules>& newProfiles) noexcept;
@ -203,7 +210,7 @@ namespace ARIASDK_NS_BEGIN
/// Gets the current priority timers.
/// </summary>
/// <param name="out">A reference to a vector of integers that will contain the current timers.</param>
static void getTimers(std::vector<int>& out);
static void getTimers(TimerArray& out);
/// <summary>
/// Gets the name of the current transmit profile.

Просмотреть файл

@ -14,8 +14,8 @@ namespace ARIASDK_NS_BEGIN {
MATSDK_LOG_INST_COMPONENT_CLASS(TransmissionPolicyManager, "EventsSDK.TPM", "Events telemetry client - TransmissionPolicyManager class");
TransmissionPolicyManager::TransmissionPolicyManager(ITelemetrySystem& system, ITaskDispatcher& taskDispatcher, IBandwidthController* bandwidthController)
: m_lock(),
TransmissionPolicyManager::TransmissionPolicyManager(ITelemetrySystem& system, ITaskDispatcher& taskDispatcher, IBandwidthController* bandwidthController) :
m_lock(),
m_system(system),
m_taskDispatcher(taskDispatcher),
m_config(m_system.getConfig()),
@ -23,9 +23,9 @@ namespace ARIASDK_NS_BEGIN {
m_isPaused(true),
m_isUploadScheduled(false),
m_scheduledUploadTime(std::numeric_limits<uint64_t>::max()),
m_scheduledUploadAborted(false),
m_timerdelay(DEFAULT_DELAY_SEND_HTTP),
m_runningLatency(EventLatency_RealTime),
m_scheduledUploadAborted(false)
m_runningLatency(EventLatency_RealTime)
{
m_backoffConfig = "E,3000,300000,2,1";
m_backoff = IBackoff::createFromConfig(m_backoffConfig);
@ -105,7 +105,7 @@ namespace ARIASDK_NS_BEGIN {
return;
}
if (m_timers.size() > 2 && m_timers[0] < 0) {
if (m_timers[0] < 0) {
latency = std::max(latency, EventLatency_RealTime); // low priority disabled by profile
}
@ -282,11 +282,8 @@ namespace ARIASDK_NS_BEGIN {
if (TransmitProfiles::isTimerUpdateRequired())
{
TransmitProfiles::getTimers(m_timers);
if (m_timers.size() > 2)
{
m_timerdelay = m_timers[2];
forceTimerRestart = true;
}
m_timerdelay = m_timers[1];
forceTimerRestart = true;
}
EventLatency proposed = calculateNewPriority();
if (m_timerdelay >= 0) {
@ -300,20 +297,17 @@ namespace ARIASDK_NS_BEGIN {
// We alternate RealTime and Normal otherwise (timers differ)
EventLatency TransmissionPolicyManager::calculateNewPriority()
{
if (m_timers.size() < 3) {
return EventLatency_Normal;
}
if (m_timers[0] < 0) {
return EventLatency_RealTime;
}
if (m_timers[0] == m_timers[2])
if (m_timers[0] == m_timers[1])
{
return EventLatency_Normal;
}
if (m_runningLatency == EventLatency_RealTime)
if (m_timers[0] < 0)
{
return EventLatency_RealTime;
}
if (m_runningLatency == EventLatency_RealTime)
{
return EventLatency_Normal;
}

Просмотреть файл

@ -14,9 +14,11 @@
#include "DeviceStateHandler.hpp"
#include "pal/TaskDispatcher.hpp"
#include <set>
#include "TransmitProfiles.hpp"
#include <atomic>
#include <cstdint>
#include <set>
// This macro allows to specify max upload task cancellation wait time at compile-time,
// addressing the case when a task that we are trying to cancel is currently running.
@ -144,7 +146,7 @@ namespace ARIASDK_NS_BEGIN {
int m_timerdelay;
EventLatency m_runningLatency;
std::vector<int> m_timers;
TimerArray m_timers;
public:
RoutePassThrough<TransmissionPolicyManager> start{ this, &TransmissionPolicyManager::handleStart };

Просмотреть файл

@ -102,7 +102,7 @@ static void initTransmitProfileFields()
transmitProfilePowerState["charging"] = (PowerSource_Charging);
};
#define LOCK_PROFILES std::lock_guard<std::mutex> lock(profiles_mtx)
#define LOCK_PROFILES std::lock_guard<std::recursive_mutex> lock(profiles_mtx)
namespace ARIASDK_NS_BEGIN {
@ -110,13 +110,13 @@ namespace ARIASDK_NS_BEGIN {
static const char* ATTR_NAME = "name"; /// <summary>name attribute</summary>
static const char* ATTR_RULES = "rules"; /// <summary>rules attribute</summary>
static std::mutex profiles_mtx;
static std::recursive_mutex profiles_mtx;
map<string, TransmitProfileRules> TransmitProfiles::profiles;
string TransmitProfiles::currProfileName = DEFAULT_PROFILE;
size_t TransmitProfiles::currRule = 0;
NetworkCost TransmitProfiles::currNetCost = NetworkCost::NetworkCost_Any;
PowerSource TransmitProfiles::currPowState = PowerSource::PowerSource_Any;
bool TransmitProfiles::isTimerUpdated = true;
std::atomic<bool> TransmitProfiles::isTimerUpdated(true);
/// <summary>
/// Get current transmit profile name
@ -176,40 +176,39 @@ namespace ARIASDK_NS_BEGIN {
void TransmitProfiles::UpdateProfiles(const std::vector<TransmitProfileRules>& newProfiles) noexcept
{
LOCK_PROFILES;
removeCustomProfiles();
// Add new profiles
for (const auto& profile : newProfiles)
{
LOCK_PROFILES;
removeCustomProfiles();
// Add new profiles
for (const auto& profile : newProfiles)
{
profiles[profile.name] = profile;
}
// Check if profile is still valid. If no such profile loaded anymore, then switch to default.
auto it = profiles.find(currProfileName);
if (it == profiles.end())
{
currProfileName = DEFAULT_PROFILE;
LOG_TRACE("Switched to profile %s", currProfileName.c_str());
}
profiles[profile.name] = profile;
}
// Check if profile is still valid. If no such profile loaded anymore, then switch to default.
auto it = profiles.find(currProfileName);
if (it == profiles.end())
{
currProfileName = DEFAULT_PROFILE;
LOG_TRACE("Switched to profile %s", currProfileName.c_str());
}
#ifdef HAVE_MAT_LOGGING
// Print combined list of profiles: default + custom
LOG_TRACE("Profiles:");
size_t i = 0;
for (const auto& kv : profiles)
{
LOG_TRACE("[%d] %s%s", i, kv.first.c_str(),
(!kv.first.compare(currProfileName)) ? " [active]" : "");
i++;
}
// Print combined list of profiles: default + custom
LOG_TRACE("Profiles:");
size_t i = 0;
for (const auto& kv : profiles)
{
LOG_TRACE("[%d] %s%s", i, kv.first.c_str(),
(!kv.first.compare(currProfileName)) ? " [active]" : "");
i++;
}
#endif
currRule = 0;
} // Unlock here because updateStates performs its own LOCK_PROFILES
currRule = 0;
updateStates(currNetCost, currPowState);
}
void TransmitProfiles::EnsureDefaultProfiles() noexcept
{
LOCK_PROFILES;
if (profiles.size() == 0)
{
LOG_TRACE("Loading default profiles...");
@ -426,27 +425,18 @@ namespace ARIASDK_NS_BEGIN {
bool TransmitProfiles::setProfile(const std::string& profileName) {
bool result = false;
// We do not lock it here, but it's OK because reset would lock if
// needed. We're reading an integer value typically on non-empty
// collection and not modifying it without a lock.
if (profiles.size() == 0) {
// Load default profiles if nothing is loaded yet
reset();
EnsureDefaultProfiles();
LOCK_PROFILES;
auto it = profiles.find(profileName);
if (it != profiles.end()) {
currProfileName = profileName;
LOG_INFO("selected profile %s ...", profileName.c_str());
result = true;
}
{
LOCK_PROFILES;
auto it = profiles.find(profileName);
if (it != profiles.end()) {
currProfileName = profileName;
LOG_INFO("selected profile %s ...", profileName.c_str());
result = true;
}
else {
LOG_WARN("profile %s not found!", profileName.c_str());
currProfileName = DEFAULT_PROFILE;
LOG_WARN("selected profile %s instead", currProfileName.c_str());
}
else {
LOG_WARN("profile %s not found!", profileName.c_str());
currProfileName = DEFAULT_PROFILE;
LOG_WARN("selected profile %s instead", currProfileName.c_str());
}
updateStates(currNetCost, currPowState);
return result;
@ -456,27 +446,44 @@ namespace ARIASDK_NS_BEGIN {
/// Get the current list of priority timers
/// </summary>
/// <returns></returns>
void TransmitProfiles::getTimers(std::vector<int>& out) {
{
out.clear();
if (profiles.size() == 0) {
// Load default profiles if nothing is loaded yet
reset();
}
LOCK_PROFILES;
auto it = profiles.find(currProfileName);
if (it == profiles.end()) {
for (size_t i = 0; i < MAX_TIMERS_SIZE; i++) {
out.push_back(-1);
}
LOG_WARN("No active profile found, disabling all transmission timers.");
return;
}
for (int timer : (it->second).rules[currRule].timers) {
out.push_back(timer * 1000);// convert time in milisec
}
isTimerUpdated = false;
void TransmitProfiles::getTimers(TimerArray& out) {
EnsureDefaultProfiles();
LOCK_PROFILES;
auto it = profiles.find(currProfileName);
// When we can't get timers, we won't set isTimerUpdated to false,
// so we will keep calling getTimers from TransmissionPolicyManager.
if (it == profiles.end()) {
out.fill(-1);
LOG_WARN("No active profile found, disabling all transmission timers.");
return;
}
if (currRule >= it->second.rules.size()) {
out.fill(-1);
LOG_ERROR(
"Profile %s current rule %iz >= profile length %iz",
currProfileName.c_str(),
currRule,
it->second.rules.size()
);
return;
}
auto const & rule = (it->second).rules[currRule];
if (rule.timers.empty()) {
out.fill(-1);
LOG_ERROR(
"Profile %s rule %iz has no timers",
currProfileName.c_str(),
currRule
);
return;
}
out[0] = 1000 * rule.timers[0];
out[1] = out[0];
if (rule.timers.size() > 2) {
out[1] = 1000 * rule.timers[2];
}
isTimerUpdated = false;
}
/// <summary>
@ -513,30 +520,28 @@ namespace ARIASDK_NS_BEGIN {
/// <param name="powState"></param>
bool TransmitProfiles::updateStates(NetworkCost netCost, PowerSource powState) {
bool result = false;
// remember the current state in case if profile change happens
LOCK_PROFILES;
currNetCost = netCost;
currPowState = powState;
{
LOCK_PROFILES;
auto it = profiles.find(currProfileName);
if (it != profiles.end()) {
auto &profile = it->second;
// Search for a matching rule. If not found, then return the first (the most restrictive) rule in the list.
currRule = 0;
for (size_t i = 0; i < profile.rules.size(); i++) {
const auto &rule = profile.rules[i];
if ((
(rule.netCost == netCost) || (NetworkCost::NetworkCost_Any == netCost) || (NetworkCost::NetworkCost_Any == rule.netCost)) &&
((rule.powerState == powState) || (PowerSource::PowerSource_Any == powState) || (PowerSource::PowerSource_Any == rule.powerState))
)
{
currRule = i;
result = true;
break;
}
auto it = profiles.find(currProfileName);
if (it != profiles.end()) {
auto &profile = it->second;
// Search for a matching rule. If not found, then return the first (the most restrictive) rule in the list.
currRule = 0;
for (size_t i = 0; i < profile.rules.size(); i++) {
const auto &rule = profile.rules[i];
if ((
(rule.netCost == netCost) || (NetworkCost::NetworkCost_Any == netCost) || (NetworkCost::NetworkCost_Any == rule.netCost)) &&
((rule.powerState == powState) || (PowerSource::PowerSource_Any == powState) || (PowerSource::PowerSource_Any == rule.powerState))
)
{
currRule = i;
result = true;
break;
}
onTimersUpdated();
}
onTimersUpdated();
}
return result;
}

Просмотреть файл

@ -98,14 +98,14 @@ TEST_F(TransmissionPolicyManagerTests, StopLeavesNoScheduledUploads)
{
tpm.paused(false);
EXPECT_CALL(tpm, scheduleUpload(1000, EventLatency_Normal, false))
EXPECT_CALL(tpm, scheduleUpload(1000, AnyOf(EventLatency_Normal, EventLatency_RealTime), false))
.WillOnce(Return());
tpm.start();
size_t i = 1000;
while (i--)
{
EXPECT_CALL(tpm, scheduleUpload(_, EventLatency_Normal, false))
EXPECT_CALL(tpm, scheduleUpload(_, AnyOf(EventLatency_Normal, EventLatency_RealTime), false))
.Times(3)
.WillOnce(Return())
.WillOnce(Return())