Inheritance: implements Phan\Library\Hasher
Example #1
0
 /**
  * @param int $process_count
  * The number of processes we'd like to divide work up
  * amongst.
  *
  * @param string[] $analysis_file_list
  * A list of files that should be analyzed which will be
  * used to ignore any files outside of the list and to
  * draw from for any missing files.
  *
  * @return string[][]
  * A map from process_id to a list of files to be analyzed
  * on that process in stable ordering.
  */
 public function orderForProcessCount(int $process_count, array $analysis_file_list) : array
 {
     assert($process_count > 0, "The process count must be greater than zero.");
     if (Config::get()->randomize_file_order) {
         $random_proc_file_map = [];
         $i = 0;
         shuffle($analysis_file_list);
         foreach ($analysis_file_list as $i => $file) {
             $random_proc_file_map[$i++ % $process_count][] = $file;
         }
         return $random_proc_file_map;
     }
     // Construct a Hasher implementation based on config.
     if (Config::get()->consistent_hashing_file_order) {
         sort($analysis_file_list, SORT_STRING);
         $hasher = new Consistent($process_count);
     } else {
         $hasher = new Sequential($process_count);
     }
     // Create a Set from the file list
     $analysis_file_map = [];
     foreach ($analysis_file_list as $i => $file) {
         $analysis_file_map[$file] = true;
     }
     // A map from the root of an object hierarchy to all
     // elements within that hierarchy
     $root_fqsen_list = [];
     $file_names_for_classes = [];
     // Iterate over each class extracting files
     foreach ($this->code_base->getClassMap() as $fqsen => $class) {
         // We won't be analyzing internal stuff
         if ($class->isInternal()) {
             continue;
         }
         // Get the name of the file associated with the class
         $file_name = $class->getContext()->getFile();
         // Ignore any files that are not to be analyzed
         if (!isset($analysis_file_map[$file_name])) {
             continue;
         }
         unset($analysis_file_map[$file_name]);
         $file_names_for_classes[$file_name] = $class;
     }
     if (Config::get()->consistent_hashing_file_order) {
         ksort($file_names_for_classes, SORT_STRING);
     }
     foreach ($file_names_for_classes as $file_name => $class) {
         // Get the class's depth in its object hierarchy and
         // the FQSEN of the object at the root of its hierarchy
         $hierarchy_depth = $class->getHierarchyDepth($this->code_base);
         $hierarchy_root = $class->getHierarchyRootFQSEN($this->code_base);
         // Create a bucket for this root if it doesn't exist
         if (empty($root_fqsen_list[(string) $hierarchy_root])) {
             $root_fqsen_list[(string) $hierarchy_root] = [];
         }
         // Append this {file,depth} pair to the hierarchy
         // root
         $root_fqsen_list[(string) $hierarchy_root][] = ['file' => $file_name, 'depth' => $hierarchy_depth];
     }
     // Create a map from processor_id to the list of files
     // to be analyzed on that processor
     $processor_file_list_map = [];
     // Sort the set of files with a given root by their
     // depth in the hierarchy
     foreach ($root_fqsen_list as $root_fqsen => $list) {
         // Sort first by depth, and break ties by file name lexicographically
         // (usort is not a stable sort).
         usort($list, function (array $a, array $b) {
             return $a['depth'] <=> $b['depth'] ?: strcmp($a['file'], $b['file']);
         });
         // Choose which process this file list will be
         // run on
         $process_id = $hasher->getGroup((string) $root_fqsen);
         // Append each file to this process list
         foreach ($list as $item) {
             $processor_file_list_map[$process_id][] = $item['file'];
         }
     }
     // Distribute any remaining files without classes evenly
     // between the processes
     $hasher->reset();
     foreach (array_keys($analysis_file_map) as $file) {
         // Choose which process this file list will be
         // run on
         $process_id = $hasher->getGroup((string) $file);
         $processor_file_list_map[$process_id][] = $file;
     }
     return $processor_file_list_map;
 }