summaryrefslogtreecommitdiff
path: root/tools/lldb-perf/lib
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lldb-perf/lib')
-rw-r--r--tools/lldb-perf/lib/Gauge.cpp53
-rw-r--r--tools/lldb-perf/lib/Gauge.h64
-rw-r--r--tools/lldb-perf/lib/Measurement.h217
-rw-r--r--tools/lldb-perf/lib/MemoryGauge.cpp165
-rw-r--r--tools/lldb-perf/lib/MemoryGauge.h147
-rw-r--r--tools/lldb-perf/lib/Metric.cpp85
-rw-r--r--tools/lldb-perf/lib/Metric.h72
-rw-r--r--tools/lldb-perf/lib/Results.cpp275
-rw-r--r--tools/lldb-perf/lib/Results.h312
-rw-r--r--tools/lldb-perf/lib/TestCase.cpp358
-rw-r--r--tools/lldb-perf/lib/TestCase.h205
-rw-r--r--tools/lldb-perf/lib/Timer.cpp61
-rw-r--r--tools/lldb-perf/lib/Timer.h66
-rw-r--r--tools/lldb-perf/lib/Xcode.cpp165
-rw-r--r--tools/lldb-perf/lib/Xcode.h64
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__) */