Skip to content

Commit

Permalink
Make compaction available for Oj::Doc (#650)
Browse files Browse the repository at this point in the history
* reformat fast.c

Formatting done using VSCode's C extension and using tabular indent.

https://lea.verou.me/2012/01/why-tabs-are-clearly-superior/

Signed-off-by: Ulysse Buonomo <buonomo.ulysse@gmail.com>

* Make compaction available for `Oj::Doc`

Introduce compaction to `fast.c`, only if `rb_gc_mark_movable` is
available. Otherwise, keep a version that supports ruby <2.7.

Since `rb_data_object_wrap` and `TypedData_Wrap_Struct` is available
in every supported versions (eg >=2.4.10), I've also removed support
for earlier versions.

Result for compaction is great. I've tested it by allocating and
removing arbitrary sized json. For a count of 70 pages, we can see
that we used to need 68 pages after compaction,and now 61 pages. Of
course this test include also lots of noise, but if we count pinned
objects (objects that are marked in C extension as uncollectible),
we can see that for a benchmark with no allocations, we have the
same amount as a benchmark with this commit with thousands of allocations
(499 pinned objects total), and before this, `Oj::Doc` used to generate
5k more objects (5499 pinned objects total).

Hence this is a win, see PR for a graphical result.

Signed-off-by: Ulysse Buonomo <buonomo.ulysse@gmail.com>

* Fix formatting rules

Using a `.clang-format` file, we fixed formatting rules to make sur they
fit as much as possible current existing code, while still fixing spaces
and tabs mixing issues.

Signed-off-by: Ulysse Buonomo <buonomo.ulysse@gmail.com>

* Apply formatting rules for every c files

Signed-off-by: Ulysse Buonomo <buonomo.ulysse@gmail.com>
  • Loading branch information
BuonOmo committed Apr 8, 2021
1 parent a4f4590 commit 33c6dd3
Show file tree
Hide file tree
Showing 55 changed files with 10,584 additions and 10,211 deletions.
7 changes: 7 additions & 0 deletions .clang-format
@@ -0,0 +1,7 @@
BasedOnStyle: Mozilla
IndentWidth: 4
BreakBeforeBraces: Attach
ColumnLimit: 0
AlwaysBreakAfterReturnType: AllDefinitions
DerivePointerAlignment: false
PointerAlignment: Right
4 changes: 4 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,9 @@
# CHANGELOG

## Ongoing

- Added support for `GC.compact` on `Oj::Doc`

## 3.11.3 - 2021-03-09

- Fixed `respond_to?` method on `Oj::EasyHash`.
Expand Down
1 change: 0 additions & 1 deletion Rakefile
Expand Up @@ -92,4 +92,3 @@ begin

rescue LoadError
end

54 changes: 27 additions & 27 deletions ext/oj/buf.h
Expand Up @@ -6,11 +6,11 @@
#include "ruby.h"

typedef struct _buf {
char *head;
char *end;
char *tail;
char base[1024];
} *Buf;
char *head;
char *end;
char *tail;
char base[1024];
} * Buf;

