Merge pull request #380 from microsoft/maharrim/vector
Avoid reallocate-and-copy in TPM
This commit is contained in:
Коммит
64c5f633b8
|
@ -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())
|
||||
|
|
Загрузка…
Ссылка в новой задаче