 Chromium Code Reviews
 Chromium Code Reviews Issue 6822028:
  factory_test_tools: improve gft_hwcomp (hardware_Components) performance  (Closed) 
  Base URL: ssh://gitrw.chromium.org:9222/factory_test_tools.git@master
    
  
    Issue 6822028:
  factory_test_tools: improve gft_hwcomp (hardware_Components) performance  (Closed) 
  Base URL: ssh://gitrw.chromium.org:9222/factory_test_tools.git@master| OLD | NEW | 
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python | 
| 2 # | 2 # | 
| 3 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | 3 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | 
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be | 
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. | 
| 6 | 6 | 
| 7 import glob | 7 import glob | 
| 8 import os | 8 import os | 
| 9 import pprint | 9 import pprint | 
| 10 import re | 10 import re | 
| 11 import sys | 11 import sys | 
| 12 import threading | |
| 12 | 13 | 
| 13 import flashrom_util | 14 import flashrom_util | 
| 14 import gft_common | 15 import gft_common | 
| 15 import gft_fwhash | 16 import gft_fwhash | 
| 16 import vblock | 17 import vblock | 
| 17 | 18 | 
| 18 from gft_common import DebugMsg, VerboseMsg, WarningMsg, ErrorMsg, ErrorDie | 19 from gft_common import DebugMsg, VerboseMsg, WarningMsg, ErrorMsg, ErrorDie | 
| 19 | 20 | 
| 20 | 21 | 
| 21 def Memorize(f): | 22 def Memorize(f): | 
| 22 """ Decorator for functions that need memorization.""" | 23 return gft_common.ThreadSafe(gft_common.Memorize(f)) | 
| 23 memorize_data = {} | |
| 24 def memorize_call(*args): | |
| 25 index = repr(args) | |
| 26 if index in memorize_data: | |
| 27 value = memorize_data[index] | |
| 28 # DebugMsg('Memorize: using cached value for: %s %s' % (repr(f), index)) | |
| 29 return value | |
| 30 value = f(*args) | |
| 31 memorize_data[index] = value | |
| 32 return value | |
| 33 return memorize_call | |
| 34 | 24 | 
| 35 | 25 | 
| 36 class HardwareComponents(object): | 26 class HardwareComponents(object): | 
| 37 """ Hardware Components Scanner """ | 27 """ Hardware Components Scanner """ | 
| 38 | 28 | 
| 39 # Function names in this class are used for reflection, so please don't change | 29 # Function names in this class are used for reflection, so please don't change | 
| 40 # the function names even if they are not comliant to coding style guide. | 30 # the function names even if they are not comliant to coding style guide. | 
| 41 | 31 | 
| 42 version = 5 | 32 version = 6 | 
| 43 | 33 | 
| 44 # We divide all component IDs (cids) into 5 categories: | 34 # We divide all component IDs (cids) into 5 categories: | 
| 45 # - enumerable: able to get the results by running specific commands; | 35 # - enumerable: able to get the results by running specific commands; | 
| 46 # - probable: returns existed or not by given some pre-defined choices; | 36 # - probable: returns existed or not by given some pre-defined choices; | 
| 47 # - pure data: data for some special purpose, can't be tested; | 37 # - pure data: data for some special purpose, can't be tested; | 
| 48 | 38 | 
| 49 _enumerable_cids = [ | 39 _enumerable_cids = [ | 
| 50 'data_display_geometry', | 40 'data_display_geometry', | 
| 51 'hash_ec_firmware', | 41 'hash_ec_firmware', | 
| 52 'hash_ro_firmware', | 42 'hash_ro_firmware', | 
| (...skipping 28 matching lines...) Expand all Loading... | |
| 81 _probable_cids = [ | 71 _probable_cids = [ | 
| 82 'key_recovery', | 72 'key_recovery', | 
| 83 'key_root', | 73 'key_root', | 
| 84 'part_id_cardreader', | 74 'part_id_cardreader', | 
| 85 ] | 75 ] | 
| 86 _pure_data_cids = [ | 76 _pure_data_cids = [ | 
| 87 'data_bitmap_fv', | 77 'data_bitmap_fv', | 
| 88 'data_recovery_url', | 78 'data_recovery_url', | 
| 89 ] | 79 ] | 
| 90 | 80 | 
| 81 # list of cids that should not be fetched asynchronously. | |
| 82 _non_async_cids = [ | |
| 83 # Reading EC will become very slow and cause inaccurate results if we try to | |
| 84 # probe components that also fires EC command at the same time. | |
| 85 'part_id_ec_flash_chip', | |
| 86 ] | |
| 87 | |
| 91 # _not_test_cids and _to_be_tested_cids will be re-created for each match. | 88 # _not_test_cids and _to_be_tested_cids will be re-created for each match. | 
| 92 _not_test_cids = [] | 89 _not_test_cids = [] | 
| 93 _to_be_tested_cids = [] | 90 _to_be_tested_cids = [] | 
| 94 | 91 | 
| 95 # TODO(hungte) unify the 'not available' style messages | 92 # TODO(hungte) unify the 'not available' style messages | 
| 96 _not_present = '' | 93 _not_present = '' | 
| 97 _no_match = 'No match' | 94 _no_match = 'No match' | 
| 98 | 95 | 
| 99 def __init__(self, verbose=False): | 96 def __init__(self, verbose=False): | 
| 100 self._initialized = False | 97 self._initialized = False | 
| (...skipping 525 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 626 def read_approved_from_file(self, filename): | 623 def read_approved_from_file(self, filename): | 
| 627 approved = gft_common.LoadComponentsDatabaseFile(filename) | 624 approved = gft_common.LoadComponentsDatabaseFile(filename) | 
| 628 for cid in self._to_be_tested_cids + self._not_test_cids: | 625 for cid in self._to_be_tested_cids + self._not_test_cids: | 
| 629 if cid not in approved: | 626 if cid not in approved: | 
| 630 # If we don't have any listing for this type | 627 # If we don't have any listing for this type | 
| 631 # of part in HWID, it's not required. | 628 # of part in HWID, it's not required. | 
| 632 WarningMsg('gft_hwcomp: Bypassing unlisted cid %s' % cid) | 629 WarningMsg('gft_hwcomp: Bypassing unlisted cid %s' % cid) | 
| 633 approved[cid] = '*' | 630 approved[cid] = '*' | 
| 634 return approved | 631 return approved | 
| 635 | 632 | 
| 636 def get_all_enumerable_components(self): | 633 def get_all_enumerable_components(self, async): | 
| 637 results = {} | 634 results = {} | 
| 638 for cid in self._enumerable_cids: | 635 thread_pools = [] | 
| 636 | |
| 637 def fetch_enumerable_component(cid): | |
| 638 """ Fetch an enumerable component and update the results """ | |
| 639 if self._verbose: | 639 if self._verbose: | 
| 640 sys.stdout.flush() | 640 sys.stdout.flush() | 
| 641 sys.stderr.write('<Fetching property %s>\n' % cid) | 641 sys.stderr.write('<Fetching property %s>\n' % cid) | 
| 642 components = self.force_get_property('get_' + cid) | 642 components = self.force_get_property('get_' + cid) | 
| 643 if not isinstance(components, list): | 643 if not isinstance(components, list): | 
| 644 components = [components] | 644 components = [components] | 
| 645 results[cid] = components | 645 results[cid] = components | 
| 646 | |
| 647 class FetchThread(threading.Thread): | |
| 648 """ Thread object for parallel enumerating """ | |
| 649 def __init__(self, cid): | |
| 650 threading.Thread.__init__(self) | |
| 651 self.cid = cid | |
| 652 | |
| 653 def run(self): | |
| 654 fetch_enumerable_component(self.cid) | |
| 655 | |
| 656 for cid in self._enumerable_cids: | |
| 657 if async and cid not in self._non_async_cids: | |
| 658 thread_pools.append(FetchThread(cid)) | |
| 659 else: | |
| 660 fetch_enumerable_component(cid) | |
| 661 | |
| 662 # Complete the threads | |
| 663 for thread in thread_pools: | |
| 664 thread.start() | |
| 665 for thread in thread_pools: | |
| 666 thread.join() | |
| 646 return results | 667 return results | 
| 647 | 668 | 
| 648 def check_enumerable_component(self, cid, exact_values, approved_values): | 669 def check_enumerable_component(self, cid, exact_values, approved_values): | 
| 649 if '*' in approved_values: | 670 if '*' in approved_values: | 
| 650 return | 671 return | 
| 651 | 672 | 
| 652 for value in exact_values: | 673 for value in exact_values: | 
| 653 if value not in approved_values: | 674 if value not in approved_values: | 
| 654 if cid in self._failures: | 675 if cid in self._failures: | 
| 655 self._failures[cid].append(value) | 676 self._failures[cid].append(value) | 
| (...skipping 14 matching lines...) Expand all Loading... | |
| 670 def check_probable_component(self, cid, approved_values): | 691 def check_probable_component(self, cid, approved_values): | 
| 671 (probed, value) = self.verify_probable_component(cid, approved_values) | 692 (probed, value) = self.verify_probable_component(cid, approved_values) | 
| 672 if probed: | 693 if probed: | 
| 673 self._system[cid] = value | 694 self._system[cid] = value | 
| 674 else: | 695 else: | 
| 675 self._failures[cid] = value | 696 self._failures[cid] = value | 
| 676 | 697 | 
| 677 def pformat(self, obj): | 698 def pformat(self, obj): | 
| 678 return '\n' + self._pp.pformat(obj) + '\n' | 699 return '\n' + self._pp.pformat(obj) + '\n' | 
| 679 | 700 | 
| 680 def initialize(self, force=False): | 701 def initialize(self, force=False, async=False): | 
| 681 if self._initialized and not force: | 702 if self._initialized and not force: | 
| 682 return | 703 return | 
| 683 # probe current system components | 704 # probe current system components | 
| 684 DebugMsg('Starting to detect system components...') | 705 DebugMsg('Starting to detect system components...') | 
| 685 self._enumerable_system = self.get_all_enumerable_components() | 706 self._enumerable_system = self.get_all_enumerable_components(async) | 
| 686 self._initialized = True | 707 self._initialized = True | 
| 687 | 708 | 
| 688 def match_current_system(self, filename, ignored_cids=[]): | 709 def match_current_system(self, filename, ignored_cids=[]): | 
| 689 """ Matches a given component list to current system. | 710 """ Matches a given component list to current system. | 
| 690 Returns: (current, failures) | 711 Returns: (current, failures) | 
| 691 """ | 712 """ | 
| 692 | 713 | 
| 693 # assert self._initialized, 'Not initialized.' | 714 # assert self._initialized, 'Not initialized.' | 
| 694 self._to_be_tested_cids = (self._enumerable_cids + | 715 self._to_be_tested_cids = (self._enumerable_cids + | 
| 695 self._probable_cids) | 716 self._probable_cids) | 
| (...skipping 18 matching lines...) Expand all Loading... | |
| 714 else: | 735 else: | 
| 715 self.check_probable_component(cid, approved[cid]) | 736 self.check_probable_component(cid, approved[cid]) | 
| 716 | 737 | 
| 717 return (self._system, self._failures) | 738 return (self._system, self._failures) | 
| 718 | 739 | 
| 719 | 740 | 
| 720 ############################################################################# | 741 ############################################################################# | 
| 721 # Console main entry | 742 # Console main entry | 
| 722 @gft_common.GFTConsole | 743 @gft_common.GFTConsole | 
| 723 def _main(self_path, args): | 744 def _main(self_path, args): | 
| 724 if not args: | 745 do_async = True | 
| 725 print 'Usage: %s components_db_files...\n' % self_path | 746 | 
| 726 sys.exit(1) | 747 # preprocess args | 
| 748 compdb_list = [] | |
| 749 for arg in args: | |
| 750 if arg == '--sync': | |
| 751 do_async = False | |
| 752 elif arg == '--async': | |
| 753 do_async = True | |
| 754 elif not os.path.exists(arg): | |
| 755 print 'ERROR: unknown parameter: ' + arg | |
| 756 print 'Usage: %s [--sync|--async] [components_db_files...]\n' % self_path | |
| 757 sys.exit(1) | |
| 758 else: | |
| 759 compdb_list.append(arg) | |
| 760 | |
| 727 components = HardwareComponents(verbose=True) | 761 components = HardwareComponents(verbose=True) | 
| 728 print 'Starting to probe system...' | 762 print 'Starting to detect %s...' % ('Asynchronously' if do_async else '') | 
| 
Tom Wai-Hong Tam
2011/04/13 01:19:36
Asynchronously -> asynchronously
 | |
| 729 components.initialize() | 763 components.initialize(async=do_async) | 
| 764 | |
| 765 if not compdb_list: | |
| 766 print 'Enumerable properties:' | |
| 767 print components.pformat(components._enumerable_system) | |
| 768 sys.exit(0) | |
| 769 | |
| 730 print 'Starting to match system...' | 770 print 'Starting to match system...' | 
| 731 | 771 for arg in compdb_list: | 
| 732 for arg in args: | |
| 733 (matched, failures) = components.match_current_system(arg) | 772 (matched, failures) = components.match_current_system(arg) | 
| 734 print 'Probed (%s):' % arg | 773 print 'Probed (%s):' % arg | 
| 735 print components.pformat(matched) | 774 print components.pformat(matched) | 
| 736 print 'Failures (%s):' % arg | 775 print 'Failures (%s):' % arg | 
| 737 print components.pformat(failures) | 776 print components.pformat(failures) | 
| 738 | 777 | 
| 739 if __name__ == '__main__': | 778 if __name__ == '__main__': | 
| 740 _main(sys.argv[0], sys.argv[1:]) | 779 _main(sys.argv[0], sys.argv[1:]) | 
| OLD | NEW |