| /********************************************************************* |
| * |
| * Copyright 2006 Keith Packard and Carl Worth |
| * Copyright 2012 Intel Corporation |
| * Copyright 2012 VMware, Inc. |
| * All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person |
| * obtaining a copy of this software and associated documentation |
| * files (the "Software"), to deal in the Software without |
| * restriction, including without limitation the rights to use, copy, |
| * modify, merge, publish, distribute, sublicense, and/or sell copies |
| * of the Software, and to permit persons to whom the Software is |
| * furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
| * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
| * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| * |
| *********************************************************************/ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <limits> |
| #include <vector> |
| |
| #include "os.hpp" |
| #include "trace_fast_callset.hpp" |
| |
| using namespace trace; |
| |
| #define MAX_LEVEL 16 |
| |
| FastCallRange::FastCallRange(CallNo first, CallNo last, int level) |
| : ref_counter(0) |
| { |
| this->first = first; |
| this->last = last; |
| this->level = level; |
| |
| next.resize(level, 0); |
| } |
| |
| bool |
| FastCallRange::contains(CallNo call_no) const |
| { |
| return (first <= call_no && last >= call_no); |
| } |
| |
| bool |
| FastCallSet::empty(void) const |
| { |
| return max_level == 0; |
| } |
| |
| FastCallSet::FastCallSet(): head(0, 0, MAX_LEVEL) |
| { |
| head.first = std::numeric_limits<CallNo>::max(); |
| head.last = std::numeric_limits<CallNo>::min(); |
| |
| max_level = 0; |
| } |
| |
| /* |
| * Generate a random level number, distributed |
| * so that each level is 1/4 as likely as the one before |
| * |
| * Note that level numbers run 1 <= level < MAX_LEVEL |
| */ |
| static int |
| random_level (void) |
| { |
| /* tricky bit -- each bit is '1' 75% of the time */ |
| long int bits = os::random() | os::random(); |
| int level = 1; |
| |
| while (level < MAX_LEVEL) |
| { |
| if (bits & 1) |
| break; |
| level++; |
| bits >>= 1; |
| } |
| |
| return level; |
| } |
| |
| void |
| FastCallSet::add(CallNo first, CallNo last) |
| { |
| std::vector<FastCallRangePtr*> update (MAX_LEVEL); |
| FastCallRange *node; |
| FastCallRangePtr new_node; |
| int i, level; |
| |
| /* Find node immediately before insertion point. |
| * NOTE: FastCallRangePtr(), e.g., next[i](), returns FastCallRange* */ |
| node = &head; // Can't reference &head as a FastCallRangePtr |
| for (i = max_level - 1; i >= 0; i--) { |
| while (node->next[i]() && first > node->next[i]->last) { |
| node = node->next[i](); |
| } |
| update[i] = &node->next[i]; |
| } |
| |
| /* Can we contain first by expanding tail of current range by 1? */ |
| if (node != &head && node->last == first - 1) { |
| |
| new_node = FastCallRangePtr(node); |
| new_node->last = last; |
| goto MERGE_NODE_WITH_SUBSEQUENT_COVERED_NODES; |
| |
| } |
| |
| /* Current range could not contain first, look at next. */ |
| node = node->next[0](); |
| |
| if (node) { |
| /* Do nothing if new range is already entirely contained. */ |
| if (node->first <= first && node->last >= last) { |
| return; |
| } |
| |
| /* If last is already included, we can simply expand |
| * node->first to fully include the range. */ |
| if (node->first <= last && node->last >= last) { |
| node->first = first; |
| return; |
| } |
| |
| /* This is our candidate node if first is contained */ |
| if (node->first <= first && node->last >= first) { |
| new_node = FastCallRangePtr(node); |
| new_node->last = last; |
| goto MERGE_NODE_WITH_SUBSEQUENT_COVERED_NODES; |
| } |
| } |
| |
| /* Not possible to expand any existing node, so create a new one. */ |
| |
| level = random_level(); |
| |
| /* Handle first node of this level. */ |
| if (level > max_level) { |
| level = max_level + 1; |
| update[max_level] = &head.next[max_level]; |
| max_level = level; |
| } |
| |
| new_node = FastCallRangePtr(new FastCallRange(first, last, level)); |
| |
| /* Perform insertion into all lists. */ |
| for (i = 0; i < level; i++) { |
| new_node->next[i] = *update[i]; |
| *update[i] = new_node; |
| } |
| |
| MERGE_NODE_WITH_SUBSEQUENT_COVERED_NODES: |
| FastCallRangePtr next = new_node->next[0]; |
| node = new_node(); |
| while (next() && next->first <= node->last + 1) { |
| if (next->last > node->last) |
| node->last = next->last; |
| |
| for (i = 0; i < node->level && i < next->level; i++) { |
| node->next[i] = next->next[i]; |
| } |
| |
| for (; i < next->level; i++) { |
| *update[i] = next->next[i]; |
| } |
| |
| next = node->next[0]; |
| } |
| } |
| |
| void |
| FastCallSet::add(CallNo call_no) |
| { |
| this->add(call_no, call_no); |
| } |
| |
| bool |
| FastCallSet::contains(CallNo call_no) const |
| { |
| FastCallRange *node; |
| int i; |
| |
| node = const_cast<FastCallRange*>(&head); |
| for (i = max_level - 1; i >= 0; i--) { |
| while (node->next[i]() && call_no > node->next[i]->last) { |
| node = node->next[i](); |
| } |
| } |
| |
| node = node->next[0](); |
| |
| if (node == NULL) |
| return false; |
| |
| return node->contains(call_no); |
| } |