// Method to mark the block as filled static void set_block_filled(flag_input_databuf_t * db, block_info_t * binfo) { static int last_filled = -1; // The last block that was filled uint32_t block_idx = get_block_idx(binfo->mcnt_start); fprintf(stdout, "Marking block %d as filled\n", block_idx); fprintf(stdout, "Number of packets in block = %d (expected %d)\n", binfo->packet_count[block_idx], N_PACKETS_PER_BLOCK); // Validate that we're filling blocks in the proper sequence last_filled = (last_filled + 1)% N_INPUT_BLOCKS; if (last_filled != block_idx) { hashpipe_warn(__FUNCTION__, "block %d being marked filled, but expected block %d!", block_idx, last_filled); } // Validate that block_idx matches binfo->block_i if (block_idx != binfo->block_i) { hashpipe_warn(__FUNCTION__, "block_idx (%d) != binfo->block_i (%d)", block_idx, binfo->block_i); } // Mark block as good if all packets are there if (binfo->packet_count[block_idx] == N_PACKETS_PER_BLOCK) { // RACE CONDITION !!!!!!!!! // We need to lock the buffer first before modifing it. // Arguably, this data will not be accessed by the next thread until the // block is marked as filled... db->block[block_idx].header.good_data = 1; } fprintf(stdout, "Filled block good? %ld", db->block[block_idx].header.good_data); // Mark block as filled so next thread can process it flag_input_databuf_set_filled(db, block_idx); }
//---------------------------------------------------------- int init_etfits(etfits_t *etf, int start_file_num) { //---------------------------------------------------------- strcpy(etf->basefilename, "serendip6"); // TODO where to get file name? etf->file_num = start_file_num; etf->file_cnt = 0; etf->new_run = 1; etf->new_file = 1; etf->file_open = 0; etf->multifile = 1; etf->integrations_per_file = 3; // TODO place holder - should come from status shmem etf->integration_cnt = 0; etf->max_file_size = 1000000000; // 1GB TODO runtime config etf->s6_dir = getenv("S6_DIR"); if (etf->s6_dir==NULL) { etf->s6_dir = (char *)"/usr/local/etc"; hashpipe_warn(__FUNCTION__, "S6_DIR environment variable not set, using /usr/local/etc for ETFITS template"); } }
static void *run(hashpipe_thread_args_t * args) { // Local aliases to shorten access to args fields // Our output buffer happens to be a paper_input_databuf hashpipe_status_t st = args->st; const char * status_key = args->thread_desc->skey; st_p = &st; // allow global (this source file) access to the status buffer // Get inital value for crc32 function uint32_t init_crc = crc32(0,0,0); // Flag that holds off the crc thread int holdoff = 1; // Force ourself into the hold off state hashpipe_status_lock_safe(&st); hputi4(st.buf, "CRCHOLD", 1); hashpipe_status_unlock_safe(&st); while(holdoff) { // We're not in any hurry to startup sleep(1); hashpipe_status_lock_safe(&st); // Look for CRCHOLD value hgeti4(st.buf, "CRCHOLD", &holdoff); if(!holdoff) { // Done holding, so delete the key hdel(st.buf, "CRCHOLD"); } hashpipe_status_unlock_safe(&st); } /* Read network params */ struct hashpipe_udp_params up = { .bindhost = "0.0.0.0", .bindport = 8511, .packet_size = 8200 }; hashpipe_status_lock_safe(&st); // Get info from status buffer if present (no change if not present) hgets(st.buf, "BINDHOST", 80, up.bindhost); hgeti4(st.buf, "BINDPORT", &up.bindport); // Store bind host/port info etc in status buffer hputs(st.buf, "BINDHOST", up.bindhost); hputi4(st.buf, "BINDPORT", up.bindport); hputu4(st.buf, "CRCPKOK", 0); hputu4(st.buf, "CRCPKERR", 0); hputs(st.buf, status_key, "running"); hashpipe_status_unlock_safe(&st); struct hashpipe_udp_packet p; /* Give all the threads a chance to start before opening network socket */ sleep(1); /* Set up UDP socket */ int rv = hashpipe_udp_init(&up); if (rv!=HASHPIPE_OK) { hashpipe_error("paper_crc_thread", "Error opening UDP socket."); pthread_exit(NULL); } pthread_cleanup_push((void *)hashpipe_udp_close, &up); /* Main loop */ uint64_t packet_count = 0; uint64_t good_count = 0; uint64_t error_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; packet_header_t hdr; while (run_threads()) { /* Read packet */ clock_gettime(CLOCK_MONOTONIC, &recv_start); do { clock_gettime(CLOCK_MONOTONIC, &start); p.packet_size = recv(up.sock, p.data, HASHPIPE_MAX_PACKET_SIZE, 0); clock_gettime(CLOCK_MONOTONIC, &recv_stop); } while (p.packet_size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) && run_threads()); // Break out of loop if stopping if(!run_threads()) break; // Increment packet count packet_count++; // Check CRC if(crc32(init_crc, (/*const?*/ uint8_t *)p.data, p.packet_size) == 0xffffffff) { // CRC OK! Increment good counter good_count++; } else { // CRC error! Increment error counter error_count++; // Log message get_header(&p, &hdr); hashpipe_warn("paper_crc", "CRC error mcnt %llu ; fid %u ; xid %u", hdr.mcnt, hdr.fid, hdr.xid); } 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(packet_count % 1000 == 0) { // Compute stats get_header(&p, &hdr); 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; // Update status hashpipe_status_lock_busywait_safe(&st); hputu8(st.buf, "CRCMCNT", hdr.mcnt); // Gbps = bits_per_packet / ns_per_packet // (N_BYTES_PER_PACKET excludes header, so +8 for the header) hputr4(st.buf, "CRCGBPS", 8*(N_BYTES_PER_PACKET+8)/(ns_per_recv+ns_per_proc)); hputr4(st.buf, "CRCWATNS", ns_per_wait); hputr4(st.buf, "CRCRECNS", ns_per_recv); hputr4(st.buf, "CRCPRCNS", ns_per_proc); // TODO Provide some way to recognize request to zero out the // CRCERR and CRCOK fields. hputu8(st.buf, "CRCPKOK", good_count); hputu8(st.buf, "CRCPKERR", error_count); hashpipe_status_unlock_safe(&st); // Start new average elapsed_wait_ns = 0; elapsed_recv_ns = 0; elapsed_proc_ns = 0; packet_count = 0; } /* Will exit if thread has been cancelled */ pthread_testcancel(); } /* Have to close all push's */ pthread_cleanup_pop(1); /* Closes push(hashpipe_udp_close) */ return NULL; } static hashpipe_thread_desc_t crc_thread = { name: "paper_crc_thread", skey: "CRCSTAT", init: NULL, run: run, ibuf_desc: {NULL},
// Run method for the thread // It is meant to do the following: // (1) Initialize status buffer // (2) Set up network parameters and socket // (3) Start main loop // (3a) Receive packet on socket // (3b) Error check packet (packet size, etc) // (3c) Call process_packet on received packet // (4) Terminate thread cleanly static void *run(hashpipe_thread_args_t * args) { fprintf(stdout, "N_INPUTS = %d\n", N_INPUTS); fprintf(stdout, "N_CHAN = %d\n", N_CHAN); fprintf(stdout, "N_CHAN_PER_X = %d\n", N_CHAN_PER_X); fprintf(stdout, "N_CHAN_PER_PACKET = %d\n", N_CHAN_PER_PACKET); fprintf(stdout, "N_TIME_PER_PACKET = %d\n", N_TIME_PER_PACKET); fprintf(stdout, "N_TIME_PER_BLOCK = %d\n", N_TIME_PER_BLOCK); fprintf(stdout, "N_BYTES_PER_BLOCK = %d\n", N_BYTES_PER_BLOCK); fprintf(stdout, "N_BYTES_PER_PACKET = %d\n", N_BYTES_PER_PACKET); fprintf(stdout, "N_PACKETS_PER_BLOCK = %d\n", N_PACKETS_PER_BLOCK); fprintf(stdout, "N_COR_MATRIX = %d\n", N_COR_MATRIX); // Local aliases to shorten access to args fields // Our output buffer happens to be a paper_input_databuf flag_input_databuf_t *db = (flag_input_databuf_t *)args->obuf; hashpipe_status_t st = args->st; const char * status_key = args->thread_desc->skey; st_p = &st; // allow global (this source file) access to the status buffer /* Read network params */ fprintf(stdout, "Setting up network parameters\n"); struct hashpipe_udp_params up = { .bindhost = "0.0.0.0", .bindport = 8511, .packet_size = 8008 }; hashpipe_status_lock_safe(&st); // Get info from status buffer if present (no change if not present) hgets(st.buf, "BINDHOST", 80, up.bindhost); hgeti4(st.buf, "BINDPORT", &up.bindport); // Store bind host/port info etc in status buffer 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"); hashpipe_status_unlock_safe(&st); struct hashpipe_udp_packet p; /* Give all the threads a chance to start before opening network socket */ int netready = 0; int corready = 0; int checkready = 0; while (!netready) { sleep(1); // Check the correlator to see if it's ready yet hashpipe_status_lock_safe(&st); hgeti4(st.buf, "CORREADY", &corready); hgeti4(st.buf, "SAVEREADY", &checkready); hashpipe_status_unlock_safe(&st); if (!corready) { continue; } //if (!checkready) { // continue; //} // Check the other threads to see if they're ready yet // TBD // If we get here, then all threads are initialized netready = 1; } sleep(3); /* Set up UDP socket */ fprintf(stderr, "NET: BINDHOST = %s\n", up.bindhost); fprintf(stderr, "NET: BINDPORT = %d\n", up.bindport); int rv = hashpipe_udp_init(&up); if (rv!=HASHPIPE_OK) { hashpipe_error("paper_net_thread", "Error opening UDP socket."); pthread_exit(NULL); } pthread_cleanup_push((void *)hashpipe_udp_close, &up); // Initialize first few blocks in the buffer int i; for (i = 0; i < 2; i++) { // Wait until block semaphore is free if (flag_input_databuf_wait_free(db, i) != HASHPIPE_OK) { if (errno == EINTR) { // Interrupt occurred hashpipe_error(__FUNCTION__, "waiting for free block interrupted\n"); pthread_exit(NULL); } else { hashpipe_error(__FUNCTION__, "error waiting for free block\n"); pthread_exit(NULL); } } initialize_block(db, i*Nm); } // Set correlator to "start" state hashpipe_status_lock_safe(&st); hputs(st.buf, "INTSTAT", "start"); hashpipe_status_unlock_safe(&st); /* Main loop */ uint64_t packet_count = 0; fprintf(stdout, "Net: Starting Thread!\n"); while (run_threads()) { // Get packet do { p.packet_size = recv(up.sock, p.data, HASHPIPE_MAX_PACKET_SIZE, 0); } while (p.packet_size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK) && run_threads()); if(!run_threads()) break; if (up.packet_size != p.packet_size && up.packet_size != p.packet_size-8) { // If an error was returned instead of a valid packet size if (p.packet_size == -1) { fprintf(stderr, "uh oh!\n"); // Log error and exit hashpipe_error("paper_net_thread", "hashpipe_udp_recv returned error"); perror("hashpipe_udp_recv"); pthread_exit(NULL); } else { // Log warning and ignore wrongly sized packet hashpipe_warn("paper_net_thread", "Incorrect pkt size (%d)", p.packet_size); continue; } } packet_count++; process_packet(db, &p); /* Will exit if thread has been cancelled */ pthread_testcancel(); } pthread_cleanup_pop(1); /* Closes push(hashpipe_udp_close) */ hashpipe_status_lock_busywait_safe(&st); hputs(st.buf, status_key, "terminated"); hashpipe_status_unlock_safe(&st); return NULL; } static hashpipe_thread_desc_t net_thread = { name: "flag_net_thread", skey: "NETSTAT", init: NULL, run: run, ibuf_desc: {NULL},