| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_DEVELOPER_SYSTEM_MONITOR_LIB_DOCKYARD_DOCKYARD_H_ |
| #define SRC_DEVELOPER_SYSTEM_MONITOR_LIB_DOCKYARD_DOCKYARD_H_ |
| |
| #include <stdint.h> |
| |
| #include <atomic> |
| #include <functional> |
| #include <iostream> |
| #include <map> |
| #include <mutex> |
| #include <set> |
| #include <sstream> |
| #include <string> |
| #include <thread> |
| #include <vector> |
| |
| class SystemMonitorDockyardHostTest; |
| namespace grpc { |
| class Server; |
| } // namespace grpc |
| |
| namespace dockyard { |
| |
| class DockyardServiceImpl; |
| class SystemMonitorDockyardTest; |
| |
| // An integer value representing a dockyard path. |
| typedef uint32_t DockyardId; |
| constexpr DockyardId INVALID_DOCKYARD_ID = 0; |
| // Sample time stamp in nanoseconds. |
| typedef uint64_t SampleTimeNs; |
| // The data type of a sample value. |
| typedef uint64_t SampleValue; |
| // This is not intended to remain a std::map. This works fine for small numbers |
| // of samples and it has the API desired. So a std::map is being used while |
| // framing out the API. |
| using SampleStream = std::map<SampleTimeNs, SampleValue>; |
| |
| // This is clearer than using the raw number. |
| constexpr SampleTimeNs kNanosecondsPerSecond = 1000000000; |
| constexpr SampleTimeNs kSampleTimeInfinite = UINT64_MAX; |
| |
| // Special value for missing sample stream. |
| constexpr SampleValue NO_STREAM = (SampleValue)-1ULL; |
| // Special value for missing data. |
| constexpr SampleValue NO_DATA = (SampleValue)-2ULL; |
| // The highest value for sample data. |
| constexpr SampleValue SAMPLE_MAX_VALUE = (SampleValue)-3ULL; |
| |
| // The slope value is scaled up to preserve decimal precision when using an |
| // integer value. To convert the slope integer (slope_value) to floating point: |
| // float slope_as_percentage = float(slope_value) * SLOPE_SCALE. |
| constexpr SampleValue SLOPE_LIMIT = 1000000ULL; |
| constexpr float SLOPE_SCALE = 100.0f / static_cast<float>(SLOPE_LIMIT); |
| |
| // The upper value used to represent zero to one values with integers. |
| constexpr SampleValue NORMALIZATION_RANGE = 1000000ULL; |
| |
| // For compatibility check with the Harvester. |
| constexpr uint32_t DOCKYARD_VERSION = 2; |
| |
| enum KoidType : SampleValue { |
| JOB = 100ULL, |
| PROCESS = 101ULL, |
| THREAD = 102ULL, |
| CHANNEL = 103ULL, |
| }; |
| |
| // A Sample. |
| struct Sample { |
| Sample(SampleTimeNs t, SampleValue v) : time(t), value(v) {} |
| |
| SampleTimeNs time; |
| // Sample values range from [0 to SAMPLE_MAX_VALUE]. |
| SampleValue value; |
| }; |
| |
| // Mapping between IDs and path strings. |
| struct PathInfo { |
| // The dockyard ID that corresponds to |path|, below. |
| DockyardId id; |
| // The dockyard path that corresponds to |id|, above. |
| std::string path; |
| }; |
| |
| // Avoid removing elements from this enum. |
| enum class MessageType : int64_t { |
| // A response to a k*Request message. Match request IDs to determine which |
| // request this is a response to. |
| kResponseOk = 0, |
| // The request (represented by the request ID) failed in some fundamental way. |
| // E.e. maybe the request never made it to the handler. |
| kRequestFailed = -1, |
| // The connection to the Harvester on Fuchsia device has broken. No further |
| // requests will work until a new connection is established. |
| kDisconnected = -2, |
| // The version of the Harvester is incompatible with the Dockyard. |
| kVersionMismatch = -3, |
| |
| // Requests from the UI to the Dockyard. |
| kStreamSetsRequest = 1, |
| kDiscardSamplesRequest, |
| kIgnoreSamplesRequest, |
| kUnignoreSamplesRequest, |
| kConnectionRequest, |
| kSampleStreamsRequest, |
| }; |
| |
| std::ostream& operator<<(std::ostream& os, MessageType message_type); |
| |
| // A message to or from the dockyard. |
| struct Message { |
| // The request ID normally matches a request to a response. In the case of a |
| // 'push' message with no request, the ID will be |NULL_REQUEST_ID|. |
| static constexpr uint64_t NULL_REQUEST_ID = {0u}; |
| |
| // Context identifier for a message. Used to match a response to a request. |
| // For matching against a MessageResponse::request_id. |
| Message(MessageType type, uint64_t id) |
| : message_type_(type), request_id_(id) {} |
| |
| // The message type helps in routing the message. Expect to use both the |
| // message type and the request ID together (all current cases require both |
| // values). |
| MessageType GetMessageType() const { return message_type_; } |
| |
| // Context identifier for a message. Used to match a response to a request. |
| uint64_t RequestId() const { return request_id_; } |
| |
| protected: |
| // Identifier used for message routing, i.e. which code should handle this |
| // message. |
| MessageType message_type_; |
| |
| // Context identifier for a message. Used to match a response to a request. |
| uint64_t request_id_; |
| }; |
| |
| // A message to the dockyard. The response to this message will arrive as a |
| // |MessageResponse| with a matching |RequestId()|. |
| struct MessageRequest : public Message { |
| MessageRequest(MessageType type) : Message(type, ++next_request_id_) {} |
| |
| private: |
| // There is no rollover (wrap around) guard for the ID value. It's expected |
| // that a 64 bit integer is large enough to eliminate concern about it. |
| static uint64_t next_request_id_; |
| }; |
| |
| // A message from the dockyard. |
| struct MessageResponse : public Message { |
| MessageResponse() |
| : Message(MessageType::kResponseOk, Message::NULL_REQUEST_ID) {} |
| |
| void SetMessageType(MessageType message_type) { |
| message_type_ = message_type; |
| } |
| |
| bool Ok() const { return message_type_ == MessageType::kResponseOk; } |
| |
| // The request ID defaults to a 'push' message with a null request ID. If this |
| // is a response to a specific request, set the request ID to the request's |
| // request ID. |
| void SetRequestId(uint64_t id) { request_id_ = id; } |
| }; |
| |
| // Ask that the Dockyard make a connection to a Harvester running on a Fuchsia |
| // device. |
| struct ConnectionRequest : public MessageRequest { |
| ConnectionRequest() : MessageRequest(MessageType::kConnectionRequest) {} |
| |
| const std::string& DeviceName() const { return device_name_; } |
| void SetDeviceName(std::string name) { device_name_ = name; } |
| |
| private: |
| std::string device_name_; |
| }; |
| |
| // A |ConnectionResponse| is a reply for an individual |
| // |ConnectionRequest|. |
| // See: ConnectionRequest. |
| struct ConnectionResponse : public MessageResponse { |
| ConnectionResponse(uint32_t dockyard_version, uint32_t harvester_version) |
| : dockyard_version_(dockyard_version), |
| harvester_version_(harvester_version) {} |
| |
| uint32_t DockyardVersion() const { return dockyard_version_; } |
| uint32_t HarvesterVersion() const { return harvester_version_; } |
| |
| private: |
| uint32_t dockyard_version_; |
| uint32_t harvester_version_; |
| }; |
| |
| // To delete/remove samples from a sample stream, create a DiscardSamplesRequest |
| // for the desired time range (by default it will remove all samples for the |
| // stream) and pass the struct to Dockyard::DiscardSamples(). |
| struct DiscardSamplesRequest : public MessageRequest { |
| DiscardSamplesRequest() |
| : MessageRequest(MessageType::kDiscardSamplesRequest) {} |
| |
| // Request that samples are for time range |start_time..end_time|. Defaults to |
| // all samples (time zero to kSampleTimeInfinite). If there is no positive |
| // difference between start and end, the request will not have an effect. |
| SampleTimeNs start_time_ns = 0; |
| SampleTimeNs end_time_ns = kSampleTimeInfinite; |
| |
| // Each stream is identified by a Dockyard ID. Multiple streams can be |
| // discarded. |
| std::vector<DockyardId> dockyard_ids; |
| |
| friend std::ostream& operator<<(std::ostream& out, |
| const DiscardSamplesRequest& request); |
| }; |
| |
| // A |DiscardSamplesResponse| is a reply for an individual |
| // |DiscardSamplesRequest|. |
| // See: DiscardSamplesRequest. |
| struct DiscardSamplesResponse : MessageResponse { |
| DiscardSamplesResponse() = default; |
| |
| friend std::ostream& operator<<(std::ostream& out, |
| const DiscardSamplesResponse& response); |
| }; |
| |
| // To ignore samples, i.e. prevent them from being tracked, create a |
| // IgnoreSamplesRequest that will match the beginning and ending of the stream |
| // paths to ignore. |
| struct IgnoreSamplesRequest : public MessageRequest { |
| IgnoreSamplesRequest() : MessageRequest(MessageType::kIgnoreSamplesRequest) {} |
| |
| std::string prefix; |
| std::string suffix; |
| }; |
| |
| // An |IgnoreSamplesResponse| is a reply for an individual |
| // |IgnoreSamplesRequest|. |
| // See: IgnoreSamplesRequest. |
| struct IgnoreSamplesResponse : public MessageResponse { |
| IgnoreSamplesResponse() = default; |
| }; |
| |
| // A stream set is a portion of a sample stream. This request allows for |
| // requesting multiple stream sets in a single request. The results will arrive |
| // in the form of a |StreamSetsResponse|. |
| // |
| // Note: Set an |OnStreamSetsCallback| with |SetStreamSetsHandler()| |
| // before using the request to be sure of getting the message that the |
| // request is complete. |
| // |
| // See: StreamSetsResponse. |
| struct StreamSetsRequest : public MessageRequest { |
| enum RenderStyle { |
| // When smoothing across samples, use a wider set of samples, including |
| // samples that are just outside of the sample set range. E.g. if the range |
| // is time 9 to 18, smooth over time 7 to 20. |
| WIDE_SMOOTHING, |
| // When sculpting across samples, pull the result toward the peaks and |
| // valleys in the data (rather than showing the average). |
| SCULPTING, |
| // For each column of the output, use the least value from the samples. |
| LOWEST_PER_COLUMN, |
| // For each column of the output, use the greatest value from the samples. |
| HIGHEST_PER_COLUMN, |
| // Add up the sample values for the slice of time and divide by the number |
| // of values found (i.e. take the average or mean). |
| AVERAGE_PER_COLUMN, |
| // Get the single, most recent value prior to |end_time_ns|. Generally used |
| // with |start_time_ns| of zero, but |start_time_ns| can still be used to |
| // restrict the time range. |
| // The |flags| NORMALIZE and SLOPE are ignored when using RECENT. |
| RECENT, |
| }; |
| |
| enum StreamSetsRequestFlags { |
| // Frame (or scale) the data set aesthetically. E.g. if the graph has little |
| // variance, zoom in to show that detail, rather than just having a flat |
| // vertical line in the graph. In some cases (like comparing graphs) this |
| // will be undesired. The values in the response will be in the range |
| // [0 to NORMALIZATION_RANGE]. |
| NORMALIZE = 1 << 0, |
| // Compute the slope of the curve. |
| SLOPE = 1 << 1, |
| }; |
| |
| StreamSetsRequest() |
| : MessageRequest(MessageType::kStreamSetsRequest), |
| start_time_ns(0), |
| end_time_ns(0), |
| sample_count(0), |
| min(0), |
| max(0), |
| reserved(0), |
| render_style(AVERAGE_PER_COLUMN), |
| flags(0) {} |
| |
| // Request graph data for time range |start_time..end_time| that has |
| // |sample_count| values for each set. If the sample stream has more or less |
| // samples for that time range, virtual samples will be generated based on |
| // available samples. |
| SampleTimeNs start_time_ns; |
| SampleTimeNs end_time_ns; |
| uint64_t sample_count; |
| |
| SampleValue min; // Future use. |
| SampleValue max; // Future use. |
| uint64_t reserved; // Future use. |
| |
| RenderStyle render_style; |
| uint64_t flags; |
| |
| // Each stream is identified by a Dockyard ID. Multiple streams can be |
| // requested. Include a DockyardId for each stream of interest. |
| std::vector<DockyardId> dockyard_ids; |
| |
| bool HasFlag(StreamSetsRequestFlags flag) const; |
| |
| friend std::ostream& operator<<(std::ostream& out, |
| const StreamSetsRequest& request); |
| }; |
| |
| // A |StreamSetsResponse| is a reply for an individual |StreamSetsRequest|. |
| // See: StreamSetsRequest. |
| struct StreamSetsResponse : MessageResponse { |
| StreamSetsResponse() = default; |
| |
| // The low and high all-time values for all sample streams requested. All-time |
| // means that these low and high points might not appear in the |data_sets| |
| // below. "All sample streams" means that these points may not appear in the |
| // same sample streams. |
| SampleValue lowest_value; |
| SampleValue highest_value; |
| |
| // Each data set will correspond to a stream requested in the |
| // StreamSetsRequest::dockyard_ids. The value for each sample is normally in |
| // the range [0 to SAMPLE_MAX_VALUE]. If no value exists for the column, the |
| // value NO_DATA is used. |
| // For any DockyardId from StreamSetsRequest::dockyard_ids that isn't found, |
| // the resulting samples will have the value NO_STREAM. |
| std::vector<std::vector<SampleValue>> data_sets; |
| |
| friend std::ostream& operator<<(std::ostream& out, |
| const StreamSetsResponse& response); |
| }; |
| |
| // This request allows for requesting multiple sample streams in a single |
| // request. The results will arrive in the form of a |SampleStreamsResponse|. |
| // |
| // Note: Set an |OnSampleStreamsCallback| with |SampleStreamsHandler()| |
| // before using the request to be sure of getting the message that the |
| // request is complete. |
| // |
| // See: SampleStreamsResponse. |
| struct SampleStreamsRequest : public MessageRequest { |
| SampleStreamsRequest() |
| : MessageRequest(MessageType::kSampleStreamsRequest), |
| start_time_ns(0), |
| end_time_ns(0) {} |
| |
| SampleTimeNs start_time_ns; |
| SampleTimeNs end_time_ns; |
| |
| // Each stream is identified by a Dockyard ID. Multiple streams can be |
| // requested. Include a DockyardId for each stream of interest. |
| std::vector<DockyardId> dockyard_ids; |
| |
| friend std::ostream& operator<<(std::ostream& out, |
| const SampleStreamsRequest& request); |
| }; |
| |
| // A |SampleStreamsResponse| is a reply for an individual |
| // |SampleStreamsRequest|. See: SampleStreamsRequest. |
| struct SampleStreamsResponse : MessageResponse { |
| SampleStreamsResponse() = default; |
| |
| // The low and high all-time values for all sample streams requested. All-time |
| // means that these low and high points might not appear in the |data_sets| |
| // below. "All sample streams" means that these points may not appear in the |
| // same sample streams. |
| SampleValue lowest_value; |
| SampleValue highest_value; |
| |
| // Each data set will correspond to a stream requested in the |
| // SampleStreamsRequest::dockyard_ids. |
| std::vector<std::vector<std::pair<SampleTimeNs, SampleValue>>> data_sets; |
| |
| friend std::ostream& operator<<(std::ostream& out, |
| const SampleStreamsResponse& response); |
| }; |
| |
| // To stop ignoring samples, create a UnignoreSamplesRequest that will match |
| // the |prefix| and |suffix| values from a prior IgnoreSamplesRequest. |
| struct UnignoreSamplesRequest : public MessageRequest { |
| UnignoreSamplesRequest() |
| : MessageRequest(MessageType::kUnignoreSamplesRequest) {} |
| |
| std::string prefix; |
| std::string suffix; |
| }; |
| |
| // An |UnignoreSamplesResponse| is a reply for an individual |
| // |UnignoreSamplesRequest|. |
| // See: UnignoreSamplesRequest. |
| struct UnignoreSamplesResponse : MessageResponse { |
| UnignoreSamplesResponse() = default; |
| }; |
| |
| class SampleStreamMap |
| : public std::map<DockyardId, std::unique_ptr<SampleStream>> { |
| public: |
| // Get a reference to the sample stream for the given |dockyard_id|. |
| // The stream will be created if necessary. |
| SampleStream& StreamRef(DockyardId dockyard_id) { |
| return *emplace(dockyard_id, std::make_unique<SampleStream>()) |
| .first->second; |
| } |
| }; |
| |
| // Lookup for a sample stream name string, given the sample stream ID. |
| using DockyardIdToPathMap = std::map<DockyardId, std::string>; |
| using DockyardPathToIdMap = std::map<std::string, DockyardId>; |
| |
| // Called when a request to ignore samples is complete. |
| using IgnoreSamplesCallback = |
| std::function<void(const IgnoreSamplesRequest& request, |
| const IgnoreSamplesResponse& response)>; |
| |
| // Called when a connection is made between the Dockyard and Harvester on a |
| // Fuchsia device. |
| using OnConnectionCallback = std::function<void( |
| const ConnectionRequest& request, const ConnectionResponse& response)>; |
| |
| // Called when new streams are added or removed. Added values include their ID |
| // and string path. Removed values only have the ID. |
| // Intended to inform clients of PathInfoMap changes (so they may keep |
| // their equivalent map in sync). The racy nature of this update is not an issue |
| // because the rest of the API will cope with invalid stream IDs, so 'eventually |
| // consistent' is acceptable). |
| // Use SetDockyardPathsHandler() to install a StreamCallback callback. |
| using OnPathsCallback = std::function<void( |
| const std::vector<PathInfo>& add, const std::vector<DockyardId>& remove)>; |
| |
| // Called after (and in response to) a request is sent to |GetStreamSets()|. |
| // Use SetStreamSetsHandler() to install a StreamSetsCallback callback. |
| using OnStreamSetsCallback = std::function<void( |
| const StreamSetsRequest& request, const StreamSetsResponse& response)>; |
| |
| // Called after (and in response to) a request is sent to |GetSampleStreams()|. |
| // Use SetSampleStreamsHandler() to install a SampleStreamsCallback callback. |
| using OnSampleStreamsCallback = |
| std::function<void(const SampleStreamsRequest& request, |
| const SampleStreamsResponse& response)>; |
| |
| // Called after (and in response to) a request is sent to |DiscardSamples()|. |
| using OnDiscardSamplesCallback = |
| std::function<void(const DiscardSamplesRequest& request, |
| const DiscardSamplesResponse& response)>; |
| |
| class Dockyard { |
| public: |
| Dockyard(); |
| ~Dockyard(); |
| |
| // Insert sample information for a given dockyard_id. Not intended for use by |
| // the GUI. |
| void AddSample(DockyardId dockyard_id, Sample sample); |
| |
| // Insert sample information for a given dockyard_id. Not intended for use by |
| // the GUI. |
| void AddSamples(DockyardId dockyard_id, const std::vector<Sample>& samples); |
| |
| // The *approximate* difference between host time and device time. This value |
| // is negotiated at connection time and not reevaluated. If either clock is |
| // altered this value may be wildly inaccurate. The intended use of this value |
| // is to hint the GUI when displaying sample times (not for doing CI analysis |
| // or similar computations). |
| // If the value is positive then the device clock is ahead of the host clock. |
| // Given a sample, subtract this value to get the host time. |
| // Given a host time, add this value to get device (sample) time. |
| // See: LatestSampleTimeNs() |
| SampleTimeNs DeviceDeltaTimeNs() const; |
| |
| // Helper functions to compute time. Read important details in the description |
| // of |DeviceDeltaTimeNs|. |
| SampleTimeNs DeviceTimeToHostTime(SampleTimeNs device_time_ns) const { |
| return device_time_ns - device_time_delta_ns_; |
| } |
| SampleTimeNs HostTimeToDeviceTime(SampleTimeNs host_time_ns) const { |
| return host_time_ns + device_time_delta_ns_; |
| } |
| |
| // Discard the stream data. The path/ID lookup will remain intact after the |
| // discard (i.e. MatchPaths() will still find the paths). |
| void DiscardSamples(DiscardSamplesRequest&& request, |
| OnDiscardSamplesCallback callback); |
| |
| // Set the difference in clocks between the host machine and the Fuchsia |
| // device, in nanoseconds. |
| void SetDeviceTimeDeltaNs(SampleTimeNs delta_ns); |
| |
| // The time stamp for the most recent batch of samples to arrive. The time is |
| // device time (not host time) in nanoseconds. |
| // See: DeviceDeltaTimeNs() |
| SampleTimeNs LatestSampleTimeNs() const; |
| |
| // Get Dockyard identifier for a given path. The ID values are stable |
| // throughout execution, so they may be cached. |
| // |
| // Returns a Dockyard ID that corresponds to |dockyard_path|. |
| DockyardId GetDockyardId(const std::string& dockyard_path); |
| |
| // Determine whether |dockyard_path| is valid (if it exists). |
| bool HasDockyardPath(const std::string& dockyard_path, |
| DockyardId* dockyard_id) const; |
| |
| // Translate a |dockyard_id| to a |dockyard_path|. |dockyard_path| is an out |
| // value. Returns false if |dockyard_id| is unknown. |
| bool GetDockyardPath(DockyardId dockyard_id, |
| std::string* dockyard_path) const; |
| |
| // Search the existing paths for those that start with |starting| and end with |
| // |ending|. This is similar to having a single '*' wildcard search, something |
| // akin to find all "$starting*$ending". |
| // Returns a map of paths to IDs that is a subset of (or equal to) all known |
| // stream sets. |
| DockyardPathToIdMap MatchPaths(const std::string& starting, |
| const std::string& ending) const; |
| |
| // Request graph data for time range |start_time..end_time| that has |
| // |sample_count| values for each set. If the sample stream has more or less |
| // samples for that time range, virtual samples will be generated based on |
| // available samples. |
| // |
| // The results will be supplied in a call to the |callback|. |
| void GetStreamSets(StreamSetsRequest&& request, |
| OnStreamSetsCallback callback); |
| |
| // Request sample stream data for time range |start_time..end_time|. |
| // |
| // The results will be supplied in a call to the |callback|. |
| void GetSampleStreams(SampleStreamsRequest&& request, |
| OnSampleStreamsCallback callback); |
| |
| // Ignore subsequent samples per |request|. Note that existing (prior) samples |
| // are not removed/discarded. To remove samples see: DiscardSamples(). |
| void IgnoreSamples(IgnoreSamplesRequest&& request, |
| IgnoreSamplesCallback callback); |
| |
| // Called by server when a connection is made. |
| void OnConnection(MessageType message_type, uint32_t harvester_version); |
| |
| // Start collecting data from a named device. Tip: device names are normally |
| // four short words, such as "duck-floor-quick-rock". If |StartCollectingFrom| |
| // was previously called, call |StopCollectingFromDevice| before starting a |
| // new connection (otherwise this call will fail and return false). |
| // Returns true if successful. |
| bool StartCollectingFrom(ConnectionRequest&& request, |
| OnConnectionCallback callback); |
| |
| // The inverse of |StartCollectingFrom|. It's safe to call this regardless of |
| // whether |StartCollectingFrom| succeeded (no work is done unless |
| // |StartCollectingFrom| had succeeded). |
| void StopCollectingFromDevice(); |
| |
| // Sets the function called when sample streams are added or removed. Pass |
| // nullptr as |callback| to stop receiving calls. |
| // |
| // Returns prior callback or nullptr. |
| OnPathsCallback SetDockyardPathsHandler(OnPathsCallback callback); |
| |
| // Generate responses and call handlers for sample requests. Not intended for |
| // use by the GUI. |
| void ProcessRequests(); |
| |
| // Clear out the samples and other data that has been collected by the |
| // harvester. This is not normally used unless the host wishes to reset the |
| // data when a new connection is made. |
| void ResetHarvesterData(); |
| |
| // Write a snapshot of the current dockyard state to a string. Note that this |
| // could be rather large. As the name implies it's intended for debugging |
| // only. |
| std::ostringstream DebugDump() const; |
| |
| private: |
| // TODO(fxb/38): avoid having a global mutex. Use a queue to update |
| // data. |
| mutable std::mutex mutex_; |
| std::thread server_thread_; |
| |
| // The server handles grpc messages (runs in a background thread). |
| std::unique_ptr<grpc::Server> grpc_server_; |
| |
| // The service handles proto buffers. The |service_| must remain valid until |
| // the |server_| (which holds a weak pointer to |service_|) is finished. |
| std::unique_ptr<DockyardServiceImpl> protocol_buffer_service_; |
| |
| // The time (clock) on the device will likely differ from the host. |
| SampleTimeNs device_time_delta_ns_; |
| SampleTimeNs latest_sample_time_ns_; |
| |
| // Communication with the GUI. |
| ConnectionRequest on_connection_request_; |
| OnConnectionCallback on_connection_handler_; |
| OnPathsCallback on_paths_handler_; |
| |
| std::vector<std::pair<DiscardSamplesRequest, OnDiscardSamplesCallback>> |
| pending_discard_requests_owned_; |
| std::vector<std::pair<SampleStreamsRequest, OnSampleStreamsCallback>> |
| pending_raw_get_requests_owned_; |
| std::vector<std::pair<StreamSetsRequest, OnStreamSetsCallback>> |
| pending_get_requests_owned_; |
| std::vector<std::pair<IgnoreSamplesRequest, IgnoreSamplesCallback>> |
| pending_ignore_samples_owned_; |
| |
| // Storage of sample data. |
| SampleStreamMap sample_streams_; |
| std::map<DockyardId, std::pair<SampleValue, SampleValue>> |
| sample_stream_low_high_; |
| |
| // Track the ignore requests that have been made so that future paths that |
| // match the ignore list can be added to the ignore_dockyard_ids_. |
| std::set<std::pair<std::string, std::string>> ignore_streams_; |
| // Ignore list derived from |ignore_streams_|. This is an optimization over |
| // checking each update against the ignore_streams_. Doing a set lookup is |
| // much less expensive. |
| std::set<DockyardId> ignore_dockyard_ids_; |
| |
| // Dockyard path <--> ID look up. |
| DockyardPathToIdMap dockyard_path_to_id_; |
| DockyardIdToPathMap dockyard_id_to_path_; |
| |
| // Each of these Compute*() methods aggregate samples in different ways. |
| // There's no single 'true' way to represent aggregated data, so the choice |
| // is left to the caller. Which of these is used depends on the |
| // |StreamSetsRequestFlags| in the |StreamSetsRequest.flags| field. |
| void ComputeAveragePerColumn(DockyardId dockyard_id, |
| const SampleStream& sample_stream, |
| const StreamSetsRequest& request, |
| std::vector<SampleValue>* samples) const; |
| void ComputeHighestPerColumn(DockyardId dockyard_id, |
| const SampleStream& sample_stream, |
| const StreamSetsRequest& request, |
| std::vector<SampleValue>* samples) const; |
| void ComputeLowestPerColumn(DockyardId dockyard_id, |
| const SampleStream& sample_stream, |
| const StreamSetsRequest& request, |
| std::vector<SampleValue>* samples) const; |
| void ComputeRecent(DockyardId dockyard_id, const SampleStream& sample_stream, |
| const StreamSetsRequest& request, |
| std::vector<SampleValue>* samples) const; |
| void ComputeSculpted(DockyardId dockyard_id, |
| const SampleStream& sample_stream, |
| const StreamSetsRequest& request, |
| std::vector<SampleValue>* samples) const; |
| void ComputeSmoothed(DockyardId dockyard_id, |
| const SampleStream& sample_stream, |
| const StreamSetsRequest& request, |
| std::vector<SampleValue>* samples) const; |
| |
| void ComputeLowestHighestForRequest(const StreamSetsRequest& request, |
| StreamSetsResponse* response) const; |
| |
| void ComputeLowestHighestForSampleStreamsRequest( |
| const SampleStreamsRequest& request, |
| SampleStreamsResponse* response) const; |
| |
| // A private version of GetDockyardId that expects that a |mutex_| lock has |
| // already been acquired. |
| DockyardId GetDockyardIdLocked(const std::string& dockyard_path); |
| |
| // Ignore all further stream set data received that matches the patterns. |
| // Existing samples are not removed by this call. This call expects that a |
| // lock on |mutex_| has already been acquired. |
| void IgnoreSamplesLocked(const std::string& starting, |
| const std::string& ending); |
| |
| // Listen for incoming samples. |
| // |
| // Returns |false| on problems with starting the gRPC server. |
| bool Initialize(); |
| |
| // A private version of MatchPaths that expects that a lock has already been |
| // acquired. |
| DockyardPathToIdMap MatchPathsLocked(const std::string& starting, |
| const std::string& ending) const; |
| |
| // Rework the response so that all values are in the range 0 to one million. |
| // This represents a 0.0 to 1.0 value, scaled up. |
| void NormalizeResponse(DockyardId dockyard_id, |
| const SampleStream& sample_stream, |
| const StreamSetsRequest& request, |
| std::vector<SampleValue>* samples) const; |
| |
| // The average of the lowest and highest value in the stream. |
| SampleValue OverallAverageForStream(DockyardId dockyard_id) const; |
| |
| // Processes the requests entered by DiscardSamples(). |
| void ProcessDiscardSamples(const DiscardSamplesRequest& request, |
| DiscardSamplesResponse* response); |
| |
| // Process a request to ignore samples. |
| void ProcessIgnoreSamples(const IgnoreSamplesRequest& request, |
| IgnoreSamplesResponse* response); |
| |
| // Gather the overall lowest and highest values encountered. |
| void ProcessSingleRequest(const StreamSetsRequest& request, |
| StreamSetsResponse* response) const; |
| |
| // Process a single request for sample streams. |
| void ProcessSingleSampleStreamsRequest(const SampleStreamsRequest& request, |
| SampleStreamsResponse* response) const; |
| |
| // Listen for Harvester connections from the Fuchsia device. |
| void RunGrpcServer(); |
| |
| friend class ::SystemMonitorDockyardHostTest; |
| friend class ::dockyard::SystemMonitorDockyardTest; |
| friend std::ostream& operator<<(std::ostream& out, const Dockyard& dockyard); |
| }; |
| |
| // Merge and print a request and response. It can make debugging easier to have |
| // the data correlated. |
| std::ostringstream DebugPrintQuery(const Dockyard& dockyard, |
| const StreamSetsRequest& request, |
| const StreamSetsResponse& response); |
| |
| } // namespace dockyard |
| |
| #endif // SRC_DEVELOPER_SYSTEM_MONITOR_LIB_DOCKYARD_DOCKYARD_H_ |