Changeset 91245 in webkit
- Timestamp:
- Jul 19, 2011 2:25:46 AM (13 years ago)
- Location:
- trunk/Tools
- Files:
-
- 16 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Tools/ChangeLog
r91241 r91245 1 2011-07-18 Eric Seidel <eric@webkit.org> 2 3 new-run-webkit-tests should support --leaks 4 https://bugs.webkit.org/show_bug.cgi?id=63832 5 6 Reviewed by Dirk Pranke. 7 8 This may not be sufficient to actually transition over the leaks bot, 9 but this is a huge step in the right direction. 10 11 I had to make parse-malloc-history understand being passed more than 12 one file (to avoid the silly cat | nonsense in old-run-webkit-tests). 13 14 I removed some dead code relating to previous iterations of our crash detection. 15 16 I created a new class "LeakDetector" to encapsulate all this logic. 17 Eventually we should consider pulling that class out of mac.py and 18 sharing with other ports. However given that ORWT has had 19 --leaks support on Mac for almost 7 years and no other port has added 20 it, leaves me to believe we're in no rush to move LeakDetector. 21 22 I've tested --leaks locally. I suspect there are more bugs to shake out 23 but it seems to work well enough to start. 24 25 I also added support for --guard-malloc, but have not tested it much. It 26 should be viewed as experimental at this time. 27 28 I also fixed various os.path uses to self._filesystem as I was reading 29 through the various files to understand how best to fix this bug. 30 31 * Scripts/old-run-webkit-tests: 32 (parseLeaksandPrintUniqueLeaks): 33 * Scripts/parse-malloc-history: 34 (main): 35 * Scripts/webkitpy/common/system/crashlogs.py: 36 * Scripts/webkitpy/layout_tests/controllers/manager.py: 37 * Scripts/webkitpy/layout_tests/controllers/worker.py: 38 * Scripts/webkitpy/layout_tests/port/base.py: 39 * Scripts/webkitpy/layout_tests/port/chromium_win.py: 40 * Scripts/webkitpy/layout_tests/port/gtk.py: 41 * Scripts/webkitpy/layout_tests/port/mac.py: 42 * Scripts/webkitpy/layout_tests/port/mac_unittest.py: 43 * Scripts/webkitpy/layout_tests/port/server_process.py: 44 * Scripts/webkitpy/layout_tests/port/webkit.py: 45 * Scripts/webkitpy/layout_tests/run_webkit_tests.py: 46 1 47 2011-07-19 Adam Barth <abarth@webkit.org> 2 48 -
trunk/Tools/Scripts/old-run-webkit-tests
r90125 r91245 2242 2242 { 2243 2243 return unless @leaksFilenames; 2244 2244 2245 2245 my $mergedFilenames = join " ", @leaksFilenames; 2246 2246 my $parseMallocHistoryTool = sourceDir() . "/Tools/Scripts/parse-malloc-history"; -
trunk/Tools/Scripts/parse-malloc-history
r58350 r91245 58 58 "merge-depth:i" => \$mergeDepth 59 59 ); 60 my $fileName = $ARGV[0]; 61 die $usage if (!$getOptionsResult || !$fileName); 60 die $usage if (!$getOptionsResult || !scalar(@ARGV)); 62 61 63 open FILE, "<$fileName" or die "bad file: $fileName"; 64 my @file = <FILE>; 65 close FILE; 62 my @lines = (); 63 foreach my $fileName (@ARGV) { 64 open FILE, "<$fileName" or die "bad file: $fileName"; 65 push(@lines, <FILE>); 66 close FILE; 67 } 66 68 67 69 my %callstacks = (); 68 70 my $byteCountTotal = 0; 69 71 70 for (my $i = 0; $i < @ file; $i++) {71 my $line = $ file[$i];72 for (my $i = 0; $i < @lines; $i++) { 73 my $line = $lines[$i]; 72 74 my ($callCount, $byteCount); 73 75 … … 87 89 while (!($line =~ "Call stack: ")) { 88 90 $i++; 89 $line = $ file[$i];91 $line = $lines[$i]; 90 92 } 91 93 } … … 100 102 ($byteCount) = ($line =~ /Key: (?:\d+), (\d+) bytes/); 101 103 if ($byteCount) { 102 $line = $ file[++$i];104 $line = $lines[++$i]; 103 105 my @tempStack; 104 while ($ file[$i+1] !~ /^(?:-|\d)/) {106 while ($lines[$i+1] !~ /^(?:-|\d)/) { 105 107 if ($line =~ /\): (.*)$/) { 106 108 my $call = $1; … … 108 110 unshift(@tempStack, $call); 109 111 } 110 $line = $ file[++$i];112 $line = $lines[++$i]; 111 113 } 112 114 $line = join(" | ", @tempStack); -
trunk/Tools/Scripts/webkitpy/common/system/crashlogs.py
r89899 r91245 27 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 28 29 import os30 29 import re 31 30 import sys 32 33 34 def _is_crash_reporter(process_name):35 return re.match(r"ReportCrash", process_name)36 31 37 32 … … 46 41 def _log_directory_darwin(self): 47 42 log_directory = self._filesystem.expanduser("~") 48 log_directory = os.path.join(log_directory, "Library", "Logs")49 if self._filesystem.exists( os.path.join(log_directory, "DiagnosticReports")):50 log_directory = os.path.join(log_directory, "DiagnosticReports")43 log_directory = self._filesystem.join(log_directory, "Library", "Logs") 44 if self._filesystem.exists(self._filesystem.join(log_directory, "DiagnosticReports")): 45 log_directory = self._filesystem.join(log_directory, "DiagnosticReports") 51 46 else: 52 log_directory = os.path.join(log_directory, "CrashReporter")47 log_directory = self._filesystem.join(log_directory, "CrashReporter") 53 48 return log_directory 54 49 … … 60 55 logs = self._filesystem.files_under(log_directory, file_filter=is_crash_log) 61 56 if not logs: 62 return 57 return None 63 58 return self._filesystem.read_text_file(sorted(logs)[-1]) -
trunk/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
r91210 r91245 494 494 skip_chunk = skipped 495 495 496 result_summary = ResultSummary(self._expectations, 497 self._test_files | skip_chunk) 498 self._print_expected_results_of_type(result_summary, 499 test_expectations.PASS, "passes") 500 self._print_expected_results_of_type(result_summary, 501 test_expectations.FAIL, "failures") 502 self._print_expected_results_of_type(result_summary, 503 test_expectations.FLAKY, "flaky") 504 self._print_expected_results_of_type(result_summary, 505 test_expectations.SKIP, "skipped") 496 result_summary = ResultSummary(self._expectations, self._test_files | skip_chunk) 497 self._print_expected_results_of_type(result_summary, test_expectations.PASS, "passes") 498 self._print_expected_results_of_type(result_summary, test_expectations.FAIL, "failures") 499 self._print_expected_results_of_type(result_summary, test_expectations.FLAKY, "flaky") 500 self._print_expected_results_of_type(result_summary, test_expectations.SKIP, "skipped") 506 501 507 502 if self._options.force: … … 720 715 721 716 self._printer.print_update('Sharding tests ...') 722 locked_shards, unlocked_shards = self._shard_tests(file_list, 723 int(self._options.child_processes), self._options.experimental_fully_parallel) 717 locked_shards, unlocked_shards = self._shard_tests(file_list, int(self._options.child_processes), self._options.experimental_fully_parallel) 724 718 725 719 # FIXME: We don't have a good way to coordinate the workers so that … … 739 733 self._log_num_workers(num_workers, len(all_shards), len(locked_shards)) 740 734 741 manager_connection = manager_worker_broker.get(self._port, self._options, 742 self, worker.Worker) 735 manager_connection = manager_worker_broker.get(self._port, self._options, self, worker.Worker) 743 736 744 737 if self._options.dry_run: 745 return (keyboard_interrupted, interrupted, thread_timings, 746 self._group_stats, self._all_results) 747 748 self._printer.print_update('Starting %s ...' % 749 grammar.pluralize('worker', num_workers)) 738 return (keyboard_interrupted, interrupted, thread_timings, self._group_stats, self._all_results) 739 740 self._printer.print_update('Starting %s ...' % grammar.pluralize('worker', num_workers)) 750 741 for worker_number in xrange(num_workers): 751 742 worker_connection = manager_connection.start_worker(worker_number) … … 773 764 try: 774 765 while not self.is_done(): 775 # Temporarily disabled to see how this code effect performance on the buildbots.776 # if self._port.executive.running_pids(self._port.is_crash_reporter):777 # self._printer.print_update("Waiting for crash reporter ...")778 # self._port.executive.wait_newest(self._port.is_crash_reporter)779 766 manager_connection.run_message_loop(delay_secs=1.0) 780 767 … … 809 796 810 797 # FIXME: should this be a class instead of a tuple? 811 return (interrupted, keyboard_interrupted, thread_timings, 812 self._group_stats, self._all_results) 798 return (interrupted, keyboard_interrupted, thread_timings, self._group_stats, self._all_results) 813 799 814 800 def update(self): … … 903 889 end_time = time.time() 904 890 905 self._print_timing_statistics(end_time - start_time, 906 thread_timings, test_timings, 907 individual_test_timings, 908 result_summary) 909 891 self._print_timing_statistics(end_time - start_time, thread_timings, test_timings, individual_test_timings, result_summary) 910 892 self._print_result_summary(result_summary) 911 893 … … 913 895 sys.stderr.flush() 914 896 915 self._printer.print_one_line_summary(result_summary.total, 916 result_summary.expected, 917 result_summary.unexpected) 897 self._printer.print_one_line_summary(result_summary.total, result_summary.expected, result_summary.unexpected) 918 898 919 899 unexpected_results = summarize_results(self._port, self._expectations, result_summary, retry_summary, individual_test_timings, only_unexpected=True, interrupted=interrupted) … … 926 906 # FIXME: remove record_results. It's just used for testing. There's no need 927 907 # for it to be a commandline argument. 928 if (self._options.record_results and not self._options.dry_run and 929 not keyboard_interrupted): 930 # Write the same data to log files and upload generated JSON files 931 # to appengine server. 908 if (self._options.record_results and not self._options.dry_run and not keyboard_interrupted): 909 self._port.print_leaks_summary() 910 # Write the same data to log files and upload generated JSON files to appengine server. 932 911 summarized_results = summarize_results(self._port, self._expectations, result_summary, retry_summary, individual_test_timings, only_unexpected=False, interrupted=interrupted) 933 912 self._upload_json_files(summarized_results, result_summary, individual_test_timings) -
trunk/Tools/Scripts/webkitpy/layout_tests/controllers/worker.py
r90796 r91245 121 121 122 122 def _run_test(self, test_input): 123 # Before running the test, we wait for any crash reporters to finish124 # running. On Mac, ReportCrash chews up a bunch of resources and125 # causes the tests to become unstable, so we don't want to run in126 # parallel with ReportCrash.127 #128 # Temporarily disabled to see how this code effect performance on the buildbots.129 # self._port.executive.wait_newest(self._port.is_crash_reporter)130 131 123 test_timeout_sec = self.timeout(test_input) 132 124 start = time.time() -
trunk/Tools/Scripts/webkitpy/layout_tests/port/base.py
r91059 r91245 289 289 return False 290 290 291 def check_for_leaks(self, process_name, process_pid): 292 # Subclasses should check for leaks in the running process 293 # and print any necessary warnings if leaks are found. 294 # FIXME: We should consider moving much of this logic into 295 # Executive and make it platform-specific instead of port-specific. 296 pass 297 298 def print_leaks_summary(self): 299 # Subclasses can override this to print a summary of leaks found 300 # while running the layout tests. 301 pass 302 291 303 def driver_name(self): 292 304 """Returns the name of the actual binary that is performing the test, … … 853 865 # output and stop trying. 854 866 self._pretty_patch_available = False 855 _log.error("Failed to run PrettyPatch (%s):\n%s" % (command, 856 e.message_with_output())) 867 _log.error("Failed to run PrettyPatch (%s):\n%s" % (command, e.message_with_output())) 857 868 return self._pretty_patch_error_html 858 869 -
trunk/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py
r91215 r91245 118 118 result = chromium.ChromiumPort.check_build(self, needs_http) 119 119 if not result: 120 _log.error('For complete Windows build requirements, please ' 121 'see:') 120 _log.error('For complete Windows build requirements, please see:') 122 121 _log.error('') 123 _log.error(' http://dev.chromium.org/developers/how-tos/' 124 'build-instructions-windows') 122 _log.error(' http://dev.chromium.org/developers/how-tos/build-instructions-windows') 125 123 return result 126 124 … … 134 132 def _build_path(self, *comps): 135 133 if self.get_option('build_directory'): 136 return self._filesystem.join(self.get_option('build_directory'), 137 *comps) 134 return self._filesystem.join(self.get_option('build_directory'), *comps) 138 135 139 136 p = self.path_from_chromium_base('webkit', *comps) … … 149 146 150 147 def _lighttpd_path(self, *comps): 151 return self.path_from_chromium_base('third_party', 'lighttpd', 'win', 152 *comps) 148 return self.path_from_chromium_base('third_party', 'lighttpd', 'win', *comps) 153 149 154 150 def _path_to_apache(self): 155 return self.path_from_chromium_base('third_party', 'cygwin', 'usr', 156 'sbin', 'httpd') 151 return self.path_from_chromium_base('third_party', 'cygwin', 'usr', 'sbin', 'httpd') 157 152 158 153 def _path_to_apache_config_file(self): … … 183 178 184 179 def _path_to_wdiff(self): 185 return self.path_from_chromium_base('third_party', 'cygwin', 'bin', 186 'wdiff.exe') 180 return self.path_from_chromium_base('third_party', 'cygwin', 'bin', 'wdiff.exe') -
trunk/Tools/Scripts/webkitpy/layout_tests/port/gtk.py
r90826 r91245 48 48 # We must do this here because the DISPLAY number depends on _worker_number 49 49 environment['DISPLAY'] = ":%d" % (display_id) 50 self._server_process = server_process.ServerProcess(self._port, 51 self._port.driver_name(), self.cmd_line(), environment) 50 self._server_process = server_process.ServerProcess(self._port, self._port.driver_name(), self.cmd_line(), environment) 52 51 53 52 def stop(self): -
trunk/Tools/Scripts/webkitpy/layout_tests/port/mac.py
r90826 r91245 33 33 import re 34 34 35 from webkitpy.common.system.executive import ScriptError 35 36 from webkitpy.layout_tests.port.webkit import WebKitPort 36 37 37 38 38 39 _log = logging.getLogger(__name__) 40 41 42 # If other ports/platforms decide to support --leaks, we should see about sharing as much of this code as possible. 43 class LeakDetector(object): 44 def __init__(self, port): 45 # We should operate on a "platform" not a port here. 46 self._port = port 47 self._executive = port._executive 48 self._filesystem = port._filesystem 49 50 # We exclude the following reported leaks so they do not get in our way when looking for WebKit leaks: 51 # This allows us ignore known leaks and only be alerted when new leaks occur. Some leaks are in the old 52 # versions of the system frameworks that are being used by the leaks bots. Even though a leak has been 53 # fixed, it will be listed here until the bot has been updated with the newer frameworks. 54 def _types_to_exlude_from_leaks(self): 55 # Currently we don't have any type excludes from OS leaks, but we will likely again in the future. 56 return [] 57 58 def _callstacks_to_exclude_from_leaks(self): 59 callstacks = [ 60 "Flash_EnforceLocalSecurity", # leaks in Flash plug-in code, rdar://problem/4449747 61 ] 62 if self._port.is_leopard(): 63 callstacks += [ 64 "CFHTTPMessageAppendBytes", # leak in CFNetwork, rdar://problem/5435912 65 "sendDidReceiveDataCallback", # leak in CFNetwork, rdar://problem/5441619 66 "_CFHTTPReadStreamReadMark", # leak in CFNetwork, rdar://problem/5441468 67 "httpProtocolStart", # leak in CFNetwork, rdar://problem/5468837 68 "_CFURLConnectionSendCallbacks", # leak in CFNetwork, rdar://problem/5441600 69 "DispatchQTMsg", # leak in QuickTime, PPC only, rdar://problem/5667132 70 "QTMovieContentView createVisualContext", # leak in QuickTime, PPC only, rdar://problem/5667132 71 "_CopyArchitecturesForJVMVersion", # leak in Java, rdar://problem/5910823 72 ] 73 elif self._port.is_snowleopard(): 74 callstacks += [ 75 "readMakerNoteProps", # <rdar://problem/7156432> leak in ImageIO 76 "QTKitMovieControllerView completeUISetup", # <rdar://problem/7155156> leak in QTKit 77 "getVMInitArgs", # <rdar://problem/7714444> leak in Java 78 "Java_java_lang_System_initProperties", # <rdar://problem/7714465> leak in Java 79 "glrCompExecuteKernel", # <rdar://problem/7815391> leak in graphics driver while using OpenGL 80 "NSNumberFormatter getObjectValue:forString:errorDescription:", # <rdar://problem/7149350> Leak in NSNumberFormatter 81 ] 82 return callstacks 83 84 def _leaks_args(self, pid): 85 leaks_args = [] 86 for callstack in self._callstacks_to_exclude_from_leaks(): 87 leaks_args += ['--exclude-callstack="%s"' % callstack] # Callstacks can have spaces in them, so we quote the arg to prevent confusing perl's optparse. 88 for excluded_type in self._types_to_exlude_from_leaks(): 89 leaks_args += ['--exclude-type="%s"' % excluded_type] 90 leaks_args.append(pid) 91 return leaks_args 92 93 def _parse_leaks_output(self, leaks_output, process_pid): 94 count, bytes = re.search(r'Process %s: (\d+) leaks? for (\d+) total' % process_pid, leaks_output).groups() 95 excluded_match = re.search(r'(\d+) leaks? excluded', leaks_output) 96 excluded = excluded_match.group(0) if excluded_match else 0 97 return int(count), int(excluded), int(bytes) 98 99 def leaks_files_in_directory(self, directory): 100 return self._filesystem.glob(self._filesystem.join(directory, "leaks-*")) 101 102 def leaks_file_name(self, process_name, process_pid): 103 # We include the number of files this worker has already written in the name to prevent overwritting previous leak results.. 104 return "leaks-%s-%s.txt" % (process_name, process_pid) 105 106 def parse_leak_files(self, leak_files): 107 merge_depth = 5 # ORWT had a --merge-leak-depth argument, but that seems out of scope for the run-webkit-tests tool. 108 args = [ 109 '--merge-depth', 110 merge_depth, 111 ] + leak_files 112 parse_malloc_history_output = self._port._run_script("parse-malloc-history", args, include_configuration_arguments=False) 113 114 unique_leak_count = len(re.findall(r'^(\d*)\scalls', parse_malloc_history_output)) 115 total_bytes = int(re.search(r'^total\:\s(.*)\s\(', parse_malloc_history_output).group(1)) 116 return (total_bytes, unique_leak_count) 117 118 def check_for_leaks(self, process_name, process_pid): 119 _log.debug("Checking for leaks in %s" % process_name) 120 try: 121 leaks_output = self._port._run_script("run-leaks", self._leaks_args(process_pid), include_configuration_arguments=False) 122 except ScriptError, e: 123 _log.warn("Failed to run leaks tool: %s" % e.message_with_output()) 124 return 125 126 count, excluded, bytes = self._parse_leaks_output(leaks_output, process_pid) 127 adjusted_count = count - excluded 128 if not adjusted_count: 129 return 130 131 leaks_filename = self.leaks_file_name(process_name, process_pid) 132 leaks_output_path = self._filesystem.join(self._port.results_directory(), leaks_filename) 133 self._filesystem.write_text_file(leaks_output_path, leaks_output) 134 135 # FIXME: Ideally we would not be logging from the worker process, but rather pass the leak 136 # information back to the manager and have it log. 137 if excluded: 138 _log.info("%s leaks (%s bytes including %s excluded leaks) were found, details in %s" % (adjusted_count, bytes, excluded, leaks_output_path)) 139 else: 140 _log.info("%s leaks (%s bytes) were found, details in %s" % (count, bytes, leaks_output_path)) 39 141 40 142 … … 93 195 assert self._version in self.SUPPORTED_VERSIONS, "%s is not in %s" % (self._version, self.SUPPORTED_VERSIONS) 94 196 self._operating_system = 'mac' 197 self._leak_detector = LeakDetector(self) 95 198 96 199 def baseline_search_path(self): … … 100 203 return map(self._webkit_baseline_path, search_paths) 101 204 205 def setup_environ_for_server(self): 206 env = WebKitPort.setup_environ_for_server(self) 207 if self.get_option('leaks'): 208 env['MallocStackLogging'] = '1' 209 if self.get_option('guard_malloc'): 210 env['DYLD_INSERT_LIBRARIES'] = '/usr/lib/libgmalloc.dylib' 211 return env 212 213 # Belongs on a Platform object. 214 def is_leopard(self): 215 return self._version == "leopard" 216 217 # Belongs on a Platform object. 218 def is_snowleopard(self): 219 return self._version == "snowleopard" 220 221 # Belongs on a Platform object. 102 222 def is_crash_reporter(self, process_name): 103 223 return re.search(r'ReportCrash', process_name) … … 106 226 java_tests_path = self._filesystem.join(self.layout_tests_dir(), "java") 107 227 build_java = ["/usr/bin/make", "-C", java_tests_path] 108 if self._executive.run_command(build_java, return_exit_code=True): 228 if self._executive.run_command(build_java, return_exit_code=True): # Paths are absolute, so we don't need to set a cwd. 109 229 _log.error("Failed to build Java support files: %s" % build_java) 110 230 return False 111 231 return True 112 232 233 def check_for_leaks(self, process_name, process_pid): 234 if not self.get_option('leaks'): 235 return 236 # We could use http://code.google.com/p/psutil/ to get the process_name from the pid. 237 self._leak_detector.check_for_leaks(process_name, process_pid) 238 239 def print_leaks_summary(self): 240 if not self.get_option('leaks'): 241 return 242 # We're in the manager process, so the leak detector will not have a valid list of leak files. 243 # FIXME: This is a hack, but we don't have a better way to get this information from the workers yet. 244 leaks_files = self._leak_detector.leaks_files_in_directory(self.results_directory()) 245 if not leaks_files: 246 return 247 total_bytes, unique_leaks = self.parse_leak_files(leaks_files) 248 _log.info("%s total leaks found for a total of %s!" % (self._total_leaks, total_bytes)) 249 _log.info("%s unique leaks found!" % unique_leaks) 250 113 251 def _check_port_build(self): 114 252 return self._build_java_test_support() -
trunk/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py
r91210 r91245 31 31 import unittest 32 32 33 from webkitpy.layout_tests.port.mac import MacPort 33 from webkitpy.layout_tests.port.mac import MacPort, LeakDetector 34 34 from webkitpy.layout_tests.port import port_testcase 35 35 from webkitpy.common.system.filesystem_mock import MockFileSystem 36 36 from webkitpy.common.system.outputcapture import OutputCapture 37 37 from webkitpy.tool.mocktool import MockOptions, MockUser, MockExecutive 38 39 40 class LeakDetectorTest(unittest.TestCase): 41 def _mock_port(self): 42 class MockPort(object): 43 def __init__(self): 44 self._filesystem = MockFileSystem() 45 self._executive = MockExecutive() 46 47 return MockPort() 48 49 def _make_detector(self): 50 return LeakDetector(self._mock_port()) 51 52 def test_leaks_args(self): 53 detector = self._make_detector() 54 detector._callstacks_to_exclude_from_leaks = lambda: ['foo bar', 'BAZ'] 55 detector._types_to_exlude_from_leaks = lambda: ['abcdefg', 'hi jklmno'] 56 expected_args = ['--exclude-callstack="foo bar"', '--exclude-callstack="BAZ"', '--exclude-type="abcdefg"', '--exclude-type="hi jklmno"', 1234] 57 self.assertEquals(detector._leaks_args(1234), expected_args) 58 59 example_leaks_output = """Process 5122: 663744 nodes malloced for 78683 KB 60 Process 5122: 337301 leaks for 6525216 total leaked bytes. 61 Leak: 0x38cb600 size=3072 zone: DefaultMallocZone_0x1d94000 instance of 'NSCFData', type ObjC, implemented in Foundation 62 0xa033f0b8 0x01001384 0x00000b3a 0x00000b3a ..3.....:...:... 63 0x00000000 0x038cb620 0x00000000 0x00000000 .... ........... 64 0x00000000 0x21000000 0x726c6468 0x00000000 .......!hdlr.... 65 0x00000000 0x7269646d 0x6c707061 0x00000000 ....mdirappl.... 66 0x00000000 0x04000000 0x736c69c1 0x00000074 .........ilst... 67 0x6f74a923 0x0000006f 0x7461641b 0x00000061 #.too....data... 68 0x00000001 0x76614c00 0x2e323566 0x302e3236 .....Lavf52.62.0 69 0x37000000 0x6d616ea9 0x2f000000 0x61746164 ...7.nam.../data 70 ... 71 Leak: 0x2a9c960 size=288 zone: DefaultMallocZone_0x1d94000 72 0x09a1cc47 0x1bda8560 0x3d472cd1 0xfbe9bccd G...`....,G=.... 73 0x8bcda008 0x9e972a91 0xa892cf63 0x2448bdb0 .....*..c.....H$ 74 0x4736fc34 0xdbe2d94e 0x25f56688 0x839402a4 4.6GN....f.%.... 75 0xd12496b3 0x59c40c12 0x8cfcab2a 0xd20ef9c4 ..$....Y*....... 76 0xe7c56b1b 0x5835af45 0xc69115de 0x6923e4bb .k..E.5X......#i 77 0x86f15553 0x15d40fa9 0x681288a4 0xc33298a9 SU.........h..2. 78 0x439bb535 0xc4fc743d 0x7dfaaff8 0x2cc49a4a 5..C=t.....}J.., 79 0xdd119df8 0x7e086821 0x3d7d129e 0x2e1b1547 ....!h.~..}=G... 80 ... 81 Leak: 0x25102fe0 size=176 zone: DefaultMallocZone_0x1d94000 string 'NSException Data' 82 """ 83 84 def test_parse_leaks_output(self): 85 self.assertEquals(self._make_detector()._parse_leaks_output(self.example_leaks_output, 5122), (337301, 0, 6525216)) 86 87 def test_leaks_files_in_directory(self): 88 detector = self._make_detector() 89 self.assertEquals(detector.leaks_files_in_directory('/bogus-directory'), []) 90 detector._filesystem = MockFileSystem({ 91 '/mock-results/leaks-DumpRenderTree-0-1.txt': '', 92 '/mock-results/leaks-DumpRenderTree-1-1.txt': '', 93 '/mock-results/leaks-DumpRenderTree-0-2.txt': '', 94 }) 95 self.assertEquals(len(detector.leaks_files_in_directory('/mock-results')), 3) 96 97 def test_parse_leak_files(self): 98 detector = self._make_detector() 99 100 def mock_run_script(name, args, include_configuration_arguments=False): 101 print "MOCK _run_script: %s %s" % (name, args) 102 return "total: 12345 (" 103 detector._port._run_script = mock_run_script 104 105 leak_files = ['/mock-results/leaks-DumpRenderTree-1234.txt', '/mock-results/leaks-DumpRenderTree-1235.txt'] 106 expected_stdout = "MOCK _run_script: parse-malloc-history ['--merge-depth', 5, '/mock-results/leaks-DumpRenderTree-1234.txt', '/mock-results/leaks-DumpRenderTree-1235.txt']\n" 107 results_tuple = OutputCapture().assert_outputs(self, detector.parse_leak_files, [leak_files], expected_stdout=expected_stdout) 108 self.assertEquals(results_tuple, (12345, 0)) 38 109 39 110 -
trunk/Tools/Scripts/webkitpy/layout_tests/port/server_process.py
r90534 r91245 55 55 def __init__(self, port_obj, name, cmd, env=None, executive=Executive()): 56 56 self._port = port_obj 57 self._name = name 57 self._name = name # Should be the command name (e.g. DumpRenderTree, ImageDiff) 58 58 self._cmd = cmd 59 59 self._env = env 60 60 self._reset() 61 61 self._executive = executive 62 63 def name(self): 64 return self._name 65 66 def pid(self): 67 return self._proc.pid 62 68 63 69 def _reset(self): … … 217 223 218 224 # Nope - wait for more data. 219 (read_fds, write_fds, err_fds) = select.select(select_fds, [], 220 select_fds, 221 deadline - now) 225 (read_fds, write_fds, err_fds) = select.select(select_fds, [], select_fds, deadline - now) 222 226 try: 223 227 if out_fd in read_fds: … … 232 236 if not self._proc: 233 237 return 238 239 self._port.check_for_leaks(self.name(), self.pid()) 234 240 235 241 pid = self._proc.pid … … 249 255 time.sleep(0.1) 250 256 if self._proc.poll() is None: 251 _log.warning('stopping %s timed out, killing it' % 252 self._name) 257 _log.warning('stopping %s timed out, killing it' % self._name) 253 258 self._executive.kill_process(self._proc.pid) 254 259 _log.warning('killed') -
trunk/Tools/Scripts/webkitpy/layout_tests/port/server_process_unittest.py
r91210 r91245 48 48 return "/mock-results" 49 49 50 def check_for_leaks(self, process_name, process_pid): 51 pass 52 50 53 51 54 class MockFile(object): … … 84 87 class TestServerProcess(unittest.TestCase): 85 88 def test_broken_pipe(self): 86 server_process = FakeServerProcess(port_obj= None, name="test", cmd=["test"])89 server_process = FakeServerProcess(port_obj=TrivialMockPort(), name="test", cmd=["test"]) 87 90 server_process.write("should break") 88 91 self.assertTrue(server_process.crashed) -
trunk/Tools/Scripts/webkitpy/layout_tests/port/webkit.py
r90826 r91245 56 56 self.set_option_default("pixel_tests", False) 57 57 # WebKit ports expect a 35s timeout, or 350s timeout when running with -g/--guard-malloc. 58 self.set_option_default("time_out_ms", 35000) 58 # FIXME: --guard-malloc is only supported on Mac, so this logic should be in mac.py. 59 default_time_out_seconds = 350 if self.get_option('guard_malloc') else 35 60 self.set_option_default("time_out_ms", default_time_out_seconds * 1000) 59 61 60 62 def driver_name(self): … … 116 118 if args: 117 119 run_script_command.extend(args) 118 return self._executive.run_command(run_script_command, cwd=self._config.webkit_base_dir()) # It's unclear if setting cwd is necessary for all callers.120 return self._executive.run_command(run_script_command, cwd=self._config.webkit_base_dir()) 119 121 120 122 def _build_driver(self): … … 451 453 def poll(self): 452 454 return self._server_process.poll() 453 454 def restart(self):455 self._server_process.stop()456 self._server_process.start()457 return458 455 459 456 def detected_crash(self): -
trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
r91136 r91245 242 242 optparse.make_option("--complex-text", action="store_true", default=False, 243 243 help="Use the complex text code path for all text (Mac OS X and Windows only)"), 244 optparse.make_option("-l", "--leaks", action="store_true", default=False, 245 help="Enable leaks checking (Mac OS X only)"), 246 optparse.make_option("-g", "--guard-malloc", action="store_true", default=False, 247 help="Enable malloc guard (Mac OS X only)"), 244 248 optparse.make_option("--threaded", action="store_true", default=False, 245 249 help="Run a concurrent JavaScript thread with each test"), … … 248 252 ] 249 253 250 # Missing Mac-specific old-run-webkit-tests options:251 # FIXME: Need: -g, --guard for guard malloc support on Mac.252 # FIXME: Need: -l --leaks Enable leaks checking.253 254 254 old_run_webkit_tests_compat = [ 255 255 # FIXME: Remove this option once the bots don't refer to it. 256 256 # results.html is smart enough to figure this out itself. 257 257 _compat_shim_option("--use-remote-links-to-tests"), 258 # FIXME: Implement leak detection.259 _compat_shim_option("--leaks"),260 258 ] 261 259 -
trunk/Tools/Scripts/webkitpy/layout_tests/views/printing.py
r90534 r91245 344 344 """Prints one unexpected test result line.""" 345 345 desc = TestExpectations.EXPECTATION_DESCRIPTIONS[result.type][0] 346 self.write(" %s -> unexpected %s" % 347 (result.test_name, desc), "unexpected") 346 self.write(" %s -> unexpected %s" % (result.test_name, desc), "unexpected") 348 347 349 348 def print_progress(self, result_summary, retrying, test_list):
Note: See TracChangeset
for help on using the changeset viewer.