diff options
| author | Matt Derksen <mderkse1@us.ibm.com> | 2017-10-03 11:02:13 -0500 |
|---|---|---|
| committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2017-10-19 22:17:55 -0400 |
| commit | ad1909dedffab93922fe80f06bf89d5b76d9e9a0 (patch) | |
| tree | a244fa143b4463dc2f51b742d606a64cefd1548a /src/usr/trace/runtime/rt_daemon.C | |
| parent | 20250c0b1f6de53b2bfddd1c714fb8c97e655ce2 (diff) | |
| download | talos-hostboot-ad1909dedffab93922fe80f06bf89d5b76d9e9a0.tar.gz talos-hostboot-ad1909dedffab93922fe80f06bf89d5b76d9e9a0.zip | |
Log traces to error logs in HBRT
This enables buffer tracing at hostboot runtime.
Will add these traces to runtime errors for better debug
Change-Id: I795bb7deafdd02adea4588ebf8dfb11cbce116a0
RTC:172770
Reviewed-on: http://ralgit01.raleigh.ibm.com/gerrit1/48084
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Reviewed-by: Christian R. Geddes <crgeddes@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>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Martin Gloff <mgloff@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr/trace/runtime/rt_daemon.C')
| -rw-r--r-- | src/usr/trace/runtime/rt_daemon.C | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/src/usr/trace/runtime/rt_daemon.C b/src/usr/trace/runtime/rt_daemon.C new file mode 100644 index 000000000..0e8300f95 --- /dev/null +++ b/src/usr/trace/runtime/rt_daemon.C @@ -0,0 +1,369 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/trace/runtime/rt_daemon.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* 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 "../daemon/daemon.H" +#include "../daemonif.H" +#include "../service.H" +#include "../buffer.H" +#include "../bufferpage.H" +#include "../entry.H" +#include "../compdesc.H" +#include "../debug.H" + +#include <errl/hberrltypes.H> +#include <string.h> +#include <util/align.H> + + +namespace TRACEDAEMON +{ + using namespace TRACE; + + Daemon::Daemon() : iv_service(nullptr), iv_totalPruned(0) + { + iv_first = iv_last = BufferPage::allocate(true); + } + + Daemon::~Daemon() + { + assert(0, "No need to destruct the trace Daemon"); + } + + void Daemon::signal_trace_daemon(void) + { + // Put here to avoid build issue instead of in class constructor + // iv_service won't be used until these functions are called + iv_service = Service::getGlobalInstance(); + + // Collect trace entries from client. + collectTracePages(); + + // Reduce buffer space in daemon-side buffer. + pruneTraceEntries(); + + // combine trace buffer pages to remove pruned entries + coalescePages(); + } + + + void Daemon::collectTracePages() + { + // Collect buffer pages from front-end. + BufferPage* srcPages[BUFFER_COUNT]; + for (size_t i = 0; i < BUFFER_COUNT; i++) + { + if (iv_service->iv_buffers[i] == nullptr) + { + iv_curPages[i] = srcPages[i] = nullptr; + } + else + { + iv_curPages[i] = srcPages[i] = + iv_service->iv_buffers[i]->claimPages(); + } + iv_curOffset[i] = 0; + } + + uint32_t entry_number = 0; + // Process buffer pages. + do + { + size_t whichBuffer = BUFFER_COUNT; + Entry* whichEntry = nullptr; + uint64_t minTimeStamp = UINT64_MAX; + + // Find the entry with the earliest timestamp. + for (size_t i = 0; i < BUFFER_COUNT; i++) + { + if (nullptr == iv_curPages[i]) continue; + + Entry* entry = + reinterpret_cast<Entry*>( + &((&(iv_curPages[i]->data[0]))[iv_curOffset[i]]) + ); + + trace_bin_entry_t* binEntry = + reinterpret_cast<trace_bin_entry_t*>( + &(entry->data[0]) + ); + + + uint64_t curTimeStamp = + TWO_UINT32_TO_UINT64(binEntry->stamp.tbh, + binEntry->stamp.tbl); + + if (curTimeStamp < minTimeStamp ) + { + whichBuffer = i; + whichEntry = entry; + minTimeStamp = curTimeStamp; + } + } + + // Did not find another entry, our work is done. + if (whichBuffer == BUFFER_COUNT) + { + break; + } + + if ((whichEntry == nullptr) || (whichEntry->comp == nullptr)) + { + break; + } + + // Increment pointers to next buffer entry. + iv_curOffset[whichBuffer] += whichEntry->size + sizeof(Entry); + if (iv_curOffset[whichBuffer] >= iv_curPages[whichBuffer]->usedSize) + { + iv_curPages[whichBuffer] = iv_curPages[whichBuffer]->next; + iv_curOffset[whichBuffer] = 0; + } + + // Allocate a new back-end entry. + Entry* mainBuffEntry = nullptr; + while (nullptr == + (mainBuffEntry = + iv_last->claimEntry(whichEntry->size + sizeof(Entry)))) + { + BufferPage* n = BufferPage::allocate(true); + + // Remember iv_last = Last newest combined-buffer page. + // Set n to the newest page, and push current iv_last back + n->next = iv_last; + iv_last->prev = n; + iv_last = n; + iv_last->prev = nullptr; + } + + // Move entry from front-end buffer to back-end. + replaceEntry(whichEntry, mainBuffEntry); + + entry_number++; + } while(1); + + // Release pages. + for (size_t i = 0; i < BUFFER_COUNT; i++) + { + while(srcPages[i]) + { + BufferPage* tmp = srcPages[i]->next; + BufferPage::deallocate(srcPages[i]); + srcPages[i] = tmp; + } + } + } + + + void Daemon::replaceEntry(Entry* from, Entry* to) + { + do + { + // Copy entry content to new entry. + memcpy(to, + from, + from->size + sizeof(Entry)); + + // Update next object's pointer. + if (to->next) + { + to->next->prev = to; + } + else + { + if (to->comp != nullptr) + { + to->comp->iv_last = to; + } + } + + // Update prev object's pointer. + // Buffer ensures that an entry's "next" is written before + // the "next->prev", so we can be certain that if to->prev + // then to->prev->next is finalized. + if (to->prev) + { + to->prev->next = to; + } + else // If there is no previous, this is the first (most recent) + // for the component, so update the component object. + { + if (to->comp != nullptr) + { + Buffer* b = + iv_service->iv_buffers[to->comp->iv_bufferType]; + + // Need to toggle the consumer lock on this one, so use + // the consumerOp to move the compoment->first from + // 'from' to 'to'. + // + // If it fails (first != from anymore) then retry this + // whole sequence. + if (!b->consumerOp(&to->comp->iv_first, from, + &to->comp->iv_first, to)) + { + continue; + } + } + } + + // Successfully updated everything, break from loop. + break; + + } while (1); + } + + + void Daemon::pruneTraceEntries(bool i_all) + { + ComponentList::List::iterator component; + + size_t pruned = 0; + + // Iterate through the components... + bool more = iv_service->iv_compList->first(component); + while(more) + { + Entry* entry = component->iv_last; + Entry* orig_entry = entry; + + // Invalidate entries until the component is small enough. + while((entry) && + ((component->iv_curSize > component->iv_maxSize) || + i_all) + ) + { + if (!reinterpret_cast<BufferPage*>( + ALIGN_PAGE_DOWN( + reinterpret_cast<uint64_t>(entry)))->commonPage) + { + break; + } + + entry->comp = nullptr; // Invalidate entry. + + __sync_sub_and_fetch(&component->iv_curSize, entry->size); + pruned += entry->size; + + entry = entry->prev; + } + + if (entry != orig_entry) + { + + // Break chain of linked list. + if (entry != nullptr) + { + entry->next = nullptr; + } + + // Update component pointers. + Buffer* b = + iv_service->iv_buffers[component->iv_bufferType]; + + // consumerOp pseudo-code: + // if (entry == nullptr) component->first = nullptr; + // component->last = entry; + b->consumerOp(&entry, nullptr, + &component->iv_first, nullptr, + &component->iv_last, entry); + } + + // Get next component. + more = iv_service->iv_compList->next(component); + } + + // Record size of pruned entries in a global. + if (pruned) + { + iv_totalPruned += pruned; + } + } + + void Daemon::coalescePages() + { + // Skip if there hasn't been enough entries pruned to make this + // worth our while. + if (iv_totalPruned < PAGESIZE) { return; } + + iv_totalPruned = 0; + + // Allocate a new back-end page for the coalesced entries. + BufferPage* outputPage = BufferPage::allocate(true); + BufferPage* originalOutputPage = outputPage; + + // Get the first page from the original back-end buffer. + BufferPage* currentPage = iv_first; + + // Iterate through the back-end pages. + while(currentPage != nullptr) + { + // Look at all the entries on the back-end pages. + size_t offset = 0; + while (offset < currentPage->usedSize) + { + Entry* entry = + reinterpret_cast<Entry*>(¤tPage->data[offset]); + + if (nullptr != entry->comp) // Ensure entry is valid. + { + Entry* newEntry = nullptr; + + // Allocate space on new back-end pages. + while (nullptr == (newEntry = + outputPage->claimEntry(entry->size + sizeof(Entry)))) + { + BufferPage* newPage = BufferPage::allocate(true); + + newPage->next = outputPage; + outputPage->prev = newPage; + outputPage = newPage; + } + + // Move entry to new back-end page. + replaceEntry(entry, newEntry); + } + + offset += entry->size + sizeof(Entry); + } + + currentPage = currentPage->prev; + } + + BufferPage* oldPage = iv_first; + + // Update back-end buffer pointers to point to new back-end pages. + iv_last = outputPage; + iv_first = originalOutputPage; + + // Delete the old back-end pages. + while(oldPage) + { + BufferPage* temp = oldPage->prev; + BufferPage::deallocate(oldPage); + oldPage = temp; + } + + } + +} |

