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