From 26c198fd789aa058c84f1b2229e93aedd6a422ea Mon Sep 17 00:00:00 2001 From: Shakeeb Date: Fri, 26 Aug 2016 04:54:37 -0500 Subject: SBE code restructure: Set up tools directory Change-Id: I2ad810c3310a7b2ae0a1e1a57b3bd04ef7e9f256 RTC:159709 Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/28836 Tested-by: Jenkins Server Tested-by: FSP CI Jenkins Reviewed-by: RAJA DAS Reviewed-by: Sachin Gupta --- sbe/tools/ppetracepp/ppe2fsp.c | 532 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 532 insertions(+) create mode 100755 sbe/tools/ppetracepp/ppe2fsp.c (limited to 'sbe/tools/ppetracepp/ppe2fsp.c') diff --git a/sbe/tools/ppetracepp/ppe2fsp.c b/sbe/tools/ppetracepp/ppe2fsp.c new file mode 100755 index 00000000..469ceced --- /dev/null +++ b/sbe/tools/ppetracepp/ppe2fsp.c @@ -0,0 +1,532 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: sbe/tools/ppetracepp/ppe2fsp.c $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#include "pk_trace.h" +#include "ppe2fsp.h" +#include "trac_interface.h" +#include +#include +#include + +#define TRACE_BUF_VERSION 0x01 /*!< Trace buffer version */ +#define TRACE_FIELDTRACE 0x4654 /*!< Field Trace - "FT" */ +#define TRACE_FIELDBIN 0x4644 /*!< Binary Field Trace - "FD" */ + +#define TRAC_TIME_REAL 0 // upper 32 = seconds, lower 32 = nanoseconds +#define TRAC_TIME_50MHZ 1 +#define TRAC_TIME_200MHZ 2 +#define TRAC_TIME_167MHZ 3 // 166666667Hz + +typedef struct +{ + trace_entry_stamp_t stamp; + trace_entry_head_t head; + union + { + uint8_t data[PK_TRACE_MAX_BINARY + 1]; //add 1 byte for padding + uint32_t parms[PK_TRACE_MAX_PARMS]; + }; + uint32_t size; +}largest_fsp_entry_t; + +typedef struct +{ + union + { + uint8_t binary_data[PK_TRACE_MAX_BINARY + 1]; + struct + { + uint8_t rsvd[(PK_TRACE_MAX_BINARY + 1) - (PK_TRACE_MAX_PARMS * sizeof(uint32_t))]; + uint32_t parms[PK_TRACE_MAX_PARMS]; + }; + }; + PkTraceEntryFooter footer; +}LargestPpeEntry; + +//convert a ppe timestamp to an fsp trace timestamp +uint64_t ppe2fsp_time(uint64_t ppe_time, uint32_t hz) +{ + uint32_t seconds; + uint32_t remainder; + uint32_t nseconds; + + //convert from ppe ticks to seconds and nanoseconds + seconds = ppe_time / hz; + remainder = ppe_time - (((uint64_t)seconds) * hz); + nseconds = (((uint64_t)remainder) * 1000000000) / hz; + return (((uint64_t)seconds) << 32) | nseconds; +} + +//Writes an fsp trace entry to the fsp trace buffer +void fsp_put_entry(trace_buf_head_t* tb, largest_fsp_entry_t* fte, size_t entry_size, uint32_t bytes_left) +{ + char* buffer = ((char*)tb) + sizeof(trace_buf_head_t); + char* tb_start; + char* fte_start; + uint32_t copy_bytes; + + if(entry_size <= bytes_left) + { + tb_start = buffer + bytes_left - entry_size; + fte_start = (char*)fte; + copy_bytes = entry_size; + } + else + { + tb_start = buffer; + fte_start = ((char*)fte) + (entry_size - bytes_left); + copy_bytes = bytes_left; + } + + memcpy(tb_start, fte_start, copy_bytes); +} + + +//convert a ppe trace entry to an fsp trace entry +size_t pte2fte(PkTraceBuffer* ptb, + LargestPpeEntry* pte, + size_t pte_size, + largest_fsp_entry_t* fte, + uint64_t ppe_time64) +{ + size_t entry_size; + PkTraceGeneric* pte_footer = &pte->footer.generic; + uint32_t format; + uint32_t hash32; + uint32_t hash32_partial; + uint32_t* parm_start; + uint32_t parm_bytes; + uint64_t fsp_time64; + + //convert the ppe trace time to an fsp trace time + fsp_time64 = ppe2fsp_time(ppe_time64, ntohl(ptb->hz)); + + //fill in the 64 bit timestamp + fte->stamp.tbh = htonl((uint32_t)(fsp_time64 >> 32)); + fte->stamp.tbl = htonl((uint32_t)(fsp_time64 & 0x00000000ffffffffull)); + + //use the ppe instance id as the thread id. + fte->stamp.tid = htonl((uint32_t)ntohs(ptb->instance_id)); + + //merge the hash prefix and the string_id fields together for a 32 bit hash value + hash32 = ((uint32_t)ntohs(ptb->hash_prefix)) << 16; + hash32 |= pte_footer->string_id; + fte->head.hash = htonl(hash32); + + //generate the 32bit hash value for a partial trace entry in case it's needed + hash32_partial = ((uint32_t)ntohs(ptb->hash_prefix)) << 16; + hash32_partial |= ntohs(ptb->partial_trace_hash); + + //set the line number to 1 + fte->head.line = htonl(1); + + //determine the FSP trace format + format = PK_GET_TRACE_FORMAT(pte_footer->time_format.word32); + if(format == PK_TRACE_FORMAT_BINARY) + { + fte->head.tag = htons(TRACE_FIELDBIN); + } + else + { + fte->head.tag = htons(TRACE_FIELDTRACE); + } + + parm_start = (uint32_t*)(((char*)pte) + (sizeof(LargestPpeEntry) - pte_size)); + + //fill in the parameters/binary data and size at the end + switch(format) + { + + case PK_TRACE_FORMAT_TINY: + //one or 0 parameters + entry_size = sizeof(trace_entry_stamp_t) + + sizeof(trace_entry_head_t) + + sizeof(uint32_t); + fte->parms[0] = htonl((uint32_t)(pte_footer->parm16)); + fte->head.length = htons(sizeof(uint32_t)); + parm_bytes = 0; + break; + + case PK_TRACE_FORMAT_BIG: + //1 - 4 parameters + // + //If the trace entry data is incomplete (not all parm data + //had been written at the time the trace was captured) then + //we will write a trace to the fsp buffer that says + //"PARTIAL TRACE ENTRY. HASH_ID = %d" + if(pte_footer->complete) + { + parm_bytes = pte_footer->bytes_or_parms_count * sizeof(uint32_t); + fte->head.length = htons(parm_bytes + sizeof(uint32_t)); + entry_size = sizeof(trace_entry_stamp_t) + + sizeof(trace_entry_head_t) + + parm_bytes + sizeof(uint32_t); + } + else + { + parm_bytes = 0; + entry_size = sizeof(trace_entry_stamp_t) + + sizeof(trace_entry_head_t) + + sizeof(uint32_t); + fte->parms[0] = fte->head.hash; //already corrected for endianess + fte->head.hash = htonl(hash32_partial); + fte->head.length = htons(sizeof(uint32_t)); + } + break; + + case PK_TRACE_FORMAT_BINARY: + //If the trace entry data is incomplete (not all parm data + //had been written at the time the trace was captured) then + //we will write a trace to the fsp buffer that says + //"PARTIAL TRACE ENTRY. HASH_ID = %d" + if(pte_footer->complete) + { + parm_bytes = pte_footer->bytes_or_parms_count; + fte->head.length = htons((uint16_t)parm_bytes); + entry_size = sizeof(trace_entry_stamp_t) + + sizeof(trace_entry_head_t) + + parm_bytes; + + //pad to 4 byte boundary + entry_size = (entry_size + 3) & ~3; + } + else + { + parm_bytes = 0; + entry_size = sizeof(trace_entry_stamp_t) + + sizeof(trace_entry_head_t) + + sizeof(uint32_t); + fte->parms[0] = fte->head.hash; + fte->head.hash = htonl(hash32_partial); + fte->head.length = htons(sizeof(uint32_t)); + fte->head.tag = htons(TRACE_FIELDTRACE); + } + break; + + + default: + entry_size = 0; + parm_bytes = 0; + break; + } + + //copy parameter bytes to the fsp entry if necessary + if(parm_bytes) + { + memcpy(fte->data, parm_start, parm_bytes); + } + + //add the entry size to the end + if(entry_size) + { + uint32_t new_entry_size = entry_size + sizeof(uint32_t); + *((uint32_t*)(((char*)fte) + entry_size)) = htonl(new_entry_size); + entry_size = new_entry_size; + } + + return entry_size; +} + +//retrieve a ppe trace entry from a ppe trace buffer +size_t ppe_get_entry(PkTraceBuffer* tb, uint32_t offset, LargestPpeEntry* pte) +{ + uint32_t mask = ntohs(tb->size) - 1; + PkTraceEntryFooter* footer; + size_t entry_size; + size_t parm_size; + char* dest = (char*)pte; + uint32_t format; + uint32_t start_index; + uint32_t bytes_left; + uint32_t bytes_to_copy; + + //Find the footer in the circular buffer + footer = (PkTraceEntryFooter*)(&tb->cb[(offset - sizeof(PkTraceEntryFooter)) & mask]); + + //always correct endianess for the time and string id words + pte->footer.generic.time_format.word32 = ntohl(footer->generic.time_format.word32); + pte->footer.generic.string_id = ntohs(footer->generic.string_id); + + //only need to byte swap the parm16 value if this is a tiny format + pte->footer.generic.parm16 = footer->generic.parm16; + + //use footer data to determine the length of the binary data or parameters + format = PK_GET_TRACE_FORMAT(pte->footer.generic.time_format.word32); + switch(format) + { + case PK_TRACE_FORMAT_TINY: + pte->footer.generic.parm16 = ntohs(pte->footer.generic.parm16); + parm_size = 0; + entry_size = sizeof(PkTraceEntryFooter); + break; + + case PK_TRACE_FORMAT_BIG: + parm_size = pte->footer.generic.bytes_or_parms_count * sizeof(uint32_t); + entry_size = sizeof(PkTraceEntryFooter); + break; + + case PK_TRACE_FORMAT_BINARY: + parm_size = pte->footer.generic.bytes_or_parms_count; + entry_size = sizeof(PkTraceEntryFooter); + break; + + default: + entry_size = 0; + parm_size = 0; + break; + } + + //pad to 8 byte boundary + parm_size = (parm_size + 7) & ~0x00000007ul; + + //add the parameter size to the total entry size + entry_size += parm_size; + + //copy the entry from the circular buffer to pte + start_index = (offset - entry_size) & mask; + bytes_left = ntohs(tb->size) - start_index; + + //only copy up to the end of the circular buffer + if(parm_size < bytes_left) + { + bytes_to_copy = parm_size; + } + else + { + bytes_to_copy = bytes_left; + } + + dest += sizeof(LargestPpeEntry) - entry_size; + memcpy(dest, &tb->cb[start_index], bytes_to_copy); + + //now copy the rest of the data starting from the beginning of the + //circular buffer. + if(bytes_to_copy < parm_size) + { + memcpy(dest + bytes_to_copy, tb->cb, parm_size - bytes_to_copy); + } + + //return the size of the entry + return entry_size; +} + +//convert a ppe trace buffer to an fsp trace buffer +int ppe2fsp(void* in, size_t in_size, void* out, size_t* io_size) +{ + PkTraceBuffer* ptb = (PkTraceBuffer*)in; + trace_buf_head_t* ftb = (trace_buf_head_t*)out; + uint32_t ppe_bytes_left; + uint32_t fsp_bytes_left; + int rc = 0; + uint32_t ptb_offset; + uint64_t ppe_time64; + uint32_t fte_size, pte_size; + uint32_t fsp_te_count = 0; + uint32_t time_diff32, prev_time32, new_time32; + PkTraceGeneric* pte_footer; + largest_fsp_entry_t fte; + LargestPpeEntry pte; + uint64_t time_adj64; + + do + { + if(!ptb || !ftb || !io_size) + { + rc = P2F_NULL_POINTER; + break; + } + + if(ntohs(ptb->version) != PK_TRACE_VERSION) + { + rc = P2F_INVALID_VERSION; + break; + } + + //check that the input buffer is large enough to have a ppe trace buffer + if(in_size < (((uintptr_t)(&ptb->cb[0])) - (uintptr_t)(ptb))) + { + rc = P2F_INPUT_BUFFER_TOO_SMALL; + break; + } + + //initialize some locals + fsp_bytes_left = *io_size - sizeof(trace_buf_head_t); + ppe_bytes_left = ntohs(ptb->size); + ptb_offset = ntohl(ptb->state.offset); + if(htonl(1) == 1) + { + time_adj64 = ptb->time_adj64; + } + else + { + time_adj64 = ntohl((uint32_t)(ptb->time_adj64 >> 32)); + time_adj64 |= ((uint64_t)(ntohl((uint32_t)(ptb->time_adj64 & 0x00000000ffffffff)))) << 32; + } + + //make sure the ppe buffer size is a power of two + if((ppe_bytes_left - 1) & ppe_bytes_left) + { + //size is not a power of two + rc = P2F_INVALID_INPUT_SIZE; + break; + } + + //The ppe bytes field should always be a multiple of 8 + if(ptb_offset & 0x7) + { + rc = P2F_INVALID_PPE_OFFSET; + break; + } + + //make sure there is enough room for the fsp header + if(*io_size < sizeof(trace_buf_head_t)) + { + rc = P2F_OUTPUT_BUFFER_TOO_SMALL; + break; + } + + + //initialize the fsp header + ftb->ver = TRACE_BUF_VERSION; + ftb->hdr_len = sizeof(trace_buf_head_t); + ftb->time_flg = TRAC_TIME_REAL; + ftb->endian_flg = 'B'; //big endian + memcpy(ftb->comp, ptb->image_str, sizeof(ftb->comp)); + ftb->times_wrap = htonl(1); + ftb->size = htonl(sizeof(trace_buf_head_t) + sizeof(uint32_t)); + ftb->next_free = htonl(sizeof(trace_buf_head_t)); + ftb->extracted = htonl(0); + ftb->te_count = htonl(0); + + //find the latest timestamp so that we can work back from there + ppe_time64 = ((uint64_t)(ntohl(ptb->state.tbu32) & 0xefffffff)) << 32; + pte_size = ppe_get_entry(ptb, ptb_offset, &pte); + prev_time32 = PK_GET_TRACE_TIME(pte.footer.generic.time_format.word32); + ppe_time64 |= prev_time32; + + //process all of the input bytes one trace entry at a time + //from newest to oldest (backwards) until we run out of input bytes or + //we run out of output space. + while(1) + { + //check if we have enough data for a ppe footer + if(ppe_bytes_left < sizeof(PkTraceEntryFooter)) + { + break; + } + + //get the next ppe entry + pte_size = ppe_get_entry(ptb, ptb_offset, &pte); + + //Stop if there are no more entries to retrieve from the ppe trace buffer + if(!pte_size) + { + break; + } + pte_footer = &pte.footer.generic; + + //mark the entry as incomplete if we didn't have enough data + //for the entire entry + if(pte_size > ppe_bytes_left) + { + pte_footer->complete = 0; + ppe_bytes_left = 0; + } + else + { + ppe_bytes_left -= pte_size; + ptb_offset -= pte_size; + } + + //Calculate the 64 bit timestamp for this entry.... + //On PPE, getting the timestamp is not done atomically with writing + //the entry to the buffer. This means that an entry with an older + //timestamp could possibly be added to the buffer after an entry + //with a newer timestamp. Detect this condition by checking if the + //time difference is bigger than the max difference. The max + //difference is enforced by the PPE having a trace added on a + //shorter time boundary (using a timer). + new_time32 = PK_GET_TRACE_TIME(pte_footer->time_format.word32); + time_diff32 = prev_time32 - new_time32; + + if(time_diff32 > ntohl(ptb->max_time_change)) + { + time_diff32 = new_time32 - prev_time32; + ppe_time64 += time_diff32; + } + else + { + ppe_time64 -= time_diff32; + } + + //save off the lower 32bit timestamp for the next iteration + prev_time32 = new_time32; + + //convert the ppe trace entry to an fsp trace entry + fte_size = pte2fte(ptb, &pte, pte_size, &fte, ppe_time64 + time_adj64); + + //fit as much of the entry into the fsp trace buffer as possible + fsp_put_entry(ftb, &fte, fte_size, fsp_bytes_left); + + //update the fsp trace entry count + fsp_te_count++; + + //stop if there is no more room left in the fsp trace buffer + if(fte_size >= fsp_bytes_left) + { + fsp_bytes_left = 0; + ftb->times_wrap = htonl(1); + break; + } + else + { + fsp_bytes_left -= fte_size; + } + }//while(1) + + + //shift the trace data up if there is space to do so + if(fsp_bytes_left) + { + char* dest = ((char*)ftb) + sizeof(trace_buf_head_t); + char* src = dest + fsp_bytes_left; + size_t data_size = *io_size - sizeof(trace_buf_head_t) - fsp_bytes_left; + memmove(dest, src, data_size); + } + + //update the fsp header to reflect the true size and entry count + ftb->te_count = htonl(fsp_te_count); + + //inform the caller of how many bytes were actually used + *io_size -= fsp_bytes_left; + + //shrink the size field to what we actually ended up using + ftb->size = htonl(*io_size); + + }while(0); + + return rc; +} + + + -- cgit v1.2.1