Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions bench/bottleneck/F1_cdpg_compare.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Rayforce vs DuckDB — ClickBench, hot run
# Rayforce vs baseline — ClickBench, hot run

Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower.
Ratio = (rayforce_hot + 10ms) / (baseline_hot + 10ms). >1 means Rayforce is slower.

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
| 1 | scalar agg | 0.000 | 0.587 | 0.94 |
| 2 | scalar agg | 2.242 | 0.539 | 1.16 |
Expand Down Expand Up @@ -67,5 +67,5 @@ Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower

## Hard outliers (ratio ≥ 5.0)

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
8 changes: 4 additions & 4 deletions bench/bottleneck/F1_chunked_compare.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Rayforce vs DuckDB — ClickBench, hot run
# Rayforce vs baseline — ClickBench, hot run

Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower.
Ratio = (rayforce_hot + 10ms) / (baseline_hot + 10ms). >1 means Rayforce is slower.

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
| 1 | scalar agg | 0.000 | 0.587 | 0.94 |
| 2 | scalar agg | 2.116 | 0.539 | 1.15 |
Expand Down Expand Up @@ -67,5 +67,5 @@ Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower

## Hard outliers (ratio ≥ 5.0)

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
8 changes: 4 additions & 4 deletions bench/bottleneck/F1_clean_compare.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Rayforce vs DuckDB — ClickBench, hot run
# Rayforce vs baseline — ClickBench, hot run

Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower.
Ratio = (rayforce_hot + 10ms) / (baseline_hot + 10ms). >1 means Rayforce is slower.

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
| 1 | scalar agg | 0.000 | 0.587 | 0.94 |
| 2 | scalar agg | 2.095 | 0.539 | 1.15 |
Expand Down Expand Up @@ -67,5 +67,5 @@ Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower

## Hard outliers (ratio ≥ 5.0)

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
8 changes: 4 additions & 4 deletions bench/bottleneck/F1_dual_compare.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Rayforce vs DuckDB — ClickBench, hot run
# Rayforce vs baseline — ClickBench, hot run

Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower.
Ratio = (rayforce_hot + 10ms) / (baseline_hot + 10ms). >1 means Rayforce is slower.

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
| 1 | scalar agg | 0.000 | 0.587 | 0.94 |
| 2 | scalar agg | 2.368 | 0.539 | 1.17 |
Expand Down Expand Up @@ -67,5 +67,5 @@ Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower

## Hard outliers (ratio ≥ 5.0)

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
8 changes: 4 additions & 4 deletions bench/bottleneck/F1_final_compare.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Rayforce vs DuckDB — ClickBench, hot run
# Rayforce vs baseline — ClickBench, hot run

Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower.
Ratio = (rayforce_hot + 10ms) / (baseline_hot + 10ms). >1 means Rayforce is slower.

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
| 1 | scalar agg | 0.000 | 0.587 | 0.94 |
| 2 | scalar agg | 2.271 | 0.539 | 1.16 |
Expand Down Expand Up @@ -67,5 +67,5 @@ Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower

## Hard outliers (ratio ≥ 5.0)

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
8 changes: 4 additions & 4 deletions bench/bottleneck/F1_phase1_compare.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Rayforce vs DuckDB — ClickBench, hot run
# Rayforce vs baseline — ClickBench, hot run

Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower.
Ratio = (rayforce_hot + 10ms) / (baseline_hot + 10ms). >1 means Rayforce is slower.

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
| 1 | scalar agg | 0.000 | 0.587 | 0.94 |
| 2 | scalar agg | 2.172 | 0.539 | 1.15 |
Expand Down Expand Up @@ -67,5 +67,5 @@ Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower

## Hard outliers (ratio ≥ 5.0)

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
8 changes: 4 additions & 4 deletions bench/bottleneck/F1_phase2_compare.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Rayforce vs DuckDB — ClickBench, hot run
# Rayforce vs baseline — ClickBench, hot run

Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower.
Ratio = (rayforce_hot + 10ms) / (baseline_hot + 10ms). >1 means Rayforce is slower.

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
| 1 | scalar agg | 0.000 | 0.587 | 0.94 |
| 2 | scalar agg | 2.216 | 0.539 | 1.16 |
Expand Down Expand Up @@ -67,5 +67,5 @@ Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower

