diff options
Diffstat (limited to 'tools/lldb-perf/lib')
-rw-r--r-- | tools/lldb-perf/lib/Gauge.cpp | 53 | ||||
-rw-r--r-- | tools/lldb-perf/lib/Gauge.h | 64 | ||||
-rw-r--r-- | tools/lldb-perf/lib/Measurement.h | 217 | ||||
-rw-r--r-- | tools/lldb-perf/lib/MemoryGauge.cpp | 165 | ||||
-rw-r--r-- | tools/lldb-perf/lib/MemoryGauge.h | 147 | ||||
-rw-r--r-- | tools/lldb-perf/lib/Metric.cpp | 85 | ||||
-rw-r--r-- | tools/lldb-perf/lib/Metric.h | 72 | ||||
-rw-r--r-- | tools/lldb-perf/lib/Results.cpp | 275 | ||||
-rw-r--r-- | tools/lldb-perf/lib/Results.h | 312 | ||||
-rw-r--r-- | tools/lldb-perf/lib/TestCase.cpp | 358 | ||||
-rw-r--r-- | tools/lldb-perf/lib/TestCase.h | 205 | ||||
-rw-r--r-- | tools/lldb-perf/lib/Timer.cpp | 61 | ||||
-rw-r--r-- | tools/lldb-perf/lib/Timer.h | 66 | ||||
-rw-r--r-- | tools/lldb-perf/lib/Xcode.cpp | 165 | ||||
-rw-r--r-- | tools/lldb-perf/lib/Xcode.h | 64 |
15 files changed, 2309 insertions, 0 deletions
diff --git a/tools/lldb-perf/lib/Gauge.cpp b/tools/lldb-perf/lib/Gauge.cpp new file mode 100644 index 000000000000..4c4593b3b292 --- /dev/null +++ b/tools/lldb-perf/lib/Gauge.cpp @@ -0,0 +1,53 @@ +//===-- Gauge.cpp -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Gauge.h" +#include "lldb/lldb-forward.h" + +template <> +lldb_perf::Results::ResultSP +lldb_perf::GetResult (const char *description, double value) +{ + if (description && description[0]) + { + std::unique_ptr<Results::Dictionary> value_dict_ap (new Results::Dictionary ()); + value_dict_ap->AddString("description", NULL, description); + value_dict_ap->AddDouble("value", NULL, value); + return Results::ResultSP (value_dict_ap.release()); + } + return Results::ResultSP (new Results::Double (NULL, NULL, value)); +} + +template <> +lldb_perf::Results::ResultSP +lldb_perf::GetResult (const char *description, uint64_t value) +{ + if (description && description[0]) + { + std::unique_ptr<Results::Dictionary> value_dict_ap (new Results::Dictionary ()); + value_dict_ap->AddString("description", NULL, description); + value_dict_ap->AddUnsigned("value", NULL, value); + return Results::ResultSP (value_dict_ap.release()); + } + return Results::ResultSP (new Results::Unsigned (NULL, NULL, value)); +} + +template <> +lldb_perf::Results::ResultSP +lldb_perf::GetResult (const char *description, std::string value) +{ + if (description && description[0]) + { + std::unique_ptr<Results::Dictionary> value_dict_ap (new Results::Dictionary ()); + value_dict_ap->AddString("description", NULL, description); + value_dict_ap->AddString("value", NULL, value.c_str()); + return Results::ResultSP (value_dict_ap.release()); + } + return Results::ResultSP (new Results::String (NULL, NULL, value.c_str())); +} diff --git a/tools/lldb-perf/lib/Gauge.h b/tools/lldb-perf/lib/Gauge.h new file mode 100644 index 000000000000..fc5c444a38b8 --- /dev/null +++ b/tools/lldb-perf/lib/Gauge.h @@ -0,0 +1,64 @@ +//===-- Gauge.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef PerfTestDriver_Gauge_h +#define PerfTestDriver_Gauge_h + +#include <functional> +#include <string> + +#include "Results.h" + +namespace lldb_perf { + +template <class T> +class Gauge +{ +public: + typedef T ValueType; + + Gauge () + {} + + virtual + ~Gauge () + {} + + virtual void + Start () = 0; + + virtual ValueType + Stop () = 0; + + virtual ValueType + GetStartValue () const = 0; + + virtual ValueType + GetStopValue () const = 0; + + virtual ValueType + GetDeltaValue () const = 0; + +}; + +template <class T> +Results::ResultSP GetResult (const char *description, T value); + +template <> +Results::ResultSP GetResult (const char *description, double value); + +template <> +Results::ResultSP GetResult (const char *description, uint64_t value); + +template <> +Results::ResultSP GetResult (const char *description, std::string value); + +} + +#endif diff --git a/tools/lldb-perf/lib/Measurement.h b/tools/lldb-perf/lib/Measurement.h new file mode 100644 index 000000000000..877e618d5469 --- /dev/null +++ b/tools/lldb-perf/lib/Measurement.h @@ -0,0 +1,217 @@ +//===-- Measurement.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __PerfTestDriver__Measurement__ +#define __PerfTestDriver__Measurement__ + +#include "Gauge.h" +#include "Timer.h" +#include "Metric.h" +#include "MemoryGauge.h" + +namespace lldb_perf +{ +template <typename GaugeType, typename Callable> +class Measurement +{ +public: + Measurement () : + m_gauge (), + m_callable (), + m_metric () + { + } + + Measurement (Callable callable, const char* name, const char* desc) : + m_gauge (), + m_callable (callable), + m_metric (Metric<typename GaugeType::ValueType>(name, desc)) + { + } + + Measurement (const char* name, const char* desc) : + m_gauge (), + m_callable (), + m_metric (Metric<typename GaugeType::ValueType>(name, desc)) + { + } + + template <typename GaugeType_Rhs, typename Callable_Rhs> + Measurement (const Measurement<GaugeType_Rhs, Callable_Rhs>& rhs) : + m_gauge(rhs.GetGauge()), + m_callable(rhs.GetCallable()), + m_metric(rhs.GetMetric()) + { + } + + template <typename... Args> + void + operator () (Args... args) + { + m_gauge.Start(); + m_callable(args...); + m_metric.Append (m_gauge.Stop()); + } + + virtual const Callable& + GetCallable () const + { + return m_callable; + } + + virtual const GaugeType& + GetGauge () const + { + return m_gauge; + } + + virtual const Metric<typename GaugeType::ValueType>& + GetMetric () const + { + return m_metric; + } + + void + Start () + { + m_gauge.Start(); + } + + typename GaugeType::ValueType + Stop () + { + auto value = m_gauge.Stop(); + m_metric.Append(value); + return value; + } + + void + WriteStartValue (Results &results) + { + auto metric = GetMetric (); + results.GetDictionary().Add(metric.GetName(), metric.GetDescription(), lldb_perf::GetResult<typename GaugeType::ValueType> (NULL, metric.GetStartValue())); + } + + void + WriteStopValue (Results &results) + { + auto metric = GetMetric (); + results.GetDictionary().Add(metric.GetName(), metric.GetDescription(), lldb_perf::GetResult<typename GaugeType::ValueType> (NULL, metric.GetStopValue())); + } + + void + WriteAverageValue (Results &results) + { + auto metric = GetMetric (); + results.GetDictionary().Add(metric.GetName(), metric.GetDescription(), lldb_perf::GetResult<typename GaugeType::ValueType> (NULL, metric.GetAverage())); + } + + void + WriteAverageAndStandardDeviation (Results &results) + { + auto metric = GetMetric (); + auto dictionary = (Results::Dictionary*)results.GetDictionary().Add(metric.GetName(), metric.GetDescription(), lldb_perf::GetResult<typename GaugeType::ValueType> (NULL, metric.GetAverage())).get(); + if (dictionary) + { + dictionary->Add("stddev", NULL, lldb_perf::GetResult<typename GaugeType::ValueType> (NULL, metric.GetStandardDeviation())); + } + } + + void + WriteStandardDeviation (Results &results) + { + auto metric = GetMetric (); + results.GetDictionary().Add(metric.GetName(), metric.GetDescription(), lldb_perf::GetResult<typename GaugeType::ValueType> (NULL, metric.GetStandardDeviation())); + } + +protected: + GaugeType m_gauge; + Callable m_callable; + Metric<typename GaugeType::ValueType> m_metric; +}; + +template <typename Callable> +class TimeMeasurement : public Measurement<TimeGauge,Callable> +{ +public: + TimeMeasurement () : + Measurement<TimeGauge,Callable> () + { + } + + TimeMeasurement (Callable callable, + const char* name = NULL, + const char* descr = NULL) : + Measurement<TimeGauge,Callable> (callable, name, descr) + { + } + + template <typename Callable_Rhs> + TimeMeasurement (const TimeMeasurement<Callable_Rhs>& rhs) : + Measurement<TimeGauge,Callable>(rhs) + { + } + + template <typename GaugeType_Rhs, typename Callable_Rhs> + TimeMeasurement (const Measurement<GaugeType_Rhs, Callable_Rhs>& rhs) : + Measurement<GaugeType_Rhs,Callable_Rhs>(rhs) + { + } + + template <typename... Args> + void + operator () (Args... args) + { + Measurement<TimeGauge,Callable>::operator()(args...); + } +}; + +template <typename Callable> +class MemoryMeasurement : public Measurement<MemoryGauge,Callable> +{ +public: + MemoryMeasurement () : Measurement<MemoryGauge,Callable> () + { + } + + MemoryMeasurement (Callable callable, + const char* name, + const char* descr) : + Measurement<MemoryGauge,Callable> (callable, name, descr) + { + } + + MemoryMeasurement (const char* name, const char* descr) : + Measurement<MemoryGauge,Callable> (name, descr) + { + } + + template <typename Callable_Rhs> + MemoryMeasurement (const MemoryMeasurement<Callable_Rhs>& rhs) : + Measurement<MemoryGauge,Callable>(rhs) + { + } + + template <typename GaugeType_Rhs, typename Callable_Rhs> + MemoryMeasurement (const Measurement<GaugeType_Rhs, Callable_Rhs>& rhs) : + Measurement<GaugeType_Rhs,Callable_Rhs>(rhs) + { + } + + template <typename... Args> + void + operator () (Args... args) + { + Measurement<MemoryGauge,Callable>::operator()(args...); + } +}; + +} + +#endif /* defined(__PerfTestDriver__Measurement__) */ diff --git a/tools/lldb-perf/lib/MemoryGauge.cpp b/tools/lldb-perf/lib/MemoryGauge.cpp new file mode 100644 index 000000000000..2a46453f540b --- /dev/null +++ b/tools/lldb-perf/lib/MemoryGauge.cpp @@ -0,0 +1,165 @@ +//===-- MemoryGauge.cpp -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MemoryGauge.h" +#include "lldb/lldb-forward.h" +#include <assert.h> +#include <cmath> +#include <mach/mach.h> +#include <mach/task.h> +#include <mach/mach_traps.h> + +using namespace lldb_perf; + +MemoryStats::MemoryStats (mach_vm_size_t virtual_size, + mach_vm_size_t resident_size, + mach_vm_size_t max_resident_size) : + m_virtual_size (virtual_size), + m_resident_size (resident_size), + m_max_resident_size (max_resident_size) +{ +} + +MemoryStats::MemoryStats (const MemoryStats& rhs) : + m_virtual_size (rhs.m_virtual_size), + m_resident_size (rhs.m_resident_size), + m_max_resident_size (rhs.m_max_resident_size) +{ +} + + +MemoryStats& +MemoryStats::operator = (const MemoryStats& rhs) +{ + if (this != &rhs) + { + m_virtual_size = rhs.m_virtual_size; + m_resident_size = rhs.m_resident_size; + m_max_resident_size = rhs.m_max_resident_size; + } + return *this; +} + +MemoryStats& +MemoryStats::operator += (const MemoryStats& rhs) +{ + m_virtual_size += rhs.m_virtual_size; + m_resident_size += rhs.m_resident_size; + m_max_resident_size += rhs.m_max_resident_size; + return *this; +} + +MemoryStats +MemoryStats::operator - (const MemoryStats& rhs) +{ + return MemoryStats(m_virtual_size - rhs.m_virtual_size, + m_resident_size - rhs.m_resident_size, + m_max_resident_size - rhs.m_max_resident_size); +} + +MemoryStats +MemoryStats::operator + (const MemoryStats& rhs) +{ + return MemoryStats(m_virtual_size + rhs.m_virtual_size, + m_resident_size + rhs.m_resident_size, + m_max_resident_size + rhs.m_max_resident_size); +} + +MemoryStats +MemoryStats::operator / (size_t n) +{ + MemoryStats result(*this); + result.m_virtual_size /= n; + result.m_resident_size /= n; + result.m_max_resident_size /= n; + return result; +} + +MemoryStats +MemoryStats::operator * (const MemoryStats& rhs) +{ + return MemoryStats(m_virtual_size * rhs.m_virtual_size, + m_resident_size * rhs.m_resident_size, + m_max_resident_size * rhs.m_max_resident_size); +} + +Results::ResultSP +MemoryStats::GetResult (const char *name, const char *description) const +{ + std::unique_ptr<Results::Dictionary> dict_ap (new Results::Dictionary (name, NULL)); + dict_ap->AddUnsigned("resident", NULL, GetResidentSize()); + dict_ap->AddUnsigned("max_resident", NULL, GetMaxResidentSize()); + return Results::ResultSP(dict_ap.release()); +} + +MemoryGauge::ValueType +MemoryGauge::Now () +{ + task_t task = mach_task_self(); + mach_task_basic_info_data_t taskBasicInfo; + mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT; + auto task_info_ret = task_info(task, MACH_TASK_BASIC_INFO, (task_info_t) & taskBasicInfo, &count); + if (task_info_ret == KERN_SUCCESS) { + return MemoryStats(taskBasicInfo.virtual_size, taskBasicInfo.resident_size, taskBasicInfo.resident_size_max); + } + return 0; +} + +MemoryGauge::MemoryGauge () : + m_state(MemoryGauge::State::eNeverUsed), + m_start(), + m_delta() +{ +} + +void +MemoryGauge::Start () +{ + m_state = MemoryGauge::State::eCounting; + m_start = Now(); +} + +MemoryGauge::ValueType +MemoryGauge::Stop () +{ + m_stop = Now(); + assert(m_state == MemoryGauge::State::eCounting && "cannot stop a non-started gauge"); + m_state = MemoryGauge::State::eStopped; + m_delta = m_stop - m_start; + return m_delta; +} + + +MemoryGauge::ValueType +MemoryGauge::GetDeltaValue () const +{ + assert(m_state == MemoryGauge::State::eStopped && "gauge must be used before you can evaluate it"); + return m_delta; +} + +template <> +Results::ResultSP +lldb_perf::GetResult (const char *description, MemoryStats value) +{ + return value.GetResult (NULL, description); +} + +MemoryStats +sqrt (const MemoryStats& arg) +{ + long double virt_size = arg.GetVirtualSize(); + long double resident_size = arg.GetResidentSize(); + long double max_resident_size = arg.GetMaxResidentSize(); + + virt_size = sqrtl(virt_size); + resident_size = sqrtl(resident_size); + max_resident_size = sqrtl(max_resident_size); + + return MemoryStats(virt_size,resident_size,max_resident_size); +} diff --git a/tools/lldb-perf/lib/MemoryGauge.h b/tools/lldb-perf/lib/MemoryGauge.h new file mode 100644 index 000000000000..a1221b6b66cc --- /dev/null +++ b/tools/lldb-perf/lib/MemoryGauge.h @@ -0,0 +1,147 @@ +//===-- MemoryGauge.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __PerfTestDriver__MemoryGauge__ +#define __PerfTestDriver__MemoryGauge__ + +#include "Gauge.h" +#include "Results.h" + +#include <mach/task_info.h> + +namespace lldb_perf { + +class MemoryStats +{ +public: + MemoryStats (mach_vm_size_t virtual_size = 0, + mach_vm_size_t resident_size = 0, + mach_vm_size_t max_resident_size = 0); + MemoryStats (const MemoryStats& rhs); + + MemoryStats& + operator = (const MemoryStats& rhs); + + MemoryStats& + operator += (const MemoryStats& rhs); + + MemoryStats + operator - (const MemoryStats& rhs); + + MemoryStats + operator + (const MemoryStats& rhs); + + MemoryStats + operator / (size_t rhs); + + MemoryStats + operator * (const MemoryStats& rhs); + + mach_vm_size_t + GetVirtualSize () const + { + return m_virtual_size; + } + + mach_vm_size_t + GetResidentSize () const + { + return m_resident_size; + } + + mach_vm_size_t + GetMaxResidentSize () const + { + return m_max_resident_size; + } + + void + SetVirtualSize (mach_vm_size_t vs) + { + m_virtual_size = vs; + } + + void + SetResidentSize (mach_vm_size_t rs) + { + m_resident_size = rs; + } + + void + SetMaxResidentSize (mach_vm_size_t mrs) + { + m_max_resident_size = mrs; + } + + Results::ResultSP + GetResult (const char *name, const char *description) const; +private: + mach_vm_size_t m_virtual_size; + mach_vm_size_t m_resident_size; + mach_vm_size_t m_max_resident_size; +}; + +class MemoryGauge : public Gauge<MemoryStats> +{ +public: + MemoryGauge (); + + virtual + ~MemoryGauge () + { + } + + void + Start (); + + ValueType + Stop (); + + virtual ValueType + GetStartValue() const + { + return m_start; + } + + virtual ValueType + GetStopValue() const + { + return m_stop; + } + + virtual ValueType + GetDeltaValue() const; + +private: + enum class State + { + eNeverUsed, + eCounting, + eStopped + }; + + ValueType + Now (); + + State m_state; + ValueType m_start; + ValueType m_stop; + ValueType m_delta; +}; + +template <> +Results::ResultSP +GetResult (const char *description, MemoryStats value); + +} // namespace lldb_perf + +lldb_perf::MemoryStats +sqrt (const lldb_perf::MemoryStats& arg); + +#endif // #ifndef __PerfTestDriver__MemoryGauge__ diff --git a/tools/lldb-perf/lib/Metric.cpp b/tools/lldb-perf/lib/Metric.cpp new file mode 100644 index 000000000000..1951cdb0250a --- /dev/null +++ b/tools/lldb-perf/lib/Metric.cpp @@ -0,0 +1,85 @@ +//===-- Metric.cpp ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Metric.h" +#include "MemoryGauge.h" +#include <cmath> + +using namespace lldb_perf; + +template <class T> +Metric<T>::Metric () : Metric ("") +{ +} + +template <class T> +Metric<T>::Metric (const char* n, const char* d) : + m_name(n ? n : ""), + m_description(d ? d : ""), + m_dataset () +{ +} + +template <class T> +void +Metric<T>::Append (T v) +{ + m_dataset.push_back(v); +} + +template <class T> +size_t +Metric<T>::GetCount () const +{ + return m_dataset.size(); +} + +template <class T> +T +Metric<T>::GetSum () const +{ + T sum = 0; + for (auto v : m_dataset) + sum += v; + return sum; +} + +template <class T> +T +Metric<T>::GetAverage () const +{ + return GetSum()/GetCount(); +} + + +// Knuth's algorithm for stddev - massive cancellation resistant +template <class T> +T +Metric<T>::GetStandardDeviation (StandardDeviationMode mode) const +{ + size_t n = 0; + T mean = 0; + T M2 = 0; + for (auto x : m_dataset) + { + n = n + 1; + T delta = x - mean; + mean = mean + delta/n; + M2 = M2+delta*(x-mean); + } + T variance; + if (mode == StandardDeviationMode::ePopulation || n == 1) + variance = M2 / n; + else + variance = M2 / (n - 1); + return sqrt(variance); +} + +template class lldb_perf::Metric<double>; +template class lldb_perf::Metric<MemoryStats>; diff --git a/tools/lldb-perf/lib/Metric.h b/tools/lldb-perf/lib/Metric.h new file mode 100644 index 000000000000..45342d25b41a --- /dev/null +++ b/tools/lldb-perf/lib/Metric.h @@ -0,0 +1,72 @@ +//===-- Metric.h ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __PerfTestDriver__Metric__ +#define __PerfTestDriver__Metric__ + +#include <vector> +#include <string> +#include <mach/task_info.h> + +namespace lldb_perf { + +class MemoryStats; + +template <class ValueType> +class Metric +{ +public: + enum class StandardDeviationMode + { + eSample, + ePopulation + }; + + Metric (); + Metric (const char*, const char* = NULL); + + void + Append (ValueType v); + + ValueType + GetAverage () const; + + size_t + GetCount () const; + + ValueType + GetSum () const; + + ValueType + GetStandardDeviation (StandardDeviationMode mode = StandardDeviationMode::ePopulation) const; + + const char* + GetName () const + { + if (m_name.empty()) + return NULL; + return m_name.c_str(); + } + + const char* + GetDescription () const + { + if (m_description.empty()) + return NULL; + return m_description.c_str(); + } + +private: + std::string m_name; + std::string m_description; + std::vector<ValueType> m_dataset; +}; +} + +#endif /* defined(__PerfTestDriver__Metric__) */ diff --git a/tools/lldb-perf/lib/Results.cpp b/tools/lldb-perf/lib/Results.cpp new file mode 100644 index 000000000000..6abf67e53b67 --- /dev/null +++ b/tools/lldb-perf/lib/Results.cpp @@ -0,0 +1,275 @@ +//===-- Results.cpp ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Results.h" +#include <assert.h> + +#ifdef __APPLE__ +#include "CFCMutableArray.h" +#include "CFCMutableDictionary.h" +#include "CFCReleaser.h" +#include "CFCString.h" +#endif + +using namespace lldb_perf; + +static void +AddResultToArray (CFCMutableArray &array, Results::Result *result); + +static void +AddResultToDictionary (CFCMutableDictionary &parent_dict, const char *key, Results::Result *result); + +static void +AddResultToArray (CFCMutableArray &parent_array, Results::Result *result) +{ + switch (result->GetType()) + { + case Results::Result::Type::Invalid: + break; + + case Results::Result::Type::Array: + { + Results::Array *value = result->GetAsArray(); + CFCMutableArray array; + value->ForEach([&array](const Results::ResultSP &value_sp) -> bool + { + AddResultToArray (array, value_sp.get()); + return true; + }); + parent_array.AppendValue(array.get(), true); + } + break; + + case Results::Result::Type::Dictionary: + { + Results::Dictionary *value = result->GetAsDictionary(); + CFCMutableDictionary dict; + value->ForEach([&dict](const std::string &key, const Results::ResultSP &value_sp) -> bool + { + AddResultToDictionary (dict, key.c_str(), value_sp.get()); + return true; + }); + if (result->GetDescription()) + { + dict.AddValueCString(CFSTR("description"), result->GetDescription()); + } + parent_array.AppendValue(dict.get(), true); + } + break; + + case Results::Result::Type::Double: + { + double d = result->GetAsDouble()->GetValue(); + CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberDoubleType, &d)); + if (cf_number.get()) + parent_array.AppendValue(cf_number.get(), true); + } + break; + case Results::Result::Type::String: + { + CFCString cfstr (result->GetAsString()->GetValue()); + if (cfstr.get()) + parent_array.AppendValue(cfstr.get(), true); + } + break; + + case Results::Result::Type::Unsigned: + { + uint64_t uval64 = result->GetAsUnsigned()->GetValue(); + CFCReleaser<CFNumberRef> cf_number(::CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &uval64)); + if (cf_number.get()) + parent_array.AppendValue(cf_number.get(), true); + } + break; + + default: + assert (!"unhandled result"); + break; + } +} + + +static void +AddResultToDictionary (CFCMutableDictionary &parent_dict, const char *key, Results::Result *result) +{ + assert (key && key[0]); + CFCString cf_key(key); + switch (result->GetType()) + { + case Results::Result::Type::Invalid: + break; + + case Results::Result::Type::Array: + { + Results::Array *value = result->GetAsArray(); + CFCMutableArray array; + value->ForEach([&array](const Results::ResultSP &value_sp) -> bool + { + AddResultToArray (array, value_sp.get()); + return true; + }); + parent_dict.AddValue(cf_key.get(), array.get(), true); + } + break; + case Results::Result::Type::Dictionary: + { + Results::Dictionary *value = result->GetAsDictionary(); + CFCMutableDictionary dict; + value->ForEach([&dict](const std::string &key, const Results::ResultSP &value_sp) -> bool + { + AddResultToDictionary (dict, key.c_str(), value_sp.get()); + return true; + }); + if (result->GetDescription()) + { + dict.AddValueCString(CFSTR("description"), result->GetDescription()); + } + parent_dict.AddValue(cf_key.get(), dict.get(), true); + } + break; + case Results::Result::Type::Double: + { + parent_dict.SetValueDouble(cf_key.get(), result->GetAsDouble()->GetValue(), true); + } + break; + case Results::Result::Type::String: + { + parent_dict.SetValueCString(cf_key.get(), result->GetAsString()->GetValue(), true); + } + break; + + case Results::Result::Type::Unsigned: + { + parent_dict.SetValueUInt64 (cf_key.get(), result->GetAsUnsigned()->GetValue(), true); + } + break; + default: + assert (!"unhandled result"); + break; + } +} +void +Results::Write (const char *out_path) +{ +#ifdef __APPLE__ + CFCMutableDictionary dict; + + m_results.ForEach([&dict](const std::string &key, const ResultSP &value_sp) -> bool + { + AddResultToDictionary (dict, key.c_str(), value_sp.get()); + return true; + }); + CFDataRef xmlData = CFPropertyListCreateData(kCFAllocatorDefault, dict.get(), kCFPropertyListXMLFormat_v1_0, 0, NULL); + + if (out_path == NULL) + out_path = "/dev/stdout"; + + CFURLRef file = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8*)out_path, strlen(out_path), FALSE); + + CFURLWriteDataAndPropertiesToResource(file, xmlData, NULL, NULL); +#endif +} + +Results::ResultSP +Results::Dictionary::AddUnsigned (const char *name, const char *description, uint64_t value) +{ + assert (name && name[0]); + if (description && description[0]) + { + std::unique_ptr<Results::Dictionary> value_dict_ap (new Results::Dictionary ()); + value_dict_ap->AddString("description", NULL, description); + value_dict_ap->AddUnsigned("value", NULL, value); + m_dictionary[std::string(name)] = ResultSP (value_dict_ap.release()); + } + else + m_dictionary[std::string(name)] = ResultSP (new Unsigned (name, description, value)); + return m_dictionary[std::string(name)]; +} + +Results::ResultSP +Results::Dictionary::AddDouble (const char *name, const char *description, double value) +{ + assert (name && name[0]); + + if (description && description[0]) + { + std::unique_ptr<Results::Dictionary> value_dict_ap (new Results::Dictionary ()); + value_dict_ap->AddString("description", NULL, description); + value_dict_ap->AddDouble("value", NULL, value); + m_dictionary[std::string(name)] = ResultSP (value_dict_ap.release()); + } + else + m_dictionary[std::string(name)] = ResultSP (new Double (name, description, value)); + return m_dictionary[std::string(name)]; +} +Results::ResultSP +Results::Dictionary::AddString (const char *name, const char *description, const char *value) +{ + assert (name && name[0]); + if (description && description[0]) + { + std::unique_ptr<Results::Dictionary> value_dict_ap (new Results::Dictionary ()); + value_dict_ap->AddString("description", NULL, description); + value_dict_ap->AddString("value", NULL, value); + m_dictionary[std::string(name)] = ResultSP (value_dict_ap.release()); + } + else + m_dictionary[std::string(name)] = ResultSP (new String (name, description, value)); + return m_dictionary[std::string(name)]; +} + +Results::ResultSP +Results::Dictionary::Add (const char *name, const char *description, const ResultSP &result_sp) +{ + assert (name && name[0]); + if (description && description[0]) + { + std::unique_ptr<Results::Dictionary> value_dict_ap (new Results::Dictionary ()); + value_dict_ap->AddString("description", NULL, description); + value_dict_ap->Add("value", NULL, result_sp); + m_dictionary[std::string(name)] = ResultSP (value_dict_ap.release()); + } + else + m_dictionary[std::string(name)] = result_sp; + return m_dictionary[std::string(name)]; +} + +void +Results::Dictionary::ForEach (const std::function <bool (const std::string &, const ResultSP &)> &callback) +{ + collection::const_iterator pos, end = m_dictionary.end(); + for (pos = m_dictionary.begin(); pos != end; ++pos) + { + if (callback (pos->first.c_str(), pos->second) == false) + return; + } +} + + + +Results::ResultSP +Results::Array::Append (const ResultSP &result_sp) +{ + m_array.push_back (result_sp); + return result_sp; +} + +void +Results::Array::ForEach (const std::function <bool (const ResultSP &)> &callback) +{ + collection::const_iterator pos, end = m_array.end(); + for (pos = m_array.begin(); pos != end; ++pos) + { + if (callback (*pos) == false) + return; + } +} + + + diff --git a/tools/lldb-perf/lib/Results.h b/tools/lldb-perf/lib/Results.h new file mode 100644 index 000000000000..388077e7f581 --- /dev/null +++ b/tools/lldb-perf/lib/Results.h @@ -0,0 +1,312 @@ +//===-- Results.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __PerfTestDriver_Results_h__ +#define __PerfTestDriver_Results_h__ + +#include "lldb/lldb-forward.h" +#include <map> +#include <string> +#include <vector> + +namespace lldb_perf { + +class Results +{ +public: + class Array; + class Dictionary; + class Double; + class String; + class Unsigned; + + class Result + { + public: + enum class Type + { + Invalid, + Array, + Dictionary, + Double, + String, + Unsigned + }; + + Result (Type type, const char *name, const char *description) : + m_name (), + m_description(), + m_type (type) + { + if (name && name[0]) + m_name = name; + if (description && description[0]) + m_description = description; + } + + virtual + ~Result() + { + } + + virtual void + Write (Results &results) = 0; + + Array * + GetAsArray () + { + if (m_type == Type::Array) + return (Array *)this; + return NULL; + } + Dictionary * + GetAsDictionary () + { + if (m_type == Type::Dictionary) + return (Dictionary *)this; + return NULL; + } + Double * + GetAsDouble () + { + if (m_type == Type::Double) + return (Double *)this; + return NULL; + } + + String * + GetAsString () + { + if (m_type == Type::String) + return (String *)this; + return NULL; + } + Unsigned * + GetAsUnsigned () + { + if (m_type == Type::Unsigned) + return (Unsigned *)this; + return NULL; + } + + const char * + GetName() const + { + if (m_name.empty()) + return NULL; + return m_name.c_str(); + } + + const char * + GetDescription() const + { + if (m_description.empty()) + return NULL; + return m_description.c_str(); + } + + Type + GetType() const + { + return m_type; + } + + protected: + std::string m_name; + std::string m_description; + Type m_type; + }; + + typedef std::shared_ptr<Result> ResultSP; + + class Array : public Result + { + public: + Array (const char *name, const char *description) : + Result (Type::Array, name, description) + { + } + + virtual + ~Array() + { + } + + ResultSP + Append (const ResultSP &result_sp); + + void + ForEach (const std::function <bool (const ResultSP &)> &callback); + + virtual void + Write (Results &results) + { + } + protected: + typedef std::vector<ResultSP> collection; + collection m_array; + }; + + class Dictionary : public Result + { + public: + Dictionary () : + Result (Type::Dictionary, NULL, NULL) + { + } + + Dictionary (const char *name, const char *description) : + Result (Type::Dictionary, name, description) + { + } + + virtual + ~Dictionary() + { + } + + virtual void + Write (Results &results) + { + } + + void + ForEach (const std::function <bool (const std::string &, const ResultSP &)> &callback); + + ResultSP + Add (const char *name, const char *description, const ResultSP &result_sp); + + ResultSP + AddDouble (const char *name, const char *descriptiorn, double value); + + ResultSP + AddUnsigned (const char *name, const char *description, uint64_t value); + + ResultSP + AddString (const char *name, const char *description, const char *value); + + protected: + + typedef std::map<std::string, ResultSP> collection; + collection m_dictionary; + }; + + class String : public Result + { + public: + String (const char *name, const char *description, const char *value) : + Result (Type::String, name, description), + m_string () + { + if (value && value[0]) + m_string = value; + } + + virtual + ~String() + { + } + + virtual void + Write (Results &results) + { + } + + const char * + GetValue () const + { + return m_string.empty() ? NULL : m_string.c_str(); + } + + protected: + std::string m_string; + }; + + class Double : public Result + { + public: + Double (const char *name, const char *description, double value) : + Result (Type::Double, name, description), + m_double (value) + { + } + + virtual + ~Double() + { + } + + virtual void + Write (Results &results) + { + } + + double + GetValue () const + { + return m_double; + } + + protected: + double m_double; + }; + + class Unsigned : public Result + { + public: + Unsigned (const char *name, const char *description, uint64_t value) : + Result (Type::Unsigned, name, description), + m_unsigned (value) + { + } + + virtual + ~Unsigned() + { + } + + virtual void + Write (Results &results) + { + } + + uint64_t + GetValue () const + { + return m_unsigned; + } + + protected: + uint64_t m_unsigned; + }; + + Results () : + m_results () + { + } + + ~Results() + { + } + + Dictionary & + GetDictionary () + { + return m_results; + } + + void + Write (const char *path); + +protected: + Dictionary m_results; +}; + +} // namespace lldb_perf +#endif // #ifndef __PerfTestDriver_Results_h__ diff --git a/tools/lldb-perf/lib/TestCase.cpp b/tools/lldb-perf/lib/TestCase.cpp new file mode 100644 index 000000000000..c23a5e519773 --- /dev/null +++ b/tools/lldb-perf/lib/TestCase.cpp @@ -0,0 +1,358 @@ +//===-- TestCase.cpp --------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TestCase.h" +#include "Results.h" +#include "Xcode.h" + +using namespace lldb_perf; + +TestCase::TestCase () : + m_debugger(), + m_target(), + m_process(), + m_thread(), + m_listener(), + m_verbose(false), + m_step(0) +{ + SBDebugger::Initialize(); + SBHostOS::ThreadCreated ("<lldb-tester.app.main>"); + m_debugger = SBDebugger::Create(false); + m_listener = m_debugger.GetListener(); + m_listener.StartListeningForEventClass (m_debugger, SBProcess::GetBroadcasterClass(), SBProcess::eBroadcastBitStateChanged | SBProcess::eBroadcastBitInterrupt); +} + +static std::string +GetShortOptionString (struct option *long_options) +{ + std::string option_string; + for (int i = 0; long_options[i].name != NULL; ++i) + { + if (long_options[i].flag == NULL) + { + option_string.push_back ((char) long_options[i].val); + switch (long_options[i].has_arg) + { + default: + case no_argument: + break; + case required_argument: + option_string.push_back (':'); + break; + case optional_argument: + option_string.append (2, ':'); + break; + } + } + } + return option_string; +} + +bool +TestCase::Setup (int& argc, const char**& argv) +{ + bool done = false; + + struct option* long_options = GetLongOptions(); + + if (long_options) + { + std::string short_option_string (GetShortOptionString(long_options)); + + #if __GLIBC__ + optind = 0; + #else + optreset = 1; + optind = 1; + #endif + while (!done) + { + int long_options_index = -1; + const int short_option = ::getopt_long_only (argc, + const_cast<char **>(argv), + short_option_string.c_str(), + long_options, + &long_options_index); + + switch (short_option) + { + case 0: + // Already handled + break; + + case -1: + done = true; + break; + + default: + done = !ParseOption(short_option, optarg); + break; + } + } + argc -= optind; + argv += optind; + } + + return false; +} + +bool +TestCase::Launch (lldb::SBLaunchInfo &launch_info) +{ + lldb::SBError error; + m_process = m_target.Launch (launch_info, error); + if (!error.Success()) + fprintf (stderr, "error: %s\n", error.GetCString()); + if (m_process.IsValid()) + return true; + return false; +} + +bool +TestCase::Launch (std::initializer_list<const char*> args) +{ + std::vector<const char*> args_vect(args); + args_vect.push_back(NULL); + lldb::SBLaunchInfo launch_info((const char**)&args_vect[0]); + return Launch(launch_info); +} + +void +TestCase::SetVerbose (bool b) +{ + m_verbose = b; +} + +bool +TestCase::GetVerbose () +{ + return m_verbose; +} + +void +TestCase::Loop () +{ + while (true) + { + bool call_test_step = false; + if (m_process.IsValid()) + { + SBEvent evt; + m_listener.WaitForEvent (UINT32_MAX, evt); + StateType state = SBProcess::GetStateFromEvent (evt); + if (m_verbose) + printf("event = %s\n",SBDebugger::StateAsCString(state)); + if (SBProcess::GetRestartedFromEvent(evt)) + { + if (m_verbose) + { + const uint32_t num_threads = m_process.GetNumThreads(); + for (auto thread_index = 0; thread_index < num_threads; thread_index++) + { + SBThread thread(m_process.GetThreadAtIndex(thread_index)); + SBFrame frame(thread.GetFrameAtIndex(0)); + SBStream strm; + strm.RedirectToFileHandle(stdout, false); + frame.GetDescription(strm); + } + puts("restarted"); + } + call_test_step = false; + } + else + { + switch (state) + { + case eStateInvalid: + case eStateDetached: + case eStateCrashed: + case eStateUnloaded: + break; + case eStateExited: + return; + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + call_test_step = false; + break; + + case eStateStopped: + case eStateSuspended: + { + call_test_step = true; + bool fatal = false; + bool selected_thread = false; + const uint32_t num_threads = m_process.GetNumThreads(); + for (auto thread_index = 0; thread_index < num_threads; thread_index++) + { + SBThread thread(m_process.GetThreadAtIndex(thread_index)); + SBFrame frame(thread.GetFrameAtIndex(0)); + SBStream strm; + strm.RedirectToFileHandle(stdout, false); + frame.GetDescription(strm); + bool select_thread = false; + StopReason stop_reason = thread.GetStopReason(); + if (m_verbose) printf("tid = 0x%llx pc = 0x%llx ",thread.GetThreadID(),frame.GetPC()); + switch (stop_reason) + { + case eStopReasonNone: + if (m_verbose) + printf("none\n"); + break; + + case eStopReasonTrace: + select_thread = true; + if (m_verbose) + printf("trace\n"); + break; + + case eStopReasonPlanComplete: + select_thread = true; + if (m_verbose) + printf("plan complete\n"); + break; + case eStopReasonThreadExiting: + if (m_verbose) + printf("thread exiting\n"); + break; + case eStopReasonExec: + if (m_verbose) + printf("exec\n"); + break; + case eStopReasonInvalid: + if (m_verbose) + printf("invalid\n"); + break; + case eStopReasonException: + select_thread = true; + if (m_verbose) + printf("exception\n"); + fatal = true; + break; + case eStopReasonBreakpoint: + select_thread = true; + if (m_verbose) + printf("breakpoint id = %lld.%lld\n",thread.GetStopReasonDataAtIndex(0),thread.GetStopReasonDataAtIndex(1)); + break; + case eStopReasonWatchpoint: + select_thread = true; + if (m_verbose) + printf("watchpoint id = %lld\n",thread.GetStopReasonDataAtIndex(0)); + break; + case eStopReasonSignal: + select_thread = true; + if (m_verbose) + printf("signal %d\n",(int)thread.GetStopReasonDataAtIndex(0)); + break; + } + if (select_thread && !selected_thread) + { + m_thread = thread; + selected_thread = m_process.SetSelectedThread(thread); + } + } + if (fatal) + { + if (m_verbose) Xcode::RunCommand(m_debugger,"bt all",true); + exit(1); + } + } + break; + } + } + } + else + { + call_test_step = true; + } + + if (call_test_step) + { + do_the_call: + if (m_verbose) + printf("RUNNING STEP %d\n",m_step); + ActionWanted action; + TestStep(m_step, action); + m_step++; + SBError err; + switch (action.type) + { + case ActionWanted::Type::eNone: + // Just exit and wait for the next event + break; + case ActionWanted::Type::eContinue: + err = m_process.Continue(); + break; + case ActionWanted::Type::eStepOut: + if (action.thread.IsValid() == false) + { + if (m_verbose) + { + Xcode::RunCommand(m_debugger,"bt all",true); + printf("error: invalid thread for step out on step %d\n", m_step); + } + exit(501); + } + m_process.SetSelectedThread(action.thread); + action.thread.StepOut(); + break; + case ActionWanted::Type::eStepOver: + if (action.thread.IsValid() == false) + { + if (m_verbose) + { + Xcode::RunCommand(m_debugger,"bt all",true); + printf("error: invalid thread for step over %d\n",m_step); + } + exit(500); + } + m_process.SetSelectedThread(action.thread); + action.thread.StepOver(); + break; + case ActionWanted::Type::eRelaunch: + if (m_process.IsValid()) + { + m_process.Kill(); + m_process.Clear(); + } + Launch(action.launch_info); + break; + case ActionWanted::Type::eKill: + if (m_verbose) + printf("kill\n"); + m_process.Kill(); + return; + case ActionWanted::Type::eCallNext: + goto do_the_call; + break; + } + } + + } + + if (GetVerbose()) printf("I am gonna die at step %d\n",m_step); +} + +int +TestCase::Run (TestCase& test, int argc, const char** argv) +{ + if (test.Setup(argc, argv)) + { + test.Loop(); + Results results; + test.WriteResults(results); + return RUN_SUCCESS; + } + else + return RUN_SETUP_ERROR; +} + diff --git a/tools/lldb-perf/lib/TestCase.h b/tools/lldb-perf/lib/TestCase.h new file mode 100644 index 000000000000..811d0432b58a --- /dev/null +++ b/tools/lldb-perf/lib/TestCase.h @@ -0,0 +1,205 @@ +//===-- TestCase.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __PerfTestDriver__TestCase__ +#define __PerfTestDriver__TestCase__ + +#include "lldb/API/LLDB.h" +#include "Measurement.h" +#include <getopt.h> + +namespace lldb_perf { + +class Results; + +class TestCase +{ +public: + TestCase(); + + struct ActionWanted + { + enum class Type + { + eStepOver, + eContinue, + eStepOut, + eRelaunch, + eCallNext, + eNone, + eKill + } type; + lldb::SBThread thread; + lldb::SBLaunchInfo launch_info; + + ActionWanted () : + type (Type::eContinue), + thread (), + launch_info (NULL) + { + } + + void + None () + { + type = Type::eNone; + thread = lldb::SBThread(); + } + + void + Continue() + { + type = Type::eContinue; + thread = lldb::SBThread(); + } + + void + StepOver (lldb::SBThread t) + { + type = Type::eStepOver; + thread = t; + } + + void + StepOut (lldb::SBThread t) + { + type = Type::eStepOut; + thread = t; + } + + void + Relaunch (lldb::SBLaunchInfo l) + { + type = Type::eRelaunch; + thread = lldb::SBThread(); + launch_info = l; + } + + void + Kill () + { + type = Type::eKill; + thread = lldb::SBThread(); + } + + void + CallNext () + { + type = Type::eCallNext; + thread = lldb::SBThread(); + } + }; + + virtual + ~TestCase () + { + } + + virtual bool + Setup (int& argc, const char**& argv); + + virtual void + TestStep (int counter, ActionWanted &next_action) = 0; + + bool + Launch (lldb::SBLaunchInfo &launch_info); + + bool + Launch (std::initializer_list<const char*> args = {}); + + void + Loop(); + + void + SetVerbose (bool); + + bool + GetVerbose (); + + virtual void + WriteResults (Results &results) = 0; + + template <typename G,typename A> + Measurement<G,A> CreateMeasurement (A a, const char* name = NULL, const char* description = NULL) + { + return Measurement<G,A> (a,name, description); + } + + template <typename A> + TimeMeasurement<A> CreateTimeMeasurement (A a, const char* name = NULL, const char* description = NULL) + { + return TimeMeasurement<A> (a,name, description); + } + + template <typename A> + MemoryMeasurement<A> CreateMemoryMeasurement (A a, const char* name = NULL, const char* description = NULL) + { + return MemoryMeasurement<A> (a,name, description); + } + + static int + Run (TestCase& test, int argc, const char** argv); + + virtual bool + ParseOption (int short_option, const char* optarg) + { + return false; + } + + virtual struct option* + GetLongOptions () + { + return NULL; + } + + lldb::SBDebugger & + GetDebugger() + { + return m_debugger; + } + + lldb::SBTarget & + GetTarget() + { + return m_target; + } + + lldb::SBProcess & + GetProcess () + { + return m_process; + } + + lldb::SBThread & + GetThread () + { + return m_thread; + } + + int + GetStep () + { + return m_step; + } + + static const int RUN_SUCCESS = 0; + static const int RUN_SETUP_ERROR = 100; + +protected: + lldb::SBDebugger m_debugger; + lldb::SBTarget m_target; + lldb::SBProcess m_process; + lldb::SBThread m_thread; + lldb::SBListener m_listener; + bool m_verbose; + int m_step; +}; +} + +#endif /* defined(__PerfTestDriver__TestCase__) */ diff --git a/tools/lldb-perf/lib/Timer.cpp b/tools/lldb-perf/lib/Timer.cpp new file mode 100644 index 000000000000..4bbab904c63e --- /dev/null +++ b/tools/lldb-perf/lib/Timer.cpp @@ -0,0 +1,61 @@ +//===-- Timer.cpp -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Timer.h" +#include <assert.h> + +using namespace lldb_perf; + +TimeGauge::TimeType +TimeGauge::Now () +{ + return high_resolution_clock::now(); +} + +TimeGauge::TimeGauge () : + m_start(), + m_state(TimeGauge::State::eNeverUsed) +{ +} + +void +TimeGauge::Start () +{ + m_state = TimeGauge::State::eCounting; + m_start = Now(); +} + +double +TimeGauge::Stop () +{ + m_stop = Now(); + assert(m_state == TimeGauge::State::eCounting && "cannot stop a non-started clock"); + m_state = TimeGauge::State::eStopped; + m_delta = duration_cast<duration<double>>(m_stop-m_start).count(); + return m_delta; +} + +double +TimeGauge::GetStartValue () const +{ + return (double)m_start.time_since_epoch().count() * (double)system_clock::period::num / (double)system_clock::period::den; +} + +double +TimeGauge::GetStopValue () const +{ + return (double)m_stop.time_since_epoch().count() * (double)system_clock::period::num / (double)system_clock::period::den; +} + +double +TimeGauge::GetDeltaValue () const +{ + assert(m_state == TimeGauge::State::eStopped && "clock must be used before you can evaluate it"); + return m_delta; +} diff --git a/tools/lldb-perf/lib/Timer.h b/tools/lldb-perf/lib/Timer.h new file mode 100644 index 000000000000..ff179355cd43 --- /dev/null +++ b/tools/lldb-perf/lib/Timer.h @@ -0,0 +1,66 @@ +//===-- Timer.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __PerfTestDriver__Timer__ +#define __PerfTestDriver__Timer__ + +#include "Gauge.h" + +#include <chrono> + +using namespace std::chrono; + +namespace lldb_perf +{ +class TimeGauge : public Gauge<double> +{ +public: + TimeGauge (); + + virtual + ~TimeGauge () + { + } + + void + Start (); + + double + Stop (); + + virtual double + GetStartValue () const; + + virtual double + GetStopValue () const; + + virtual double + GetDeltaValue () const; + +private: + enum class State + { + eNeverUsed, + eCounting, + eStopped + }; + + typedef high_resolution_clock::time_point TimeType; + TimeType m_start; + TimeType m_stop; + double m_delta; + State m_state; + + TimeType + Now (); + +}; +} + +#endif /* defined(__PerfTestDriver__Timer__) */ diff --git a/tools/lldb-perf/lib/Xcode.cpp b/tools/lldb-perf/lib/Xcode.cpp new file mode 100644 index 000000000000..7b35e1c8cb54 --- /dev/null +++ b/tools/lldb-perf/lib/Xcode.cpp @@ -0,0 +1,165 @@ +//===-- Xcode.cpp -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Xcode.h" +#include <string> + +using namespace std; +using namespace lldb_perf; + +void +Xcode::FetchVariable (SBValue value, uint32_t expand, bool verbose) +{ + auto name = value.GetName(); + auto num_value = value.GetValueAsUnsigned(0); + auto summary = value.GetSummary(); + auto in_scope = value.IsInScope(); + auto has_children = value.MightHaveChildren(); + auto type_1 = value.GetType(); + auto type_2 = value.GetType(); + auto type_name_1 = value.GetTypeName(); + auto type_3 = value.GetType(); + auto type_name_2 = value.GetTypeName(); + if (verbose) + printf("%s %s = 0x%llx (%llu) %s\n",value.GetTypeName(),value.GetName(),num_value, num_value,summary); + if (expand > 0) + { + auto count = value.GetNumChildren(); + for (int i = 0; i < count; i++) + { + SBValue child(value.GetChildAtIndex(i, lldb::eDynamicCanRunTarget, true)); + FetchVariable (child,expand-1,verbose); + } + } +} + +void +Xcode::FetchModules (SBTarget target, bool verbose) +{ + auto count = target.GetNumModules(); + for (int i = 0; i < count; i++) + { + SBModule module(target.GetModuleAtIndex(i)); + auto fspec = module.GetFileSpec(); + std::string path(1024,0); + fspec.GetPath(&path[0],1024); + auto uuid = module.GetUUIDBytes(); + if (verbose) + { + printf("%s %s\n",path.c_str(),module.GetUUIDString()); + } + } +} + +void +Xcode::FetchVariables (SBFrame frame, uint32_t expand, bool verbose) +{ + auto values = frame.GetVariables (true,true,true,false, eDynamicCanRunTarget); + auto count = values.GetSize(); + for (int i = 0; i < count; i++) + { + SBValue value(values.GetValueAtIndex(i)); + FetchVariable (value,expand,verbose); + } +} + +void +Xcode::FetchFrames(SBProcess process, bool variables, bool verbose) +{ + auto pCount = process.GetNumThreads(); + for (int p = 0; p < pCount; p++) + { + SBThread thread(process.GetThreadAtIndex(p)); + auto tCount = thread.GetNumFrames (); + if (verbose) + printf("%s %d %d {%d}\n",thread.GetQueueName(),tCount,thread.GetStopReason(),eStopReasonBreakpoint); + for (int t = 0; t < tCount; t++) + { + SBFrame frame(thread.GetFrameAtIndex(t)); + auto fp = frame.GetFP(); + SBThread thread_dup = frame.GetThread(); + SBFileSpec filespec(process.GetTarget().GetExecutable()); + std::string path(1024,0); + filespec.GetPath(&path[0],1024); + auto state = process.GetState(); + auto pCount_dup = process.GetNumThreads(); + auto byte_size = process.GetAddressByteSize(); + auto pc = frame.GetPC(); + SBSymbolContext context(frame.GetSymbolContext(0x0000006e)); + SBModule module(context.GetModule()); + SBLineEntry entry(context.GetLineEntry()); + SBFileSpec entry_filespec(process.GetTarget().GetExecutable()); + std::string entry_path(1024,0); + entry_filespec.GetPath(&entry_path[0],1024); + auto line_1 = entry.GetLine(); + auto line_2 = entry.GetLine(); + auto fname = frame.GetFunctionName(); + if (verbose) + printf("%llu %s %d %d %llu %s %d %s\n",fp,path.c_str(),state,byte_size,pc,entry_path.c_str(),line_1,fname); + if (variables) + FetchVariables (frame, 0, verbose); + } + } +} + +void +Xcode::RunExpression (SBFrame frame, const char* expression, bool po, bool verbose) +{ + SBValue value (frame.EvaluateExpression (expression, eDynamicCanRunTarget)); + FetchVariable (value,0,verbose); + if (po) + { + auto descr = value.GetObjectDescription(); + if (descr) + printf("po = %s\n",descr); + } +} + +void +Xcode::Next (SBThread thread) +{ + thread.StepOver(); +} + +void +Xcode::Continue (SBProcess process) +{ + process.Continue(); +} + +void +Xcode::RunCommand (SBDebugger debugger, const char* cmd, bool verbose) +{ + SBCommandReturnObject sb_ret; + auto interpreter = debugger.GetCommandInterpreter(); + interpreter.HandleCommand(cmd,sb_ret); + if (verbose) + printf("%s\n%s\n",sb_ret.GetOutput(false),sb_ret.GetError(false)); +} + +SBThread +Xcode::GetThreadWithStopReason (SBProcess process, StopReason reason) +{ + auto threads_count = process.GetNumThreads(); + for (auto thread_num = 0; thread_num < threads_count; thread_num++) + { + SBThread thread(process.GetThreadAtIndex(thread_num)); + if (thread.GetStopReason() == reason) + { + return thread; + } + } + return SBThread(); +} + +SBBreakpoint +Xcode::CreateFileLineBreakpoint (SBTarget target, const char* file, uint32_t line) +{ + return target.BreakpointCreateByLocation(file, line); +} diff --git a/tools/lldb-perf/lib/Xcode.h b/tools/lldb-perf/lib/Xcode.h new file mode 100644 index 000000000000..77e025369372 --- /dev/null +++ b/tools/lldb-perf/lib/Xcode.h @@ -0,0 +1,64 @@ +//===-- Xcode.h -------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef __PerfTestDriver__Xcode__ +#define __PerfTestDriver__Xcode__ + +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBValue.h" +#include "lldb/API/SBTarget.h" +#include "lldb/API/SBModule.h" +#include "lldb/API/SBProcess.h" +#include "lldb/API/SBLineEntry.h" +#include "lldb/API/SBThread.h" +#include "lldb/API/SBDebugger.h" +#include "lldb/API/SBCommandInterpreter.h" +#include "lldb/API/SBCommandReturnObject.h" +#include "lldb/API/SBBreakpoint.h" + +using namespace lldb; + +namespace lldb_perf +{ +class Xcode +{ +public: + static void + FetchVariable (SBValue value, uint32_t expand = 0, bool verbose = false); + + static void + FetchModules (SBTarget target, bool verbose = false); + + static void + FetchVariables (SBFrame frame, uint32_t expand = 0, bool verbose = false); + + static void + FetchFrames (SBProcess process, bool variables = false, bool verbose = false); + + static void + RunExpression (SBFrame frame, const char* expression, bool po = false, bool verbose = false); + + static void + Next (SBThread thread); + + static void + Continue (SBProcess process); + + static void + RunCommand (SBDebugger debugger, const char* cmd, bool verbose = false); + + static SBThread + GetThreadWithStopReason (SBProcess process, StopReason reason); + + static SBBreakpoint + CreateFileLineBreakpoint (SBTarget target, const char* file, uint32_t line); +}; +} + +#endif /* defined(__PerfTestDriver__Xcode__) */ |