// Copyright 2018 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef BAZEL_SRC_MAIN_CPP_UTIL_PROFILER_H_ #define BAZEL_SRC_MAIN_CPP_UTIL_PROFILER_H_ #include // int64_t #include // printf namespace blaze_util { namespace profiler { // A time duration, measured in some implementation-dependent units. // // Using a struct to wrap int64_t yields a unique type that we can't // accidentally use as a type-synonym of other int64_t types. struct Ticks { int64_t value_; static Ticks Now(); }; // A time duration, measured in microseconds. // // Using a struct to wrap int64_t yields a unique type that we can't // accidentally use as a type-synonym of other int64_t types. struct Duration { int64_t micros_; static Duration FromTicks(const Ticks ticks); }; // Accumulates statistics about a function or some C++ scope. // // Usage: see ScopedTask. // // Records the number of times the scope was entered (the function called) and // the total time spent in there. Prints the statistics in the destructor. class Task { const char* name_; uint64_t calls_; Ticks total_; public: Task(const char* name) : name_(name), calls_(0), total_({0}) {} ~Task(); void AddCall() { calls_++; } void AddTicks(const Ticks t) { total_.value_ += t.value_; } uint64_t GetCalls() const { return calls_; } Duration GetDuration() const { return Duration::FromTicks(total_); } }; // Measures elapsed time. // // Example: // void foo() { // StopWatch s; // ... // s.PrintAndReset("marker 1"); // prints elapsed time since creation // ... // s.PrintAndReset("marker 2"); // prints elapsed time since "marker 1" // ... // s.Reset(); // ... // Ticks t1 = s.Elapsed(); // time since Reset // ... // Ticks t2 = s.Elapsed(); // time since Reset, not since t1 // } // class StopWatch { Ticks start_; public: // Constructor -- it also resets this StopWatch. StopWatch() { start_ = Ticks::Now(); } // Prints elapsed time since last reset, then resets. // // Args: // name: a descriptive name, will be printed in the output void PrintAndReset(const char* name); // Returns the elapsed time since the last reset as `Ticks`. Ticks Elapsed() const { Ticks now = Ticks::Now(); return {now.value_ - start_.value_}; } // Returns the elapsed time since the last reset as `Duration`. Duration ElapsedTime() const { return Duration::FromTicks(Elapsed()); } // Resets this StopWatch to the current time. void Reset() { start_ = Ticks::Now(); } }; // Measures the execution duration of a given C++ scope. // // The constructor records one call of the scope in a `Task` object, and the // destructor records the time spent in the scope in that `Task` object. // // Usage: // create one Task that accumulates the statistics for a given function // or scope, and create one ScopedTask in the beginning of the scope you want // to measure. Every time the scope is entered (the function is called), a // ScopedTask is created, then destructed when the execution leaves the scope. // The destructor then records the statistics in the Task. // // Example: // Task slow_function_stats("slow function"); // d'tor prints stats // // void slow_function() { // ScopedTask prof(&slow_function_stats); // ... // } // class ScopedTask { public: ScopedTask(Task* s) : stat_(s) { stat_->AddCall(); } ~ScopedTask() { stat_->AddTicks(prof_.Elapsed()); } private: Task* stat_; StopWatch prof_; }; } // namespace profiler } // namespace blaze_util #endif // BAZEL_SRC_MAIN_CPP_UTIL_PROFILER_H_