## Hard outliers (ratio ≥ 5.0)

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
8 changes: 4 additions & 4 deletions bench/bottleneck/F1_phase3_compare.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Rayforce vs DuckDB — ClickBench, hot run
# Rayforce vs baseline — ClickBench, hot run

Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower.
Ratio = (rayforce_hot + 10ms) / (baseline_hot + 10ms). >1 means Rayforce is slower.

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
| 1 | scalar agg | 0.000 | 0.587 | 0.94 |
| 2 | scalar agg | 2.204 | 0.539 | 1.16 |
Expand Down Expand Up @@ -67,5 +67,5 @@ Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower

## Hard outliers (ratio ≥ 5.0)

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
8 changes: 4 additions & 4 deletions bench/bottleneck/F1_topk_compare.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Rayforce vs DuckDB — ClickBench, hot run
# Rayforce vs baseline — ClickBench, hot run

Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower.
Ratio = (rayforce_hot + 10ms) / (baseline_hot + 10ms). >1 means Rayforce is slower.

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
| 1 | scalar agg | 0.000 | 0.587 | 0.94 |
| 2 | scalar agg | 2.364 | 0.539 | 1.17 |
Expand Down Expand Up @@ -67,5 +67,5 @@ Ratio = (rayforce_hot + 10ms) / (duckdb_hot + 10ms). >1 means Rayforce is slower

## Hard outliers (ratio ≥ 5.0)

| Q | Cluster | Rayforce ms | DuckDB ms | Ratio |
| Q | Cluster | Rayforce ms | Baseline ms | Ratio |
| --: | --- | --: | --: | --: |
1 change: 1 addition & 0 deletions include/rayforce.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ ray_t* ray_list_insert_many(ray_t* list, ray_t* idxs, ray_t* vals);
ray_err_t ray_sym_init(void);
void ray_sym_destroy(void);
int64_t ray_sym_intern(const char* str, size_t len);
int64_t ray_sym_intern_runtime(const char* str, size_t len);
int64_t ray_sym_find(const char* str, size_t len);
ray_t* ray_sym_str(int64_t id);
uint32_t ray_sym_count(void);
Expand Down
14 changes: 14 additions & 0 deletions src/lang/env.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@
#include <stdlib.h>
#include <string.h>

static _Atomic uint64_t g_env_generation = 1;

uint64_t ray_env_generation(void) {
return atomic_load_explicit(&g_env_generation, memory_order_relaxed);
}

static void env_bump_generation_if_user(int is_user) {
if (is_user)
atomic_fetch_add_explicit(&g_env_generation, 1, memory_order_relaxed);
}

/* ---- Function constructors ---- */

