int main() { void *dev; int cnt; int i,j; //Registrieren msr_init(&rtp,NULL); msr_reg_rtw_param("/daten/p1(ll=\"1\" ul=\"2\")","gain","int",&p1,1,1,SS_INT32,var_SCALAR,sizeof(int)); msr_reg_rtw_param("/daten/p2(init=\"0.5\" ll=\"1\" ul=\"2\")","gain","double",&p2,1,1,SS_DOUBLE,var_SCALAR,sizeof(double)); msr_reg_rtw_param("/daten/p3(unit=\"s\")","gain","double",&p3,1,10,SS_DOUBLE,var_VECTOR,sizeof(double)); msr_reg_rtw_signal("/kanal/k1","","int",(void *)&rtp.k1 - (void *)&rtp,1,1,SS_INT32,var_SCALAR,sizeof(int)); msr_reg_rtw_signal("/kanal/k2","","int",(void *)&rtp.k2 - (void *)&rtp,1,1,SS_DOUBLE,var_SCALAR,sizeof(double)); msr_reg_rtw_signal("/kanal/k3","","int",(void *)&rtp.k3[0] - (void *)&rtp,1,5,SS_DOUBLE,var_VECTOR,sizeof(double)); msr_reg_enum_list("/Aufzaehlung","",&en[0],MSR_R |MSR_W,5,1,"Eins,Zwei,Drei",NULL,NULL); //Kanäle füllen for(i=0;i<1000;i++) { // printf("index %i\n",i); rtp.k1 = i; rtp.k2 = i*0.3; for(j=0;j<5;j++) rtp.k3[j] = j*i; msr_update(&rtp); } //Lesen dev = msr_open(STDIN_FILENO,STDOUT_FILENO); msr_read(dev); do { cnt = msr_write(dev); // printf("Write count: %i\n",cnt); } while(cnt>0); msr_close(dev); msr_cleanup(); return 0; }
bool MSeedWriter::write(IntegerMSeedRecord::SharedPtr_t sampleRange) { // наполнения хедера mseed MSRecord* msr = msr_init(NULL); // общие для записей данные strcpy(msr->network, sampleRange->network().toLatin1().constData()); strcpy(msr->station, sampleRange->station().toLatin1().constData()); strcpy(msr->location, sampleRange->location().toLatin1().constData()); strcpy(msr->channel, sampleRange->channelName().toLatin1().constData()); msr->samprate = sampleRange->samplingRateHz(); msr->reclen = _recordLength; msr->record = NULL; msr->encoding = _encoding; // compression msr->byteorder = 1; // big endian byte order BTime btime = dateTimeToBTime(sampleRange->startTime()); msr->starttime = ms_btime2hptime(&btime); msr->sampletype = 'i'; // declare type to be 32-bit integers msr->datasamples = sampleRange->data().data(); msr->numsamples = sampleRange->data().size(); flag verbose = _verbose; _packedSamples = 0; _packedRecords = msr_pack(msr, &binaryStreamRecorder, _binaryStream.get(), &_packedSamples, 1, verbose); if (_packedRecords == -1) { return false; } msr->datasamples = NULL; msr_free(&msr); ms_log(0, "Packed %d samples into %d records\n", _packedSamples, _packedRecords); return true; }
void likwid_markerInit(void) { int cpuId = likwid_getProcessorId(); char* modeStr = getenv("LIKWID_MODE"); char* maskStr = getenv("LIKWID_MASK"); if ((modeStr != NULL) && (maskStr != NULL)) { likwid_init = 1; } else { return; } if (!lock_check()) { fprintf(stderr,"Access to performance counters is locked.\n"); exit(EXIT_FAILURE); } cpuid_init(); numa_init(); affinity_init(); timer_init(); hashTable_init(); for(int i=0; i<MAX_NUM_THREADS; i++) thread_socketFD[i] = -1; for(int i=0; i<MAX_NUM_NODES; i++) socket_lock[i] = LOCK_INIT; accessClient_mode = atoi(modeStr); str2BitMask(maskStr, &counterMask); if (accessClient_mode != DAEMON_AM_DIRECT) { accessClient_init(&thread_socketFD[cpuId]); } msr_init(thread_socketFD[cpuId]); thermal_init(cpuId); switch ( cpuid_info.family ) { case P6_FAMILY: switch ( cpuid_info.model ) { case PENTIUM_M_BANIAS: case PENTIUM_M_DOTHAN: perfmon_counter_map = pm_counter_map; perfmon_numCounters = NUM_COUNTERS_PM; perfmon_numCountersCore = NUM_COUNTERS_CORE_PM; break; case ATOM_45: case ATOM_32: case ATOM_22: case ATOM: perfmon_counter_map = core2_counter_map; perfmon_numCounters = NUM_COUNTERS_CORE2; perfmon_numCountersCore = NUM_COUNTERS_CORE_CORE2; break; case CORE_DUO: ERROR_PLAIN_PRINT(Unsupported Processor); break; case XEON_MP: case CORE2_65: case CORE2_45: perfmon_counter_map = core2_counter_map; perfmon_numCounters = NUM_COUNTERS_CORE2; perfmon_numCountersCore = NUM_COUNTERS_CORE_CORE2; break; case NEHALEM_EX: case WESTMERE_EX: perfmon_counter_map = westmereEX_counter_map; perfmon_numCounters = NUM_COUNTERS_WESTMEREEX; perfmon_numCountersCore = NUM_COUNTERS_CORE_WESTMEREEX; perfmon_numCountersUncore = NUM_COUNTERS_UNCORE_WESTMEREEX; break; case NEHALEM_BLOOMFIELD: case NEHALEM_LYNNFIELD: case NEHALEM_WESTMERE_M: case NEHALEM_WESTMERE: perfmon_counter_map = nehalem_counter_map; perfmon_numCounters = NUM_COUNTERS_NEHALEM; perfmon_numCountersCore = NUM_COUNTERS_CORE_NEHALEM; perfmon_numCountersUncore = NUM_COUNTERS_UNCORE_NEHALEM; break; case IVYBRIDGE: case IVYBRIDGE_EP: { int socket_fd = thread_socketFD[cpuId]; hasPCICounters = 1; power_init(0); /* FIXME Static coreId is dangerous */ pci_init(socket_fd); perfmon_counter_map = ivybridge_counter_map; perfmon_numCounters = NUM_COUNTERS_IVYBRIDGE; perfmon_numCountersCore = NUM_COUNTERS_CORE_IVYBRIDGE; perfmon_numCountersUncore = NUM_COUNTERS_UNCORE_IVYBRIDGE; } break; case HASWELL: case HASWELL_EX: case HASWELL_M1: case HASWELL_M2: power_init(0); /* FIXME Static coreId is dangerous */ perfmon_counter_map = haswell_counter_map; perfmon_numCounters = NUM_COUNTERS_HASWELL; perfmon_numCountersCore = NUM_COUNTERS_CORE_HASWELL; break; case SANDYBRIDGE: case SANDYBRIDGE_EP: { int socket_fd = thread_socketFD[cpuId]; hasPCICounters = 1; power_init(0); /* FIXME Static coreId is dangerous */ pci_init(socket_fd); perfmon_counter_map = sandybridge_counter_map; perfmon_numCounters = NUM_COUNTERS_SANDYBRIDGE; perfmon_numCountersCore = NUM_COUNTERS_CORE_SANDYBRIDGE; perfmon_numCountersUncore = NUM_COUNTERS_UNCORE_SANDYBRIDGE; } break; default: ERROR_PLAIN_PRINT(Unsupported Processor); break; } break; case MIC_FAMILY: switch ( cpuid_info.model ) { case XEON_PHI: perfmon_counter_map = phi_counter_map; perfmon_numCounters = NUM_COUNTERS_PHI; perfmon_numCountersCore = NUM_COUNTERS_CORE_PHI; break; default: ERROR_PLAIN_PRINT(Unsupported Processor); break; } break; case K8_FAMILY: perfmon_counter_map = k10_counter_map; perfmon_numCounters = NUM_COUNTERS_K10; perfmon_numCountersCore = NUM_COUNTERS_CORE_K10; break; case K10_FAMILY: perfmon_counter_map = k10_counter_map; perfmon_numCounters = NUM_COUNTERS_K10; perfmon_numCountersCore = NUM_COUNTERS_CORE_K10; break; case K15_FAMILY: perfmon_counter_map = interlagos_counter_map; perfmon_numCounters = NUM_COUNTERS_INTERLAGOS; perfmon_numCountersCore = NUM_COUNTERS_CORE_INTERLAGOS; break; case K16_FAMILY: perfmon_counter_map = kabini_counter_map; perfmon_numCounters = NUM_COUNTERS_KABINI; perfmon_numCountersCore = NUM_COUNTERS_CORE_KABINI; break; default: ERROR_PLAIN_PRINT(Unsupported Processor); break; } }
// Function that reads from a MiniSEED binary file from a char buffer and // returns a LinkedIDList. LinkedIDList * readMSEEDBuffer (char *mseed, int buflen, Selections *selections, flag unpack_data, int reclen, flag verbose, flag details, int header_byteorder, long (*allocData) (int, char), void (*diag_print) (char*), void (*log_print) (char*)) { int retcode = 0; int retval = 0; flag swapflag = 0; // current offset of mseed char pointer int offset = 0; // Unpack without reading the data first flag dataflag = 0; // the timing_qual of BLK 1001 uint8_t timing_qual = 0xFF; // the calibration type, availability of BLK 300, 310, 320, 390, 395 int8_t calibration_type = -1; // Init all the pointers to NULL. Most compilers should do this anyway. LinkedIDList * idListHead = NULL; LinkedIDList * idListCurrent = NULL; LinkedIDList * idListLast = NULL; MSRecord *msr = NULL; ContinuousSegment * segmentCurrent = NULL; hptime_t lastgap = 0; hptime_t hptimetol = 0; hptime_t nhptimetol = 0; long data_offset; LinkedRecordList *recordHead = NULL; LinkedRecordList *recordPrevious = NULL; LinkedRecordList *recordCurrent = NULL; int datasize; int record_count = 0; // A negative verbosity suppressed as much as possible. if (verbose < 0) { ms_loginit(&empty_print, NULL, &empty_print, NULL); } else { ms_loginit(log_print, "INFO: ", diag_print, "ERROR: "); } if (header_byteorder >= 0) { // Enforce little endian. if (header_byteorder == 0) { MS_UNPACKHEADERBYTEORDER(0); } // Enforce big endian. else { MS_UNPACKHEADERBYTEORDER(1); } } else { MS_UNPACKHEADERBYTEORDER(-1); } // // Read all records and save them in a linked list. // while (offset < buflen) { msr = msr_init(NULL); if ( msr == NULL ) { ms_log (2, "readMSEEDBuffer(): Error initializing msr\n"); return NULL; } if (verbose > 1) { ms_log(0, "readMSEEDBuffer(): calling msr_parse with " "mseed+offset=%d+%d, buflen=%d, reclen=%d, dataflag=%d, verbose=%d\n", mseed, offset, buflen, reclen, dataflag, verbose); } // If the record length is given, make sure at least that amount of data is available. if (reclen != -1) { if (offset + reclen > buflen) { ms_log(1, "readMSEEDBuffer(): Last reclen exceeds buflen, skipping.\n"); msr_free(&msr); break; } } // Otherwise assume the smallest possible record length and assure that enough // data is present. else { if (offset + 256 > buflen) { ms_log(1, "readMSEEDBuffer(): Last record only has %i byte(s) which " "is not enough to constitute a full SEED record. Corrupt data? " "Record will be skipped.\n", buflen - offset); msr_free(&msr); break; } } // Pass (buflen - offset) because msr_parse() expects only a single record. This // way libmseed can take care to not overstep bounds. retcode = msr_parse ( (mseed+offset), buflen - offset, &msr, reclen, dataflag, verbose); if (retcode != MS_NOERROR) { switch ( retcode ) { case MS_ENDOFFILE: ms_log(1, "readMSEEDBuffer(): Unexpected end of file when " "parsing record starting at offset %d. The rest " "of the file will not be read.\n", offset); break; case MS_GENERROR: ms_log(1, "readMSEEDBuffer(): Generic error when parsing " "record starting at offset %d. The rest of the " "file will not be read.\n", offset); break; case MS_NOTSEED: ms_log(1, "readMSEEDBuffer(): Record starting at offset " "%d is not valid SEED. The rest of the file " "will not be read.\n", offset); break; case MS_WRONGLENGTH: ms_log(1, "readMSEEDBuffer(): Length of data read was not " "correct when parsing record starting at " "offset %d. The rest of the file will not be " "read.\n", offset); break; case MS_OUTOFRANGE: ms_log(1, "readMSEEDBuffer(): SEED record length out of " "range for record starting at offset %d. The " "rest of the file will not be read.\n", offset); break; case MS_UNKNOWNFORMAT: ms_log(1, "readMSEEDBuffer(): Unknown data encoding " "format for record starting at offset %d. The " "rest of the file will not be read.\n", offset); break; case MS_STBADCOMPFLAG: ms_log(1, "readMSEEDBuffer(): Invalid STEIM compression " "flag(s) in record starting at offset %d. The " "rest of the file will not be read.\n", offset); break; default: ms_log(1, "readMSEEDBuffer(): Unknown error '%d' in " "record starting at offset %d. The rest of the " "file will not be read.\n", retcode, offset); break; } msr_free(&msr); break; } if (offset + msr->reclen > buflen) { ms_log(1, "readMSEEDBuffer(): Last msr->reclen exceeds buflen, skipping.\n"); msr_free(&msr); break; } // Test against selections if supplied if ( selections ) { char srcname[50]; hptime_t endtime; msr_srcname (msr, srcname, 1); endtime = msr_endtime (msr); if ( ms_matchselect (selections, srcname, msr->starttime, endtime, NULL) == NULL ) { // Add the record length for the next iteration offset += msr->reclen; // Free record. msr_free(&msr); continue; } } record_count += 1; recordCurrent = lrl_init (); // Append to linked record list if one exists. if ( recordHead != NULL ) { recordPrevious->next = recordCurrent; recordCurrent->previous = recordPrevious; recordCurrent->next = NULL; recordPrevious = recordCurrent; } // Otherwise create a new one. else { recordHead = recordCurrent; recordCurrent->previous = NULL; recordPrevious = recordCurrent; } recordCurrent->record = msr; // Determine the byte order swapflag only for the very first record. // The byte order should not change within the file. // XXX: Maybe check for every record? if (swapflag <= 0) { // Returns 0 if the host is little endian, otherwise 1. flag bigendianhost = ms_bigendianhost(); // Set the swapbyteflag if it is needed. if ( msr->Blkt1000 != 0) { /* If BE host and LE data need swapping */ if ( bigendianhost && msr->byteorder == 0 ) { swapflag = 1; } /* If LE host and BE data (or bad byte order value) need swapping */ if ( !bigendianhost && msr->byteorder > 0 ) { swapflag = 1; } } } // Actually unpack the data if the flag is not set. if (unpack_data != 0) { retval = msr_unpack_data (msr, swapflag, verbose); } if ( retval > 0 ) { msr->numsamples = retval; } // Add the record length for the next iteration offset += msr->reclen; } // Return empty id list if no records could be found. if (record_count == 0) { idListHead = lil_init(); return idListHead; } // All records that match the selection are now stored in a LinkedRecordList // that starts at recordHead. The next step is to sort them by matching ids // and then by time. recordCurrent = recordHead; while (recordCurrent != NULL) { // Check if the ID of the record is already available and if not create a // new one. // Start with the last id as it is most likely to be the correct one. idListCurrent = idListLast; while (idListCurrent != NULL) { if (strcmp(idListCurrent->network, recordCurrent->record->network) == 0 && strcmp(idListCurrent->station, recordCurrent->record->station) == 0 && strcmp(idListCurrent->location, recordCurrent->record->location) == 0 && strcmp(idListCurrent->channel, recordCurrent->record->channel) == 0 && idListCurrent->dataquality == recordCurrent->record->dataquality) { break; } else { idListCurrent = idListCurrent->previous; } } // Create a new id list if one is needed. if (idListCurrent == NULL) { idListCurrent = lil_init(); idListCurrent->previous = idListLast; if (idListLast != NULL) { idListLast->next = idListCurrent; } idListLast = idListCurrent; if (idListHead == NULL) { idListHead = idListCurrent; } // Set the IdList attributes. strcpy(idListCurrent->network, recordCurrent->record->network); strcpy(idListCurrent->station, recordCurrent->record->station); strcpy(idListCurrent->location, recordCurrent->record->location); strcpy(idListCurrent->channel, recordCurrent->record->channel); idListCurrent->dataquality = recordCurrent->record->dataquality; } // Now check if the current record fits exactly to the end of the last // segment of the current id. If not create a new segment. Therefore // if records with the same id are in wrong order a new segment will be // created. This is on purpose. segmentCurrent = idListCurrent->lastSegment; if (segmentCurrent != NULL) { hptimetol = (hptime_t) (0.5 * segmentCurrent->hpdelta); nhptimetol = ( hptimetol ) ? -hptimetol : 0; lastgap = recordCurrent->record->starttime - segmentCurrent->endtime - segmentCurrent->hpdelta; } if (details == 1) { /* extract information on calibration BLKs */ calibration_type = -1; if (recordCurrent->record->blkts) { BlktLink *cur_blkt = recordCurrent->record->blkts; while (cur_blkt) { switch (cur_blkt->blkt_type) { case 300: calibration_type = 1; break; case 310: calibration_type = 2; break; case 320: calibration_type = 3; break; case 390: calibration_type = 4; break; case 395: calibration_type = -2; break; default: break; } cur_blkt = cur_blkt->next; } } /* extract information based on timing quality */ timing_qual = 0xFF; if (recordCurrent->record->Blkt1001 != 0) { timing_qual = recordCurrent->record->Blkt1001->timing_qual; } } if ( segmentCurrent != NULL && segmentCurrent->sampletype == recordCurrent->record->sampletype && // Test the default sample rate tolerance: abs(1-sr1/sr2) < 0.0001 MS_ISRATETOLERABLE (segmentCurrent->samprate, recordCurrent->record->samprate) && // Check if the times are within the time tolerance lastgap <= hptimetol && lastgap >= nhptimetol && segmentCurrent->timing_qual == timing_qual && segmentCurrent->calibration_type == calibration_type) { recordCurrent->previous = segmentCurrent->lastRecord; segmentCurrent->lastRecord = segmentCurrent->lastRecord->next = recordCurrent; segmentCurrent->samplecnt += recordCurrent->record->samplecnt; segmentCurrent->endtime = msr_endtime(recordCurrent->record); } // Otherwise create a new segment and add the current record. else { segmentCurrent = seg_init(); segmentCurrent->previous = idListCurrent->lastSegment; if (idListCurrent->lastSegment != NULL) { idListCurrent->lastSegment->next = segmentCurrent; } else { idListCurrent->firstSegment = segmentCurrent; } idListCurrent->lastSegment = segmentCurrent; segmentCurrent->starttime = recordCurrent->record->starttime; segmentCurrent->endtime = msr_endtime(recordCurrent->record); segmentCurrent->samprate = recordCurrent->record->samprate; segmentCurrent->sampletype = recordCurrent->record->sampletype; segmentCurrent->samplecnt = recordCurrent->record->samplecnt; // Calculate high-precision sample period segmentCurrent->hpdelta = (hptime_t) (( recordCurrent->record->samprate ) ? (HPTMODULUS / recordCurrent->record->samprate) : 0.0); segmentCurrent->timing_qual = timing_qual; segmentCurrent->calibration_type = calibration_type; segmentCurrent->firstRecord = segmentCurrent->lastRecord = recordCurrent; recordCurrent->previous = NULL; } recordPrevious = recordCurrent->next; recordCurrent->next = NULL; recordCurrent = recordPrevious; } // Now loop over all segments, combine the records and free the msr // structures. idListCurrent = idListHead; while (idListCurrent != NULL) { segmentCurrent = idListCurrent->firstSegment; while (segmentCurrent != NULL) { if (segmentCurrent->datasamples) { free(segmentCurrent->datasamples); } // Allocate data via a callback function. if (unpack_data != 0) { segmentCurrent->datasamples = (void *) allocData(segmentCurrent->samplecnt, segmentCurrent->sampletype); } // Loop over all records, write the data to the buffer and free the msr structures. recordCurrent = segmentCurrent->firstRecord; data_offset = (long)(segmentCurrent->datasamples); while (recordCurrent != NULL) { datasize = recordCurrent->record->samplecnt * ms_samplesize(recordCurrent->record->sampletype); memcpy((void *)data_offset, recordCurrent->record->datasamples, datasize); // Free the record. msr_free(&(recordCurrent->record)); // Increase the data_offset and the record. data_offset += (long)datasize; recordCurrent = recordCurrent->next; } segmentCurrent = segmentCurrent->next; } idListCurrent = idListCurrent->next; } return idListHead; }
/*************************************************************************** * collect_and_write: * * Attempt to connect to a device, slows down the loop checking * after 20 attempts with a larger delay to reduce pointless * work being done. * * Returns 0 on success and -1 otherwise. ***************************************************************************/ int collect_and_write() { int32_t idata[2000]; // enough space for data of 2 records hptime_t hptime; hptime_t start_hptime_est = 0; hptime_t last_hptime; DOUBLE dt, dt_est, sample_rate_est; DOUBLE start_hptime_current, record_window_current, record_window_est; DOUBLE prev_start_hptime_est = -1; int n_start_hptime_est; // debug hptime_t start_hptime_nominal = 0; hptime_t prev_start_next_hptime_est = 0; double diff_end, diff_end_cumul = 0.0; char seedtimestr[64]; // decay constant depends on required decay time and sample rate //double decay_minutes = 60.0; // 1 hour double decay_minutes = 1.0; double decay_consant = 1.0 / (decay_minutes * 60.0 * (double) nominal_sample_rate); // initialize last_hptime to current time last_hptime = current_utc_hptime(); // initialize dt_est based on nominal sample rate dt_est = (nominal_sample_rate == 80) ? 1.0 / SAMP_PER_SEC_80 : (nominal_sample_rate == 40) ? 1.0 / SAMP_PER_SEC_40 : 1.0 / SAMP_PER_SEC_20; // ‘a’: 20.032 SPS // ‘b’: 39.860 SPS // ‘c’: 79.719 SPS // initialize record_window_est based on nominal sample rate and record length record_window_est = dt_est * num_samples_in_record; if (DEBUG) { logprintf(MSG_FLAG, "Initialize: last_hptime=%lld, dt_est=%lld, dt=%lf, dt_end=%lf, dt_end_cumul=%lf)\n", last_hptime, dt_est, record_window_est); } int first = 1; MSRecord *pmsrecord = msr_init(NULL); strcpy(pmsrecord->network, station_network); strcpy(pmsrecord->station, station_name); strcpy(pmsrecord->location, ""); sprintf(pmsrecord->channel, "%s%s", channel_prefix, component); pmsrecord->samprate = 1.0; pmsrecord->reclen = SLRECSIZE; pmsrecord->encoding = mswrite_data_encoding_type_code; pmsrecord->byteorder = 1; pmsrecord->datasamples = idata; pmsrecord->numsamples = 0; pmsrecord->sampletype = 'i'; while (1) { // load data up to SLRECSIZE long ivalue; int nsamp = 0; start_hptime_current = 0; n_start_hptime_est = 0; while (nsamp < num_samples_in_record) { ivalue = read_next_value(&hptime, TIMEOUT_LARGE); if (ivalue == READ_ERROR || ivalue < MIN_DATA || ivalue > MAX_DATA) { logprintf(MSG_FLAG, "READ_ERROR: port=%s, nsamp=%d, ivalue=%ld\n", port_path, nsamp, ivalue); pmsrecord->datasamples = NULL; msr_free(&pmsrecord); return (-1); } if (DEBUG && nsamp == 0) { start_hptime_nominal = hptime; } idata[pmsrecord->numsamples + nsamp] = (int32_t) ivalue; dt = (DOUBLE) (hptime - last_hptime) / (DOUBLE) HPTMODULUS; last_hptime = hptime; if (verbose > 3) { logprintf(MSG_FLAG, "%d %ld %s (dt=%lf)\n", nsamp, ivalue, ms_hptime2seedtimestr(hptime, seedtimestr, 1), (double) dt); } // estimate start time and dt // use only later samples in record since writing previous record may delay reading of first samples of this record if (nsamp >= num_samples_in_record / 2) { // 20131107 AJL - use all samples, may give better start time estimate, since buffering should compensate for any delay of first samples //if (1) { // start time estimate is timestamp of current data minus dt_est*nsamp start_hptime_current += (hptime - (hptime_t) ((DOUBLE) 0.5 + dt_est * (DOUBLE) HPTMODULUS * (DOUBLE) nsamp)); n_start_hptime_est++; // accumulate dt_est using low-pass filter //dt_est = dt_est + (DOUBLE) decay_consant * (dt - dt_est); } nsamp++; } start_hptime_current /= n_start_hptime_est; if (prev_start_hptime_est > 0) { record_window_current = (DOUBLE) (start_hptime_current - prev_start_hptime_est) / (DOUBLE) HPTMODULUS; } else { record_window_current = record_window_est; } // accumulate record_window_est using low-pass filter record_window_est = record_window_est + (DOUBLE) decay_consant * (record_window_current - record_window_est); if (prev_start_hptime_est > 0) { start_hptime_est = prev_start_hptime_est + (hptime_t) ((DOUBLE) 0.5 + record_window_est * (DOUBLE) HPTMODULUS); } else { start_hptime_est = start_hptime_current; } prev_start_hptime_est = start_hptime_est; // test - truncate dt to 1/10000 s to match precision of miniseed btime //logprintf(MSG_FLAG, "0 sample_rate_est=%lf (dt=%lfs)\n", (double) ((DOUBLE) 1.0 / dt_est), (double) dt_est); dt_est = record_window_est / (DOUBLE) num_samples_in_record; sample_rate_est = (DOUBLE) 1.0 / dt_est; if (DEBUG) { diff_end = (double) (start_hptime_est - prev_start_next_hptime_est) / (double) HPTMODULUS; if (!first) diff_end_cumul += diff_end; logprintf(MSG_FLAG, "sample_rate_est=%lf (dt=%lfs)\n", (double) sample_rate_est, (double) dt_est); logprintf(MSG_FLAG, "start_hptime_est=%lld, start_hptime_nominal=%lld, dt=%lf, dt_end=%lf, dt_end_cumul=%lf)\n", start_hptime_est, start_hptime_nominal, (double) ((DOUBLE) (start_hptime_est - start_hptime_nominal) / (DOUBLE) HPTMODULUS), diff_end, diff_end_cumul); prev_start_next_hptime_est = start_hptime_est + (hptime_t) ((DOUBLE) 0.5 + dt_est * (DOUBLE) HPTMODULUS * (DOUBLE) nsamp); } pmsrecord->starttime = start_hptime_est - (DOUBLE) HPTMODULUS * pmsrecord->numsamples / pmsrecord->samprate; pmsrecord->samprate = mswrite_header_sample_rate > 0.0 ? mswrite_header_sample_rate : sample_rate_est; pmsrecord->numsamples += nsamp; int64_t npackedsamples = 0; if (msr_pack(pmsrecord, record_handler, NULL, &npackedsamples, 0, verbose) < 0) { logprintf(ERROR_FLAG, "Error encoding data!\n"); exit(1); } pmsrecord->numsamples -= npackedsamples; memmove(&idata[0], &idata[npackedsamples], pmsrecord->numsamples * 4); } return (0); }
int main (int argc, char** argv) { int socket_fd = -1; int optInfo = 0; int optClock = 0; int optStethoscope = 0; int optSockets = 0; double runtime; int hasDRAM = 0; int c; bstring argString; bstring eventString = bfromcstr("CLOCK"); int numSockets=1; int numThreads=0; int threadsSockets[MAX_NUM_NODES*2]; int threads[MAX_NUM_THREADS]; threadsSockets[0] = 0; if (argc == 1) { HELP_MSG; exit (EXIT_SUCCESS); } while ((c = getopt (argc, argv, "+c:hiM:ps:v")) != -1) { switch (c) { case 'c': CHECK_OPTION_STRING; numSockets = bstr_to_cpuset_physical((uint32_t*) threadsSockets, argString); bdestroy(argString); optSockets = 1; break; case 'h': HELP_MSG; exit (EXIT_SUCCESS); case 'i': optInfo = 1; break; case 'M': /* Set MSR Access mode */ CHECK_OPTION_STRING; accessClient_setaccessmode(str2int((char*) argString->data)); bdestroy(argString); break; case 'p': optClock = 1; break; case 's': CHECK_OPTION_STRING; optStethoscope = str2int((char*) argString->data); bdestroy(argString); break; case 'v': VERSION_MSG; exit (EXIT_SUCCESS); case '?': if (optopt == 's' || optopt == 'M' || optopt == 'c') { HELP_MSG; } else if (isprint (optopt)) { fprintf (stderr, "Unknown option `-%c'.\n", optopt); } else { fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt); } exit( EXIT_FAILURE); default: HELP_MSG; exit (EXIT_SUCCESS); } } if (!lock_check()) { fprintf(stderr,"Access to performance counters is locked.\n"); exit(EXIT_FAILURE); } if (optClock && optind == argc) { fprintf(stderr,"Commandline option -p requires an executable.\n"); exit(EXIT_FAILURE); } if (optSockets && !optStethoscope && optind == argc) { fprintf(stderr,"Commandline option -c requires an executable if not used in combination with -s.\n"); exit(EXIT_FAILURE); } if (cpuid_init() == EXIT_FAILURE) { fprintf(stderr, "CPU not supported\n"); exit(EXIT_FAILURE); } if (numSockets > cpuid_topology.numSockets) { fprintf(stderr, "System has only %d sockets but %d are given on commandline\n", cpuid_topology.numSockets, numSockets); exit(EXIT_FAILURE); } numa_init(); /* consider NUMA node as power unit for the moment */ accessClient_init(&socket_fd); msr_init(socket_fd); timer_init(); /* check for supported processors */ if ((cpuid_info.model == SANDYBRIDGE_EP) || (cpuid_info.model == SANDYBRIDGE) || (cpuid_info.model == IVYBRIDGE) || (cpuid_info.model == IVYBRIDGE_EP) || (cpuid_info.model == HASWELL) || (cpuid_info.model == NEHALEM_BLOOMFIELD) || (cpuid_info.model == NEHALEM_LYNNFIELD) || (cpuid_info.model == NEHALEM_WESTMERE)) { power_init(numa_info.nodes[0].processors[0]); } else { fprintf (stderr, "Query Turbo Mode only supported on Intel Nehalem/Westmere/SandyBridge/IvyBridge/Haswell processors!\n"); exit(EXIT_FAILURE); } double clock = (double) timer_getCpuClock(); printf(HLINE); printf("CPU name:\t%s \n",cpuid_info.name); printf("CPU clock:\t%3.2f GHz \n", (float) clock * 1.E-09); printf(HLINE); if (optInfo) { if (power_info.turbo.numSteps != 0) { printf("Base clock:\t%.2f MHz \n", power_info.baseFrequency ); printf("Minimal clock:\t%.2f MHz \n", power_info.minFrequency ); printf("Turbo Boost Steps:\n"); for (int i=0; i < power_info.turbo.numSteps; i++ ) { printf("C%d %.2f MHz \n",i+1, power_info.turbo.steps[i] ); } } printf(HLINE); } if (cpuid_info.model == SANDYBRIDGE_EP) { hasDRAM = 1; } else if ((cpuid_info.model != SANDYBRIDGE) && (cpuid_info.model != SANDYBRIDGE_EP) && (cpuid_info.model != IVYBRIDGE) && (cpuid_info.model != IVYBRIDGE_EP) && (cpuid_info.model != HASWELL)) { fprintf (stderr, "RAPL not supported on this processor!\n"); exit(EXIT_FAILURE); } if (optInfo) { printf("Thermal Spec Power: %g Watts \n", power_info.tdp ); printf("Minimum Power: %g Watts \n", power_info.minPower); printf("Maximum Power: %g Watts \n", power_info.maxPower); printf("Maximum Time Window: %g micro sec \n", power_info.maxTimeWindow); printf(HLINE); exit(EXIT_SUCCESS); } if (optClock) { affinity_init(); argString = bformat("S%u:0-%u", threadsSockets[0], cpuid_topology.numCoresPerSocket-1); for (int i=1; i<numSockets; i++) { bstring tExpr = bformat("@S%u:0-%u", threadsSockets[i], cpuid_topology.numCoresPerSocket-1); bconcat(argString, tExpr); } numThreads = bstr_to_cpuset(threads, argString); bdestroy(argString); perfmon_init(numThreads, threads, stdout); perfmon_setupEventSet(eventString, NULL); } { PowerData pDataPkg[MAX_NUM_NODES*2]; PowerData pDataDram[MAX_NUM_NODES*2]; printf("Measure on sockets: %d", threadsSockets[0]); for (int i=1; i<numSockets; i++) { printf(", %d", threadsSockets[i]); } printf("\n"); if (optStethoscope) { if (optClock) { perfmon_startCounters(); } else { for (int i=0; i<numSockets; i++) { int cpuId = numa_info.nodes[threadsSockets[i]].processors[0]; if (hasDRAM) power_start(pDataDram+i, cpuId, DRAM); power_start(pDataPkg+i, cpuId, PKG); } } sleep(optStethoscope); if (optClock) { perfmon_stopCounters(); perfmon_printCounterResults(); perfmon_finalize(); } else { for (int i=0; i<numSockets; i++) { int cpuId = numa_info.nodes[threadsSockets[i]].processors[0]; power_stop(pDataPkg+i, cpuId, PKG); if (hasDRAM) power_stop(pDataDram+i, cpuId, DRAM); } } runtime = (double) optStethoscope; } else { TimerData time; argv += optind; bstring exeString = bfromcstr(argv[0]); for (int i=1; i<(argc-optind); i++) { bconchar(exeString, ' '); bcatcstr(exeString, argv[i]); } printf("%s\n",bdata(exeString)); if (optClock) { perfmon_startCounters(); } else { for (int i=0; i<numSockets; i++) { int cpuId = numa_info.nodes[threadsSockets[i]].processors[0]; if (hasDRAM) power_start(pDataDram+i, cpuId, DRAM); power_start(pDataPkg+i, cpuId, PKG); } timer_start(&time); } if (system(bdata(exeString)) == EOF) { fprintf(stderr, "Failed to execute %s!\n", bdata(exeString)); exit(EXIT_FAILURE); } if (optClock) { perfmon_stopCounters(); perfmon_printCounterResults(); perfmon_finalize(); } else { timer_stop(&time); for (int i=0; i<numSockets; i++) { int cpuId = numa_info.nodes[threadsSockets[i]].processors[0]; power_stop(pDataPkg+i, cpuId, PKG); if (hasDRAM) power_stop(pDataDram+i, cpuId, DRAM); } runtime = timer_print(&time); } } if (!optClock) { printf("Runtime: %g second \n",runtime); printf(HLINE); for (int i=0; i<numSockets; i++) { printf("Socket %d\n",threadsSockets[i]); printf("Domain: PKG \n"); printf("Energy consumed: %g Joules \n", power_printEnergy(pDataPkg+i)); printf("Power consumed: %g Watts \n", power_printEnergy(pDataPkg+i) / runtime ); if (hasDRAM) { printf("Domain: DRAM \n"); printf("Energy consumed: %g Joules \n", power_printEnergy(pDataDram+i)); printf("Power consumed: %g Watts \n", power_printEnergy(pDataDram+i) / runtime ); } printf("\n"); } } } #if 0 if ( cpuid_hasFeature(TM2) ) { thermal_init(0); printf("Current core temperatures:\n"); for (uint32_t i = 0; i < cpuid_topology.numCoresPerSocket; i++ ) { printf("Core %d: %u C\n", numa_info.nodes[socketId].processors[i], thermal_read(numa_info.nodes[socketId].processors[i])); } } #endif msr_finalize(); return EXIT_SUCCESS; }
// Function that reads from a MiniSEED binary file from a char buffer and // returns a LinkedIDList. LinkedIDList * readMSEEDBuffer (char *mseed, int buflen, Selections *selections, flag unpack_data, int reclen, flag verbose, flag details, int header_byteorder, long long (*allocData) (int, char), void (*diag_print) (char*), void (*log_print) (char*)) { int retcode = 0; int retval = 0; flag swapflag = 0; flag bigendianhost = ms_bigendianhost(); // current offset of mseed char pointer int offset = 0; // Unpack without reading the data first flag dataflag = 0; // the timing_qual of BLK 1001 uint8_t timing_qual = 0xFF; // the calibration type, availability of BLK 300, 310, 320, 390, 395 int8_t calibration_type = -1; // Init all the pointers to NULL. Most compilers should do this anyway. LinkedIDList * idListHead = NULL; LinkedIDList * idListCurrent = NULL; LinkedIDList * idListLast = NULL; MSRecord *msr = NULL; ContinuousSegment * segmentCurrent = NULL; hptime_t lastgap = 0; hptime_t hptimetol = 0; hptime_t nhptimetol = 0; long long data_offset; LinkedRecordList *recordHead = NULL; LinkedRecordList *recordPrevious = NULL; LinkedRecordList *recordCurrent = NULL; int datasize; int record_count = 0; // A negative verbosity suppresses as much as possible. if (verbose < 0) { ms_loginit(&empty_print, NULL, &empty_print, NULL); } else { ms_loginit(log_print, "INFO: ", diag_print, "ERROR: "); } if (header_byteorder >= 0) { // Enforce little endian. if (header_byteorder == 0) { MS_UNPACKHEADERBYTEORDER(0); } // Enforce big endian. else { MS_UNPACKHEADERBYTEORDER(1); } } else { MS_UNPACKHEADERBYTEORDER(-1); } // Read all records and save them in a linked list. while (offset < buflen) { msr = msr_init(NULL); if ( msr == NULL ) { ms_log (2, "readMSEEDBuffer(): Error initializing msr\n"); return NULL; } if (verbose > 1) { ms_log(0, "readMSEEDBuffer(): calling msr_parse with " "mseed+offset=%d+%d, buflen=%d, reclen=%d, dataflag=%d, verbose=%d\n", mseed, offset, buflen, reclen, dataflag, verbose); } // If the record length is given, make sure at least that amount of data is available. if (reclen != -1) { if (offset + reclen > buflen) { ms_log(1, "readMSEEDBuffer(): Last reclen exceeds buflen, skipping.\n"); msr_free(&msr); break; } } // Otherwise assume the smallest possible record length and assure that enough // data is present. else { if (offset + MINRECLEN > buflen) { ms_log(1, "readMSEEDBuffer(): Last record only has %i byte(s) which " "is not enough to constitute a full SEED record. Corrupt data? " "Record will be skipped.\n", buflen - offset); msr_free(&msr); break; } } // Skip empty or noise records. if (OBSPY_ISVALIDBLANK(mseed + offset)) { offset += MINRECLEN; continue; } // Pass (buflen - offset) because msr_parse() expects only a single record. This // way libmseed can take care to not overstep bounds. // Return values: // 0 : Success, populates the supplied MSRecord. // >0 : Data record detected but not enough data is present, the // return value is a hint of how many more bytes are needed. // <0 : libmseed error code (listed in libmseed.h) is returned. retcode = msr_parse ((mseed+offset), buflen - offset, &msr, reclen, dataflag, verbose); // Handle error. if (retcode < 0) { log_error(retcode, offset); msr_free(&msr); break; } // msr_parse() returns > 0 if a data record has been detected but the buffer either has not enough // data (this cannot happen with ObsPy's logic) or the last record has no Blockette 1000 and it cannot // determine the record length because there is no next record (this can happen in ObsPy) - handle that // case by just calling msr_parse() with an explicit record length set. else if ( retcode > 0 && retcode < (buflen - offset)) { // Check if the remaining bytes can exactly make up a record length. int r_bytes = buflen - offset; float exp = log10((float)r_bytes) / log10(2.0); if ((fmodf(exp, 1.0) < 0.0000001) && ((int)roundf_(exp) >= 7) && ((int)roundf_(exp) <= 256)) { retcode = msr_parse((mseed + offset), buflen - offset, &msr, r_bytes, dataflag, verbose); if ( retcode != 0 ) { log_error(retcode, offset); msr_free(&msr); break; } } else { msr_free(&msr); break; } } if (offset + msr->reclen > buflen) { ms_log(1, "readMSEEDBuffer(): Last msr->reclen exceeds buflen, skipping.\n"); msr_free(&msr); break; } // Test against selections if supplied if ( selections ) { char srcname[50]; hptime_t endtime; msr_srcname (msr, srcname, 1); endtime = msr_endtime (msr); if ( ms_matchselect (selections, srcname, msr->starttime, endtime, NULL) == NULL ) { // Add the record length for the next iteration offset += msr->reclen; // Free record. msr_free(&msr); continue; } } record_count += 1; recordCurrent = lrl_init (); // Append to linked record list if one exists. if ( recordHead != NULL ) { recordPrevious->next = recordCurrent; recordCurrent->previous = recordPrevious; recordCurrent->next = NULL; recordPrevious = recordCurrent; } // Otherwise create a new one. else { recordHead = recordCurrent; recordCurrent->previous = NULL; recordPrevious = recordCurrent; } recordCurrent->record = msr; // Figure out if the byte-order of the data has to be swapped. swapflag = 0; // If blockette 1000 is present, use it. if ( msr->Blkt1000 != 0) { /* If BE host and LE data need swapping */ if ( bigendianhost && msr->byteorder == 0 ) { swapflag = 1; } /* If LE host and BE data (or bad byte order value) need swapping */ if ( !bigendianhost && msr->byteorder > 0 ) { swapflag = 1; } } // Otherwise assume the data has the same byte order as the header. // This needs to be done on the raw header bytes as libmseed only returns // header fields in the native byte order. else { unsigned char* _t = (unsigned char*)mseed + offset + 20; unsigned int year = _t[0] | _t[1] << 8; unsigned int day = _t[2] | _t[3] << 8; // Swap data if header needs to be swapped. if (!MS_ISVALIDYEARDAY(year, day)) { swapflag = 1; } } // Actually unpack the data if the flag is not set and if the data // offset is valid. if ((unpack_data != 0) && (msr->fsdh->data_offset >= 48) && (msr->fsdh->data_offset < msr->reclen) && (msr->samplecnt > 0)) { retval = msr_unpack_data (msr, swapflag, verbose); } if ( retval > 0 ) { msr->numsamples = retval; } if ( msr->fsdh->start_time.fract > 9999 ) { ms_log(1, "readMSEEDBuffer(): Record with offset=%d has a " "fractional second (.0001 seconds) of %d. This is not " "strictly valid but will be interpreted as one or more " "additional seconds.", offset, msr->fsdh->start_time.fract); } // Add the record length for the next iteration offset += msr->reclen; } // Return empty id list if no records could be found. if (record_count == 0) { idListHead = lil_init(); return idListHead; } // All records that match the selection are now stored in a LinkedRecordList // that starts at recordHead. The next step is to sort them by matching ids // and then by time. recordCurrent = recordHead; while (recordCurrent != NULL) { // Check if the ID of the record is already available and if not create a // new one. // Start with the last id as it is most likely to be the correct one. idListCurrent = idListLast; while (idListCurrent != NULL) { if (strcmp(idListCurrent->network, recordCurrent->record->network) == 0 && strcmp(idListCurrent->station, recordCurrent->record->station) == 0 && strcmp(idListCurrent->location, recordCurrent->record->location) == 0 && strcmp(idListCurrent->channel, recordCurrent->record->channel) == 0 && idListCurrent->dataquality == recordCurrent->record->dataquality) { break; } else { idListCurrent = idListCurrent->previous; } } // Create a new id list if one is needed. if (idListCurrent == NULL) { idListCurrent = lil_init(); idListCurrent->previous = idListLast; if (idListLast != NULL) { idListLast->next = idListCurrent; } idListLast = idListCurrent; if (idListHead == NULL) { idListHead = idListCurrent; } // Set the IdList attributes. strcpy(idListCurrent->network, recordCurrent->record->network); strcpy(idListCurrent->station, recordCurrent->record->station); strcpy(idListCurrent->location, recordCurrent->record->location); strcpy(idListCurrent->channel, recordCurrent->record->channel); idListCurrent->dataquality = recordCurrent->record->dataquality; } // Now check if the current record fits exactly to the end of the last // segment of the current id. If not create a new segment. Therefore // if records with the same id are in wrong order a new segment will be // created. This is on purpose. segmentCurrent = idListCurrent->lastSegment; if (segmentCurrent != NULL) { hptimetol = (hptime_t) (0.5 * segmentCurrent->hpdelta); nhptimetol = ( hptimetol ) ? -hptimetol : 0; lastgap = recordCurrent->record->starttime - segmentCurrent->endtime - segmentCurrent->hpdelta; } if (details == 1) { /* extract information on calibration BLKs */ calibration_type = -1; if (recordCurrent->record->blkts) { BlktLink *cur_blkt = recordCurrent->record->blkts; while (cur_blkt) { switch (cur_blkt->blkt_type) { case 300: calibration_type = 1; break; case 310: calibration_type = 2; break; case 320: calibration_type = 3; break; case 390: calibration_type = 4; break; case 395: calibration_type = -2; break; default: break; } cur_blkt = cur_blkt->next; } } /* extract information based on timing quality */ timing_qual = 0xFF; if (recordCurrent->record->Blkt1001 != 0) { timing_qual = recordCurrent->record->Blkt1001->timing_qual; } } if ( segmentCurrent != NULL && // This is important for zero data record coupled with not unpacking // the data. It needs to be split in two places: Before the zero data // record and after it. recordCurrent->record->samplecnt > 0 && segmentCurrent->samplecnt > 0 && segmentCurrent->sampletype == recordCurrent->record->sampletype && // Test the default sample rate tolerance: abs(1-sr1/sr2) < 0.0001 MS_ISRATETOLERABLE (segmentCurrent->samprate, recordCurrent->record->samprate) && // Check if the times are within the time tolerance lastgap <= hptimetol && lastgap >= nhptimetol && segmentCurrent->timing_qual == timing_qual && segmentCurrent->calibration_type == calibration_type) { recordCurrent->previous = segmentCurrent->lastRecord; segmentCurrent->lastRecord = segmentCurrent->lastRecord->next = recordCurrent; segmentCurrent->samplecnt += recordCurrent->record->samplecnt; segmentCurrent->endtime = msr_endtime(recordCurrent->record); } // Otherwise create a new segment and add the current record. else { segmentCurrent = seg_init(); segmentCurrent->previous = idListCurrent->lastSegment; if (idListCurrent->lastSegment != NULL) { idListCurrent->lastSegment->next = segmentCurrent; } else { idListCurrent->firstSegment = segmentCurrent; } idListCurrent->lastSegment = segmentCurrent; segmentCurrent->starttime = recordCurrent->record->starttime; segmentCurrent->endtime = msr_endtime(recordCurrent->record); segmentCurrent->samprate = recordCurrent->record->samprate; segmentCurrent->sampletype = recordCurrent->record->sampletype; segmentCurrent->samplecnt = recordCurrent->record->samplecnt; // Calculate high-precision sample period segmentCurrent->hpdelta = (hptime_t) (( recordCurrent->record->samprate ) ? (HPTMODULUS / recordCurrent->record->samprate) : 0.0); segmentCurrent->timing_qual = timing_qual; segmentCurrent->calibration_type = calibration_type; segmentCurrent->firstRecord = segmentCurrent->lastRecord = recordCurrent; recordCurrent->previous = NULL; } recordPrevious = recordCurrent->next; recordCurrent->next = NULL; recordCurrent = recordPrevious; } // Now loop over all segments, combine the records and free the msr // structures. idListCurrent = idListHead; while (idListCurrent != NULL) { segmentCurrent = idListCurrent->firstSegment; while (segmentCurrent != NULL) { if (segmentCurrent->datasamples) { free(segmentCurrent->datasamples); } // Allocate data via a callback function. if (unpack_data != 0) { segmentCurrent->datasamples = (void *) allocData(segmentCurrent->samplecnt, segmentCurrent->sampletype); } // Loop over all records, write the data to the buffer and free the msr structures. recordCurrent = segmentCurrent->firstRecord; data_offset = (long long)(segmentCurrent->datasamples); while (recordCurrent != NULL) { datasize = recordCurrent->record->samplecnt * ms_samplesize(recordCurrent->record->sampletype); memcpy((void *)data_offset, recordCurrent->record->datasamples, datasize); // Free the record. msr_free(&(recordCurrent->record)); // Increase the data_offset and the record. data_offset += (long long)datasize; recordCurrent = recordCurrent->next; } segmentCurrent = segmentCurrent->next; } idListCurrent = idListCurrent->next; } return idListHead; }
// Function that reads from a MiniSEED binary file from a char buffer and // returns a LinkedIDList. LinkedIDList * readMSEEDBuffer (char *mseed, int buflen, Selections *selections, flag unpack_data, int reclen, flag verbose, flag details, long (*allocData) (int, char)) { int retcode = 0; int retval = 0; flag swapflag = 0; // current offset of mseed char pointer int offset = 0; // Unpack without reading the data first flag dataflag = 0; // the timing_qual of BLK 1001 uint8_t timing_qual = 0xFF; // the calibration type, availability of BLK 300, 310, 320, 390, 395 int8_t calibration_type = -1; // Init all the pointers to NULL. Most compilers should do this anyway. LinkedIDList * idListHead = NULL; LinkedIDList * idListCurrent = NULL; LinkedIDList * idListLast = NULL; MSRecord *msr = NULL; ContinuousSegment * segmentCurrent = NULL; hptime_t lastgap; hptime_t hptimetol; hptime_t nhptimetol; long data_offset; LinkedRecordList *recordHead = NULL; LinkedRecordList *recordPrevious = NULL; LinkedRecordList *recordCurrent = NULL; int datasize; // // Read all records and save them in a linked list. // int record_count = 0; while (offset < buflen) { msr = msr_init(NULL); retcode = msr_parse ( (mseed+offset), buflen, &msr, reclen, dataflag, verbose); if ( ! (retcode == MS_NOERROR)) { msr_free(&msr); break; } // Test against selections if supplied if ( selections ) { char srcname[50]; hptime_t endtime; msr_srcname (msr, srcname, 1); endtime = msr_endtime (msr); if ( ms_matchselect (selections, srcname, msr->starttime, endtime, NULL) == NULL ) { // Add the record length for the next iteration offset += msr->reclen; // Free record. msr_free(&msr); continue; } } record_count += 1; recordCurrent = lrl_init (); // Append to linked record list if one exists. if ( recordHead != NULL ) { recordPrevious->next = recordCurrent; recordCurrent->previous = recordPrevious; recordCurrent->next = NULL; recordPrevious = recordCurrent; } // Otherwise create a new one. else { recordHead = recordCurrent; recordCurrent->previous = NULL; recordPrevious = recordCurrent; } recordCurrent->record = msr; // Determine the byteorder swapflag only for the very first record. The byteorder // should not change within the file. // XXX: Maybe check for every record? if (swapflag <= 0) { // Returns 0 if the host is little endian, otherwise 1. flag bigendianhost = ms_bigendianhost(); // Set the swapbyteflag if it is needed. if ( msr->Blkt1000 != 0) { /* If BE host and LE data need swapping */ if ( bigendianhost && msr->byteorder == 0 ) { swapflag = 1; } /* If LE host and BE data (or bad byte order value) need swapping */ if ( !bigendianhost && msr->byteorder > 0 ) { swapflag = 1; } } } // Actually unpack the data if the flag is not set. if (unpack_data != 0) { retval = msr_unpack_data (msr, swapflag, verbose); } if ( retval > 0 ) { msr->numsamples = retval; } // Add the record length for the next iteration offset += msr->reclen; } // Return empty id list if no records could be found. if (record_count == 0) { idListHead = lil_init(); return idListHead; } // All records that match the selection are now stored in a LinkedRecordList // that starts at recordHead. The next step is to sort them by matching ids // and then by time. recordCurrent = recordHead; while (recordCurrent != NULL) { // Check if the ID of the record is already available and if not create a // new one. // Start with the last id as it is most likely to be the correct one. idListCurrent = idListLast; while (idListCurrent != NULL) { if (strcmp(idListCurrent->network, recordCurrent->record->network) == 0 && strcmp(idListCurrent->station, recordCurrent->record->station) == 0 && strcmp(idListCurrent->location, recordCurrent->record->location) == 0 && strcmp(idListCurrent->channel, recordCurrent->record->channel) == 0 && idListCurrent->dataquality == recordCurrent->record->dataquality) { break; } else { idListCurrent = idListCurrent->previous; } } // Create a new id list if one is needed. if (idListCurrent == NULL) { idListCurrent = lil_init(); idListCurrent->previous = idListLast; if (idListLast != NULL) { idListLast->next = idListCurrent; } idListLast = idListCurrent; if (idListHead == NULL) { idListHead = idListCurrent; } // Set the IdList attributes. strcpy(idListCurrent->network, recordCurrent->record->network); strcpy(idListCurrent->station, recordCurrent->record->station); strcpy(idListCurrent->location, recordCurrent->record->location); strcpy(idListCurrent->channel, recordCurrent->record->channel); idListCurrent->dataquality = recordCurrent->record->dataquality; } // Now check if the current record fits exactly to the end of the last // segment of the current id. If not create a new segment. Therefore // if records with the same id are in wrong order a new segment will be // created. This is on purpose. segmentCurrent = idListCurrent->lastSegment; if (segmentCurrent != NULL) { hptimetol = (hptime_t) (0.5 * segmentCurrent->hpdelta); nhptimetol = ( hptimetol ) ? -hptimetol : 0; lastgap = recordCurrent->record->starttime - segmentCurrent->endtime - segmentCurrent->hpdelta; } if (details == 1) { /* extract information on calibration BLKs */ calibration_type = -1; if (recordCurrent->record->blkts) { BlktLink *cur_blkt = recordCurrent->record->blkts; while (cur_blkt) { switch (cur_blkt->blkt_type) { case 300: calibration_type = 1; break; case 310: calibration_type = 2; break; case 320: calibration_type = 3; break; case 390: calibration_type = 4; break; case 395: calibration_type = -2; break; default: break; } cur_blkt = cur_blkt->next; } } /* extract information based on timing quality */ timing_qual = 0xFF; if (recordCurrent->record->Blkt1001 != 0) { timing_qual = recordCurrent->record->Blkt1001->timing_qual; } } if ( segmentCurrent != NULL && segmentCurrent->sampletype == recordCurrent->record->sampletype && // Test the default sample rate tolerance: abs(1-sr1/sr2) < 0.0001 MS_ISRATETOLERABLE (segmentCurrent->samprate, recordCurrent->record->samprate) && // Check if the times are within the time tolerance lastgap <= hptimetol && lastgap >= nhptimetol && segmentCurrent->timing_qual == timing_qual && segmentCurrent->calibration_type == calibration_type) { recordCurrent->previous = segmentCurrent->lastRecord; segmentCurrent->lastRecord = segmentCurrent->lastRecord->next = recordCurrent; segmentCurrent->samplecnt += recordCurrent->record->samplecnt; segmentCurrent->endtime = msr_endtime(recordCurrent->record); } // Otherwise create a new segment and add the current record. else { segmentCurrent = seg_init(); segmentCurrent->previous = idListCurrent->lastSegment; if (idListCurrent->lastSegment != NULL) { idListCurrent->lastSegment->next = segmentCurrent; } else { idListCurrent->firstSegment = segmentCurrent; } idListCurrent->lastSegment = segmentCurrent; segmentCurrent->starttime = recordCurrent->record->starttime; segmentCurrent->endtime = msr_endtime(recordCurrent->record); segmentCurrent->samprate = recordCurrent->record->samprate; segmentCurrent->sampletype = recordCurrent->record->sampletype; segmentCurrent->samplecnt = recordCurrent->record->samplecnt; // Calculate high-precision sample period segmentCurrent->hpdelta = (hptime_t) (( recordCurrent->record->samprate ) ? (HPTMODULUS / recordCurrent->record->samprate) : 0.0); segmentCurrent->timing_qual = timing_qual; segmentCurrent->calibration_type = calibration_type; segmentCurrent->firstRecord = segmentCurrent->lastRecord = recordCurrent; recordCurrent->previous = NULL; } recordPrevious = recordCurrent->next; recordCurrent->next = NULL; recordCurrent = recordPrevious; } // Now loop over all segments, combine the records and free the msr // structures. idListCurrent = idListHead; while (idListCurrent != NULL) { segmentCurrent = idListCurrent->firstSegment; while (segmentCurrent != NULL) { if (segmentCurrent->datasamples) { free(segmentCurrent->datasamples); } // Allocate data via a callback function. if (unpack_data != 0) { segmentCurrent->datasamples = (void *) allocData(segmentCurrent->samplecnt, segmentCurrent->sampletype); } // Loop over all records, write the data to the buffer and free the msr structures. recordCurrent = segmentCurrent->firstRecord; data_offset = (long)(segmentCurrent->datasamples); while (recordCurrent != NULL) { datasize = recordCurrent->record->samplecnt * ms_samplesize(recordCurrent->record->sampletype); memcpy((void *)data_offset, recordCurrent->record->datasamples, datasize); // Free the record. msr_free(&(recordCurrent->record)); // Increase the data_offset and the record. data_offset += (long)datasize; recordCurrent = recordCurrent->next; } segmentCurrent = segmentCurrent->next; } idListCurrent = idListCurrent->next; } return idListHead; }
/*************************************************************************** * msr_duplicate: * * Duplicate an MSRecord struct * including the fixed-section data * header and blockette chain. If * the datadup flag is true and the * source MSRecord has associated * data samples copy them as well. * * Returns a pointer to a new MSRecord on success and NULL on error. ***************************************************************************/ MSRecord * msr_duplicate (MSRecord *msr, flag datadup) { MSRecord *dupmsr = 0; int samplesize = 0; if ( ! msr ) return NULL; /* Allocate target MSRecord structure */ if ( (dupmsr = msr_init (NULL)) == NULL ) return NULL; /* Copy MSRecord structure */ memcpy (dupmsr, msr, sizeof(MSRecord)); /* Copy fixed-section data header structure */ if ( msr->fsdh ) { /* Allocate memory for new FSDH structure */ if ( (dupmsr->fsdh = (struct fsdh_s *) malloc (sizeof(struct fsdh_s))) == NULL ) { ms_log (2, "msr_duplicate(): Error allocating memory\n"); free (dupmsr); return NULL; } /* Copy the contents */ memcpy (dupmsr->fsdh, msr->fsdh, sizeof(struct fsdh_s)); } /* Copy the blockette chain */ if ( msr->blkts ) { BlktLink *blkt = msr->blkts; BlktLink *next = NULL; dupmsr->blkts = 0; while ( blkt ) { next = blkt->next; /* Add blockette to chain of new MSRecord */ if ( msr_addblockette (dupmsr, blkt->blktdata, blkt->blktdatalen, blkt->blkt_type, 0) == NULL ) { ms_log (2, "msr_duplicate(): Error adding blockettes\n"); msr_free (&dupmsr); return NULL; } blkt = next; } } /* Copy data samples if requested and available */ if ( datadup && msr->datasamples ) { /* Determine size of samples in bytes */ samplesize = ms_samplesize (msr->sampletype); if ( samplesize == 0 ) { ms_log (2, "msr_duplicate(): unrecognized sample type: '%c'\n", msr->sampletype); free (dupmsr); return NULL; } /* Allocate memory for new data array */ if ( (dupmsr->datasamples = (void *) malloc ((size_t)(msr->numsamples * samplesize))) == NULL ) { ms_log (2, "msr_duplicate(): Error allocating memory\n"); free (dupmsr); return NULL; } /* Copy the data array */ memcpy (dupmsr->datasamples, msr->datasamples, ((size_t)(msr->numsamples * samplesize))); } /* Otherwise make sure the sample array and count are zero */ else { dupmsr->datasamples = 0; dupmsr->numsamples = 0; } return dupmsr; } /* End of msr_duplicate() */