Skip to content

Commit

Permalink
perf(rmtxop): Added memory-mapping for double matrices
Browse files Browse the repository at this point in the history
  • Loading branch information
Gregungory committed Mar 4, 2022
1 parent 51ed684 commit c23375f
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 58 deletions.
4 changes: 4 additions & 0 deletions doc/notes/ReleaseNotes
Original file line number Diff line number Diff line change
Expand Up @@ -2504,3 +2504,7 @@ sanity checks.

Added -O option to pvalue and pextrem to report watts/sr/m^2 even if
picture is XYZE.

Made subtle changes to header i/o routines to preserve alignment in
binary file formats to enable memory-mapping. Implemented memory-mapped
matrix loading in rmtxop for binary double files.
148 changes: 95 additions & 53 deletions src/util/rmatrix.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef lint
static const char RCSid[] = "$Id: rmatrix.c,v 2.49 2022/03/03 03:55:13 greg Exp $";
static const char RCSid[] = "$Id: rmatrix.c,v 2.50 2022/03/04 01:27:12 greg Exp $";
#endif
/*
* General matrix operations.
Expand All @@ -12,25 +12,51 @@ static const char RCSid[] = "$Id: rmatrix.c,v 2.49 2022/03/03 03:55:13 greg Exp
#include "resolu.h"
#include "paths.h"
#include "rmatrix.h"
#if !defined(_WIN32) && !defined(_WIN64)
#include <sys/mman.h>
#endif

static char rmx_mismatch_warn[] = "WARNING: data type mismatch\n";

/* Allocate a nr x nc matrix with n components */
#define array_size(rm) (sizeof(double)*(rm)->nrows*(rm)->ncols*(rm)->ncomp)
#define mapped_size(rm) ((char *)(rm)->mtx + array_size(rm) - (char *)(rm)->mapped)

/* Initialize a RMATRIX struct but don't allocate array space */
RMATRIX *
rmx_new(int nr, int nc, int n)
{
RMATRIX *dnew = (RMATRIX *)calloc(1, sizeof(RMATRIX));

if (dnew) {
dnew->dtype = DTdouble;
dnew->nrows = nr;
dnew->ncols = nc;
dnew->ncomp = n;
}
return(dnew);
}

/* Prepare a RMATRIX for writing (allocate array if needed) */
int
rmx_prepare(RMATRIX *rm)
{
if (!rm) return(0);
if (rm->mtx)
return(1);
rm->mtx = (double *)malloc(array_size(rm));
return(rm->mtx != NULL);
}

/* Call rmx_new() and rmx_prepare() */
RMATRIX *
rmx_alloc(int nr, int nc, int n)
{
RMATRIX *dnew;
RMATRIX *dnew = rmx_new(nr, nc, n);

if ((nr <= 0) | (nc <= 0) | (n <= 0))
return(NULL);
dnew = (RMATRIX *)malloc(sizeof(RMATRIX)-sizeof(dnew->mtx) +
sizeof(dnew->mtx[0])*n*nr*nc);
if (!dnew)
return(NULL);
dnew->nrows = nr; dnew->ncols = nc; dnew->ncomp = n;
dnew->dtype = DTdouble;
dnew->swapin = 0;
dnew->info = NULL;
if (dnew && !rmx_prepare(dnew)) {
rmx_free(dnew);
dnew = NULL;
}
return(dnew);
}

Expand All @@ -41,6 +67,12 @@ rmx_free(RMATRIX *rm)
if (!rm) return;
if (rm->info)
free(rm->info);
#ifdef MAP_FILE
if (rm->mapped)
munmap(rm->mapped, mapped_size(rm));
else
#endif
free(rm->mtx);
free(rm);
}

Expand All @@ -61,17 +93,21 @@ rmx_newtype(int dtyp1, int dtyp2)
int
rmx_addinfo(RMATRIX *rm, const char *info)
{
int oldlen = 0;

if (!rm || !info || !*info)
return(0);
if (!rm->info) {
rm->info = (char *)malloc(strlen(info)+1);
if (rm->info) rm->info[0] = '\0';
} else
} else {
oldlen = strlen(rm->info);
rm->info = (char *)realloc(rm->info,
strlen(rm->info)+strlen(info)+1);
oldlen+strlen(info)+1);
}
if (!rm->info)
return(0);
strcat(rm->info, info);
strcpy(rm->info+oldlen, info);
return(1);
}

