add openmp support for osdi

This commit is contained in:
Pascal Kuthe 2022-12-08 14:18:32 +01:00 committed by Holger Vogt
parent 95712ea48a
commit 23e9d417a4
3 changed files with 134 additions and 84 deletions

View File

@ -189,7 +189,7 @@ typedef struct OsdiDescriptor {
double temperature, uint32_t num_terminals,
OsdiSimParas *sim_params, OsdiInitInfo *res);
uint32_t (*eval)(void *handle, void *inst, void *model, OsdiSimInfo *info);
uint32_t (*eval)(void *handle, void *inst, void *model, const OsdiSimInfo *info);
void (*load_noise)(void *inst, void *model, double freq, double *noise_dens,
double *ln_noise_dens);
void (*load_residual_resist)(void *inst, void* model, double *dst);

View File

@ -59,7 +59,7 @@ typedef struct OsdiExtraInstData {
double temp;
bool temp_given;
bool dt_given;
bool finish;
uint32_t eval_flags;
} ALIGN(MAX_ALIGN) OsdiExtraInstData;

View File

@ -28,11 +28,10 @@ char *sim_params[NUM_SIM_PARAMS + 1] = {
"gdev", "gmin", "tnom", "simulatorVersion", "sourceScaleFactor", NULL};
char *sim_params_str[1] = {NULL};
double sim_param_vals[NUM_SIM_PARAMS] = {0,0,0,0,0};
double sim_param_vals[NUM_SIM_PARAMS] = {0, 0, 0, 0, 0};
/* values returned by $simparam*/
OsdiSimParas get_simparams(const CKTcircuit *ckt) {
double simulatorVersion = strtod(PACKAGE_VERSION, NULL);
double gdev = ckt->CKTgmin;
double sourceScaleFactor = ckt->CKTsrcFact;
@ -48,6 +47,71 @@ OsdiSimParas get_simparams(const CKTcircuit *ckt) {
return sim_params_;
}
static void eval(const OsdiDescriptor *descr, const GENinstance *gen_inst,
void *inst, OsdiExtraInstData *extra_inst_data,
const void *model, const OsdiSimInfo *sim_info) {
OsdiNgspiceHandle handle =
(OsdiNgspiceHandle){.kind = 3, .name = gen_inst->GENname};
/* TODO initial conditions? */
extra_inst_data->eval_flags = descr->eval(&handle, inst, model, sim_info);
}
static void load(CKTcircuit *ckt, const GENinstance *gen_inst, void *model,
void *inst, OsdiExtraInstData *extra_inst_data, bool is_tran,
bool is_init_tran, const OsdiDescriptor *descr) {
double dump;
if (is_tran) {
/* load dc matrix and capacitances (charge derivative multiplied with
* CKTag[0]) */
descr->load_jacobian_tran(inst, model, ckt->CKTag[0]);
/* load static rhs and dynamic linearized rhs (SUM Vb * dIa/dVb)*/
descr->load_spice_rhs_tran(inst, model, ckt->CKTrhs, ckt->CKTrhsOld,
ckt->CKTag[0]);
uint32_t *node_mapping =
(uint32_t *)(((char *)inst) + descr->node_mapping_offset);
/* use numeric integration to obtain the remainer of the RHS*/
int state = gen_inst->GENstate + (int)descr->num_states;
for (uint32_t i = 0; i < descr->num_nodes; i++) {
if (descr->nodes[i].react_residual_off != UINT32_MAX) {
double residual_react =
*((double *)(((char *)inst) + descr->nodes[i].react_residual_off));
/* store charges in state vector*/
ckt->CKTstate0[state] = residual_react;
if (is_init_tran) {
ckt->CKTstate1[state] = residual_react;
}
/* we only care about the numeric integration itself not ceq/geq
because those are already calculated by load_jacobian_tran and
load_spice_rhs_tran*/
NIintegrate(ckt, &dump, &dump, 0, state);
/* add the numeric derivative to the rhs */
ckt->CKTrhs[node_mapping[i]] -= ckt->CKTstate0[state + 1];
if (is_init_tran) {
ckt->CKTstate1[state + 1] = ckt->CKTstate0[state + 1];
}
state += 2;
}
}
} else {
/* copy internal derivatives into global matrix */
descr->load_jacobian_resist(inst, model);
/* calculate spice RHS from internal currents and store into global RHS
*/
descr->load_spice_rhs_dc(inst, model, ckt->CKTrhs, ckt->CKTrhsOld);
}
}
extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
OsdiNgspiceHandle handle;
GENmodel *gen_model;
@ -113,6 +177,35 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
OsdiRegistryEntry *entry = osdi_reg_entry_model(inModel);
const OsdiDescriptor *descr = entry->descriptor;
uint32_t eval_flags = 0;
#ifdef USE_OMP
/* use openmp 3.0 tasks to parallelize linked list transveral */
#pragma omp parallel
#pragma omp single
{
for (gen_model = inModel; gen_model; gen_model = gen_model->GENnextModel) {
void *model = osdi_model_data(gen_model);
for (gen_inst = gen_model->GENinstances; gen_inst;
gen_inst = gen_inst->GENnextInstance) {
void *inst = osdi_instance_data(entry, gen_inst);
OsdiExtraInstData *extra_inst_data =
osdi_extra_instance_data(entry, gen_inst);
#pragma omp task firstprivate(gen_inst, inst, extra_inst_data, model)
eval(descr, gen_inst, inst, extra_inst_data, model, &sim_info);
}
}
}
/* init small signal analysis does not require loading values into
* matrix/rhs*/
if (is_init_smsig) {
return ret;
}
for (gen_model = inModel; gen_model; gen_model = gen_model->GENnextModel) {
void *model = osdi_model_data(gen_model);
@ -120,92 +213,49 @@ extern int OSDIload(GENmodel *inModel, CKTcircuit *ckt) {
for (gen_inst = gen_model->GENinstances; gen_inst;
gen_inst = gen_inst->GENnextInstance) {
void *inst = osdi_instance_data(entry, gen_inst);
OsdiExtraInstData *extra_inst_data =
osdi_extra_instance_data(entry, gen_inst);
load(ckt, gen_inst, model, inst, extra_inst_data, is_tran, is_init_tran,
descr);
eval_flags |= extra_inst_data->eval_flags;
}
}
#else
for (gen_model = inModel; gen_model; gen_model = gen_model->GENnextModel) {
void *model = osdi_model_data(gen_model);
/* hpyothetically this could run in parallel we do not write any shared
data here*/
handle = (OsdiNgspiceHandle){.kind = 3, .name = gen_inst->GENname};
/* TODO initial conditions? */
uint32_t ret_flags = descr->eval(&handle, inst, model, &sim_info);
for (gen_inst = gen_model->GENinstances; gen_inst;
gen_inst = gen_inst->GENnextInstance) {
void *inst = osdi_instance_data(entry, gen_inst);
/* call to $fatal in Verilog-A abort!*/
if (ret_flags & EVAL_RET_FLAG_FATAL) {
return E_PANIC;
}
OsdiExtraInstData *extra_inst_data =
osdi_extra_instance_data(entry, gen_inst);
eval(descr, gen_inst, inst, extra_inst_data, model, &sim_info);
/* init small signal analysis does not require loading values into
* matrix/rhs*/
if (is_init_smsig) {
continue;
}
/* handle calls to $finish, $limit, $stop
* TODO actually do something with extra_inst_data->finish and
* extra_inst_data->limt
* */
OsdiExtraInstData *extra_inst_data =
osdi_extra_instance_data(entry, gen_inst);
if (ret_flags & EVAL_RET_FLAG_FINISH) {
extra_inst_data->finish = true;
}
if (ret_flags & EVAL_RET_FLAG_LIM) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = gen_inst;
}
if (ret_flags & EVAL_RET_FLAG_STOP) {
ret = (E_PAUSE);
}
if (is_tran) {
/* load dc matrix and capacitances (charge derivative multiplied with
* CKTag[0]) */
descr->load_jacobian_tran(inst, model, ckt->CKTag[0]);
/* load static rhs and dynamic linearized rhs (SUM Vb * dIa/dVb)*/
descr->load_spice_rhs_tran(inst, model, ckt->CKTrhs, ckt->CKTrhsOld,
ckt->CKTag[0]);
uint32_t *node_mapping =
(uint32_t *)(((char *)inst) + descr->node_mapping_offset);
/* use numeric integration to obtain the remainer of the RHS*/
int state = gen_inst->GENstate + (int) descr->num_states;
for (uint32_t i = 0; i < descr->num_nodes; i++) {
if (descr->nodes[i].react_residual_off != UINT32_MAX) {
double residual_react = *((
double *)(((char *)inst) + descr->nodes[i].react_residual_off));
/* store charges in state vector*/
ckt->CKTstate0[state] = residual_react;
if (is_init_tran) {
ckt->CKTstate1[state] = residual_react;
}
/* we only care about the numeric integration itself not ceq/geq
because those are already calculated by load_jacobian_tran and
load_spice_rhs_tran*/
NIintegrate(ckt, &dump, &dump, 0, state);
/* add the numeric derivative to the rhs */
ckt->CKTrhs[node_mapping[i]] -= ckt->CKTstate0[state + 1];
if (is_init_tran) {
ckt->CKTstate1[state + 1] = ckt->CKTstate0[state + 1];
}
state += 2;
}
}
} else {
/* copy internal derivatives into global matrix */
descr->load_jacobian_resist(inst, model);
/* calculate spice RHS from internal currents and store into global RHS
*/
descr->load_spice_rhs_dc(inst, model, ckt->CKTrhs, ckt->CKTrhsOld);
if (!is_init_smsig) {
load(ckt, gen_inst, model, inst, extra_inst_data, is_tran, is_init_tran,
descr);
eval_flags |= extra_inst_data->eval_flags;
}
}
}
return ret;
#endif
/* call to $fatal in Verilog-A abort simulation!*/
if (eval_flags & EVAL_RET_FLAG_FATAL) {
return E_PANIC;
}
if (eval_flags & EVAL_RET_FLAG_LIM) {
ckt->CKTnoncon++;
ckt->CKTtroubleElt = gen_inst;
}
if (eval_flags & EVAL_RET_FLAG_STOP) {
return E_PAUSE;
}
return OK;
}