Skip to content

Commit

Permalink
String implementation: Move character data into the memo_t.
Browse files Browse the repository at this point in the history
This changes two allocations per underlying string data into one.  Requires
changes in StringAccum as well, since StringAccum calls
String::make_claim().
  • Loading branch information
kohler committed Nov 14, 2009
1 parent 93c7474 commit 20c4be6
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 59 deletions.
17 changes: 11 additions & 6 deletions include/click/straccum.hh
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ class StringAccum { public:

/** @brief Destroy a StringAccum, freeing its memory. */
~StringAccum() {
if (_cap >= 0)
CLICK_LFREE(_s, _cap);
if (_cap > 0)
CLICK_LFREE(_s - MEMO_SPACE, _cap + MEMO_SPACE);
}


Expand Down Expand Up @@ -374,6 +374,10 @@ class StringAccum { public:

private:

enum {
MEMO_SPACE = String::MEMO_SPACE
};

unsigned char *_s;
int _len;
int _cap;
Expand Down Expand Up @@ -437,12 +441,13 @@ StringAccum::StringAccum(int capacity)
: _len(0)
{
assert(capacity >= 0);
if (capacity) {
_s = (unsigned char *) CLICK_LALLOC(capacity);
_cap = (_s ? capacity : -1);
if (capacity
&& (_s = (unsigned char *) CLICK_LALLOC(capacity + MEMO_SPACE))) {
_s += MEMO_SPACE;
_cap = capacity;
} else {
_s = 0;
_cap = 0;
_cap = (capacity ? -1 : 0);
}
}

Expand Down
14 changes: 8 additions & 6 deletions include/click/string.hh
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,7 @@ class String { public:

/** @brief Return true iff this is an out-of-memory string. */
inline bool out_of_memory() const {
return _r.data == &oom_string_data;
return _r.data == oom_memo.real_data;
}

/** @brief Return a const reference to an out-of-memory String. */
Expand All @@ -625,7 +625,7 @@ class String { public:
* The returned value may be dereferenced; it points to a null
* character. */
static inline const char *out_of_memory_data() {
return &oom_string_data;
return oom_memo.real_data;
}


Expand All @@ -640,11 +640,15 @@ class String { public:
volatile uint32_t refcount;
uint32_t capacity;
volatile uint32_t dirty;
char *real_data;
#if HAVE_STRING_PROFILING > 1
memo_t **pprev;
memo_t *next;
#endif
char real_data[1]; // but it is almost certainly more
};

enum {
MEMO_SPACE = offsetof(memo_t, real_data)
};

struct rep_t {
Expand Down Expand Up @@ -721,11 +725,9 @@ class String { public:

void assign(const char *cstr, int len, bool need_deref);
void assign_out_of_memory();
static memo_t *create_memo(char *data, int dirty, int capacity);
static memo_t *create_memo(char *space, int dirty, int capacity);
static void delete_memo(memo_t *memo);

static const char null_string_data;
static const char oom_string_data;
static const char bool_data[11];
static const char int_data[20];
static memo_t null_memo;
Expand Down
15 changes: 9 additions & 6 deletions lib/straccum.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ void
StringAccum::assign_out_of_memory()
{
assert(_cap >= 0);
CLICK_LFREE(_s, _cap);
if (_cap > 0)
CLICK_LFREE(_s - MEMO_SPACE, _cap + MEMO_SPACE);
_s = reinterpret_cast<unsigned char *>(const_cast<char *>(String::out_of_memory_data()));
_cap = -1;
_len = 0;
Expand All @@ -70,19 +71,21 @@ StringAccum::grow(int want)
if (_cap < 0)
return false;

int ncap = (_cap ? _cap * 2 : 128);
int ncap = (_cap ? (_cap + MEMO_SPACE) * 2 : 128) - MEMO_SPACE;
while (ncap <= want)
ncap *= 2;
ncap = (ncap + MEMO_SPACE) * 2 - MEMO_SPACE;

unsigned char *n = (unsigned char *) CLICK_LALLOC(ncap);
unsigned char *n = (unsigned char *) CLICK_LALLOC(ncap + MEMO_SPACE);
if (!n) {
assign_out_of_memory();
return false;
}
n += MEMO_SPACE;

if (_s)
if (_s) {
memcpy(n, _s, _cap);
CLICK_LFREE(_s, _cap);
CLICK_LFREE(_s - MEMO_SPACE, _cap + MEMO_SPACE);
}
_s = n;
_cap = ncap;
return true;
Expand Down
82 changes: 41 additions & 41 deletions lib/string.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ CLICK_DECLS
* returns an out-of-memory string.
*/

const char String::null_string_data = 0;
const char String::oom_string_data = 0;
const char String::bool_data[] = "true\0false";
const char String::int_data[] = "0\0001\0002\0003\0004\0005\0006\0007\0008\0009";

Expand All @@ -77,20 +75,20 @@ const char String::int_data[] = "0\0001\0002\0003\0004\0005\0006\0007\0008\0009"
#endif

String::memo_t String::null_memo = {
2, 0, 0, const_cast<char *>(&null_string_data) MEMO_INITIALIZER_TAIL
2, 0, 0 MEMO_INITIALIZER_TAIL, { '\0' }
};
String::memo_t String::permanent_memo = {
1, 0, 0, const_cast<char *>(&null_string_data) MEMO_INITIALIZER_TAIL
1, 0, 0 MEMO_INITIALIZER_TAIL, { '\0' }
};
String::memo_t String::oom_memo = {
2, 0, 0, const_cast<char *>(&oom_string_data) MEMO_INITIALIZER_TAIL
2, 0, 0 MEMO_INITIALIZER_TAIL, { '\0' }
};

const String::rep_t String::null_string_rep = {
&null_string_data, 0, &null_memo
null_memo.real_data, 0, &null_memo
};
const String::rep_t String::oom_string_rep = {
&oom_string_data, 0, &oom_memo
oom_memo.real_data, 0, &oom_memo
};

#if HAVE_STRING_PROFILING
Expand All @@ -105,20 +103,18 @@ String::memo_t *String::live_memos[55];

/** @cond never */
String::memo_t *
String::create_memo(char *data, int dirty, int capacity)
String::create_memo(char *space, int dirty, int capacity)
{
assert(capacity > 0 && capacity >= dirty);
memo_t *memo = new memo_t;
memo_t *memo;
if (space)
memo = reinterpret_cast<memo_t *>(space);
else
memo = (memo_t *) CLICK_LALLOC(MEMO_SPACE + capacity);
if (memo) {
if (data)
memo->real_data = data;
else if (!(memo->real_data = (char *) CLICK_LALLOC(capacity))) {
delete memo;
return 0;
}
memo->capacity = capacity;
memo->dirty = dirty;
memo->refcount = (data ? 0 : 1);
memo->refcount = (space ? 0 : 1);
#if HAVE_STRING_PROFILING
int bucket = profile_memo_size_bucket(dirty, capacity);
++memo_sizes[bucket];
Expand All @@ -139,8 +135,10 @@ String::create_memo(char *data, int dirty, int capacity)
void
String::delete_memo(memo_t *memo)
{
assert(memo->capacity > 0 && memo->capacity >= memo->dirty);
CLICK_LFREE(memo->real_data, memo->capacity);
assert(memo->capacity > 0);
if (memo->capacity < memo->dirty)
click_chatter("%.*s %d %d\n", memo->capacity,memo->real_data, memo->dirty, memo->capacity);
assert(memo->capacity >= memo->dirty);
#if HAVE_STRING_PROFILING
int bucket = profile_memo_size_bucket(memo->dirty, memo->capacity);
--live_memo_sizes[bucket];
Expand All @@ -151,7 +149,7 @@ String::delete_memo(memo_t *memo)
memo->next->pprev = memo->pprev;
# endif
#endif
delete memo;
CLICK_LFREE(memo, MEMO_SPACE + memo->capacity);
}


Expand Down Expand Up @@ -313,10 +311,8 @@ String
String::make_claim(char *str, int len, int capacity)
{
assert(str && len > 0 && capacity >= len);
if (memo_t *new_memo = create_memo(str, len, capacity))
return String(str, len, new_memo);
else
return String(&oom_string_data, 0, &oom_memo);
memo_t *new_memo = create_memo(str - MEMO_SPACE, len, capacity);
return String(str, len, new_memo);
}

String
Expand Down Expand Up @@ -384,13 +380,13 @@ String::assign(const char *str, int len, bool need_deref)
}

if (len == 0) {
_r.memo = (str == &oom_string_data ? &oom_memo : &null_memo);
_r.memo = (str == oom_memo.real_data ? &oom_memo : &null_memo);
atomic_uint32_t::inc(_r.memo->refcount);

} else {
// Make 'capacity' a multiple of 16 characters and bigger than 'len'.
int capacity = (len + 16) & ~15;
_r.memo = create_memo(0, len, capacity);
// Make the memo a multiple of 16 characters and bigger than 'len'.
int memo_capacity = (len + 15 + MEMO_SPACE) & ~15;
_r.memo = create_memo(0, len, memo_capacity - MEMO_SPACE);
if (!_r.memo) {
assign_out_of_memory();
return;
Expand Down Expand Up @@ -426,22 +422,26 @@ String::append_garbage(int len)
}
}

// Now we have to make new space. Make sure the new capacity is a
// multiple of 16 characters and that it is at least 16. But for large
// strings, allocate a power of 2, since power-of-2 sizes minimize waste
// in frequently-used allocators, like Linux kmalloc.
int new_capacity = (_r.length + len < 1024 ? (_r.length + 16) & ~15 : 1024);
while (new_capacity < _r.length + len)
new_capacity *= 2;
// Now we have to make new space. Make sure the memo is a multiple of 16
// bytes and that it is at least 16. But for large strings, allocate a
// power of 2, since power-of-2 sizes minimize waste in frequently-used
// allocators, like Linux kmalloc.
int want_memo_len = _r.length + len + MEMO_SPACE;
int memo_capacity;
if (want_memo_len <= 1024)
memo_capacity = (want_memo_len + 15) & ~15;
else
for (memo_capacity = 2048; memo_capacity < want_memo_len; )
memo_capacity *= 2;

#if CLICK_DMALLOC
// Keep total allocation a power of 2 by leaving extra space for the
// DMALLOC Chunk.
if (_r.length + len < new_capacity - 32)
new_capacity -= 32;
if (want_memo_len < memo_capacity - 32)
memo_capacity -= 32;
#endif

memo_t *new_memo = create_memo(0, _r.length + len, new_capacity);
memo_t *new_memo = create_memo(0, _r.length + len, memo_capacity - MEMO_SPACE);
if (!new_memo) {
assign_out_of_memory();
return 0;
Expand All @@ -467,7 +467,7 @@ String::append(const char *s, int len)
} else if (len < 0)
len = strlen(s);

if (s == &oom_string_data)
if (s == oom_memo.real_data)
// Appending "out of memory" to a regular string makes it "out of
// memory"
assign_out_of_memory();
Expand Down Expand Up @@ -794,7 +794,7 @@ String::equals(const char *s, int len) const
else if (_r.data == s)
return true;
else if (len == 0)
return (s != &oom_string_data && _r.memo != &oom_memo);
return (s != oom_memo.real_data && _r.memo != &oom_memo);
else
return memcmp(_r.data, s, len) == 0;
}
Expand All @@ -810,7 +810,7 @@ String::starts_with(const char *s, int len) const
else if (_r.data == s)
return true;
else if (len == 0)
return (s != &oom_string_data && _r.memo != &oom_memo);
return (s != oom_memo.real_data && _r.memo != &oom_memo);
else
return memcmp(_r.data, s, len) == 0;
}
Expand All @@ -824,7 +824,7 @@ String::compare(const char *s, int len) const
return _r.length - len;
else if (_r.memo == &oom_memo)
return 1;
else if (s == &oom_string_data)
else if (s == oom_memo.real_data)
return -1;
else if (_r.length == len)
return memcmp(_r.data, s, len);
Expand Down

0 comments on commit 20c4be6

Please sign in to comment.