Expand Down Expand Up @@ -102,19 +138,19 @@ get_dminfo(char *s, void *p)
}
if (isexpos(s)) {
double d = exposval(s);
scalecolor(ip->mtx, d);
scalecolor(ip->cexp, d);
return(0);
}
if (iscolcor(s)) {
COLOR ctmp;
colcorval(ctmp, s);
multcolor(ip->mtx, ctmp);
multcolor(ip->cexp, ctmp);
return(0);
}
if (!formatval(fmt, s)) {
rmx_addinfo(ip, s);
return(0);
}
} /* else check format */
for (i = 1; i < DTend; i++)
if (!strcmp(fmt, cm_fmt_id[i])) {
ip->dtype = i;
Expand All @@ -128,6 +164,8 @@ rmx_load_ascii(RMATRIX *rm, FILE *fp)
{
int i, j, k;

if (!rmx_prepare(rm))
return(0);
for (i = 0; i < rm->nrows; i++)
for (j = 0; j < rm->ncols; j++)
for (k = 0; k < rm->ncomp; k++)
Expand All @@ -146,6 +184,8 @@ rmx_load_float(RMATRIX *rm, FILE *fp)
fputs("Unsupported # components in rmx_load_float()\n", stderr);
exit(1);
}
if (!rmx_prepare(rm))
return(0);
for (i = 0; i < rm->nrows; i++)
for (j = 0; j < rm->ncols; j++) {
if (getbinary(val, sizeof(val[0]), rm->ncomp, fp) != rm->ncomp)
Expand All @@ -162,12 +202,20 @@ static int
rmx_load_double(RMATRIX *rm, FILE *fp)
{
int i;

if ((char *)&rmx_lval(rm,1,0,0) - (char *)&rmx_lval(rm,0,0,0) !=
sizeof(double)*rm->ncols*rm->ncomp) {
fputs("Code error in rmx_load_double()\n", stderr);
exit(1);
#ifdef MAP_FILE
long pos; /* map memory to file if possible */
if (!rm->swapin && (pos = ftell(fp)) >= 0 && !(pos % sizeof(double))) {
rm->mapped = mmap(NULL, array_size(rm)+pos, PROT_READ|PROT_WRITE,
MAP_PRIVATE, fileno(fp), 0);
if (rm->mapped != MAP_FAILED) {
rm->mtx = (double *)rm->mapped + pos/sizeof(double);
return(1);
}
rm->mapped = NULL;
}
#endif
if (!rmx_prepare(rm))
return(0);
for (i = 0; i < rm->nrows; i++) {
if (getbinary(&rmx_lval(rm,i,0,0), sizeof(double)*rm->ncomp,
rm->ncols, fp) != rm->ncols)
Expand All @@ -186,6 +234,8 @@ rmx_load_rgbe(RMATRIX *rm, FILE *fp)

if (!scan)
return(0);
if (!rmx_prepare(rm))
return(0);
for (i = 0; i < rm->nrows; i++) {
if (freadscan(scan, rm->ncols, fp) < 0) {
free(scan);
Expand All @@ -206,7 +256,6 @@ RMATRIX *
rmx_load(const char *inspec, RMPref rmp)
{
FILE *fp;
RMATRIX dinfo;
RMATRIX *dnew;

if (!inspec)
Expand Down Expand Up @@ -242,49 +291,40 @@ rmx_load(const char *inspec, RMPref rmp)
#ifdef getc_unlocked
flockfile(fp);
#endif
dinfo.nrows = dinfo.ncols = dinfo.ncomp = 0;
dinfo.dtype = DTascii; /* assumed w/o FORMAT */
dinfo.swapin = 0;
dinfo.info = NULL;
dinfo.mtx[0] = dinfo.mtx[1] = dinfo.mtx[2] = 1.;
if (getheader(fp, get_dminfo, &dinfo) < 0) {
if (!(dnew = rmx_new(0,0,3))) {
fclose(fp);
return(NULL);
}
if ((dinfo.nrows <= 0) | (dinfo.ncols <= 0)) {
if (!fscnresolu(&dinfo.ncols, &dinfo.nrows, fp)) {
dnew->dtype = DTascii; /* assumed w/o FORMAT */
dnew->cexp[0] = dnew->cexp[1] = dnew->cexp[2] = 1.f;
if (getheader(fp, get_dminfo, dnew) < 0) {
fclose(fp);
return(NULL);
}
if ((dnew->nrows <= 0) | (dnew->ncols <= 0)) {
if (!fscnresolu(&dnew->ncols, &dnew->nrows, fp)) {
fclose(fp);
return(NULL);
}
if (dinfo.ncomp <= 0)
dinfo.ncomp = 3;
else if ((dinfo.dtype == DTrgbe) | (dinfo.dtype == DTxyze) &&
dinfo.ncomp != 3) {
if ((dnew->dtype == DTrgbe) | (dnew->dtype == DTxyze) &&
dnew->ncomp != 3) {
fclose(fp);
return(NULL);
}
}
dnew = rmx_alloc(dinfo.nrows, dinfo.ncols, dinfo.ncomp);
if (!dnew) {
fclose(fp);
return(NULL);
}
dnew->info = dinfo.info;
switch (dinfo.dtype) {
switch (dnew->dtype) {
case DTascii:
SET_FILE_TEXT(fp);
if (!rmx_load_ascii(dnew, fp))
goto loaderr;
dnew->dtype = DTascii; /* should leave double? */
break;
case DTfloat:
dnew->swapin = dinfo.swapin;
if (!rmx_load_float(dnew, fp))
goto loaderr;
dnew->dtype = DTfloat;
break;
case DTdouble:
dnew->swapin = dinfo.swapin;
if (!rmx_load_double(dnew, fp))
goto loaderr;
dnew->dtype = DTdouble;
Expand All @@ -293,14 +333,16 @@ rmx_load(const char *inspec, RMPref rmp)
case DTxyze:
if (!rmx_load_rgbe(dnew, fp))
goto loaderr;
dnew->dtype = dinfo.dtype; /* undo exposure? */
if ((dinfo.mtx[0] != 1.) | (dinfo.mtx[1] != 1.) |
(dinfo.mtx[2] != 1.)) {
dinfo.mtx[0] = 1./dinfo.mtx[0];
dinfo.mtx[1] = 1./dinfo.mtx[1];
dinfo.mtx[2] = 1./dinfo.mtx[2];
rmx_scale(dnew, dinfo.mtx);
/* undo exposure? */
if ((dnew->cexp[0] != 1.f) | (dnew->cexp[1] != 1.f) |
(dnew->cexp[2] != 1.f)) {
double cmlt[3];
cmlt[0] = 1./dnew->cexp[0];
cmlt[1] = 1./dnew->cexp[1];
cmlt[2] = 1./dnew->cexp[2];
rmx_scale(dnew, cmlt);
}
dnew->swapin = 0;
break;
default:
goto loaderr;
Expand Down
18 changes: 13 additions & 5 deletions src/util/rmatrix.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* RCSid $Id: rmatrix.h,v 2.13 2021/01/19 23:32:00 greg Exp $ */
/* RCSid $Id: rmatrix.h,v 2.14 2022/03/04 01:27:12 greg Exp $ */
/*
* Header file for general matrix routines.
*/
Expand All @@ -16,19 +16,27 @@ extern "C" {
transmission, reflection front (normal side), reflection back */
typedef enum {RMPtrans=0, RMPreflF, RMPreflB} RMPref;

/* General plane-ordered component matrix */
/* General [row][col][cmp] component matrix */
typedef struct {
char *info;
void *mapped;
double *mtx;
COLOR cexp;
int nrows, ncols;
short ncomp;
uby8 dtype;
uby8 swapin;
char *info;
double mtx[3]; /* extends struct */
} RMATRIX;

#define rmx_lval(rm,r,c,i) (rm)->mtx[(i)+(rm)->ncomp*((c)+(size_t)(rm)->ncols*(r))]

/* Allocate a nr x nc matrix with n components */
/* Initialize a RMATRIX struct but don't allocate array space */
extern RMATRIX *rmx_new(int nr, int nc, int n);

/* Prepare a RMATRIX for writing (allocate array if needed) */
extern int rmx_prepare(RMATRIX *rm);

/* Call rmx_new() and rmx_prepare() */
extern RMATRIX *rmx_alloc(int nr, int nc, int n);

/* Free a RMATRIX array */
Expand Down

0 comments on commit c23375f

Please sign in to comment.