new models
This commit is contained in:
parent
60832b51cf
commit
ad90295e0d
13 changed files with 617 additions and 102 deletions
|
|
@ -5,7 +5,12 @@ model: opencode/nemotron-3-ultra-free
|
|||
temperature: 0.1
|
||||
permission:
|
||||
edit: deny
|
||||
bash: deny
|
||||
bash:
|
||||
"*": deny
|
||||
"rg *": allow
|
||||
"git grep*": allow
|
||||
"git diff*": allow
|
||||
"sed -n *": allow
|
||||
task: deny
|
||||
---
|
||||
|
||||
|
|
|
|||
79
.opencode/agents/lardon-build-backup-router.md
Normal file
79
.opencode/agents/lardon-build-backup-router.md
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
---
|
||||
description: Reprend un build complexe via OpenRouter lorsque Google ou Zen sont indisponibles
|
||||
mode: subagent
|
||||
model: openrouter/nvidia/nemotron-3-ultra-550b-a55b:free
|
||||
temperature: 0.1
|
||||
permission:
|
||||
edit:
|
||||
"*": allow
|
||||
"scan3d/**": deny
|
||||
bash:
|
||||
"*": deny
|
||||
"rg *": allow
|
||||
"git grep*": allow
|
||||
"git status*": allow
|
||||
"git diff*": allow
|
||||
"git log*": allow
|
||||
"sed -n *": allow
|
||||
"CC=clang meson setup *": allow
|
||||
"meson setup *": allow
|
||||
"meson compile *": allow
|
||||
"meson test *": allow
|
||||
"ninja *": allow
|
||||
"git diff --check*": allow
|
||||
task: deny
|
||||
---
|
||||
|
||||
Tu es le deuxième agent de secours pour l'implémentation de Lardon3D.
|
||||
|
||||
Tu interviens uniquement lorsqu'un ticket est déjà préparé et que le build
|
||||
principal ou le premier backup sont indisponibles.
|
||||
|
||||
Commence par lire :
|
||||
|
||||
- `.opencode/work/current_ticket.md` ;
|
||||
- le diff courant ;
|
||||
- uniquement les fichiers explicitement cités dans le handoff.
|
||||
|
||||
Ne refais pas l'exploration ou l'architecture si le handoff contient déjà les
|
||||
informations nécessaires.
|
||||
|
||||
Ne charge jamais tout le dépôt.
|
||||
|
||||
Ne lance jamais :
|
||||
|
||||
- `pwd`
|
||||
- `ls`
|
||||
- `find`
|
||||
- glob global
|
||||
- lecture complète de la documentation
|
||||
|
||||
Respecte strictement :
|
||||
|
||||
- l'objectif du ticket ;
|
||||
- les contraintes ;
|
||||
- les API existantes ;
|
||||
- les invariants ;
|
||||
- le périmètre de fichiers indiqué.
|
||||
|
||||
Ne crée aucune fonctionnalité supplémentaire.
|
||||
|
||||
Ne modifie jamais `scan3d/`.
|
||||
|
||||
Ne fais aucun commit.
|
||||
Ne fais aucun push.
|
||||
|
||||
Après implémentation :
|
||||
|
||||
- exécute uniquement les validations demandées par le ticket ;
|
||||
- ne tente pas de corriger un autre problème découvert hors périmètre ;
|
||||
- signale-le seulement.
|
||||
|
||||
À la fin, rapporte uniquement :
|
||||
|
||||
- modification exacte ;
|
||||
- fichiers modifiés ;
|
||||
- validations exécutées ;
|
||||
- erreurs éventuelles ;
|
||||
- limites restantes ;
|
||||
- prochaine action sûre.
|
||||
|
|
@ -1,12 +1,26 @@
|
|||
---
|
||||
description: Reprend les tickets complexes interrompus sans refaire l'analyse
|
||||
mode: subagent
|
||||
model: opencode/nemotron-3-ultra-free
|
||||
model: opencode/deepseek-v4-flash-free
|
||||
temperature: 0.1
|
||||
permission:
|
||||
edit:
|
||||
"*": allow
|
||||
"scan3d/**": deny
|
||||
bash:
|
||||
"*": deny
|
||||
"rg *": allow
|
||||
"git grep*": allow
|
||||
"git status*": allow
|
||||
"git diff*": allow
|
||||
"git log*": allow
|
||||
"sed -n *": allow
|
||||
"CC=clang meson setup *": allow
|
||||
"meson setup *": allow
|
||||
"meson compile *": allow
|
||||
"meson test *": allow
|
||||
"ninja *": allow
|
||||
"git diff --check*": allow
|
||||
task: deny
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,20 @@ permission:
|
|||
edit:
|
||||
"*": allow
|
||||
"scan3d/**": deny
|
||||
bash:
|
||||
"*": deny
|
||||
"rg *": allow
|
||||
"git grep*": allow
|
||||
"git status*": allow
|
||||
"git diff*": allow
|
||||
"git log*": allow
|
||||
"sed -n *": allow
|
||||
"CC=clang meson setup *": allow
|
||||
"meson setup *": allow
|
||||
"meson compile *": allow
|
||||
"meson test *": allow
|
||||
"ninja *": allow
|
||||
"git diff --check*": allow
|
||||
task: deny
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,26 @@
|
|||
---
|
||||
description: Implémente seul les tickets complexes Lardon3D
|
||||
mode: subagent
|
||||
model: opencode/deepseek-v4-flash-free
|
||||
model: google/gemini-3.6-flash
|
||||
temperature: 0.1
|
||||
permission:
|
||||
edit:
|
||||
"*": allow
|
||||
"scan3d/**": deny
|
||||
bash:
|
||||
"*": deny
|
||||
"rg *": allow
|
||||
"git grep*": allow
|
||||
"git status*": allow
|
||||
"git diff*": allow
|
||||
"git log*": allow
|
||||
"sed -n *": allow
|
||||
"CC=clang meson setup *": allow
|
||||
"meson setup *": allow
|
||||
"meson compile *": allow
|
||||
"meson test *": allow
|
||||
"ninja *": allow
|
||||
"git diff --check*": allow
|
||||
task: deny
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,12 @@ permission:
|
|||
edit: deny
|
||||
bash:
|
||||
"*": deny
|
||||
"git diff*": allow
|
||||
"rg *": allow
|
||||
"git grep*": allow
|
||||
"git status*": allow
|
||||
"git diff*": allow
|
||||
"git log*": allow
|
||||
"sed -n *": allow
|
||||
task: deny
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ permission:
|
|||
"*": deny
|
||||
"rg *": allow
|
||||
"git grep*": allow
|
||||
"git status*": allow
|
||||
"git diff*": allow
|
||||
"sed -n *": allow
|
||||
task: deny
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ permission:
|
|||
"*": deny
|
||||
"lardon-build": allow
|
||||
"lardon-build-backup": allow
|
||||
"lardon-build-backup-router": allow
|
||||
"lardon-build-light": allow
|
||||
"lardon-architect": allow
|
||||
"lardon-explore": allow
|
||||
|
|
@ -70,6 +71,21 @@ Cette règle s’applique même si le ticket ne crée aucun nouveau thread.
|
|||
- fichiers concernés ;
|
||||
- API et invariants ;
|
||||
- tests requis.
|
||||
|
||||
Chaîne d'implémentation :
|
||||
|
||||
1. Utiliser `lardon-build` pour l'implémentation normale.
|
||||
2. Si `lardon-build` échoue pour indisponibilité du fournisseur, quota ou erreur
|
||||
429/503, conserver le handoff et utiliser `lardon-build-backup`.
|
||||
3. Si le premier backup est lui-même indisponible, utiliser
|
||||
`lardon-build-backup-router`.
|
||||
4. Ne jamais recommencer l'exploration ou l'architecture lors d'un fallback si
|
||||
le handoff contient déjà les informations nécessaires.
|
||||
5. Ne jamais basculer vers un modèle payant.
|
||||
|
||||
Un fallback ne doit modifier ni l'objectif, ni le périmètre, ni les invariants
|
||||
du ticket.
|
||||
|
||||
7. Mettre à jour le handoff après chaque phase importante.
|
||||
|
||||
Le répertoire `.opencode/work/` est préparé localement. Ne vérifie pas son
|
||||
|
|
|
|||
|
|
@ -7,8 +7,12 @@ permission:
|
|||
edit: deny
|
||||
bash:
|
||||
"*": deny
|
||||
"git diff*": allow
|
||||
"rg *": allow
|
||||
"git grep*": allow
|
||||
"git status*": allow
|
||||
"git diff*": allow
|
||||
"git log*": allow
|
||||
"sed -n *": allow
|
||||
task: deny
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,11 @@ permission:
|
|||
bash:
|
||||
"*": deny
|
||||
"CC=clang meson setup *": allow
|
||||
"meson setup *": allow
|
||||
"meson compile *": allow
|
||||
"meson test *": allow
|
||||
"ninja *": allow
|
||||
"git diff --check*": allow
|
||||
"git diff*": allow
|
||||
"git status*": allow
|
||||
task: deny
|
||||
---
|
||||
|
|
|
|||
|
|
@ -83,8 +83,11 @@ bool lardon3d_task_execution_contract(
|
|||
);
|
||||
/* Libère la réservation courante, en obtient une nouvelle auprès du gouverneur
|
||||
* et met à jour le contrat. À appeler uniquement depuis le callback en cours
|
||||
* d'exécution. Retourne false si pause/annulation est demandée ou si le
|
||||
* gouverneur répond WAIT/REJECT (la tâche passe alors en échec). */
|
||||
* d'exécution. Une réponse WAIT du gouverneur est une indisponibilité
|
||||
* temporaire : la fonction attend un changement de ressources puis retente
|
||||
* l'admission sans échouer la tâche. Retourne false si la tâche est annulée
|
||||
* (TASK_CANCELLED), si le gouverneur répond REJECT ou en cas d'erreur interne
|
||||
* (TASK_FAILED). */
|
||||
bool lardon3d_task_sequence_break(
|
||||
Lardon3DTask *task,
|
||||
Lardon3DResourceGovernor *governor,
|
||||
|
|
|
|||
202
src/task.c
202
src/task.c
|
|
@ -278,6 +278,11 @@ lardon3d_task_checkpoint(Lardon3DTask *task)
|
|||
return continuing;
|
||||
}
|
||||
|
||||
enum {
|
||||
/* Attente bornée entre deux tentatives d'admission : 50 ms. */
|
||||
LARDON3D_SEQUENCE_ADMISSION_WAIT_NS = 50000000ULL,
|
||||
};
|
||||
|
||||
bool
|
||||
lardon3d_task_sequence_break(
|
||||
Lardon3DTask *task,
|
||||
|
|
@ -302,6 +307,7 @@ lardon3d_task_sequence_break(
|
|||
(void)pthread_cond_wait(&task->condition, &task->mutex);
|
||||
}
|
||||
if (task->cancel_requested) {
|
||||
finish_locked(task, TASK_CANCELLED, "Tâche annulée.");
|
||||
(void)pthread_mutex_unlock(&task->mutex);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -314,95 +320,121 @@ lardon3d_task_sequence_break(
|
|||
(void)lardon3d_resource_governor_release(governor, previous);
|
||||
}
|
||||
|
||||
Lardon3DResourceDecision decision;
|
||||
Lardon3DResourceReservation *next = NULL;
|
||||
bool reserved = lardon3d_resource_governor_reserve_available(
|
||||
governor,
|
||||
&task->estimate,
|
||||
&decision,
|
||||
&next
|
||||
);
|
||||
for (;;) {
|
||||
/* Vérifier pause et annulation avant chaque tentative d'admission. */
|
||||
(void)pthread_mutex_lock(&task->mutex);
|
||||
while (task->pause_requested && !task->cancel_requested) {
|
||||
task->state = TASK_PAUSED;
|
||||
copy_text(task->message, sizeof(task->message), "Tâche en pause.");
|
||||
(void)pthread_cond_broadcast(&task->condition);
|
||||
(void)pthread_cond_wait(&task->condition, &task->mutex);
|
||||
}
|
||||
if (task->cancel_requested) {
|
||||
finish_locked(task, TASK_CANCELLED, "Tâche annulée.");
|
||||
(void)pthread_mutex_unlock(&task->mutex);
|
||||
return false;
|
||||
}
|
||||
task->state = TASK_RUNNING;
|
||||
(void)pthread_mutex_unlock(&task->mutex);
|
||||
|
||||
(void)pthread_mutex_lock(&task->mutex);
|
||||
if (task->cancel_requested) {
|
||||
if (next) {
|
||||
(void)lardon3d_resource_governor_release(governor, next);
|
||||
}
|
||||
finish_locked(
|
||||
task,
|
||||
TASK_CANCELLED,
|
||||
"Tâche annulée pendant sequence_break."
|
||||
);
|
||||
(void)pthread_mutex_unlock(&task->mutex);
|
||||
return false;
|
||||
}
|
||||
while (task->pause_requested && !task->cancel_requested) {
|
||||
task->state = TASK_PAUSED;
|
||||
copy_text(task->message, sizeof(task->message), "Tâche en pause.");
|
||||
(void)pthread_cond_broadcast(&task->condition);
|
||||
(void)pthread_cond_wait(&task->condition, &task->mutex);
|
||||
}
|
||||
if (task->cancel_requested) {
|
||||
if (next) {
|
||||
(void)lardon3d_resource_governor_release(governor, next);
|
||||
}
|
||||
finish_locked(task, TASK_CANCELLED, "Tâche annulée.");
|
||||
(void)pthread_mutex_unlock(&task->mutex);
|
||||
return false;
|
||||
}
|
||||
if (!reserved || !next) {
|
||||
task->current_reservation = NULL;
|
||||
finish_locked(
|
||||
task,
|
||||
TASK_FAILED,
|
||||
"Impossible de réserver les ressources de la séquence."
|
||||
);
|
||||
(void)pthread_mutex_unlock(&task->mutex);
|
||||
return false;
|
||||
}
|
||||
if (decision.kind == LARDON3D_RESOURCE_WAIT
|
||||
|| decision.kind == LARDON3D_RESOURCE_REJECT) {
|
||||
task->current_reservation = NULL;
|
||||
finish_locked(
|
||||
task,
|
||||
TASK_FAILED,
|
||||
decision.reason[0] ? decision.reason
|
||||
: "Ressources impossibles à réserver."
|
||||
);
|
||||
(void)pthread_mutex_unlock(&task->mutex);
|
||||
return false;
|
||||
}
|
||||
Lardon3DResourceReservationInfo information;
|
||||
if (!lardon3d_resource_reservation_get_active(
|
||||
uint64_t generation = lardon3d_resource_governor_generation(governor);
|
||||
Lardon3DResourceDecision decision;
|
||||
Lardon3DResourceReservation *next = NULL;
|
||||
bool admitted = lardon3d_resource_governor_reserve_available(
|
||||
governor,
|
||||
next,
|
||||
&information
|
||||
)) {
|
||||
(void)lardon3d_resource_governor_release(governor, next);
|
||||
task->current_reservation = NULL;
|
||||
finish_locked(
|
||||
task,
|
||||
TASK_FAILED,
|
||||
"Réservation de séquence invalide."
|
||||
&task->estimate,
|
||||
&decision,
|
||||
&next
|
||||
);
|
||||
(void)pthread_mutex_unlock(&task->mutex);
|
||||
return false;
|
||||
if (!admitted) {
|
||||
/* Erreur interne : échec d'allocation ou d'instantané. */
|
||||
(void)pthread_mutex_lock(&task->mutex);
|
||||
task->current_reservation = NULL;
|
||||
finish_locked(
|
||||
task,
|
||||
TASK_FAILED,
|
||||
"Impossible de réserver les ressources de la séquence."
|
||||
);
|
||||
(void)pthread_mutex_unlock(&task->mutex);
|
||||
return false;
|
||||
}
|
||||
switch (decision.kind) {
|
||||
case LARDON3D_RESOURCE_START:
|
||||
case LARDON3D_RESOURCE_REDUCE_BATCH: {
|
||||
if (!next) {
|
||||
(void)pthread_mutex_lock(&task->mutex);
|
||||
task->current_reservation = NULL;
|
||||
finish_locked(
|
||||
task,
|
||||
TASK_FAILED,
|
||||
"Réservation de séquence invalide."
|
||||
);
|
||||
(void)pthread_mutex_unlock(&task->mutex);
|
||||
return false;
|
||||
}
|
||||
Lardon3DResourceReservationInfo information;
|
||||
if (!lardon3d_resource_reservation_get_active(
|
||||
governor,
|
||||
next,
|
||||
&information
|
||||
)) {
|
||||
(void)lardon3d_resource_governor_release(governor, next);
|
||||
(void)pthread_mutex_lock(&task->mutex);
|
||||
task->current_reservation = NULL;
|
||||
finish_locked(
|
||||
task,
|
||||
TASK_FAILED,
|
||||
"Réservation de séquence invalide."
|
||||
);
|
||||
(void)pthread_mutex_unlock(&task->mutex);
|
||||
return false;
|
||||
}
|
||||
(void)pthread_mutex_lock(&task->mutex);
|
||||
task->current_reservation = next;
|
||||
task->contract = (Lardon3DTaskExecutionContract) {
|
||||
.batch_size = information.batch_size,
|
||||
.memory_bytes = information.memory_bytes,
|
||||
.gpu_memory_bytes = information.gpu_memory_bytes,
|
||||
.cpu_threads = information.cpu_threads,
|
||||
.gpu_slots = information.gpu_slots,
|
||||
.io_slots = information.io_slots,
|
||||
};
|
||||
task->has_contract = true;
|
||||
++task->sequence_count;
|
||||
*out_reservation = next;
|
||||
*out_contract = task->contract;
|
||||
(void)pthread_mutex_unlock(&task->mutex);
|
||||
return true;
|
||||
}
|
||||
case LARDON3D_RESOURCE_REJECT:
|
||||
if (next) {
|
||||
(void)lardon3d_resource_governor_release(governor, next);
|
||||
}
|
||||
(void)pthread_mutex_lock(&task->mutex);
|
||||
task->current_reservation = NULL;
|
||||
finish_locked(
|
||||
task,
|
||||
TASK_FAILED,
|
||||
decision.reason[0] ? decision.reason
|
||||
: "Ressources impossibles à réserver."
|
||||
);
|
||||
(void)pthread_mutex_unlock(&task->mutex);
|
||||
return false;
|
||||
case LARDON3D_RESOURCE_WAIT:
|
||||
default:
|
||||
/* Indisponibilité temporaire : ne pas échouer, attendre un
|
||||
* changement de ressources puis retenter l'admission. */
|
||||
if (next) {
|
||||
(void)lardon3d_resource_governor_release(governor, next);
|
||||
}
|
||||
(void)lardon3d_resource_governor_wait_for_change(
|
||||
governor,
|
||||
generation,
|
||||
LARDON3D_SEQUENCE_ADMISSION_WAIT_NS
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
task->current_reservation = next;
|
||||
task->contract = (Lardon3DTaskExecutionContract) {
|
||||
.batch_size = information.batch_size,
|
||||
.memory_bytes = information.memory_bytes,
|
||||
.gpu_memory_bytes = information.gpu_memory_bytes,
|
||||
.cpu_threads = information.cpu_threads,
|
||||
.gpu_slots = information.gpu_slots,
|
||||
.io_slots = information.io_slots,
|
||||
};
|
||||
task->has_contract = true;
|
||||
++task->sequence_count;
|
||||
*out_reservation = next;
|
||||
*out_contract = task->contract;
|
||||
(void)pthread_mutex_unlock(&task->mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
|
|
|
|||
|
|
@ -28,7 +28,14 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
Lardon3DResourceGovernor *governor;
|
||||
} WaitContext;
|
||||
pthread_mutex_t sync_mutex;
|
||||
pthread_cond_t sync_cond;
|
||||
bool in_break;
|
||||
} WaitRetryContext;
|
||||
|
||||
typedef struct {
|
||||
Lardon3DResourceGovernor *governor;
|
||||
} RejectContext;
|
||||
|
||||
typedef struct {
|
||||
Lardon3DResourceGovernor *governor;
|
||||
|
|
@ -102,9 +109,27 @@ seq_callback(Lardon3DTask *task, void *userdata)
|
|||
}
|
||||
|
||||
static bool
|
||||
wait_callback(Lardon3DTask *task, void *userdata)
|
||||
wait_retry_callback(Lardon3DTask *task, void *userdata)
|
||||
{
|
||||
WaitContext *ctx = userdata;
|
||||
WaitRetryContext *ctx = userdata;
|
||||
(void)pthread_mutex_lock(&ctx->sync_mutex);
|
||||
ctx->in_break = true;
|
||||
(void)pthread_cond_broadcast(&ctx->sync_cond);
|
||||
(void)pthread_mutex_unlock(&ctx->sync_mutex);
|
||||
Lardon3DResourceReservation *reservation = NULL;
|
||||
Lardon3DTaskExecutionContract contract;
|
||||
return lardon3d_task_sequence_break(
|
||||
task,
|
||||
ctx->governor,
|
||||
&reservation,
|
||||
&contract
|
||||
);
|
||||
}
|
||||
|
||||
static bool
|
||||
reject_callback(Lardon3DTask *task, void *userdata)
|
||||
{
|
||||
RejectContext *ctx = userdata;
|
||||
Lardon3DResourceReservation *reservation = NULL;
|
||||
Lardon3DTaskExecutionContract contract;
|
||||
return lardon3d_task_sequence_break(
|
||||
|
|
@ -247,7 +272,7 @@ run_sequential_test(void)
|
|||
}
|
||||
|
||||
static bool
|
||||
run_wait_test(void)
|
||||
run_wait_retry_test(void)
|
||||
{
|
||||
const Lardon3DResourceEstimate estimate = {
|
||||
.minimum_batch_size = 1,
|
||||
|
|
@ -274,7 +299,6 @@ run_wait_test(void)
|
|||
Lardon3DResourceSnapshot resource_snapshot = {
|
||||
.memory_available_bytes = UINT64_MAX,
|
||||
.cpu_load_1m = 0.0,
|
||||
.io_pressure_known = false,
|
||||
};
|
||||
Lardon3DResourceDecision decision;
|
||||
Lardon3DResourceReservation *reservation;
|
||||
|
|
@ -285,11 +309,255 @@ run_wait_test(void)
|
|||
&decision,
|
||||
&reservation
|
||||
));
|
||||
WaitContext ctx = {.governor = governor};
|
||||
CHECK(reservation);
|
||||
WaitRetryContext ctx = {.governor = governor};
|
||||
CHECK(pthread_mutex_init(&ctx.sync_mutex, NULL) == 0);
|
||||
CHECK(pthread_cond_init(&ctx.sync_cond, NULL) == 0);
|
||||
Lardon3DTask *task = lardon3d_task_create(
|
||||
"Attente",
|
||||
"Attente puis reprise",
|
||||
&estimate,
|
||||
wait_callback,
|
||||
wait_retry_callback,
|
||||
&ctx
|
||||
);
|
||||
CHECK(task);
|
||||
StartContext start = {task, governor, reservation};
|
||||
pthread_t thread;
|
||||
CHECK(pthread_create(&thread, NULL, start_task, &start) == 0);
|
||||
(void)pthread_mutex_lock(&ctx.sync_mutex);
|
||||
while (!ctx.in_break) {
|
||||
(void)pthread_cond_wait(&ctx.sync_cond, &ctx.sync_mutex);
|
||||
}
|
||||
(void)pthread_mutex_unlock(&ctx.sync_mutex);
|
||||
/* Tant que la politique reste bloquante, le gouverneur répond WAIT :
|
||||
* la tâche doit rester en cours et ne jamais passer en échec. */
|
||||
Lardon3DTaskSnapshot snapshot;
|
||||
for (size_t attempt = 0; attempt < 50; ++attempt) {
|
||||
CHECK(lardon3d_task_snapshot(task, &snapshot));
|
||||
CHECK(snapshot.state == TASK_RUNNING);
|
||||
short_pause(1000000);
|
||||
}
|
||||
CHECK(lardon3d_task_sequence_count(task) == 0);
|
||||
/* Lever la contrainte : la prochaine tentative doit réussir. */
|
||||
Lardon3DResourcePolicy allowed = policy;
|
||||
allowed.maximum_io_pressure_avg10 = 100.0;
|
||||
CHECK(lardon3d_resource_governor_set_policy(governor, &allowed));
|
||||
CHECK(lardon3d_task_join(task));
|
||||
void *thread_result;
|
||||
CHECK(pthread_join(thread, &thread_result) == 0);
|
||||
CHECK((uintptr_t)thread_result == 1);
|
||||
CHECK(lardon3d_task_snapshot(task, &snapshot));
|
||||
CHECK(snapshot.state == TASK_COMPLETED);
|
||||
CHECK(lardon3d_task_sequence_count(task) == 1);
|
||||
CHECK(lardon3d_resource_governor_reservation_count(governor) == 0);
|
||||
lardon3d_task_destroy(task);
|
||||
(void)pthread_cond_destroy(&ctx.sync_cond);
|
||||
(void)pthread_mutex_destroy(&ctx.sync_mutex);
|
||||
lardon3d_resource_governor_destroy(governor);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
run_cancel_during_wait_test(void)
|
||||
{
|
||||
const Lardon3DResourceEstimate estimate = {
|
||||
.minimum_batch_size = 1,
|
||||
.maximum_batch_size = 100,
|
||||
.desired_cpu_threads = 1,
|
||||
.desired_io_slots = 1,
|
||||
};
|
||||
Lardon3DHardwareProfile profile = {
|
||||
.logical_cpu_count = 16,
|
||||
.page_size_bytes = 4096,
|
||||
.memory_total_bytes = UINT64_MAX,
|
||||
.cpu_architecture = "test",
|
||||
};
|
||||
Lardon3DResourcePolicy policy = {
|
||||
.maximum_cpu_load_ratio = 1.0,
|
||||
.maximum_io_pressure_avg10 = 0.0,
|
||||
.io_slot_capacity = 1,
|
||||
};
|
||||
Lardon3DResourceGovernor *governor = lardon3d_resource_governor_create(
|
||||
&profile,
|
||||
&policy
|
||||
);
|
||||
CHECK(governor);
|
||||
Lardon3DResourceSnapshot resource_snapshot = {
|
||||
.memory_available_bytes = UINT64_MAX,
|
||||
.cpu_load_1m = 0.0,
|
||||
};
|
||||
Lardon3DResourceDecision decision;
|
||||
Lardon3DResourceReservation *reservation;
|
||||
CHECK(lardon3d_resource_governor_reserve(
|
||||
governor,
|
||||
&resource_snapshot,
|
||||
&estimate,
|
||||
&decision,
|
||||
&reservation
|
||||
));
|
||||
CHECK(reservation);
|
||||
WaitRetryContext ctx = {.governor = governor};
|
||||
CHECK(pthread_mutex_init(&ctx.sync_mutex, NULL) == 0);
|
||||
CHECK(pthread_cond_init(&ctx.sync_cond, NULL) == 0);
|
||||
Lardon3DTask *task = lardon3d_task_create(
|
||||
"Annulation pendant attente",
|
||||
&estimate,
|
||||
wait_retry_callback,
|
||||
&ctx
|
||||
);
|
||||
CHECK(task);
|
||||
StartContext start = {task, governor, reservation};
|
||||
pthread_t thread;
|
||||
CHECK(pthread_create(&thread, NULL, start_task, &start) == 0);
|
||||
(void)pthread_mutex_lock(&ctx.sync_mutex);
|
||||
while (!ctx.in_break) {
|
||||
(void)pthread_cond_wait(&ctx.sync_cond, &ctx.sync_mutex);
|
||||
}
|
||||
(void)pthread_mutex_unlock(&ctx.sync_mutex);
|
||||
/* Annuler pendant que la tâche attend les ressources. */
|
||||
lardon3d_task_request_cancel(task);
|
||||
CHECK(lardon3d_task_join(task));
|
||||
CHECK(pthread_join(thread, NULL) == 0);
|
||||
Lardon3DTaskSnapshot snapshot;
|
||||
CHECK(lardon3d_task_snapshot(task, &snapshot));
|
||||
CHECK(snapshot.state == TASK_CANCELLED);
|
||||
CHECK(lardon3d_resource_governor_reservation_count(governor) == 0);
|
||||
lardon3d_task_destroy(task);
|
||||
(void)pthread_cond_destroy(&ctx.sync_cond);
|
||||
(void)pthread_mutex_destroy(&ctx.sync_mutex);
|
||||
lardon3d_resource_governor_destroy(governor);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
run_pause_during_wait_test(void)
|
||||
{
|
||||
const Lardon3DResourceEstimate estimate = {
|
||||
.minimum_batch_size = 1,
|
||||
.maximum_batch_size = 100,
|
||||
.desired_cpu_threads = 1,
|
||||
.desired_io_slots = 1,
|
||||
};
|
||||
Lardon3DHardwareProfile profile = {
|
||||
.logical_cpu_count = 16,
|
||||
.page_size_bytes = 4096,
|
||||
.memory_total_bytes = UINT64_MAX,
|
||||
.cpu_architecture = "test",
|
||||
};
|
||||
Lardon3DResourcePolicy policy = {
|
||||
.maximum_cpu_load_ratio = 1.0,
|
||||
.maximum_io_pressure_avg10 = 0.0,
|
||||
.io_slot_capacity = 1,
|
||||
};
|
||||
Lardon3DResourceGovernor *governor = lardon3d_resource_governor_create(
|
||||
&profile,
|
||||
&policy
|
||||
);
|
||||
CHECK(governor);
|
||||
Lardon3DResourceSnapshot resource_snapshot = {
|
||||
.memory_available_bytes = UINT64_MAX,
|
||||
.cpu_load_1m = 0.0,
|
||||
};
|
||||
Lardon3DResourceDecision decision;
|
||||
Lardon3DResourceReservation *reservation;
|
||||
CHECK(lardon3d_resource_governor_reserve(
|
||||
governor,
|
||||
&resource_snapshot,
|
||||
&estimate,
|
||||
&decision,
|
||||
&reservation
|
||||
));
|
||||
CHECK(reservation);
|
||||
WaitRetryContext ctx = {.governor = governor};
|
||||
CHECK(pthread_mutex_init(&ctx.sync_mutex, NULL) == 0);
|
||||
CHECK(pthread_cond_init(&ctx.sync_cond, NULL) == 0);
|
||||
Lardon3DTask *task = lardon3d_task_create(
|
||||
"Pause pendant attente",
|
||||
&estimate,
|
||||
wait_retry_callback,
|
||||
&ctx
|
||||
);
|
||||
CHECK(task);
|
||||
StartContext start = {task, governor, reservation};
|
||||
pthread_t thread;
|
||||
CHECK(pthread_create(&thread, NULL, start_task, &start) == 0);
|
||||
(void)pthread_mutex_lock(&ctx.sync_mutex);
|
||||
while (!ctx.in_break) {
|
||||
(void)pthread_cond_wait(&ctx.sync_cond, &ctx.sync_mutex);
|
||||
}
|
||||
(void)pthread_mutex_unlock(&ctx.sync_mutex);
|
||||
/* Mettre en pause pendant l'attente, puis reprendre. */
|
||||
CHECK(lardon3d_task_pause(task));
|
||||
CHECK(wait_for_state(task, TASK_PAUSED));
|
||||
CHECK(lardon3d_task_resume(task));
|
||||
CHECK(wait_for_state(task, TASK_RUNNING));
|
||||
/* Lever la contrainte : la tâche doit reprendre puis réussir. */
|
||||
Lardon3DResourcePolicy allowed = policy;
|
||||
allowed.maximum_io_pressure_avg10 = 100.0;
|
||||
CHECK(lardon3d_resource_governor_set_policy(governor, &allowed));
|
||||
CHECK(lardon3d_task_join(task));
|
||||
CHECK(pthread_join(thread, NULL) == 0);
|
||||
Lardon3DTaskSnapshot snapshot;
|
||||
CHECK(lardon3d_task_snapshot(task, &snapshot));
|
||||
CHECK(snapshot.state == TASK_COMPLETED);
|
||||
CHECK(lardon3d_task_sequence_count(task) == 1);
|
||||
CHECK(lardon3d_resource_governor_reservation_count(governor) == 0);
|
||||
lardon3d_task_destroy(task);
|
||||
(void)pthread_cond_destroy(&ctx.sync_cond);
|
||||
(void)pthread_mutex_destroy(&ctx.sync_mutex);
|
||||
lardon3d_resource_governor_destroy(governor);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
run_reject_test(void)
|
||||
{
|
||||
const Lardon3DResourceEstimate valid_estimate = {
|
||||
.minimum_batch_size = 1,
|
||||
.maximum_batch_size = 1,
|
||||
.desired_cpu_threads = 1,
|
||||
};
|
||||
const Lardon3DResourceEstimate reject_estimate = {
|
||||
.memory_fixed_bytes = UINT64_MAX,
|
||||
.memory_bytes_per_item = 1,
|
||||
.minimum_batch_size = 1,
|
||||
.maximum_batch_size = 1,
|
||||
.desired_cpu_threads = 1,
|
||||
};
|
||||
Lardon3DHardwareProfile profile = {
|
||||
.logical_cpu_count = 16,
|
||||
.page_size_bytes = 4096,
|
||||
.memory_total_bytes = UINT64_MAX,
|
||||
.cpu_architecture = "test",
|
||||
};
|
||||
Lardon3DResourcePolicy policy = {
|
||||
.maximum_cpu_load_ratio = 1.0,
|
||||
.maximum_io_pressure_avg10 = 100.0,
|
||||
.io_slot_capacity = 1,
|
||||
};
|
||||
Lardon3DResourceGovernor *governor = lardon3d_resource_governor_create(
|
||||
&profile,
|
||||
&policy
|
||||
);
|
||||
CHECK(governor);
|
||||
Lardon3DResourceSnapshot resource_snapshot = {
|
||||
.memory_available_bytes = UINT64_MAX,
|
||||
.cpu_load_1m = 0.0,
|
||||
};
|
||||
Lardon3DResourceDecision decision;
|
||||
Lardon3DResourceReservation *reservation;
|
||||
CHECK(lardon3d_resource_governor_reserve(
|
||||
governor,
|
||||
&resource_snapshot,
|
||||
&valid_estimate,
|
||||
&decision,
|
||||
&reservation
|
||||
));
|
||||
CHECK(reservation);
|
||||
RejectContext ctx = {.governor = governor};
|
||||
Lardon3DTask *task = lardon3d_task_create(
|
||||
"Refus gouverneur",
|
||||
&reject_estimate,
|
||||
reject_callback,
|
||||
&ctx
|
||||
);
|
||||
CHECK(task);
|
||||
|
|
@ -303,6 +571,52 @@ run_wait_test(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
run_invalid_break_test(void)
|
||||
{
|
||||
const Lardon3DResourceEstimate estimate = {
|
||||
.minimum_batch_size = 1,
|
||||
.maximum_batch_size = 1,
|
||||
.desired_cpu_threads = 1,
|
||||
};
|
||||
Lardon3DHardwareProfile profile = {
|
||||
.logical_cpu_count = 4,
|
||||
.page_size_bytes = 4096,
|
||||
.memory_total_bytes = UINT64_MAX,
|
||||
.cpu_architecture = "test",
|
||||
};
|
||||
Lardon3DResourcePolicy policy = {
|
||||
.maximum_cpu_load_ratio = 1.0,
|
||||
.maximum_io_pressure_avg10 = 100.0,
|
||||
.io_slot_capacity = 1,
|
||||
};
|
||||
Lardon3DResourceGovernor *governor = lardon3d_resource_governor_create(
|
||||
&profile,
|
||||
&policy
|
||||
);
|
||||
CHECK(governor);
|
||||
Lardon3DTask *task = lardon3d_task_create(
|
||||
"Sans réservation",
|
||||
&estimate,
|
||||
wait_retry_callback,
|
||||
NULL
|
||||
);
|
||||
CHECK(task);
|
||||
Lardon3DResourceReservation *reservation = NULL;
|
||||
Lardon3DTaskExecutionContract contract;
|
||||
CHECK(!lardon3d_task_sequence_break(task, governor, &reservation, &contract));
|
||||
CHECK(!lardon3d_task_sequence_break(NULL, governor, &reservation, &contract));
|
||||
CHECK(!lardon3d_task_sequence_break(task, NULL, &reservation, &contract));
|
||||
CHECK(!lardon3d_task_sequence_break(task, governor, NULL, &contract));
|
||||
CHECK(!lardon3d_task_sequence_break(task, governor, &reservation, NULL));
|
||||
Lardon3DTaskSnapshot snapshot;
|
||||
CHECK(lardon3d_task_snapshot(task, &snapshot));
|
||||
CHECK(snapshot.state == TASK_PENDING);
|
||||
lardon3d_task_destroy(task);
|
||||
lardon3d_resource_governor_destroy(governor);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
run_cancel_test(void)
|
||||
{
|
||||
|
|
@ -382,11 +696,23 @@ main(void)
|
|||
if (!run_sequential_test()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!run_wait_test()) {
|
||||
if (!run_wait_retry_test()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!run_cancel_test()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!run_cancel_during_wait_test()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!run_pause_during_wait_test()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!run_reject_test()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (!run_invalid_break_test()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Loading…
Reference in a new issue