int set_block_filled(paper_input_databuf_t *paper_input_databuf_p, block_info_t *binfo, int block_i) { static int last_filled = -1; uint32_t block_missed_pkt_cnt=0, block_missed_mod_cnt, block_missed_feng, missed_pkt_cnt=0; if(binfo->block_active[block_i]) { // if all packets are accounted for, mark this block as good if(binfo->block_active[block_i] == N_PACKETS_PER_BLOCK) { paper_input_databuf_p->block[block_i].header.good_data = 1; } last_filled = (last_filled+1) % N_INPUT_BLOCKS; if(last_filled != block_i) { printf("block %d being marked filled, but expected block %d!\n", block_i, last_filled); #ifdef DIE_ON_OUT_OF_SEQ_FILL die(paper_input_databuf_p, binfo); #else binfo->initialized = 0; return 0; #endif } if(paper_input_databuf_set_filled(paper_input_databuf_p, block_i) != GUPPI_OK) { guppi_error(__FUNCTION__, "error waiting for databuf filled call"); run_threads=0; pthread_exit(NULL); return 0; } block_missed_pkt_cnt = N_PACKETS_PER_BLOCK - binfo->block_active[block_i]; // If we missed more than N_PACKETS_PER_BLOCK_PER_F, then assume we // are missing one or more F engines. Any missed packets beyond an // integer multiple of N_PACKETS_PER_BLOCK_PER_F will be considered // as dropped packets. block_missed_feng = block_missed_pkt_cnt / N_PACKETS_PER_BLOCK_PER_F; block_missed_mod_cnt = block_missed_pkt_cnt % N_PACKETS_PER_BLOCK_PER_F; guppi_status_lock_busywait_safe(st_p); hputu4(st_p->buf, "NETBKOUT", block_i); hputu4(st_p->buf, "MISSEDFE", block_missed_feng); if(block_missed_mod_cnt) { // Increment MISSEDPK by number of missed packets for this block hgetu4(st_p->buf, "MISSEDPK", &missed_pkt_cnt); missed_pkt_cnt += block_missed_mod_cnt; hputu4(st_p->buf, "MISSEDPK", missed_pkt_cnt); // fprintf(stderr, "got %d packets instead of %d\n", // binfo->block_active[block_i], N_PACKETS_PER_BLOCK); } guppi_status_unlock_safe(st_p); binfo->block_active[block_i] = 0; } return block_missed_pkt_cnt; }
// Open and connect a UDP socket to the given host and port. Note that port is // a string and can be a stringified integer (e.g. "7148") or a service name // (e.g. "ntp"). Returns -1 on error, otherwise a valid descriptor for an open // and connected socket. static int open_udp_socket(const char *host, const char *port) { struct addrinfo hints; struct addrinfo *result, *rp; int s, sfd=-1; // Obtain address(es) matching host/port memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = 0; hints.ai_protocol = 0; s = getaddrinfo(host, port, &hints, &result); if (s != 0) { guppi_error("getaddrinfo", gai_strerror(s)); return -1; } // getaddrinfo() returns a list of address structures. // Try each address until we successfully connect(2). // If socket(2) (or connect(2)) fails, we (close the socket // and) try the next address. for (rp = result; rp != NULL; rp = rp->ai_next) { sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sfd == -1) { continue; } if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) { break; // Success } close(sfd); sfd = -1; } freeaddrinfo(result); #if 0 // Print send buffer size int bufsize; unsigned int bufsizesize = sizeof(bufsize); getsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &bufsize, &bufsizesize); printf("send buffer size is %d\n", bufsize); #endif return sfd; }
/* Dynamically allocates memory for the vector accumulators */ void create_accumulators(float ***accumulator, int num_chans, int num_subbands) { int i; /* Want: float accumulator[NUM_SW_STATES][num_chan][num_subband][NUM_STOKES] */ *accumulator = malloc(NUM_SW_STATES * sizeof(float*)); if(*accumulator == NULL) { guppi_error("guppi_net_thread", "malloc failed"); pthread_exit(NULL); } for(i = 0; i < NUM_SW_STATES; i++) { (*accumulator)[i] = malloc(num_chans * num_subbands * NUM_STOKES * sizeof(float)); if((*accumulator)[i] == NULL) { guppi_error("guppi_net_thread", "malloc failed"); pthread_exit(NULL); } } }
static inline int calc_block_indexes(block_info_t *binfo, packet_header_t * pkt_header) { if(pkt_header->mcnt < binfo->mcnt_start) { char msg[120]; sprintf(msg, "current packet mcnt %012lx less than mcnt start %012lx", pkt_header->mcnt, binfo->mcnt_start); guppi_error(__FUNCTION__, msg); //guppi_error(__FUNCTION__, "current packet mcnt less than mcnt start"); //run_threads=0; //pthread_exit(NULL); return -1; } else { binfo->mcnt_offset = pkt_header->mcnt - binfo->mcnt_start; } binfo->block_i = (binfo->mcnt_offset) / N_SUB_BLOCKS_PER_INPUT_BLOCK % N_INPUT_BLOCKS; binfo->m = (binfo->mcnt_offset) % Nm; binfo->x = (pkt_header->xid) % Nx; binfo->q = (pkt_header->fid) / 4; binfo->f = (pkt_header->fid) % 4; return 0; }
/* The main CPU accumulator thread */ void guppi_accum_thread(void *_args) { float **accumulator; //indexed accumulator[accum_id][chan][subband][stokes] char accum_dirty[NUM_SW_STATES]; struct sdfits_data_columns data_cols[NUM_SW_STATES]; int payload_type; int i, j, k, rv; /* Get arguments */ struct guppi_thread_args *args = (struct guppi_thread_args *)_args; /* Set cpu affinity */ cpu_set_t cpuset, cpuset_orig; sched_getaffinity(0, sizeof(cpu_set_t), &cpuset_orig); //CPU_ZERO(&cpuset); CPU_CLR(13, &cpuset); CPU_SET(9, &cpuset); rv = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); if (rv<0) { guppi_error("guppi_accum_thread", "Error setting cpu affinity."); perror("sched_setaffinity"); } /* Set priority */ rv = setpriority(PRIO_PROCESS, 0, args->priority); if (rv<0) { guppi_error("guppi_accum_thread", "Error setting priority level."); perror("set_priority"); } /* Attach to status shared mem area */ struct guppi_status st; rv = guppi_status_attach(&st); if (rv!=GUPPI_OK) { guppi_error("guppi_accum_thread", "Error attaching to status shared memory."); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_status_detach, &st); pthread_cleanup_push((void *)set_exit_status, &st); pthread_cleanup_push((void *)guppi_thread_set_finished, args); /* Init status */ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "init"); guppi_status_unlock_safe(&st); /* Read in general parameters */ struct guppi_params gp; struct sdfits sf; pthread_cleanup_push((void *)guppi_free_sdfits, &sf); /* Attach to databuf shared mem */ struct guppi_databuf *db_in, *db_out; db_in = guppi_databuf_attach(args->input_buffer); char errmsg[256]; if (db_in==NULL) { sprintf(errmsg, "Error attaching to input databuf(%d) shared memory.", args->input_buffer); guppi_error("guppi_accum_thread", errmsg); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_databuf_detach, db_in); db_out = guppi_databuf_attach(args->output_buffer); if (db_out==NULL) { sprintf(errmsg, "Error attaching to output databuf(%d) shared memory.", args->output_buffer); guppi_error("guppi_accum_thread", errmsg); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_databuf_detach, db_out); /* Determine high/low bandwidth mode */ char bw_mode[16]; if (hgets(st.buf, "BW_MODE", 16, bw_mode)) { if(strncmp(bw_mode, "high", 4) == 0) payload_type = INT_PAYLOAD; else if(strncmp(bw_mode, "low", 3) == 0) payload_type = FLOAT_PAYLOAD; else guppi_error("guppi_net_thread", "Unsupported bandwidth mode"); } else guppi_error("guppi_net_thread", "BW_MODE not set"); /* Read nchan and nsubband from status shared memory */ guppi_read_obs_params(st.buf, &gp, &sf); /* Allocate memory for vector accumulators */ create_accumulators(&accumulator, sf.hdr.nchan, sf.hdr.nsubband); pthread_cleanup_push((void *)destroy_accumulators, accumulator); /* Clear the vector accumulators */ for(i = 0; i < NUM_SW_STATES; i++) accum_dirty[i] = 1; reset_accumulators(accumulator, data_cols, accum_dirty, sf.hdr.nsubband, sf.hdr.nchan); /* Loop */ int curblock_in=0, curblock_out=0; int first=1; float reqd_exposure=0; double accum_time=0; int integ_num; float pfb_rate; int heap, accumid, struct_offset, array_offset; char *hdr_in=NULL, *hdr_out=NULL; struct databuf_index *index_in, *index_out; int nblock_int=0, npacket=0, n_pkt_drop=0, n_heap_drop=0; signal(SIGINT,cc); while (run) { /* Note waiting status */ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "waiting"); guppi_status_unlock_safe(&st); /* Wait for buf to have data */ rv = guppi_databuf_wait_filled(db_in, curblock_in); if (rv!=0) continue; /* Note waiting status and current block*/ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "accumulating"); hputi4(st.buf, "ACCBLKIN", curblock_in); guppi_status_unlock_safe(&st); /* Read param struct for this block */ hdr_in = guppi_databuf_header(db_in, curblock_in); if (first) guppi_read_obs_params(hdr_in, &gp, &sf); else guppi_read_subint_params(hdr_in, &gp, &sf); /* Do any first time stuff: first time code runs, not first time process this block */ if (first) { /* Set up first output header. This header is copied from block to block each time a new block is created */ hdr_out = guppi_databuf_header(db_out, curblock_out); memcpy(hdr_out, guppi_databuf_header(db_in, curblock_in), GUPPI_STATUS_SIZE); /* Read required exposure and PFB rate from status shared memory */ reqd_exposure = sf.data_columns.exposure; pfb_rate = sf.hdr.efsampfr / (2 * sf.hdr.nchan); /* Initialise the index in the output block */ index_out = (struct databuf_index*)guppi_databuf_index(db_out, curblock_out); index_out->num_datasets = 0; index_out->array_size = sf.hdr.nsubband * sf.hdr.nchan * NUM_STOKES * 4; first=0; } /* Loop through each spectrum (heap) in input buffer */ index_in = (struct databuf_index*)guppi_databuf_index(db_in, curblock_in); for(heap = 0; heap < index_in->num_heaps; heap++) { /* If invalid, record it and move to next heap */ if(!index_in->cpu_gpu_buf[heap].heap_valid) { n_heap_drop++; continue; } /* Read in heap from buffer */ char* heap_addr = (char*)(guppi_databuf_data(db_in, curblock_in) + sizeof(struct freq_spead_heap) * heap); struct freq_spead_heap* freq_heap = (struct freq_spead_heap*)(heap_addr); char* payload_addr = (char*)(guppi_databuf_data(db_in, curblock_in) + sizeof(struct freq_spead_heap) * MAX_HEAPS_PER_BLK + (index_in->heap_size - sizeof(struct freq_spead_heap)) * heap ); int *i_payload = (int*)(payload_addr); float *f_payload = (float*)(payload_addr); accumid = freq_heap->status_bits & 0x7; /*Debug: print heap */ /* printf("%d, %d, %d, %d, %d, %d\n", freq_heap->time_cntr, freq_heap->spectrum_cntr, freq_heap->integ_size, freq_heap->mode, freq_heap->status_bits, freq_heap->payload_data_off); */ /* If we have accumulated for long enough, write vectors to output block */ if(accum_time >= reqd_exposure) { for(i = 0; i < NUM_SW_STATES; i++) { /*If a particular accumulator is dirty, write it to output buffer */ if(accum_dirty[i]) { /*If insufficient space, first mark block as filled and request new block*/ index_out = (struct databuf_index*)(guppi_databuf_index(db_out, curblock_out)); if( (index_out->num_datasets+1) * (index_out->array_size + sizeof(struct sdfits_data_columns)) > db_out->block_size) { printf("Accumulator finished with output block %d\n", curblock_out); /* Write block number to status buffer */ guppi_status_lock_safe(&st); hputi4(st.buf, "ACCBLKOU", curblock_out); guppi_status_unlock_safe(&st); /* Update packet count and loss fields in output header */ hputi4(hdr_out, "NBLOCK", nblock_int); hputi4(hdr_out, "NPKT", npacket); hputi4(hdr_out, "NPKTDROP", n_pkt_drop); hputi4(hdr_out, "NHPDROP", n_heap_drop); /* Close out current integration */ guppi_databuf_set_filled(db_out, curblock_out); /* Wait for next output buf */ curblock_out = (curblock_out + 1) % db_out->n_block; guppi_databuf_wait_free(db_out, curblock_out); while ((rv=guppi_databuf_wait_free(db_out, curblock_out)) != GUPPI_OK) { if (rv==GUPPI_TIMEOUT) { guppi_warn("guppi_accum_thread", "timeout while waiting for output block"); continue; } else { guppi_error("guppi_accum_thread", "error waiting for free databuf"); run=0; pthread_exit(NULL); break; } } hdr_out = guppi_databuf_header(db_out, curblock_out); memcpy(hdr_out, guppi_databuf_header(db_in, curblock_in), GUPPI_STATUS_SIZE); /* Initialise the index in new output block */ index_out = (struct databuf_index*)guppi_databuf_index(db_out, curblock_out); index_out->num_datasets = 0; index_out->array_size = sf.hdr.nsubband * sf.hdr.nchan * NUM_STOKES * 4; nblock_int=0; npacket=0; n_pkt_drop=0; n_heap_drop=0; } /*Update index for output buffer*/ index_out = (struct databuf_index*)(guppi_databuf_index(db_out, curblock_out)); if(index_out->num_datasets == 0) struct_offset = 0; else struct_offset = index_out->disk_buf[index_out->num_datasets-1].array_offset + index_out->array_size; array_offset = struct_offset + sizeof(struct sdfits_data_columns); index_out->disk_buf[index_out->num_datasets].struct_offset = struct_offset; index_out->disk_buf[index_out->num_datasets].array_offset = array_offset; /*Copy sdfits_data_columns struct to disk buffer */ memcpy(guppi_databuf_data(db_out, curblock_out) + struct_offset, &data_cols[i], sizeof(struct sdfits_data_columns)); /*Copy data array to disk buffer */ memcpy(guppi_databuf_data(db_out, curblock_out) + array_offset, accumulator[i], index_out->array_size); /*Update SDFITS data_columns pointer to data array */ ((struct sdfits_data_columns*) (guppi_databuf_data(db_out, curblock_out) + struct_offset))->data = (unsigned char*)(guppi_databuf_data(db_out, curblock_out) + array_offset); index_out->num_datasets = index_out->num_datasets + 1; } } accum_time = 0; integ_num += 1; reset_accumulators(accumulator, data_cols, accum_dirty, sf.hdr.nsubband, sf.hdr.nchan); } /* Only add spectrum to accumulator if blanking bit is low */ if((freq_heap->status_bits & 0x08) == 0) { /* Fill in data columns header fields */ if(!accum_dirty[accumid]) { /*Record SPEAD header fields*/ data_cols[accumid].time = index_in->cpu_gpu_buf[heap].heap_rcvd_mjd; data_cols[accumid].time_counter = freq_heap->time_cntr; data_cols[accumid].integ_num = integ_num; data_cols[accumid].sttspec = freq_heap->spectrum_cntr; data_cols[accumid].accumid = accumid; /* Fill in rest of fields from status buffer */ strcpy(data_cols[accumid].object, sf.data_columns.object); data_cols[accumid].azimuth = sf.data_columns.azimuth; data_cols[accumid].elevation = sf.data_columns.elevation; data_cols[accumid].bmaj = sf.data_columns.bmaj; data_cols[accumid].bmin = sf.data_columns.bmin; data_cols[accumid].bpa = sf.data_columns.bpa; data_cols[accumid].centre_freq_idx = sf.data_columns.centre_freq_idx; data_cols[accumid].ra = sf.data_columns.ra; data_cols[accumid].dec = sf.data_columns.dec; data_cols[accumid].exposure = 0.0; for(i = 0; i < NUM_SW_STATES; i++) data_cols[accumid].centre_freq[i] = sf.data_columns.centre_freq[i]; accum_dirty[accumid] = 1; } data_cols[accumid].exposure += (float)(freq_heap->integ_size)/pfb_rate; data_cols[accumid].stpspec = freq_heap->spectrum_cntr; /* Add spectrum to appropriate vector accumulator (high-bw mode) */ if(payload_type == INT_PAYLOAD) { for(i = 0; i < sf.hdr.nchan; i++) { for(j = 0; j < sf.hdr.nsubband; j++) { for(k = 0; k < NUM_STOKES; k++) { accumulator[accumid] [i*sf.hdr.nsubband*NUM_STOKES + j*NUM_STOKES + k] += (float)i_payload[i*sf.hdr.nsubband*NUM_STOKES + j*NUM_STOKES + k]; } } } } /* Add spectrum to appropriate vector accumulator (low-bw mode) */ else { for(i = 0; i < sf.hdr.nchan; i++) { for(j = 0; j < sf.hdr.nsubband; j++) { for(k = 0; k < NUM_STOKES; k++) { accumulator[accumid] [i*sf.hdr.nsubband*NUM_STOKES + j*NUM_STOKES + k] += f_payload[i*sf.hdr.nsubband*NUM_STOKES + j*NUM_STOKES + k]; } } } } } accum_time += (double)freq_heap->integ_size / pfb_rate; } /* Update packet count and loss fields from input header */ nblock_int++; npacket += gp.num_pkts_rcvd; n_pkt_drop += gp.num_pkts_dropped; /* Done with current input block */ guppi_databuf_set_free(db_in, curblock_in); curblock_in = (curblock_in + 1) % db_in->n_block; /* Check for cancel */ pthread_testcancel(); } pthread_exit(NULL); pthread_cleanup_pop(0); /* Closes set_exit_status */ pthread_cleanup_pop(0); /* Closes set_finished */ pthread_cleanup_pop(0); /* Closes guppi_free_sdfits */ pthread_cleanup_pop(0); /* Closes ? */ pthread_cleanup_pop(0); /* Closes destroy_accumulators */ pthread_cleanup_pop(0); /* Closes guppi_status_detach */ pthread_cleanup_pop(0); /* Closes guppi_databuf_detach */ }
void guppi_psrfits_thread(void *_args) { /* Get args */ struct guppi_thread_args *args = (struct guppi_thread_args *)_args; pthread_cleanup_push((void *)guppi_thread_set_finished, args); /* Set cpu affinity */ cpu_set_t cpuset, cpuset_orig; sched_getaffinity(0, sizeof(cpu_set_t), &cpuset_orig); CPU_ZERO(&cpuset); CPU_SET(1, &cpuset); int rv = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); if (rv<0) { guppi_error("guppi_psrfits_thread", "Error setting cpu affinity."); perror("sched_setaffinity"); } /* Set priority */ rv = setpriority(PRIO_PROCESS, 0, args->priority); if (rv<0) { guppi_error("guppi_psrfits_thread", "Error setting priority level."); perror("set_priority"); } /* Attach to status shared mem area */ struct guppi_status st; rv = guppi_status_attach(&st); if (rv!=GUPPI_OK) { guppi_error("guppi_psrfits_thread", "Error attaching to status shared memory."); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_status_detach, &st); pthread_cleanup_push((void *)set_exit_status, &st); /* Init status */ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "init"); guppi_status_unlock_safe(&st); /* Initialize some key parameters */ struct guppi_params gp; struct psrfits pf; pf.sub.data = NULL; pf.sub.dat_freqs = pf.sub.dat_weights = NULL; pf.sub.dat_offsets = pf.sub.dat_scales = NULL; pf.hdr.chan_dm = 0.0; pf.filenum = 0; // This is crucial pthread_cleanup_push((void *)guppi_free_psrfits, &pf); pthread_cleanup_push((void *)psrfits_close, &pf); //pf.multifile = 0; // Use a single file for fold mode pf.multifile = 1; // Use a multiple files for fold mode pf.quiet = 0; // Print a message per each subint written /* Attach to databuf shared mem */ struct guppi_databuf *db; db = guppi_databuf_attach(args->input_buffer); if (db==NULL) { guppi_error("guppi_psrfits_thread", "Error attaching to databuf shared memory."); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_databuf_detach, db); /* Loop */ int curblock=0, total_status=0, firsttime=1, run=1, got_packet_0=0; int mode=SEARCH_MODE; char *ptr; char tmpstr[256]; struct foldbuf fb; struct polyco pc[64]; memset(pc, 0, sizeof(pc)); int n_polyco_written=0; float *fold_output_array = NULL; int scan_finished=0; signal(SIGINT, cc); do { /* Note waiting status */ guppi_status_lock_safe(&st); if (got_packet_0) sprintf(tmpstr, "waiting(%d)", curblock); else sprintf(tmpstr, "ready"); hputs(st.buf, STATUS_KEY, tmpstr); guppi_status_unlock_safe(&st); /* Wait for buf to have data */ rv = guppi_databuf_wait_filled(db, curblock); if (rv!=0) { // This is a big ol' kludge to avoid this process hanging // due to thread synchronization problems. sleep(1); continue; } /* Note current block */ guppi_status_lock_safe(&st); hputi4(st.buf, "CURBLOCK", curblock); guppi_status_unlock_safe(&st); /* See how full databuf is */ total_status = guppi_databuf_total_status(db); /* Read param structs for this block */ ptr = guppi_databuf_header(db, curblock); if (firsttime) { guppi_read_obs_params(ptr, &gp, &pf); firsttime = 0; } else { guppi_read_subint_params(ptr, &gp, &pf); } /* Find out what mode this data is in */ mode = psrfits_obs_mode(pf.hdr.obs_mode); /* Check if we got both packet 0 and a valid observation * start time. If so, flag writing to start. */ if (got_packet_0==0 && gp.packetindex==0 && gp.stt_valid==1) { got_packet_0 = 1; guppi_read_obs_params(ptr, &gp, &pf); guppi_update_ds_params(&pf); memset(pc, 0, sizeof(pc)); n_polyco_written=0; } /* If actual observation has started, write the data */ if (got_packet_0) { /* Note waiting status */ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "writing"); guppi_status_unlock_safe(&st); /* Get the pointer to the current data */ if (mode==FOLD_MODE) { fb.nchan = pf.hdr.nchan; fb.npol = pf.hdr.npol; fb.nbin = pf.hdr.nbin; fb.data = (float *)guppi_databuf_data(db, curblock); fb.count = (unsigned *)(guppi_databuf_data(db, curblock) + foldbuf_data_size(&fb)); fold_output_array = (float *)realloc(fold_output_array, sizeof(float) * pf.hdr.nbin * pf.hdr.nchan * pf.hdr.npol); pf.sub.data = (unsigned char *)fold_output_array; pf.fold.pc = (struct polyco *)(guppi_databuf_data(db,curblock) + foldbuf_data_size(&fb) + foldbuf_count_size(&fb)); } else pf.sub.data = (unsigned char *)guppi_databuf_data(db, curblock); /* Set the DC and Nyquist channels explicitly to zero */ /* because of the "FFT Problem" that splits DC power */ /* into those two bins. */ zero_end_chans(&pf); /* Output only Stokes I (in place) */ if (pf.hdr.onlyI && pf.hdr.npol==4) get_stokes_I(&pf); /* Downsample in frequency (in place) */ if (pf.hdr.ds_freq_fact > 1) downsample_freq(&pf); /* Downsample in time (in place) */ if (pf.hdr.ds_time_fact > 1) downsample_time(&pf); /* Folded data needs a transpose */ if (mode==FOLD_MODE) normalize_transpose_folds(fold_output_array, &fb); /* Write the data */ int last_filenum = pf.filenum; psrfits_write_subint(&pf); /* Any actions that need to be taken when a new file * is created. */ if (pf.filenum!=last_filenum) { /* No polycos yet written to the new file */ n_polyco_written=0; } /* Write the polycos if needed */ int write_pc=0, i, j; for (i=0; i<pf.fold.n_polyco_sets; i++) { if (pf.fold.pc[i].used==0) continue; int new_pc=1; for (j=0; j<n_polyco_written; j++) { if (polycos_differ(&pf.fold.pc[i], &pc[j])==0) { new_pc=0; break; } } if (new_pc || n_polyco_written==0) { pc[n_polyco_written] = pf.fold.pc[i]; n_polyco_written++; write_pc=1; } else { pf.fold.pc[i].used = 0; // Already have this one } } if (write_pc) psrfits_write_polycos(&pf, pf.fold.pc, pf.fold.n_polyco_sets); /* Is the scan complete? */ if ((pf.hdr.scanlen > 0.0) && (pf.T > pf.hdr.scanlen)) scan_finished = 1; /* For debugging... */ if (gp.drop_frac > 0.0) { printf("Block %d dropped %.3g%% of the packets\n", pf.tot_rows, gp.drop_frac*100.0); } } /* Mark as free */ guppi_databuf_set_free(db, curblock); /* Go to next block */ curblock = (curblock + 1) % db->n_block; /* Check for cancel */ pthread_testcancel(); } while (run && !scan_finished); /* Cleanup */ if (fold_output_array!=NULL) free(fold_output_array); pthread_exit(NULL); pthread_cleanup_pop(0); /* Closes psrfits_close */ pthread_cleanup_pop(0); /* Closes guppi_free_psrfits */ pthread_cleanup_pop(0); /* Closes set_exit_status */ pthread_cleanup_pop(0); /* Closes set_finished */ pthread_cleanup_pop(0); /* Closes guppi_status_detach */ pthread_cleanup_pop(0); /* Closes guppi_databuf_detach */ }
void guppi_null_thread(void *_args) { int rv; /* Set cpu affinity */ cpu_set_t cpuset, cpuset_orig; sched_getaffinity(0, sizeof(cpu_set_t), &cpuset_orig); CPU_ZERO(&cpuset); CPU_SET(6, &cpuset); rv = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); if (rv<0) { guppi_error("guppi_null_thread", "Error setting cpu affinity."); perror("sched_setaffinity"); } /* Set priority */ rv = setpriority(PRIO_PROCESS, 0, 0); if (rv<0) { guppi_error("guppi_null_thread", "Error setting priority level."); perror("set_priority"); } /* Get args */ struct guppi_thread_args *args = (struct guppi_thread_args *)_args; /* Attach to status shared mem area */ struct guppi_status st; rv = guppi_status_attach(&st); if (rv!=GUPPI_OK) { guppi_error("guppi_null_thread", "Error attaching to status shared memory."); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_status_detach, &st); pthread_cleanup_push((void *)set_exit_status, &st); /* Init status */ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "init"); guppi_status_unlock_safe(&st); /* Attach to databuf shared mem */ struct guppi_databuf *db; db = guppi_databuf_attach(args->input_buffer); if (db==NULL) { guppi_error("guppi_null_thread", "Error attaching to databuf shared memory."); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_databuf_detach, db); /* Loop */ char *ptr; struct guppi_params gp; #if FITS_TYPE == PSRFITS struct psrfits pf; pf.sub.dat_freqs = NULL; pf.sub.dat_weights = NULL; pf.sub.dat_offsets = NULL; pf.sub.dat_scales = NULL; pthread_cleanup_push((void *)guppi_free_psrfits, &pf); #else struct sdfits pf; pthread_cleanup_push((void *)guppi_free_sdfits, &pf); #endif int curblock=0; signal(SIGINT,cc); while (run_threads) { /* Note waiting status */ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "waiting"); guppi_status_unlock_safe(&st); /* Wait for buf to have data */ rv = guppi_databuf_wait_filled(db, curblock); if (rv!=0) { //sleep(1); continue; } /* Note waiting status, current block */ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "discarding"); hputi4(st.buf, "DSKBLKIN", curblock); guppi_status_unlock_safe(&st); /* Get params */ ptr = guppi_databuf_header(db, curblock); guppi_read_obs_params(ptr, &gp, &pf); /* Output if data was lost */ #if FITS_TYPE == PSRFITS if (gp.n_dropped!=0 && (gp.packetindex==0 || strcmp(pf.hdr.obs_mode,"SEARCH"))) { printf("Block beginning with pktidx=%lld dropped %d packets\n", gp.packetindex, gp.n_dropped); fflush(stdout); } #else if (gp.num_pkts_dropped!=0 && gp.num_pkts_rcvd!=0) { printf("Block received %d packets and dropped %d packets\n", gp.num_pkts_rcvd, gp.num_pkts_dropped); fflush(stdout); } #endif /* Mark as free */ guppi_databuf_set_free(db, curblock); /* Go to next block */ curblock = (curblock + 1) % db->n_block; /* Check for cancel */ pthread_testcancel(); } pthread_exit(NULL); pthread_cleanup_pop(0); /* Closes set_exit_status */ pthread_cleanup_pop(0); /* Closes guppi_free_psrfits */ pthread_cleanup_pop(0); /* Closes guppi_status_detach */ pthread_cleanup_pop(0); /* Closes guppi_databuf_detach */ }
static void *run(void * _args) { // Cast _args struct guppi_thread_args *args = (struct guppi_thread_args *)_args; #ifdef DEBUG_SEMS fprintf(stderr, "s/tid %lu/ FLUFf/\n", pthread_self()); #endif THREAD_RUN_BEGIN(args); THREAD_RUN_SET_AFFINITY_PRIORITY(args); /* Attach to status shared mem area */ THREAD_RUN_ATTACH_STATUS(args->instance_id, st); /* Attach to paper_input_databuf */ THREAD_RUN_ATTACH_DATABUF(args->instance_id, paper_input_databuf, db_in, args->input_buffer); /* Attach to paper_gpu_input_databuf */ THREAD_RUN_ATTACH_DATABUF(args->instance_id, paper_gpu_input_databuf, db_out, args->output_buffer); // Init status variables guppi_status_lock_safe(&st); hputi8(st.buf, "FLUFMCNT", 0); guppi_status_unlock_safe(&st); /* Loop */ int rv; int curblock_in=0; int curblock_out=0; struct timespec start, finish; while (run_threads) { // Note waiting status, // query integrating status // and, if armed, start count guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "waiting"); guppi_status_unlock_safe(&st); // Wait for new input block to be filled while ((rv=paper_input_databuf_wait_filled(db_in, curblock_in)) != GUPPI_OK) { if (rv==GUPPI_TIMEOUT) { guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "blocked_in"); guppi_status_unlock_safe(&st); continue; } else { guppi_error(__FUNCTION__, "error waiting for filled databuf"); run_threads=0; pthread_exit(NULL); break; } } // Wait for new gpu_input block (our output block) to be free while ((rv=paper_gpu_input_databuf_wait_free(db_out, curblock_out)) != GUPPI_OK) { if (rv==GUPPI_TIMEOUT) { guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "blocked gpu input"); guppi_status_unlock_safe(&st); continue; } else { guppi_error(__FUNCTION__, "error waiting for free databuf"); run_threads=0; pthread_exit(NULL); break; } } // Got a new data block, update status guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "fluffing"); hputi4(st.buf, "FLUFBKIN", curblock_in); hputu8(st.buf, "FLUFMCNT", db_in->block[curblock_in].header.mcnt); guppi_status_unlock_safe(&st); // Copy header and call fluff function clock_gettime(CLOCK_MONOTONIC, &start); memcpy(&db_out->block[curblock_out].header, &db_in->block[curblock_in].header, sizeof(paper_input_header_t)); paper_fluff(db_in->block[curblock_in].data, db_out->block[curblock_out].data); clock_gettime(CLOCK_MONOTONIC, &finish); // Note processing time guppi_status_lock_safe(&st); // Bits per fluff / ns per fluff = Gbps hputr4(st.buf, "FLUFGBPS", (float)(8*N_BYTES_PER_BLOCK)/ELAPSED_NS(start,finish)); guppi_status_unlock_safe(&st); // Mark input block as free and advance paper_input_databuf_set_free(db_in, curblock_in); curblock_in = (curblock_in + 1) % db_in->header.n_block; // Mark output block as full and advance paper_gpu_input_databuf_set_filled(db_out, curblock_out); curblock_out = (curblock_out + 1) % db_out->header.n_block; /* Check for cancel */ pthread_testcancel(); } run_threads=0; // Have to close all pushes THREAD_RUN_DETACH_DATAUF; THREAD_RUN_DETACH_DATAUF; THREAD_RUN_DETACH_STATUS; THREAD_RUN_END; // Thread success! return NULL; }
int guppi_udp_init(struct guppi_udp_params *p) { /* Resolve sender hostname */ struct addrinfo hints; struct addrinfo *result, *rp; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; int rv = getaddrinfo(p->sender, NULL, &hints, &result); if (rv!=0) { guppi_error("guppi_udp_init", "getaddrinfo failed"); return(GUPPI_ERR_SYS); } /* Set up socket */ p->sock = socket(PF_INET, SOCK_DGRAM, 0); if (p->sock==-1) { guppi_error("guppi_udp_init", "socket error"); freeaddrinfo(result); return(GUPPI_ERR_SYS); } /* bind to local address */ struct sockaddr_in local_ip; local_ip.sin_family = AF_INET; local_ip.sin_port = htons(p->port); local_ip.sin_addr.s_addr = INADDR_ANY; rv = bind(p->sock, (struct sockaddr *)&local_ip, sizeof(local_ip)); if (rv==-1) { guppi_error("guppi_udp_init", "bind"); return(GUPPI_ERR_SYS); } /* Set up socket to recv only from sender */ for (rp=result; rp!=NULL; rp=rp->ai_next) { if (connect(p->sock, rp->ai_addr, rp->ai_addrlen)==0) { break; } } if (rp==NULL) { guppi_error("guppi_udp_init", "connect error"); close(p->sock); freeaddrinfo(result); return(GUPPI_ERR_SYS); } memcpy(&p->sender_addr, rp, sizeof(struct addrinfo)); freeaddrinfo(result); /* Non-blocking recv */ fcntl(p->sock, F_SETFL, O_NONBLOCK); /* Increase recv buffer for this sock */ int bufsize = 128*1024*1024; socklen_t ss = sizeof(int); rv = setsockopt(p->sock, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(int)); if (rv<0) { guppi_error("guppi_udp_init", "Error setting rcvbuf size."); perror("setsockopt"); } rv = getsockopt(p->sock, SOL_SOCKET, SO_RCVBUF, &bufsize, &ss); if (0 && rv==0) { printf("guppi_udp_init: SO_RCVBUF=%d\n", bufsize); } /* Poll command */ p->pfd.fd = p->sock; p->pfd.events = POLLIN; return(GUPPI_OK); }
void guppi_rawdisk_thread(void *_args) { /* Set cpu affinity */ cpu_set_t cpuset, cpuset_orig; sched_getaffinity(0, sizeof(cpu_set_t), &cpuset_orig); CPU_ZERO(&cpuset); CPU_SET(1, &cpuset); int rv = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); if (rv<0) { guppi_error("guppi_rawdisk_thread", "Error setting cpu affinity."); perror("sched_setaffinity"); } /* Get args */ struct guppi_thread_args *args = (struct guppi_thread_args *)_args; /* Set priority */ rv = setpriority(PRIO_PROCESS, 0, 0); if (rv<0) { guppi_error("guppi_rawdisk_thread", "Error setting priority level."); perror("set_priority"); } /* Attach to status shared mem area */ struct guppi_status st; rv = guppi_status_attach(&st); if (rv!=GUPPI_OK) { guppi_error("guppi_rawdisk_thread", "Error attaching to status shared memory."); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_status_detach, &st); pthread_cleanup_push((void *)set_exit_status, &st); /* Init status */ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "init"); guppi_status_unlock_safe(&st); /* Read in general parameters */ struct guppi_params gp; #if FITS_TYPE == PSRFITS struct sdfits pf; pf.sub.dat_freqs = NULL; pf.sub.dat_weights = NULL; pf.sub.dat_offsets = NULL; pf.sub.dat_scales = NULL; pthread_cleanup_push((void *)guppi_free_psrfits, &pf); #else struct sdfits pf; pthread_cleanup_push((void *)guppi_free_sdfits, &pf); #endif /* Attach to databuf shared mem */ struct guppi_databuf *db; db = guppi_databuf_attach(args->input_buffer); if (db==NULL) { guppi_error("guppi_rawdisk_thread", "Error attaching to databuf shared memory."); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_databuf_detach, db); /* Init output file */ FILE *fraw = NULL; pthread_cleanup_push((void *)safe_fclose, fraw); /* Pointers for quantization params */ double *mean = NULL; double *std = NULL; printf("casper: raw disk thread created and running\n"); /* Loop */ int packetidx=0, npacket=0, ndrop=0, packetsize=0, blocksize=0; int orig_blocksize=0; int curblock=0; int block_count=0, blocks_per_file=128, filenum=0; int got_packet_0=0, first=1; int requantize = 0; char *ptr, *hend; signal(SIGINT,cc); while (run_threads) { /* Note waiting status */ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "waiting"); guppi_status_unlock_safe(&st); /* Wait for buf to have data */ rv = guppi_databuf_wait_filled(db, curblock); if (rv!=0) continue; printf("casper: raw disk thread rcvd data.\n"); /* Read param struct for this block */ ptr = guppi_databuf_header(db, curblock); if (first) { guppi_read_obs_params(ptr, &gp, &pf); first = 0; } else { guppi_read_subint_params(ptr, &gp, &pf); } /* Parse packet size, npacket from header */ hgeti4(ptr, "PKTIDX", &packetidx); hgeti4(ptr, "PKTSIZE", &packetsize); hgeti4(ptr, "NPKT", &npacket); hgeti4(ptr, "NDROP", &ndrop); #if FITS_TYPE == PSR_FITS /* Check for re-quantization flag */ int nbits_req = 0; if (hgeti4(ptr, "NBITSREQ", &nbits_req) == 0) { /* Param not present, don't requantize */ requantize = 0; } else { /* Param is present */ if (nbits_req==8) requantize = 0; else if (nbits_req==2) requantize = 1; else /* Invalid selection for requested nbits * .. die or ignore? */ requantize = 0; } #endif /* Set up data ptr for quant routines */ #if FITS_TYPE == PSR_FITS pf.sub.data = (unsigned char *)guppi_databuf_data(db, curblock); #else pf.data_columns.data = (unsigned char *)guppi_databuf_data(db, curblock); #endif /* Wait for packet 0 before starting write */ if (got_packet_0==0 && packetidx==0 && gp.stt_valid==1) { got_packet_0 = 1; guppi_read_obs_params(ptr, &gp, &pf); #if FITS_TYPE == PSR_FITS orig_blocksize = pf.sub.bytes_per_subint; #endif char fname[256]; sprintf(fname, "%s.%4.4d.raw", pf.basefilename, filenum); fprintf(stderr, "Opening raw file '%s'\n", fname); // TODO: check for file exist. fraw = fopen(fname, "w"); if (fraw==NULL) { guppi_error("guppi_rawdisk_thread", "Error opening file."); pthread_exit(NULL); } #if FITS_TYPE == PSR_FITS /* Determine scaling factors for quantization if appropriate */ if (requantize) { mean = (double *)realloc(mean, pf.hdr.rcvr_polns * pf.hdr.nchan * sizeof(double)); std = (double *)realloc(std, pf.hdr.rcvr_polns * pf.hdr.nchan * sizeof(double)); compute_stat(&pf, mean, std); fprintf(stderr, "Computed 2-bit stats\n"); } #endif } /* See if we need to open next file */ if (block_count >= blocks_per_file) { fclose(fraw); filenum++; char fname[256]; sprintf(fname, "%s.%4.4d.raw", pf.basefilename, filenum); fprintf(stderr, "Opening raw file '%s'\n", fname); fraw = fopen(fname, "w"); if (fraw==NULL) { guppi_error("guppi_rawdisk_thread", "Error opening file."); pthread_exit(NULL); } block_count=0; } /* See how full databuf is */ //total_status = guppi_databuf_total_status(db); /* Requantize from 8 bits to 2 bits if necessary. * See raw_quant.c for more usage examples. */ #if FITS_TYPE == PSR_FITS if (requantize && got_packet_0) { pf.sub.bytes_per_subint = orig_blocksize; /* Does the quantization in-place */ quantize_2bit(&pf, mean, std); /* Update some parameters for output */ hputi4(ptr, "BLOCSIZE", pf.sub.bytes_per_subint); hputi4(ptr, "NBITS", pf.hdr.nbits); } #endif /* Get full data block size */ hgeti4(ptr, "BLOCSIZE", &blocksize); /* If we got packet 0, write data to disk */ if (got_packet_0) { /* Note waiting status */ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "writing"); guppi_status_unlock_safe(&st); /* Write header to file */ hend = ksearch(ptr, "END"); for (ptr=ptr; ptr<=hend; ptr+=80) { fwrite(ptr, 80, 1, fraw); } /* Write data */ printf("block size: %d\n", blocksize); ptr = guppi_databuf_data(db, curblock); rv = fwrite(ptr, 1, (size_t)blocksize, fraw); if (rv != blocksize) { guppi_error("guppi_rawdisk_thread", "Error writing data."); } /* Increment counter */ block_count++; /* flush output */ fflush(fraw); } /* Mark as free */ guppi_databuf_set_free(db, curblock); /* Go to next block */ curblock = (curblock + 1) % db->n_block; /* Check for cancel */ pthread_testcancel(); } pthread_exit(NULL); pthread_cleanup_pop(0); /* Closes fclose */ pthread_cleanup_pop(0); /* Closes guppi_databuf_detach */ pthread_cleanup_pop(0); /* Closes guppi_free_psrfits */ pthread_cleanup_pop(0); /* Closes set_exit_status */ pthread_cleanup_pop(0); /* Closes guppi_status_detach */ }
static void *run(void * _args) { // Cast _args struct guppi_thread_args *args = (struct guppi_thread_args *)_args; THREAD_RUN_BEGIN(args); THREAD_RUN_SET_AFFINITY_PRIORITY(args); THREAD_RUN_ATTACH_STATUS(args->instance_id, st); // Attach to paper_ouput_databuf THREAD_RUN_ATTACH_DATABUF(args->instance_id, paper_output_databuf, db, args->input_buffer); // Setup socket and message structures int sockfd; unsigned int xengine_id = 0; struct timespec packet_delay = { .tv_sec = 0, .tv_nsec = PACKET_DELAY_NS }; guppi_status_lock_safe(&st); hgetu4(st.buf, "XID", &xengine_id); // No change if not found hputu4(st.buf, "XID", xengine_id); hputu4(st.buf, "OUTDUMPS", 0); guppi_status_unlock_safe(&st); pkt_t pkt; pkt.hdr.header = HEADER; pkt.hdr.instids = INSTIDS(xengine_id); pkt.hdr.pktinfo = PKTINFO(BYTES_PER_PACKET); pkt.hdr.heaplen = HEAPLEN; // TODO Get catcher hostname and port from somewhere #ifndef CATCHER_PORT #define CATCHER_PORT 7148 #endif #define stringify2(x) #x #define stringify(x) stringify2(x) // Open socket sockfd = open_udp_socket("catcher", stringify(CATCHER_PORT)); if(sockfd == -1) { guppi_error(__FUNCTION__, "error opening socket"); run_threads=0; pthread_exit(NULL); } #ifdef TEST_INDEX_CALCS int i, j; for(i=0; i<32; i++) { for(j=i; j<32; j++) { regtile_index(2*i, 2*j); } } for(i=0; i<32; i++) { for(j=i; j<32; j++) { casper_index(2*i, 2*j); } } run_threads=0; #endif /* Main loop */ int rv; int casper_chan, gpu_chan; int baseline; unsigned int dumps = 0; int block_idx = 0; struct timespec start, stop; signal(SIGINT,cc); signal(SIGTERM,cc); while (run_threads) { guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "waiting"); guppi_status_unlock_safe(&st); // Wait for new block to be filled while ((rv=paper_output_databuf_wait_filled(db, block_idx)) != GUPPI_OK) { if (rv==GUPPI_TIMEOUT) { guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "blocked"); guppi_status_unlock_safe(&st); continue; } else { guppi_error(__FUNCTION__, "error waiting for filled databuf"); run_threads=0; pthread_exit(NULL); break; } } clock_gettime(CLOCK_MONOTONIC, &start); // Note processing status, current input block guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "processing"); hputi4(st.buf, "OUTBLKIN", block_idx); guppi_status_unlock_safe(&st); // Update header's timestamp for this dump pkt.hdr.timestamp = TIMESTAMP(db->block[block_idx].header.mcnt * N_TIME_PER_PACKET * 2 * N_CHAN_TOTAL / 128); // Init header's offset for this dump uint32_t nbytes = 0; pkt.hdr.offset = OFFSET(nbytes); // Unpack and convert in packet sized chunks float * pf_re = db->block[block_idx].data; float * pf_im = db->block[block_idx].data + xgpu_info.matLength; pktdata_t * p_out = pkt.data; for(casper_chan=0; casper_chan<N_CHAN_PER_X; casper_chan++) { // De-interleave the channels gpu_chan = (casper_chan/Nc) + ((casper_chan%Nc)*Nx); for(baseline=0; baseline<CASPER_CHAN_LENGTH; baseline++) { off_t idx_regtile = idx_map[baseline]; pktdata_t re = CONVERT(pf_re[gpu_chan*REGTILE_CHAN_LENGTH+idx_regtile]); pktdata_t im = CONVERT(pf_im[gpu_chan*REGTILE_CHAN_LENGTH+idx_regtile]); *p_out++ = re; *p_out++ = -im; // Conjugate data to match downstream expectations nbytes += 2*sizeof(pktdata_t); if(nbytes % BYTES_PER_PACKET == 0) { int bytes_sent = send(sockfd, &pkt, sizeof(pkt.hdr)+BYTES_PER_PACKET, 0); if(bytes_sent == -1) { // Send all packets even if cactcher is not listening (i.e. we // we get a connection refused error), but abort sending this // dump if we get any other error. if(errno != ECONNREFUSED) { perror("send"); // Update stats guppi_status_lock_safe(&st); hputu4(st.buf, "OUTDUMPS", ++dumps); hputr4(st.buf, "OUTSECS", 0.0); hputr4(st.buf, "OUTMBPS", 0.0); guppi_status_unlock_safe(&st); // Break out of both for loops goto done_sending; } } else if(bytes_sent != sizeof(pkt.hdr)+BYTES_PER_PACKET) { printf("only sent %d of %lu bytes!!!\n", bytes_sent, sizeof(pkt.hdr)+BYTES_PER_PACKET); } // Delay to prevent overflowing network TX queue nanosleep(&packet_delay, NULL); // Setup for next packet p_out = pkt.data; // Update header's byte_offset for this chunk pkt.hdr.offset = OFFSET(nbytes); } } } clock_gettime(CLOCK_MONOTONIC, &stop); guppi_status_lock_safe(&st); hputu4(st.buf, "OUTDUMPS", ++dumps); hputr4(st.buf, "OUTSECS", (float)ELAPSED_NS(start,stop)/1e9); hputr4(st.buf, "OUTMBPS", (1e3*8*bytes_per_dump)/ELAPSED_NS(start,stop)); guppi_status_unlock_safe(&st); done_sending: // Mark block as free paper_output_databuf_set_free(db, block_idx); // Setup for next block block_idx = (block_idx + 1) % db->header.n_block; /* Will exit if thread has been cancelled */ pthread_testcancel(); } // Have to close all pushes THREAD_RUN_DETACH_DATAUF; THREAD_RUN_DETACH_STATUS; THREAD_RUN_END; // Thread success! return NULL; } static pipeline_thread_module_t module = { name: "paper_gpu_output_thread", type: PIPELINE_OUTPUT_THREAD, init: init, run: run };
/* This thread is passed a single arg, pointer * to the guppi_udp_params struct. This thread should * be cancelled and restarted if any hardware params * change, as this potentially affects packet size, etc. */ void *guppi_fake_net_thread(void *_args) { /* Get arguments */ struct guppi_thread_args *args = (struct guppi_thread_args *)_args; /* Set cpu affinity */ cpu_set_t cpuset, cpuset_orig; sched_getaffinity(0, sizeof(cpu_set_t), &cpuset_orig); CPU_ZERO(&cpuset); //CPU_SET(2, &cpuset); CPU_SET(3, &cpuset); int rv = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); if (rv<0) { guppi_error("guppi_fake_net_thread", "Error setting cpu affinity."); perror("sched_setaffinity"); } /* Set priority */ rv = setpriority(PRIO_PROCESS, 0, args->priority); if (rv<0) { guppi_error("guppi_fake_net_thread", "Error setting priority level."); perror("set_priority"); } /* Attach to status shared mem area */ struct guppi_status st; rv = guppi_status_attach(&st); if (rv!=GUPPI_OK) { guppi_error("guppi_fake_net_thread", "Error attaching to status shared memory."); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_status_detach, &st); pthread_cleanup_push((void *)set_exit_status, &st); /* Init status, read info */ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "init"); guppi_status_unlock_safe(&st); /* Read in general parameters */ struct guppi_params gp; #if FITS_TYPE == PSRFITS struct psrfits pf; pf.sub.dat_freqs = NULL; pf.sub.dat_weights = NULL; pf.sub.dat_offsets = NULL; pf.sub.dat_scales = NULL; #else struct sdfits pf; #endif char status_buf[GUPPI_STATUS_SIZE]; guppi_status_lock_safe(&st); memcpy(status_buf, st.buf, GUPPI_STATUS_SIZE); guppi_status_unlock_safe(&st); guppi_read_obs_params(status_buf, &gp, &pf); #if FITS_TYPE == PSRFITS pthread_cleanup_push((void *)guppi_free_psrfits, &pf); #else pthread_cleanup_push((void *)guppi_free_sdfits, &pf); #endif /* Attach to databuf shared mem */ struct guppi_databuf *db; db = guppi_databuf_attach(args->output_buffer); if (db==NULL) { guppi_error("guppi_fake_net_thread", "Error attaching to databuf shared memory."); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_databuf_detach, db); /* Time parameters */ int stt_imjd=0, stt_smjd=0; double stt_offs=0.0; /* Figure out size of data in each packet, number of packets * per block, etc. Changing packet size during an obs is not * recommended. */ int block_size; if (hgeti4(status_buf, "BLOCSIZE", &block_size)==0) { block_size = db->block_size; hputi4(status_buf, "BLOCSIZE", block_size); } else { if (block_size > db->block_size) { guppi_error("guppi_net_thread", "BLOCSIZE > databuf block_size"); block_size = db->block_size; hputi4(status_buf, "BLOCSIZE", block_size); } } unsigned heaps_per_block = block_size / sizeof(struct freq_spead_heap); /* List of databuf blocks currently in use */ unsigned i; const int nblock = 2; struct fake_datablock_stats blocks[nblock]; for (i=0; i<nblock; i++) fake_init_block(&blocks[i], db, sizeof(struct freq_spead_heap), heaps_per_block); /* Convenience names for first/last blocks in set */ struct fake_datablock_stats *fblock, *lblock; fblock = &blocks[0]; lblock = &blocks[nblock-1]; /* Misc counters, etc */ char *curdata=NULL, *curheader=NULL, *curindex=NULL; int first_time = 1; int heap_cntr = 0, next_block_heap_cntr = heaps_per_block; /* Main loop */ unsigned force_new_block=0, waiting=-1; signal(SIGINT,cc); while (run_threads) { /* Wait for data */ struct timespec sleep_dur, rem_sleep_dur; sleep_dur.tv_sec = 0; sleep_dur.tv_nsec = 2e6; nanosleep(&sleep_dur, &rem_sleep_dur); /* Update status if needed */ if (waiting!=0) { guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "receiving"); guppi_status_unlock_safe(&st); waiting=0; } /* Convert packet format if needed */ if (first_time) { first_time = 0; force_new_block=1; } else force_new_block=0; /* Determine if we go to next block */ if ((heap_cntr>=next_block_heap_cntr) || force_new_block) { printf("casper: going to next shared memory block\n"); /* Update drop stats */ guppi_status_lock_safe(&st); hputr8(st.buf, "DROPAVG", 0.0); hputr8(st.buf, "DROPTOT", 0.0); hputr8(st.buf, "DROPBLK", 0.0); guppi_status_unlock_safe(&st); /* Finalize first block, and push it off the list. * Then grab next available block. */ if (fblock->block_idx>=0) fake_finalize_block(fblock); fake_block_stack_push(blocks, nblock); fake_increment_block(lblock, heap_cntr); curdata = guppi_databuf_data(db, lblock->block_idx); curheader = guppi_databuf_header(db, lblock->block_idx); curindex = guppi_databuf_index(db, lblock->block_idx); next_block_heap_cntr = lblock->heap_idx + heaps_per_block; /* If new obs started, reset total counters, get start * time. Start time is rounded to nearest integer * second, with warning if we're off that by more * than 100ms. Any current blocks on the stack * are also finalized/reset */ if (force_new_block) { /* Get obs start time */ get_current_mjd(&stt_imjd, &stt_smjd, &stt_offs); if (stt_offs>0.5) { stt_smjd+=1; stt_offs-=1.0; } stt_offs = 0.0; /* Flush any current buffers */ for (i=0; i<nblock-1; i++) { if (blocks[i].block_idx>=0) fake_finalize_block(&blocks[i]); fake_reset_block(&blocks[i]); } } /* Read/update current status shared mem */ guppi_status_lock_safe(&st); if (stt_imjd!=0) { #if 1 hputi4(st.buf, "STT_IMJD", stt_imjd); hputi4(st.buf, "STT_SMJD", stt_smjd); hputr8(st.buf, "STT_OFFS", stt_offs); #endif hputi4(st.buf, "STTVALID", 1); } else { hputi4(st.buf, "STTVALID", 0); } memcpy(status_buf, st.buf, GUPPI_STATUS_SIZE); guppi_status_unlock_safe(&st); /* Wait for new block to be free, then clear it * if necessary and fill its header with new values. */ while ((rv=guppi_databuf_wait_free(db, lblock->block_idx)) != GUPPI_OK) { if (rv==GUPPI_TIMEOUT) { waiting=1; guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "blocked"); guppi_status_unlock_safe(&st); continue; } else { guppi_error("guppi_fake_net_thread", "error waiting for free databuf"); run_threads=0; pthread_exit(NULL); break; } } memcpy(curheader, status_buf, GUPPI_STATUS_SIZE); memset(curdata, 0, block_size); memset(curindex, 0, db->index_size); } /*Write fake data to block */ write_fake_heap_to_block(lblock, heap_cntr); heap_cntr++; /* Will exit if thread has been cancelled */ pthread_testcancel(); } pthread_exit(NULL); /* Have to close all push's */ pthread_cleanup_pop(0); /* Closes set_exit_status */ pthread_cleanup_pop(0); /* Closes guppi_free_psrfits */ pthread_cleanup_pop(0); /* Closes guppi_status_detach */ pthread_cleanup_pop(0); /* Closes guppi_databuf_detach */ }
void vegas_pfb_thread(void *_args) { /* Get args */ struct guppi_thread_args *args = (struct guppi_thread_args *)_args; int rv; /* Set cpu affinity */ cpu_set_t cpuset, cpuset_orig; sched_getaffinity(0, sizeof(cpu_set_t), &cpuset_orig); //CPU_ZERO(&cpuset); CPU_CLR(13, &cpuset); CPU_SET(11, &cpuset); rv = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset); if (rv<0) { guppi_error("vegas_pfb_thread", "Error setting cpu affinity."); perror("sched_setaffinity"); } /* Set priority */ rv = setpriority(PRIO_PROCESS, 0, args->priority); if (rv<0) { guppi_error("vegas_pfb_thread", "Error setting priority level."); perror("set_priority"); } /* Attach to status shared mem area */ struct guppi_status st; rv = guppi_status_attach(&st); if (rv!=GUPPI_OK) { guppi_error("vegas_pfb_thread", "Error attaching to status shared memory."); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_status_detach, &st); pthread_cleanup_push((void *)set_exit_status, &st); pthread_cleanup_push((void *)guppi_thread_set_finished, args); /* Init status */ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "init"); guppi_status_unlock_safe(&st); /* Init structs */ struct guppi_params gp; struct sdfits sf; pthread_cleanup_push((void *)guppi_free_sdfits, &sf); /* Attach to databuf shared mem */ struct guppi_databuf *db_in, *db_out; db_in = guppi_databuf_attach(args->input_buffer); if (db_in==NULL) { char msg[256]; sprintf(msg, "Error attaching to databuf(%d) shared memory.", args->input_buffer); guppi_error("vegas_pfb_thread", msg); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_databuf_detach, db_in); db_out = guppi_databuf_attach(args->output_buffer); if (db_out==NULL) { char msg[256]; sprintf(msg, "Error attaching to databuf(%d) shared memory.", args->output_buffer); guppi_error("vegas_pfb_thread", msg); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_databuf_detach, db_out); /* Loop */ char *hdr_in = NULL; int curblock_in=0; int first=1; int acc_len = 0; int nchan = 0; int nsubband = 0; signal(SIGINT,cc); guppi_status_lock_safe(&st); if (hgeti4(st.buf, "NCHAN", &nchan)==0) { fprintf(stderr, "ERROR: %s not in status shm!\n", "NCHAN"); } if (hgeti4(st.buf, "NSUBBAND", &nsubband)==0) { fprintf(stderr, "ERROR: %s not in status shm!\n", "NSUBBAND"); } guppi_status_unlock_safe(&st); if (EXIT_SUCCESS != init_gpu(db_in->block_size, db_out->block_size, nsubband, nchan)) { (void) fprintf(stderr, "ERROR: GPU initialisation failed!\n"); run = 0; } while (run) { /* Note waiting status */ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "waiting"); guppi_status_unlock_safe(&st); /* Wait for buf to have data */ rv = guppi_databuf_wait_filled(db_in, curblock_in); if (rv!=0) continue; /* Note waiting status, current input block */ guppi_status_lock_safe(&st); hputs(st.buf, STATUS_KEY, "processing"); hputi4(st.buf, "PFBBLKIN", curblock_in); guppi_status_unlock_safe(&st); hdr_in = guppi_databuf_header(db_in, curblock_in); /* Get params */ if (first) { guppi_read_obs_params(hdr_in, &gp, &sf); /* Read required exposure from status shared memory, and calculate corresponding accumulation length */ acc_len = (sf.hdr.chan_bw * sf.hdr.hwexposr); } guppi_read_subint_params(hdr_in, &gp, &sf); /* Call PFB function */ do_pfb(db_in, curblock_in, db_out, first, st, acc_len); /* Mark input block as free */ guppi_databuf_set_free(db_in, curblock_in); /* Go to next input block */ curblock_in = (curblock_in + 1) % db_in->n_block; /* Check for cancel */ pthread_testcancel(); if (first) { first=0; } } run=0; //cudaThreadExit(); pthread_exit(NULL); cleanup_gpu(); pthread_cleanup_pop(0); /* Closes guppi_databuf_detach(out) */ pthread_cleanup_pop(0); /* Closes guppi_databuf_detach(in) */ pthread_cleanup_pop(0); /* Closes guppi_free_sdfits */ pthread_cleanup_pop(0); /* Closes guppi_thread_set_finished */ pthread_cleanup_pop(0); /* Closes set_exit_status */ pthread_cleanup_pop(0); /* Closes guppi_status_detach */ }
static void *run(void * _args) { // Cast _args struct guppi_thread_args *args = (struct guppi_thread_args *)_args; #ifdef DEBUG_SEMS fprintf(stderr, "s/tid %lu/NET/' <<.\n", pthread_self()); #endif THREAD_RUN_BEGIN(args); THREAD_RUN_SET_AFFINITY_PRIORITY(args); THREAD_RUN_ATTACH_STATUS(args->instance_id, st); st_p = &st; // allow global (this source file) access to the status buffer /* Attach to paper_input_databuf */ THREAD_RUN_ATTACH_DATABUF(args->instance_id, paper_input_databuf, db, args->output_buffer); /* Read in general parameters */ struct guppi_params gp; struct sdfits pf; char status_buf[GUPPI_STATUS_SIZE]; guppi_status_lock_busywait_safe(st_p); memcpy(status_buf, st_p->buf, GUPPI_STATUS_SIZE); guppi_status_unlock_safe(st_p); guppi_read_obs_params(status_buf, &gp, &pf); pthread_cleanup_push((void *)guppi_free_sdfits, &pf); /* Read network params */ struct guppi_udp_params up; //guppi_read_net_params(status_buf, &up); paper_read_net_params(status_buf, &up); // Store bind host/port info etc in status buffer guppi_status_lock_busywait_safe(&st); hputs(st.buf, "BINDHOST", up.bindhost); hputi4(st.buf, "BINDPORT", up.bindport); hputu4(st.buf, "MISSEDFE", 0); hputu4(st.buf, "MISSEDPK", 0); hputs(st.buf, STATUS_KEY, "running"); guppi_status_unlock_safe(&st); struct guppi_udp_packet p; /* Give all the threads a chance to start before opening network socket */ sleep(1); #ifndef TIMING_TEST /* Set up UDP socket */ int rv = guppi_udp_init(&up); if (rv!=GUPPI_OK) { guppi_error("guppi_net_thread", "Error opening UDP socket."); pthread_exit(NULL); } pthread_cleanup_push((void *)guppi_udp_close, &up); #endif /* Main loop */ uint64_t packet_count = 0; uint64_t elapsed_wait_ns = 0; uint64_t elapsed_recv_ns = 0; uint64_t elapsed_proc_ns = 0; float ns_per_wait = 0.0; float ns_per_recv = 0.0; float ns_per_proc = 0.0; struct timespec start, stop; struct timespec recv_start, recv_stop; signal(SIGINT,cc); while (run_threads) { #ifndef TIMING_TEST /* Read packet */ clock_gettime(CLOCK_MONOTONIC, &recv_start); do { clock_gettime(CLOCK_MONOTONIC, &start); p.packet_size = recv(up.sock, p.data, GUPPI_MAX_PACKET_SIZE, 0); clock_gettime(CLOCK_MONOTONIC, &recv_stop); } while (p.packet_size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) && run_threads); if(!run_threads) break; if (up.packet_size != p.packet_size) { if (p.packet_size != -1) { #ifdef DEBUG_NET guppi_warn("guppi_net_thread", "Incorrect pkt size"); #endif continue; } else { guppi_error("guppi_net_thread", "guppi_udp_recv returned error"); perror("guppi_udp_recv"); pthread_exit(NULL); } } #endif packet_count++; // Copy packet into any blocks where it belongs. const uint64_t mcnt = write_paper_packet_to_blocks((paper_input_databuf_t *)db, &p); clock_gettime(CLOCK_MONOTONIC, &stop); elapsed_wait_ns += ELAPSED_NS(recv_start, start); elapsed_recv_ns += ELAPSED_NS(start, recv_stop); elapsed_proc_ns += ELAPSED_NS(recv_stop, stop); if(mcnt != -1) { // Update status ns_per_wait = (float)elapsed_wait_ns / packet_count; ns_per_recv = (float)elapsed_recv_ns / packet_count; ns_per_proc = (float)elapsed_proc_ns / packet_count; guppi_status_lock_busywait_safe(&st); hputu8(st.buf, "NETMCNT", mcnt); // Gbps = bits_per_packet / ns_per_packet // (N_BYTES_PER_PACKET excludes header, so +8 for the header) hputr4(st.buf, "NETGBPS", 8*(N_BYTES_PER_PACKET+8)/(ns_per_recv+ns_per_proc)); hputr4(st.buf, "NETWATNS", ns_per_wait); hputr4(st.buf, "NETRECNS", ns_per_recv); hputr4(st.buf, "NETPRCNS", ns_per_proc); guppi_status_unlock_safe(&st); // Start new average elapsed_wait_ns = 0; elapsed_recv_ns = 0; elapsed_proc_ns = 0; packet_count = 0; } #if defined TIMING_TEST || defined NET_TIMING_TEST #define END_LOOP_COUNT (1*1000*1000) static int loop_count=0; static struct timespec tt_start, tt_stop; if(loop_count == 0) { clock_gettime(CLOCK_MONOTONIC, &tt_start); } //if(loop_count == 1000000) run_threads = 0; if(loop_count == END_LOOP_COUNT) { clock_gettime(CLOCK_MONOTONIC, &tt_stop); int64_t elapsed = ELAPSED_NS(tt_start, tt_stop); printf("processed %d packets in %.6f ms (%.3f us per packet)\n", END_LOOP_COUNT, elapsed/1e6, elapsed/1e3/END_LOOP_COUNT); exit(0); } loop_count++; #endif /* Will exit if thread has been cancelled */ pthread_testcancel(); } /* Have to close all push's */ #ifndef TIMING_TEST pthread_cleanup_pop(0); /* Closes push(guppi_udp_close) */ #endif pthread_cleanup_pop(0); /* Closes guppi_free_psrfits */ THREAD_RUN_DETACH_DATAUF; THREAD_RUN_DETACH_STATUS; THREAD_RUN_END; return NULL; }
// This function returns -1 unless the given packet causes a block to be marked // as filled in which case this function returns the marked block's first mcnt. // Any return value other than -1 will be stored in the status memory as // NETMCNT, so it is important that values other than -1 are returned rarely // (i.e. when marking a block as filled)!!! static inline uint64_t write_paper_packet_to_blocks(paper_input_databuf_t *paper_input_databuf_p, struct guppi_udp_packet *p) { static block_info_t binfo; packet_header_t pkt_header; const uint64_t *payload_p; int rv; int i; uint64_t *dest_p; uint64_t netmcnt = -1; // Value to store in status memory #if N_DEBUG_INPUT_BLOCKS == 1 static uint64_t debug_remaining = -1ULL; static off_t debug_offset = 0; uint64_t * debug_ptr; #endif // housekeeping for each packet get_header(p, &pkt_header); #if N_DEBUG_INPUT_BLOCKS == 1 debug_ptr = (uint64_t *)&paper_input_databuf_p->block[N_INPUT_BLOCKS]; debug_ptr[debug_offset++] = be64toh(*(uint64_t *)(p->data)); if(--debug_remaining == 0) { exit(1); } if(debug_offset >= sizeof(paper_input_block_t)/sizeof(uint64_t)) { debug_offset = 0; } #endif if(! binfo.initialized) { // insist that we start on a multiple of sub_blocks/block if(pkt_header.mcnt % N_SUB_BLOCKS_PER_INPUT_BLOCK != 0) { return -1; } initialize_block_info(paper_input_databuf_p, &binfo, pkt_header.mcnt); } if(out_of_seq_mcnt(&binfo, pkt_header.mcnt)) { return(handle_out_of_seq_mcnt(&binfo)); } if((rv = calc_block_indexes(&binfo, &pkt_header))) { return rv; } if(! binfo.block_active[binfo.block_i]) { // new block, pass along the block for N_INPUT_BLOCKS/2 blocks ago i = subtract_block_i(binfo.block_i, N_INPUT_BLOCKS/2); #if N_DEBUG_INPUT_BLOCKS == 1 #define DEBUG_EXTRA (0x10000) if(set_block_filled(paper_input_databuf_p, &binfo, i) && debug_remaining > DEBUG_EXTRA) { debug_remaining = DEBUG_EXTRA; } #else set_block_filled(paper_input_databuf_p, &binfo, i); #endif netmcnt = paper_input_databuf_p->block[i].header.mcnt; // Wait (hopefully not long!) for free block for this packet if((rv = paper_input_databuf_busywait_free(paper_input_databuf_p, binfo.block_i)) != GUPPI_OK) { if (rv==GUPPI_TIMEOUT) { // run_threads is 0 (i.e. shutting down) return -1; } else { guppi_error(__FUNCTION__, "error waiting for free databuf"); run_threads=0; pthread_exit(NULL); return -1; } } initialize_block(paper_input_databuf_p, &binfo, pkt_header.mcnt); } binfo.block_active[binfo.block_i]++; // increment packet count for block // end housekeeping // Calculate starting points for unpacking this packet into block's data buffer. dest_p = paper_input_databuf_p->block[binfo.block_i].data + paper_input_databuf_data_idx(binfo.m, binfo.x, binfo.q, binfo.f, 0, 0); payload_p = (uint64_t *)(p->data+8); // Copy data into buffer memcpy(dest_p, payload_p, N_BYTES_PER_PACKET); return netmcnt; }