mirror of
https://github.com/gperftools/gperftools
synced 2024-12-21 06:50:03 +00:00
4585b78c8d
This is significant speedup of fast-path of malloc. Large part comes from avoiding expensive function prologue/epilogue. Which is achieved by making sure that tc_{malloc,new,free} etc are small functions that do only tail-calls. We keep only critical path in those functions and tail-call to slower "full" versions when we need to deal with less common case. This helps compiler generate much tidier code. Fast-path readyness check is now different too. We used to have "min size for slow path" variable, which was set to non-zero value when we know that thread cache is present and ready. We now have use thread-cache pointer not equal to NULL as readyness check. There is special ThreadCache::threadlocal_data_.fast_path_heap copy of that pointer that can be temporarily nulled to disable malloc fast path. This is used to enable emergency malloc. There is also slight change to tracking thread cache size. Instead of tracking total size of free list, it now tracks size headroom. This allows for slightly faster deallocation fast-path check where we're checking headroom to stay above zero. This check is a bit faster than comparing with max_size_.
116 lines
3.3 KiB
C++
116 lines
3.3 KiB
C++
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
|
// Copyright (c) 2008, Google Inc.
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
// in the documentation and/or other materials provided with the
|
|
// distribution.
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
// ---
|
|
// Author: Sanjay Ghemawat <opensource@google.com>
|
|
//
|
|
// Some very basic linked list functions for dealing with using void * as
|
|
// storage.
|
|
|
|
#ifndef TCMALLOC_LINKED_LIST_H_
|
|
#define TCMALLOC_LINKED_LIST_H_
|
|
|
|
#include <stddef.h>
|
|
|
|
namespace tcmalloc {
|
|
|
|
inline void *SLL_Next(void *t) {
|
|
return *(reinterpret_cast<void**>(t));
|
|
}
|
|
|
|
inline void SLL_SetNext(void *t, void *n) {
|
|
*(reinterpret_cast<void**>(t)) = n;
|
|
}
|
|
|
|
inline void SLL_Push(void **list, void *element) {
|
|
void *next = *list;
|
|
*list = element;
|
|
SLL_SetNext(element, next);
|
|
}
|
|
|
|
inline void *SLL_Pop(void **list) {
|
|
void *result = *list;
|
|
*list = SLL_Next(*list);
|
|
return result;
|
|
}
|
|
|
|
inline bool SLL_TryPop(void **list, void **rv) {
|
|
void *result = *list;
|
|
if (!result) {
|
|
return false;
|
|
}
|
|
void *next = SLL_Next(*list);
|
|
*list = next;
|
|
*rv = result;
|
|
return true;
|
|
}
|
|
|
|
// Remove N elements from a linked list to which head points. head will be
|
|
// modified to point to the new head. start and end will point to the first
|
|
// and last nodes of the range. Note that end will point to NULL after this
|
|
// function is called.
|
|
inline void SLL_PopRange(void **head, int N, void **start, void **end) {
|
|
if (N == 0) {
|
|
*start = NULL;
|
|
*end = NULL;
|
|
return;
|
|
}
|
|
|
|
void *tmp = *head;
|
|
for (int i = 1; i < N; ++i) {
|
|
tmp = SLL_Next(tmp);
|
|
}
|
|
|
|
*start = *head;
|
|
*end = tmp;
|
|
*head = SLL_Next(tmp);
|
|
// Unlink range from list.
|
|
SLL_SetNext(tmp, NULL);
|
|
}
|
|
|
|
inline void SLL_PushRange(void **head, void *start, void *end) {
|
|
if (!start) return;
|
|
SLL_SetNext(end, *head);
|
|
*head = start;
|
|
}
|
|
|
|
inline size_t SLL_Size(void *head) {
|
|
int count = 0;
|
|
while (head) {
|
|
count++;
|
|
head = SLL_Next(head);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
} // namespace tcmalloc
|
|
|
|
#endif // TCMALLOC_LINKED_LIST_H_
|