summaryrefslogtreecommitdiffstats
path: root/src/usr/errl
diff options
context:
space:
mode:
authorMatt Raybuck <mraybuc@us.ibm.com>2018-08-16 15:56:18 -0500
committerDaniel M. Crowell <dcrowell@us.ibm.com>2018-08-28 13:42:51 -0500
commit6a593d78b7c559ab77ab315b0534b253df2f3ace (patch)
treeb31e0da193d50fc806a062f686f9ff7d5a855bf4 /src/usr/errl
parentcc012e3efd4cf8b66b65e6c3e6731cdec870da18 (diff)
downloadblackbird-hostboot-6a593d78b7c559ab77ab315b0534b253df2f3ace.tar.gz
blackbird-hostboot-6a593d78b7c559ab77ab315b0534b253df2f3ace.zip
Combine trace buffers in errlog
Whenever ErrlEntry::collectTrace() was called it would create a new trace UD section each time. This led to duplicate entries in the errl. A new function was added to ErrlEntry to prune duplicates called removeDuplicateTraces(). Change-Id: I3685ecf1368dad421bca2d1b6b612e08755e25ce RTC: 118128 Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/64971 Reviewed-by: Roland Veloz <rveloz@us.ibm.com> Reviewed-by: ILYA SMIRNOV <ismirno@us.ibm.com> Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com> Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com> Reviewed-by: Nicholas E. Bofferding <bofferdn@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/errl')
-rw-r--r--src/usr/errl/errlentry.C235
-rw-r--r--src/usr/errl/test/errluserdetailtest.H183
2 files changed, 414 insertions, 4 deletions
diff --git a/src/usr/errl/errlentry.C b/src/usr/errl/errlentry.C
index d16ba7dab..b5df8a071 100644
--- a/src/usr/errl/errlentry.C
+++ b/src/usr/errl/errlentry.C
@@ -36,6 +36,7 @@
#include <stdlib.h>
#include <string.h>
#include <map>
+#include <algorithm>
#include <hbotcompid.H>
#include <errl/errlentry.H>
#include <errl/errlmanager.H>
@@ -47,6 +48,10 @@
#include <errl/errludattribute.H>
#include <errl/errludstate.H>
#include <trace/interface.H>
+
+#include "../trace/entry.H"
+#include <util/align.H>
+
#include <arch/ppc.H>
#include <hwas/common/hwasCallout.H>
#include <hwas/common/deconfigGard.H>
@@ -292,7 +297,7 @@ bool ErrlEntry::collectTrace(const char i_name[], const uint64_t i_max)
return l_rc;
}
-////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
void ErrlEntry::removeBackTrace()
{
@@ -1645,14 +1650,19 @@ uint64_t ErrlEntry::flatten( void * o_pBuffer,
}
} // for
+ // Before the trace UD sections are flattened, make sure there are no
+ // duplicates.
+ removeDuplicateTraces();
+
for(it = iv_SectionVector.begin();
- (it != iv_SectionVector.end()) && (l_flatSize != 0);
+ (it != iv_SectionVector.end()) && (l_flatSize != 0);
it++)
{
// If UD section is a trace.
if( (FIPS_ERRL_COMP_ID == (*it)->iv_header.iv_compId) &&
(FIPS_ERRL_UDT_HB_TRACE == (*it)->iv_header.iv_sst) )
{
+
l_cb = (*it)->flatten( pBuffer, l_sizeRemaining );
if( 0 == l_cb )
{
@@ -1794,6 +1804,227 @@ std::vector<void*> ErrlEntry::getUDSections(compId_t i_compId,
return copy_vector;
}
+
+void ErrlEntry::removeDuplicateTraces()
+{
+ // Define a custom comparator function for std::map.find()
+ struct mapComparator
+ {
+ bool operator()(const char* a, const char * b) const
+ {
+ return strcmp(a, b) < 0;
+ }
+ };
+
+ // map of component id and corresponding trace entries.
+ std::map<const char *, std::vector<TRACE::trace_bin_entry_t*>*,
+ mapComparator> traceUD_map;
+ auto it = traceUD_map.end();
+
+ uint64_t l_flatSize = flattenedSize();
+
+ // vector that will hold all of the trace UD sections
+ // that are free of duplicates.
+ std::vector<ErrlUD*> l_uniqueTraceUDVector;
+
+
+ // Iterate through iv_SectionVector and create a map of all unique
+ // component ids and their corresponding trace entries.
+ for(auto sectionVectorIt = iv_SectionVector.begin();
+ (sectionVectorIt != iv_SectionVector.end()) && (l_flatSize != 0);
+ ++sectionVectorIt)
+ {
+ // If UD section is a trace.
+ if( (FIPS_ERRL_COMP_ID == (*sectionVectorIt)->iv_header.iv_compId)
+ && (FIPS_ERRL_UDT_HB_TRACE == (*sectionVectorIt)->iv_header.iv_sst) )
+ {
+ char* l_data = static_cast<char*>((*sectionVectorIt)->data());
+
+ TRACE::trace_buf_head_t* l_trace_buf_head =
+ reinterpret_cast<TRACE::trace_buf_head_t*>(l_data);
+
+ // Look for the component id in the map to insert trace entries
+ // or insert a new component id into the map to insert trace entries
+ const char* l_compName = l_trace_buf_head->comp;
+
+ it = traceUD_map.find(l_compName);
+
+ if (traceUD_map.end() == it)
+ {
+ traceUD_map[l_compName] =
+ new std::vector<TRACE::trace_bin_entry_t*>;
+ it = traceUD_map.find(l_compName);
+ }
+
+ // Add all trace entries to map for the current component id.
+ l_data += l_trace_buf_head->hdr_len;
+
+ for (size_t traceCount = 0; traceCount < l_trace_buf_head->te_count;
+ traceCount++)
+ {
+ TRACE::trace_bin_entry_t* l_trace_entry =
+ reinterpret_cast<TRACE::trace_bin_entry_t*>(l_data);
+
+ it->second->push_back(l_trace_entry);
+
+ // fsp-trace entries have an extra 4 bytes at the end of them
+ // hence the sizeof(uint32_t)
+ l_data += sizeof(TRACE::trace_bin_entry_t)
+ + ALIGN_8(l_trace_entry->head.length)
+ + sizeof(uint32_t);
+ }
+ }
+ }
+
+ // Iterate through the map to apply duplicate pruning to all component ids
+ // found in iv_SectionVector
+ for (auto const& it : traceUD_map)
+ {
+ // Sort the vector by timestamp and hash
+ std::sort(it.second->begin(), it.second->end(),
+ // Define a lambda comparator function for sorting criteria
+ [](const TRACE::trace_bin_entry_t* a,
+ const TRACE::trace_bin_entry_t* b)
+ {
+ // a goes before b if a's timestamp is less than b's.
+ // If they are equal then compare the hash values.
+ bool result = false;
+ if (a->stamp.tbh < b->stamp.tbh)
+ {
+ result = true;
+ }
+ else if ((a->stamp.tbh == b->stamp.tbh)
+ && (a->stamp.tbl < b->stamp.tbl))
+ {
+ result = true;
+ }
+ else if ((a->stamp.tbh == b->stamp.tbh)
+ && (a->stamp.tbl == b->stamp.tbl)
+ && (a->head.hash < b->head.hash))
+ {
+ result = true;
+ }
+ return result;
+ });
+
+ // Call unique to prune the duplicate trace entries
+ auto newEndIt = std::unique(it.second->begin(), it.second->end(),
+ // Define a lambda predicate function for duplicate criteria
+ [](const TRACE::trace_bin_entry_t* a,
+ const TRACE::trace_bin_entry_t* b)
+ {
+ // a is equivalent to b if a's timestamp is the same as
+ // b's and their hashes are the same.
+ bool result = false;
+ if ((a->stamp.tbh == b->stamp.tbh)
+ && (a->stamp.tbl == b->stamp.tbl)
+ && (a->head.hash == b->head.hash))
+ {
+ result = true;
+ }
+ return result;
+ });
+
+ it.second->resize(std::distance(it.second->begin(), newEndIt));
+
+ // Calculate the size of the buffer that will hold all remaining
+ // trace entries in the new UD section
+ size_t uniqueSize = sizeof(TRACE::trace_buf_head_t);
+
+ for (auto uniqueIt = it.second->begin(); uniqueIt != it.second->end();
+ ++uniqueIt)
+ {
+ uniqueSize += sizeof(TRACE::trace_bin_entry_t)
+ + ALIGN_8((*uniqueIt)->head.length)
+ + sizeof(uint32_t);
+ }
+
+
+ // Create a new buffer for the new UD section from the vector of traces
+ // for this component id.
+ TRACE::trace_buf_head_t* header = nullptr;
+ char* l_pBuffer = new char[ uniqueSize ]();
+ size_t l_pos = 0;
+
+ // Write the header info to the buffer.
+ // This header info was chosen based on the code that is found in
+ // Buffer::getTrace() if that code is changed in the future those
+ // changes will need to be reflected here.
+ header = reinterpret_cast<TRACE::trace_buf_head_t*>(&l_pBuffer[l_pos]);
+
+ memset(header, '\0', sizeof(TRACE::trace_buf_head_t));
+
+ header->ver = TRACE::TRACE_BUF_VERSION;
+ header->hdr_len = sizeof(TRACE::trace_buf_head_t);
+ header->time_flg = TRACE::TRACE_TIME_REAL;
+ header->endian_flg = 'B';
+ memcpy(&header->comp[0], it.first, TRAC_COMP_SIZE);
+ header->times_wrap = 0;
+ header->te_count = it.second->size();
+ header->size = uniqueSize;
+ header->next_free = uniqueSize;
+
+ l_pos += header->hdr_len;
+
+ // Copy the trace entries to the buffer
+ for (auto uniqueIt = it.second->begin(); uniqueIt != it.second->end();
+ ++uniqueIt)
+ {
+ // fsp-traces have an extra 4 bytes. Hence the sizeof(uint32_t)
+ size_t entrySize = sizeof(TRACE::trace_bin_entry_t)
+ + ALIGN_8((*uniqueIt)->head.length)
+ + sizeof(uint32_t);
+
+ memcpy(&l_pBuffer[l_pos], (*uniqueIt), entrySize);
+
+ l_pos += entrySize;
+
+ }
+
+ ErrlUD* l_udSection = new ErrlUD( l_pBuffer,
+ uniqueSize,
+ FIPS_ERRL_COMP_ID,
+ FIPS_ERRL_UDV_DEFAULT_VER_1,
+ FIPS_ERRL_UDT_HB_TRACE );
+
+ l_uniqueTraceUDVector.push_back(l_udSection);
+
+ delete[] l_pBuffer;
+ delete it.second;
+ }
+
+ // Remove old trace UD sections
+ auto sectionVectorIt = iv_SectionVector.begin();
+ while(sectionVectorIt != iv_SectionVector.end())
+ {
+ // If UD section is a trace.
+ if( (FIPS_ERRL_COMP_ID == (*sectionVectorIt)->iv_header.iv_compId)
+ && (FIPS_ERRL_UDT_HB_TRACE == (*sectionVectorIt)->iv_header.iv_sst))
+ {
+ // Remove the ErrlUD* at this position
+ delete (*sectionVectorIt);
+ // Erase this entry from the vector
+ sectionVectorIt = iv_SectionVector.erase(sectionVectorIt);
+ }
+ else
+ {
+ ++sectionVectorIt;
+ }
+
+ }
+
+ // Add new trace UD sections
+ for(auto it = l_uniqueTraceUDVector.begin();
+ it != l_uniqueTraceUDVector.end();
+ ++it)
+ {
+ iv_SectionVector.push_back((*it));
+ }
+
+}
+
+
+
/**
* @brief Check if the severity of this log indicates it is
* customer visible, note this ignores any override flags that
diff --git a/src/usr/errl/test/errluserdetailtest.H b/src/usr/errl/test/errluserdetailtest.H
index 204951e38..4d3ad6db4 100644
--- a/src/usr/errl/test/errluserdetailtest.H
+++ b/src/usr/errl/test/errluserdetailtest.H
@@ -5,7 +5,7 @@
/* */
/* OpenPOWER HostBoot Project */
/* */
-/* Contributors Listed Below - COPYRIGHT 2011,2016 */
+/* Contributors Listed Below - COPYRIGHT 2011,2018 */
/* [+] International Business Machines Corp. */
/* */
/* */
@@ -37,18 +37,19 @@
#include <errl/errlentry.H>
#include <errl/errluserdetails.H>
#include <errl/errlreasoncodes.H>
+#include <errl/errlud.H>
#include <errl/errludstring.H>
#include <errl/errludbacktrace.H>
#include <errl/errludtarget.H>
#include <errl/errludlogregister.H>
#include <errl/errludcallout.H>
#include <errl/errludattribute.H>
+#include <errl/hberrltypes.H>
#include <targeting/common/targetservice.H>
#include <targeting/common/iterators/rangefilter.H>
#include <targeting/common/predicates/predicates.H>
#include <targeting/common/util.H>
#include <hwas/common/deconfigGard.H>
-
#include <devicefw/driverif.H>
using namespace ERRORLOG;
@@ -59,6 +60,184 @@ public:
// Note that errlUserDetailsTarget is tested in the targeting unit test
+
+ void testRemoveDuplicateTraces(void)
+ {
+ const size_t NUM_TRACE_ENTRIES = 5, NUM_COMPONENTS = 4;
+ typedef std::vector<void*> pVoidVec_t;
+
+ trace_desc_t* trac_testRmDupTrac1_trace = nullptr;
+ TRAC_INIT(&trac_testRmDupTrac1_trace, "TEST_TRACE1", 2*KILOBYTE);
+
+ trace_desc_t* trac_testRmDupTrac2_trace = nullptr;
+ TRAC_INIT(&trac_testRmDupTrac2_trace, "TEST_TRACE2", 2*KILOBYTE);
+
+ trace_desc_t* trac_testRmDupTrac3_trace = nullptr;
+ TRAC_INIT(&trac_testRmDupTrac3_trace, "TEST_TRACE3", 2*KILOBYTE);
+
+ trace_desc_t* trac_testRmDupTrac4_trace = nullptr;
+ TRAC_INIT(&trac_testRmDupTrac4_trace, "TEST_TRACE4", 2*KILOBYTE);
+
+ // Test Case 1: Collect traces five times from the same component and
+ // verify no duplicates remain.
+
+ ErrlEntry* l_err1 = new ErrlEntry( ERRL_SEV_INFORMATIONAL,
+ ERRL_USERDATA_TEST_MOD_ID,
+ ERRL_TEST_DUPLICATE_TRACE,
+ 0x1234567890,
+ 0x9876543210 );
+ // Write traces to comp 1
+ for (size_t i = 0; i < NUM_TRACE_ENTRIES; ++i)
+ {
+ TRACFCOMP(trac_testRmDupTrac1_trace, "Trace %d.", (i+1));
+ }
+
+ for (size_t i = 0; i < 5; ++i)
+ {
+ l_err1->collectTrace("TEST_TRACE1");
+ }
+
+ l_err1->removeDuplicateTraces();
+
+ pVoidVec_t traceUDSections_case1 =
+ l_err1->getUDSections(FIPS_ERRL_COMP_ID, FIPS_ERRL_UDT_HB_TRACE);
+
+ errlCommit(l_err1, CXXTEST_COMP_ID);
+
+ // ErrlEntry::removeDuplicateTraces() should have removed all duplicates
+ // and combined all trace UD sections into one section. If that isn't
+ // case then this test case should fail.
+ if(traceUDSections_case1.size() != 1)
+ {
+ TS_FAIL("The number of trace UD sections was != 1");
+ }
+
+ for(auto it = traceUDSections_case1.begin();
+ it != traceUDSections_case1.end(); ++it)
+ {
+ TRACE::trace_buf_head_t* header =
+ reinterpret_cast<TRACE::trace_buf_head_t*>((*it));
+
+ if (header->te_count != NUM_TRACE_ENTRIES)
+ {
+ TS_FAIL("The number of trace entries was != NUM_TRACE_ENTRIES");
+ }
+ }
+
+ // Test Case 2: Collect from several components and verify that none
+ // of the traces were removed.
+
+ ErrlEntry* l_err2 = new ErrlEntry( ERRL_SEV_INFORMATIONAL,
+ ERRL_USERDATA_TEST_MOD_ID,
+ ERRL_TEST_DUPLICATE_TRACE,
+ 0x1234567890,
+ 0x9876543210 );
+
+ // Write traces to comp 2
+ for (size_t i = 0; i < NUM_TRACE_ENTRIES; ++i)
+ {
+ TRACFCOMP(trac_testRmDupTrac2_trace, "Trace %d.", (i+1));
+ }
+
+ // Write traces to comp 3
+ for (size_t i = 0; i < NUM_TRACE_ENTRIES; ++i)
+ {
+ TRACFCOMP(trac_testRmDupTrac3_trace, "Trace %d.", (i+1));
+ }
+
+ // Write traces to comp 4
+ for (size_t i = 0; i < NUM_TRACE_ENTRIES; ++i)
+ {
+ TRACFCOMP(trac_testRmDupTrac4_trace, "Trace %d.", (i+1));
+ }
+
+
+ // Collect the traces for each one once.
+ l_err2->collectTrace("TEST_TRACE1");
+ l_err2->collectTrace("TEST_TRACE2");
+ l_err2->collectTrace("TEST_TRACE3");
+ l_err2->collectTrace("TEST_TRACE4");
+
+ l_err2->removeDuplicateTraces();
+
+ // Get the trace UD sections
+ pVoidVec_t traceUDSections_case2 =
+ l_err2->getUDSections(FIPS_ERRL_COMP_ID, FIPS_ERRL_UDT_HB_TRACE);
+
+ // Commit the error log
+ errlCommit(l_err2, CXXTEST_COMP_ID);
+
+ // Since the ErrlEntry::collectTrace() function creates a new UD section
+ // on each call to it there should only be NUM_COMPONENTS trace UD
+ // sections returned from ErrlEntry::getUDSections(). If that isn't the
+ // case then something unexpected happened and this test case should
+ // fail.
+ if(traceUDSections_case2.size() != NUM_COMPONENTS)
+ {
+ TS_FAIL("The number of trace UD sections was != NUM_COMPONENTS.");
+ }
+
+ // If ErrlEntry::removeDuplicateTraces() worked then none of the trace
+ // entries should be missing in any of the components.
+ for(auto it = traceUDSections_case2.begin();
+ it != traceUDSections_case2.end(); it++)
+ {
+ TRACE::trace_buf_head_t* header =
+ reinterpret_cast<TRACE::trace_buf_head_t*>((*it));
+
+ if (header->te_count != NUM_TRACE_ENTRIES)
+ {
+ TS_FAIL("The number of trace entries was != NUM_TRACE_ENTRIES");
+ }
+ }
+
+ // Test Case 3: Collect from a component once, write a new trace to that
+ // component, and then collect from it several times.
+
+ ErrlEntry* l_err3 = new ErrlEntry( ERRL_SEV_INFORMATIONAL,
+ ERRL_USERDATA_TEST_MOD_ID,
+ ERRL_TEST_DUPLICATE_TRACE,
+ 0x1234567890,
+ 0x9876543210 );
+
+ l_err3->collectTrace("TEST_TRACE1");
+
+ TRACFCOMP(trac_testRmDupTrac1_trace, "A New Trace.");
+
+ for (size_t i = 0; i < 5; ++i)
+ {
+ l_err3->collectTrace("TEST_TRACE1");
+ }
+
+ l_err3->removeDuplicateTraces();
+
+ pVoidVec_t traceUDSections_case3 =
+ l_err3->getUDSections(FIPS_ERRL_COMP_ID, FIPS_ERRL_UDT_HB_TRACE);
+
+ errlCommit(l_err3, CXXTEST_COMP_ID);
+
+ // ErrlEntry::removeDuplicateTraces() should have removed all duplicates
+ // and combined all trace UD sections into one section. If that isn't
+ // case then this test case should fail.
+ if(traceUDSections_case3.size() != 1)
+ {
+ TS_FAIL("The number of trace UD sections was != 1");
+ }
+
+ for(auto it = traceUDSections_case3.begin();
+ it != traceUDSections_case3.end(); ++it)
+ {
+ TRACE::trace_buf_head_t* header =
+ reinterpret_cast<TRACE::trace_buf_head_t*>((*it));
+
+ if (header->te_count != (NUM_TRACE_ENTRIES + 1))
+ {
+ TS_FAIL("The number of trace entries was != 6");
+ }
+ }
+ }
+
+
/**
* @test testString - Capture a String in an error log
*/
OpenPOWER on IntegriCloud