GMP and Win32 Memory Management

Linas Vepstas linas at austin.ibm.com
Mon Dec 4 20:26:03 CET 2006


On Mon, Dec 04, 2006 at 11:29:47AM +0100, Emmanuel Thomé wrote:
> On Fri, Dec 01, 2006 at 11:09:30PM +0000, Jim White wrote:
> > [...]
> >
> > The feature is called "memory-mapped files". Stripped
> > [...]
> > From a functional aspect, we can implement a "Save all
> > key variables" and "restore all key variables" feature
> > without doing any IO at all.  At the end of any
> > execution, the mapped file is itself an IMAGE of all
> > variables that were allocated in that address space.
> 
> Really, if you want checkpointing and resuming, that's your application's
> job, not the library's.

Some versions of Linux support checkpointing. However, 
as Emmanuel pointed out, this does not mean that your computations
got "easier", and there's lots of ways of screwing things up, some of
them disasterously. If you want to save intermediae values from a 
computation, you should explicitly save them. This is not hard.

I've attached below a very very simple low-brow wrapper that 
saves & restores values to a database. It has a trivial inteface. 
It'll do what you want, but more reliably and simply.

--linas


/* 
 * db-cache.h
 *
 * File cache for pre-computed bignum values. Stores values,
 * with indicated precision, so we don't waste too much compute 
 * time.
 *
 * You may redistribute this, and/or modify this, under the terms 
 * of the GNU Lesser General Public License as  published by the
 * Free Software Foundation; either version 2.1 of the License,
 * or (at your option) any later version.
 * 
 * Copyright Linas Vepstas July 2006
 */

#include <gmp.h>

/**
 * fp_cache_put -- put mpf_t value into the database.
 * prec: number of decimal places of precision to store.
 * idx:  index under which to store the value
 */
void fp_cache_put (const char * dbname, const mpf_t val, int idx, int nprec);

/**
 * fp_cache_get -- get mpf_t from database
 * Returns 0 if no value in the database, or if the value in the
 * database has fewer than nprec digits. Thus, nprec is a minimum
 * requirement.
 */ 
int fp_cache_get (const char * dbname, mpf_t val, int idx, int nprec);

=================================================================

/* 
 * db-cache.c
 *
 * File cache for pre-computed bignum values.
 *
 * You may redistribute this, and/or modify this, under the terms 
 * of the GNU Lesser General Public License as  published by the
 * Free Software Foundation; either version 2.1 of the License,
 * or (at your option) any later version.
 *
 * Copyright Linas Vepstas July 2006
 */

#include <db_185.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <gmp.h>
#include "db-cache.h"

void fp_cache_put (const char * dbname, const mpf_t val, int idx, int nprec)
{
	DB *db;

	db = dbopen (dbname, O_RDWR|O_EXCL, 
	             S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, DB_HASH, NULL);

	if (!db && (ENOENT == errno))
	{
		db = dbopen (dbname, O_RDWR|O_CREAT|O_EXCL, 
	             S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, DB_HASH, NULL);
	}

	if (!db)
	{
		int norr = errno;
		fprintf (stderr, "Error: cannot open the cache file, idx=%d\n", idx);
		fprintf (stderr, "\t(%d) %s\n", norr, strerror(norr));
		return;
	}

	/* Save the value data to the file */
	DBT vkey;
	char buf[50];
	sprintf (buf, "val[%d]", idx);
	vkey.data = &buf;
	vkey.size = strlen(buf)+1;

	/* the printf is floating point */
	size_t allo = nprec*sizeof(char)+50;
	char *vstr= malloc (allo);
	gmp_snprintf (vstr, allo, "%.*Fg", nprec, val);

	DBT vdat;
	vdat.data = vstr;
	vdat.size = strlen(vstr)+1;

	db->put (db, &vkey, &vdat, 0);
	free (vstr);

	/* Save the precision data to the file */
	DBT pkey;
	sprintf (buf, "prec[%d]", idx);
	pkey.data = &buf;
	pkey.size = strlen(buf)+1;

	DBT pdat;
	pdat.data = &nprec;
	pdat.size = sizeof(int);

	db->put (db, &pkey, &pdat, 0);
	db->close (db);
}

int fp_cache_get (const char * dbname, mpf_t val, int idx, int nprec)
{
	DB *db;

	db = dbopen (dbname, O_RDONLY, 0, DB_HASH, NULL);

	if (!db) return 0;

	/* Look for the stored precision of data in the file */
	DBT pkey;
	char buf[50];
	sprintf (buf, "prec[%d]", idx);
	pkey.data = &buf;
	pkey.size = strlen(buf)+1;

	DBT pdat;

	/* if not key, then nothing */
	int rc = db->get (db, &pkey, &pdat, 0);
	if (rc)
	{
		db->close (db);
		return 0;
	}

	/* check to see if we have enough precision */
	int have_prec = *((int *)pdat.data);
	if (nprec > have_prec)
	{
		db->close (db);
		return 0;
	}

	/* Get the value data from the file */
	DBT vkey;
	sprintf (buf, "val[%d]", idx);
	vkey.data = &buf;
	vkey.size = strlen(buf)+1;

	rc = db->get (db, &vkey, &pdat, 0);
	if (rc)
	{
		db->close (db);
		return 0;
	}

	// printf ("found nprec=%d for %d = %s\n", have_prec, idx, pdat.data);
	mpf_set_str (val, pdat.data, 10);
	
	db->close (db);
	return have_prec;
}

/* ========================== END OF FILE ============= */


More information about the gmp-discuss mailing list