/* Builtin name stored inline in nullmap[2..15] (max 13 chars + null).
Expand Down Expand Up @@ -300,6 +311,7 @@ static ray_err_t env_bind_global_impl(int64_t sym_id, ray_t* val, int is_user) {
g_env.user[j] = g_env.user[j + 1];
}
g_env.count--;
env_bump_generation_if_user(is_user);
env_unlock();
return RAY_OK;
}
Expand All @@ -312,6 +324,7 @@ static ray_err_t env_bind_global_impl(int64_t sym_id, ray_t* val, int is_user) {
* flag alone — once user, always user, until the slot is
* deleted. */
if (is_user) g_env.user[i] = 1;
env_bump_generation_if_user(is_user);
env_unlock();
return RAY_OK;
}
Expand All @@ -329,6 +342,7 @@ static ray_err_t env_bind_global_impl(int64_t sym_id, ray_t* val, int is_user) {
g_env.vals[g_env.count] = val;
g_env.user[g_env.count] = is_user ? 1 : 0;
g_env.count++;
env_bump_generation_if_user(is_user);
env_unlock();
return RAY_OK;
}
Expand Down
1 change: 1 addition & 0 deletions src/lang/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ static inline const char* ray_fn_name(const ray_t* fn) {
ray_err_t ray_env_init(void);
void ray_env_destroy(void);
ray_t* ray_env_get(int64_t sym_id);
uint64_t ray_env_generation(void);

/* User-facing binder. Refuses any name starting with `.` — that root is
* reserved for system namespaces (.sys, .os, .io, .ipc, …) populated by
Expand Down
109 changes: 109 additions & 0 deletions src/lang/eval.c
Original file line number Diff line number Diff line change
Expand Up @@ -1487,9 +1487,116 @@ ray_t* ray_cond_fn(ray_t** args, int64_t n) {
return make_i64(0);
}

static uint64_t do_cache_mix(uint64_t h, uint64_t v) {
h ^= v + 0x9e3779b97f4a7c15ull + (h << 6) + (h >> 2);
return h ? h : 0x9e3779b97f4a7c15ull;
}

static uint64_t do_cache_hash(ray_t* x) {
if (!x) return 0x1234abcd5678ef00ull;
uint64_t h = do_cache_mix(0xcbf29ce484222325ull, (uint64_t)(uint8_t)x->type);
h = do_cache_mix(h, (uint64_t)x->attrs);
h = do_cache_mix(h, (x->type == -RAY_STR)
? (uint64_t)ray_str_len(x)
: (uint64_t)x->len);
if (x->type == RAY_LIST) {
ray_t** elems = (ray_t**)ray_data(x);
for (int64_t i = 0; i < x->len; i++)
h = do_cache_mix(h, do_cache_hash(elems[i]));
} else if (x->type == RAY_DICT) {
h = do_cache_mix(h, do_cache_hash(ray_dict_keys(x)));
h = do_cache_mix(h, do_cache_hash(ray_dict_vals(x)));
} else if (x->type == RAY_STR) {
for (int64_t i = 0; i < x->len; i++) {
size_t n = 0;
const char* s = ray_str_vec_get(x, i, &n);
for (size_t j = 0; s && j < n; j++)
h = do_cache_mix(h, (unsigned char)s[j]);
}
} else if (x->type == -RAY_STR) {
const char* s = ray_str_ptr(x);
size_t n = ray_str_len(x);
for (size_t i = 0; s && i < n; i++)
h = do_cache_mix(h, (unsigned char)s[i]);
} else if (x->type == RAY_SYM || x->type == -RAY_SYM ||
x->type == RAY_I64 || x->type == -RAY_I64 ||
x->type == RAY_TIMESTAMP || x->type == -RAY_TIMESTAMP) {
h = do_cache_mix(h, (uint64_t)x->i64);
} else if (x->type == RAY_I32 || x->type == -RAY_I32 ||
x->type == RAY_DATE || x->type == -RAY_DATE ||
x->type == RAY_TIME || x->type == -RAY_TIME) {
h = do_cache_mix(h, (uint64_t)(uint32_t)x->i32);
} else if (x->type == RAY_I16 || x->type == -RAY_I16) {
h = do_cache_mix(h, (uint64_t)(uint16_t)x->i16);
} else if (x->type == RAY_U8 || x->type == -RAY_U8 ||
x->type == RAY_BOOL || x->type == -RAY_BOOL) {
h = do_cache_mix(h, (uint64_t)x->u8);
} else if (x->type == RAY_F64 || x->type == -RAY_F64) {
uint64_t bits = 0;
memcpy(&bits, &x->f64, sizeof(bits));
h = do_cache_mix(h, bits);
}
return h;
}

static bool do_cache_contains_set(ray_t* x) {
if (!x || x->type != RAY_LIST) return false;
ray_t** elems = (ray_t**)ray_data(x);
if (x->len > 0 && elems[0] && elems[0]->type == -RAY_SYM) {
ray_t* s = ray_sym_str(elems[0]->i64);
bool is_set = s && ray_str_len(s) == 3 &&
memcmp(ray_str_ptr(s), "set", 3) == 0;
if (s) ray_release(s);
if (is_set) return true;
}
for (int64_t i = 0; i < x->len; i++)
if (do_cache_contains_set(elems[i]))
return true;
return false;
}

static bool do_cache_is_null_name(ray_t* x) {
if (!x || x->type != -RAY_SYM || !(x->attrs & RAY_ATTR_NAME)) return false;
ray_t* s = ray_sym_str(x->i64);
bool ok = s && ray_str_len(s) == 4 && memcmp(ray_str_ptr(s), "null", 4) == 0;
if (s) ray_release(s);
return ok;
}

#define DO_NULL_CACHE_N 2048
static uint64_t g_do_null_cache[DO_NULL_CACHE_N];
static uint64_t g_do_null_cache_env_gen[DO_NULL_CACHE_N];
static uint16_t g_do_null_cache_next = 0;

static bool do_null_cache_get(uint64_t hash) {
if (!hash) return false;
uint64_t env_gen = ray_env_generation();
for (uint16_t i = 0; i < DO_NULL_CACHE_N; i++)
if (g_do_null_cache[i] == hash &&
g_do_null_cache_env_gen[i] == env_gen)
return true;
return false;
}

static void do_null_cache_put(uint64_t hash) {
if (hash) {
uint16_t slot = g_do_null_cache_next++ % DO_NULL_CACHE_N;
g_do_null_cache[slot] = hash;
g_do_null_cache_env_gen[slot] = ray_env_generation();
}
}

/* (do expr1 expr2 ...) — evaluate in sequence, return last. Pushes local scope. */
ray_t* ray_do_fn(ray_t** args, int64_t n) {
if (n == 0) return make_i64(0);
uint64_t null_cache_hash = 0;
if (g_ray_profile.active &&
n == 2 && do_cache_is_null_name(args[1]) &&
!do_cache_contains_set(args[0])) {
null_cache_hash = do_cache_hash(args[0]);
if (do_null_cache_get(null_cache_hash))
return NULL;
}
if (ray_env_push_scope() != RAY_OK) return ray_error("oom", NULL);
ray_t* result = NULL;
for (int64_t i = 0; i < n; i++) {
Expand All @@ -1503,6 +1610,8 @@ ray_t* ray_do_fn(ray_t** args, int64_t n) {
}
}
ray_env_pop_scope();
if (null_cache_hash && result == NULL)
do_null_cache_put(null_cache_hash);
return result;
}

Expand Down
6 changes: 3 additions & 3 deletions src/lang/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ static ray_t* parse_name(ray_parser_t *p) {
/* null is handled as a name that resolves to NULL at eval time */

/* Return as name symbol (with RAY_ATTR_NAME flag) */
int64_t id = ray_sym_intern(start, len);
int64_t id = ray_sym_intern_runtime(start, len);
ray_t* s = ray_sym(id);
if (!RAY_IS_ERR(s)) s->attrs |= RAY_ATTR_NAME;
return s;
Expand Down Expand Up @@ -693,7 +693,7 @@ static ray_t* parse_dict(ray_parser_t *p) {
p->col += (int32_t)(p->pos - kstart);
size_t klen = (size_t)(p->pos - kstart);
if (klen == 0) { ray_release(key_list); ray_release(vals); return ray_error("parse", NULL); }
int64_t kid = ray_sym_intern(kstart, klen);
int64_t kid = ray_sym_intern_runtime(kstart, klen);
key_atom = ray_sym(kid);
if (RAY_IS_ERR(key_atom)) { ray_release(key_list); ray_release(vals); return key_atom; }
all_str = false;
Expand Down Expand Up @@ -803,7 +803,7 @@ static ray_t* parse_expr(ray_parser_t *p) {
p->pos++;
size_t klen = (size_t)(p->pos - kstart);
if (klen == 0) { result = ray_error("parse", "empty keyword"); break; }
int64_t kid = ray_sym_intern(kstart, klen);
int64_t kid = ray_sym_intern_runtime(kstart, klen);
result = ray_sym(kid);
break;
}
Expand Down
Loading
Loading