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