add common vector definition in ngspice code, vectorize CKTterr and BSIM3v32SIMDtrunc

This commit is contained in:
Florian Ballenegger 2020-07-25 12:34:32 +02:00
parent 47249ad57f
commit 47ae4fc706
19 changed files with 374 additions and 22 deletions

View File

@ -1228,6 +1228,32 @@ if test "x$enable_modsimd" = xyes; then
])
fi
# now adjust compiler flags
if test "x$enable_modsimd" = xyes; then
SIMD_CPPFLAGS=""
SIMD_LDFLAGS=""
AC_MSG_CHECKING(whether compiler understands -fopenmp-simd)
old_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -fopenmp-simd -Werror"
AC_TRY_COMPILE([],[], [
AC_MSG_RESULT(yes)
SIMD_CFLAGS="-fopenmp-simd"
],[
AC_MSG_RESULT(no)
AC_MSG_WARN([Compiler might not understand pragma omp simd])
SIMD_CFLAGS=""
])
CFLAGS="$old_CFLAGS"
#add -ffast-math, might need to be adjusted depending on your compiler
SIMD_CFLAGS="$SIMD_CFLAGS -ffast-math"
AC_SUBST(SIMD_CPPFLAGS)
AC_SUBST(SIMD_LDFLAGS)
AC_SUBST(SIMD_CFLAGS)
fi
if test "x$enable_modsimd" = xyes; then
AC_DEFINE([BSIM3v32SIMD], [1], [simd acceleration for BSIM3V32 device])
@ -1252,6 +1278,7 @@ AC_CONFIG_FILES([Makefile
src/Makefile
src/spicelib/Makefile
src/spicelib/analysis/Makefile
src/spicelib/analysis/SIMD/Makefile
src/spicelib/devices/Makefile
src/spicelib/devices/asrc/Makefile
src/spicelib/devices/bjt/Makefile

View File

@ -71,8 +71,8 @@ Xadd a1 a2 a3 a4 a1 a2 a3 a4 a1 a2 a3 a4 a1 a2 a3 a4 a1 a2 a3 a4 a1 a2 a3 a4 a1
.save V(a1) V(a2) V(a3) V(a4) V(b1) V(b2) V(b3) V(b4)
* use BSIM3 model with default parameters
.model n1 nmos level=49 version=3.2.4
.model p1 pmos level=49 version=3.2.4
.model n1 nmos level=49 version=3.2.4simd
.model p1 pmos level=49 version=3.2.4simd
*.include ./Modelcards/modelcard32.nmos
*.include ./Modelcards/modelcard32.pmos

View File

@ -151,6 +151,11 @@ ngspice_LDADD += \
spicelib/analysis/libckt.la \
spicelib/devices/libdev.la
if WANT_MODSIMD
ngspice_LDADD += \
spicelib/analysis/SIMD/libcktsimd.la
endif
if SENSE2_WANTED
ngspice_LDADD += unsupported/libunsupported.la
endif
@ -435,6 +440,11 @@ libspice_la_LIBADD += \
spicelib/analysis/libckt.la \
spicelib/devices/libdev.la
if WANT_MODSIMD
libspice_la_LIBADD += \
spicelib/analysis/SIMD/libcktsimd.la
endif
if XSPICE_WANTED
libspice_la_LIBADD += \
xspice/evt/libevtxsp.la \
@ -555,6 +565,11 @@ libngspice_la_LIBADD += \
spicelib/analysis/libckt.la \
spicelib/devices/libdev.la
if WANT_MODSIMD
libngspice_la_LIBADD += \
spicelib/analysis/SIMD/libcktsimd.la
endif
if XSPICE_WANTED
libngspice_la_LIBADD += \
xspice/evt/libevtxsp.la \

View File

@ -0,0 +1,8 @@
#ifndef ngspice_CKT_SIMD_H
#define ngspice_CKT_SIMD_H
#include "ngspice/SIMD/simdvector.h"
extern void vecN_CKTterr(VecNi , CKTcircuit *, double *);
#endif

View File

@ -0,0 +1,6 @@
#ifndef NG_SIMD_DEF_H
#define NG_SIMD_DEF_H
#define NSIMD 4
#endif

View File

@ -0,0 +1,104 @@
/*******************************************************************************
* Copyright 2020 Florian Ballenegger, Anamosic Ballenegger Design
*******************************************************************************
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#ifndef NG_SIMD_OP_H
#define NG_SIMD_OP_H
#include "ngspice/SIMD/simdvector.h"
inline VecNd vecN_broadcast(double x)
{
VecNd res;
for(int i=0;i<NSIMD;i++)
res[i]=x;
return res;
}
inline VecNd vecN_lu(double* array, VecNi indexes)
{
VecNd res;
for(int i=0;i<NSIMD;i++)
res[i]=array[indexes[i]];
return res;
}
inline VecNd vecN_MAX(VecNd a, VecNd b)
{
VecNd res;
for(int i=0;i<NSIMD;i++)
res[i]=(a[i] > b[i]) ? a[i] : b[i];
return res;
}
inline VecNd vecN_fabs(VecNd x)
{
VecNd res;
for(int i=0;i<NSIMD;i++)
res[i]=fabs(x[i]);
return res;
}
inline VecNd vecN_sqrt(VecNd x)
{
VecNd res;
for(int i=0;i<NSIMD;i++)
res[i]=sqrt(x[i]);
return res;
}
inline VecNd vecN_pow(VecNd x, double p)
{
VecNd res;
for(int i=0;i<NSIMD;i++)
res[i]=log(x[i]);
res = res*p;
for(int i=0;i<NSIMD;i++)
res[i]=exp(res[i]);
return res;
}
inline VecNd vecN_exp(VecNd x)
{
VecNd res;
for(int i=0;i<NSIMD;i++)
res[i]=exp(x[i]);
return res;
}
inline VecNd vecN_log(VecNd x)
{
VecNd res;
for(int i=0;i<NSIMD;i++)
res[i]=log(x[i]);
return res;
}
#endif

View File

@ -0,0 +1,32 @@
#ifndef NG_SIMD_VECTOR_H
#define NG_SIMD_VECTOR_H
#include "ngspice/SIMD/simddef.h"
#ifndef NSIMD
#error NSIMD must be defined
#endif
#if NSIMD==4
typedef double Vec4d __attribute__ ((vector_size (sizeof(double)*4), aligned (sizeof(double)*4)));
typedef int64_t Vec4m __attribute__ ((vector_size (sizeof(double)*4), aligned (sizeof(double)*4)));
typedef int64_t Vec4i __attribute__ ((vector_size (sizeof(double)*4), aligned (sizeof(double)*4)));
#define VecNd Vec4d
#define VecNm Vec4m
#define VecNi Vec4i
#endif
#if NSIMD==8
typedef double Vec8d __attribute__ ((vector_size (sizeof(double)*8), aligned (sizeof(double)*8)));
typedef int64_t Vec8m __attribute__ ((vector_size (sizeof(double)*8), aligned (sizeof(double)*8)));
typedef int64_t Vec8i __attribute__ ((vector_size (sizeof(double)*8), aligned (sizeof(double)*8)));
#define VecNd Vec8d
#define VecNm Vec8m
#define VecNi Vec8i
#endif
#endif

View File

@ -1,5 +1,10 @@
## Process this file with automake to produce Makefile.in
DIST_SUBDIRS = SIMD
if WANT_MODSIMD
SUBDIRS = SIMD
endif
noinst_LTLIBRARIES = libckt.la
libckt_la_SOURCES = \

View File

@ -0,0 +1,10 @@
## Process this file with automake to produce Makefile.in
noinst_LTLIBRARIES = libcktsimd.la
libcktsimd_la_SOURCES = \
simdcktterr.c
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include -I$(top_srcdir)/src/spicelib/devices
AM_CFLAGS = $(STATIC) $(SIMD_CFLAGS)
MAINTAINERCLEANFILES = Makefile.in

View File

@ -0,0 +1,90 @@
/**********
Copyright 1990 Regents of the University of California. All rights reserved.
Author: 1985 Thomas L. Quarles
**********/
/**********
Copyright 2020 Anamosic Ballenegger Design
Author: 2020 Florian Ballenegger
Vector version.
**********/
#include "ngspice/ngspice.h"
#include "ngspice/cktdefs.h"
#include "ngspice/SIMD/simdvector.h"
#include "ngspice/SIMD/simdop.h"
#include "ngspice/SIMD/simdckt.h"
void
vecN_CKTterr(VecNi qcap, CKTcircuit *ckt, double *timeStep)
{
VecNd volttol;
VecNd chargetol;
VecNd tol;
VecNd del;
VecNd diff[8];
double deltmp[8];
double factor=0;
VecNi ccap;
int i;
int j;
int k;
static double gearCoeff[] = {
.5,
.2222222222,
.1363636364,
.096,
.07299270073,
.05830903790
};
static double trapCoeff[] = {
.5,
.08333333333
};
ccap = qcap+1;
volttol = ckt->CKTabstol + ckt->CKTreltol *
vecN_MAX( vecN_fabs(vecN_lu(ckt->CKTstate0,ccap)), vecN_fabs(vecN_lu(ckt->CKTstate1,ccap)));
chargetol = vecN_MAX(vecN_fabs(vecN_lu(ckt->CKTstate0,qcap)),vecN_fabs(vecN_lu(ckt->CKTstate1,qcap)));
chargetol = ckt->CKTreltol * vecN_MAX(chargetol,vecN_broadcast(ckt->CKTchgtol))/ckt->CKTdelta;
tol = vecN_MAX(volttol,chargetol);
/* now divided differences */
for(i=ckt->CKTorder+1;i>=0;i--) {
diff[i] = vecN_lu(ckt->CKTstates[i],qcap);
}
for(i=0 ; i <= ckt->CKTorder ; i++) {
deltmp[i] = ckt->CKTdeltaOld[i];
}
j = ckt->CKTorder;
for (;;) {
for(i=0;i <= j;i++) {
diff[i] = (diff[i] - diff[i+1])/deltmp[i];
}
if (--j < 0) break;
for(i=0;i <= j;i++) {
deltmp[i] = deltmp[i+1] + ckt->CKTdeltaOld[i];
}
}
switch(ckt->CKTintegrateMethod) {
case GEAR:
factor = gearCoeff[ckt->CKTorder-1];
break;
case TRAPEZOIDAL:
factor = trapCoeff[ckt->CKTorder - 1] ;
break;
}
del = ckt->CKTtrtol * tol/vecN_MAX(vecN_broadcast(ckt->CKTabstol),factor * vecN_fabs(diff[0]));
if(ckt->CKTorder == 2) {
del = vecN_sqrt(del);
} else if (ckt->CKTorder > 2) {
del = vecN_exp(vecN_log(del)/ckt->CKTorder);
}
/* now reduce with minimum */
for(k=0;k<NSIMD;k++)
if(del[k]<(*timeStep))
*timeStep = del[k];
return;
}

View File

@ -38,7 +38,7 @@ endif
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include
AM_CFLAGS = $(STATIC)
if WANT_MODSIMD
AM_CFLAGS += -fno-math-errno -ffast-math -fopenmp-simd
AM_CFLAGS += $(SIMD_CFLAGS)
endif
MAINTAINERCLEANFILES = Makefile.in

View File

@ -32,8 +32,8 @@
#define DELTA_4 0.02
#ifdef USE_OMP
int BSIM3v32LoadOMP(BSIM3v32instance *here, CKTcircuit *ckt);
void BSIM3v32LoadRhsMat(GENmodel *inModel, CKTcircuit *ckt);
int BSIM3v32SIMDLoadOMP(BSIM3v32instance *here, CKTcircuit *ckt);
void BSIM3v32SIMDLoadRhsMat(GENmodel *inModel, CKTcircuit *ckt);
#endif
int
@ -49,18 +49,18 @@ BSIM3v32SIMDload (GENmodel *inModel, CKTcircuit *ckt)
#pragma omp parallel for
for (idx = 0; idx < model->BSIM3v32InstCount; idx++) {
BSIM3v32instance *here = InstArray[idx];
int local_error = BSIM3v32LoadOMP(here, ckt);
int local_error = BSIM3v32SIMDLoadOMP(here, ckt);
if (local_error)
error = local_error;
}
BSIM3v32LoadRhsMat(inModel, ckt);
BSIM3v32SIMDLoadRhsMat(inModel, ckt);
return error;
}
int BSIM3v32LoadOMP(BSIM3v32instance *here, CKTcircuit *ckt) {
int BSIM3v32SIMDLoadOMP(BSIM3v32instance *here, CKTcircuit *ckt) {
BSIM3v32model *model = BSIM3v32modPtr(here);
#else
BSIM3v32model *model = (BSIM3v32model*)inModel;
@ -3479,7 +3479,7 @@ return(OK);
}
#ifdef USE_OMP
void BSIM3v32LoadRhsMat(GENmodel *inModel, CKTcircuit *ckt)
void BSIM3v32SIMDLoadRhsMat(GENmodel *inModel, CKTcircuit *ckt)
{
int InstCount, idx;
BSIM3v32instance **InstArray;

View File

@ -40,7 +40,7 @@
extern int BSIM3v32LoadSeq(BSIM3v32instance *here, CKTcircuit *ckt, double* data, int stride);
extern int BSIM3v32LoadSIMD(BSIM3v32instance **heres, CKTcircuit *ckt, double data[7][NSIMD]);
#else
extern void BSIM3v32LoadRhsMat(GENmodel *inModel, CKTcircuit *ckt);
extern void BSIM3v32SIMDLoadRhsMat(GENmodel *inModel, CKTcircuit *ckt);
extern int BSIM3v32LoadSeq(BSIM3v32instance *here, CKTcircuit *ckt, int);
extern int BSIM3v32LoadSIMD(BSIM3v32instance **heres, CKTcircuit *ckt);
#endif
@ -147,7 +147,7 @@ BSIM3v32SIMDloadSel (GENmodel *inModel, CKTcircuit *ckt)
}
}
BSIM3v32LoadRhsMat(inModel, ckt);
BSIM3v32SIMDLoadRhsMat(inModel, ckt);
return error;
}
@ -251,7 +251,7 @@ BSIM3v32loadSelVrai (GENmodel *inModel, CKTcircuit *ckt)
}
if(DEBUG) printf("Now write the matrix\n");
/* Write in matrix sequentially */
BSIM3v32LoadRhsMat(inModel, ckt);
BSIM3v32SIMDLoadRhsMat(inModel, ckt);
return error;
}

