// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== // =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // // HillClimbing.h // // Defines classes for the HillClimbing concurrency-optimization algorithm. // // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #pragma once namespace Concurrency { namespace details { /// /// An enum representing all possible hill climbing transition moves. /// enum HillClimbingStateTransition { Warmup, ContinueInitializing, CompletedInitialization, DoClimbing, ChangePoint, ContinueLookingForClimb, Undefined, }; /// /// A class responsible for hill climbing. /// class HillClimbing { public: /// /// Creates a new instance of hill climbing. /// /// /// Scheduler id. /// /// /// Number that represents the maximum resources available on the machine. /// /// /// The scheduler proxy that controls this hill climbing instance. /// HillClimbing(unsigned int id, unsigned int numberOfCores, SchedulerProxy * pSchedulerProxy); /// /// External call passing statistical information to hill climbing. Based on these /// statistics, hill climbing will give a recommendation on the number of resources to be used. /// /// /// The control setting used in this period of time. /// /// /// The number of completed units or work in that period of time. /// /// /// The number of incoming units or work in that period of time. /// /// /// The total length of the work queue. /// /// /// The recommended number of resources to be used. /// unsigned int Update(unsigned int currentControlSetting, unsigned int completionRate, unsigned int arrivalRate, unsigned int queueLength); private: /// /// A class responsible for keeping hill climbing history measurements. /// class MeasuredHistory { public: /// /// Creates a new measurement history. /// MeasuredHistory(); /// /// Adds a new history data point. /// /// /// The value representing throughput in this invocation. /// /// /// The value representing the total number of samples for this history, including invalid samples and samples for previous settings. /// void Add(const double data, unsigned int totalSampleCount); /// /// Clears the history values for this control setting. /// /// /// The control setting to reset. /// void Clear(unsigned int controlSetting); /// /// Gets the count for this history measurement. /// /// /// The count. /// int Count(); /// /// Gets the count at the last data point for this history measurement. /// /// /// The last data point count. /// unsigned int LastDataPointCount(); /// /// Gets the control setting for this history measurement. /// /// /// The control setting. /// int ControlSetting(); /// /// Computes the mean for a given history. /// /// /// The mean. /// double Mean(); /// /// Computes the coefficient of variation for a given history. /// /// /// The coefficient of variation. /// double CoefficientOfVariation(); /// /// Computes the mean of coefficients of variation for a given history. /// /// /// The mean of coefficients of variation. /// double CoefficientOfVariationMean(); /// /// Computes the variance for a given history. /// /// /// The variance. /// double Variance(); /// /// Computes the mean of variances for a given history. /// /// /// The mean of variances. /// double VarianceMean(); /// /// Computes the standard deviation for a given history. /// /// /// The standard deviation. /// double StandardDeviation(); /// /// Computes the mean of standard deviations for a given history. /// /// /// The mean of standard deviations. /// double StandardDeviationMean(); /// /// Tests if the difference between two measurement histories is statistically significant to /// make a hill climbing decision. /// /// /// A two sided test is used. /// /// /// The value representing the second history. /// /// /// The significance level in percent. Accepts 1 through 10. /// /// /// The value representing the total number of samples for this history, including invalid samples and samples for previous settings. /// /// /// -1 - second history is larger than this history /// 0 - statistically identical /// 1 - this history is larger than second history /// int SignificanceTest(double value, const int significanceLevel, unsigned int totalSampleCount); /// /// Tests if the difference between two measurement histories is statistically significant to /// make a hill climbing decision. /// /// /// A two sided test is used. /// /// /// The pointer to second measurement history. /// /// /// The significance level in percent. Accepts 1 through 10. /// /// /// -1 - second history is larger than this history /// 0 - statistically identical /// 1 - this history is larger than second history /// int SignificanceTest(MeasuredHistory * pMeasuredHistory, const int significanceLevel); private: // Running sum of throughputs double m_sum; // Sum of throughput squares double m_sumOfSquares; // Count of measurements in this history int m_count; // An integer representing the control setting for this history measurement int m_controlSetting; // Last count value when a measurement was taken (used for relevance test) unsigned int m_lastDataPointCount; }; /// /// Makes a pseudo-random hill climbing move by alternating between up and down. /// /// /// The random move. /// int GetRandomMove(); /// /// Recommends NewControlSetting to be used. /// /// /// The control setting to be established. /// /// /// New control setting to be used. /// unsigned RecommendControlSetting(unsigned int newControlSetting); /// /// Establishes control setting as current. This is the only method that updates the control settings. /// /// /// The control setting to be established. /// void EstablishControlSetting(unsigned int newControlSetting); /// /// Determines whether a given history measurement is stable enough to make a hill climbing move. /// /// /// True if history measurement is stable. /// bool IsStableHistory(MeasuredHistory * pMeasuredHistory); /// /// Calculates the throughput based on the input parameters. /// /// /// The number of sample points in this measurement, including invalid ones. /// /// /// The number of completed units or work in that period of time. /// /// /// The number of incoming units or work in that period of time. /// /// /// The total length of the work queue. /// /// /// The calculated throughput. /// double CalculateThroughput(unsigned int numberOfSamples, unsigned int completionRate, unsigned int arrivalRate, unsigned int queueLength); /// /// Calculates the throughput gradient given two history measurements. /// /// /// The control setting to move from. /// /// /// The control setting to move to. /// /// /// A value representing a gradient between two measurements. /// double CalculateThroughputGradient(int fromSetting, int toSetting); /// /// Flushes all measurement histories that are no longer relevant. /// void FlushHistories(); /// /// Clears all measurement histories. /// void ClearHistories(); /// /// Gets the history measurement for a given control setting. /// /// /// The history measurement. /// MeasuredHistory * GetHistory(unsigned int controlSetting); // The maximum number of histories to keep static const unsigned int MaxHistoryCount = 64; // The array where history data is kept MeasuredHistory m_histories[MaxHistoryCount]; // Scheduler proxy to which this hill climbing instance belongs SchedulerProxy * m_pSchedulerProxy; // Used to determine the magnitude of moves, in units of (coefficient of variation)/(thread count) double m_controlGain; // Maximum number of resources that can be changed in one transition unsigned int m_maxControlSettingChange; // The current amount of resources allocated in this hill climbing instance unsigned int m_currentControlSetting; // The amount of resources allocated in this hill climbing instance before the last move unsigned int m_lastControlSetting; // Scheduler id unsigned int m_id; // Number of samples collected unsigned long m_sampleCount; // Number of samples collected including invalid samples, across settings unsigned long m_totalSampleCount; // Number of consecutive invalid samples unsigned long m_invalidCount; // Save sum of completions for consecutive invalid samples unsigned int m_saveCompleted; // Save sum of arrivals for consecutive invalid samples unsigned int m_saveIncoming; // Determines where the next random move is going bool m_nextRandomMoveIsUp; #if defined(CONCRT_TRACING) /// /// Logs the hill climbing decision by constructing a CSV dump of data. /// /// /// The control setting to be established. /// /// /// The transition that is recommended by hill climbing. /// /// /// The number of sample points in this measurement, including invalid ones. /// /// /// The number of completed units or work in that period of time. /// /// /// The number of incoming units or work in that period of time. /// /// /// The total length of the work queue. /// /// /// The throughput of the given instance. /// void LogData(unsigned int recommendedSetting, HillClimbingStateTransition transition, unsigned int numberOfSamples, unsigned int completionRate, unsigned int arrivalRate, unsigned int queueLength, double throughput); #endif }; } // namespace details } // namespace Concurrency