Memory management in .oct files

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Memory management in .oct files

Richard Hindmarsh
If, in Octave, I do

%Step 1
a = rand(3000,3000);

%and then
% Step 2
b = a;

the memory used does not increase hardly at all upon exectuation of Step 2 as presumably Octave only creates new memory
b's data when it is written to.

However, it seems that when I run the matrixdemo.cc example in
http://perso.wanadoo.fr/prthomas/intro.html#matrixdemo
at some stage (perhaps the copy constructor #2, or is it the return statement #7) a third matrix is created in memory.

Could someone kindly inform me as to which of the two steps it is and how I can avoid creating unnecessary copies?

Another useful piece of information would be the Octave equivalent of (cout,endl) <-> (octave_stdout,?) so that I can
be sure that writes to the terminal correspond to the changes in memory usage I see.

I am using cygwin by the way.

Thanks,
Richard

#include <octave/oct.h>
DEFUN_DLD (matrixdemo, args, ,
"My first matrixdemo \n\n\
transpose_of_x=matrixdemo(x) \n") {
  octave_value retval;
  if ( args.length() !=  1 ) {                             // #1
    error("this version of matrixdemo only takes one argument");
    return retval;
  }
  Matrix xin1( args(0).matrix_value() );                   // #2
  int ir = xin1.rows();                                    // #3
  int ic = xin1.cols();
  Matrix xout1(ic,ir);                                     // #4
  for (int ir1 = 0 ; ir1 < ir ; ir1++)                     // #5
    for (int ic1 = 0 ; ic1 < ic ; ic1++) {
      xout1(ic1,ir1) = xin1(ir1,ic1);                      // #6
    }
  return retval = xout1;                                   // #7
}



-------------------------------------------------------------
Octave is freely available under the terms of the GNU GPL.

Octave's home on the web:  http://www.octave.org
How to fund new projects:  http://www.octave.org/funding.html
Subscription information:  http://www.octave.org/archive.html
-------------------------------------------------------------


Reply | Threaded
Open this post in threaded view
|

Memory management in .oct files

John W. Eaton-6
On 16-Mar-2005, Richard Hindmarsh <[hidden email]> wrote:

| If, in Octave, I do
|
| %Step 1
| a = rand(3000,3000);
|
| %and then
| % Step 2
| b = a;
|
| the memory used does not increase hardly at all upon exectuation of
| Step 2 as presumably Octave only creates new memory b's data when it
| is written to.

Correct, the "Step 2" operation simply creates a new name for the same
data and increments a reference count.

| However, it seems that when I run the matrixdemo.cc example in
| http://perso.wanadoo.fr/prthomas/intro.html#matrixdemo
| at some stage (perhaps the copy constructor #2, or is it the return
| statement #7) a third matrix is created in memory.
|
| Could someone kindly inform me as to which of the two steps it is
| and how I can avoid creating unnecessary copies?

| #include <octave/oct.h>
| DEFUN_DLD (matrixdemo, args, ,
| "My first matrixdemo \n\n\
| transpose_of_x=matrixdemo(x) \n") {
|   octave_value retval;
|   if ( args.length() !=  1 ) {                             // #1
|     error("this version of matrixdemo only takes one argument");
|     return retval;
|   }
|   Matrix xin1( args(0).matrix_value() );                   // #2

The copy constructor for the Matrix class increments the reference
count to the underlying data here, so the reference count is 2.

|   int ir = xin1.rows();                                    // #3
|   int ic = xin1.cols();
|   Matrix xout1(ic,ir);                                     // #4
|   for (int ir1 = 0 ; ir1 < ir ; ir1++)                     // #5
|     for (int ic1 = 0 ; ic1 < ic ; ic1++) {
|       xout1(ic1,ir1) = xin1(ir1,ic1);                      // #6

                         ^^^^^^^^^^^^^
Since Octave does not know that this indexing operation appears on the
RHS of the assignment (I think it would be a real mess to try to do
that automatically), it splits off a copy here.  If you don't plan on
modifying the argument that is pass to this function, then you can
avoid the extra copy and the checks on the reference count that are
done each time you use the indexing operator by declaring xin1 as
"const".

| Another useful piece of information would be the Octave equivalent
| of (cout,endl) <-> (octave_stdout,?) so that I can
| be sure that writes to the terminal correspond to the changes in
| memory usage I see.

Does the function flush_octave_stdout, declared in pager.h do what you
want?

jwe



-------------------------------------------------------------
Octave is freely available under the terms of the GNU GPL.

Octave's home on the web:  http://www.octave.org
How to fund new projects:  http://www.octave.org/funding.html
Subscription information:  http://www.octave.org/archive.html
-------------------------------------------------------------


Reply | Threaded
Open this post in threaded view
|

Re: Memory management in .oct files

Richard Hindmarsh

>|   int ir = xin1.rows();                                    // #3
>|   int ic = xin1.cols();
>|   Matrix xout1(ic,ir);                                     // #4
>|   for (int ir1 = 0 ; ir1 < ir ; ir1++)                     // #5
>|     for (int ic1 = 0 ; ic1 < ic ; ic1++) {
>|       xout1(ic1,ir1) = xin1(ir1,ic1);                      // #6
>
>                         ^^^^^^^^^^^^^
>Since Octave does not know that this indexing operation appears on the
>RHS of the assignment (I think it would be a real mess to try to do
>that automatically), it splits off a copy here.  If you don't plan on
>modifying the argument that is pass to this function, then you can
>avoid the extra copy and the checks on the reference count that are
>done each time you use the indexing operator by declaring xin1 as
>"const".
>
>  
>
I guess this means that you decided not to impelemt e.g.

     xout1(ic1,ir1) = xin1(ir1,ic1);

using a helper class. The upside of this is speed; the downside is that statements such as

      double y = xin1(ir+1,ic+1);

do not trip an error and statements like

     xout1(ir+1,ic+1) = 1;

do not resize the matrix, as they do in Octave. Are there function calls e.g.

     double y = xout1.rhsindexing(ir+1,ic+1);
     xout1.lhsindexing(ir+1,ic+1) = 0;

which have the desired behaviour? Is there another route to finding this
out other than doxygen?

Thanks
Richard



-------------------------------------------------------------
Octave is freely available under the terms of the GNU GPL.

Octave's home on the web:  http://www.octave.org
How to fund new projects:  http://www.octave.org/funding.html
Subscription information:  http://www.octave.org/archive.html
-------------------------------------------------------------


Reply | Threaded
Open this post in threaded view
|

Re: Memory management in .oct files

Paul Thomas-10
Richard,

I believe that you will find Jens Ruecknagel's master's thesis very helpful.
It should answer most of your questions and more besides.

Paul T

----- Original Message -----
From: "Richard Hindmarsh" <[hidden email]>
To: "John W. Eaton" <[hidden email]>
Cc: <[hidden email]>
Sent: Saturday, March 19, 2005 1:59 PM
Subject: Re: Memory management in .oct files


>
>>|   int ir = xin1.rows();                                    // #3
>>|   int ic = xin1.cols();
>>|   Matrix xout1(ic,ir);                                     // #4
>>|   for (int ir1 = 0 ; ir1 < ir ; ir1++)                     // #5
>>|     for (int ic1 = 0 ; ic1 < ic ; ic1++) {
>>|       xout1(ic1,ir1) = xin1(ir1,ic1);                      // #6
>>
>>                         ^^^^^^^^^^^^^
>>Since Octave does not know that this indexing operation appears on the
>>RHS of the assignment (I think it would be a real mess to try to do
>>that automatically), it splits off a copy here.  If you don't plan on
>>modifying the argument that is pass to this function, then you can
>>avoid the extra copy and the checks on the reference count that are
>>done each time you use the indexing operator by declaring xin1 as
>>"const".
>>
>>
> I guess this means that you decided not to impelemt e.g.
>
>     xout1(ic1,ir1) = xin1(ir1,ic1);
> using a helper class. The upside of this is speed; the downside is that
> statements such as
>
>      double y = xin1(ir+1,ic+1);
>
> do not trip an error and statements like
>
>     xout1(ir+1,ic+1) = 1;
>
> do not resize the matrix, as they do in Octave. Are there function calls
> e.g.
>
>     double y = xout1.rhsindexing(ir+1,ic+1);
>     xout1.lhsindexing(ir+1,ic+1) = 0;
>
> which have the desired behaviour? Is there another route to finding this
> out other than doxygen?
>
> Thanks
> Richard
>
>
>
> -------------------------------------------------------------
> Octave is freely available under the terms of the GNU GPL.
>
> Octave's home on the web:  http://www.octave.org
> How to fund new projects:  http://www.octave.org/funding.html
> Subscription information:  http://www.octave.org/archive.html
> -------------------------------------------------------------
>
>




-------------------------------------------------------------
Octave is freely available under the terms of the GNU GPL.

Octave's home on the web:  http://www.octave.org
How to fund new projects:  http://www.octave.org/funding.html
Subscription information:  http://www.octave.org/archive.html
-------------------------------------------------------------


Reply | Threaded
Open this post in threaded view
|

Re: Memory management in .oct files

Paul Thomas-10
I also meant to attach the link
http://www.stud.tu-ilmenau.de/~rueckn/Oct_Interpreter_Compiler.pdf

Regards

Paul T




-------------------------------------------------------------
Octave is freely available under the terms of the GNU GPL.

Octave's home on the web:  http://www.octave.org
How to fund new projects:  http://www.octave.org/funding.html
Subscription information:  http://www.octave.org/archive.html
-------------------------------------------------------------


Reply | Threaded
Open this post in threaded view
|

Re: Memory management in .oct files

John W. Eaton-6
In reply to this post by Richard Hindmarsh
On 19-Mar-2005, Richard Hindmarsh <[hidden email]> wrote:

| I guess this means that you decided not to impelemt e.g.
|
|      xout1(ic1,ir1) = xin1(ir1,ic1);
|
| using a helper class.

In what way are you suggesting using a "helper class" and what do you
mean by that?

| The upside of this is speed; the downside is that statements such as
|
|       double y = xin1(ir+1,ic+1);
|
| do not trip an error

Why would this cause an error?

| and statements like
|
|      xout1(ir+1,ic+1) = 1;
|
| do not resize the matrix, as they do in Octave.

Doing that seemed like a bad idea at the time the Array and Matrix
classes were first implemented.

| Are there function calls e.g.
|
|      double y = xout1.rhsindexing(ir+1,ic+1);
|      xout1.lhsindexing(ir+1,ic+1) = 0;
|
| which have the desired behaviour?

Yes, but they don't look quite like this.  I think you are looking for
the set_index, index and assign methods in the Array classes.  I would
bet that you will not like the interface much, but it seemed to be
what I needed for the implementation of the scripting language way
back when, and it seems that so far, no one has contributed the code
to do it in a better way.

| Is there another route to finding this
| out other than doxygen?

Yes, reading the source without it.  :-)

But seriously, someone has to write the documentation you are
seeking.  Octave is mostly a volunteer project, and some of us are
busy enough writing code and apparently documentation is less fun
because there seems to be less of it.

jwe



-------------------------------------------------------------
Octave is freely available under the terms of the GNU GPL.

Octave's home on the web:  http://www.octave.org
How to fund new projects:  http://www.octave.org/funding.html
Subscription information:  http://www.octave.org/archive.html
-------------------------------------------------------------


Reply | Threaded
Open this post in threaded view
|

Re: Memory management in .oct files

Richard Hindmarsh


John W. Eaton wrote:

>On 19-Mar-2005, Richard Hindmarsh <[hidden email]> wrote:
>
>| I guess this means that you decided not to impelemt e.g.
>|
>|      xout1(ic1,ir1) = xin1(ir1,ic1);
>|
>| using a helper class.
>
>In what way are you suggesting using a "helper class" and what do you
>mean by that?
>  
>
I learnt the technique from

From: Corey Kosak
<http://groups.google.co.uk/groups?hl=en&lr=&safe=off&q=author:kosak%40adonis.nectar.cs.cmu.edu+>
([hidden email] <mailto:kosak%40adonis.nectar.cs.cmu.edu>)
Subject: Re: operator[] - lvalue and rvalue
View: Complete Thread (9 articles)
<http://groups.google.co.uk/groups?hl=en&lr=&safe=off&threadm=vzxu2zsihuu.fsf%40adonis.nectar.cs.cmu.edu&rnum=4&prev=/groups%3Fhl%3Den%26lr%3D%26safe%3Doff%26selm%3Dvzxu2zsihuu.fsf%2540adonis.nectar.cs.cmu.edu%26rnum%3D4>

Original Format
<http://groups.google.co.uk/groups?selm=vzxu2zsihuu.fsf%40adonis.nectar.cs.cmu.edu&output=gplain>


Newsgroups: comp.lang.c++.moderated
<http://groups.google.co.uk/groups?hl=en&lr=&safe=off&group=comp.lang.c%2B%2B.moderated>,
comp.lang.c++
<http://groups.google.co.uk/groups?hl=en&lr=&safe=off&group=comp.lang.c%2B%2B>
Date: 1998/11/22

This is the only way I know to distinguish an lvalue from a rvalue -
maybe there are some others?

>| The upside of this is speed; the downside is that statements such as
>|
>|       double y = xin1(ir+1,ic+1);
>|
>| do not trip an error
>
>  
>
I meant this to be equivalent to

double y = xin1(end+1,end+1)

which should trip an error.

I also noticed that the Matrix class is zero-based.

>I think you are looking for
>the set_index, index and assign methods in the Array classes.  I would
>bet that you will not like the interface much, but it seemed to be
>what I needed for the implementation of the scripting language way
>back when, and it seems that so far, no one has contributed the code
>to do it in a better way.
>
>  
>
I am looking for an alternative to the Matlab C++ library, which
Mathworks have stopped supporting. This has several desrable features
from an Octave users point of view. I wrote a matrix class with my ideal
properties (including helper classes) but got to the point where it was
exposing my deficiencies as a C++ programmer.  It looks as though to
recreate the Matlab C++ library one would have to inherit a further
class from Array or Matrix with lvalue/rvalue distinction as above and
one-based indexing etc. There are quite a few Matrix C++ classes about,
but it's not clear what their long-term survival prospects are. One
based on Octave would be much more convincing.

R



-------------------------------------------------------------
Octave is freely available under the terms of the GNU GPL.

Octave's home on the web:  http://www.octave.org
How to fund new projects:  http://www.octave.org/funding.html
Subscription information:  http://www.octave.org/archive.html
-------------------------------------------------------------


Reply | Threaded
Open this post in threaded view
|

Re: Memory management in .oct files

John W. Eaton-6
On 22-Mar-2005, Richard Hindmarsh <[hidden email]> wrote:

| I meant this to be equivalent to
|
| double y = xin1(end+1,end+1)
|
| which should trip an error.

You can get error checking for this if you enable bounds checking at
compile time.  That's not done by default for performance reasons.
But most of the time, we don't use the indexing operations this way
internally, so maybe it would not be much of a hit to enable the
bounds checking by default.

| I also noticed that the Matrix class is zero-based.

That's because it is C++, and I think it makes sense to be
zero-based.  But it does cause some trouble when converting from
Octave to C++.

| I am looking for an alternative to the Matlab C++ library, which
| Mathworks have stopped supporting. This has several desrable features
| from an Octave users point of view. I wrote a matrix class with my ideal
| properties (including helper classes) but got to the point where it was
| exposing my deficiencies as a C++ programmer.  It looks as though to
| recreate the Matlab C++ library one would have to inherit a further
| class from Array or Matrix with lvalue/rvalue distinction as above and
| one-based indexing etc. There are quite a few Matrix C++ classes about,
| but it's not clear what their long-term survival prospects are. One
| based on Octave would be much more convincing.

I would encourage you to report the problems you find and submit
patches or start discussions on the maintainers list about the
problems.  I think it would be better to have the Octave classes
evolve into something better than to try to start over from scratch.

jwe



-------------------------------------------------------------
Octave is freely available under the terms of the GNU GPL.

Octave's home on the web:  http://www.octave.org
How to fund new projects:  http://www.octave.org/funding.html
Subscription information:  http://www.octave.org/archive.html
-------------------------------------------------------------


Reply | Threaded
Open this post in threaded view
|

Re: Memory management in .oct files

John W. Eaton-6
In reply to this post by Richard Hindmarsh
On 22-Mar-2005, Richard Hindmarsh <[hidden email]> wrote:

| John W. Eaton wrote:
|
| >On 19-Mar-2005, Richard Hindmarsh <[hidden email]> wrote:
| >
| >| I guess this means that you decided not to impelemt e.g.
| >|
| >|      xout1(ic1,ir1) = xin1(ir1,ic1);
| >|
| >| using a helper class.
| >
| >In what way are you suggesting using a "helper class" and what do you
| >mean by that?
| >  
| >
| I learnt the technique from
|
| From: Corey Kosak
|
| [...]
|
| Date: 1998/11/22
|
| This is the only way I know to distinguish an lvalue from a rvalue -
| maybe there are some others?

I don't know of one.  This technique is also described in James
Coplien's Advanced C++ book published in 1992 but is probably older
than that.

Earlier versions of Octave's Array classes had code like this but it
was (mostly) abandoned because of the complexity.  You can still find
an example of it in the DiagArray2.h file, where there is the
following comment:

  // A two-dimensional array with diagonal elements only.
  //
  // Idea and example code for Proxy class and functions from:
  //
  // From: [hidden email] (James Kanze)
  // Subject: Re: How to overload [] to do READ/WRITE differently ?
  // Message-ID: <[hidden email]>
  // Sender: [hidden email]
  // Date: 29 Nov 1993 14:14:07 GMT
  // --
  // James Kanze                             email: [hidden email]
  // GABI Software, Sarl., 8 rue du Faisan, F-67000 Strasbourg, France

so apparently I was aware of this article but not aware that it was
described in Coplien's book, which I found quite dense and hard to
understand way back then.  (Amazingly, Google makes the article
available again -- where did they dig up the tapes?)

Anyway, it is not enough to overload only operator=.  You also need to
overload +=, -=, *=, etc.  And then you can't just do it once in the
base class.  The code must be repeated in each derived class.  It did
not seem worth the effort.  But maybe you see a clean way to implement
this in a reliable way (without a great deal of code duplication, or
at least managing the duplication in a sane way with templates or
macros) so that it will work and also result in something that is
possible to maintain?

jwe



-------------------------------------------------------------
Octave is freely available under the terms of the GNU GPL.

Octave's home on the web:  http://www.octave.org
How to fund new projects:  http://www.octave.org/funding.html
Subscription information:  http://www.octave.org/archive.html
-------------------------------------------------------------