Add partial support for the breakdown model
For now only Runtime and Task breakdown trees are implemented. The Idle state is not decomposed.
This commit is contained in:
parent
6b8099b6af
commit
a90768c1d4
@ -48,6 +48,7 @@ add_library(emu STATIC
|
|||||||
ovni/setup.c
|
ovni/setup.c
|
||||||
nanos6/setup.c
|
nanos6/setup.c
|
||||||
nanos6/event.c
|
nanos6/event.c
|
||||||
|
nanos6/breakdown.c
|
||||||
nosv/setup.c
|
nosv/setup.c
|
||||||
nosv/event.c
|
nosv/event.c
|
||||||
nodes/setup.c
|
nodes/setup.c
|
||||||
|
@ -25,6 +25,7 @@ enum emu_prv_types {
|
|||||||
PRV_NANOS6_RANK = 38,
|
PRV_NANOS6_RANK = 38,
|
||||||
PRV_NANOS6_THREAD = 39,
|
PRV_NANOS6_THREAD = 39,
|
||||||
PRV_NANOS6_IDLE = 40,
|
PRV_NANOS6_IDLE = 40,
|
||||||
|
PRV_NANOS6_BREAKDOWN = 41,
|
||||||
PRV_KERNEL_CS = 45,
|
PRV_KERNEL_CS = 45,
|
||||||
PRV_RESERVED = 100,
|
PRV_RESERVED = 100,
|
||||||
};
|
};
|
||||||
|
213
src/emu/nanos6/breakdown.c
Normal file
213
src/emu/nanos6/breakdown.c
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/* Copyright (c) 2021-2023 Barcelona Supercomputing Center (BSC)
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later */
|
||||||
|
|
||||||
|
//#define ENABLE_DEBUG
|
||||||
|
|
||||||
|
#include "nanos6_priv.h"
|
||||||
|
|
||||||
|
#include "emu_prv.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
create_cpu(struct bay *bay, struct breakdown_cpu *bcpu, int64_t gindex)
|
||||||
|
{
|
||||||
|
enum chan_type t = CHAN_SINGLE;
|
||||||
|
chan_init(&bcpu->tr, t, "nanos6.cpu%ld.breakdown.tr", gindex);
|
||||||
|
chan_init(&bcpu->tri, t, "nanos6.cpu%ld.breakdown.tri", gindex);
|
||||||
|
|
||||||
|
/* Register all channels in the bay */
|
||||||
|
if (bay_register(bay, &bcpu->tr) != 0) {
|
||||||
|
err("bay_register tr failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (bay_register(bay, &bcpu->tri) != 0) {
|
||||||
|
err("bay_register tri failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
model_nanos6_breakdown_create(struct emu *emu)
|
||||||
|
{
|
||||||
|
if (emu->args.breakdown == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
struct nanos6_emu *memu = EXT(emu, '6');
|
||||||
|
struct breakdown_emu *bemu = &memu->brk;
|
||||||
|
|
||||||
|
/* Count phy cpus */
|
||||||
|
struct system *sys = &emu->system;
|
||||||
|
int nphycpus = sys->ncpus - sys->nlooms;
|
||||||
|
|
||||||
|
/* Create a new Paraver trace */
|
||||||
|
struct recorder *rec = &emu->recorder;
|
||||||
|
bemu->pvt = recorder_add_pvt(rec, "nanos6-breakdown", nphycpus);
|
||||||
|
if (bemu->pvt == NULL) {
|
||||||
|
err("recorder_add_pvt failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sort_init(&bemu->sort, &emu->bay, nphycpus, "nanos6.breakdown.sort") != 0) {
|
||||||
|
err("sort_init failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t i = 0;
|
||||||
|
for (struct cpu *cpu = sys->cpus; cpu; cpu = cpu->next) {
|
||||||
|
if (cpu->is_virtual)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
struct nanos6_cpu *mcpu = EXT(cpu, '6');
|
||||||
|
struct breakdown_cpu *bcpu = &mcpu->brk;
|
||||||
|
|
||||||
|
if (create_cpu(&emu->bay, bcpu, cpu->gindex) != 0) {
|
||||||
|
err("create_cpu failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
select_tr(struct mux *mux, struct value value, struct mux_input **input)
|
||||||
|
{
|
||||||
|
/* Only select the task if we are in ST_TASK_BODY and the task_type has
|
||||||
|
* a non-null value */
|
||||||
|
|
||||||
|
int64_t in_body = (value.type == VALUE_INT64 && value.i == ST_TASK_BODY);
|
||||||
|
|
||||||
|
if (in_body) {
|
||||||
|
struct value tt;
|
||||||
|
struct mux_input *ttinput = mux_get_input(mux, 1);
|
||||||
|
if (chan_read(ttinput->chan, &tt) != 0) {
|
||||||
|
err("chan_read failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only show task type if we have a task */
|
||||||
|
if (tt.type == VALUE_NULL)
|
||||||
|
in_body = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t i = in_body;
|
||||||
|
char *inputs[] = { "subsystem", "task_type" };
|
||||||
|
dbg("selecting input %ld (%s)", i, inputs[i]);
|
||||||
|
*input = mux_get_input(mux, i);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
select_idle(struct mux *mux, struct value value, struct mux_input **input)
|
||||||
|
{
|
||||||
|
char buf[128];
|
||||||
|
dbg("value is %s", value_str(value, buf));
|
||||||
|
if (value.type == VALUE_INT64 && value.i == ST_WORKER_IDLE) {
|
||||||
|
dbg("selecting input 1 (idle)");
|
||||||
|
*input = mux_get_input(mux, 1);
|
||||||
|
} else {
|
||||||
|
dbg("selecting input 0 (tr)");
|
||||||
|
*input = mux_get_input(mux, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
connect_cpu(struct bay *bay, struct nanos6_cpu *mcpu)
|
||||||
|
{
|
||||||
|
struct breakdown_cpu *bcpu = &mcpu->brk;
|
||||||
|
|
||||||
|
/* Channel aliases */
|
||||||
|
struct chan *ss = &mcpu->m.track[CH_SUBSYSTEM].ch;
|
||||||
|
struct chan *tt = &mcpu->m.track[CH_TYPE].ch;
|
||||||
|
struct chan *idle = &mcpu->m.track[CH_IDLE].ch;
|
||||||
|
struct chan *tr = &bcpu->tr;
|
||||||
|
struct chan *tri = &bcpu->tri;
|
||||||
|
|
||||||
|
/* Connect mux0 using ss as select */
|
||||||
|
if (mux_init(&bcpu->mux0, bay, ss, tr, select_tr, 2) != 0) {
|
||||||
|
err("mux_init failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mux_set_input(&bcpu->mux0, 0, ss) != 0) {
|
||||||
|
err("mux_set_input ss failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mux_set_input(&bcpu->mux0, 1, tt) != 0) {
|
||||||
|
err("mux_set_input tt failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connect mux 1 using idle as select */
|
||||||
|
if (mux_init(&bcpu->mux1, bay, idle, tri, select_idle, 2) != 0) {
|
||||||
|
err("mux_init failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mux_set_input(&bcpu->mux1, 0, tr) != 0) {
|
||||||
|
err("mux_set_input tr failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mux_set_input(&bcpu->mux1, 1, idle) != 0) {
|
||||||
|
err("mux_set_input idle failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
model_nanos6_breakdown_connect(struct emu *emu)
|
||||||
|
{
|
||||||
|
if (emu->args.breakdown == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
struct nanos6_emu *memu = EXT(emu, '6');
|
||||||
|
struct breakdown_emu *bemu = &memu->brk;
|
||||||
|
struct bay *bay = &emu->bay;
|
||||||
|
struct system *sys = &emu->system;
|
||||||
|
|
||||||
|
int64_t i = 0;
|
||||||
|
for (struct cpu *cpu = sys->cpus; cpu; cpu = cpu->next) {
|
||||||
|
if (cpu->is_virtual)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
struct nanos6_cpu *mcpu = EXT(cpu, '6');
|
||||||
|
struct breakdown_cpu *bcpu = &mcpu->brk;
|
||||||
|
|
||||||
|
/* Connect tr and tri channels and muxes */
|
||||||
|
if (connect_cpu(bay, mcpu) != 0) {
|
||||||
|
err("connect_cpu failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connect tri to sort */
|
||||||
|
if (sort_set_input(&bemu->sort, i, &bcpu->tri) != 0) {
|
||||||
|
err("sort_set_input failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connect out to PRV */
|
||||||
|
struct prv *prv = pvt_get_prv(bemu->pvt);
|
||||||
|
long type = PRV_NANOS6_BREAKDOWN;
|
||||||
|
long flags = PRV_SKIPDUP;
|
||||||
|
|
||||||
|
struct chan *out = sort_get_output(&bemu->sort, i);
|
||||||
|
if (prv_register(prv, i, type, bay, out, flags)) {
|
||||||
|
err("prv_register failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
52
src/emu/nanos6/breakdown.h
Normal file
52
src/emu/nanos6/breakdown.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#ifndef BREAKDOWN_H
|
||||||
|
#define BREAKDOWN_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The breakdown model is implemented on top of the CPU subsystem, task_type and
|
||||||
|
* idle channels. The first mux0 selects the task type when the subsystem
|
||||||
|
* matches "Task body" otherwise forwards the subsystem as-is to tr. The second
|
||||||
|
* mux1 selects tr only when the CPU is not Idle, otherwise sets the output tri
|
||||||
|
* as Idle.
|
||||||
|
*
|
||||||
|
* +--------+
|
||||||
|
* | |
|
||||||
|
* | v
|
||||||
|
* | +------+
|
||||||
|
* subsystem -+-->--| |
|
||||||
|
* | mux0 | +------+
|
||||||
|
* task_type ---->--| |-->-- tr -->--| |
|
||||||
|
* +------+ | mux1 |-->-- tri
|
||||||
|
* idle --------->-------------------+->--| |
|
||||||
|
* | +------+
|
||||||
|
* | ^
|
||||||
|
* | |
|
||||||
|
* +--------+
|
||||||
|
*
|
||||||
|
* Then the sort module takes the output tri of each CPU and sorts the values
|
||||||
|
* which are propagated to the PRV directly.
|
||||||
|
*
|
||||||
|
* +------+ +-----+
|
||||||
|
* cpu0.tri --->---| |--->---| |
|
||||||
|
* ... | sort | ... | PRV |
|
||||||
|
* cpuN.tri --->---| |--->---| |
|
||||||
|
* +------+ +-----+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mux.h"
|
||||||
|
#include "chan.h"
|
||||||
|
#include "sort.h"
|
||||||
|
#include "pv/pvt.h"
|
||||||
|
|
||||||
|
struct breakdown_cpu {
|
||||||
|
struct mux mux0;
|
||||||
|
struct chan tr;
|
||||||
|
struct mux mux1;
|
||||||
|
struct chan tri;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct breakdown_emu {
|
||||||
|
struct sort sort;
|
||||||
|
struct pvt *pvt;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* BREAKDOWN_H */
|
@ -60,8 +60,8 @@ static const int ss_table[256][256][3] = {
|
|||||||
[']'] = { CHSS, POP, ST_TASK_FOR },
|
[']'] = { CHSS, POP, ST_TASK_FOR },
|
||||||
},
|
},
|
||||||
['t'] = {
|
['t'] = {
|
||||||
['['] = { CHSS, PUSH, ST_TASK_BODY },
|
['['] = { CHSS, IGN, -1 },
|
||||||
[']'] = { CHSS, POP, ST_TASK_BODY },
|
[']'] = { CHSS, IGN, -1 },
|
||||||
},
|
},
|
||||||
['M'] = {
|
['M'] = {
|
||||||
['a'] = { CHSS, PUSH, ST_ALLOCATING },
|
['a'] = { CHSS, PUSH, ST_ALLOCATING },
|
||||||
@ -377,6 +377,27 @@ enforce_task_rules(struct emu *emu, char tr, struct task *next)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
update_task_ss_channel(struct emu *emu, char tr)
|
||||||
|
{
|
||||||
|
struct nanos6_thread *th = EXT(emu->thread, '6');
|
||||||
|
struct chan *ss = &th->m.ch[CH_SUBSYSTEM];
|
||||||
|
|
||||||
|
if (tr == 'x') {
|
||||||
|
if (chan_push(ss, value_int64(ST_TASK_BODY)) != 0) {
|
||||||
|
err("chan_push subsystem failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if (tr == 'e') {
|
||||||
|
if (chan_pop(ss, value_int64(ST_TASK_BODY)) != 0) {
|
||||||
|
err("chan_pop subsystem failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
update_task(struct emu *emu)
|
update_task(struct emu *emu)
|
||||||
{
|
{
|
||||||
@ -393,6 +414,12 @@ update_task(struct emu *emu)
|
|||||||
|
|
||||||
struct task *next = task_get_running(stack);
|
struct task *next = task_get_running(stack);
|
||||||
|
|
||||||
|
/* Update the subsystem channel */
|
||||||
|
if (update_task_ss_channel(emu, emu->ev->v) != 0) {
|
||||||
|
err("update_task_ss_channel failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
int was_running = (prev != NULL);
|
int was_running = (prev != NULL);
|
||||||
int runs_now = (next != NULL);
|
int runs_now = (next != NULL);
|
||||||
char tr;
|
char tr;
|
||||||
@ -402,7 +429,10 @@ update_task(struct emu *emu)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update the task related channels now */
|
/* Update the task related channels now */
|
||||||
update_task_channels(emu, tr, prev, next);
|
if (update_task_channels(emu, tr, prev, next) != 0) {
|
||||||
|
err("update_task_channels failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (enforce_task_rules(emu, tr, next) != 0) {
|
if (enforce_task_rules(emu, tr, next) != 0) {
|
||||||
err("enforce_task_rules failed");
|
err("enforce_task_rules failed");
|
||||||
|
@ -6,8 +6,10 @@
|
|||||||
|
|
||||||
#include "emu.h"
|
#include "emu.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
#include "sort.h"
|
||||||
#include "model_cpu.h"
|
#include "model_cpu.h"
|
||||||
#include "model_thread.h"
|
#include "model_thread.h"
|
||||||
|
#include "breakdown.h"
|
||||||
|
|
||||||
/* Private enums */
|
/* Private enums */
|
||||||
|
|
||||||
@ -40,6 +42,7 @@ enum nanos6_ss_state {
|
|||||||
ST_FREEING,
|
ST_FREEING,
|
||||||
ST_HANDLING_TASK,
|
ST_HANDLING_TASK,
|
||||||
ST_WORKER_LOOP,
|
ST_WORKER_LOOP,
|
||||||
|
ST_WORKER_INIT,
|
||||||
ST_SWITCH_TO,
|
ST_SWITCH_TO,
|
||||||
ST_MIGRATE,
|
ST_MIGRATE,
|
||||||
ST_SUSPEND,
|
ST_SUSPEND,
|
||||||
@ -62,7 +65,9 @@ enum nanos6_thread_type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum nanos6_worker_idle {
|
enum nanos6_worker_idle {
|
||||||
ST_WORKER_IDLE = 1,
|
/* Can mix with subsystem values */
|
||||||
|
ST_WORKER_IDLE = 100,
|
||||||
|
ST_WORKER_BUSY = 101,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nanos6_thread {
|
struct nanos6_thread {
|
||||||
@ -72,16 +77,24 @@ struct nanos6_thread {
|
|||||||
|
|
||||||
struct nanos6_cpu {
|
struct nanos6_cpu {
|
||||||
struct model_cpu m;
|
struct model_cpu m;
|
||||||
|
struct breakdown_cpu brk;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nanos6_proc {
|
struct nanos6_proc {
|
||||||
struct task_info task_info;
|
struct task_info task_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct nanos6_emu {
|
||||||
|
struct breakdown_emu brk;
|
||||||
|
};
|
||||||
|
|
||||||
int model_nanos6_probe(struct emu *emu);
|
int model_nanos6_probe(struct emu *emu);
|
||||||
int model_nanos6_create(struct emu *emu);
|
int model_nanos6_create(struct emu *emu);
|
||||||
int model_nanos6_connect(struct emu *emu);
|
int model_nanos6_connect(struct emu *emu);
|
||||||
int model_nanos6_event(struct emu *emu);
|
int model_nanos6_event(struct emu *emu);
|
||||||
int model_nanos6_finish(struct emu *emu);
|
int model_nanos6_finish(struct emu *emu);
|
||||||
|
|
||||||
|
int model_nanos6_breakdown_create(struct emu *emu);
|
||||||
|
int model_nanos6_breakdown_connect(struct emu *emu);
|
||||||
|
|
||||||
#endif /* NANOS6_PRIV_H */
|
#endif /* NANOS6_PRIV_H */
|
||||||
|
@ -99,6 +99,7 @@ static const struct pcf_value_label nanos6_ss_values[] = {
|
|||||||
{ ST_BLK_WAITFOR, "Blocking: Wait for deadline" },
|
{ ST_BLK_WAITFOR, "Blocking: Wait for deadline" },
|
||||||
{ ST_HANDLING_TASK, "Worker: Handling task" },
|
{ ST_HANDLING_TASK, "Worker: Handling task" },
|
||||||
{ ST_WORKER_LOOP, "Worker: Looking for work" },
|
{ ST_WORKER_LOOP, "Worker: Looking for work" },
|
||||||
|
{ ST_WORKER_INIT, "Worker: Starting" },
|
||||||
{ ST_SWITCH_TO, "Worker: Switching to another thread" },
|
{ ST_SWITCH_TO, "Worker: Switching to another thread" },
|
||||||
{ ST_MIGRATE, "Worker: Migrating CPU" },
|
{ ST_MIGRATE, "Worker: Migrating CPU" },
|
||||||
{ ST_SUSPEND, "Worker: Suspending thread" },
|
{ ST_SUSPEND, "Worker: Suspending thread" },
|
||||||
@ -158,7 +159,7 @@ static const int th_track[CH_MAX] = {
|
|||||||
[CH_SUBSYSTEM] = TRACK_TH_ACT,
|
[CH_SUBSYSTEM] = TRACK_TH_ACT,
|
||||||
[CH_RANK] = TRACK_TH_RUN,
|
[CH_RANK] = TRACK_TH_RUN,
|
||||||
[CH_THREAD] = TRACK_TH_ANY,
|
[CH_THREAD] = TRACK_TH_ANY,
|
||||||
[CH_IDLE] = TRACK_TH_ANY,
|
[CH_IDLE] = TRACK_TH_RUN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int cpu_track[CH_MAX] = {
|
static const int cpu_track[CH_MAX] = {
|
||||||
@ -259,6 +260,19 @@ model_nanos6_create(struct emu *emu)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct nanos6_emu *e = calloc(1, sizeof(struct nanos6_emu));
|
||||||
|
if (e == NULL) {
|
||||||
|
err("calloc failed:");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
extend_set(&emu->ext, model_id, e);
|
||||||
|
|
||||||
|
if (model_nanos6_breakdown_create(emu) != 0) {
|
||||||
|
err("model_nanos6_breakdown_connect failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,6 +289,34 @@ model_nanos6_connect(struct emu *emu)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (model_nanos6_breakdown_connect(emu) != 0) {
|
||||||
|
err("model_nanos6_breakdown_connect failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (struct thread *th = emu->system.threads; th; th = th->gnext) {
|
||||||
|
struct nanos6_thread *mth = EXT(th, model_id);
|
||||||
|
struct chan *idle = &mth->m.ch[CH_IDLE];
|
||||||
|
/* By default set all threads as Busy */
|
||||||
|
if (chan_push(idle, value_int64(ST_WORKER_BUSY)) != 0) {
|
||||||
|
err("chan_push idle failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
struct chan *ss = &mth->m.ch[CH_SUBSYSTEM];
|
||||||
|
/* And push initial subsystem to worker init */
|
||||||
|
if (chan_push(ss, value_int64(ST_WORKER_INIT)) != 0) {
|
||||||
|
err("chan_push idle failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (struct cpu *cpu = emu->system.cpus; cpu; cpu = cpu->next) {
|
||||||
|
struct nanos6_cpu *mcpu = EXT(cpu, model_id);
|
||||||
|
struct mux *mux = &mcpu->m.track[CH_IDLE].mux;
|
||||||
|
/* Emit Idle when a CPU has no idle threads */
|
||||||
|
mux_set_default(mux, value_int64(ST_WORKER_IDLE));
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,7 +335,7 @@ end_lint(struct emu *emu)
|
|||||||
struct nanos6_thread *th = EXT(t, model_id);
|
struct nanos6_thread *th = EXT(t, model_id);
|
||||||
struct chan *ch = &th->m.ch[CH_SUBSYSTEM];
|
struct chan *ch = &th->m.ch[CH_SUBSYSTEM];
|
||||||
int stacked = ch->data.stack.n;
|
int stacked = ch->data.stack.n;
|
||||||
if (stacked > 0) {
|
if (stacked > 1) {
|
||||||
struct value top;
|
struct value top;
|
||||||
if (chan_read(ch, &top) != 0) {
|
if (chan_read(ch, &top) != 0) {
|
||||||
err("chan_read failed for subsystem");
|
err("chan_read failed for subsystem");
|
||||||
|
Loading…
Reference in New Issue
Block a user