Home | History | Annotate | Download | only in clang
      1 //===-- lldb_perf_clang.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 "lldb-perf/lib/Timer.h"
     11 #include "lldb-perf/lib/Metric.h"
     12 #include "lldb-perf/lib/Measurement.h"
     13 #include "lldb-perf/lib/Results.h"
     14 #include "lldb-perf/lib/TestCase.h"
     15 #include "lldb-perf/lib/Xcode.h"
     16 #include <iostream>
     17 #include <unistd.h>
     18 #include <fstream>
     19 #include <getopt.h>
     20 
     21 using namespace lldb_perf;
     22 
     23 #define NUM_EXPR_ITERATIONS 3
     24 class ClangTest : public TestCase
     25 {
     26 public:
     27     ClangTest () :
     28         TestCase(),
     29         m_time_create_target ([this] () -> void
     30                               {
     31                                   m_memory_change_create_target.Start();
     32                                   m_target = m_debugger.CreateTarget(m_exe_path.c_str());
     33                                   m_memory_change_create_target.Stop();
     34                               }, "time-create-target", "The time it takes to create a target."),
     35         m_time_set_bp_main([this] () -> void
     36                               {
     37                                   m_memory_change_break_main.Start();
     38                                   m_target.BreakpointCreateByName("main");
     39                                   m_memory_change_break_main.Stop();
     40                               }, "time-set-break-main", "Elapsed time it takes to set a breakpoint at 'main' by name."),
     41         m_memory_change_create_target (),
     42         m_memory_change_break_main (),
     43         m_memory_total (),
     44         m_time_launch_stop_main(),
     45         m_time_total (),
     46         m_expr_first_evaluate([this] (SBFrame frame) -> void
     47                           {
     48                               frame.EvaluateExpression("Diags.DiagArgumentsStr[0].size()").GetError();
     49                           }, "time-expr", "Elapsed time it takes to evaluate an expression for the first time."),
     50         m_expr_frame_zero ([this] (SBFrame frame) -> void
     51                        {
     52                            frame.EvaluateExpression("Diags.DiagArgumentsStr[0].size()").GetError();
     53                        }, "time-expr-frame-zero", "Elapsed time it takes to evaluate an expression 3 times at frame zero."),
     54         m_expr_frame_non_zero ([this] (SBFrame frame) -> void
     55                            {
     56                                frame.EvaluateExpression("Diags.DiagArgumentsStr[0].size()").GetError();
     57                            }, "time-expr-frame-non-zero", "Elapsed time it takes to evaluate an expression 3 times at a non-zero frame."),
     58         m_exe_path(),
     59         m_out_path(),
     60         m_launch_info (NULL),
     61         m_use_dsym (false)
     62     {
     63     }
     64 
     65     virtual
     66     ~ClangTest ()
     67     {
     68     }
     69 
     70     virtual bool
     71 	Setup (int& argc, const char**& argv)
     72     {
     73         if (m_exe_path.empty())
     74             return false;
     75         m_launch_info.SetArguments(argv, false);
     76         return true;
     77     }
     78 
     79     void
     80     DoTest ()
     81     {
     82     }
     83 
     84 	virtual void
     85 	TestStep (int counter, ActionWanted &next_action)
     86     {
     87         switch (counter)
     88         {
     89             case 0:
     90                 {
     91                     //Xcode::RunCommand(m_debugger,"log enable -f /tmp/packets.txt gdb-remote packets",true);
     92 
     93                     m_memory_total.Start();
     94                     m_time_total.Start();
     95 
     96                     // Time creating the target
     97                     m_time_create_target();
     98 
     99                     m_time_set_bp_main();
    100 
    101                     m_time_launch_stop_main.Start();
    102                     const char *clang_argv[] = {
    103                         "-cc1",
    104                         "-triple", "x86_64-apple-macosx10.8.0",
    105                         "-emit-obj",
    106                         "-mrelax-all",
    107                         "-disable-free",
    108                         "-disable-llvm-verifier",
    109                         "-main-file-name", "main.cpp",
    110                         "-mrelocation-model", "pic",
    111                         "-pic-level", "2",
    112                         "-mdisable-fp-elim",
    113                         "-masm-verbose",
    114                         "-munwind-tables",
    115                         "-target-cpu", "core2",
    116                         "-target-linker-version", "132.10.1",
    117                         "-v",
    118                         "-g",
    119                         "-resource-dir", "/tmp/clang-176809/llvm-build/build/Debug/bin/../lib/clang/3.3",
    120                         "-O0",
    121                         "-fdeprecated-macro",
    122                         "-fdebug-compilation-dir", "/tmp/clang-176809/llvm-build/build/Debug/bin",
    123                         "-ferror-limit", "19",
    124                         "-fmessage-length", "298",
    125                         "-stack-protector", "1",
    126                         "-mstackrealign",
    127                         "-fblocks",
    128                         "-fobjc-runtime=macosx-10.8.0",
    129                         "-fobjc-dispatch-method=mixed",
    130                         "-fobjc-default-synthesize-properties",
    131                         "-fencode-extended-block-signature",
    132                         "-fcxx-exceptions",
    133                         "-fexceptions",
    134                         "-fdiagnostics-show-option",
    135                         "-fcolor-diagnostics",
    136                         "-backend-option",
    137                         "-vectorize-loops",
    138                         "-o", "/tmp/main.o",
    139                         "-x", "c++",
    140                         "/tmp/main.cpp",
    141                         NULL };
    142                     SBLaunchInfo launch_info(clang_argv);
    143                     Launch (launch_info);
    144                 }
    145                 break;
    146             case 1:
    147                 puts("stop");
    148                 m_time_launch_stop_main.Stop();
    149                 m_time_total.Stop();
    150             case 2:
    151                 {
    152                     SBFrame frame (m_thread.GetFrameAtIndex(0));
    153 
    154                     // Time the first expression evaluation
    155                     m_expr_first_evaluate(frame);
    156 
    157                     SBValue result;
    158                     for (size_t i=0; i<NUM_EXPR_ITERATIONS; ++i)
    159                     {
    160                         m_expr_frame_zero(frame);
    161                     }
    162                     m_target.BreakpointCreateByName("DeclContext::lookup");
    163                     next_action.Continue();
    164                 }
    165                 break;
    166             case 3:
    167                 {
    168                     SBFrame frame (m_thread.GetFrameAtIndex(21));
    169                     SBValue result;
    170                     for (size_t i=0; i<NUM_EXPR_ITERATIONS; ++i)
    171                     {
    172                         m_expr_frame_non_zero(frame);
    173                     }
    174                     m_target.BreakpointCreateByName("DeclContext::lookup");
    175                     next_action.Continue();
    176                 }
    177                 break;
    178             default:
    179                 m_memory_total.Stop();
    180                 next_action.Kill();
    181                 break;
    182         }
    183     }
    184 
    185     void
    186     WriteResults (Results &results)
    187     {
    188         Results::Dictionary& results_dict = results.GetDictionary();
    189 
    190         m_time_set_bp_main.WriteAverageAndStandardDeviation(results);
    191         results_dict.Add ("memory-change-create-target",
    192                           "Memory increase that occurs due to creating the target.",
    193                           m_memory_change_create_target.GetDeltaValue().GetResult(NULL, NULL));
    194 
    195         results_dict.Add ("memory-change-break-main",
    196                           "Memory increase that occurs due to setting a breakpoint at main by name.",
    197                           m_memory_change_break_main.GetDeltaValue().GetResult(NULL, NULL));
    198 
    199         m_time_create_target.WriteAverageAndStandardDeviation(results);
    200         m_expr_first_evaluate.WriteAverageAndStandardDeviation(results);
    201         m_expr_frame_zero.WriteAverageAndStandardDeviation(results);
    202         m_expr_frame_non_zero.WriteAverageAndStandardDeviation(results);
    203         results_dict.Add ("memory-total-break-main",
    204                           "The total memory that the current process is using after setting the first breakpoint.",
    205                           m_memory_total.GetStopValue().GetResult(NULL, NULL));
    206 
    207         results_dict.AddDouble("time-launch-stop-main",
    208                                "The time it takes to launch the process and stop at main.",
    209                                m_time_launch_stop_main.GetDeltaValue());
    210 
    211         results_dict.AddDouble("time-total",
    212                                "The time it takes to create the target, set breakpoint at main, launch clang and hit the breakpoint at main.",
    213                                m_time_total.GetDeltaValue());
    214         results.Write(GetResultFilePath());
    215     }
    216 
    217 
    218 
    219     const char *
    220     GetExecutablePath () const
    221     {
    222         if (m_exe_path.empty())
    223             return NULL;
    224         return m_exe_path.c_str();
    225     }
    226 
    227     const char *
    228     GetResultFilePath () const
    229     {
    230         if (m_out_path.empty())
    231             return NULL;
    232         return m_out_path.c_str();
    233     }
    234 
    235     void
    236     SetExecutablePath (const char *path)
    237     {
    238         if (path && path[0])
    239             m_exe_path = path;
    240         else
    241             m_exe_path.clear();
    242     }
    243 
    244     void
    245     SetResultFilePath (const char *path)
    246     {
    247         if (path && path[0])
    248             m_out_path = path;
    249         else
    250             m_out_path.clear();
    251     }
    252 
    253     void
    254     SetUseDSYM (bool b)
    255     {
    256         m_use_dsym = b;
    257     }
    258 
    259 
    260 
    261 private:
    262     // C++ formatters
    263     TimeMeasurement<std::function<void()>> m_time_create_target;
    264     TimeMeasurement<std::function<void()>> m_time_set_bp_main;
    265     MemoryGauge m_memory_change_create_target;
    266     MemoryGauge m_memory_change_break_main;
    267     MemoryGauge m_memory_total;
    268     TimeGauge m_time_launch_stop_main;
    269     TimeGauge m_time_total;
    270     TimeMeasurement<std::function<void(SBFrame)>> m_expr_first_evaluate;
    271     TimeMeasurement<std::function<void(SBFrame)>> m_expr_frame_zero;
    272     TimeMeasurement<std::function<void(SBFrame)>> m_expr_frame_non_zero;
    273     std::string m_exe_path;
    274     std::string m_out_path;
    275     SBLaunchInfo m_launch_info;
    276     bool m_use_dsym;
    277 
    278 };
    279 
    280 
    281 struct Options
    282 {
    283     std::string clang_path;
    284     std::string out_file;
    285     bool verbose;
    286     bool use_dsym;
    287     bool error;
    288     bool print_help;
    289 
    290     Options() :
    291         verbose (false),
    292         error (false),
    293         print_help (false)
    294     {
    295     }
    296 };
    297 
    298 static struct option g_long_options[] = {
    299     { "verbose",    no_argument,            NULL, 'v' },
    300     { "clang",      required_argument,      NULL, 'c' },
    301     { "out-file",   required_argument,      NULL, 'o' },
    302     { "dsym",       no_argument,            NULL, 'd' },
    303     { NULL,         0,                      NULL,  0  }
    304 };
    305 
    306 
    307 std::string
    308 GetShortOptionString (struct option *long_options)
    309 {
    310     std::string option_string;
    311     for (int i = 0; long_options[i].name != NULL; ++i)
    312     {
    313         if (long_options[i].flag == NULL)
    314         {
    315             option_string.push_back ((char) long_options[i].val);
    316             switch (long_options[i].has_arg)
    317             {
    318                 default:
    319                 case no_argument:
    320                     break;
    321                 case required_argument:
    322                     option_string.push_back (':');
    323                     break;
    324                 case optional_argument:
    325                     option_string.append (2, ':');
    326                     break;
    327             }
    328         }
    329     }
    330     return option_string;
    331 }
    332 
    333 int main(int argc, const char * argv[])
    334 {
    335 
    336     // Prepare for & make calls to getopt_long_only.
    337 
    338     std::string short_option_string (GetShortOptionString(g_long_options));
    339 
    340     ClangTest test;
    341 
    342     Options option_data;
    343     bool done = false;
    344 
    345 #if __GLIBC__
    346     optind = 0;
    347 #else
    348     optreset = 1;
    349     optind = 1;
    350 #endif
    351     while (!done)
    352     {
    353         int long_options_index = -1;
    354         const int short_option = ::getopt_long_only (argc,
    355                                                      const_cast<char **>(argv),
    356                                                      short_option_string.c_str(),
    357                                                      g_long_options,
    358                                                      &long_options_index);
    359 
    360         switch (short_option)
    361         {
    362             case 0:
    363                 // Already handled
    364                 break;
    365 
    366             case -1:
    367                 done = true;
    368                 break;
    369 
    370             case '?':
    371                 option_data.print_help = true;
    372                 break;
    373 
    374             case 'h':
    375                 option_data.print_help = true;
    376                 break;
    377 
    378             case 'v':
    379                 option_data.verbose = true;
    380                 break;
    381 
    382             case 'c':
    383                 {
    384                     SBFileSpec file(optarg);
    385                     if (file.Exists())
    386                         test.SetExecutablePath(optarg);
    387                     else
    388                         fprintf(stderr, "error: file specified in --clang (-c) option doesn't exist: '%s'\n", optarg);
    389                 }
    390                 break;
    391 
    392             case 'o':
    393                 test.SetResultFilePath(optarg);
    394                 break;
    395 
    396             case 'd':
    397                 test.SetUseDSYM(true);
    398                 break;
    399 
    400             default:
    401                 option_data.error = true;
    402                 option_data.print_help = true;
    403                 fprintf (stderr, "error: unrecognized option %c\n", short_option);
    404                 break;
    405         }
    406     }
    407 
    408 
    409     if (test.GetExecutablePath() == NULL)
    410     {
    411         // --clang is mandatory
    412         option_data.print_help = true;
    413         option_data.error = true;
    414         fprintf (stderr, "error: the '--clang=PATH' option is mandatory\n");
    415     }
    416 
    417     if (option_data.print_help)
    418     {
    419         puts(R"(
    420 NAME
    421     lldb_perf_clang -- a tool that measures LLDB peformance while debugging clang.
    422 
    423 SYNOPSIS
    424     lldb_perf_clang --clang=PATH [--out-file=PATH --verbose --dsym] -- [clang options]
    425 
    426 DESCRIPTION
    427     Runs a set of static timing and memory tasks against clang and outputs results
    428     to a plist file.
    429 )");
    430     }
    431     if (option_data.error)
    432     {
    433         exit(1);
    434     }
    435 
    436     // Update argc and argv after parsing options
    437     argc -= optind;
    438     argv += optind;
    439 
    440     test.SetVerbose(true);
    441     TestCase::Run(test, argc, argv);
    442     return 0;
    443 }
    444 
    445