def _run(params, x_region, y_region, regions, index): """Execute one pass on all possible GPUs with slice ranges given by *regions*.""" from gi.repository import Ufo pm = Ufo.PluginManager() graph = Ufo.TaskGraph() scheduler = Ufo.FixedScheduler() gpus = scheduler.get_resources().get_gpu_nodes() num_gpus = len(gpus) broadcast = Ufo.CopyTask() source = _setup_source(params, pm, graph) graph.connect_nodes(source, broadcast) for i, region in enumerate(regions): subindex = index * num_gpus + i _setup_graph(pm, graph, subindex, x_region, y_region, region, params, broadcast, gpu=gpus[i]) scheduler.run(graph) duration = scheduler.props.time LOG.info('Execution time: {} s'.format(duration)) return duration
def _create_runs(params, queue): """Workaround function to get the number of gpus and compute regions. gi.repository must always be called in a separate process, otherwise the resources return None gpus. """ #TODO: remove the whole function after memory leak fix! from gi.repository import Ufo scheduler = Ufo.FixedScheduler() gpus = scheduler.get_resources().get_gpu_nodes() num_gpus = len(gpus) x_region, y_region, regions = _split_regions(params, gpus) LOG.info('Using {} GPUs in {} passes'.format(min(len(regions), num_gpus), len(regions))) queue.put((x_region, y_region, regions, num_gpus))
def start_one(index): gpu_index, region = regions[index] scheduler = Ufo.FixedScheduler() scheduler.set_resources(resources[index]) graph = Ufo.TaskGraph() gpu = scheduler.get_resources().get_gpu_nodes()[gpu_index] region_index = run_number * len(resources) + index geometry = CTGeometry(args) if (len(args.center_position_z) == 1 and np.modf(args.center_position_z[0])[0] == 0 and geometry.is_simple_parallel_tomo): LOG.info( 'Simple tomography with integer z center, changing to center_position_z + 0.5 ' 'to avoid interpolation') geometry.args.center_position_z = ( geometry.args.center_position_z[0] + 0.5, ) if not args.disable_projection_crop: if not args.dry_run and (args.y or args.height): LOG.debug( '--y or --height specified, not optimizing projection region' ) else: geometry.optimize_args(region=region) opt_args = geometry.args if args.dry_run: source = get_task('dummy-data', number=args.number, width=args.width, height=args.height) else: source = None setup_graph(opt_args, graph, x_region, y_region, region, source=source, gpu=gpu, index=region_index, make_reader=True) LOG.debug('Pass: %d, device: %d, region: %s', run_number + 1, gpu_index, region) scheduler.run(graph) return scheduler.props.time
def test_core_issue_64_fixed_expansion(): g = Ufo.TaskGraph() pm = Ufo.PluginManager() sched = Ufo.FixedScheduler() arch = Ufo.ArchGraph() gpus = arch.get_gpu_nodes() sched.set_gpu_nodes(arch, gpus) generate = pm.get_task('generate') null = pm.get_task('null') generate.set_properties(number=5, width=512, height=512) for gpu in gpus: median = pm.get_task('median-filter') median.set_proc_node(gpu) g.connect_nodes(generate, median) g.connect_nodes(median, null) sched.run(g)
def start(self, arch=None, gpu=None): """ Run the processing in a new thread. Use :meth:`.push` to insert data into the processing chaing and :meth:`~InjectProcess.wait` to wait until processing has finished.""" def run_scheduler(sched): sched.run(self.graph) if arch and gpu: sched = Ufo.FixedScheduler() sched.set_gpu_nodes(arch, [gpu]) else: sched = self.sched self.thread = threading.Thread(target=run_scheduler, args=(sched,), daemon=True) self.thread.start() if not self._started: self._started = True
def __init__(self, args, resources=None, gpu_index=0, do_normalization=False, region=None, copy_inputs=False): if args.width is None or args.height is None: raise GeneralBackprojectError('width and height must be set in GeneralBackprojectArgs') scheduler = Ufo.FixedScheduler() if resources: scheduler.set_resources(resources) gpu = scheduler.get_resources().get_gpu_nodes()[gpu_index] self.args = copy.deepcopy(args) x_region, y_region, z_region = get_reconstruction_regions(self.args, store=True, dtype=float) set_projection_filter_scale(self.args) if region is not None: self.args.region = region LOG.debug('Creating reconstructor for gpu %d, region: %s', gpu_index, self.args.region) geometry = CTGeometry(self.args) if not self.args.disable_projection_crop: geometry.optimize_args() self.args = geometry.args regions = make_runs([gpu], [gpu_index], x_region, y_region, self.args.region, DTYPE_CL_SIZE[self.args.store_type], slices_per_device=self.args.slices_per_device, slice_memory_coeff=self.args.slice_memory_coeff, data_splitting_policy=self.args.data_splitting_policy) if len(regions) > 1: raise GeneralBackprojectError('Region does not fit to the GPU memory') graph = Ufo.TaskGraph() # Normalization self.ffc = None self.do_normalization = do_normalization if do_normalization: self.ffc = get_task('flat-field-correct', processing_node=gpu) self.ffc.props.fix_nan_and_inf = self.args.fix_nan_and_inf self.ffc.props.absorption_correct = self.args.absorptivity self._darks_averaged = False self._flats_averaged = False self.dark_avg = get_task('average', processing_node=gpu) self.flat_avg = get_task('average', processing_node=gpu) graph.connect_nodes_full(self.dark_avg, self.ffc, 1) graph.connect_nodes_full(self.flat_avg, self.ffc, 2) (first, last) = setup_graph(self.args, graph, x_region, y_region, self.args.region, source=self.ffc, gpu=gpu, index=gpu_index, do_output=False, make_reader=False) output_dims = 2 if args.slice_metric: output_dims = 1 metric = self.args.slice_metric if args.slice_metric == 'sag': metric = 'sum' gradient_task = get_task('gradient', processing_node=gpu, direction='both_abs') graph.connect_nodes(last, gradient_task) last = gradient_task measure_task = get_task('measure', processing_node=gpu, axis=-1, metric=metric) graph.connect_nodes(last, measure_task) elif first == last: # There are no other processing steps other than back projection LOG.debug('Only back projection, no other processing') graph = first super().__init__(graph, get_output=True, output_dims=output_dims, scheduler=scheduler, copy_inputs=copy_inputs) if self.do_normalization: # Setup input tasks for normalization images averaging. Our parent picks up only the two # averagers and not the ffc's zero port for projections. self.input_tasks[self.ffc] = [Ufo.InputTask()] self.ufo_buffers[self.ffc] = [None] self.graph.connect_nodes_full(self.input_tasks[self.ffc][0], self.ffc, 0)