inline static void
buf_init(Buf buf) {
Expand All @@ -34,18 +34,18 @@ buf_len(Buf buf) {
inline static void
buf_append_string(Buf buf, const char *s, size_t slen) {
if (buf->end <= buf->tail + slen) {
size_t len = buf->end - buf->head;
size_t toff = buf->tail - buf->head;
size_t new_len = len + slen + len / 2;
size_t len = buf->end - buf->head;
size_t toff = buf->tail - buf->head;
size_t new_len = len + slen + len / 2;

if (buf->base == buf->head) {
buf->head = ALLOC_N(char, new_len);
memcpy(buf->head, buf->base, len);
} else {
REALLOC_N(buf->head, char, new_len);
}
buf->tail = buf->head + toff;
buf->end = buf->head + new_len - 1;
if (buf->base == buf->head) {
buf->head = ALLOC_N(char, new_len);
memcpy(buf->head, buf->base, len);
} else {
REALLOC_N(buf->head, char, new_len);
}
buf->tail = buf->head + toff;
buf->end = buf->head + new_len - 1;
}
memcpy(buf->tail, s, slen);
buf->tail += slen;
Expand All @@ -54,18 +54,18 @@ buf_append_string(Buf buf, const char *s, size_t slen) {
inline static void
buf_append(Buf buf, char c) {
if (buf->end <= buf->tail) {
size_t len = buf->end - buf->head;
size_t toff = buf->tail - buf->head;
size_t new_len = len + len / 2;
size_t len = buf->end - buf->head;
size_t toff = buf->tail - buf->head;
size_t new_len = len + len / 2;

if (buf->base == buf->head) {
buf->head = ALLOC_N(char, new_len);
memcpy(buf->head, buf->base, len);
} else {
REALLOC_N(buf->head, char, new_len);
}
buf->tail = buf->head + toff;
buf->end = buf->head + new_len - 1;
if (buf->base == buf->head) {
buf->head = ALLOC_N(char, new_len);
memcpy(buf->head, buf->base, len);
} else {
REALLOC_N(buf->head, char, new_len);
}
buf->tail = buf->head + toff;
buf->end = buf->head + new_len - 1;
}
*buf->tail = c;
buf->tail++;
Expand Down
92 changes: 46 additions & 46 deletions ext/oj/cache8.c
@@ -1,40 +1,40 @@
// Copyright (c) 2011 Peter Ohler. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for license details.

#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

#include "ruby.h"
#include "cache8.h"
#include "ruby.h"

#define BITS 4
#define MASK 0x000000000000000FULL
#define SLOT_CNT 16
#define DEPTH 16
#define BITS 4
#define MASK 0x000000000000000FULL
#define SLOT_CNT 16
#define DEPTH 16

typedef union {
struct _cache8 *child;
slot_t value;
struct _cache8 *child;
slot_t value;
} Bucket;

struct _cache8 {
Bucket buckets[SLOT_CNT];
Bucket buckets[SLOT_CNT];
};

static void cache8_delete(Cache8 cache, int depth);
static void slot_print(Cache8 cache, sid_t key, unsigned int depth);
static void cache8_delete(Cache8 cache, int depth);
static void slot_print(Cache8 cache, sid_t key, unsigned int depth);

void
oj_cache8_new(Cache8 *cache) {
Bucket *b;
int i;
Bucket *b;
int i;

*cache = ALLOC(struct _cache8);
for (i = SLOT_CNT, b = (*cache)->buckets; 0 < i; i--, b++) {
b->value = 0;
b->value = 0;
}
}

Expand All @@ -45,33 +45,33 @@ oj_cache8_delete(Cache8 cache) {

static void
cache8_delete(Cache8 cache, int depth) {
Bucket *b;
unsigned int i;
Bucket *b;
unsigned int i;

for (i = 0, b = cache->buckets; i < SLOT_CNT; i++, b++) {
if (0 != b->child) {
if (DEPTH - 1 != depth) {
cache8_delete(b->child, depth + 1);
}
}
if (0 != b->child) {
if (DEPTH - 1 != depth) {
cache8_delete(b->child, depth + 1);
}
}
}
xfree(cache);
}

slot_t
oj_cache8_get(Cache8 cache, sid_t key, slot_t **slot) {
Bucket *b;
int i;
sid_t k8 = (sid_t)key;
sid_t k;
Bucket *b;
int i;
sid_t k8 = (sid_t)key;
sid_t k;

for (i = 64 - BITS; 0 < i; i -= BITS) {
k = (k8 >> i) & MASK;
b = cache->buckets + k;
if (0 == b->child) {
oj_cache8_new(&b->child);
}
cache = b->child;
k = (k8 >> i) & MASK;
b = cache->buckets + k;
if (0 == b->child) {
oj_cache8_new(&b->child);
}
cache = b->child;
}
*slot = &(cache->buckets + (k8 & MASK))->value;

Expand All @@ -86,24 +86,24 @@ oj_cache8_print(Cache8 cache) {

static void
slot_print(Cache8 c, sid_t key, unsigned int depth) {
Bucket *b;
unsigned int i;
sid_t k8 = (sid_t)key;
sid_t k;
Bucket *b;
unsigned int i;
sid_t k8 = (sid_t)key;
sid_t k;

for (i = 0, b = c->buckets; i < SLOT_CNT; i++, b++) {
if (0 != b->child) {
k = (k8 << BITS) | i;
/*printf("*** key: 0x%016llx depth: %u i: %u\n", k, depth, i); */
if (DEPTH - 1 == depth) {
if (0 != b->child) {
k = (k8 << BITS) | i;
/*printf("*** key: 0x%016llx depth: %u i: %u\n", k, depth, i); */
if (DEPTH - 1 == depth) {
#if IS_WINDOWS
printf("0x%016lx: %4lu\n", (long unsigned int)k, (long unsigned int)b->value);
printf("0x%016lx: %4lu\n", (long unsigned int)k, (long unsigned int)b->value);
#else
printf("0x%016llx: %4llu\n", (long long unsigned int)k, (long long unsigned int)b->value);
printf("0x%016llx: %4llu\n", (long long unsigned int)k, (long long unsigned int)b->value);
#endif
} else {
slot_print(b->child, k, depth + 1);
}
}
} else {
slot_print(b->child, k, depth + 1);
}
}
}
}
14 changes: 7 additions & 7 deletions ext/oj/cache8.h
Expand Up @@ -7,15 +7,15 @@
#include "ruby.h"
#include "stdint.h"

typedef struct _cache8 *Cache8;
typedef uint64_t slot_t;
typedef uint64_t sid_t;
typedef struct _cache8 *Cache8;
typedef uint64_t slot_t;
typedef uint64_t sid_t;

extern void oj_cache8_new(Cache8 *cache);
extern void oj_cache8_delete(Cache8 cache);
extern void oj_cache8_new(Cache8 *cache);
extern void oj_cache8_delete(Cache8 cache);

extern slot_t oj_cache8_get(Cache8 cache, sid_t key, slot_t **slot);
extern slot_t oj_cache8_get(Cache8 cache, sid_t key, slot_t **slot);

extern void oj_cache8_print(Cache8 cache);
extern void oj_cache8_print(Cache8 cache);

#endif /* OJ_CACHE8_H */
52 changes: 26 additions & 26 deletions ext/oj/circarray.c
Expand Up @@ -5,10 +5,10 @@

CircArray
oj_circ_array_new() {
CircArray ca;
CircArray ca;

if (0 == (ca = ALLOC(struct _circArray))) {
rb_raise(rb_eNoMemError, "not enough memory\n");
rb_raise(rb_eNoMemError, "not enough memory\n");
}
ca->objs = ca->obj_array;
ca->size = sizeof(ca->obj_array) / sizeof(VALUE);
Expand All @@ -20,46 +20,46 @@ oj_circ_array_new() {
void
oj_circ_array_free(CircArray ca) {
if (ca->objs != ca->obj_array) {
xfree(ca->objs);
xfree(ca->objs);
}
xfree(ca);
}

void
oj_circ_array_set(CircArray ca, VALUE obj, unsigned long id) {
if (0 < id && 0 != ca) {
unsigned long i;
unsigned long i;

if (ca->size < id) {
unsigned long cnt = id + 512;
if (ca->size < id) {
unsigned long cnt = id + 512;

if (ca->objs == ca->obj_array) {
if (0 == (ca->objs = ALLOC_N(VALUE, cnt))) {
rb_raise(rb_eNoMemError, "not enough memory\n");
}
memcpy(ca->objs, ca->obj_array, sizeof(VALUE) * ca->cnt);
} else {
REALLOC_N(ca->objs, VALUE, cnt);
}
ca->size = cnt;
}
id--;
for (i = ca->cnt; i < id; i++) {
ca->objs[i] = Qnil;
}
ca->objs[id] = obj;
if (ca->cnt <= id) {
ca->cnt = id + 1;
}
if (ca->objs == ca->obj_array) {
if (0 == (ca->objs = ALLOC_N(VALUE, cnt))) {
rb_raise(rb_eNoMemError, "not enough memory\n");
}
memcpy(ca->objs, ca->obj_array, sizeof(VALUE) * ca->cnt);
} else {
REALLOC_N(ca->objs, VALUE, cnt);
}
ca->size = cnt;
}
id--;
for (i = ca->cnt; i < id; i++) {
ca->objs[i] = Qnil;
}
ca->objs[id] = obj;
if (ca->cnt <= id) {
ca->cnt = id + 1;
}
}
}

VALUE
oj_circ_array_get(CircArray ca, unsigned long id) {
VALUE obj = Qnil;
VALUE obj = Qnil;

if (id <= ca->cnt && 0 != ca) {
obj = ca->objs[id - 1];
obj = ca->objs[id - 1];
}
return obj;
}
18 changes: 9 additions & 9 deletions ext/oj/circarray.h
Expand Up @@ -7,15 +7,15 @@
#include "ruby.h"

typedef struct _circArray {
VALUE obj_array[1024];
VALUE *objs;
unsigned long size; // allocated size or initial array size
unsigned long cnt;
} *CircArray;
VALUE obj_array[1024];
VALUE *objs;
unsigned long size; // allocated size or initial array size
unsigned long cnt;
} * CircArray;

extern CircArray oj_circ_array_new(void);
extern void oj_circ_array_free(CircArray ca);
extern void oj_circ_array_set(CircArray ca, VALUE obj, unsigned long id);
extern VALUE oj_circ_array_get(CircArray ca, unsigned long id);
extern CircArray oj_circ_array_new(void);
extern void oj_circ_array_free(CircArray ca);
extern void oj_circ_array_set(CircArray ca, VALUE obj, unsigned long id);
extern VALUE oj_circ_array_get(CircArray ca, unsigned long id);

#endif /* OJ_CIRCARRAY_H */

0 comments on commit 33c6dd3

Please sign in to comment.