Rejigged solver statistics in preparation for islanding.
- See public description below. - Stopped incrementing the iteration count in saveStats(). - `sizeof(mjSolverStat) == 40`, so this ends up costing 160KB, up from 40KB. BEGIN_PUBLIC Changed the size of `mjData.solver`, the structure used to collect solver diagnostic information. The array is now of length `mjNISLAND * mjNSOLVER`, where each row of length `mjNSOLVER` contains separate solver statistics for each constraint island. Until solver islanding is implemented, only row 0 is used. - The new constant `mjNISLAND` is set to 20. - `mjNSOLVER` is reduced from 1000 to 200. - Added `mjData.solver_nisland`, the number of islands for which the solver ran. - `mjData.solver_niter` (renamed from mjData.solver_iter) and `mjData.solver_nnz` are now integer vectors of length `mjNISLAND`. END_PUBLIC PiperOrigin-RevId: 565030093 Change-Id: I773e918805c6ced79f0dab5f19ea23956760c8c5
This commit is contained in:
committed by
Copybara-Service
parent
8faf47dd16
commit
86d8b912f4
+115
-53
@@ -176,6 +176,10 @@ const char help_title[] =
|
||||
|
||||
//-------------------------------- profiler, sensor, info, watch -----------------------------------
|
||||
|
||||
// number of lines in the Constraint ("Counts") and Cost ("Convergence") figures
|
||||
static constexpr int kConstraintNum = 5;
|
||||
static constexpr int kCostNum = 3;
|
||||
|
||||
// init profiler figures
|
||||
void InitializeProfiler(mj::Simulate* sim) {
|
||||
// set figures to default
|
||||
@@ -212,6 +216,20 @@ void InitializeProfiler(mj::Simulate* sim) {
|
||||
sim->figsize.figurergba[3] = 0.5f;
|
||||
sim->figtimer.figurergba[3] = 0.5f;
|
||||
|
||||
// repeat line colors for constraint and cost figures
|
||||
mjvFigure* fig = &sim->figcost;
|
||||
for (int i=kCostNum; i<mjMAXLINE; i++) {
|
||||
fig->linergb[i][0] = fig->linergb[i - kCostNum][0];
|
||||
fig->linergb[i][1] = fig->linergb[i - kCostNum][1];
|
||||
fig->linergb[i][2] = fig->linergb[i - kCostNum][2];
|
||||
}
|
||||
fig = &sim->figconstraint;
|
||||
for (int i=kConstraintNum; i<mjMAXLINE; i++) {
|
||||
fig->linergb[i][0] = fig->linergb[i - kConstraintNum][0];
|
||||
fig->linergb[i][1] = fig->linergb[i - kConstraintNum][1];
|
||||
fig->linergb[i][2] = fig->linergb[i - kConstraintNum][2];
|
||||
}
|
||||
|
||||
// legends
|
||||
mju::strcpy_arr(sim->figconstraint.linename[0], "total");
|
||||
mju::strcpy_arr(sim->figconstraint.linename[1], "active");
|
||||
@@ -272,54 +290,76 @@ void InitializeProfiler(mj::Simulate* sim) {
|
||||
|
||||
// update profiler figures
|
||||
void UpdateProfiler(mj::Simulate* sim, const mjModel* m, const mjData* d) {
|
||||
// update constraint figure
|
||||
sim->figconstraint.linepnt[0] = mjMIN(mjMIN(d->solver_iter, mjNSOLVER), mjMAXLINEPNT);
|
||||
for (int i=1; i<5; i++) {
|
||||
sim->figconstraint.linepnt[i] = sim->figconstraint.linepnt[0];
|
||||
}
|
||||
if (m->opt.solver==mjSOL_PGS) {
|
||||
sim->figconstraint.linepnt[3] = 0;
|
||||
sim->figconstraint.linepnt[4] = 0;
|
||||
}
|
||||
if (m->opt.solver==mjSOL_CG) {
|
||||
sim->figconstraint.linepnt[4] = 0;
|
||||
}
|
||||
for (int i=0; i<sim->figconstraint.linepnt[0]; i++) {
|
||||
// x
|
||||
sim->figconstraint.linedata[0][2*i] = i;
|
||||
sim->figconstraint.linedata[1][2*i] = i;
|
||||
sim->figconstraint.linedata[2][2*i] = i;
|
||||
sim->figconstraint.linedata[3][2*i] = i;
|
||||
sim->figconstraint.linedata[4][2*i] = i;
|
||||
// reset lines in Constraint and Cost figures
|
||||
memset(sim->figconstraint.linepnt, 0, mjMAXLINE*sizeof(int));
|
||||
memset(sim->figcost.linepnt, 0, mjMAXLINE*sizeof(int));
|
||||
|
||||
// y
|
||||
sim->figconstraint.linedata[0][2*i+1] = d->nefc;
|
||||
sim->figconstraint.linedata[1][2*i+1] = d->solver[i].nactive;
|
||||
sim->figconstraint.linedata[2][2*i+1] = d->solver[i].nchange;
|
||||
sim->figconstraint.linedata[3][2*i+1] = d->solver[i].neval;
|
||||
sim->figconstraint.linedata[4][2*i+1] = d->solver[i].nupdate;
|
||||
}
|
||||
// number of islands that have diagnostics
|
||||
int nisland = mjMIN(d->solver_nisland, mjNISLAND);
|
||||
|
||||
// update cost figure
|
||||
sim->figcost.linepnt[0] = mjMIN(mjMIN(d->solver_iter, mjNSOLVER), mjMAXLINEPNT);
|
||||
for (int i=1; i<3; i++) {
|
||||
sim->figcost.linepnt[i] = sim->figcost.linepnt[0];
|
||||
}
|
||||
if (m->opt.solver==mjSOL_PGS) {
|
||||
sim->figcost.linepnt[1] = 0;
|
||||
sim->figcost.linepnt[2] = 0;
|
||||
}
|
||||
// iterate over islands
|
||||
for (int k=0; k < nisland; k++) {
|
||||
// ==== update Constraint ("Counts") figure
|
||||
|
||||
for (int i=0; i<sim->figcost.linepnt[0]; i++) {
|
||||
// x
|
||||
sim->figcost.linedata[0][2*i] = i;
|
||||
sim->figcost.linedata[1][2*i] = i;
|
||||
sim->figcost.linedata[2][2*i] = i;
|
||||
// number of points to plot, starting line
|
||||
int npoints = mjMIN(mjMIN(d->solver_niter[k], mjNSOLVER), mjMAXLINEPNT);
|
||||
int start = kConstraintNum * k;
|
||||
|
||||
// y
|
||||
sim->figcost.linedata[0][2*i+1] = mju_log10(mju_max(mjMINVAL, d->solver[i].improvement));
|
||||
sim->figcost.linedata[1][2*i+1] = mju_log10(mju_max(mjMINVAL, d->solver[i].gradient));
|
||||
sim->figcost.linedata[2][2*i+1] = mju_log10(mju_max(mjMINVAL, d->solver[i].lineslope));
|
||||
sim->figconstraint.linepnt[start + 0] = npoints;
|
||||
for (int i=1; i < kConstraintNum; i++) {
|
||||
sim->figconstraint.linepnt[start + i] = npoints;
|
||||
}
|
||||
if (m->opt.solver == mjSOL_PGS) {
|
||||
sim->figconstraint.linepnt[start + 3] = 0;
|
||||
sim->figconstraint.linepnt[start + 4] = 0;
|
||||
}
|
||||
if (m->opt.solver == mjSOL_CG) {
|
||||
sim->figconstraint.linepnt[start + 4] = 0;
|
||||
}
|
||||
for (int i=0; i<npoints; i++) {
|
||||
// x
|
||||
sim->figconstraint.linedata[start + 0][2*i] = i;
|
||||
sim->figconstraint.linedata[start + 1][2*i] = i;
|
||||
sim->figconstraint.linedata[start + 2][2*i] = i;
|
||||
sim->figconstraint.linedata[start + 3][2*i] = i;
|
||||
sim->figconstraint.linedata[start + 4][2*i] = i;
|
||||
|
||||
// y
|
||||
int nefc = nisland == 1 ? d->nefc : d->island_efcnum[k];
|
||||
sim->figconstraint.linedata[start + 0][2*i+1] = nefc;
|
||||
const mjSolverStat* stat = d->solver + k*mjNSOLVER + i;
|
||||
sim->figconstraint.linedata[start + 1][2*i+1] = stat->nactive;
|
||||
sim->figconstraint.linedata[start + 2][2*i+1] = stat->nchange;
|
||||
sim->figconstraint.linedata[start + 3][2*i+1] = stat->neval;
|
||||
sim->figconstraint.linedata[start + 4][2*i+1] = stat->nupdate;
|
||||
}
|
||||
|
||||
// update cost figure
|
||||
start = kCostNum * k;
|
||||
sim->figcost.linepnt[start + 0] = npoints;
|
||||
for (int i=1; i<kCostNum; i++) {
|
||||
sim->figcost.linepnt[start + i] = npoints;
|
||||
}
|
||||
if (m->opt.solver==mjSOL_PGS) {
|
||||
sim->figcost.linepnt[start + 1] = 0;
|
||||
sim->figcost.linepnt[start + 2] = 0;
|
||||
}
|
||||
|
||||
for (int i=0; i<sim->figcost.linepnt[0]; i++) {
|
||||
// x
|
||||
sim->figcost.linedata[start + 0][2*i] = i;
|
||||
sim->figcost.linedata[start + 1][2*i] = i;
|
||||
sim->figcost.linedata[start + 2][2*i] = i;
|
||||
|
||||
// y
|
||||
const mjSolverStat* stat = d->solver + k*mjNSOLVER + i;
|
||||
sim->figcost.linedata[start + 0][2*i + 1] =
|
||||
mju_log10(mju_max(mjMINVAL, stat->improvement));
|
||||
sim->figcost.linedata[start + 1][2*i + 1] =
|
||||
mju_log10(mju_max(mjMINVAL, stat->gradient));
|
||||
sim->figcost.linedata[start + 2][2*i + 1] =
|
||||
mju_log10(mju_max(mjMINVAL, stat->lineslope));
|
||||
}
|
||||
}
|
||||
|
||||
// get timers: total, collision, prepare, solve, other
|
||||
@@ -355,14 +395,22 @@ void UpdateProfiler(mj::Simulate* sim, const mjModel* m, const mjData* d) {
|
||||
}
|
||||
}
|
||||
|
||||
// get total number of iterations and nonzeros
|
||||
mjtNum sqrt_nnz = 0;
|
||||
int solver_niter = 0;
|
||||
for (int island=0; island < nisland; island++) {
|
||||
sqrt_nnz += mju_sqrt(d->solver_nnz[island]);
|
||||
solver_niter += d->solver_niter[island];
|
||||
}
|
||||
|
||||
// get sizes: nv, nbody, nefc, sqrt(nnz), ncont, iter
|
||||
float sdata[6] = {
|
||||
static_cast<float>(m->nv),
|
||||
static_cast<float>(m->nbody),
|
||||
static_cast<float>(d->nefc),
|
||||
static_cast<float>(mju_sqrt(d->solver_nnz)),
|
||||
static_cast<float>(sqrt_nnz),
|
||||
static_cast<float>(d->ncon),
|
||||
static_cast<float>(d->solver_iter)
|
||||
static_cast<float>(solver_niter)
|
||||
};
|
||||
|
||||
// update figsize
|
||||
@@ -497,14 +545,22 @@ void UpdateInfoText(mj::Simulate* sim, const mjModel* m, const mjData* d,
|
||||
char (&content)[mj::Simulate::kMaxFilenameLength]) {
|
||||
char tmp[20];
|
||||
|
||||
// compute solver error
|
||||
// number of islands with statistics
|
||||
int nisland = mjMIN(d->solver_nisland, mjNISLAND);
|
||||
|
||||
// compute solver error (maximum over islands)
|
||||
mjtNum solerr = 0;
|
||||
if (d->solver_iter) {
|
||||
int ind = mjMIN(d->solver_iter-1, mjNSOLVER-1);
|
||||
solerr = mju_min(d->solver[ind].improvement, d->solver[ind].gradient);
|
||||
if (solerr==0) {
|
||||
solerr = mju_max(d->solver[ind].improvement, d->solver[ind].gradient);
|
||||
for (int i=0; i < nisland; i++) {
|
||||
mjtNum solerr_i = 0;
|
||||
if (d->solver_niter[i]) {
|
||||
int ind = mjMIN(d->solver_niter[i], mjNSOLVER) - 1;
|
||||
const mjSolverStat* stat = d->solver + i*mjNSOLVER + ind;
|
||||
solerr_i = mju_min(stat->improvement, stat->gradient);
|
||||
if (solerr_i==0) {
|
||||
solerr_i = mju_max(stat->improvement, stat->gradient);
|
||||
}
|
||||
}
|
||||
solerr = mju_max(solerr, solerr_i);
|
||||
}
|
||||
solerr = mju_log10(mju_max(mjMINVAL, solerr));
|
||||
|
||||
@@ -516,6 +572,12 @@ void UpdateInfoText(mj::Simulate* sim, const mjModel* m, const mjData* d,
|
||||
mju::sprintf_arr(fps, "%.0f ", sim->fps_);
|
||||
}
|
||||
|
||||
// total iterations of all islands with statistics
|
||||
int solver_niter = 0;
|
||||
for (int i=0; i < nisland; i++) {
|
||||
solver_niter += d->solver_niter[i];
|
||||
}
|
||||
|
||||
// prepare info text
|
||||
mju::strcpy_arr(title, "Time\nSize\nCPU\nSolver \nFPS\nMemory");
|
||||
mju::sprintf_arr(content,
|
||||
@@ -525,7 +587,7 @@ void UpdateInfoText(mj::Simulate* sim, const mjModel* m, const mjData* d,
|
||||
sim->run ?
|
||||
d->timer[mjTIMER_STEP].duration / mjMAX(1, d->timer[mjTIMER_STEP].number) :
|
||||
d->timer[mjTIMER_FORWARD].duration / mjMAX(1, d->timer[mjTIMER_FORWARD].number),
|
||||
solerr, d->solver_iter,
|
||||
solerr, solver_niter,
|
||||
fps,
|
||||
d->maxuse_arena/(double)(d->narena),
|
||||
mju_writeNumBytes(d->narena));
|
||||
|
||||
Reference in New Issue
Block a user