Getting ready to shift to dlmalloc

This commit is contained in:
2022-02-23 17:29:49 -05:00
parent 6a9bf4ca42
commit f2ab8d9e34
7 changed files with 6424 additions and 20 deletions

View File

@@ -65,6 +65,7 @@ LUA_OBJ_FILES=\
CORE_OBJ_FILES=\
obj/invocation.o\
obj/spookyv2.o\
obj/eng-malloc.o\
obj/debugcollector.o\
obj/drivenengine.o\
obj/dummycert.o\

View File

@@ -1,6 +1,7 @@
#include "drivertests.hpp"
#include "drivenengine.hpp"
#include "world.hpp"
#include "eng-malloc.hpp"
#include <iomanip>
static void write_closed_message(Channel *ch, StreamBuffer *out) {
@@ -92,7 +93,7 @@ public:
virtual void event_update() {
double clock = get_clock();
if (clock > last_clock_ + 0.5) {
int ms = util::hash_of_mallocs();
int ms = dlmalloc_hash();
stdostream() << std::fixed << std::setprecision(2) << clock << " " << std::hex << ms << " ";
count_++;
last_clock_ = clock;

View File

@@ -0,0 +1,64 @@
// We only use a custom allocator on linux (for now)
// The allocator we chose is 'dlmalloc' (doug lea's malloc).
// It's a good allocator for single-threaded programs.
// It needs to be configured by setting a bunch of defines.
//
#ifdef __linux__
// We need this to define dlmalloc, not malloc.
#define USE_DL_PREFIX 1
// We don't need mspaces.
#define ONLY_MSPACES 0
#define MSPACES 0
// We don't need mallinfo
#define NO_MALLINFO 1
// We don't need dlmalloc_inspect_all
#define MALLOC_INSPECT_ALL 0
// We don't need dlmalloc_stats.
#define NO_MALLOC_STATS 1
// Disable locking. The entire engine is single-threaded.
#define USE_LOCKS 0
// For now, we'll let the allocator use mmap to get memory.
// It's not clear if this is going to be deterministic.
#define HAVE_MMAP 1
// One way to force determinism would be to emulate sbrk
// using mmap and mremap, always putting the heap at a fixed
// address. For now, we're not doing that, we're just
// using mmap and relying on that being deterministic (we hope).
#define HAVE_MORECORE 0
#define MORECORE emulate_sbrk
// The properties of mmap under linux
#define MMAP_CLEARS 1
#define HAVE_MREMAP 1
// Don't generate random seeds, or time-based seeds.
#define USE_DEV_RANDOM 0
#define LACKS_TIME_H 1
#include "dlmalloc/dlmalloc.c"
#endif
int dlmalloc_hash() {
void *blocks[15];
int hash = 0;
for (int i = 0; i < 15; i++) {
void *blk = dlmalloc(1 << i);
blocks[i] = blk;
hash = (hash * 17) + (int)(intptr_t)(blk);
}
for (int i = 0; i < 15; i++) {
free(blocks[i]);
}
return (hash & 0x7FFFFFFF) | (0x40000000);
}

View File

@@ -0,0 +1,105 @@
#ifndef ENG_MALLOC_HPP
#define ENG_MALLOC_HPP
#include <string>
#include <vector>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <sstream>
// dlmalloc is only used on linux.
extern "C" {
#ifdef __linux__
void* dlmalloc(size_t x);
void dlfree(void *p);
void* dlrealloc(void*, size_t);
#else
void* dlmalloc(size_t x) { return malloc(x); }
void dlfree(void *p) { free(p); }
void* dlrealloc(void *p, size_t x) { return realloc(p,x); }
#endif
}
// Return the current state of the dlmalloc allocator as a 30-bit hash.
extern int dlmalloc_hash();
// EngAllocator: a class meant to be used as an STL Allocator.
// Causes objects to be allocated using dlmalloc and dlfree.
template <class T>
class EngAllocator
{
public:
using value_type = T;
EngAllocator() noexcept {}
template <class U> EngAllocator(EngAllocator<U> const&) noexcept {}
value_type* allocate(std::size_t n)
{
return static_cast<value_type*>(dlmalloc(n*sizeof(value_type)));
}
void deallocate(value_type* p, std::size_t) noexcept
{
dlfree(p);
}
};
template <class T, class U>
bool operator==(EngAllocator<T> const&, EngAllocator<U> const&) noexcept
{
return true;
}
template <class T, class U>
bool operator!=(EngAllocator<T> const&, EngAllocator<U> const&) noexcept
{
return false;
}
namespace eng {
template<class T>
using hash = std::hash<T>;
template<class T>
using less = std::less<T>;
template<class T>
using equal_to = std::equal_to<T>;
template<class T>
using char_traits = std::char_traits<T>;
template<class A, class B>
using pair = std::pair<A, B>;
template<class C, class T=char_traits<C>>
using basic_string = std::basic_string<C, T, EngAllocator<C>>;
template<class C, class T=char_traits<C>>
using basic_stringstream = std::basic_stringstream<C, T, EngAllocator<C>>;
template<class T>
using vector = std::vector<T, EngAllocator<T>>;
template<class K, class V, class C=less<K>>
using map = std::map<K, V, C, EngAllocator<pair<const K, V>>>;
template<class K, class V, class H=hash<K>, class E=equal_to<K>>
using unordered_map = std::unordered_map<K, V, H, E, EngAllocator<pair<const K, V>>>;
template<class K, class C=std::less<K>>
using set = std::set<K, C, EngAllocator<K>>;
template<class K, class H=hash<K>, class E=equal_to<K>>
using unordered_set = std::unordered_set<K, H, E, EngAllocator<K>>;
using string = basic_string<char>;
using stringstream = basic_stringstream<char>;
}
#endif // ENG_MALLOC_HPP

View File

@@ -353,20 +353,6 @@ bool is_lua_comment(const std::string &s) {
return s.substr(start, 2) == "--";
}
int hash_of_mallocs() {
void *blocks[15];
int hash = 0;
for (int i = 0; i < 15; i++) {
void *blk = malloc(1 << i);
blocks[i] = blk;
hash = (hash * 17) + (int)(ptrdiff_t)(blk);
}
for (int i = 0; i < 15; i++) {
free(blocks[i]);
}
return (hash & 0x7FFFFFFF) | (0x40000000);
}
std::string XYZ::debug_string() const {
std::ostringstream oss;
oss << "(" << x << "," << y << "," << z << ")";

View File

@@ -125,11 +125,6 @@ LuaSourcePtr make_lua_source(const std::string &code);
// Return true if the line of code is a lua comment.
bool is_lua_comment(const std::string &line);
// Malloc some blocks of RAM, and calculate a hash from
// their addresses. This can be used to determine if the malloc
// heap is in a deterministic state.
int hash_of_mallocs();
// Remove nullptrs from a vector of unique pointers.
template<class T>
void remove_nullptrs(std::vector<std::unique_ptr<T>> &vec) {

File diff suppressed because it is too large Load Diff