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
|
temperature: 0.1
|
||||||
permission:
|
permission:
|
||||||
edit: deny
|
edit: deny
|
||||||
bash: deny
|
bash:
|
||||||
|
"*": deny
|
||||||
|
"rg *": allow
|
||||||
|
"git grep*": allow
|
||||||
|
"git diff*": allow
|
||||||
|
"sed -n *": allow
|
||||||
task: deny
|
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
|
description: Reprend les tickets complexes interrompus sans refaire l'analyse
|
||||||
mode: subagent
|
mode: subagent
|
||||||
model: opencode/nemotron-3-ultra-free
|
model: opencode/deepseek-v4-flash-free
|
||||||
temperature: 0.1
|
temperature: 0.1
|
||||||
permission:
|
permission:
|
||||||
edit:
|
edit:
|
||||||
"*": allow
|
"*": allow
|
||||||
"scan3d/**": deny
|
"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
|
task: deny
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,20 @@ permission:
|
||||||
edit:
|
edit:
|
||||||
"*": allow
|
"*": allow
|
||||||
"scan3d/**": deny
|
"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
|
task: deny
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,26 @@
|
||||||
---
|
---
|
||||||
description: Implémente seul les tickets complexes Lardon3D
|
description: Implémente seul les tickets complexes Lardon3D
|
||||||
mode: subagent
|
mode: subagent
|
||||||
model: opencode/deepseek-v4-flash-free
|
model: google/gemini-3.6-flash
|
||||||
temperature: 0.1
|
temperature: 0.1
|
||||||
permission:
|
permission:
|
||||||
edit:
|
edit:
|
||||||
"*": allow
|
"*": allow
|
||||||
"scan3d/**": deny
|
"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
|
task: deny
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,12 @@ permission:
|
||||||
edit: deny
|
edit: deny
|
||||||
bash:
|
bash:
|
||||||
"*": deny
|
"*": deny
|
||||||
"git diff*": allow
|
|
||||||
"rg *": allow
|
"rg *": allow
|
||||||
|
"git grep*": allow
|
||||||
|
"git status*": allow
|
||||||
|
"git diff*": allow
|
||||||
|
"git log*": allow
|
||||||
|
"sed -n *": allow
|
||||||
task: deny
|
task: deny
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ permission:
|
||||||
"*": deny
|
"*": deny
|
||||||
"rg *": allow
|
"rg *": allow
|
||||||
"git grep*": allow
|
"git grep*": allow
|
||||||
|
"git status*": allow
|
||||||
|
"git diff*": allow
|
||||||
|
"sed -n *": allow
|
||||||
task: deny
|
task: deny
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ permission:
|
||||||
"*": deny
|
"*": deny
|
||||||
"lardon-build": allow
|
"lardon-build": allow
|
||||||
"lardon-build-backup": allow
|
"lardon-build-backup": allow
|
||||||
|
"lardon-build-backup-router": allow
|
||||||
"lardon-build-light": allow
|
"lardon-build-light": allow
|
||||||
"lardon-architect": allow
|
"lardon-architect": allow
|
||||||
"lardon-explore": 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 ;
|
- fichiers concernés ;
|
||||||
- API et invariants ;
|
- API et invariants ;
|
||||||
- tests requis.
|
- 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.
|
7. Mettre à jour le handoff après chaque phase importante.
|
||||||
|
|
||||||
Le répertoire `.opencode/work/` est préparé localement. Ne vérifie pas son
|
Le répertoire `.opencode/work/` est préparé localement. Ne vérifie pas son
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,12 @@ permission:
|
||||||
edit: deny
|
edit: deny
|
||||||
bash:
|
bash:
|
||||||
"*": deny
|
"*": deny
|
||||||
"git diff*": allow
|
"rg *": allow
|
||||||
|
"git grep*": allow
|
||||||
"git status*": allow
|
"git status*": allow
|
||||||
|
"git diff*": allow
|
||||||
|
"git log*": allow
|
||||||
|
"sed -n *": allow
|
||||||
task: deny
|
task: deny
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,11 @@ permission:
|
||||||
bash:
|
bash:
|
||||||
"*": deny
|
"*": deny
|
||||||
"CC=clang meson setup *": allow
|
"CC=clang meson setup *": allow
|
||||||
|
"meson setup *": allow
|
||||||
"meson compile *": allow
|
"meson compile *": allow
|
||||||
"meson test *": allow
|
"meson test *": allow
|
||||||
"ninja *": allow
|
"ninja *": allow
|
||||||
"git diff --check*": allow
|
"git diff*": allow
|
||||||
"git status*": allow
|
"git status*": allow
|
||||||
task: deny
|
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
|
/* 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
|
* 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
|
* d'exécution. Une réponse WAIT du gouverneur est une indisponibilité
|
||||||
* gouverneur répond WAIT/REJECT (la tâche passe alors en échec). */
|
* 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(
|
bool lardon3d_task_sequence_break(
|
||||||
Lardon3DTask *task,
|
Lardon3DTask *task,
|
||||||
Lardon3DResourceGovernor *governor,
|
Lardon3DResourceGovernor *governor,
|
||||||
|
|
|
||||||
90
src/task.c
90
src/task.c
|
|
@ -278,6 +278,11 @@ lardon3d_task_checkpoint(Lardon3DTask *task)
|
||||||
return continuing;
|
return continuing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* Attente bornée entre deux tentatives d'admission : 50 ms. */
|
||||||
|
LARDON3D_SEQUENCE_ADMISSION_WAIT_NS = 50000000ULL,
|
||||||
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
lardon3d_task_sequence_break(
|
lardon3d_task_sequence_break(
|
||||||
Lardon3DTask *task,
|
Lardon3DTask *task,
|
||||||
|
|
@ -302,6 +307,7 @@ lardon3d_task_sequence_break(
|
||||||
(void)pthread_cond_wait(&task->condition, &task->mutex);
|
(void)pthread_cond_wait(&task->condition, &task->mutex);
|
||||||
}
|
}
|
||||||
if (task->cancel_requested) {
|
if (task->cancel_requested) {
|
||||||
|
finish_locked(task, TASK_CANCELLED, "Tâche annulée.");
|
||||||
(void)pthread_mutex_unlock(&task->mutex);
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -314,28 +320,9 @@ lardon3d_task_sequence_break(
|
||||||
(void)lardon3d_resource_governor_release(governor, previous);
|
(void)lardon3d_resource_governor_release(governor, previous);
|
||||||
}
|
}
|
||||||
|
|
||||||
Lardon3DResourceDecision decision;
|
for (;;) {
|
||||||
Lardon3DResourceReservation *next = NULL;
|
/* Vérifier pause et annulation avant chaque tentative d'admission. */
|
||||||
bool reserved = lardon3d_resource_governor_reserve_available(
|
|
||||||
governor,
|
|
||||||
&task->estimate,
|
|
||||||
&decision,
|
|
||||||
&next
|
|
||||||
);
|
|
||||||
|
|
||||||
(void)pthread_mutex_lock(&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) {
|
while (task->pause_requested && !task->cancel_requested) {
|
||||||
task->state = TASK_PAUSED;
|
task->state = TASK_PAUSED;
|
||||||
copy_text(task->message, sizeof(task->message), "Tâche en pause.");
|
copy_text(task->message, sizeof(task->message), "Tâche en pause.");
|
||||||
|
|
@ -343,14 +330,25 @@ lardon3d_task_sequence_break(
|
||||||
(void)pthread_cond_wait(&task->condition, &task->mutex);
|
(void)pthread_cond_wait(&task->condition, &task->mutex);
|
||||||
}
|
}
|
||||||
if (task->cancel_requested) {
|
if (task->cancel_requested) {
|
||||||
if (next) {
|
|
||||||
(void)lardon3d_resource_governor_release(governor, next);
|
|
||||||
}
|
|
||||||
finish_locked(task, TASK_CANCELLED, "Tâche annulée.");
|
finish_locked(task, TASK_CANCELLED, "Tâche annulée.");
|
||||||
(void)pthread_mutex_unlock(&task->mutex);
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!reserved || !next) {
|
task->state = TASK_RUNNING;
|
||||||
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
|
|
||||||
|
uint64_t generation = lardon3d_resource_governor_generation(governor);
|
||||||
|
Lardon3DResourceDecision decision;
|
||||||
|
Lardon3DResourceReservation *next = NULL;
|
||||||
|
bool admitted = lardon3d_resource_governor_reserve_available(
|
||||||
|
governor,
|
||||||
|
&task->estimate,
|
||||||
|
&decision,
|
||||||
|
&next
|
||||||
|
);
|
||||||
|
if (!admitted) {
|
||||||
|
/* Erreur interne : échec d'allocation ou d'instantané. */
|
||||||
|
(void)pthread_mutex_lock(&task->mutex);
|
||||||
task->current_reservation = NULL;
|
task->current_reservation = NULL;
|
||||||
finish_locked(
|
finish_locked(
|
||||||
task,
|
task,
|
||||||
|
|
@ -360,14 +358,16 @@ lardon3d_task_sequence_break(
|
||||||
(void)pthread_mutex_unlock(&task->mutex);
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (decision.kind == LARDON3D_RESOURCE_WAIT
|
switch (decision.kind) {
|
||||||
|| decision.kind == LARDON3D_RESOURCE_REJECT) {
|
case LARDON3D_RESOURCE_START:
|
||||||
|
case LARDON3D_RESOURCE_REDUCE_BATCH: {
|
||||||
|
if (!next) {
|
||||||
|
(void)pthread_mutex_lock(&task->mutex);
|
||||||
task->current_reservation = NULL;
|
task->current_reservation = NULL;
|
||||||
finish_locked(
|
finish_locked(
|
||||||
task,
|
task,
|
||||||
TASK_FAILED,
|
TASK_FAILED,
|
||||||
decision.reason[0] ? decision.reason
|
"Réservation de séquence invalide."
|
||||||
: "Ressources impossibles à réserver."
|
|
||||||
);
|
);
|
||||||
(void)pthread_mutex_unlock(&task->mutex);
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -379,6 +379,7 @@ lardon3d_task_sequence_break(
|
||||||
&information
|
&information
|
||||||
)) {
|
)) {
|
||||||
(void)lardon3d_resource_governor_release(governor, next);
|
(void)lardon3d_resource_governor_release(governor, next);
|
||||||
|
(void)pthread_mutex_lock(&task->mutex);
|
||||||
task->current_reservation = NULL;
|
task->current_reservation = NULL;
|
||||||
finish_locked(
|
finish_locked(
|
||||||
task,
|
task,
|
||||||
|
|
@ -388,6 +389,7 @@ lardon3d_task_sequence_break(
|
||||||
(void)pthread_mutex_unlock(&task->mutex);
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
(void)pthread_mutex_lock(&task->mutex);
|
||||||
task->current_reservation = next;
|
task->current_reservation = next;
|
||||||
task->contract = (Lardon3DTaskExecutionContract) {
|
task->contract = (Lardon3DTaskExecutionContract) {
|
||||||
.batch_size = information.batch_size,
|
.batch_size = information.batch_size,
|
||||||
|
|
@ -403,6 +405,36 @@ lardon3d_task_sequence_break(
|
||||||
*out_contract = task->contract;
|
*out_contract = task->contract;
|
||||||
(void)pthread_mutex_unlock(&task->mutex);
|
(void)pthread_mutex_unlock(&task->mutex);
|
||||||
return true;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int
|
unsigned int
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,14 @@ typedef struct {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Lardon3DResourceGovernor *governor;
|
Lardon3DResourceGovernor *governor;
|
||||||
} WaitContext;
|
pthread_mutex_t sync_mutex;
|
||||||
|
pthread_cond_t sync_cond;
|
||||||
|
bool in_break;
|
||||||
|
} WaitRetryContext;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Lardon3DResourceGovernor *governor;
|
||||||
|
} RejectContext;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Lardon3DResourceGovernor *governor;
|
Lardon3DResourceGovernor *governor;
|
||||||
|
|
@ -102,9 +109,27 @@ seq_callback(Lardon3DTask *task, void *userdata)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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;
|
Lardon3DResourceReservation *reservation = NULL;
|
||||||
Lardon3DTaskExecutionContract contract;
|
Lardon3DTaskExecutionContract contract;
|
||||||
return lardon3d_task_sequence_break(
|
return lardon3d_task_sequence_break(
|
||||||
|
|
@ -247,7 +272,7 @@ run_sequential_test(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
run_wait_test(void)
|
run_wait_retry_test(void)
|
||||||
{
|
{
|
||||||
const Lardon3DResourceEstimate estimate = {
|
const Lardon3DResourceEstimate estimate = {
|
||||||
.minimum_batch_size = 1,
|
.minimum_batch_size = 1,
|
||||||
|
|
@ -274,7 +299,6 @@ run_wait_test(void)
|
||||||
Lardon3DResourceSnapshot resource_snapshot = {
|
Lardon3DResourceSnapshot resource_snapshot = {
|
||||||
.memory_available_bytes = UINT64_MAX,
|
.memory_available_bytes = UINT64_MAX,
|
||||||
.cpu_load_1m = 0.0,
|
.cpu_load_1m = 0.0,
|
||||||
.io_pressure_known = false,
|
|
||||||
};
|
};
|
||||||
Lardon3DResourceDecision decision;
|
Lardon3DResourceDecision decision;
|
||||||
Lardon3DResourceReservation *reservation;
|
Lardon3DResourceReservation *reservation;
|
||||||
|
|
@ -285,11 +309,255 @@ run_wait_test(void)
|
||||||
&decision,
|
&decision,
|
||||||
&reservation
|
&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(
|
Lardon3DTask *task = lardon3d_task_create(
|
||||||
"Attente",
|
"Attente puis reprise",
|
||||||
&estimate,
|
&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
|
&ctx
|
||||||
);
|
);
|
||||||
CHECK(task);
|
CHECK(task);
|
||||||
|
|
@ -303,6 +571,52 @@ run_wait_test(void)
|
||||||
return true;
|
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
|
static bool
|
||||||
run_cancel_test(void)
|
run_cancel_test(void)
|
||||||
{
|
{
|
||||||
|
|
@ -382,11 +696,23 @@ main(void)
|
||||||
if (!run_sequential_test()) {
|
if (!run_sequential_test()) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (!run_wait_test()) {
|
if (!run_wait_retry_test()) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (!run_cancel_test()) {
|
if (!run_cancel_test()) {
|
||||||
return EXIT_FAILURE;
|
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;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue