00001 // ***************************************************************************** 00002 // 00003 // Copyright (c) 2015, Southwest Research Institute® (SwRI®) 00004 // All rights reserved. 00005 // 00006 // Redistribution and use in source and binary forms, with or without 00007 // modification, are permitted provided that the following conditions are met: 00008 // * Redistributions of source code must retain the above copyright 00009 // notice, this list of conditions and the following disclaimer. 00010 // * Redistributions in binary form must reproduce the above copyright 00011 // notice, this list of conditions and the following disclaimer in the 00012 // documentation and/or other materials provided with the distribution. 00013 // * Neither the name of Southwest Research Institute® (SwRI®) nor the 00014 // names of its contributors may be used to endorse or promote products 00015 // derived from this software without specific prior written permission. 00016 // 00017 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 // ARE DISCLAIMED. IN NO EVENT SHALL Southwest Research Institute® BE LIABLE 00021 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00022 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 00023 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00024 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00025 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00026 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 00027 // DAMAGE. 00028 // 00029 // ***************************************************************************** 00030 00031 #ifndef SWRI_PROFILER_TOOLS_PROFILE_H_ 00032 #define SWRI_PROFILER_TOOLS_PROFILE_H_ 00033 00034 #include <deque> 00035 #include <set> 00036 #include <map> 00037 #include <unordered_map> 00038 00039 #include <QObject> 00040 #include <QString> 00041 #include <QStringList> 00042 #include <swri_profiler_tools/new_profile_data.h> 00043 00044 namespace swri_profiler_tools 00045 { 00046 class ProfileDatabase; 00047 00048 class ProfileEntry 00049 { 00050 00051 public: 00052 // projected is for internal use in the profiler. This flag 00053 // indicates that the item's current data was projected from a 00054 // previous data point. This is used to keep the profile data 00055 // consistent despite missing or late data. This flag only applies 00056 // to data in measured nodes. 00057 00058 bool projected; 00059 uint64_t cumulative_call_count; 00060 uint64_t cumulative_inclusive_duration_ns; 00061 uint64_t incremental_inclusive_duration_ns; 00062 uint64_t cumulative_exclusive_duration_ns; 00063 uint64_t incremental_exclusive_duration_ns; 00064 uint64_t incremental_max_duration_ns; 00065 00066 ProfileEntry() 00067 : 00068 projected(false), 00069 cumulative_call_count(0), 00070 cumulative_inclusive_duration_ns(0), 00071 incremental_inclusive_duration_ns(0), 00072 cumulative_exclusive_duration_ns(0), 00073 incremental_exclusive_duration_ns(0), 00074 incremental_max_duration_ns(0) 00075 {} 00076 }; // class ProfileEntry 00077 00078 class ProfileNode 00079 { 00080 // This is the node's key within it's profile. It must be positive 00081 // to be a valid node. 00082 int node_key_; 00083 00084 // The name of this node. This is the last element of the path (c 00085 // in a/b/c). 00086 QString name_; 00087 00088 // The full path of the node in the call tree. (e.g. a/b/c) 00089 QString path_; 00090 00091 // Nodes can be either measured or inferred. Measured nodes have 00092 // their inclusive timing information provided by the profiler. 00093 // These are your typical blocks measured by 00094 // SWRI_PROFILE(). Inferred nodes are nodes that were created to 00095 // fill in the call tree. These are typically your root node and 00096 // nodes corresponding to ROS namespaces. 00097 bool measured_; 00098 00099 // The data stored by the node. The array is managed by the 00100 // profile. Each element corresponds to a time which is determined 00101 // by the Profile's min_time and max_time. 00102 std::deque<ProfileEntry> data_; 00103 00104 // The node's depth in the tree. 00105 int depth_; 00106 00107 // The key of this node's parent node. This will be invalid 00108 // (negative) for the root node. 00109 int parent_; 00110 00111 // They node's children, in alphabetical order according to their 00112 // paths. 00113 std::vector<int> children_; 00114 00115 // The ProfileNode is a "dumb" data storage object with read-only 00116 // access to the rest of the world. The node is managed and 00117 // manipulated directly by the profile. 00118 friend class Profile; 00119 00120 public: 00121 ProfileNode() 00122 : 00123 node_key_(-1), 00124 measured_(false), 00125 depth_(-1), 00126 parent_(-1) 00127 {} 00128 00129 bool isValid() const { return node_key_ >= 0; } 00130 int nodeKey() const { return node_key_; } 00131 const QString& name() const { return name_; } 00132 const QString& path() const { return path_; } 00133 bool isMeasured() const { return measured_; } 00134 const std::deque<ProfileEntry>& data() const { return data_; } 00135 int depth() const { return depth_; } 00136 int parentKey() const { return parent_; } 00137 const std::vector<int>& childKeys() const { return children_; } 00138 bool hasChildren() const { return !children_.empty(); } 00139 }; // class ProfileNode 00140 00141 class Profile : public QObject 00142 { 00143 Q_OBJECT; 00144 00145 00146 // The key of this profile in the database. This is negative for 00147 // an invalid profile. 00148 int profile_key_; 00149 00150 // Name of the profile. This is initialized by the source and may 00151 // be modified by the user. 00152 QString name_; 00153 00154 // All node data is stored in dense arrays of the same size. The 00155 // min_time_s_ and max_time_s_ correspond to the timespan currently 00156 // covered by the array. They are inclusive and exclusive, 00157 // respectively (index 0 => min_time_s, index size() => max_time_s. 00158 uint64_t min_time_s_; 00159 uint64_t max_time_s_; 00160 00161 // Nodes are stored in an unordered_map so that we can provide 00162 // persistent keys with fast look ups. We could use the node's path 00163 // as the key (though we need an adapter hash a QString rather than 00164 // std::string), but they we're constantly hashing very long 00165 // strings. Instead, we assign a unique integer key when the node 00166 // is added. This map provides reasonable reverse-lookups. We 00167 // could actually change nodes_ to a vector or deque and still have 00168 // persistent indices as long as we don't allow nodes to be deleted. 00169 std::map<QString, int> node_key_from_path_; 00170 std::unordered_map<int, ProfileNode> nodes_; 00171 00172 // The flat index stores all the profile's nodes in alphabetical by 00173 // path order. Traversing in order corresponds to visiting the call 00174 // tree in a depth-first pattern. 00175 std::vector<int> flat_index_; 00176 00177 00178 // The ProfileDatabase is the only place we want to create valid 00179 // profiles. A valid profile is created by initializing a default 00180 // profile. Initialization is only allowed to happen once. 00181 friend class ProfileDatabase; 00182 void initialize(int profile_key, const QString &name); 00183 00184 void expandTimeline(const uint64_t sec); 00185 void addDataToAllNodes(const bool back, const size_t count); 00186 00187 bool touchNode(const QString &path); 00188 00189 void storeItemData(std::set<uint64_t> &modified_times, 00190 const int node_key, 00191 const NewProfileData &item); 00192 00193 size_t indexFromSec(const uint64_t secs) const { return secs - min_time_s_; } 00194 uint64_t secFromIndex(const uint64_t index) const { return index + min_time_s_; } 00195 00196 void rebuildIndices(); 00197 void rebuildFlatIndex(); 00198 void rebuildTreeIndex(); 00199 00200 void updateDerivedData(size_t index); 00201 void updateDerivedDataInternal(ProfileNode& node, size_t index); 00202 00203 public: 00204 Profile(); 00205 ~Profile(); 00206 00207 void addData(const NewProfileDataVector &data); 00208 const bool isValid() const { return profile_key_ >= 0; } 00209 const int profileKey() const { return profile_key_; } 00210 00211 const QString& name() const { return name_; } 00212 void setName(const QString &name); 00213 00214 const ProfileNode& node(int node_key) const; 00215 const ProfileNode& rootNode() const; 00216 const int rootKey() const { return 0; } 00217 const std::vector<int>& nodeKeys() const; 00218 00219 Q_SIGNALS: 00220 // Emitted when the profile is renamed. 00221 void profileModified(int profile_key); 00222 void nodesAdded(int profile_key); 00223 void dataAdded(int profile_key); 00224 }; // class Profile 00225 } // namespace swri_profiler_tools 00226 #endif // SWRI_PROFILER_TOOLS_PROFILE_H_