Home | History | Annotate | Download | only in sketch
      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 
     23 using namespace lldb_perf;
     24 
     25 static 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 
     33 class SketchTest : public TestCase
     34 {
     35 public:
     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         static int launch = 1;
    205         switch (counter % 10)
    206         {
    207         case 0:
    208             {
    209                 DoTest ();
    210                 if (counter == 0)
    211                     m_file_line_bp_measurement("SKTDocument.m",254);
    212                 next_action.Continue();
    213             }
    214             break;
    215 
    216         case 1:
    217             {
    218                 DoTest ();
    219                 m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"properties");
    220                 m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"[properties description]");
    221                 m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"typeName");
    222                 m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"data");
    223                 m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"[data description]");
    224                 next_action.Continue();
    225             }
    226             break;
    227 
    228         case 2:
    229             {
    230                 DoTest ();
    231                 next_action.Continue();
    232             }
    233             break;
    234 
    235         case 3:
    236             {
    237                 DoTest ();
    238                 next_action.StepOver(m_thread);
    239             }
    240             break;
    241 
    242         case 4:
    243             {
    244                 DoTest ();
    245                 m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"layoutManager");
    246                 m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"contents");
    247                 next_action.StepOver(m_thread);
    248             }
    249             break;
    250 
    251         case 5:
    252             {
    253                 DoTest ();
    254                 next_action.StepOver(m_thread);
    255             }
    256             break;
    257 
    258         case 6:
    259             {
    260                 DoTest ();
    261                 next_action.StepOver(m_thread);
    262             }
    263             break;
    264 
    265         case 7:
    266             {
    267                 DoTest ();
    268                 m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"@\"an NSString\"");
    269                 m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"[(id)@\"an NSString\" description]");
    270                 m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"@[@1,@2,@3]");
    271                 next_action.StepOut(m_thread);
    272             }
    273             break;
    274 
    275         case 8:
    276             {
    277                 DoTest ();
    278                 m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"[graphics description]");
    279                 m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"[selectionIndexes description]");
    280                 m_run_expr_measurement(m_thread.GetFrameAtIndex(0),"(BOOL)NSIntersectsRect(rect, graphicDrawingBounds)");
    281             }
    282             next_action.CallNext();
    283             break;
    284         case 9:
    285             if (++launch < 10)
    286                 next_action.Relaunch(GetLaunchInfo());
    287             else
    288                 next_action.Kill();
    289             break;
    290 
    291 
    292         default:
    293             {
    294                 next_action.Kill();
    295             }
    296             break;
    297         }
    298     }
    299 
    300     virtual void
    301     WriteResults (Results &results)
    302     {
    303         m_fetch_frames_measurement.WriteAverageAndStandardDeviation(results);
    304         m_file_line_bp_measurement.WriteAverageAndStandardDeviation(results);
    305         m_fetch_modules_measurement.WriteAverageAndStandardDeviation(results);
    306         m_fetch_vars_measurement.WriteAverageAndStandardDeviation(results);
    307         m_run_expr_measurement.WriteAverageAndStandardDeviation(results);
    308         results.Write(GetResultFilePath());
    309     }
    310 
    311     void
    312     SetExecutablePath (const char* str)
    313     {
    314         if (str)
    315             m_app_path.assign(str);
    316     }
    317 
    318     const char*
    319     GetExecutablePath ()
    320     {
    321         if (m_app_path.empty())
    322             return NULL;
    323         return m_app_path.c_str();
    324     }
    325 
    326     void
    327     SetDocumentPath (const char* str)
    328     {
    329         if (str)
    330             m_doc_path.assign(str);
    331     }
    332 
    333     const char*
    334     GetDocumentPath ()
    335     {
    336         if (m_doc_path.empty())
    337             return NULL;
    338         return m_doc_path.c_str();
    339     }
    340 
    341 
    342     void
    343     SetResultFilePath (const char* str)
    344     {
    345         if (str)
    346             m_out_path.assign(str);
    347     }
    348 
    349     const char*
    350     GetResultFilePath ()
    351     {
    352         if (m_out_path.empty())
    353             return "/dev/stdout";
    354         return m_out_path.c_str();
    355     }
    356 
    357     bool
    358     GetPrintHelp ()
    359     {
    360         return m_print_help;
    361     }
    362 
    363 private:
    364     Measurement<lldb_perf::TimeGauge, std::function<void()>> m_fetch_frames_measurement;
    365     Measurement<lldb_perf::TimeGauge, std::function<void(const char*, uint32_t)>> m_file_line_bp_measurement;
    366     Measurement<lldb_perf::TimeGauge, std::function<void()>> m_fetch_modules_measurement;
    367     Measurement<lldb_perf::TimeGauge, std::function<void(int)>> m_fetch_vars_measurement;
    368     Measurement<lldb_perf::TimeGauge, std::function<void(SBFrame, const char*)>> m_run_expr_measurement;
    369 
    370     std::string m_app_path;
    371     std::string m_doc_path;
    372     std::string m_out_path;
    373     bool m_print_help;
    374 };
    375 
    376 int main(int argc, const char * argv[])
    377 {
    378     SketchTest test;
    379     return TestCase::Run(test, argc, argv);
    380 }
    381