class MultiTransformBlock(Block): def __init__(self, irings_, guarantee=True, *args, **kwargs): super(MultiTransformBlock, self).__init__(irings_, *args, **kwargs) # Note: Must use self.irings rather than irings_ because they may # actually be Block instances. self.guarantee = guarantee self.orings = [ self.create_ring(space=iring.space) for iring in self.irings ] self._seq_count = 0 self.perf_proclog = ProcLog(self.name + "/perf") self.sequence_proclogs = [ ProcLog(self.name + "/sequence%i" % i) for i in range(len(self.irings)) ] self.out_proclog = ProcLog(self.name + "/out") rnames = {'nring': len(self.orings)} for i, r in enumerate(self.orings): rnames['ring%i' % i] = r.name self.out_proclog.update(rnames) def main(self, orings): for iseqs in izip( * [iring.read(guarantee=self.guarantee) for iring in self.irings]): if self.shutdown_event.is_set(): break for i, iseq in enumerate(iseqs): self.sequence_proclogs[i].update(iseq.header) oheaders = self._on_sequence(iseqs) for ohdr in oheaders: if 'time_tag' not in ohdr: ohdr['time_tag'] = self._seq_count self._seq_count += 1 igulp_nframes = [ self.gulp_nframe or iseq.header['gulp_nframe'] for iseq in iseqs ] igulp_overlaps = self._define_input_overlap_nframe(iseqs) istride_nframes = igulp_nframes[:] igulp_nframes = [ igulp_nframe + nframe_overlap for igulp_nframe, nframe_overlap in zip( igulp_nframes, igulp_overlaps) ] for iseq, igulp_nframe in zip(iseqs, igulp_nframes): if self.buffer_factor is None: src_block = iseq.ring.owner if src_block is not None and self.is_fused_with(src_block): buffer_factor = 1 else: buffer_factor = None else: buffer_factor = self.buffer_factor iseq.resize(gulp_nframe=igulp_nframe, buf_nframe=self.buffer_nframe, buffer_factor=buffer_factor) # TODO: Ever need to specify starting offset? iframe0s = [0 for _ in igulp_nframes] force_skip = False with ExitStack() as oseq_stack: oseqs, ogulp_overlaps = self.begin_sequences( oseq_stack, orings, oheaders, igulp_nframes, istride_nframes) if self.shutdown_event.is_set(): break prev_time = time.time() for ispans in izip(*[ iseq.read(igulp_nframe, istride_nframe, iframe0) for (iseq, igulp_nframe, istride_nframe, iframe0) in zip(iseqs, igulp_nframes, istride_nframes, iframe0s) ]): if self.shutdown_event.is_set(): return if any([ispan.nframe_skipped for ispan in ispans]): # There were skipped (overwritten) frames with ExitStack() as ospan_stack: iskip_slices = [ slice(iframe0, iframe0 + ispan.nframe_skipped, istride_nframe) for iframe0, istride_nframe, ispan in zip( iframe0s, istride_nframes, ispans) ] iskip_nframes = [ ispan.nframe_skipped for ispan in ispans ] # ***TODO: Need to loop over multiple ospans here, # because iskip_nframes can be # arbitrarily large! ospans = self.reserve_spans( ospan_stack, oseqs, iskip_nframes) ostrides_actual = self._on_skip( iskip_slices, ospans) device.stream_synchronize() self.commit_spans(ospans, ostrides_actual, ogulp_overlaps) if all([ispan.nframe == 0 for ispan in ispans]): # No data to see here, move right along continue cur_time = time.time() acquire_time = cur_time - prev_time prev_time = cur_time with ExitStack() as ospan_stack: igulp_nframes = [ispan.nframe for ispan in ispans] ospans = self.reserve_spans(ospan_stack, oseqs, igulp_nframes) cur_time = time.time() reserve_time = cur_time - prev_time prev_time = cur_time if not force_skip: # *TODO: See if can fuse together multiple on_data calls here before # calling stream_synchronize(). # Consider passing .data instead of rings here ostrides_actual = self._on_data(ispans, ospans) device.stream_synchronize() any_frames_overwritten = any( [ispan.nframe_overwritten for ispan in ispans]) if force_skip or any_frames_overwritten: # Note: To allow interrupted pipelines to catch up, # we force-skip an additional gulp whenever # a span is overwritten during on_data. force_skip = any_frames_overwritten iskip_slices = [ slice( ispan.frame_offset, ispan.frame_offset + ispan.nframe_overwritten, istride_nframe) for ispan, istride_nframe in zip( ispans, istride_nframes) ] ostrides_actual = self._on_skip( iskip_slices, ospans) device.stream_synchronize() self.commit_spans(ospans, ostrides_actual, ogulp_overlaps) cur_time = time.time() process_time = cur_time - prev_time prev_time = cur_time self.perf_proclog.update({ 'acquire_time': acquire_time, 'reserve_time': reserve_time, 'process_time': process_time }) # **TODO: This will not be called if an exception is raised # Need to call it from a context manager somehow self._on_sequence_end(iseqs) def _on_sequence(self, iseqs): return self.on_sequence(iseqs) def _on_sequence_end(self, iseqs): return self.on_sequence_end(iseqs) def _on_data(self, ispans, ospans): return self.on_data(ispans, ospans) def _on_skip(self, islices, ospans): return self.on_skip(islices, ospans) def _define_input_overlap_nframe(self, iseqs): return self.define_input_overlap_nframe(iseqs) def define_input_overlap_nframe(self, iseqs): """Return no. input frames that should overlap between successive spans for each input sequence. """ return [0] * len(self.irings) def define_output_nframes(self, input_nframes): """Return output nframe for each output, given input_nframes. """ return input_nframes def on_sequence(self, iseqs): """Return: oheaders (one per output) """ raise NotImplementedError def on_sequence_end(self, iseqs): """Do any necessary cleanup""" pass def on_data(self, ispans, ospans): """Process data from from ispans to ospans and return the number of frames to commit for each output (or None to commit complete spans).""" raise NotImplementedError def on_skip(self, islices, ospans): """Handle skipped frames""" raise NotImplementedError
class Block(BlockScope): instance_counts = defaultdict(lambda: 0) def __init__(self, irings, name=None, type_=None, **kwargs): self.type = type_ or self.__class__.__name__ self.name = name or '%s_%i' % (self.type, Block.instance_counts[self.type]) Block.instance_counts[self.type] += 1 super(Block, self).__init__(**kwargs) self.pipeline = get_default_pipeline() self.pipeline.blocks.append(self) # Allow Block instances to be passed in place of rings irings = [get_ring(iring) for iring in irings] self.irings = irings valid_inp_spaces = self._define_valid_input_spaces() for i, (iring, valid_spaces) in enumerate(zip(irings, valid_inp_spaces)): if not memory.space_accessible(iring.space, valid_spaces): raise ValueError( "Block %s input %i's space must be accessible from one of: %s" % (self.name, i, str(valid_spaces))) self.orings = [] # Update this in subclass constructors self.shutdown_event = threading.Event() self.bind_proclog = ProcLog(self.name + "/bind") self.in_proclog = ProcLog(self.name + "/in") rnames = {'nring': len(self.irings)} for i, r in enumerate(self.irings): rnames['ring%i' % i] = r.name self.in_proclog.update(rnames) self.init_trace = ''.join(traceback.format_stack()[:-1]) def shutdown(self): self.shutdown_event.set() def create_ring(self, *args, **kwargs): return Ring(*args, owner=self, **kwargs) def run(self): #affinity.set_openmp_cores(cpus) # TODO core = self.core if core is not None: affinity.set_core(core if isinstance(core, int) else core[0]) self.bind_proclog.update({'ncore': 1, 'core0': affinity.get_core()}) if self.gpu is not None: device.set_device(self.gpu) self.cache_scope_hierarchy() with ExitStack() as oring_stack: active_orings = self.begin_writing(oring_stack, self.orings) try: self.main(active_orings) except Exception: self.pipeline.block_init_queue.put((self, False)) sys.stderr.write("From block instantiated here:\n") sys.stderr.write(self.init_trace) raise def num_outputs(self): # TODO: This is a little hacky return len(self.orings) def begin_writing(self, exit_stack, orings): return [ exit_stack.enter_context(oring.begin_writing()) for oring in orings ] def begin_sequences(self, exit_stack, orings, oheaders, igulp_nframes, istride_nframes): # Note: The gulp_nframe that is set in the output header does not # include the overlap (i.e., it's based on stride not gulp). ostride_nframes = self._define_output_nframes(istride_nframes) for ohdr, ostride_nframe in zip(oheaders, ostride_nframes): ohdr['gulp_nframe'] = ostride_nframe ogulp_nframes = self._define_output_nframes(igulp_nframes) # Note: This always specifies buffer_factor=1 on the assumption that # additional buffering is defined by the reader(s) rather # than the writer. obuf_nframes = [1 * ogulp_nframe for ogulp_nframe in ogulp_nframes] oseqs = [ exit_stack.enter_context( oring.begin_sequence(ohdr, ogulp_nframe, obuf_nframe)) for (oring, ohdr, ogulp_nframe, obuf_nframe ) in zip(orings, oheaders, ogulp_nframes, obuf_nframes) ] # Synchronize all blocks here to ensure no sequence race conditions self.pipeline.block_init_queue.put((self, True)) self.pipeline.all_blocks_finished_initializing_event.wait() ogulp_overlaps = [ ogulp_nframe - ostride_nframe for ogulp_nframe, ostride_nframe in zip(ogulp_nframes, ostride_nframes) ] return oseqs, ogulp_overlaps def reserve_spans(self, exit_stack, oseqs, igulp_nframes=[]): ogulp_nframes = self._define_output_nframes(igulp_nframes) return [ exit_stack.enter_context(oseq.reserve(ogulp_nframe)) for (oseq, ogulp_nframe) in zip(oseqs, ogulp_nframes) ] def commit_spans(self, ospans, ostrides_actual, ogulp_overlaps): # Allow returning None to indicate complete consumption if ostrides_actual is None: ostrides = [None] * len(ospans) # Note: If ospan.nframe < ogulp_overlap, no frames will be committed ostrides = [ ostride if ostride is not None else max( ospan.nframe - ogulp_overlap, 0) for (ostride, ospan, ogulp_overlap) in zip(ostrides_actual, ospans, ogulp_overlaps) ] for ospan, ostride in zip(ospans, ostrides): ospan.commit(ostride) def _define_output_nframes(self, input_nframes): return self.define_output_nframes(input_nframes) def define_output_nframes(self, input_nframes): """Return output nframe for each output, given input_nframes. """ raise NotImplementedError def _define_valid_input_spaces(self): return self.define_valid_input_spaces() def define_valid_input_spaces(self): """Return set of valid spaces (or 'any') for each input""" return ['any'] * len(self.irings)
class SourceBlock(Block): def __init__(self, sourcenames, gulp_nframe, space=None, *args, **kwargs): super(SourceBlock, self).__init__([], *args, gulp_nframe=gulp_nframe, **kwargs) self.sourcenames = sourcenames default_space = 'cuda_host' if core.cuda_enabled() else 'system' if space is None: space = default_space self.orings = [self.create_ring(space=space)] self._seq_count = 0 self.perf_proclog = ProcLog(self.name + "/perf") self.out_proclog = ProcLog(self.name + "/out") rnames = {'nring': len(self.orings)} for i, r in enumerate(self.orings): rnames['ring%i' % i] = r.name self.out_proclog.update(rnames) def main(self, orings): for sourcename in self.sourcenames: if self.shutdown_event.is_set(): break with self.create_reader(sourcename) as ireader: oheaders = self.on_sequence(ireader, sourcename) for ohdr in oheaders: if 'time_tag' not in ohdr: ohdr['time_tag'] = self._seq_count if 'name' not in ohdr: ohdr['name'] = 'unnamed-sequence-%i' % self._seq_count self._seq_count += 1 with ExitStack() as oseq_stack: oseqs, ogulp_overlaps = self.begin_sequences( oseq_stack, orings, oheaders, igulp_nframes=[], istride_nframes=[]) while not self.shutdown_event.is_set(): prev_time = time.time() with ExitStack() as ospan_stack: ospans = self.reserve_spans(ospan_stack, oseqs) cur_time = time.time() reserve_time = cur_time - prev_time prev_time = cur_time ostrides_actual = self.on_data(ireader, ospans) device.stream_synchronize() self.commit_spans(ospans, ostrides_actual, ogulp_overlaps) # TODO: Is this an OK way to detect end-of-data? if any( [ostride == 0 for ostride in ostrides_actual]): break cur_time = time.time() process_time = cur_time - prev_time prev_time = cur_time self.perf_proclog.update({ 'acquire_time': -1, 'reserve_time': reserve_time, 'process_time': process_time }) def define_output_nframes(self, _): """Return output nframe for each output, given input_nframes. """ return [self.gulp_nframe] * self.num_outputs() def define_valid_input_spaces(self): """Return set of valid spaces (or 'any') for each input""" return [] def create_reader(self, sourcename): """Return an object to use for reading source data""" # TODO: Should return a dummy reader object here? raise NotImplementedError def on_sequence(self, reader, sourcename): """Return header for each output""" raise NotImplementedError def on_data(self, reader, ospans): """Process data from from ispans to ospans and return the number of frames to commit for each output.""" raise NotImplementedError
class StatisticsOp(object): def __init__(self, log, id, iring, ntime_gulp=1, guarantee=True, core=None): self.log = log self.iring = iring self.ntime_gulp = ntime_gulp self.guarantee = guarantee self.core = core self.client = Client(id) self.bind_proclog = ProcLog(type(self).__name__+"/bind") self.in_proclog = ProcLog(type(self).__name__+"/in") self.size_proclog = ProcLog(type(self).__name__+"/size") self.sequence_proclog = ProcLog(type(self).__name__+"/sequence0") self.perf_proclog = ProcLog(type(self).__name__+"/perf") self.in_proclog.update( {'nring':1, 'ring0':self.iring.name}) self.size_proclog.update({'nseq_per_gulp': self.ntime_gulp}) def main(self): if self.core is not None: cpu_affinity.set_core(self.core) self.bind_proclog.update({'ncore': 1, 'core0': cpu_affinity.get_core(),}) for iseq in self.iring.read(guarantee=self.guarantee): ihdr = json.loads(iseq.header.tostring()) self.sequence_proclog.update(ihdr) self.log.info("Statistics: Start of new sequence: %s", str(ihdr)) # Setup the ring metadata and gulp sizes time_tag = ihdr['time_tag'] navg = ihdr['navg'] nbl = ihdr['nbl'] nstand = ihdr['nstand'] chan0 = ihdr['chan0'] nchan = ihdr['nchan'] chan_bw = ihdr['bw'] / nchan npol = ihdr['npol'] igulp_size = self.ntime_gulp*nbl*nchan*npol*8 # ci32 ishape = (self.ntime_gulp,nbl,nchan,npol) autos = [i*(2*(nstand-1)+1-i)//2 + i for i in range(nstand)] data_pols = ['XX', 'YY'] last_save = 0.0 prev_time = time.time() iseq_spans = iseq.read(igulp_size) for ispan in iseq_spans: if ispan.size < igulp_size: continue # Ignore final gulp curr_time = time.time() acquire_time = curr_time - prev_time prev_time = curr_time ## Setup and load idata = ispan.data_view('ci32').reshape(ishape) if time.time() - last_save > 60: ## Timestamp tt = LWATime(time_tag, format='timetag') ts = tt.unix ## Pull out the auto-correlations adata = idata.view(numpy.int32) adata = adata.reshape(ishape+(2,)) adata = adata[0,autos,:,:,0] adata = adata[:,:,[0,3]] ## Run the statistics over all times/channels ## * only really works for ntime_gulp=1 data_min = numpy.min(adata, axis=1) data_max = numpy.max(adata, axis=1) data_avg = numpy.mean(adata, axis=1) ## Save for data,name in zip((data_min,data_avg,data_max), ('min','avg','max')): value = MultiMonitorPoint([data[:,i].tolist() for i in range(data.shape[1])], timestamp=ts, field=data_pols) self.client.write_monitor_point('statistics/%s' % name, value) last_save = time.time() time_tag += navg * self.ntime_gulp curr_time = time.time() process_time = curr_time - prev_time prev_time = curr_time self.perf_proclog.update({'acquire_time': acquire_time, 'reserve_time': -1, 'process_time': process_time,}) self.log.info("StatisticsOp - Done")
class WriterOp(object): def __init__(self, log, station, iring, ntime_gulp=1, fast=False, guarantee=True, core=None): self.log = log self.station = station self.iring = iring self.ntime_gulp = ntime_gulp self.fast = fast self.guarantee = guarantee self.core = core self.bind_proclog = ProcLog(type(self).__name__+"/bind") self.in_proclog = ProcLog(type(self).__name__+"/in") self.size_proclog = ProcLog(type(self).__name__+"/size") self.sequence_proclog = ProcLog(type(self).__name__+"/sequence0") self.perf_proclog = ProcLog(type(self).__name__+"/perf") self.in_proclog.update( {'nring':1, 'ring0':self.iring.name}) self.size_proclog.update({'nseq_per_gulp': self.ntime_gulp}) def main(self): global QUEUE if self.core is not None: cpu_affinity.set_core(self.core) self.bind_proclog.update({'ncore': 1, 'core0': cpu_affinity.get_core(),}) for iseq in self.iring.read(guarantee=self.guarantee): ihdr = json.loads(iseq.header.tostring()) self.sequence_proclog.update(ihdr) self.log.info("Writer: Start of new sequence: %s", str(ihdr)) # Setup the ring metadata and gulp sizes time_tag = ihdr['time_tag'] navg = ihdr['navg'] nbl = ihdr['nbl'] chan0 = ihdr['chan0'] nchan = ihdr['nchan'] chan_bw = ihdr['bw'] / nchan npol = ihdr['npol'] pols = ['XX','XY','YX','YY'] igulp_size = self.ntime_gulp*nbl*nchan*npol*8 # ci32 ishape = (self.ntime_gulp,nbl,nchan,npol) self.iring.resize(igulp_size, 10*igulp_size*(4 if self.fast else 1)) norm_factor = navg // (2*NCHAN) first_gulp = True was_active = False prev_time = time.time() iseq_spans = iseq.read(igulp_size) for ispan in iseq_spans: if ispan.size < igulp_size: continue # Ignore final gulp curr_time = time.time() acquire_time = curr_time - prev_time prev_time = curr_time ## On our first span, update the pipeline lag for the queue ## so that we start recording at the right times if first_gulp: QUEUE.update_lag(LWATime(time_tag, format='timetag').datetime) self.log.info("Current pipeline lag is %s", QUEUE.lag) first_gulp = False ## Setup and load idata = ispan.data_view('ci32').reshape(ishape) idata = idata.view(numpy.int32) idata = idata.reshape(ishape+(2,)) idata = idata[...,0] + 1j*idata[...,1] idata /= norm_factor idata = idata.astype(numpy.complex64) ## Determine what to do if QUEUE.active is not None: ### Recording active - write if not QUEUE.active.is_started: self.log.info("Started operation - %s", QUEUE.active) QUEUE.active.start(self.station, chan0, navg, nchan, chan_bw, npol, pols) was_active = True QUEUE.active.write(time_tag, idata) elif was_active: ### Recording just finished #### Clean was_active = False QUEUE.clean() #### Close self.log.info("Ended operation - %s", QUEUE.previous) QUEUE.previous.stop() time_tag += navg curr_time = time.time() process_time = curr_time - prev_time prev_time = curr_time self.perf_proclog.update({'acquire_time': acquire_time, 'reserve_time': -1, 'process_time': process_time,}) self.log.info("WriterOp - Done")
class SpectraOp(object): def __init__(self, log, id, iring, ntime_gulp=1, guarantee=True, core=-1): self.log = log self.iring = iring self.ntime_gulp = ntime_gulp self.guarantee = guarantee self.core = core self.client = Client(id) self.bind_proclog = ProcLog(type(self).__name__+"/bind") self.in_proclog = ProcLog(type(self).__name__+"/in") self.size_proclog = ProcLog(type(self).__name__+"/size") self.sequence_proclog = ProcLog(type(self).__name__+"/sequence0") self.perf_proclog = ProcLog(type(self).__name__+"/perf") self.in_proclog.update({'nring':1, 'ring0':self.iring.name}) def _plot_spectra(self, time_tag, freq, specs): # Plotting setup nchan = freq.size nstand = specs.shape[0] try: minval = numpy.min(specs[numpy.where(numpy.isfinite(specs))]) maxval = numpy.max(specs[numpy.where(numpy.isfinite(specs))]) except ValueError: minval = 0.0 maxval = 1.0 # Image setup width = 20 height = 18 im = PIL.Image.new('RGB', (width * 65 + 1, height * 65 + 21), '#FFFFFF') draw = PIL.ImageDraw.Draw(im) font = PIL.ImageFont.load(os.path.join(BASE_PATH, 'fonts', 'helvB10.pil')) # Axes boxes for i in range(width + 1): draw.line([i * 65, 0, i * 65, height * 65], fill = '#000000') for i in range(height + 1): draw.line([(0, i * 65), (im.size[0], i * 65)], fill = '#000000') # Power as a function of frequency for all antennas x = numpy.arange(nchan) * 64 // nchan for s in range(nstand): if s >= height * width: break x0, y0 = (s % width) * 65 + 1, (s // width + 1) * 65 draw.text((x0 + 5, y0 - 60), str(s+1), font=font, fill='#000000') ## XX c = '#1F77B4' y = ((54.0 / (maxval - minval)) * (specs[s,:,0] - minval)).clip(0, 54) draw.point(list(zip(x0 + x, y0 - y)), fill=c) ## YY c = '#FF7F0E' y = ((54.0 / (maxval - minval)) * (specs[s,:,1] - minval)).clip(0, 54) draw.point(list(zip(x0 + x, y0 - y)), fill=c) # Summary ySummary = height * 65 + 2 timeStr = datetime.utcfromtimestamp(time_tag / FS) timeStr = timeStr.strftime("%Y/%m/%d %H:%M:%S UTC") draw.text((5, ySummary), timeStr, font = font, fill = '#000000') rangeStr = 'range shown: %.3f to %.3f dB' % (minval, maxval) draw.text((210, ySummary), rangeStr, font = font, fill = '#000000') x = im.size[0] + 15 for label, c in reversed(list(zip(('XX', 'YY'), ('#1F77B4','#FF7F0E')))): x -= draw.textsize(label, font = font)[0] + 20 draw.text((x, ySummary), label, font = font, fill = c) return im def main(self): cpu_affinity.set_core(self.core) self.bind_proclog.update({'ncore': 1, 'core0': cpu_affinity.get_core(),}) for iseq in self.iring.read(guarantee=self.guarantee): ihdr = json.loads(iseq.header.tostring()) self.sequence_proclog.update(ihdr) self.log.info("Spectra: Start of new sequence: %s", str(ihdr)) # Setup the ring metadata and gulp sizes time_tag = ihdr['time_tag'] navg = ihdr['navg'] nbl = ihdr['nbl'] nstand = ihdr['nstand'] chan0 = ihdr['chan0'] nchan = ihdr['nchan'] chan_bw = ihdr['bw'] / nchan npol = ihdr['npol'] igulp_size = self.ntime_gulp*nbl*nchan*npol*8 # ci32 ishape = (self.ntime_gulp,nbl,nchan,npol) # Setup the arrays for the frequencies and auto-correlations freq = chan0*chan_bw + numpy.arange(nchan)*chan_bw autos = [i*(2*(nstand-1)+1-i)//2 + i for i in range(nstand)] last_save = 0.0 prev_time = time.time() for ispan in iseq.read(igulp_size): if ispan.size < igulp_size: continue # Ignore final gulp curr_time = time.time() acquire_time = curr_time - prev_time prev_time = curr_time ## Setup and load idata = ispan.data_view('ci32').reshape(ishape) if time.time() - last_save > 60: ## Timestamp tt = LWATime(time_tag, format='timetag') ts = tt.unix ## Pull out the auto-correlations adata = idata.view(numpy.int32) adata = adata.reshape(ishape+(2,)) adata = adata[0,autos,:,:,0] adata = adata[:,:,[0,3]] ## Plot im = self._plot_spectra(time_tag, freq, 10*numpy.log10(adata)) ## Save mp = ImageMonitorPoint.from_image(im) self.client.write_monitor_point('diagnostics/spectra', mp, timestamp=ts) last_save = time.time() time_tag += navg * self.ntime_gulp curr_time = time.time() process_time = curr_time - prev_time prev_time = curr_time self.perf_proclog.update({'acquire_time': acquire_time, 'reserve_time': 0.0, 'process_time': process_time,}) self.log.info("SpectraOp - Done")
class BaselineOp(object): def __init__(self, log, id, station, iring, ntime_gulp=1, guarantee=True, core=-1): self.log = log self.station = station self.iring = iring self.ntime_gulp = ntime_gulp self.guarantee = guarantee self.core = core self.client = Client(id) self.bind_proclog = ProcLog(type(self).__name__+"/bind") self.in_proclog = ProcLog(type(self).__name__+"/in") self.size_proclog = ProcLog(type(self).__name__+"/size") self.sequence_proclog = ProcLog(type(self).__name__+"/sequence0") self.perf_proclog = ProcLog(type(self).__name__+"/perf") self.in_proclog.update({'nring':1, 'ring0':self.iring.name}) def _plot_baselines(self, time_tag, freq, dist, baselines, valid): # Plotting setup nchan = freq.size nbl = baselines.shape[0] freq = freq[nchan//2] baselines = baselines[valid,nchan//2,:] baselines = numpy.abs(baselines[:,[0,1,3]]) minval = numpy.min(baselines) maxval = numpy.max(baselines) if minval == maxval: maxval = minval + 1.0 mindst = 0.0 maxdst = numpy.max(dist) # Image setup im = PIL.Image.new('RGB', (601, 421), '#FFFFFF') draw = PIL.ImageDraw.Draw(im) font = PIL.ImageFont.load(os.path.join(BASE_PATH, 'fonts', 'helvB10.pil')) # Axes boxes for i in range(2): draw.line([i * 600, 0, i * 600, 400], fill = '#000000') for i in range(2): draw.line([(0, i * 400), (im.size[0], i * 400)], fill = '#000000') # Visiblity amplitudes as a function of (u,v) distance x0, y0 = 1, 400 draw.text((x0 + 500, y0 - 395), '%.3f MHz' % (freq/1e6,), font=font, fill='#000000') ## (u,v) distance x = ((599.0 / (maxdst - mindst)) * (dist - mindst)).clip(0, 599) ## XX y = ((399.0 / (maxval - minval)) * (baselines[:,0] - minval)).clip(0, 399) draw.point(list(zip(x0 + x, y0 - y)), fill='#1F77B4') ## YY y = ((399.0 / (maxval - minval)) * (baselines[:,2] - minval)).clip(0, 399) draw.point(list(zip(x0 + x, y0 - y)), fill='#FF7F0E') ### XY #y = ((399.0 / (maxval - minval)) * (baselines[:,1] - minval)).clip(0, 399) #draw.point(list(zip(x0 + x, y0 - y)), fill='#A00000') # Details and labels ySummary = 402 timeStr = datetime.utcfromtimestamp(time_tag / FS) timeStr = timeStr.strftime("%Y/%m/%d %H:%M:%S UTC") draw.text((5, ySummary), timeStr, font = font, fill = '#000000') rangeStr = 'range shown: %.6f - %.6f' % (minval, maxval) draw.text((210, ySummary), rangeStr, font = font, fill = '#000000') x = im.size[0] + 15 #for label, c in reversed(list(zip(('XX','XY','YY'), ('#1F77B4','#A00000','#FF7F0E')))): for label, c in reversed(list(zip(('XX','YY'), ('#1F77B4','#FF7F0E')))): x -= draw.textsize(label, font = font)[0] + 20 draw.text((x, ySummary), label, font = font, fill = c) return im def main(self): cpu_affinity.set_core(self.core) self.bind_proclog.update({'ncore': 1, 'core0': cpu_affinity.get_core(),}) for iseq in self.iring.read(guarantee=self.guarantee): ihdr = json.loads(iseq.header.tostring()) self.sequence_proclog.update(ihdr) self.log.info("Baseline: Start of new sequence: %s", str(ihdr)) # Setup the ring metadata and gulp sizes time_tag = ihdr['time_tag'] navg = ihdr['navg'] nbl = ihdr['nbl'] nstand = ihdr['nstand'] chan0 = ihdr['chan0'] nchan = ihdr['nchan'] chan_bw = ihdr['bw'] / nchan npol = ihdr['npol'] igulp_size = self.ntime_gulp*nbl*nchan*npol*8 ishape = (self.ntime_gulp,nbl,nchan,npol) self.iring.resize(igulp_size) # Setup the arrays for the frequencies and baseline lenghts freq = chan0*chan_bw + numpy.arange(nchan)*chan_bw uvw = get_zenith_uvw(self.station, LWATime(time_tag, format='timetag')) uvw[:,2] = 0 dist = numpy.sqrt((uvw**2).sum(axis=1)) valid = numpy.where(dist > 0.1)[0] last_save = 0.0 prev_time = time.time() for ispan in iseq.read(igulp_size): if ispan.size < igulp_size: continue # Ignore final gulp curr_time = time.time() acquire_time = curr_time - prev_time prev_time = curr_time ## Setup and load idata = ispan.data_view('ci32').reshape(ishape) if time.time() - last_save > 60: ## Timestamp tt = LWATime(time_tag, format='timetag') ts = tt.unix ## Plot bdata = idata[0,...] bdata = bdata.view(numpy.int32) bdata = bdata.reshape(ishape+(2,)) bdata = bdata[0,:,:,:,0] + 1j*bdata[0,:,:,:,1] bdata = bdata.astype(numpy.complex64) im = self._plot_baselines(time_tag, freq, dist, bdata, valid) ## Save mp = ImageMonitorPoint.from_image(im) self.client.write_monitor_point('diagnostics/baselines', mp, timestamp=ts) last_save = time.time() time_tag += navg * self.ntime_gulp curr_time = time.time() process_time = curr_time - prev_time prev_time = curr_time self.perf_proclog.update({'acquire_time': acquire_time, 'reserve_time': 0.0, 'process_time': process_time,}) self.log.info("BaselineOp - Done")
class MultiTransformBlock(Block): def __init__(self, irings_, guarantee=True, *args, **kwargs): super(MultiTransformBlock, self).__init__(irings_, *args, **kwargs) # Note: Must use self.irings rather than irings_ because they may # actually be Block instances. self.guarantee = guarantee self.orings = [ self.create_ring(space=iring.space) for iring in self.irings ] self._seq_count = 0 self.perf_proclog = ProcLog(self.name + "/perf") self.sequence_proclogs = [ ProcLog(self.name + "/sequence%i" % i) for i in xrange(len(self.irings)) ] def main(self, orings): for iseqs in izip( * [iring.read(guarantee=self.guarantee) for iring in self.irings]): if self.shutdown_event.is_set(): break for i, iseq in enumerate(iseqs): self.sequence_proclogs[i].update(iseq.header) oheaders, islices = self._on_sequence(iseqs) for ohdr in oheaders: if 'time_tag' not in ohdr: ohdr['time_tag'] = self._seq_count self._seq_count += 1 # Allow passing None to mean slice(gulp_nframe) if islices is None: islices = [None] * len(self.irings) default_igulp_nframes = [ self.gulp_nframe or iseq.header['gulp_nframe'] for iseq in iseqs ] islices = [ islice or slice(igulp_nframe) for (islice, igulp_nframe) in zip(islices, default_igulp_nframes) ] islices = [_span_slice(slice_) for slice_ in islices] for iseq, islice in zip(iseqs, islices): if self.buffer_factor is None: src_block = iseq.ring.owner if src_block is not None and self.is_fused_with(src_block): buffer_factor = 1 else: buffer_factor = None else: buffer_factor = self.buffer_factor iseq.resize(gulp_nframe=(islice.stop - islice.start), buf_nframe=self.buffer_nframe, buffer_factor=buffer_factor) igulp_nframes = [islice.stop - islice.start for islice in islices] with ExitStack() as oseq_stack: oseqs = self.begin_sequences(oseq_stack, orings, oheaders, igulp_nframes) prev_time = time.time() for ispans in izip(*[ iseq.read(islice.stop - islice.start, islice.step, islice.start) for (iseq, islice) in zip(iseqs, islices) ]): if self.shutdown_event.is_set(): break cur_time = time.time() acquire_time = cur_time - prev_time prev_time = cur_time with ExitStack() as ospan_stack: ospans = self.reserve_spans(ospan_stack, oseqs, ispans) cur_time = time.time() reserve_time = cur_time - prev_time prev_time = cur_time # *TODO: See if can fuse together multiple on_data calls here before # calling stream_synchronize(). # Consider passing .data instead of rings here ostrides = self._on_data(ispans, ospans) # TODO: // Default to not spinning the CPU: cudaSetDeviceFlags(cudaDeviceScheduleBlockingSync); bf.device.stream_synchronize() # Allow returning None to indicate complete consumption if ostrides is None: ostrides = [ospan.nframe for ospan in ospans] ostrides = [ ostride if ostride is not None else ospan.nframe for (ostride, ospan) in zip(ostrides, ospans) ] for ospan, ostride in zip(ospans, ostrides): ospan.commit(ostride) cur_time = time.time() process_time = cur_time - prev_time prev_time = cur_time self.perf_proclog.update({ 'acquire_time': acquire_time, 'reserve_time': reserve_time, 'process_time': process_time }) self._on_sequence_end(iseqs) def _on_sequence(self, iseqs): return self.on_sequence(iseqs) def _on_sequence_end(self, iseqs): return self.on_sequence_end(iseqs) def _on_data(self, ispans, ospans): return self.on_data(ispans, ospans) def define_output_nframes(self, input_nframes): """Return output nframe for each output, given input_nframes. """ return input_nframes def on_sequence(self, iseqs): """Return: oheaders (one per output) and islices (one per input) """ raise NotImplementedError def on_sequence_end(self, iseqs): """Do any necessary cleanup""" pass def on_data(self, ispans, ospans): """Process data from from ispans to ospans and return the number of frames to commit for each output (or None to commit complete spans).""" raise NotImplementedError
class DummyOp(object): def __init__(self, log, sock, oring, nbl, ntime_gulp=1, slot_ntime=6, fast=False, shutdown_event=None, core=None): self.log = log self.sock = sock self.oring = oring self.nbl = nbl self.ntime_gulp = ntime_gulp self.slot_ntime = slot_ntime self.fast = fast if shutdown_event is None: shutdown_event = threading.Event() self.shutdown_event = shutdown_event self.core = core self.bind_proclog = ProcLog(type(self).__name__+"/bind") self.out_proclog = ProcLog(type(self).__name__+"/out") self.size_proclog = ProcLog(type(self).__name__+"/size") self.perf_proclog = ProcLog(type(self).__name__+"/perf") self.out_proclog.update( {'nring':1, 'ring0':self.oring.name}) self.size_proclog.update({'nseq_per_gulp': self.ntime_gulp}) def shutdown(self): self.shutdown_event.set() def main(self): with self.oring.begin_writing() as oring: navg = 2400 if self.fast else 240000 tint = navg / CHAN_BW tgulp = tint * self.ntime_gulp nsrc = self.nbl nbl = self.nbl chan0 = 1234 nchan = 192 // (4 if self.fast else 1) npol = 4 # Try to load model visibilities try: vis_base = numpy.load('utils/sky.npy') except: self.log.warn("Could not load model visibilities from utils/sky.py, using random data") vis_base = numpy.zeros((nbl, nchan, npol), dtype=numpy.complex64) assert(vis_base.shape[0] >= nbl) assert(vis_base.shape[1] >= nchan) assert(vis_base.shape[2] == npol) vis_base = vis_base[:self.nbl,::(4 if self.fast else 1),:] vis_base_r = (vis_base.real*1000).astype(numpy.int32) vis_base_i = (vis_base.imag*1000).astype(numpy.int32) vis_base = numpy.zeros((nbl, nchan, npol, 2), dtype=numpy.int32) vis_base[...,0] = vis_base_r vis_base[...,1] = vis_base_i ohdr = {'time_tag': int(int(time.time())*FS), 'seq0': 0, 'chan0': chan0, 'cfreq': chan0*CHAN_BW, 'nchan': nchan, 'bw': nchan*CHAN_BW*(4 if self.fast else 1), 'navg': navg*8192, 'nstand': int(numpy.sqrt(8*nsrc+1)-1)//2, 'npol': npol, 'nbl': nbl, 'complex': True, 'nbit': 32} ohdr_str = json.dumps(ohdr) ogulp_size = self.ntime_gulp*nbl*nchan*npol*8 # ci32 oshape = (self.ntime_gulp,nbl,nchan,npol) self.oring.resize(ogulp_size) prev_time = time.time() with oring.begin_sequence(time_tag=ohdr['time_tag'], header=ohdr_str) as oseq: while not self.shutdown_event.is_set(): with oseq.reserve(ogulp_size) as ospan: curr_time = time.time() reserve_time = curr_time - prev_time prev_time = curr_time odata = ospan.data_view(numpy.int32).reshape(oshape+(2,)) temp = vis_base + (1000*0.01*numpy.random.randn(*odata.shape)).astype(numpy.int32) odata[...] = temp curr_time = time.time() while curr_time - prev_time < tgulp: time.sleep(0.01) curr_time = time.time() curr_time = time.time() process_time = curr_time - prev_time prev_time = curr_time self.perf_proclog.update({'acquire_time': -1, 'reserve_time': reserve_time, 'process_time': process_time,})
class WriterOp(object): def __init__(self, log, iring, beam=1, ntime_gulp=250, guarantee=True, core=None): self.log = log self.iring = iring self.beam = beam self.ntime_gulp = ntime_gulp self.guarantee = guarantee self.core = core self.bind_proclog = ProcLog(type(self).__name__ + "/bind") self.in_proclog = ProcLog(type(self).__name__ + "/in") self.size_proclog = ProcLog(type(self).__name__ + "/size") self.sequence_proclog = ProcLog(type(self).__name__ + "/sequence0") self.perf_proclog = ProcLog(type(self).__name__ + "/perf") self.in_proclog.update({'nring': 1, 'ring0': self.iring.name}) self.size_proclog.update({'nseq_per_gulp': self.ntime_gulp}) def main(self): global QUEUE if self.core is not None: cpu_affinity.set_core(self.core) self.bind_proclog.update({ 'ncore': 1, 'core0': cpu_affinity.get_core(), }) for iseq in self.iring.read(guarantee=self.guarantee): ihdr = json.loads(iseq.header.tostring()) self.sequence_proclog.update(ihdr) self.log.info("Writer: Start of new sequence: %s", str(ihdr)) # Setup the ring metadata and gulp sizes time_tag = ihdr['time_tag'] navg = ihdr['navg'] nbeam = ihdr['nbeam'] chan0 = ihdr['chan0'] nchan = ihdr['nchan'] chan_bw = ihdr['bw'] / nchan npol = ihdr['npol'] pols = ihdr['pols'] pols = pols.replace('CR', 'XY_real') pols = pols.replace('CI', 'XY_imag') igulp_size = self.ntime_gulp * nbeam * nchan * npol * 4 # float32 ishape = (self.ntime_gulp, nbeam, nchan, npol) self.iring.resize(igulp_size, 10 * igulp_size) first_gulp = True was_active = False prev_time = time.time() iseq_spans = iseq.read(igulp_size) for ispan in iseq_spans: if ispan.size < igulp_size: continue # Ignore final gulp curr_time = time.time() acquire_time = curr_time - prev_time prev_time = curr_time ## On our first span, update the pipeline lag for the queue ## so that we start recording at the right times if first_gulp: QUEUE.update_lag( LWATime(time_tag, format='timetag').datetime) self.log.info("Current pipeline lag is %s", QUEUE.lag) first_gulp = False ## Setup and load idata = ispan.data_view(numpy.float32).reshape(ishape) ## Determine what to do if QUEUE.active is not None: ### Recording active - write if not QUEUE.active.is_started: self.log.info("Started operation - %s", QUEUE.active) QUEUE.active.start(self.beam, chan0, navg, nchan, chan_bw, npol, pols) was_active = True QUEUE.active.write(time_tag, idata) elif was_active: ### Recording just finished - clean #### Clean was_active = False QUEUE.clean() #### Close self.log.info("Ended operation - %s", QUEUE.previous) QUEUE.previous.stop() time_tag += navg * self.ntime_gulp * (int(FS) // int(CHAN_BW)) curr_time = time.time() process_time = curr_time - prev_time prev_time = curr_time self.perf_proclog.update({ 'acquire_time': acquire_time, 'reserve_time': -1, 'process_time': process_time, }) self.log.info("WriterOp - Done")
class StatisticsOp(object): def __init__(self, log, id, iring, ntime_gulp=250, guarantee=True, core=None): self.log = log self.iring = iring self.ntime_gulp = ntime_gulp self.guarantee = guarantee self.core = core self.client = Client(id) self.bind_proclog = ProcLog(type(self).__name__ + "/bind") self.in_proclog = ProcLog(type(self).__name__ + "/in") self.size_proclog = ProcLog(type(self).__name__ + "/size") self.sequence_proclog = ProcLog(type(self).__name__ + "/sequence0") self.perf_proclog = ProcLog(type(self).__name__ + "/perf") self.in_proclog.update({'nring': 1, 'ring0': self.iring.name}) self.size_proclog.update({'nseq_per_gulp': self.ntime_gulp}) def main(self): if self.core is not None: cpu_affinity.set_core(self.core) self.bind_proclog.update({ 'ncore': 1, 'core0': cpu_affinity.get_core(), }) for iseq in self.iring.read(guarantee=self.guarantee): ihdr = json.loads(iseq.header.tostring()) self.sequence_proclog.update(ihdr) self.log.info("Statistics: Start of new sequence: %s", str(ihdr)) # Setup the ring metadata and gulp sizes time_tag = ihdr['time_tag'] navg = ihdr['navg'] nbeam = ihdr['nbeam'] chan0 = ihdr['chan0'] nchan = ihdr['nchan'] chan_bw = ihdr['bw'] / nchan npol = ihdr['npol'] pols = ihdr['pols'] igulp_size = self.ntime_gulp * nbeam * nchan * npol * 4 # float32 ishape = (self.ntime_gulp, nbeam, nchan, npol) data_pols = pols.split(',') last_save = 0.0 prev_time = time.time() iseq_spans = iseq.read(igulp_size) for ispan in iseq_spans: if ispan.size < igulp_size: continue # Ignore final gulp curr_time = time.time() acquire_time = curr_time - prev_time prev_time = curr_time ## Setup and load idata = ispan.data_view(numpy.float32).reshape(ishape) idata = idata.reshape(-1, npol) if time.time() - last_save > 60: ## Timestamp tt = LWATime(time_tag, format='timetag') ts = tt.unix ## Run the statistics over all times/channels ## * only really works for nbeam=1 data_min = numpy.min(idata, axis=0) data_max = numpy.max(idata, axis=0) data_avg = numpy.mean(idata, axis=0) ## Save for data, name in zip((data_min, data_avg, data_max), ('min', 'avg', 'max')): value = MultiMonitorPoint(data.tolist(), timestamp=ts, field=data_pols) self.client.write_monitor_point( 'statistics/%s' % name, value) last_save = time.time() time_tag += navg * self.ntime_gulp * (int(FS) // int(CHAN_BW)) curr_time = time.time() process_time = curr_time - prev_time prev_time = curr_time self.perf_proclog.update({ 'acquire_time': acquire_time, 'reserve_time': -1, 'process_time': process_time, }) self.log.info("StatisticsOp - Done")
class SpectraOp(object): def __init__(self, log, id, iring, ntime_gulp=250, guarantee=True, core=None): self.log = log self.iring = iring self.ntime_gulp = ntime_gulp self.guarantee = guarantee self.core = core self.client = Client(id) self.bind_proclog = ProcLog(type(self).__name__ + "/bind") self.in_proclog = ProcLog(type(self).__name__ + "/in") self.size_proclog = ProcLog(type(self).__name__ + "/size") self.sequence_proclog = ProcLog(type(self).__name__ + "/sequence0") self.perf_proclog = ProcLog(type(self).__name__ + "/perf") self.in_proclog.update({'nring': 1, 'ring0': self.iring.name}) self.size_proclog.update({'nseq_per_gulp': self.ntime_gulp}) def main(self): if self.core is not None: cpu_affinity.set_core(self.core) self.bind_proclog.update({ 'ncore': 1, 'core0': cpu_affinity.get_core(), }) # Setup the figure ## Import import matplotlib matplotlib.use('Agg') from matplotlib import pyplot as plt from matplotlib.ticker import MultipleLocator ## Create fig = plt.Figure(figsize=(6, 6)) ax = fig.gca() for iseq in self.iring.read(guarantee=self.guarantee): ihdr = json.loads(iseq.header.tostring()) self.sequence_proclog.update(ihdr) self.log.info("Spectra: Start of new sequence: %s", str(ihdr)) # Setup the ring metadata and gulp sizes time_tag = ihdr['time_tag'] navg = ihdr['navg'] nbeam = ihdr['nbeam'] chan0 = ihdr['chan0'] nchan = ihdr['nchan'] chan_bw = ihdr['bw'] / nchan npol = ihdr['npol'] pols = ihdr['pols'] igulp_size = self.ntime_gulp * nbeam * nchan * npol * 4 # float32 ishape = (self.ntime_gulp, nbeam, nchan, npol) nchan_pipeline = nchan // NPIPELINE frange = (numpy.arange(nchan) + chan0) * CHAN_BW last_save = 0.0 prev_time = time.time() iseq_spans = iseq.read(igulp_size) for ispan in iseq_spans: if ispan.size < igulp_size: continue # Ignore final gulp curr_time = time.time() acquire_time = curr_time - prev_time prev_time = curr_time ## Setup and load idata = ispan.data_view(numpy.float32).reshape(ishape) if time.time() - last_save > 60: ## Timestamp tt = LWATime(time_tag, format='timetag') ts = tt.datetime.strftime('%y%m%d %H:%M:%S') ## Average over time sdata = idata.mean(axis=0) ## Create a diagnostic plot after suming the flags across polarization ax.cla() ax.plot(frange / 1e6, numpy.log10(sdata[0, :, 0]) * 10, color='#1F77B4') ax.plot(frange / 1e6, numpy.log10(sdata[0, :, 1]) * 10, color='#FF7F0E') ylim = ax.get_ylim() for b in range(1, NPIPELINE): linestyle = ':' if b % 4 == 0: linestyle = '--' ax.vlines(frange[b * nchan_pipeline] / 1e6, *ylim, linestyle=linestyle, color='black', alpha=0.2) ax.set_ylim(ylim) ax.set_xlim((frange[0] / 1e6, frange[-1] / 1e6)) ax.set_xlabel('Frequency [MHz]') ax.set_ylabel('Power [arb. dB]') ax.xaxis.set_major_locator(MultipleLocator(base=10.0)) fig.tight_layout() ## Save tt = LWATime(time_tag, format='timetag') mp = ImageMonitorPoint.from_figure(fig) self.client.write_monitor_point('diagnostics/spectra', mp, timestamp=tt.unix) last_save = time.time() time_tag += navg * self.ntime_gulp * (int(FS) // int(CHAN_BW)) curr_time = time.time() process_time = curr_time - prev_time prev_time = curr_time self.perf_proclog.update({ 'acquire_time': acquire_time, 'reserve_time': -1, 'process_time': process_time, }) self.log.info("SpectraOp - Done")
class DummyOp(object): def __init__(self, log, sock, oring, nserver, beam0=1, ntime_gulp=250, slot_ntime=25000, shutdown_event=None, core=None): self.log = log self.sock = sock self.oring = oring self.nserver = nserver self.beam0 = beam0 self.ntime_gulp = ntime_gulp self.slot_ntime = slot_ntime if shutdown_event is None: shutdown_event = threading.Event() self.shutdown_event = shutdown_event self.core = core self.bind_proclog = ProcLog(type(self).__name__ + "/bind") self.out_proclog = ProcLog(type(self).__name__ + "/out") self.size_proclog = ProcLog(type(self).__name__ + "/size") self.perf_proclog = ProcLog(type(self).__name__ + "/perf") self.out_proclog.update({'nring': 1, 'ring0': self.oring.name}) self.size_proclog.update({'nseq_per_gulp': self.ntime_gulp}) def shutdown(self): self.shutdown_event.set() def main(self): with self.oring.begin_writing() as oring: navg = 24 tint = navg / CHAN_BW tgulp = tint * self.ntime_gulp nbeam = 1 chan0 = 1234 nchan = 16 * 192 npol = 4 ohdr = { 'time_tag': int(int(time.time()) * FS), 'seq0': 0, 'chan0': chan0, 'cfreq0': chan0 * CHAN_BW, 'bw': nchan * CHAN_BW, 'navg': navg, 'nbeam': nbeam, 'nchan': nchan, 'npol': npol, 'pols': 'XX,YY,CR,CI', 'complex': False, 'nbit': 32 } ohdr_str = json.dumps(ohdr) ogulp_size = self.ntime_gulp * nbeam * nchan * npol * 4 # float32 oshape = (self.ntime_gulp, nbeam, nchan, npol) self.oring.resize(ogulp_size) prev_time = time.time() with oring.begin_sequence(time_tag=ohdr['time_tag'], header=ohdr_str) as oseq: while not self.shutdown_event.is_set(): with oseq.reserve(ogulp_size) as ospan: curr_time = time.time() reserve_time = curr_time - prev_time prev_time = curr_time odata = ospan.data_view(numpy.float32).reshape(oshape) odata[...] = numpy.random.randn(*oshape) curr_time = time.time() while curr_time - prev_time < tgulp: time.sleep(0.01) curr_time = time.time() curr_time = time.time() process_time = curr_time - prev_time prev_time = curr_time self.perf_proclog.update({ 'acquire_time': -1, 'reserve_time': reserve_time, 'process_time': process_time, })
class Block(BlockScope): instance_counts = defaultdict(lambda: 0) def __init__(self, irings, name=None, type_=None, **kwargs): self.type = type_ or self.__class__.__name__ self.name = name or '%s_%i' % (self.type, Block.instance_counts[self.type]) Block.instance_counts[self.type] += 1 super(Block, self).__init__(**kwargs) self.pipeline = get_default_pipeline() self.pipeline.blocks.append(self) # Allow Block instances to be passed in place of rings irings = [get_ring(iring) for iring in irings] self.irings = irings valid_inp_spaces = self._define_valid_input_spaces() for i, (iring, valid_spaces) in enumerate(zip(irings, valid_inp_spaces)): if not bf.memory.space_accessible(iring.space, valid_spaces): raise ValueError( "Block %s input %i's space must be accessible from one of: %s" % (self.name, i, str(valid_spaces))) self.orings = [] # Update this in subclass constructors self.shutdown_event = threading.Event() self.bind_proclog = ProcLog(self.name + "/bind") self.in_proclog = ProcLog(self.name + "/in") rnames = {'nring': len(self.irings)} for i, r in enumerate(self.irings): rnames['ring%i' % i] = r.name self.in_proclog.update(rnames) def shutdown(self): self.shutdown_event.set() def create_ring(self, *args, **kwargs): return Ring(*args, owner=self, **kwargs) def run(self): #bf.affinity.set_openmp_cores(cpus) # TODO core = self.core if core is not None: bf.affinity.set_core(core if isinstance(core, int) else core[0]) self.bind_proclog.update({'ncore': 1, 'core0': bf.affinity.get_core()}) if self.gpu is not None: bf.device.set_device(self.gpu) self.cache_scope_hierarchy() with ExitStack() as oring_stack: active_orings = self.begin_writing(oring_stack, self.orings) self.main(active_orings) def num_outputs(self): # TODO: This is a little hacky return len(self.orings) def begin_writing(self, exit_stack, orings): return [ exit_stack.enter_context(oring.begin_writing()) for oring in orings ] def begin_sequences(self, exit_stack, orings, oheaders, igulp_nframes): ogulp_nframes = self._define_output_nframes(igulp_nframes) for ohdr, ogulp_nframe in zip(oheaders, ogulp_nframes): ohdr['gulp_nframe'] = ogulp_nframe # Note: This always specifies buffer_factor=1 on the assumption that # additional buffering is defined by the reader(s) rather # than the writer. obuf_nframes = [1 * ogulp_nframe for ogulp_nframe in ogulp_nframes] return [ exit_stack.enter_context(oring.begin_sequence(ohdr, obuf_nframe)) for (oring, ohdr, obuf_nframe) in zip(orings, oheaders, obuf_nframes) ] def reserve_spans(self, exit_stack, oseqs, ispans): igulp_nframes = [span.nframe for span in ispans] ogulp_nframes = self._define_output_nframes(igulp_nframes) return [ exit_stack.enter_context(oseq.reserve(ogulp_nframe)) for (oseq, ogulp_nframe) in zip(oseqs, ogulp_nframes) ] def _define_output_nframes(self, input_nframes): return self.define_output_nframes(input_nframes) def define_output_nframes(self, input_nframes): """Return output nframe for each output, given input_nframes. """ raise NotImplementedError def _define_valid_input_spaces(self): return self.define_valid_input_spaces() def define_valid_input_spaces(self): """Return set of valid spaces (or 'any') for each input""" return ['any'] * len(self.irings)