summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/usr/errl/errlentry.H47
-rw-r--r--src/include/usr/errl/errlreasoncodes.H1
-rw-r--r--src/usr/errl/errlentry.C235
-rw-r--r--src/usr/errl/test/errluserdetailtest.H183
4 files changed, 451 insertions, 15 deletions
diff --git a/src/include/usr/errl/errlentry.H b/src/include/usr/errl/errlentry.H
index 2d36218ae..6ac856237 100644
--- a/src/include/usr/errl/errlentry.H
+++ b/src/include/usr/errl/errlentry.H
@@ -487,6 +487,27 @@ public:
const uint64_t i_max = KILOBYTE);
/**
+ * @brief Remove the duplicate trace entries from user detail data
+ * When multiple calls to collectTrace() on the same component id occur a
+ * new user detail section is created each time. This function removes the
+ * duplicates created from that process.
+ *
+ * @algorithm A high level overview of what the code does is as follows:
+ * * Iterate through the iv_SectionVector which contains all UD
+ * sections and add each trace_bin_entry_t to a vector corresponding
+ * to each component id found in iv_SectionVector.
+ * * For each vector in the map of component id vectors
+ * * sort the collection of traces by timestamp and hash
+ * * call unique where the same timestamp and hash are considered
+ * to be equivalent trace entries to be removed.
+ * * Put all remaining trace entries into a new, consolidated trace
+ * UD section.
+ * * Remove the old trace UD sections from iv_SectionVector
+ * * Add the new consolidated trace UD sections to the iv_SectionVector
+ */
+ void removeDuplicateTraces(void);
+
+ /**
* @brief Remove the back trace user detail data
* When an error log is constructed, the back trace is automatically
* captured. This function removes the backtrace. This should be used when
@@ -896,6 +917,8 @@ private:
ErrlEntry(const ErrlEntry& i_right);
ErrlEntry& operator=(const ErrlEntry& i_right);
+
+
private:
// Data Members
ErrlPrvt iv_Private; // private header object
@@ -909,20 +932,22 @@ private:
// hostboot.
errlTermState_t iv_termState;
- // when true, the severity has been set "final" and can not be changed.
- bool iv_sevFinal;
+ // when true, the severity has been set "final" and can not be changed.
+ bool iv_sevFinal;
+
+ //when true, the current error log will not be saved to PNOR, sent to the
+ //BMC, or displayed in the console
+ bool iv_skipShowingLog;
+
+ // when true, send this special type of eSEL to the BMC
+ // This is used to send OCC informational errors up to BMC
+ bool iv_eselCallhomeInfoEvent;
- //when true, the current error log will not be saved to PNOR, sent to the
- //BMC, or displayed in the console
- bool iv_skipShowingLog;
+ // when true, if error log is committed, then the error log is tracked so
+ // doShutdown can request that a HB dump be done.
+ bool iv_doHbDump;
- // when true, send this special type of eSEL to the BMC
- // This is used to send OCC informational errors up to BMC
- bool iv_eselCallhomeInfoEvent;
- // when true, if error log is committed, then the error log is tracked so
- // doShutdown can request that a HB dump be done.
- bool iv_doHbDump;
};
diff --git a/src/include/usr/errl/errlreasoncodes.H b/src/include/usr/errl/errlreasoncodes.H
index c77e1de2a..56f9b7f87 100644
--- a/src/include/usr/errl/errlreasoncodes.H
+++ b/src/include/usr/errl/errlreasoncodes.H
@@ -58,6 +58,7 @@ namespace ERRORLOG
ERRL_TEST_LOGREGISTER_UD = ERRL_COMP_ID | 0x05,
ERRL_TEST_CALLOUT_UD = ERRL_COMP_ID | 0x06,
ERRL_CORE_EX_TARGET_NULL = ERRL_COMP_ID | 0x07,
+ ERRL_TEST_DUPLICATE_TRACE = ERRL_COMP_ID | 0x08,
//........
ERRL_LAST_ERR = ERRL_COMP_ID | 0xFF
};
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