sketch.cpp revision ec87e5c098f1ce1c9182d1c5438e0beca0996597
1//===-- sketch.cpp ----------------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include <CoreFoundation/CoreFoundation.h>
11
12#include "lldb-perf/lib/Timer.h"
13#include "lldb-perf/lib/Metric.h"
14#include "lldb-perf/lib/Measurement.h"
15#include "lldb-perf/lib/TestCase.h"
16#include "lldb-perf/lib/Xcode.h"
17
18#include <iostream>
19#include <unistd.h>
20#include <fstream>
21#include <getopt.h>
22
23using namespace lldb_perf;
24
25static struct option g_long_options[] = {
26    { "verbose",    no_argument,            NULL, 'v' },
27    { "sketch",     required_argument,      NULL, 'c' },
28    { "foobar",     required_argument,      NULL, 'f' },
29    { "out-file",   required_argument,      NULL, 'o' },
30    { NULL,         0,                      NULL,  0  }
31};
32
33class SketchTest : public TestCase
34{
35public:
36    SketchTest () :
37        m_fetch_frames_measurement ([this] () -> void
38            {
39                Xcode::FetchFrames (GetProcess(),false,false);
40            }, "fetch-frames", "time to dump backtrace for every frame in every thread"),
41        m_file_line_bp_measurement([this] (const char* file, uint32_t line) -> void
42            {
43                Xcode::CreateFileLineBreakpoint(GetTarget(), file, line);
44            }, "file-line-bkpt", "time to set a breakpoint given a file and line"),
45        m_fetch_modules_measurement ([this] () -> void
46            {
47                Xcode::FetchModules(GetTarget());
48            }, "fetch-modules", "time to get info for all modules in the process"),
49        m_fetch_vars_measurement([this] (int depth) -> void
50            {
51                SBProcess process (GetProcess());
52                auto threads_count = process.GetNumThreads();
53                for (size_t thread_num = 0; thread_num < threads_count; thread_num++)
54                {
55                    SBThread thread(process.GetThreadAtIndex(thread_num));
56                    SBFrame frame(thread.GetFrameAtIndex(0));
57                    Xcode::FetchVariables(frame,depth,GetVerbose());
58                }
59            }, "fetch-vars", "time to dump variables for the topmost frame in every thread"),
60        m_run_expr_measurement([this] (SBFrame frame, const char* expr) -> void
61            {
62                SBValue value(frame.EvaluateExpression(expr, lldb::eDynamicCanRunTarget));
63                Xcode::FetchVariable (value, 0, GetVerbose());
64            }, "run-expr", "time to evaluate an expression and display the result")
65    {
66        m_app_path.clear();
67        m_out_path.clear();
68        m_doc_path.clear();
69        m_print_help = false;
70    }
71
72    virtual
73    ~SketchTest ()
74    {
75    }
76
77    virtual bool
78    ParseOption (int short_option, const char* optarg)
79    {
80        switch (short_option)
81        {
82            case 0:
83                return false;
84
85            case -1:
86                return false;
87
88            case '?':
89            case 'h':
90                m_print_help = true;
91                break;
92
93            case 'v':
94                SetVerbose(true);
95                break;
96
97            case 'c':
98            {
99                SBFileSpec file(optarg);
100                if (file.Exists())
101                    SetExecutablePath(optarg);
102                else
103                    fprintf(stderr, "error: file specified in --sketch (-c) option doesn't exist: '%s'\n", optarg);
104            }
105                break;
106
107            case 'f':
108            {
109                SBFileSpec file(optarg);
110                if (file.Exists())
111                    SetDocumentPath(optarg);
112                else
113                    fprintf(stderr, "error: file specified in --foobar (-f) option doesn't exist: '%s'\n", optarg);
114            }
115                break;
116
117            case 'o':
118                SetResultFilePath(optarg);
119                break;
120
121            default:
122                m_print_help = true;
123                fprintf (stderr, "error: unrecognized option %c\n", short_option);
124                break;
125        }
126        return true;
127    }
128
129    virtual struct option*
130    GetLongOptions ()
131    {
132        return g_long_options;
133    }
134
135    virtual bool
136	Setup (int& argc, const char**& argv)
137    {
138        TestCase::Setup(argc,argv);
139        bool error = false;
140
141        if (GetExecutablePath() == NULL)
142        {
143            // --sketch is mandatory
144            error = true;
145            fprintf (stderr, "error: the '--sketch=PATH' option is mandatory\n");
146        }
147
148        if (GetDocumentPath() == NULL)
149        {
150            // --foobar is mandatory
151            error = true;
152            fprintf (stderr, "error: the '--foobar=PATH' option is mandatory\n");
153        }
154
155        if (error || GetPrintHelp())
156        {
157            puts(R"(
158                 NAME
159                 lldb_perf_sketch -- a tool that measures LLDB peformance while debugging sketch.
160
161                 SYNOPSIS
162                 lldb_perf_sketch --sketch=PATH --foobar=PATH [--out-file=PATH --verbose]
163
164                 DESCRIPTION
165                 Runs a set of static timing and memory tasks against sketch and outputs results
166                 to a plist file.
167                 )");
168        }
169
170        if (error)
171        {
172            exit(1);
173        }
174        lldb::SBLaunchInfo launch_info = GetLaunchInfo();
175        m_target = m_debugger.CreateTarget(m_app_path.c_str());
176        m_file_line_bp_measurement("SKTDocument.m",245);
177        m_file_line_bp_measurement("SKTDocument.m",283);
178        m_file_line_bp_measurement("SKTText.m",326);
179        return Launch (launch_info);
180    }
181
182    lldb::SBLaunchInfo
183    GetLaunchInfo ()
184    {
185        const char* file_arg = m_doc_path.c_str();
186        const char* persist_arg = "-ApplePersistenceIgnoreState";
187        const char* persist_skip = "YES";
188        const char* empty = nullptr;
189        const char* args[] = {file_arg,persist_arg,persist_skip,empty};
190        return SBLaunchInfo(args);
191    }
192
193    void
194    DoTest ()
195    {
196        m_fetch_frames_measurement();
197        m_fetch_modules_measurement();
198        m_fetch_vars_measurement(1);
199    }
200
201	virtual void
202	TestStep (int counter, ActionWanted &next_action)
203    {
204        switch (counter)
205        {
206        case 0:
207            case 10:
208            case 20:
209            {
210                DoTest ();
211                if (counter == 0)
212                    m_file_line_bp_measurement("SKTDocument.m",254);
213                next_action.Continue();
214            }
215            break;
216
217        case 1:
218            case 11:
219            case 21:
220            {
221                DoTest ();
222                m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"properties");
223                m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"[properties description]");
224                m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"typeName");
225                m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"data");
226                m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"[data description]");
227                next_action.Continue();
228            }
229            break;
230
231        case 2:
232            case 12:
233            case 22:
234            {
235                DoTest ();
236                next_action.Continue();
237            }
238            break;
239
240        case 3:
241            case 13:
242            case 23:
243            {
244                DoTest ();
245                next_action.StepOver(m_thread);
246            }
247            break;
248
249        case 4:
250            case 14:
251            case 24:
252
253            {
254                DoTest ();
255                m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"layoutManager");
256                m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"contents");
257                next_action.StepOver(m_thread);
258            }
259            break;
260
261        case 5:
262            case 15:
263            case 25:
264            {
265                DoTest ();
266                next_action.StepOver(m_thread);
267            }
268            break;
269
270        case 6:
271            case 16:
272            case 26:
273            {
274                DoTest ();
275                next_action.StepOver(m_thread);
276            }
277            break;
278
279        case 7:
280            case 17:
281            case 27:
282            {
283                DoTest ();
284                m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"@\"an NSString\"");
285                m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"[(id)@\"an NSString\" description]");
286                m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"@[@1,@2,@3]");
287                next_action.StepOut(m_thread);
288            }
289            break;
290
291        case 8:
292            case 18:
293            case 28:
294            {
295                DoTest ();
296                m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"[graphics description]");
297                m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"[selectionIndexes description]");
298                m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"(BOOL)NSIntersectsRect(rect, graphicDrawingBounds)");
299            }
300            break;
301        case 9:
302            case 19:
303            {
304                next_action.Relaunch(GetLaunchInfo());
305                break;
306            }
307
308        default:
309            {
310                next_action.Kill();
311            }
312            break;
313        }
314    }
315
316    virtual void
317    WriteResults (Results &results)
318    {
319        m_fetch_frames_measurement.WriteAverageAndStandardDeviation(results);
320        m_file_line_bp_measurement.WriteAverageAndStandardDeviation(results);
321        m_fetch_modules_measurement.WriteAverageAndStandardDeviation(results);
322        m_fetch_vars_measurement.WriteAverageAndStandardDeviation(results);
323        m_run_expr_measurement.WriteAverageAndStandardDeviation(results);
324        results.Write(GetResultFilePath());
325    }
326
327    void
328    SetExecutablePath (const char* str)
329    {
330        if (str)
331            m_app_path.assign(str);
332    }
333
334    const char*
335    GetExecutablePath ()
336    {
337        if (m_app_path.empty())
338            return NULL;
339        return m_app_path.c_str();
340    }
341
342    void
343    SetDocumentPath (const char* str)
344    {
345        if (str)
346            m_doc_path.assign(str);
347    }
348
349    const char*
350    GetDocumentPath ()
351    {
352        if (m_doc_path.empty())
353            return NULL;
354        return m_doc_path.c_str();
355    }
356
357
358    void
359    SetResultFilePath (const char* str)
360    {
361        if (str)
362            m_out_path.assign(str);
363    }
364
365    const char*
366    GetResultFilePath ()
367    {
368        if (m_out_path.empty())
369            return "/dev/stdout";
370        return m_out_path.c_str();
371    }
372
373    bool
374    GetPrintHelp ()
375    {
376        return m_print_help;
377    }
378
379private:
380    Measurement<lldb_perf::TimeGauge, std::function<void()>> m_fetch_frames_measurement;
381    Measurement<lldb_perf::TimeGauge, std::function<void(const char*, uint32_t)>> m_file_line_bp_measurement;
382    Measurement<lldb_perf::TimeGauge, std::function<void()>> m_fetch_modules_measurement;
383    Measurement<lldb_perf::TimeGauge, std::function<void(int)>> m_fetch_vars_measurement;
384    Measurement<lldb_perf::TimeGauge, std::function<void(SBFrame, const char*)>> m_run_expr_measurement;
385
386    std::string m_app_path;
387    std::string m_doc_path;
388    std::string m_out_path;
389    bool m_print_help;
390};
391
392int main(int argc, const char * argv[])
393{
394    SketchTest test;
395    return TestCase::Run(test, argc, argv);
396}
397