View File

@ -40,6 +40,8 @@
#include "ngspice/devdefs.h"
#include "ngspice/suffix.h"
#include "ngspice/SIMD/simdvector.h"
#if USEX86INTRINSICS==1
#include <x86intrin.h>
#endif

View File

@ -28,9 +28,6 @@
* POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
typedef double Vec4d __attribute__ ((vector_size (sizeof(double)*4), aligned (sizeof(double)*4)));
typedef int64_t Vec4m __attribute__ ((vector_size (sizeof(double)*4), aligned (sizeof(double)*4)));
#if USEX86INTRINSICS==1
static inline Vec4d vec4_blend(Vec4d fa, Vec4d tr, Vec4m mask)

View File

@ -28,9 +28,6 @@
* POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
typedef double Vec8d __attribute__ ((vector_size (sizeof(double)*8), aligned (sizeof(double)*8)));
typedef int64_t Vec8m __attribute__ ((vector_size (sizeof(double)*8), aligned (sizeof(double)*8)));
static inline Vec8d vec8_blend(Vec8d fa, Vec8d tr, Vec8m mask)
{
Vec8d r;

View File

@ -1211,7 +1211,7 @@ do { if((here->ptr = SMPmakeElt(matrix, here->first, here->second)) == NULL){\
}
}
}
printf("BSIM3v32/SIMD has %d groups\n",ngroups);
printf("BSIM3v32/SIMD has %d groups and %d instances total\n",ngroups, InstCount);
if (cp_getvar("no_modsimd", CP_BOOL, NULL, 0))
{
printf("BSIM3v32 simd disabled at runtime\n");

View File

@ -14,10 +14,12 @@
#include "bsim3v32def.h"
#include "ngspice/sperror.h"
#include "ngspice/suffix.h"
#include "ngspice/SIMD/simdvector.h"
#include "ngspice/SIMD/simdckt.h"
#include <float.h>
int
BSIM3v32SIMDtrunc (GENmodel *inModel, CKTcircuit *ckt, double *timeStep)
BSIM3v32SIMDtruncSeq (GENmodel *inModel, CKTcircuit *ckt, double *timeStep)
{
BSIM3v32model *model = (BSIM3v32model*)inModel;
BSIM3v32instance *here;
@ -46,3 +48,60 @@ BSIM3v32instance *here;
}
return(OK);
}
/* omp multiprocessing is found to be counter-productive here, probably due to
overhead, so we disable it for the BSIM3v32SIMDtrunc function */
#undef USE_OMP
int
BSIM3v32SIMDtrunc (GENmodel *inModel, CKTcircuit *ckt, double *timeStep)
{
BSIM3v32model *model = (BSIM3v32model*)inModel;
BSIM3v32instance *here;
#ifdef STEPDEBUG
double debugtemp;
#endif /* STEPDEBUG */
int i;
#ifndef USE_OMP
#define TIMESTEPptr timeStep
#else
double reduTimeStep = *timeStep;
#define TIMESTEPptr &locTimeStep
#pragma omp parallel for reduction(min:reduTimeStep)
#endif
for(i=0;i<model->BSIM3v32InstCount;i+=NSIMD)
{
VecNi indexes;
#ifdef USE_OMP
double locTimeStep = *timeStep;
#endif
for(int k=0;k<NSIMD;k++)
indexes[k] = model->BSIM3v32InstanceArray[i+k]->BSIM3v32qb;
vecN_CKTterr(indexes,ckt,TIMESTEPptr);
for(int k=0;k<NSIMD;k++)
indexes[k] = model->BSIM3v32InstanceArray[i+k]->BSIM3v32qg;
vecN_CKTterr(indexes,ckt,TIMESTEPptr);
for(int k=0;k<NSIMD;k++)
indexes[k] = model->BSIM3v32InstanceArray[i+k]->BSIM3v32qd;
vecN_CKTterr(indexes,ckt,TIMESTEPptr);
#ifdef USE_OMP
reduTimeStep = fmin(reduTimeStep,locTimeStep);
#endif
}
#ifdef USE_OMP
*timeStep = reduTimeStep;
i=model->BSIM3v32InstCount & (NSIMD-1);
#endif
/* less than NSIMD devices left: not worth to use openMP ? */
for(;i<model->BSIM3v32InstCount;i++)
{
CKTterr(model->BSIM3v32InstanceArray[i]->BSIM3v32qb,ckt,timeStep);
CKTterr(model->BSIM3v32InstanceArray[i]->BSIM3v32qg,ckt,timeStep);
CKTterr(model->BSIM3v32InstanceArray[i]->BSIM3v32qd,ckt,timeStep);
}
return(OK);
}

View File

@ -18,7 +18,7 @@ File: bsim3v32def.h
#include "ngspice/noisedef.h"
#ifdef BSIM3v32SIMD
#define NSIMD 4
#include "ngspice/SIMD/simddef.h"
#endif
#define OMP_EFFMEM