perf: faster builds, leaner daemon, smoother install/run (0.9.20)
Reuse libcstcore.a for tests with -MMD incremental deps; idle-backoff the parliament seat loop; defer curl init and cache settings; add systemd helper. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+27
-4
@@ -139,6 +139,26 @@ int cst_discover_local_put(const char *realm_fp, const char *instance_id,
|
||||
arr = cJSON_CreateArray();
|
||||
cJSON_AddItemToObject(root, "instances", arr);
|
||||
}
|
||||
time_t now = time(NULL);
|
||||
const cJSON *it;
|
||||
cJSON_ArrayForEach(it, arr) {
|
||||
const cJSON *iid = cJSON_GetObjectItemCaseSensitive(it, "iid");
|
||||
const cJSON *rid = cJSON_GetObjectItemCaseSensitive(it, "rid");
|
||||
const cJSON *port = cJSON_GetObjectItemCaseSensitive(it, "port");
|
||||
const cJSON *updated = cJSON_GetObjectItemCaseSensitive(it, "updated");
|
||||
if (!cJSON_IsString(iid) || strcmp(iid->valuestring, instance_id) != 0)
|
||||
continue;
|
||||
if (cJSON_IsString(rid) && !strcmp(rid->valuestring, realm_fp) &&
|
||||
cJSON_IsNumber(port) && port->valueint == peer_port &&
|
||||
cJSON_IsNumber(updated) &&
|
||||
now - (time_t)updated->valuedouble < 60) {
|
||||
/* Same seat advertisement still fresh — skip disk rewrite. */
|
||||
cJSON_Delete(root);
|
||||
pthread_mutex_unlock(&local_mu);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
local_remove_iid(arr, instance_id);
|
||||
cJSON *row = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(row, "rid", realm_fp);
|
||||
@@ -146,7 +166,7 @@ int cst_discover_local_put(const char *realm_fp, const char *instance_id,
|
||||
cJSON_AddStringToObject(row, "name", name ? name : "");
|
||||
cJSON_AddNumberToObject(row, "port", peer_port);
|
||||
cJSON_AddNumberToObject(row, "pid", (double)os_getpid());
|
||||
cJSON_AddNumberToObject(row, "updated", (double)time(NULL));
|
||||
cJSON_AddNumberToObject(row, "updated", (double)now);
|
||||
cJSON_AddItemToArray(arr, row);
|
||||
int rc = save_local(root);
|
||||
cJSON_Delete(root);
|
||||
@@ -283,12 +303,15 @@ static void *discover_main(void *arg) {
|
||||
cst_discover_t *d = arg;
|
||||
int ticks = 0;
|
||||
while (!d->stop) {
|
||||
if ((ticks++ % 10) == 0) {
|
||||
/* ~100ms recv timeout: beacon every ~5s, rewrite local registry ~60s. */
|
||||
if ((ticks % 50) == 0) {
|
||||
send_beacon(d);
|
||||
(void)cst_discover_local_put(d->realm_fp, d->instance_id, d->name,
|
||||
d->peer_port);
|
||||
if ((ticks / 50) % 12 == 0)
|
||||
(void)cst_discover_local_put(d->realm_fp, d->instance_id, d->name,
|
||||
d->peer_port);
|
||||
ingest_local(d);
|
||||
}
|
||||
ticks++;
|
||||
if (d->sock == DISC_BAD) {
|
||||
struct timespec ts = {0, 100 * 1000 * 1000};
|
||||
nanosleep(&ts, NULL);
|
||||
|
||||
+6
-1
@@ -20,7 +20,12 @@ void cst_extensions_wait(FILE *log) {
|
||||
cst_mcp_counts(&ready, &total);
|
||||
if (total == 0)
|
||||
return;
|
||||
cst_mcp_wait_ready(30000);
|
||||
/* Default 8s (was 30s); override with CST_MCP_WAIT_MS. */
|
||||
const char *e = getenv("CST_MCP_WAIT_MS");
|
||||
int ms = e && atoi(e) >= 0 ? atoi(e) : 8000;
|
||||
if (ms > 60000)
|
||||
ms = 60000;
|
||||
cst_mcp_wait_ready(ms);
|
||||
cst_mcp_info_t info[CST_MCP_MAX];
|
||||
int n = cst_mcp_info(info, CST_MCP_MAX);
|
||||
for (int i = 0; log && i < n; i++) {
|
||||
|
||||
+54
-36
@@ -22,6 +22,21 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* Defer libcurl init: --version / --login / parliament CLI need none of it. */
|
||||
static int g_curl_ready;
|
||||
static void cst_curl_ensure(void) {
|
||||
if (!g_curl_ready) {
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
g_curl_ready = 1;
|
||||
}
|
||||
}
|
||||
static void cst_curl_cleanup(void) {
|
||||
if (g_curl_ready) {
|
||||
curl_global_cleanup();
|
||||
g_curl_ready = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(const char *argv0) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s [options] (works in the current directory)\n"
|
||||
@@ -311,7 +326,6 @@ int main(int argc, char **argv) {
|
||||
"1903 or later is required); non-ASCII text may break\n");
|
||||
os_set_prog_path(argv[0]);
|
||||
os_temp_dir_export();
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
|
||||
cst_agent_config_t cfg = {0};
|
||||
char cwd[4096];
|
||||
@@ -532,7 +546,7 @@ int main(int argc, char **argv) {
|
||||
case 'r':
|
||||
if (cst_protocol_parse(optarg, &cfg.protocol) != 0) {
|
||||
fprintf(stderr, "unknown protocol: %s\n", optarg);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
@@ -545,7 +559,7 @@ int main(int argc, char **argv) {
|
||||
if (cst_tool_profile_parse(optarg, &cfg.tool_profile) != 0) {
|
||||
fprintf(stderr, "unknown tool profile: %s (default | minimal)\n",
|
||||
optarg);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
@@ -580,14 +594,14 @@ int main(int argc, char **argv) {
|
||||
case 'A':
|
||||
if (cst_approval_parse(optarg, &approval) != 0) {
|
||||
fprintf(stderr, "bad --approval %s (ask | auto | yolo)\n", optarg);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
if (parse_confirm(optarg, &cfg) != 0) {
|
||||
fprintf(stderr, "bad --confirm %s (shell,write,net | none)\n", optarg);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
@@ -595,7 +609,7 @@ int main(int argc, char **argv) {
|
||||
if (!cst_effort_valid(optarg)) {
|
||||
fprintf(stderr, "bad --effort %s (low | medium | high | max)\n",
|
||||
optarg);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
snprintf(cfg.effort, sizeof(cfg.effort), "%s", optarg);
|
||||
@@ -603,21 +617,22 @@ int main(int argc, char **argv) {
|
||||
case 'M':
|
||||
if (!cst_mode_valid(optarg)) {
|
||||
fprintf(stderr, "bad --mode %s (coding | general)\n", optarg);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
snprintf(cfg.mode, sizeof(cfg.mode), "%s", optarg);
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 0;
|
||||
case 0x100: {
|
||||
const char *only = optarg;
|
||||
if (!only && optind < argc && argv[optind][0] != '-')
|
||||
only = argv[optind++];
|
||||
cst_curl_ensure();
|
||||
int rc = list_models(only);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
case 0x101:
|
||||
@@ -626,7 +641,7 @@ int main(int argc, char **argv) {
|
||||
case 0x102:
|
||||
if (parse_port(optarg, &web.port) != 0) {
|
||||
fprintf(stderr, "--web-port %s is not a port (0-65535)\n", optarg);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
web_mode = 1;
|
||||
@@ -652,30 +667,30 @@ int main(int argc, char **argv) {
|
||||
break;
|
||||
case 'V':
|
||||
printf("cst-agent %s\n", CST_VERSION);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 0;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_migrate) {
|
||||
int rc = migrate_store(cfg.workspace_root);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (do_realm_new) {
|
||||
int rc = cst_parliament_cli_realm_new();
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
if (do_realm_pw_init) {
|
||||
const char *pw = getenv("CST_REALM_PASSWORD");
|
||||
int rc = cst_parliament_cli_realm_password_init(pw);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
if (do_login) {
|
||||
@@ -687,17 +702,17 @@ int main(int argc, char **argv) {
|
||||
iid = iidbuf;
|
||||
}
|
||||
int rc = cst_parliament_cli_login(pw, iid, realm_label, discover_peer_port);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
if (do_new_project) {
|
||||
int rc = cst_parliament_cli_new_project(new_project_id);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
if (do_service_stop) {
|
||||
int rc = cst_parliament_cli_service_stop();
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
if (do_service || do_service_fg) {
|
||||
@@ -710,12 +725,12 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
int rc = cst_parliament_cli_service(pw, iid, discover_peer_port,
|
||||
do_service_fg);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
if (do_realm_enroll) {
|
||||
int rc = cst_parliament_cli_realm_enroll(realm_enroll_id, realm_label);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
if (do_peer_listen) {
|
||||
@@ -723,7 +738,7 @@ int main(int argc, char **argv) {
|
||||
if (!iid)
|
||||
iid = getenv("CST_INSTANCE_ID");
|
||||
int rc = cst_parliament_cli_peer_listen(peer_listen_port, iid);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
if (do_peer_dial) {
|
||||
@@ -743,13 +758,13 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
int rc = cst_parliament_cli_peer_dial(host, port, iid);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
if (do_discover) {
|
||||
const char *iid = parliament_instance ? parliament_instance : getenv("CST_INSTANCE_ID");
|
||||
int rc = cst_parliament_cli_discover(iid, discover_peer_port, discover_wait_ms);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -778,7 +793,7 @@ int main(int argc, char **argv) {
|
||||
fprintf(stderr, "%s\n", err[0] ? err : "login required");
|
||||
if (pw == pwbuf)
|
||||
memset(pwbuf, 0, sizeof(pwbuf));
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
free(hand);
|
||||
@@ -792,7 +807,7 @@ int main(int argc, char **argv) {
|
||||
fprintf(stderr,
|
||||
"password Realm active: run --login (or set "
|
||||
"CST_REALM_PASSWORD) before opening the agent\n");
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -800,10 +815,13 @@ int main(int argc, char **argv) {
|
||||
|
||||
if (do_list) {
|
||||
int rc = list_sessions(cfg.workspace_root);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Agent / TUI / WebUI / headless need libcurl; parliament CLI above does not. */
|
||||
cst_curl_ensure();
|
||||
|
||||
/* Explicit option > environment > last used (settings.json) > preset. */
|
||||
cst_settings_t saved;
|
||||
cst_settings_load(&saved);
|
||||
@@ -815,7 +833,7 @@ int main(int argc, char **argv) {
|
||||
prov = cst_provider_find(provider_name);
|
||||
if (!prov) {
|
||||
fprintf(stderr, "unknown provider: %s\n", provider_name);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -894,7 +912,7 @@ int main(int argc, char **argv) {
|
||||
if (rc != 0 || cst_agent_store_path_for_id(cfg.workspace_root, id,
|
||||
cfg.session_path,
|
||||
sizeof(cfg.session_path)) != 0) {
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
cst_agent_store_set_current(cfg.workspace_root, id);
|
||||
@@ -906,7 +924,7 @@ int main(int argc, char **argv) {
|
||||
sizeof(id)) != 0) {
|
||||
fprintf(stderr, "failed to init .agent/sessions under %s\n",
|
||||
cfg.workspace_root);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
fprintf(stderr, "session %s\n", id);
|
||||
@@ -914,7 +932,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
if (do_demo) {
|
||||
int rc = demo_ctl_impl(cfg.workspace_root);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -924,7 +942,7 @@ int main(int argc, char **argv) {
|
||||
if (cst_creds_prompt_console(cfg.provider, cfg.api_key,
|
||||
sizeof(cfg.api_key)) != 0) {
|
||||
fprintf(stderr, "no API key entered\n");
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
char dir[1024] = "the config directory";
|
||||
@@ -936,7 +954,7 @@ int main(int argc, char **argv) {
|
||||
dir);
|
||||
/* --ask-key alone: save and exit */
|
||||
if (force_ask_key && !cfg.headless && !prompt) {
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -945,7 +963,7 @@ int main(int argc, char **argv) {
|
||||
"no API key for %s: start cst-agent once to enter it, or run "
|
||||
"cst-agent --ask-key --provider %s\n",
|
||||
cfg.provider, cfg.provider);
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
/* Router presets have no fixed model: take the first one the API lists
|
||||
@@ -968,7 +986,7 @@ int main(int argc, char **argv) {
|
||||
} else {
|
||||
fprintf(stderr, "no model for %s: pass --model (%s)\n", cfg.provider,
|
||||
err[0] ? err : "the API listed none");
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -989,7 +1007,7 @@ int main(int argc, char **argv) {
|
||||
cst_agent_t *agent = cst_agent_create(&cfg);
|
||||
if (!agent) {
|
||||
fprintf(stderr, "failed to create agent (session path?)\n");
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1021,6 +1039,6 @@ int main(int argc, char **argv) {
|
||||
|
||||
cst_agent_destroy(agent);
|
||||
cst_extensions_unload();
|
||||
curl_global_cleanup();
|
||||
cst_curl_cleanup();
|
||||
return rc;
|
||||
}
|
||||
|
||||
+22
-12
@@ -272,33 +272,43 @@ int cst_parliament_daemon_run(const char *password, const char *instance_id,
|
||||
signal(SIGHUP, on_sig);
|
||||
#endif
|
||||
g_stop = 0;
|
||||
int tick = 0;
|
||||
int tick = 0, idle = 0;
|
||||
while (!g_stop) {
|
||||
cst_peer_session_t sess;
|
||||
char herr[128];
|
||||
if (cst_peer_accept((intptr_t)ls, &cert, sk, realm.pk, 500, &sess, herr,
|
||||
sizeof(herr)) == 0) {
|
||||
/* Accept wait backs off when idle so a quiet seat barely wakes. */
|
||||
int accept_ms = idle > 20 ? 2000 : idle > 5 ? 1000 : 400;
|
||||
if (cst_peer_accept((intptr_t)ls, &cert, sk, realm.pk, accept_ms, &sess,
|
||||
herr, sizeof(herr)) == 0) {
|
||||
sync_on_session(&sess);
|
||||
cst_peer_close(&sess);
|
||||
idle = 0;
|
||||
} else {
|
||||
idle++;
|
||||
}
|
||||
int push = cst_parliament_sync_pending();
|
||||
tick++;
|
||||
if ((push || tick % 10 == 0) && disc) {
|
||||
/* Dial peers on push, or periodically (slower while idle). */
|
||||
int period = idle > 20 ? 45 : idle > 5 ? 20 : 8;
|
||||
if ((push || tick % period == 0) && disc) {
|
||||
cst_peer_info_t peers[16];
|
||||
int n = cst_discover_peers(disc, peers, 16);
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (peers[i].port <= 0)
|
||||
continue;
|
||||
if (cst_peer_dial(peers[i].host, peers[i].port, &cert, sk, realm.pk,
|
||||
3000, &sess, herr, sizeof(herr)) == 0) {
|
||||
sync_on_session(&sess);
|
||||
cst_peer_close(&sess);
|
||||
if (n > 0 || push) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (peers[i].port <= 0)
|
||||
continue;
|
||||
if (cst_peer_dial(peers[i].host, peers[i].port, &cert, sk, realm.pk,
|
||||
3000, &sess, herr, sizeof(herr)) == 0) {
|
||||
sync_on_session(&sess);
|
||||
cst_peer_close(&sess);
|
||||
idle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (push)
|
||||
cst_parliament_sync_ack();
|
||||
}
|
||||
sleep_ms(200);
|
||||
/* No extra sleep: accept_ms already paced the loop. */
|
||||
}
|
||||
if (disc)
|
||||
cst_discover_stop(disc);
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
static int settings_path(char *out, size_t n) {
|
||||
char dir[OS_PATH_MAX];
|
||||
@@ -20,11 +22,32 @@ static void copy_str(char *dst, size_t n, const cJSON *v) {
|
||||
snprintf(dst, n, "%s", v->valuestring);
|
||||
}
|
||||
|
||||
static struct {
|
||||
int valid;
|
||||
time_t mtime;
|
||||
off_t size;
|
||||
cst_settings_t s;
|
||||
} g_settings_cache;
|
||||
|
||||
static void settings_cache_invalidate(void) {
|
||||
g_settings_cache.valid = 0;
|
||||
g_settings_cache.mtime = 0;
|
||||
g_settings_cache.size = 0;
|
||||
}
|
||||
|
||||
int cst_settings_load(cst_settings_t *s) {
|
||||
memset(s, 0, sizeof(*s));
|
||||
char path[OS_PATH_MAX];
|
||||
if (settings_path(path, sizeof(path)) != 0)
|
||||
return -1;
|
||||
struct stat st;
|
||||
int have_st = stat(path, &st) == 0;
|
||||
if (have_st && g_settings_cache.valid &&
|
||||
g_settings_cache.mtime == st.st_mtime &&
|
||||
g_settings_cache.size == st.st_size) {
|
||||
*s = g_settings_cache.s;
|
||||
return 0;
|
||||
}
|
||||
FILE *fp = fopen(path, "rb");
|
||||
if (!fp)
|
||||
return -1;
|
||||
@@ -94,10 +117,19 @@ int cst_settings_load(cst_settings_t *s) {
|
||||
s->nparams++;
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
if (!have_st)
|
||||
have_st = stat(path, &st) == 0;
|
||||
if (have_st) {
|
||||
g_settings_cache.s = *s;
|
||||
g_settings_cache.mtime = st.st_mtime;
|
||||
g_settings_cache.size = st.st_size;
|
||||
g_settings_cache.valid = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cst_settings_save(const cst_settings_t *s) {
|
||||
settings_cache_invalidate();
|
||||
char dir[OS_PATH_MAX], path[OS_PATH_MAX], tmp[OS_PATH_MAX + 8];
|
||||
if (os_config_dir(dir, sizeof(dir)) != 0 || os_mkdir_p(dir, 0700) != 0 ||
|
||||
settings_path(path, sizeof(path)) != 0)
|
||||
|
||||
Reference in New Issue
Block a user